Auto merge of #125415 - fmease:rollup-n2bg7q5, r=fmease
Rollup of 5 pull requests Successful merges: - #124896 (miri: rename intrinsic_fallback_checks_ub to intrinsic_fallback_is_spec) - #125015 (Pattern types: Prohibit generic args on const params) - #125049 (Disallow cast with trailing braced macro in let-else) - #125259 (An async closure may implement `FnMut`/`Fn` if it has no self-borrows) - #125296 (Fix `unexpected_cfgs` lint on std) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
93e7cb835a
23 changed files with 407 additions and 354 deletions
|
@ -81,8 +81,17 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum TrailingBrace<'a> {
|
||||
/// Trailing brace in a macro call, like the one in `x as *const brace! {}`.
|
||||
/// We will suggest changing the macro call to a different delimiter.
|
||||
MacCall(&'a ast::MacCall),
|
||||
/// Trailing brace in any other expression, such as `a + B {}`. We will
|
||||
/// suggest wrapping the innermost expression in parentheses: `a + (B {})`.
|
||||
Expr(&'a ast::Expr),
|
||||
}
|
||||
|
||||
/// If an expression ends with `}`, returns the innermost expression ending in the `}`
|
||||
pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
||||
pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
|
||||
loop {
|
||||
match &expr.kind {
|
||||
AddrOf(_, _, e)
|
||||
|
@ -111,10 +120,14 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
|||
| Struct(..)
|
||||
| TryBlock(..)
|
||||
| While(..)
|
||||
| ConstBlock(_) => break Some(expr),
|
||||
| ConstBlock(_) => break Some(TrailingBrace::Expr(expr)),
|
||||
|
||||
Cast(_, ty) => {
|
||||
break type_trailing_braced_mac_call(ty).map(TrailingBrace::MacCall);
|
||||
}
|
||||
|
||||
MacCall(mac) => {
|
||||
break (mac.args.delim == Delimiter::Brace).then_some(expr);
|
||||
break (mac.args.delim == Delimiter::Brace).then_some(TrailingBrace::MacCall(mac));
|
||||
}
|
||||
|
||||
InlineAsm(_) | OffsetOf(_, _) | IncludedBytes(_) | FormatArgs(_) => {
|
||||
|
@ -131,7 +144,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
|||
| MethodCall(_)
|
||||
| Tup(_)
|
||||
| Lit(_)
|
||||
| Cast(_, _)
|
||||
| Type(_, _)
|
||||
| Await(_, _)
|
||||
| Field(_, _)
|
||||
|
@ -148,3 +160,78 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If the type's last token is `}`, it must be due to a braced macro call, such
|
||||
/// as in `*const brace! { ... }`. Returns that trailing macro call.
|
||||
fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
|
||||
loop {
|
||||
match &ty.kind {
|
||||
ast::TyKind::MacCall(mac) => {
|
||||
break (mac.args.delim == Delimiter::Brace).then_some(mac);
|
||||
}
|
||||
|
||||
ast::TyKind::Ptr(mut_ty) | ast::TyKind::Ref(_, mut_ty) => {
|
||||
ty = &mut_ty.ty;
|
||||
}
|
||||
|
||||
ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
|
||||
ast::FnRetTy::Default(_) => break None,
|
||||
ast::FnRetTy::Ty(ret) => ty = ret,
|
||||
},
|
||||
|
||||
ast::TyKind::Path(_, path) => match path_return_type(path) {
|
||||
Some(trailing_ty) => ty = trailing_ty,
|
||||
None => break None,
|
||||
},
|
||||
|
||||
ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds, _) => {
|
||||
match bounds.last() {
|
||||
Some(ast::GenericBound::Trait(bound, _)) => {
|
||||
match path_return_type(&bound.trait_ref.path) {
|
||||
Some(trailing_ty) => ty = trailing_ty,
|
||||
None => break None,
|
||||
}
|
||||
}
|
||||
Some(ast::GenericBound::Outlives(_)) | None => break None,
|
||||
}
|
||||
}
|
||||
|
||||
ast::TyKind::Slice(..)
|
||||
| ast::TyKind::Array(..)
|
||||
| ast::TyKind::Never
|
||||
| ast::TyKind::Tup(..)
|
||||
| ast::TyKind::Paren(..)
|
||||
| ast::TyKind::Typeof(..)
|
||||
| ast::TyKind::Infer
|
||||
| ast::TyKind::ImplicitSelf
|
||||
| ast::TyKind::CVarArgs
|
||||
| ast::TyKind::Pat(..)
|
||||
| ast::TyKind::Dummy
|
||||
| ast::TyKind::Err(..) => break None,
|
||||
|
||||
// These end in brace, but cannot occur in a let-else statement.
|
||||
// They are only parsed as fields of a data structure. For the
|
||||
// purpose of denying trailing braces in the expression of a
|
||||
// let-else, we can disregard these.
|
||||
ast::TyKind::AnonStruct(..) | ast::TyKind::AnonUnion(..) => break None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the trailing return type in the given path, if it has one.
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// ::std::ops::FnOnce(&str) -> fn() -> *const c_void
|
||||
/// ^^^^^^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
fn path_return_type(path: &ast::Path) -> Option<&ast::Ty> {
|
||||
let last_segment = path.segments.last()?;
|
||||
let args = last_segment.args.as_ref()?;
|
||||
match &**args {
|
||||
ast::GenericArgs::Parenthesized(args) => match &args.output {
|
||||
ast::FnRetTy::Default(_) => None,
|
||||
ast::FnRetTy::Ty(ret) => Some(ret),
|
||||
},
|
||||
ast::GenericArgs::AngleBracketed(_) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -371,9 +371,9 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
|
|||
.suggestion = cast the value to `{$cast_ty}`
|
||||
.help = cast the value to `{$cast_ty}`
|
||||
|
||||
hir_analysis_pattern_type_non_const_range = "range patterns must have constant range start and end"
|
||||
hir_analysis_pattern_type_wild_pat = "wildcard patterns are not permitted for pattern types"
|
||||
.label = "this type is the same as the inner type without a pattern"
|
||||
hir_analysis_pattern_type_non_const_range = range patterns must have constant range start and end
|
||||
hir_analysis_pattern_type_wild_pat = wildcard patterns are not permitted for pattern types
|
||||
.label = this type is the same as the inner type without a pattern
|
||||
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
|
||||
.label = not allowed in type signatures
|
||||
|
||||
|
|
|
@ -1382,7 +1382,7 @@ pub enum GenericsArgsErrExtend<'tcx> {
|
|||
span: Span,
|
||||
},
|
||||
SelfTyParam(Span),
|
||||
TyParam(DefId),
|
||||
Param(DefId),
|
||||
DefVariant,
|
||||
None,
|
||||
}
|
||||
|
@ -1498,11 +1498,11 @@ fn generics_args_err_extend<'a>(
|
|||
GenericsArgsErrExtend::DefVariant => {
|
||||
err.note("enum variants can't have type parameters");
|
||||
}
|
||||
GenericsArgsErrExtend::TyParam(def_id) => {
|
||||
if let Some(span) = tcx.def_ident_span(def_id) {
|
||||
let name = tcx.item_name(def_id);
|
||||
err.span_note(span, format!("type parameter `{name}` defined here"));
|
||||
}
|
||||
GenericsArgsErrExtend::Param(def_id) => {
|
||||
let span = tcx.def_ident_span(def_id).unwrap();
|
||||
let kind = tcx.def_descr(def_id);
|
||||
let name = tcx.item_name(def_id);
|
||||
err.span_note(span, format!("{kind} `{name}` defined here"));
|
||||
}
|
||||
GenericsArgsErrExtend::SelfTyParam(span) => {
|
||||
err.span_suggestion_verbose(
|
||||
|
|
|
@ -1758,7 +1758,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
assert_eq!(opt_self_ty, None);
|
||||
let _ = self.prohibit_generic_args(
|
||||
path.segments.iter(),
|
||||
GenericsArgsErrExtend::TyParam(def_id),
|
||||
GenericsArgsErrExtend::Param(def_id),
|
||||
);
|
||||
self.lower_ty_param(hir_id)
|
||||
}
|
||||
|
@ -2191,10 +2191,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
&hir::Path {
|
||||
res: Res::Def(DefKind::ConstParam, def_id), ..
|
||||
path @ &hir::Path {
|
||||
res: Res::Def(DefKind::ConstParam, def_id),
|
||||
..
|
||||
},
|
||||
)) => {
|
||||
let _ = self.prohibit_generic_args(
|
||||
path.segments.iter(),
|
||||
GenericsArgsErrExtend::Param(def_id),
|
||||
);
|
||||
let ty = tcx
|
||||
.type_of(def_id)
|
||||
.no_bound_vars()
|
||||
|
|
|
@ -401,6 +401,45 @@ impl<'tcx> CoroutineClosureArgs<'tcx> {
|
|||
pub fn coroutine_witness_ty(self) -> Ty<'tcx> {
|
||||
self.split().coroutine_witness_ty
|
||||
}
|
||||
|
||||
pub fn has_self_borrows(&self) -> bool {
|
||||
match self.coroutine_captures_by_ref_ty().kind() {
|
||||
ty::FnPtr(sig) => sig
|
||||
.skip_binder()
|
||||
.visit_with(&mut HasRegionsBoundAt { binder: ty::INNERMOST })
|
||||
.is_break(),
|
||||
ty::Error(_) => true,
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Unlike `has_escaping_bound_vars` or `outermost_exclusive_binder`, this will
|
||||
/// detect only regions bound *at* the debruijn index.
|
||||
struct HasRegionsBoundAt {
|
||||
binder: ty::DebruijnIndex,
|
||||
}
|
||||
// FIXME: Could be optimized to not walk into components with no escaping bound vars.
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasRegionsBoundAt {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
t: &ty::Binder<'tcx, T>,
|
||||
) -> Self::Result {
|
||||
self.binder.shift_in(1);
|
||||
t.super_visit_with(self)?;
|
||||
self.binder.shift_out(1);
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
|
||||
if let ty::ReBound(binder, _) = *r
|
||||
&& self.binder == binder
|
||||
{
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
|
||||
|
|
|
@ -15,7 +15,7 @@ use ast::Label;
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, TokenKind};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::classify::{self, TrailingBrace};
|
||||
use rustc_ast::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyle};
|
||||
use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Recovered, Stmt};
|
||||
use rustc_ast::{StmtKind, DUMMY_NODE_ID};
|
||||
|
@ -407,18 +407,24 @@ impl<'a> Parser<'a> {
|
|||
|
||||
fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) {
|
||||
if let Some(trailing) = classify::expr_trailing_brace(init) {
|
||||
let sugg = match &trailing.kind {
|
||||
ExprKind::MacCall(mac) => errors::WrapInParentheses::MacroArgs {
|
||||
left: mac.args.dspan.open,
|
||||
right: mac.args.dspan.close,
|
||||
},
|
||||
_ => errors::WrapInParentheses::Expression {
|
||||
left: trailing.span.shrink_to_lo(),
|
||||
right: trailing.span.shrink_to_hi(),
|
||||
},
|
||||
let (span, sugg) = match trailing {
|
||||
TrailingBrace::MacCall(mac) => (
|
||||
mac.span(),
|
||||
errors::WrapInParentheses::MacroArgs {
|
||||
left: mac.args.dspan.open,
|
||||
right: mac.args.dspan.close,
|
||||
},
|
||||
),
|
||||
TrailingBrace::Expr(expr) => (
|
||||
expr.span,
|
||||
errors::WrapInParentheses::Expression {
|
||||
left: expr.span.shrink_to_lo(),
|
||||
right: expr.span.shrink_to_hi(),
|
||||
},
|
||||
),
|
||||
};
|
||||
self.dcx().emit_err(errors::InvalidCurlyInLetElse {
|
||||
span: trailing.span.with_lo(trailing.span.hi() - BytePos(1)),
|
||||
span: span.with_lo(span.hi() - BytePos(1)),
|
||||
sugg,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -300,14 +300,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
|||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// If `Fn`/`FnMut`, we only implement this goal if we
|
||||
// have no captures.
|
||||
let no_borrows = match args.tupled_upvars_ty().kind() {
|
||||
ty::Tuple(tys) => tys.is_empty(),
|
||||
ty::Error(_) => false,
|
||||
_ => bug!("tuple_fields called on non-tuple"),
|
||||
};
|
||||
if closure_kind != ty::ClosureKind::FnOnce && !no_borrows {
|
||||
// A coroutine-closure implements `FnOnce` *always*, since it may
|
||||
// always be called once. It additionally implements `Fn`/`FnMut`
|
||||
// only if it has no upvars referencing the closure-env lifetime,
|
||||
// and if the closure kind permits it.
|
||||
if closure_kind != ty::ClosureKind::FnOnce && args.has_self_borrows() {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
|
|
|
@ -418,20 +418,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// Ambiguity if upvars haven't been constrained yet
|
||||
&& !args.tupled_upvars_ty().is_ty_var()
|
||||
{
|
||||
let no_borrows = match args.tupled_upvars_ty().kind() {
|
||||
ty::Tuple(tys) => tys.is_empty(),
|
||||
ty::Error(_) => false,
|
||||
_ => bug!("tuple_fields called on non-tuple"),
|
||||
};
|
||||
// A coroutine-closure implements `FnOnce` *always*, since it may
|
||||
// always be called once. It additionally implements `Fn`/`FnMut`
|
||||
// only if it has no upvars (therefore no borrows from the closure
|
||||
// that would need to be represented with a lifetime) and if the
|
||||
// closure kind permits it.
|
||||
// FIXME(async_closures): Actually, it could also implement `Fn`/`FnMut`
|
||||
// if it takes all of its upvars by copy, and none by ref. This would
|
||||
// require us to record a bit more information during upvar analysis.
|
||||
if no_borrows && closure_kind.extends(kind) {
|
||||
// only if it has no upvars referencing the closure-env lifetime,
|
||||
// and if the closure kind permits it.
|
||||
if closure_kind.extends(kind) && !args.has_self_borrows() {
|
||||
candidates.vec.push(ClosureCandidate { is_const });
|
||||
} else if kind == ty::ClosureKind::FnOnce {
|
||||
candidates.vec.push(ClosureCandidate { is_const });
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue