diff options
| author | bors <bors@rust-lang.org> | 2024-09-22 06:31:10 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-09-22 06:31:10 +0000 |
| commit | ee20c8628224ceae61f5f3dac98a18ede8872571 (patch) | |
| tree | d6de38b7510e7603d988ab5b33a317d201f32070 /compiler | |
| parent | a3fea24971e748914354acaf90033bbe594a4fa5 (diff) | |
| parent | d877ec2a3e7235c32e0fd094fb1cf813586b2665 (diff) | |
| download | rust-ee20c8628224ceae61f5f3dac98a18ede8872571.tar.gz rust-ee20c8628224ceae61f5f3dac98a18ede8872571.zip | |
Auto merge of #3902 - RalfJung:rustup, r=RalfJung
Rustup
Diffstat (limited to 'compiler')
55 files changed, 1071 insertions, 322 deletions
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 7bd2507d1ad..904c5933a18 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -337,23 +337,21 @@ impl TargetDataLayout { Ok(dl) } - /// Returns exclusive upper bound on object size. + /// Returns **exclusive** upper bound on object size in bytes. /// /// The theoretical maximum object size is defined as the maximum positive `isize` value. /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly /// index every address within an object along with one byte past the end, along with allowing /// `isize` to store the difference between any two pointers into an object. /// - /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer - /// to represent object size in bits. It would need to be 1 << 61 to account for this, but is - /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable - /// address space on 64-bit ARMv8 and x86_64. + /// LLVM uses a 64-bit integer to represent object size in *bits*, but we care only for bytes, + /// so we adopt such a more-constrained size bound due to its technical limitations. #[inline] pub fn obj_size_bound(&self) -> u64 { match self.pointer_size.bits() { 16 => 1 << 15, 32 => 1 << 31, - 64 => 1 << 47, + 64 => 1 << 61, bits => panic!("obj_size_bound: unknown pointer bit size {bits}"), } } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index ac65b7b22bc..d49265de202 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1187,8 +1187,8 @@ impl Expr { /// `min_const_generics` as more complex expressions are not supported. /// /// Does not ensure that the path resolves to a const param, the caller should check this. - pub fn is_potential_trivial_const_arg(&self) -> bool { - let this = self.maybe_unwrap_block(); + pub fn is_potential_trivial_const_arg(&self, strip_identity_block: bool) -> bool { + let this = if strip_identity_block { self.maybe_unwrap_block().1 } else { self }; if let ExprKind::Path(None, path) = &this.kind && path.is_potential_trivial_const_arg() @@ -1199,14 +1199,15 @@ impl Expr { } } - pub fn maybe_unwrap_block(&self) -> &Expr { + /// Returns an expression with (when possible) *one* outter brace removed + pub fn maybe_unwrap_block(&self) -> (bool, &Expr) { if let ExprKind::Block(block, None) = &self.kind && let [stmt] = block.stmts.as_slice() && let StmtKind::Expr(expr) = &stmt.kind { - expr + (true, expr) } else { - self + (false, self) } } diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index a9d1ee5c9c1..11867c39e02 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -20,8 +20,8 @@ use super::errors::{ }; use super::LoweringContext; use crate::{ - fluent_generated as fluent, ImplTraitContext, ImplTraitPosition, ParamMode, - ResolverAstLoweringExt, + fluent_generated as fluent, AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, + ParamMode, ResolverAstLoweringExt, }; impl<'a, 'hir> LoweringContext<'a, 'hir> { @@ -201,6 +201,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &sym.qself, &sym.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -220,7 +221,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let parent_def_id = self.current_def_id_parent; let node_id = self.next_node_id(); // HACK(min_generic_const_args): see lower_anon_const - if !expr.is_potential_trivial_const_arg() { + if !expr.is_potential_trivial_const_arg(true) { self.create_def( parent_def_id, node_id, diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index ac527df474a..97483e85f77 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -52,7 +52,7 @@ use rustc_target::spec::abi; use {rustc_ast as ast, rustc_hir as hir}; use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode}; -use crate::{ImplTraitPosition, ResolverAstLoweringExt}; +use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt}; pub(crate) struct DelegationResults<'hir> { pub body_id: hir::BodyId, @@ -340,6 +340,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &delegation.qself, &delegation.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e105026ebd1..d828c9856b9 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -23,7 +23,7 @@ use super::{ GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt, }; use crate::errors::YieldInClosure; -use crate::{fluent_generated, FnDeclKind, ImplTraitPosition}; +use crate::{fluent_generated, AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition}; impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] { @@ -281,6 +281,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -328,6 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, )), @@ -387,7 +389,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let node_id = self.next_node_id(); // HACK(min_generic_const_args): see lower_anon_const - if !arg.is_potential_trivial_const_arg() { + if !arg.is_potential_trivial_const_arg(true) { // Add a definition for the in-band const def. self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span); } @@ -1291,6 +1293,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -1311,6 +1314,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -1336,6 +1340,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index efd3ae336af..3f48fe67dbb 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -485,9 +485,23 @@ enum ParamMode { Optional, } +#[derive(Copy, Clone, Debug)] +enum AllowReturnTypeNotation { + /// Only in types, since RTN is denied later during HIR lowering. + Yes, + /// All other positions (path expr, method, use tree). + No, +} + enum GenericArgsMode { + /// Allow paren sugar, don't allow RTN. ParenSugar, + /// Allow RTN, don't allow paren sugar. + ReturnTypeNotation, + // Error if parenthesized generics or RTN are encountered. Err, + /// Silence errors when lowering generics. Only used with `Res::Err`. + Silence, } impl<'a, 'hir> LoweringContext<'a, 'hir> { @@ -1226,7 +1240,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let id = self.lower_node_id(t.id); - let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx, None); + let qpath = self.lower_qpath( + t.id, + qself, + path, + param_mode, + AllowReturnTypeNotation::Yes, + itctx, + None, + ); self.ty_path(id, t.span, qpath) } @@ -2203,6 +2225,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &None, &p.path, ParamMode::Explicit, + AllowReturnTypeNotation::No, itctx, Some(modifiers), ) { @@ -2341,6 +2364,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &None, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -2419,6 +2443,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -2441,7 +2466,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// See [`hir::ConstArg`] for when to use this function vs /// [`Self::lower_anon_const_to_const_arg`]. fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst { - if c.value.is_potential_trivial_const_arg() { + if c.value.is_potential_trivial_const_arg(true) { // HACK(min_generic_const_args): see DefCollector::visit_anon_const // Over there, we guess if this is a bare param and only create a def if // we think it's not. However we may can guess wrong (see there for example) diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index d82bdd526b7..584d94ebe2d 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -11,7 +11,7 @@ use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, }; use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt}; -use crate::ImplTraitPosition; +use crate::{AllowReturnTypeNotation, ImplTraitPosition}; impl<'a, 'hir> LoweringContext<'a, 'hir> { pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> { @@ -38,6 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -55,6 +56,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -66,6 +68,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 2ab30eff6d8..03c8097e4c3 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -5,6 +5,7 @@ use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; use rustc_middle::span_bug; +use rustc_session::parse::add_feature_diagnostics; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, DesugaringKind, Span, Symbol, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; @@ -15,10 +16,9 @@ use super::errors::{ GenericTypeWithParentheses, UseAngleBrackets, }; use super::{ - GenericArgsCtor, GenericArgsMode, ImplTraitContext, LifetimeRes, LoweringContext, ParamMode, - ResolverAstLoweringExt, + AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, ImplTraitPosition, + LifetimeRes, LoweringContext, ParamMode, ResolverAstLoweringExt, }; -use crate::ImplTraitPosition; impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "trace", skip(self))] @@ -28,6 +28,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself: &Option<ptr::P<QSelf>>, p: &Path, param_mode: ParamMode, + allow_return_type_notation: AllowReturnTypeNotation, itctx: ImplTraitContext, // modifiers of the impl/bound if this is a trait path modifiers: Option<ast::TraitBoundModifiers>, @@ -103,8 +104,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { { GenericArgsMode::ParenSugar } + Res::Def(DefKind::AssocFn, _) if i + 1 == proj_start => { + match allow_return_type_notation { + AllowReturnTypeNotation::Yes => GenericArgsMode::ReturnTypeNotation, + AllowReturnTypeNotation::No => GenericArgsMode::Err, + } + } // Avoid duplicated errors. - Res::Err => GenericArgsMode::ParenSugar, + Res::Err => GenericArgsMode::Silence, // An error _ => GenericArgsMode::Err, }; @@ -164,11 +171,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // 3. `<<std::vec::Vec<T>>::IntoIter>::Item` // * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone` for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { + // If this is a type-dependent `T::method(..)`. + let generic_args_mode = if i + 1 == p.segments.len() + && matches!(allow_return_type_notation, AllowReturnTypeNotation::Yes) + { + GenericArgsMode::ReturnTypeNotation + } else { + GenericArgsMode::Err + }; + let hir_segment = self.arena.alloc(self.lower_path_segment( p.span, segment, param_mode, - GenericArgsMode::Err, + generic_args_mode, itctx, None, )); @@ -238,11 +254,46 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) } GenericArgs::Parenthesized(data) => match generic_args_mode { - GenericArgsMode::ParenSugar => self.lower_parenthesized_parameter_data( - data, - itctx, - bound_modifier_allowed_features, - ), + GenericArgsMode::ReturnTypeNotation => { + let mut err = if !data.inputs.is_empty() { + self.dcx().create_err(BadReturnTypeNotation::Inputs { + span: data.inputs_span, + }) + } else if let FnRetTy::Ty(ty) = &data.output { + self.dcx().create_err(BadReturnTypeNotation::Output { + span: data.inputs_span.shrink_to_hi().to(ty.span), + }) + } else { + self.dcx().create_err(BadReturnTypeNotation::NeedsDots { + span: data.inputs_span, + }) + }; + if !self.tcx.features().return_type_notation + && self.tcx.sess.is_nightly_build() + { + add_feature_diagnostics( + &mut err, + &self.tcx.sess, + sym::return_type_notation, + ); + } + err.emit(); + ( + GenericArgsCtor { + args: Default::default(), + constraints: &[], + parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation, + span: path_span, + }, + false, + ) + } + GenericArgsMode::ParenSugar | GenericArgsMode::Silence => self + .lower_parenthesized_parameter_data( + data, + itctx, + bound_modifier_allowed_features, + ), GenericArgsMode::Err => { // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>` let sub = if !data.inputs.is_empty() { @@ -279,7 +330,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }, GenericArgs::ParenthesizedElided(span) => { - self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span }); + match generic_args_mode { + GenericArgsMode::ReturnTypeNotation | GenericArgsMode::Silence => { + // Ok + } + GenericArgsMode::ParenSugar | GenericArgsMode::Err => { + self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span }); + } + } ( GenericArgsCtor { args: Default::default(), diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 24cf3f061a5..8838b15d29d 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -61,6 +61,9 @@ pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: Call Conv::CCmseNonSecureCall => { sess.dcx().fatal("C-cmse-nonsecure-call call conv is not yet implemented"); } + Conv::CCmseNonSecureEntry => { + sess.dcx().fatal("C-cmse-nonsecure-entry call conv is not yet implemented"); + } Conv::Msp430Intr | Conv::PtxKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => { unreachable!("tried to use {c:?} call conv which only exists on an unsupported target"); diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 26718792f5f..0fa8c9d3f19 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -422,6 +422,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { if let Conv::RiscvInterrupt { kind } = self.conv { func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", kind.as_str())); } + if let Conv::CCmseNonSecureEntry = self.conv { + func_attrs.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")) + } attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &{ func_attrs }); let mut i = 0; @@ -659,9 +662,11 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { impl From<Conv> for llvm::CallConv { fn from(conv: Conv) -> Self { match conv { - Conv::C | Conv::Rust | Conv::CCmseNonSecureCall | Conv::RiscvInterrupt { .. } => { - llvm::CCallConv - } + Conv::C + | Conv::Rust + | Conv::CCmseNonSecureCall + | Conv::CCmseNonSecureEntry + | Conv::RiscvInterrupt { .. } => llvm::CCallConv, Conv::Cold => llvm::ColdCallConv, Conv::PreserveMost => llvm::PreserveMost, Conv::PreserveAll => llvm::PreserveAll, diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 6df63eec513..489259da856 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -483,9 +483,6 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) { - to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")); - } if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 137e481f08c..9bd8a84f5a3 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -195,24 +195,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } } - sym::cmse_nonsecure_entry => { - if let Some(fn_sig) = fn_sig() - && !matches!(fn_sig.skip_binder().abi(), abi::Abi::C { .. }) - { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0776, - "`#[cmse_nonsecure_entry]` requires C ABI" - ) - .emit(); - } - if !tcx.sess.target.llvm_target.contains("thumbv8m") { - struct_span_code_err!(tcx.dcx(), attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY - } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, sym::track_caller => { let is_closure = tcx.is_closure_like(did.to_def_id()); diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index f13c46e8bef..25712095e76 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -15,6 +15,7 @@ use crate::traits::*; pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx: &FunctionCx<'a, 'tcx, Bx>, + traversal_order: &[mir::BasicBlock], ) -> BitSet<mir::Local> { let mir = fx.mir; let dominators = mir.basic_blocks.dominators(); @@ -24,13 +25,7 @@ pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( .map(|decl| { let ty = fx.monomorphize(decl.ty); let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span); - if layout.is_zst() { - LocalKind::ZST - } else if fx.cx.is_backend_immediate(layout) || fx.cx.is_backend_scalar_pair(layout) { - LocalKind::Unused - } else { - LocalKind::Memory - } + if layout.is_zst() { LocalKind::ZST } else { LocalKind::Unused } }) .collect(); @@ -44,7 +39,8 @@ pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // If there exists a local definition that dominates all uses of that local, // the definition should be visited first. Traverse blocks in an order that // is a topological sort of dominance partial order. - for (bb, data) in traversal::reverse_postorder(mir) { + for bb in traversal_order.iter().copied() { + let data = &mir.basic_blocks[bb]; analyzer.visit_basic_block_data(bb, data); } @@ -77,11 +73,22 @@ struct LocalAnalyzer<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> { impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx> { fn define(&mut self, local: mir::Local, location: DefLocation) { + let fx = self.fx; let kind = &mut self.locals[local]; + let decl = &fx.mir.local_decls[local]; match *kind { LocalKind::ZST => {} LocalKind::Memory => {} - LocalKind::Unused => *kind = LocalKind::SSA(location), + LocalKind::Unused => { + let ty = fx.monomorphize(decl.ty); + let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span); + *kind = + if fx.cx.is_backend_immediate(layout) || fx.cx.is_backend_scalar_pair(layout) { + LocalKind::SSA(location) + } else { + LocalKind::Memory + }; + } LocalKind::SSA(_) => *kind = LocalKind::Memory, } } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 61e9b9bd774..68fb5cb2206 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -218,7 +218,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx); - let memory_locals = analyze::non_ssa_locals(&fx); + let traversal_order = traversal::mono_reachable_reverse_postorder(mir, cx.tcx(), instance); + let memory_locals = analyze::non_ssa_locals(&fx, &traversal_order); // Allocate variable and temp allocas let local_values = { @@ -277,17 +278,20 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // So drop the builder of `start_llbb` to avoid having two at the same time. drop(start_bx); - let reachable_blocks = traversal::mono_reachable_as_bitset(mir, cx.tcx(), instance); + let mut unreached_blocks = BitSet::new_filled(mir.basic_blocks.len()); + // Codegen the body of each reachable block using our reverse postorder list. + for bb in traversal_order { + fx.codegen_block(bb); + unreached_blocks.remove(bb); + } - // Codegen the body of each block using reverse postorder - for (bb, _) in traversal::reverse_postorder(mir) { - if reachable_blocks.contains(bb) { - fx.codegen_block(bb); - } else { - // We want to skip this block, because it's not reachable. But we still create - // the block so terminators in other blocks can reference it. - fx.codegen_block_as_unreachable(bb); - } + // FIXME: These empty unreachable blocks are *mostly* a waste. They are occasionally + // targets for a SwitchInt terminator, but the reimplementation of the mono-reachable + // simplification in SwitchInt lowering sometimes misses cases that + // mono_reachable_reverse_postorder manages to figure out. + // The solution is to do something like post-mono GVN. But for now we have this hack. + for bb in unreached_blocks.iter() { + fx.codegen_block_as_unreachable(bb); } } diff --git a/compiler/rustc_error_codes/src/error_codes/E0775.md b/compiler/rustc_error_codes/src/error_codes/E0775.md index 9bafd52f75c..efbd51e89ea 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0775.md +++ b/compiler/rustc_error_codes/src/error_codes/E0775.md @@ -1,13 +1,14 @@ +#### Note: this error code is no longer emitted by the compiler. + `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension. Erroneous code example: -```compile_fail,E0775 +```ignore (no longer emitted) #![feature(cmse_nonsecure_entry)] -#[cmse_nonsecure_entry] -pub extern "C" fn entry_function() {} +pub extern "C-cmse-nonsecure-entry" fn entry_function() {} ``` To fix this error, compile your code for a Rust target that supports the diff --git a/compiler/rustc_error_codes/src/error_codes/E0776.md b/compiler/rustc_error_codes/src/error_codes/E0776.md index d65beebe07c..e46d498d1c2 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0776.md +++ b/compiler/rustc_error_codes/src/error_codes/E0776.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + `#[cmse_nonsecure_entry]` functions require a C ABI Erroneous code example: -```compile_fail,E0776 +```ignore (no longer emitted) #![feature(cmse_nonsecure_entry)] #[no_mangle] diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 11cad0b8f97..8631de65ec8 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -681,4 +681,5 @@ E0800: 0800, // E0723, // unstable feature in `const` context // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. // E0744, // merged into E0728 +// E0776, // Removed; cmse_nonsecure_entry is now `C-cmse-nonsecure-entry` // E0796, // unused error code. We use `static_mut_refs` lint instead. diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0d56a005f15..84ae351ed72 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -41,7 +41,9 @@ use crate::errors::{ }; use crate::fluent_generated; use crate::mbe::diagnostics::annotate_err_with_kind; -use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; +use crate::module::{ + mod_dir_path, mod_file_path_from_attr, parse_external_mod, DirOwnership, ParsedExternalMod, +}; use crate::placeholders::{placeholder, PlaceholderExpander}; macro_rules! ast_fragments { @@ -1202,8 +1204,14 @@ impl InvocationCollectorNode for P<ast::Item> { ecx.current_expansion.dir_ownership, *inline, ); + // If the module was parsed from an external file, recover its path. + // This lets `parse_external_mod` catch cycles if it's self-referential. + let file_path = match inline { + Inline::Yes => None, + Inline::No => mod_file_path_from_attr(ecx.sess, &attrs, &dir_path), + }; node.attrs = attrs; - (None, dir_path, dir_ownership) + (file_path, dir_path, dir_ownership) } ModKind::Unloaded => { // We have an outline `mod foo;` so we need to parse the file. diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 13348376851..27a9a330f3c 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -171,7 +171,7 @@ fn mod_file_path<'a>( /// Derive a submodule path from the first found `#[path = "path_string"]`. /// The provided `dir_path` is joined with the `path_string`. -fn mod_file_path_from_attr( +pub(crate) fn mod_file_path_from_attr( sess: &Session, attrs: &[Attribute], dir_path: &Path, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 3b7e0d82d0f..fa5f152132a 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -551,10 +551,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::No, experimental!(register_tool), ), - gated!( - cmse_nonsecure_entry, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, experimental!(cmse_nonsecure_entry) - ), // RFC 2632 gated!( const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, const_trait_impl, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 40333c3953a..edc8e5f0752 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -395,7 +395,7 @@ declare_features! ( (unstable, closure_lifetime_binder, "1.64.0", Some(97362)), /// Allows `#[track_caller]` on closures and coroutines. (unstable, closure_track_caller, "1.57.0", Some(87417)), - /// Allows to use the `#[cmse_nonsecure_entry]` attribute. + /// Allows `extern "C-cmse-nonsecure-entry" fn()`. (unstable, cmse_nonsecure_entry, "1.48.0", Some(75835)), /// Allows `async {}` expressions in const contexts. (unstable, const_async_blocks, "1.53.0", Some(85368)), diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 633ccacedfc..09d466339ff 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -37,7 +37,7 @@ hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got} hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here -hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters +hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated {$what} of a trait with uninferred generic parameters .suggestion = use a fully qualified path with inferred lifetimes hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes @@ -48,6 +48,8 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh hir_analysis_bad_precise_capture = expected {$kind} parameter in `use<...>` precise captures list, found {$found} +hir_analysis_bad_return_type_notation_position = return type notation not allowed in this position yet + hir_analysis_cannot_capture_late_bound_const = cannot capture late-bound const parameter in {$what} .label = parameter defined here @@ -478,7 +480,7 @@ hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}`, bu hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]` -hir_analysis_too_large_static = extern static is too large for the current architecture +hir_analysis_too_large_static = extern static is too large for the target architecture hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]` .suggestion = remove this annotation diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index d0b0c08aa79..14ea7816291 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -9,6 +9,8 @@ use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::def_id::DefId; use rustc_span::Span; +use crate::hir_ty_lowering::OnlySelfBounds; + /// Collects together a list of type bounds. These lists of bounds occur in many places /// in Rust's syntax: /// @@ -50,6 +52,7 @@ impl<'tcx> Bounds<'tcx> { span: Span, polarity: ty::PredicatePolarity, constness: ty::BoundConstness, + only_self_bounds: OnlySelfBounds, ) { let clause = ( bound_trait_ref @@ -66,7 +69,10 @@ impl<'tcx> Bounds<'tcx> { self.clauses.push(clause); } - if !tcx.features().effects { + // FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else. + // Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated + // type bounds. + if !tcx.features().effects || only_self_bounds.0 { return; } // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index ac9976148e2..4c59f7540ee 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -460,7 +460,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { [] => (generics.span, format!("<{lt_name}>")), [bound, ..] => (bound.span.shrink_to_lo(), format!("{lt_name}, ")), }; - mpart_sugg = Some(errors::AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion { + mpart_sugg = Some(errors::AssociatedItemTraitUninferredGenericParamsMultipartSuggestion { fspan: lt_sp, first: sugg, sspan: span.with_hi(item_segment.ident.span.lo()), @@ -502,11 +502,12 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { } Ty::new_error( self.tcx(), - self.tcx().dcx().emit_err(errors::AssociatedTypeTraitUninferredGenericParams { + self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams { span, inferred_sugg, bound, mpart_sugg, + what: "type", }), ) } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index d62727e76b5..7a254c884c2 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -10,6 +10,7 @@ use rustc_span::Span; use rustc_type_ir::Upcast; use tracing::{debug, instrument}; +use super::predicates_of::assert_only_contains_predicates_from; use super::ItemCtxt; use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter}; @@ -56,6 +57,9 @@ fn associated_type_bounds<'tcx>( tcx.def_path_str(assoc_item_def_id.to_def_id()), all_bounds ); + + assert_only_contains_predicates_from(filter, all_bounds, item_ty); + all_bounds } @@ -108,18 +112,21 @@ pub(super) fn explicit_item_bounds_with_filter( Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { let item = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_item(); let opaque_ty = item.expect_opaque_ty(); - return ty::EarlyBinder::bind(opaque_type_bounds( + let item_ty = Ty::new_projection_from_args( + tcx, + def_id.to_def_id(), + ty::GenericArgs::identity_for_item(tcx, def_id), + ); + let bounds = opaque_type_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, - Ty::new_projection_from_args( - tcx, - def_id.to_def_id(), - ty::GenericArgs::identity_for_item(tcx, def_id), - ), + item_ty, item.span, filter, - )); + ); + assert_only_contains_predicates_from(filter, bounds, item_ty); + return ty::EarlyBinder::bind(bounds); } Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!( tcx.def_span(def_id), @@ -167,7 +174,9 @@ pub(super) fn explicit_item_bounds_with_filter( }) => { let args = GenericArgs::identity_for_item(tcx, def_id); let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter) + let bounds = opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter); + assert_only_contains_predicates_from(filter, bounds, item_ty); + bounds } // Since RPITITs are lowered as projections in `<dyn HirTyLowerer>::lower_ty`, when we're // asking for the item bounds of the *opaques* in a trait's default method signature, we @@ -184,15 +193,18 @@ pub(super) fn explicit_item_bounds_with_filter( }; let args = GenericArgs::identity_for_item(tcx, def_id); let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - tcx.arena.alloc_slice( + let bounds = &*tcx.arena.alloc_slice( &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter) .to_vec() .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: fn_def_id.to_def_id() }), - ) + ); + assert_only_contains_predicates_from(filter, bounds, item_ty); + bounds } hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[], _ => bug!("item_bounds called on {:?}", def_id), }; + ty::EarlyBinder::bind(bounds) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 7243e85ce98..67d8813d1f7 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -240,7 +240,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen for predicate in hir_generics.predicates { match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { - let ty = icx.lower_ty(bound_pred.bounded_ty); + let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty); + let bound_vars = tcx.late_bound_vars(bound_pred.hir_id); // Keep the type around in a dummy predicate, in case of no bounds. // That way, `where Ty:` is not a complete noop (see #53696) and `Ty` @@ -676,9 +677,63 @@ pub(super) fn implied_predicates_with_filter<'tcx>( _ => {} } + assert_only_contains_predicates_from(filter, implied_bounds, tcx.types.self_param); + ty::EarlyBinder::bind(implied_bounds) } +// Make sure when elaborating supertraits, probing for associated types, etc., +// we really truly are elaborating clauses that have `Self` as their self type. +// This is very important since downstream code relies on this being correct. +pub(super) fn assert_only_contains_predicates_from<'tcx>( + filter: PredicateFilter, + bounds: &'tcx [(ty::Clause<'tcx>, Span)], + ty: Ty<'tcx>, +) { + if !cfg!(debug_assertions) { + return; + } + + match filter { + PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { + for (clause, _) in bounds { + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(trait_predicate) => { + assert_eq!( + trait_predicate.self_ty(), + ty, + "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + ty::ClauseKind::Projection(projection_predicate) => { + assert_eq!( + projection_predicate.self_ty(), + ty, + "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + ty::ClauseKind::TypeOutlives(outlives_predicate) => { + assert_eq!( + outlives_predicate.0, ty, + "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + + ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::ConstArgHasType(_, _) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) => { + bug!( + "unexpected non-`Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + } + } + } + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {} + } +} + /// Returns the predicates defined on `item_def_id` of the form /// `X: Foo` where `X` is the type parameter `def_id`. #[instrument(level = "trace", skip(tcx))] @@ -770,6 +825,10 @@ impl<'tcx> ItemCtxt<'tcx> { continue; }; + // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we + // want to only consider predicates with `Self: ...`, but we don't want + // `OnlySelfBounds(true)` since we want to collect the nested associated + // type bound as well. let (only_self_bounds, assoc_name) = match filter { PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { (OnlySelfBounds(false), None) @@ -780,14 +839,10 @@ impl<'tcx> ItemCtxt<'tcx> { } }; - // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we - // want to only consider predicates with `Self: ...`, but we don't want - // `OnlySelfBounds(true)` since we want to collect the nested associated - // type bound as well. let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) { ty } else if matches!(filter, PredicateFilter::All) { - self.lower_ty(predicate.bounded_ty) + self.lowerer().lower_ty_maybe_return_type_notation(predicate.bounded_ty) } else { continue; }; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 53dcede91c3..d1601446b6f 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -889,7 +889,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { (pair, r) }) .unzip(); + self.record_late_bound_vars(hir_id, binders); + + // If this is an RTN type in the self type, then append those to the binder. + self.try_append_return_type_notation_params(hir_id, bounded_ty); + // Even if there are no lifetimes defined here, we still wrap it in a binder // scope. If there happens to be a nested poly trait ref (an error), that // will be `Concatenating` anyways, so we don't have to worry about the depth @@ -1635,9 +1640,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // } // ``` // and a bound that looks like: - // `for<'a> T::Trait<'a, x(): for<'b> Other<'b>>` + // `for<'a> T::Trait<'a, x(..): for<'b> Other<'b>>` // this is going to expand to something like: - // `for<'a> for<'r, T> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`. + // `for<'a> for<'r> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`. if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { let bound_vars = if let Some(type_def_id) = type_def_id @@ -1839,6 +1844,178 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let old_value = self.map.defs.swap_remove(&lifetime_ref.hir_id); assert_eq!(old_value, Some(bad_def)); } + + // When we have a return type notation type in a where clause, like + // `where <T as Trait>::method(..): Send`, we need to introduce new bound + // vars to the existing where clause's binder, to represent the lifetimes + // elided by the return-type-notation syntax. + // + // For example, given + // ``` + // trait Foo { + // async fn x<'r>(); + // } + // ``` + // and a bound that looks like: + // `for<'a, 'b> <T as Trait<'a>>::x(): Other<'b>` + // this is going to expand to something like: + // `for<'a, 'b, 'r> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: Other<'b>`. + // + // We handle this similarly for associated-type-bound style return-type-notation + // in `visit_segment_args`. + fn try_append_return_type_notation_params( + &mut self, + hir_id: HirId, + hir_ty: &'tcx hir::Ty<'tcx>, + ) { + let hir::TyKind::Path(qpath) = hir_ty.kind else { + // We only care about path types here. All other self types + // (including nesting the RTN type in another type) don't do + // anything. + return; + }; + + let (mut bound_vars, item_def_id, item_segment) = match qpath { + // If we have a fully qualified method, then we don't need to do any special lookup. + hir::QPath::Resolved(_, path) + if let [.., item_segment] = &path.segments[..] + && item_segment.args.is_some_and(|args| { + matches!( + args.parenthesized, + hir::GenericArgsParentheses::ReturnTypeNotation + ) + }) => + { + match path.res { + Res::Err => return, + Res::Def(DefKind::AssocFn, item_def_id) => (vec![], item_def_id, item_segment), + _ => bug!("only expected method resolution for fully qualified RTN"), + } + } + + // If we have a type-dependent path, then we do need to do some lookup. + hir::QPath::TypeRelative(qself, item_segment) + if item_segment.args.is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + // First, ignore a qself that isn't a type or `Self` param. Those are the + // only ones that support `T::Assoc` anyways in HIR lowering. + let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind else { + return; + }; + match path.res { + Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { trait_: _ } => { + // Get the generics of this type's hir owner. This is *different* + // from the generics of the parameter's definition, since we want + // to be able to resolve an RTN path on a nested body (e.g. method + // inside an impl) using the where clauses on the method. + // FIXME(return_type_notation): Think of some better way of doing this. + let Some(generics) = self.tcx.hir_owner_node(hir_id.owner).generics() + else { + return; + }; + + // Look for the first bound that contains an associated type that + // matches the segment that we're looking for. We ignore any subsequent + // bounds since we'll be emitting a hard error in HIR lowering, so this + // is purely speculative. + let one_bound = generics.predicates.iter().find_map(|predicate| { + let hir::WherePredicate::BoundPredicate(predicate) = predicate else { + return None; + }; + let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) = + predicate.bounded_ty.kind + else { + return None; + }; + if bounded_path.res != path.res { + return None; + } + predicate.bounds.iter().find_map(|bound| { + let hir::GenericBound::Trait(trait_, _) = bound else { + return None; + }; + BoundVarContext::supertrait_hrtb_vars( + self.tcx, + trait_.trait_ref.trait_def_id()?, + item_segment.ident, + ty::AssocKind::Fn, + ) + }) + }); + let Some((bound_vars, assoc_item)) = one_bound else { + return; + }; + (bound_vars, assoc_item.def_id, item_segment) + } + // If we have a self type alias (in an impl), try to resolve an + // associated item from one of the supertraits of the impl's trait. + Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. } => { + let hir::ItemKind::Impl(hir::Impl { of_trait: Some(trait_ref), .. }) = self + .tcx + .hir_node_by_def_id(impl_def_id.expect_local()) + .expect_item() + .kind + else { + return; + }; + let Some(trait_def_id) = trait_ref.trait_def_id() else { + return; + }; + let Some((bound_vars, assoc_item)) = BoundVarContext::supertrait_hrtb_vars( + self.tcx, + trait_def_id, + item_segment.ident, + ty::AssocKind::Fn, + ) else { + return; + }; + (bound_vars, assoc_item.def_id, item_segment) + } + _ => return, + } + } + + _ => return, + }; + + // Append the early-bound vars on the function, and then the late-bound ones. + // We actually turn type parameters into higher-ranked types here, but we + // deny them later in HIR lowering. + bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| { + match param.kind { + ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( + ty::BoundRegionKind::BrNamed(param.def_id, param.name), + ), + ty::GenericParamDefKind::Type { .. } => { + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) + } + ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, + } + })); + bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars()); + + // SUBTLE: Stash the old bound vars onto the *item segment* before appending + // the new bound vars. We do this because we need to know how many bound vars + // are present on the binder explicitly (i.e. not return-type-notation vars) + // to do bound var shifting correctly in HIR lowering. + // + // For example, in `where for<'a> <T as Trait<'a>>::method(..): Other`, + // the `late_bound_vars` of the where clause predicate (i.e. this HIR ty's + // parent) will include `'a` AND all the early- and late-bound vars of the + // method. But when lowering the RTN type, we just want the list of vars + // we used to resolve the trait ref. We explicitly stored those back onto + // the item segment, since there's no other good place to put them. + // + // See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`. + // And this is exercised in: + // `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`. + let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap(); + let existing_bound_vars_saved = existing_bound_vars.clone(); + existing_bound_vars.extend(bound_vars); + self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved); + } } /// Detects late-bound lifetimes and inserts them into diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index e4e5f76ae32..4edb68e6199 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -780,14 +780,15 @@ pub(crate) struct PlaceholderNotAllowedItemSignatures { #[derive(Diagnostic)] #[diag(hir_analysis_associated_type_trait_uninferred_generic_params, code = E0212)] -pub(crate) struct AssociatedTypeTraitUninferredGenericParams { +pub(crate) struct AssociatedItemTraitUninferredGenericParams { #[primary_span] pub span: Span, #[suggestion(style = "verbose", applicability = "maybe-incorrect", code = "{bound}")] pub inferred_sugg: Option<Span>, pub bound: String, #[subdiagnostic] - pub mpart_sugg: Option<AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion>, + pub mpart_sugg: Option<AssociatedItemTraitUninferredGenericParamsMultipartSuggestion>, + pub what: &'static str, } #[derive(Subdiagnostic)] @@ -795,7 +796,7 @@ pub(crate) struct AssociatedTypeTraitUninferredGenericParams { hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion, applicability = "maybe-incorrect" )] -pub(crate) struct AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion { +pub(crate) struct AssociatedItemTraitUninferredGenericParamsMultipartSuggestion { #[suggestion_part(code = "{first}")] pub fspan: Span, pub first: String, @@ -1693,3 +1694,10 @@ pub(crate) struct CmseCallGeneric { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_bad_return_type_notation_position)] +pub(crate) struct BadReturnTypeNotation { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index bffe68f9b74..6f7f3128347 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -6,6 +6,7 @@ use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::HirId; use rustc_middle::bug; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; use rustc_span::symbol::Ident; @@ -15,6 +16,7 @@ use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, use smallvec::SmallVec; use tracing::{debug, instrument}; +use super::errors::GenericsArgsErrExtend; use crate::bounds::Bounds; use crate::errors; use crate::hir_ty_lowering::{ @@ -332,74 +334,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .or_insert(constraint.span); let projection_term = if let ty::AssocKind::Fn = assoc_kind { - let mut emitted_bad_param_err = None; - // If we have an method return type bound, then we need to instantiate - // the method's early bound params with suitable late-bound params. - let mut num_bound_vars = candidate.bound_vars().len(); - let args = - candidate.skip_binder().args.extend_to(tcx, assoc_item.def_id, |param, _| { - let arg = match param.kind { - ty::GenericParamDefKind::Lifetime => ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { - var: ty::BoundVar::from_usize(num_bound_vars), - kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), - }, - ) - .into(), - ty::GenericParamDefKind::Type { .. } => { - let guar = *emitted_bad_param_err.get_or_insert_with(|| { - self.dcx().emit_err( - crate::errors::ReturnTypeNotationIllegalParam::Type { - span: path_span, - param_span: tcx.def_span(param.def_id), - }, - ) - }); - Ty::new_error(tcx, guar).into() - } - ty::GenericParamDefKind::Const { .. } => { - let guar = *emitted_bad_param_err.get_or_insert_with(|| { - self.dcx().emit_err( - crate::errors::ReturnTypeNotationIllegalParam::Const { - span: path_span, - param_span: tcx.def_span(param.def_id), - }, - ) - }); - ty::Const::new_error(tcx, guar).into() - } - }; - num_bound_vars += 1; - arg - }); - - // Next, we need to check that the return-type notation is being used on - // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait). - let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output(); - let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind() - && tcx.is_impl_trait_in_trait(alias_ty.def_id) - { - alias_ty.into() - } else { - return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { - span: constraint.span, - ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output), - fn_span: tcx.hir().span_if_local(assoc_item.def_id), - note: (), - })); - }; - - // Finally, move the fn return type's bound vars over to account for the early bound - // params (and trait ref's late bound params). This logic is very similar to - // `rustc_middle::ty::predicate::Clause::instantiate_supertrait` - // and it's no coincidence why. - let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); - let instantiation_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args); - let bound_vars = tcx.late_bound_vars(constraint.hir_id); - ty::Binder::bind_with_vars(instantiation_output, bound_vars) + ty::Binder::bind_with_vars( + self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(), + bound_vars, + ) } else { // Create the generic arguments for the associated type or constant by joining the // parent arguments (the arguments of the trait) and the own arguments (the ones of @@ -525,6 +464,269 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } Ok(()) } + + /// Lower a type, possibly specially handling the type if it's a return type notation + /// which we otherwise deny in other positions. + pub fn lower_ty_maybe_return_type_notation(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { + let hir::TyKind::Path(qpath) = hir_ty.kind else { + return self.lower_ty(hir_ty); + }; + + let tcx = self.tcx(); + match qpath { + hir::QPath::Resolved(opt_self_ty, path) + if let [mod_segments @ .., trait_segment, item_segment] = &path.segments[..] + && item_segment.args.is_some_and(|args| { + matches!( + args.parenthesized, + hir::GenericArgsParentheses::ReturnTypeNotation + ) + }) => + { + // We don't allow generics on the module segments. + let _ = + self.prohibit_generic_args(mod_segments.iter(), GenericsArgsErrExtend::None); + + let item_def_id = match path.res { + Res::Def(DefKind::AssocFn, item_def_id) => item_def_id, + Res::Err => { + return Ty::new_error_with_message( + tcx, + hir_ty.span, + "failed to resolve RTN", + ); + } + _ => bug!("only expected method resolution for fully qualified RTN"), + }; + let trait_def_id = tcx.parent(item_def_id); + + // Good error for `where Trait::method(..): Send`. + let Some(self_ty) = opt_self_ty else { + return self.error_missing_qpath_self_ty( + trait_def_id, + hir_ty.span, + item_segment, + ); + }; + let self_ty = self.lower_ty(self_ty); + + let trait_ref = self.lower_mono_trait_ref( + hir_ty.span, + trait_def_id, + self_ty, + trait_segment, + false, + ty::BoundConstness::NotConst, + ); + + // SUBTLE: As noted at the end of `try_append_return_type_notation_params` + // in `resolve_bound_vars`, we stash the explicit bound vars of the where + // clause onto the item segment of the RTN type. This allows us to know + // how many bound vars are *not* coming from the signature of the function + // from lowering RTN itself. + // + // For example, in `where for<'a> <T as Trait<'a>>::method(..): Other`, + // the `late_bound_vars` of the where clause predicate (i.e. this HIR ty's + // parent) will include `'a` AND all the early- and late-bound vars of the + // method. But when lowering the RTN type, we just want the list of vars + // we used to resolve the trait ref. We explicitly stored those back onto + // the item segment, since there's no other good place to put them. + let candidate = + ty::Binder::bind_with_vars(trait_ref, tcx.late_bound_vars(item_segment.hir_id)); + + match self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span) { + Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty), + Err(guar) => Ty::new_error(tcx, guar), + } + } + hir::QPath::TypeRelative(qself, item_segment) + if item_segment.args.is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + match self + .resolve_type_relative_return_type_notation( + qself, + item_segment, + hir_ty.hir_id, + hir_ty.span, + ) + .and_then(|(candidate, item_def_id)| { + self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span) + }) { + Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty), + Err(guar) => Ty::new_error(tcx, guar), + } + } + _ => self.lower_ty(hir_ty), + } + } + + /// Perform type-dependent lookup for a *method* for return type notation. + /// This generally mirrors `<dyn HirTyLowerer>::lower_assoc_path`. + fn resolve_type_relative_return_type_notation( + &self, + qself: &'tcx hir::Ty<'tcx>, + item_segment: &'tcx hir::PathSegment<'tcx>, + qpath_hir_id: HirId, + span: Span, + ) -> Result<(ty::PolyTraitRef<'tcx>, DefId), ErrorGuaranteed> { + let tcx = self.tcx(); + let qself_ty = self.lower_ty(qself); + let assoc_ident = item_segment.ident; + let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind { + path.res + } else { + Res::Err + }; + + let bound = match (qself_ty.kind(), qself_res) { + (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => { + // `Self` in an impl of a trait -- we have a concrete self type and a + // trait reference. + let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else { + // A cycle error occurred, most likely. + self.dcx().span_bug(span, "expected cycle error"); + }; + + self.probe_single_bound_for_assoc_item( + || { + traits::supertraits( + tcx, + ty::Binder::dummy(trait_ref.instantiate_identity()), + ) + }, + AssocItemQSelf::SelfTyAlias, + ty::AssocKind::Fn, + assoc_ident, + span, + None, + )? + } + ( + &ty::Param(_), + Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), + ) => self.probe_single_ty_param_bound_for_assoc_item( + param_did.expect_local(), + qself.span, + ty::AssocKind::Fn, + assoc_ident, + span, + )?, + _ => { + if let Err(reported) = qself_ty.error_reported() { + return Err(reported); + } else { + // FIXME(return_type_notation): Provide some structured suggestion here. + let err = struct_span_code_err!( + self.dcx(), + span, + E0223, + "ambiguous associated function" + ); + return Err(err.emit()); + } + } + }; + + // Don't let `T::method` resolve to some `for<'a> <T as Tr<'a>>::method`, + // which may happen via a higher-ranked where clause or supertrait. + // This is the same restrictions as associated types; even though we could + // support it, it just makes things a lot more difficult to support in + // `resolve_bound_vars`, since we'd need to introduce those as elided + // bound vars on the where clause too. + if bound.has_bound_vars() { + return Err(self.tcx().dcx().emit_err( + errors::AssociatedItemTraitUninferredGenericParams { + span, + inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())), + bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),), + mpart_sugg: None, + what: "function", + }, + )); + } + + let trait_def_id = bound.def_id(); + let assoc_ty = self + .probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id) + .expect("failed to find associated type"); + + Ok((bound, assoc_ty.def_id)) + } + + /// Do the common parts of lowering an RTN type. This involves extending the + /// candidate binder to include all of the early- and late-bound vars that are + /// defined on the function itself, and constructing a projection to the RPITIT + /// return type of that function. + fn lower_return_type_notation_ty( + &self, + candidate: ty::PolyTraitRef<'tcx>, + item_def_id: DefId, + path_span: Span, + ) -> Result<ty::AliasTy<'tcx>, ErrorGuaranteed> { + let tcx = self.tcx(); + let mut emitted_bad_param_err = None; + // If we have an method return type bound, then we need to instantiate + // the method's early bound params with suitable late-bound params. + let mut num_bound_vars = candidate.bound_vars().len(); + let args = candidate.skip_binder().args.extend_to(tcx, item_def_id, |param, _| { + let arg = match param.kind { + ty::GenericParamDefKind::Lifetime => ty::Region::new_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(num_bound_vars), + kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), + }, + ) + .into(), + ty::GenericParamDefKind::Type { .. } => { + let guar = *emitted_bad_param_err.get_or_insert_with(|| { + self.dcx().emit_err(crate::errors::ReturnTypeNotationIllegalParam::Type { + span: path_span, + param_span: tcx.def_span(param.def_id), + }) + }); + Ty::new_error(tcx, guar).into() + } + ty::GenericParamDefKind::Const { .. } => { + let guar = *emitted_bad_param_err.get_or_insert_with(|| { + self.dcx().emit_err(crate::errors::ReturnTypeNotationIllegalParam::Const { + span: path_span, + param_span: tcx.def_span(param.def_id), + }) + }); + ty::Const::new_error(tcx, guar).into() + } + }; + num_bound_vars += 1; + arg + }); + + // Next, we need to check that the return-type notation is being used on + // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait). + let output = tcx.fn_sig(item_def_id).skip_binder().output(); + let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind() + && tcx.is_impl_trait_in_trait(alias_ty.def_id) + { + alias_ty + } else { + return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { + span: path_span, + ty: tcx.liberate_late_bound_regions(item_def_id, output), + fn_span: tcx.hir().span_if_local(item_def_id), + note: (), + })); + }; + + // Finally, move the fn return type's bound vars over to account for the early bound + // params (and trait ref's late bound params). This logic is very similar to + // `rustc_middle::ty::predicate::Clause::instantiate_supertrait` + // and it's no coincidence why. + let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); + Ok(ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args)) + } } /// Detect and reject early-bound & escaping late-bound generic params in the type of assoc const bindings. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 7163352e8a4..35eebcb6be1 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -53,7 +53,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::{debug, debug_span, instrument}; use crate::bounds::Bounds; -use crate::errors::{AmbiguousLifetimeBound, WildPatTy}; +use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy}; use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; @@ -719,6 +719,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span, polarity, constness, + only_self_bounds, ); let mut dup_constraints = FxIndexMap::default(); @@ -813,17 +814,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Search for a trait bound on a type parameter whose trait defines the associated type given by `assoc_name`. + /// Search for a trait bound on a type parameter whose trait defines the associated item + /// given by `assoc_name` and `kind`. /// /// This fails if there is no such bound in the list of candidates or if there are multiple /// candidates in which case it reports ambiguity. /// /// `ty_param_def_id` is the `LocalDefId` of the type parameter. #[instrument(level = "debug", skip_all, ret)] - fn probe_single_ty_param_bound_for_assoc_ty( + fn probe_single_ty_param_bound_for_assoc_item( &self, ty_param_def_id: LocalDefId, ty_param_span: Span, + kind: ty::AssocKind, assoc_name: Ident, span: Span, ) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> { @@ -841,7 +844,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_name) }, AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span), - ty::AssocKind::Type, + kind, assoc_name, span, None, @@ -1081,9 +1084,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ( &ty::Param(_), Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), - ) => self.probe_single_ty_param_bound_for_assoc_ty( + ) => self.probe_single_ty_param_bound_for_assoc_item( param_did.expect_local(), qself.span, + ty::AssocKind::Type, assoc_ident, span, )?, @@ -1545,48 +1549,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?trait_def_id); let Some(self_ty) = opt_self_ty else { - let path_str = tcx.def_path_str(trait_def_id); - - let def_id = self.item_def_id(); - debug!(item_def_id = ?def_id); - - // FIXME: document why/how this is different from `tcx.local_parent(def_id)` - let parent_def_id = - tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id(); - debug!(?parent_def_id); - - // If the trait in segment is the same as the trait defining the item, - // use the `<Self as ..>` syntax in the error. - let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id; - let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id; - - let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { - vec!["Self".to_string()] - } else { - // Find all the types that have an `impl` for the trait. - tcx.all_impls(trait_def_id) - .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id)) - .filter(|header| { - // Consider only accessible traits - tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx) - && header.polarity != ty::ImplPolarity::Negative - }) - .map(|header| header.trait_ref.instantiate_identity().self_ty()) - // We don't care about blanket impls. - .filter(|self_ty| !self_ty.has_non_region_param()) - .map(|self_ty| tcx.erase_regions(self_ty).to_string()) - .collect() - }; - // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that - // references the trait. Relevant for the first case in - // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` - let reported = self.report_ambiguous_assoc_ty( - span, - &type_names, - &[path_str], - item_segment.ident.name, - ); - return Ty::new_error(tcx, reported); + return self.error_missing_qpath_self_ty(trait_def_id, span, item_segment); }; debug!(?self_ty); @@ -1600,6 +1563,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_projection_from_args(tcx, item_def_id, item_args) } + fn error_missing_qpath_self_ty( + &self, + trait_def_id: DefId, + span: Span, + item_segment: &hir::PathSegment<'tcx>, + ) -> Ty<'tcx> { + let tcx = self.tcx(); + let path_str = tcx.def_path_str(trait_def_id); + + let def_id = self.item_def_id(); + debug!(item_def_id = ?def_id); + + // FIXME: document why/how this is different from `tcx.local_parent(def_id)` + let parent_def_id = + tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id(); + debug!(?parent_def_id); + + // If the trait in segment is the same as the trait defining the item, + // use the `<Self as ..>` syntax in the error. + let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id; + let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id; + + let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { + vec!["Self".to_string()] + } else { + // Find all the types that have an `impl` for the trait. + tcx.all_impls(trait_def_id) + .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id)) + .filter(|header| { + // Consider only accessible traits + tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx) + && header.polarity != ty::ImplPolarity::Negative + }) + .map(|header| header.trait_ref.instantiate_identity().self_ty()) + // We don't care about blanket impls. + .filter(|self_ty| !self_ty.has_non_region_param()) + .map(|self_ty| tcx.erase_regions(self_ty).to_string()) + .collect() + }; + // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that + // references the trait. Relevant for the first case in + // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` + let reported = + self.report_ambiguous_assoc_ty(span, &type_names, &[path_str], item_segment.ident.name); + Ty::new_error(tcx, reported) + } + pub fn prohibit_generic_args<'a>( &self, segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone, @@ -1930,7 +1940,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .tcx() .dcx() .span_delayed_bug(path.span, "path with `Res::Err` but no error emitted"); - Ty::new_error(self.tcx(), e) + Ty::new_error(tcx, e) } Res::Def(..) => { assert_eq!( @@ -2061,6 +2071,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr) } + // If we encounter a fully qualified path with RTN generics, then it must have + // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore + // it's certainly in an illegal position. + hir::TyKind::Path(hir::QPath::Resolved(_, path)) + if path.segments.last().and_then(|segment| segment.args).is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); + Ty::new_error(tcx, guar) + } hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); @@ -2085,6 +2106,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } } + // If we encounter a type relative path with RTN generics, then it must have + // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore + // it's certainly in an illegal position. + hir::TyKind::Path(hir::QPath::TypeRelative(_, segment)) + if segment.args.is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); + Ty::new_error(tcx, guar) + } hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => { debug!(?qself, ?segment); let ty = self.lower_ty(qself); diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index f39d83a2a6f..81d940a3f9b 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("{v} bits") } else { // `u128` should definitely be able to hold the size of different architectures - // larger sizes should be reported as error `are too big for the current architecture` + // larger sizes should be reported as error `are too big for the target architecture` // otherwise we have a bug somewhere bug!("{:?} overflow for u128", size) } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index d81052b5e24..ce4ee45c485 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -332,6 +332,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { return; } + // Issue #45127: don't enforce `snake_case` for binary crates as binaries are not intended + // to be distributed and depended on like libraries. The lint is not suppressed for cdylib + // or staticlib because it's not clear what the desired lint behavior for those are. if cx.tcx.crate_types().iter().all(|&crate_type| crate_type == CrateType::Executable) { return; } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f9d0cd49708..3d042f21745 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1320,7 +1320,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } fn is_internal_abi(&self, abi: SpecAbi) -> bool { - matches!(abi, SpecAbi::Rust | SpecAbi::RustCall | SpecAbi::RustIntrinsic) + matches!( + abi, + SpecAbi::Rust | SpecAbi::RustCall | SpecAbi::RustCold | SpecAbi::RustIntrinsic + ) } /// Find any fn-ptr types with external ABIs in `ty`. diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 2b9d9a07a98..39485a324f2 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -103,5 +103,5 @@ middle_unknown_layout = the type `{$ty}` has an unknown layout middle_values_too_big = - values of the type `{$ty}` are too big for the current architecture + values of the type `{$ty}` are too big for the target architecture middle_written_to_path = the full type name has been written to '{$path}' diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index b7d290e58d2..90dff0f5c7d 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -120,9 +120,7 @@ bitflags::bitflags! { /// #[ffi_const]: applies clang's `const` attribute to a foreign function /// declaration. const FFI_CONST = 1 << 12; - /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a - /// function as an entry function from Non-Secure code. - const CMSE_NONSECURE_ENTRY = 1 << 13; + // (Bit 13 was used for `#[cmse_nonsecure_entry]`, but is now unused.) // (Bit 14 was used for `#[coverage(off)]`, but is now unused.) /// `#[used(linker)]`: /// indicates that neither LLVM nor the linker will eliminate this function. diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 183b898253e..63ce47ef327 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -71,7 +71,7 @@ impl<'tcx> BasicBlocks<'tcx> { #[inline] pub fn reverse_postorder(&self) -> &[BasicBlock] { self.cache.reverse_postorder.get_or_init(|| { - let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK).collect(); + let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK, ()).collect(); rpo.reverse(); rpo }) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e312e65cc21..54dcfaf5d54 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1424,6 +1424,19 @@ impl<'tcx> BasicBlockData<'tcx> { pub fn is_empty_unreachable(&self) -> bool { self.statements.is_empty() && matches!(self.terminator().kind, TerminatorKind::Unreachable) } + + /// Like [`Terminator::successors`] but tries to use information available from the [`Instance`] + /// to skip successors like the `false` side of an `if const {`. + /// + /// This is used to implement [`traversal::mono_reachable`] and + /// [`traversal::mono_reachable_reverse_postorder`]. + pub fn mono_successors(&self, tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Successors<'_> { + if let Some((bits, targets)) = Body::try_const_mono_switchint(tcx, instance, self) { + targets.successors_for_value(bits) + } else { + self.terminator().successors() + } + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 962b93a25aa..c34e22eb873 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -413,6 +413,17 @@ mod helper { use super::*; pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a; pub type SuccessorsMut<'a> = impl DoubleEndedIterator<Item = &'a mut BasicBlock> + 'a; + + impl SwitchTargets { + /// Like [`SwitchTargets::target_for_value`], but returning the same type as + /// [`Terminator::successors`]. + #[inline] + pub fn successors_for_value(&self, value: u128) -> Successors<'_> { + let target = self.target_for_value(value); + (&[]).into_iter().copied().chain(Some(target)) + } + } + impl<'tcx> TerminatorKind<'tcx> { #[inline] pub fn successors(&self) -> Successors<'_> { diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 245e9096bad..b8b74da401c 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -104,36 +104,46 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { /// ``` /// /// A Postorder traversal of this graph is `D B C A` or `D C B A` -pub struct Postorder<'a, 'tcx> { +pub struct Postorder<'a, 'tcx, C> { basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>, visited: BitSet<BasicBlock>, visit_stack: Vec<(BasicBlock, Successors<'a>)>, root_is_start_block: bool, + extra: C, } -impl<'a, 'tcx> Postorder<'a, 'tcx> { +impl<'a, 'tcx, C> Postorder<'a, 'tcx, C> +where + C: Customization<'tcx>, +{ pub fn new( basic_blocks: &'a IndexSlice<BasicBlock, BasicBlockData<'tcx>>, root: BasicBlock, - ) -> Postorder<'a, 'tcx> { + extra: C, + ) -> Postorder<'a, 'tcx, C> { let mut po = Postorder { basic_blocks, visited: BitSet::new_empty(basic_blocks.len()), visit_stack: Vec::new(), root_is_start_block: root == START_BLOCK, + extra, }; - let data = &po.basic_blocks[root]; - - if let Some(ref term) = data.terminator { - po.visited.insert(root); - po.visit_stack.push((root, term.successors())); - po.traverse_successor(); - } + po.visit(root); + po.traverse_successor(); po } + fn visit(&mut self, bb: BasicBlock) { + if !self.visited.insert(bb) { + return; + } + let data = &self.basic_blocks[bb]; + let successors = C::successors(data, self.extra); + self.visit_stack.push((bb, successors)); + } + fn traverse_successor(&mut self) { // This is quite a complex loop due to 1. the borrow checker not liking it much // and 2. what exactly is going on is not clear @@ -183,16 +193,15 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // since we've already visited `E`, that child isn't added to the stack. The last // two iterations yield `B` and finally `A` for a final traversal of [E, D, C, B, A] while let Some(bb) = self.visit_stack.last_mut().and_then(|(_, iter)| iter.next_back()) { - if self.visited.insert(bb) { - if let Some(term) = &self.basic_blocks[bb].terminator { - self.visit_stack.push((bb, term.successors())); - } - } + self.visit(bb); } } } -impl<'tcx> Iterator for Postorder<'_, 'tcx> { +impl<'tcx, C> Iterator for Postorder<'_, 'tcx, C> +where + C: Customization<'tcx>, +{ type Item = BasicBlock; fn next(&mut self) -> Option<BasicBlock> { @@ -232,6 +241,40 @@ pub fn postorder<'a, 'tcx>( reverse_postorder(body).rev() } +/// Lets us plug in some additional logic and data into a Postorder traversal. Or not. +pub trait Customization<'tcx>: Copy { + fn successors<'a>(_: &'a BasicBlockData<'tcx>, _: Self) -> Successors<'a>; +} + +impl<'tcx> Customization<'tcx> for () { + fn successors<'a>(data: &'a BasicBlockData<'tcx>, _: ()) -> Successors<'a> { + data.terminator().successors() + } +} + +impl<'tcx> Customization<'tcx> for (TyCtxt<'tcx>, Instance<'tcx>) { + fn successors<'a>( + data: &'a BasicBlockData<'tcx>, + (tcx, instance): (TyCtxt<'tcx>, Instance<'tcx>), + ) -> Successors<'a> { + data.mono_successors(tcx, instance) + } +} + +pub fn mono_reachable_reverse_postorder<'a, 'tcx>( + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, +) -> Vec<BasicBlock> { + let mut iter = Postorder::new(&body.basic_blocks, START_BLOCK, (tcx, instance)); + let mut items = Vec::with_capacity(body.basic_blocks.len()); + while let Some(block) = iter.next() { + items.push(block); + } + items.reverse(); + items +} + /// Returns an iterator over all basic blocks reachable from the `START_BLOCK` in no particular /// order. /// @@ -358,14 +401,8 @@ impl<'a, 'tcx> Iterator for MonoReachable<'a, 'tcx> { let data = &self.body[idx]; - if let Some((bits, targets)) = - Body::try_const_mono_switchint(self.tcx, self.instance, data) - { - let target = targets.target_for_value(bits); - self.add_work([target]); - } else { - self.add_work(data.terminator().successors()); - } + let targets = data.mono_successors(self.tcx, self.instance); + self.add_work(targets); return Some((idx, data)); } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 877c54c5649..941091b71d3 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -264,7 +264,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { match *self { LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"), LayoutError::SizeOverflow(ty) => { - write!(f, "values of the type `{ty}` are too big for the current architecture") + write!(f, "values of the type `{ty}` are too big for the target architecture") } LayoutError::NormalizationFailure(t, e) => write!( f, @@ -1191,6 +1191,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) -> | RiscvInterruptM | RiscvInterruptS | CCmseNonSecureCall + | CCmseNonSecureEntry | Unadjusted => false, Rust | RustCall | RustCold | RustIntrinsic => { tcx.sess.panic_strategy() == PanicStrategy::Unwind diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2f4dc8abfcd..841f255dc3a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -188,9 +188,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_must_implement_one_of, ..] | [sym::rustc_deny_explicit_impl, ..] | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), - [sym::cmse_nonsecure_entry, ..] => { - self.check_cmse_nonsecure_entry(hir_id, attr, span, target) - } [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), @@ -563,27 +560,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[cmse_nonsecure_entry]` is applied to a function definition. - fn check_cmse_nonsecure_entry( - &self, - hir_id: HirId, - attr: &Attribute, - span: Span, - target: Target, - ) { - match target { - Target::Fn - | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {} - _ => { - self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span, - defn_span: span, - on_crate: hir_id == CRATE_HIR_ID, - }); - } - } - } - /// Debugging aid for `object_lifetime_default` query. fn check_object_lifetime_default(&self, hir_id: HirId) { let tcx = self.tcx; diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 6458c888431..fc9d8f998dc 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -138,6 +138,61 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { ); assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation"); } + + /// Determines whether the const argument `AnonConst` is a simple macro call, optionally + /// surrounded with braces. + /// + /// If this const argument *is* a trivial macro call then the id for the macro call is + /// returned along with the information required to build the anon const's def if + /// the macro call expands to a non-trivial expression. + fn is_const_arg_trivial_macro_expansion( + &self, + anon_const: &'a AnonConst, + ) -> Option<(PendingAnonConstInfo, NodeId)> { + let (block_was_stripped, expr) = anon_const.value.maybe_unwrap_block(); + match expr { + Expr { kind: ExprKind::MacCall(..), id, .. } => Some(( + PendingAnonConstInfo { + id: anon_const.id, + span: anon_const.value.span, + block_was_stripped, + }, + *id, + )), + _ => None, + } + } + + /// Determines whether the expression `const_arg_sub_expr` is a simple macro call, sometimes + /// surrounded with braces if a set of braces has not already been entered. This is required + /// as `{ N }` is treated as equivalent to a bare parameter `N` whereas `{{ N }}` is treated as + /// a real block expression and is lowered to an anonymous constant which is not allowed to use + /// generic parameters. + /// + /// If this expression is a trivial macro call then the id for the macro call is + /// returned along with the information required to build the anon const's def if + /// the macro call expands to a non-trivial expression. + fn is_const_arg_sub_expr_trivial_macro_expansion( + &self, + const_arg_sub_expr: &'a Expr, + ) -> Option<(PendingAnonConstInfo, NodeId)> { + let pending_anon = self.pending_anon_const_info.unwrap_or_else(|| + panic!("Checking expr is trivial macro call without having entered anon const: `{const_arg_sub_expr:?}`"), + ); + + let (block_was_stripped, expr) = if pending_anon.block_was_stripped { + (true, const_arg_sub_expr) + } else { + const_arg_sub_expr.maybe_unwrap_block() + }; + + match expr { + Expr { kind: ExprKind::MacCall(..), id, .. } => { + Some((PendingAnonConstInfo { block_was_stripped, ..pending_anon }, *id)) + } + _ => None, + } + } } impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { @@ -354,12 +409,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // items will be messed up, but that's ok because there can't be any if we're just looking // for bare idents. - if matches!(constant.value.maybe_unwrap_block().kind, ExprKind::MacCall(..)) { - // See self.pending_anon_const_info for explanation - self.pending_anon_const_info = - Some(PendingAnonConstInfo { id: constant.id, span: constant.value.span }); - return visit::walk_anon_const(self, constant); - } else if constant.value.is_potential_trivial_const_arg() { + if let Some((pending_anon, macro_invoc)) = + self.is_const_arg_trivial_macro_expansion(constant) + { + self.pending_anon_const_info = Some(pending_anon); + return self.visit_macro_invoc(macro_invoc); + } else if constant.value.is_potential_trivial_const_arg(true) { return visit::walk_anon_const(self, constant); } @@ -368,23 +423,36 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_expr(&mut self, expr: &'a Expr) { - if matches!(expr.kind, ExprKind::MacCall(..)) { - return self.visit_macro_invoc(expr.id); + // If we're visiting the expression of a const argument that was a macro call then + // check if it is *still* unknown whether it is a trivial const arg or not. If so + // recurse into the macro call and delay creating the anon const def until expansion. + if self.pending_anon_const_info.is_some() + && let Some((pending_anon, macro_invoc)) = + self.is_const_arg_sub_expr_trivial_macro_expansion(expr) + { + self.pending_anon_const_info = Some(pending_anon); + return self.visit_macro_invoc(macro_invoc); } - let grandparent_def = if let Some(pending_anon) = self.pending_anon_const_info.take() { - // See self.pending_anon_const_info for explanation - if !expr.is_potential_trivial_const_arg() { + // See self.pending_anon_const_info for explanation + let parent_def = self + .pending_anon_const_info + .take() + // If we already stripped away a set of braces then do not do it again when determining + // if the macro expanded to a trivial const arg. This arises in cases such as: + // `Foo<{ bar!() }>` where `bar!()` expands to `{ N }`. This should not be considered a + // trivial const argument even though `{ N }` by itself *is*. + .filter(|pending_anon| { + !expr.is_potential_trivial_const_arg(!pending_anon.block_was_stripped) + }) + .map(|pending_anon| { self.create_def(pending_anon.id, kw::Empty, DefKind::AnonConst, pending_anon.span) - } else { - self.parent_def - } - } else { - self.parent_def - }; + }) + .unwrap_or(self.parent_def); - self.with_parent(grandparent_def, |this| { + self.with_parent(parent_def, |this| { let parent_def = match expr.kind { + ExprKind::MacCall(..) => return this.visit_macro_invoc(expr.id), ExprKind::Closure(..) | ExprKind::Gen(..) => { this.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ac03a3ac42c..4c84e3621dc 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -404,6 +404,8 @@ pub(crate) enum PathSource<'a> { Delegation, /// An arg in a `use<'a, N>` precise-capturing bound. PreciseCapturingArg(Namespace), + // Paths that end with `(..)`, for return type notation. + ReturnTypeNotation, } impl<'a> PathSource<'a> { @@ -413,7 +415,8 @@ impl<'a> PathSource<'a> { PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) - | PathSource::Delegation => ValueNS, + | PathSource::Delegation + | PathSource::ReturnTypeNotation => ValueNS, PathSource::TraitItem(ns) => ns, PathSource::PreciseCapturingArg(ns) => ns, } @@ -425,7 +428,8 @@ impl<'a> PathSource<'a> { | PathSource::Expr(..) | PathSource::Pat | PathSource::Struct - | PathSource::TupleStruct(..) => true, + | PathSource::TupleStruct(..) + | PathSource::ReturnTypeNotation => true, PathSource::Trait(_) | PathSource::TraitItem(..) | PathSource::Delegation @@ -471,7 +475,7 @@ impl<'a> PathSource<'a> { }, _ => "value", }, - PathSource::Delegation => "function", + PathSource::ReturnTypeNotation | PathSource::Delegation => "function", PathSource::PreciseCapturingArg(..) => "type or const parameter", } } @@ -540,6 +544,10 @@ impl<'a> PathSource<'a> { Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true, _ => false, }, + PathSource::ReturnTypeNotation => match res { + Res::Def(DefKind::AssocFn, _) => true, + _ => false, + }, PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)), PathSource::PreciseCapturingArg(ValueNS) => { matches!(res, Res::Def(DefKind::ConstParam, _)) @@ -565,8 +573,8 @@ impl<'a> PathSource<'a> { (PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425, (PathSource::Pat | PathSource::TupleStruct(..), true) => E0532, (PathSource::Pat | PathSource::TupleStruct(..), false) => E0531, - (PathSource::TraitItem(..), true) => E0575, - (PathSource::TraitItem(..), false) => E0576, + (PathSource::TraitItem(..), true) | (PathSource::ReturnTypeNotation, true) => E0575, + (PathSource::TraitItem(..), false) | (PathSource::ReturnTypeNotation, false) => E0576, (PathSource::PreciseCapturingArg(..), true) => E0799, (PathSource::PreciseCapturingArg(..), false) => E0800, } @@ -781,7 +789,20 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r } TyKind::Path(qself, path) => { self.diag_metadata.current_type_path = Some(ty); - self.smart_resolve_path(ty.id, qself, path, PathSource::Type); + + // If we have a path that ends with `(..)`, then it must be + // return type notation. Resolve that path in the *value* + // namespace. + let source = if let Some(seg) = path.segments.last() + && let Some(args) = &seg.args + && matches!(**args, GenericArgs::ParenthesizedElided(..)) + { + PathSource::ReturnTypeNotation + } else { + PathSource::Type + }; + + self.smart_resolve_path(ty.id, qself, path, source); // Check whether we should interpret this as a bare trait object. if qself.is_none() @@ -1920,7 +1941,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type - | PathSource::PreciseCapturingArg(..) => false, + | PathSource::PreciseCapturingArg(..) + | PathSource::ReturnTypeNotation => false, PathSource::Expr(..) | PathSource::Pat | PathSource::Struct @@ -4524,7 +4546,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); self.resolve_anon_const_manual( - constant.value.is_potential_trivial_const_arg(), + constant.value.is_potential_trivial_const_arg(true), anon_const_kind, |this| this.resolve_expr(&constant.value, None), ) @@ -4688,7 +4710,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // that is how they will be later lowered to HIR. if const_args.contains(&idx) { self.resolve_anon_const_manual( - argument.is_potential_trivial_const_arg(), + argument.is_potential_trivial_const_arg(true), AnonConstKind::ConstArg(IsRepeatExpr::No), |this| this.resolve_expr(argument, None), ); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c05bd9e72ea..3bb1f6b52a7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -190,6 +190,11 @@ impl InvocationParent { #[derive(Copy, Debug, Clone)] struct PendingAnonConstInfo { + // A const arg is only a "trivial" const arg if it has at *most* one set of braces + // around the argument. We track whether we have stripped an outter brace so that + // if a macro expands to a braced expression *and* the macro was itself inside of + // some braces then we can consider it to be a non-trivial const argument. + block_was_stripped: bool, id: NodeId, span: Span, } diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index f52cb010a87..e9c3b3ffc1d 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -470,6 +470,7 @@ impl RustcInternal for Abi { Abi::AvrInterrupt => rustc_target::spec::abi::Abi::AvrInterrupt, Abi::AvrNonBlockingInterrupt => rustc_target::spec::abi::Abi::AvrNonBlockingInterrupt, Abi::CCmseNonSecureCall => rustc_target::spec::abi::Abi::CCmseNonSecureCall, + Abi::CCmseNonSecureEntry => rustc_target::spec::abi::Abi::CCmseNonSecureEntry, Abi::System { unwind } => rustc_target::spec::abi::Abi::System { unwind }, Abi::RustIntrinsic => rustc_target::spec::abi::Abi::RustIntrinsic, Abi::RustCall => rustc_target::spec::abi::Abi::RustCall, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 9f554ec6c35..06f01aebf9b 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -105,6 +105,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv { Conv::PreserveAll => CallConvention::PreserveAll, Conv::ArmAapcs => CallConvention::ArmAapcs, Conv::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, + Conv::CCmseNonSecureEntry => CallConvention::CCmseNonSecureEntry, Conv::Msp430Intr => CallConvention::Msp430Intr, Conv::PtxKernel => CallConvention::PtxKernel, Conv::X86Fastcall => CallConvention::X86Fastcall, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index efbb0f244fc..74bdf97ac44 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -910,6 +910,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::spec::abi::Abi { abi::Abi::AvrInterrupt => Abi::AvrInterrupt, abi::Abi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, abi::Abi::CCmseNonSecureCall => Abi::CCmseNonSecureCall, + abi::Abi::CCmseNonSecureEntry => Abi::CCmseNonSecureEntry, abi::Abi::System { unwind } => Abi::System { unwind }, abi::Abi::RustIntrinsic => Abi::RustIntrinsic, abi::Abi::RustCall => Abi::RustCall, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 060ee4a1bc2..f4469467249 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -779,6 +779,7 @@ pub enum Conv { // Target-specific calling conventions. ArmAapcs, CCmseNonSecureCall, + CCmseNonSecureEntry, Msp430Intr, @@ -972,6 +973,7 @@ impl FromStr for Conv { "RustCold" => Ok(Conv::Rust), "ArmAapcs" => Ok(Conv::ArmAapcs), "CCmseNonSecureCall" => Ok(Conv::CCmseNonSecureCall), + "CCmseNonSecureEntry" => Ok(Conv::CCmseNonSecureEntry), "Msp430Intr" => Ok(Conv::Msp430Intr), "PtxKernel" => Ok(Conv::PtxKernel), "X86Fastcall" => Ok(Conv::X86Fastcall), diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index 9436e34d380..5fcf5be101f 100644 --- a/compiler/rustc_target/src/json.rs +++ b/compiler/rustc_target/src/json.rs @@ -103,6 +103,7 @@ impl ToJson for crate::abi::call::Conv { Self::PreserveAll => "PreserveAll", Self::ArmAapcs => "ArmAapcs", Self::CCmseNonSecureCall => "CCmseNonSecureCall", + Self::CCmseNonSecureEntry => "CCmseNonSecureEntry", Self::Msp430Intr => "Msp430Intr", Self::PtxKernel => "PtxKernel", Self::X86Fastcall => "X86Fastcall", diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs index cc383f88fbc..cac0cf9959d 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_target/src/spec/abi/mod.rs @@ -48,6 +48,7 @@ pub enum Abi { AvrInterrupt, AvrNonBlockingInterrupt, CCmseNonSecureCall, + CCmseNonSecureEntry, System { unwind: bool, }, @@ -124,6 +125,7 @@ const AbiDatas: &[AbiData] = &[ AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" }, AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" }, AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" }, + AbiData { abi: Abi::CCmseNonSecureEntry, name: "C-cmse-nonsecure-entry" }, AbiData { abi: Abi::System { unwind: false }, name: "system" }, AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" }, AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" }, @@ -244,6 +246,10 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> { feature: sym::abi_c_cmse_nonsecure_call, explain: "C-cmse-nonsecure-call ABI is experimental and subject to change", }), + "C-cmse-nonsecure-entry" => Err(AbiDisabled::Unstable { + feature: sym::cmse_nonsecure_entry, + explain: "C-cmse-nonsecure-entry ABI is experimental and subject to change", + }), _ => Err(AbiDisabled::Unrecognized), } } @@ -286,15 +292,16 @@ impl Abi { AvrInterrupt => 23, AvrNonBlockingInterrupt => 24, CCmseNonSecureCall => 25, + CCmseNonSecureEntry => 26, // Cross-platform ABIs - System { unwind: false } => 26, - System { unwind: true } => 27, - RustIntrinsic => 28, - RustCall => 29, - Unadjusted => 30, - RustCold => 31, - RiscvInterruptM => 32, - RiscvInterruptS => 33, + System { unwind: false } => 27, + System { unwind: true } => 28, + RustIntrinsic => 29, + RustCall => 30, + Unadjusted => 31, + RustCold => 32, + RiscvInterruptM => 33, + RiscvInterruptS => 34, }; debug_assert!( AbiDatas diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1d478f84c43..ec4f5ef79d1 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2724,7 +2724,10 @@ impl Target { } X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]), Aapcs { .. } => "arm" == self.arch, - CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]), + CCmseNonSecureCall | CCmseNonSecureEntry => { + ["thumbv8m.main-none-eabi", "thumbv8m.main-none-eabihf", "thumbv8m.base-none-eabi"] + .contains(&&self.llvm_target[..]) + } Win64 { .. } | SysV64 { .. } => self.arch == "x86_64", PtxKernel => self.arch == "nvptx64", Msp430Interrupt => self.arch == "msp430", diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 2de6ee9cf91..1f11ee3f939 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2269,12 +2269,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } rustc_transmute::Reason::SrcSizeOverflow => { format!( - "values of the type `{src}` are too big for the current architecture" + "values of the type `{src}` are too big for the target architecture" ) } rustc_transmute::Reason::DstSizeOverflow => { format!( - "values of the type `{dst}` are too big for the current architecture" + "values of the type `{dst}` are too big for the target architecture" ) } rustc_transmute::Reason::DstHasStricterAlignment { diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 2d0c2e83690..00d38350b20 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -312,6 +312,7 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv { SysV64 { .. } => Conv::X86_64SysV, Aapcs { .. } => Conv::ArmAapcs, CCmseNonSecureCall => Conv::CCmseNonSecureCall, + CCmseNonSecureEntry => Conv::CCmseNonSecureEntry, PtxKernel => Conv::PtxKernel, Msp430Interrupt => Conv::Msp430Intr, X86Interrupt => Conv::X86Intr, diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index 317bec3050c..dc73d9c2188 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -433,6 +433,7 @@ pub enum CallConvention { // Target-specific calling conventions. ArmAapcs, CCmseNonSecureCall, + CCmseNonSecureEntry, Msp430Intr, diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 5bad3d5ae7a..011d19f6143 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -1062,6 +1062,7 @@ pub enum Abi { AvrInterrupt, AvrNonBlockingInterrupt, CCmseNonSecureCall, + CCmseNonSecureEntry, System { unwind: bool }, RustIntrinsic, RustCall, |
