diff options
Diffstat (limited to 'compiler')
145 files changed, 2562 insertions, 1862 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 42741bdca22..f433f2eca1a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1188,14 +1188,7 @@ impl Expr { /// /// 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 = if let ExprKind::Block(block, None) = &self.kind - && let [stmt] = block.stmts.as_slice() - && let StmtKind::Expr(expr) = &stmt.kind - { - expr - } else { - self - }; + let this = self.maybe_unwrap_block(); if let ExprKind::Path(None, path) = &this.kind && path.is_potential_trivial_const_arg() @@ -1206,6 +1199,17 @@ impl Expr { } } + pub fn maybe_unwrap_block(&self) -> &Expr { + if let ExprKind::Block(block, None) = &self.kind + && let [stmt] = block.stmts.as_slice() + && let StmtKind::Expr(expr) = &stmt.kind + { + expr + } else { + self + } + } + pub fn to_bound(&self) -> Option<GenericBound> { match &self.kind { ExprKind::Path(None, path) => Some(GenericBound::Trait( @@ -2602,12 +2606,12 @@ impl CoroutineKind { } } - pub fn is_async(self) -> bool { - matches!(self, CoroutineKind::Async { .. }) - } - - pub fn is_gen(self) -> bool { - matches!(self, CoroutineKind::Gen { .. }) + pub fn as_str(self) -> &'static str { + match self { + CoroutineKind::Async { .. } => "async", + CoroutineKind::Gen { .. } => "gen", + CoroutineKind::AsyncGen { .. } => "async gen", + } } pub fn closure_id(self) -> NodeId { @@ -3486,7 +3490,7 @@ impl From<ForeignItemKind> for ItemKind { fn from(foreign_item_kind: ForeignItemKind) -> ItemKind { match foreign_item_kind { ForeignItemKind::Static(box static_foreign_item) => { - ItemKind::Static(Box::new(static_foreign_item.into())) + ItemKind::Static(Box::new(static_foreign_item)) } ForeignItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind), ForeignItemKind::TyAlias(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind), @@ -3500,9 +3504,7 @@ impl TryFrom<ItemKind> for ForeignItemKind { fn try_from(item_kind: ItemKind) -> Result<ForeignItemKind, ItemKind> { Ok(match item_kind { - ItemKind::Static(box static_item) => { - ForeignItemKind::Static(Box::new(static_item.into())) - } + ItemKind::Static(box static_item) => ForeignItemKind::Static(Box::new(static_item)), ItemKind::Fn(fn_kind) => ForeignItemKind::Fn(fn_kind), ItemKind::TyAlias(ty_alias_kind) => ForeignItemKind::TyAlias(ty_alias_kind), ItemKind::MacCall(a) => ForeignItemKind::MacCall(a), diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs index 60a12614f06..53276e0847a 100644 --- a/compiler/rustc_ast/src/entry.rs +++ b/compiler/rustc_ast/src/entry.rs @@ -45,18 +45,16 @@ pub fn entry_point_type( EntryPointType::Start } else if attr::contains_name(attrs, sym::rustc_main) { EntryPointType::RustcMainAttr - } else { - if let Some(name) = name - && name == sym::main - { - if at_root { - // This is a top-level function so it can be `main`. - EntryPointType::MainNamed - } else { - EntryPointType::OtherMain - } + } else if let Some(name) = name + && name == sym::main + { + if at_root { + // This is a top-level function so it can be `main`. + EntryPointType::MainNamed } else { - EntryPointType::None + EntryPointType::OtherMain } + } else { + EntryPointType::None } } diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 4413c259efb..a9d1ee5c9c1 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -220,9 +220,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 !self.tcx.features().const_arg_path - || !expr.is_potential_trivial_const_arg() - { + if !expr.is_potential_trivial_const_arg() { self.create_def( parent_def_id, node_id, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b887908f904..e105026ebd1 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -387,7 +387,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let node_id = self.next_node_id(); // HACK(min_generic_const_args): see lower_anon_const - if !self.tcx.features().const_arg_path || !arg.is_potential_trivial_const_arg() { + if !arg.is_potential_trivial_const_arg() { // Add a definition for the in-band const def. self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span); } diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 23729124e21..f90a0612db6 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -78,26 +78,24 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { // Make sure that the DepNode of some node coincides with the HirId // owner of that node. - if cfg!(debug_assertions) { - if hir_id.owner != self.owner { - span_bug!( - span, - "inconsistent HirId at `{:?}` for `{:?}`: \ + if cfg!(debug_assertions) && hir_id.owner != self.owner { + span_bug!( + span, + "inconsistent HirId at `{:?}` for `{:?}`: \ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", - self.tcx.sess.source_map().span_to_diagnostic_string(span), - node, - self.tcx - .definitions_untracked() - .def_path(self.owner.def_id) - .to_string_no_crate_verbose(), - self.owner, - self.tcx - .definitions_untracked() - .def_path(hir_id.owner.def_id) - .to_string_no_crate_verbose(), - hir_id.owner, - ) - } + self.tcx.sess.source_map().span_to_diagnostic_string(span), + node, + self.tcx + .definitions_untracked() + .def_path(self.owner.def_id) + .to_string_no_crate_verbose(), + self.owner, + self.tcx + .definitions_untracked() + .def_path(hir_id.owner.def_id) + .to_string_no_crate_verbose(), + hir_id.owner, + ) } self.nodes[hir_id.local_id] = ParentedNode { parent: self.parent_node, node }; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c8ec8f308a8..73c604bf28a 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -628,13 +628,11 @@ impl<'hir> LoweringContext<'_, 'hir> { .map_or(Const::No, |attr| Const::Yes(attr.span)), _ => Const::No, } + } else if self.tcx.is_const_trait(def_id) { + // FIXME(effects) span + Const::Yes(self.tcx.def_ident_span(def_id).unwrap()) } else { - if self.tcx.is_const_trait(def_id) { - // FIXME(effects) span - Const::Yes(self.tcx.def_ident_span(def_id).unwrap()) - } else { - Const::No - } + Const::No } } else { Const::No diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 754fbae4d02..efd3ae336af 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2335,7 +2335,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, ) -> &'hir hir::ConstArg<'hir> { let ct_kind = match res { - Res::Def(DefKind::ConstParam, _) if self.tcx.features().const_arg_path => { + Res::Def(DefKind::ConstParam, _) => { let qpath = self.lower_qpath( ty_id, &None, @@ -2410,8 +2410,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); debug!("res={:?}", maybe_res); // FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path - if self.tcx.features().const_arg_path - && let Some(res) = maybe_res + if let Some(res) = maybe_res && let Res::Def(DefKind::ConstParam, _) = res && let ExprKind::Path(qself, path) = &expr.kind { @@ -2442,7 +2441,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 self.tcx.features().const_arg_path && c.value.is_potential_trivial_const_arg() { + if c.value.is_potential_trivial_const_arg() { // 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_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index df5c639382f..c361c35b723 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -40,15 +40,15 @@ ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect -ast_passes_const_and_async = functions cannot be both `const` and `async` - .const = `const` because of this - .async = `async` because of this - .label = {""} - ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic .const = `const` because of this .variadic = C-variadic because of this +ast_passes_const_and_coroutine = functions cannot be both `const` and `{$coroutine_kind}` + .const = `const` because of this + .coroutine = `{$coroutine_kind}` because of this + .label = {""} + ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types ast_passes_const_without_body = diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ed9672a9e79..93881f5ed42 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -447,13 +447,13 @@ impl<'a> AstValidator<'a> { fn check_item_safety(&self, span: Span, safety: Safety) { match self.extern_mod_safety { Some(extern_safety) => { - if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) { - if extern_safety == Safety::Default { - self.dcx().emit_err(errors::InvalidSafetyOnExtern { - item_span: span, - block: Some(self.current_extern_span().shrink_to_lo()), - }); - } + if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) + && extern_safety == Safety::Default + { + self.dcx().emit_err(errors::InvalidSafetyOnExtern { + item_span: span, + block: Some(self.current_extern_span().shrink_to_lo()), + }); } } None => { @@ -1418,21 +1418,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Functions cannot both be `const async` or `const gen` if let Some(&FnHeader { - constness: Const::Yes(cspan), + constness: Const::Yes(const_span), coroutine_kind: Some(coroutine_kind), .. }) = fk.header() { - let aspan = match coroutine_kind { - CoroutineKind::Async { span: aspan, .. } - | CoroutineKind::Gen { span: aspan, .. } - | CoroutineKind::AsyncGen { span: aspan, .. } => aspan, - }; - // FIXME(gen_blocks): Report a different error for `const gen` - self.dcx().emit_err(errors::ConstAndAsync { - spans: vec![cspan, aspan], - cspan, - aspan, + self.dcx().emit_err(errors::ConstAndCoroutine { + spans: vec![coroutine_kind.span(), const_span], + const_span, + coroutine_span: coroutine_kind.span(), + coroutine_kind: coroutine_kind.as_str(), span, }); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 67c0396333c..5cce47ce7bd 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -657,16 +657,17 @@ pub(crate) enum TildeConstReason { } #[derive(Diagnostic)] -#[diag(ast_passes_const_and_async)] -pub(crate) struct ConstAndAsync { +#[diag(ast_passes_const_and_coroutine)] +pub(crate) struct ConstAndCoroutine { #[primary_span] pub spans: Vec<Span>, #[label(ast_passes_const)] - pub cspan: Span, - #[label(ast_passes_async)] - pub aspan: Span, + pub const_span: Span, + #[label(ast_passes_coroutine)] + pub coroutine_span: Span, #[label] pub span: Span, + pub coroutine_kind: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 39994ad784a..6725920746b 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -9,7 +9,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; -use rustc_mir_dataflow::{Analysis, AnalysisDomain, GenKill, Results, ResultsVisitable}; +use rustc_mir_dataflow::{Analysis, AnalysisDomain, Forward, GenKill, Results, ResultsVisitable}; use tracing::debug; use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext}; @@ -23,26 +23,25 @@ pub(crate) struct BorrowckResults<'a, 'tcx> { /// The transient state of the dataflow analyses used by the borrow checker. #[derive(Debug)] -pub(crate) struct BorrowckFlowState<'a, 'tcx> { +pub(crate) struct BorrowckDomain<'a, 'tcx> { pub(crate) borrows: <Borrows<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain, pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain, pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain, } impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { - // All three analyses are forward, but we have to use just one here. - type Direction = <Borrows<'a, 'tcx> as AnalysisDomain<'tcx>>::Direction; - type FlowState = BorrowckFlowState<'a, 'tcx>; + type Direction = Forward; + type Domain = BorrowckDomain<'a, 'tcx>; - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { - BorrowckFlowState { + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { + BorrowckDomain { borrows: self.borrows.analysis.bottom_value(body), uninits: self.uninits.analysis.bottom_value(body), ever_inits: self.ever_inits.analysis.bottom_value(body), } } - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { + fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) { state.borrows.clone_from(self.borrows.entry_set_for_block(block)); state.uninits.clone_from(self.uninits.entry_set_for_block(block)); state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block)); @@ -50,7 +49,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { fn reconstruct_before_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -61,7 +60,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { fn reconstruct_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -72,7 +71,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { fn reconstruct_before_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { @@ -83,7 +82,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { fn reconstruct_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 12ae2c29e8b..4a31aee5c96 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1999,19 +1999,32 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) { let used_in_call = matches!( explanation, - BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _) + BorrowExplanation::UsedLater( + _, + LaterUseKind::Call | LaterUseKind::Other, + _call_span, + _ + ) ); if !used_in_call { debug!("not later used in call"); return; } + if matches!( + self.body.local_decls[issued_borrow.borrowed_place.local].local_info(), + LocalInfo::IfThenRescopeTemp { .. } + ) { + // A better suggestion will be issued by the `if_let_rescope` lint + return; + } - let use_span = - if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation { - Some(use_span) - } else { - None - }; + let use_span = if let BorrowExplanation::UsedLater(_, LaterUseKind::Other, use_span, _) = + explanation + { + Some(use_span) + } else { + None + }; let outer_call_loc = if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location { @@ -2574,33 +2587,31 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { - if e.span.contains(self.capture_span) { - if let hir::ExprKind::Closure(&hir::Closure { + if e.span.contains(self.capture_span) + && let hir::ExprKind::Closure(&hir::Closure { kind: hir::ClosureKind::Closure, body, fn_arg_span, fn_decl: hir::FnDecl { inputs, .. }, .. }) = e.kind - && let hir::Node::Expr(body) = self.tcx.hir_node(body.hir_id) - { - self.suggest_arg = "this: &Self".to_string(); - if inputs.len() > 0 { - self.suggest_arg.push_str(", "); - } - self.in_closure = true; - self.closure_arg_span = fn_arg_span; - self.visit_expr(body); - self.in_closure = false; + && let hir::Node::Expr(body) = self.tcx.hir_node(body.hir_id) + { + self.suggest_arg = "this: &Self".to_string(); + if inputs.len() > 0 { + self.suggest_arg.push_str(", "); } + self.in_closure = true; + self.closure_arg_span = fn_arg_span; + self.visit_expr(body); + self.in_closure = false; } - if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e { - if let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path - && seg.ident.name == kw::SelfLower - && self.in_closure - { - self.closure_change_spans.push(e.span); - } + if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e + && let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path + && seg.ident.name == kw::SelfLower + && self.in_closure + { + self.closure_change_spans.push(e.span); } hir::intravisit::walk_expr(self, e); } @@ -2609,8 +2620,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat && let Some(init) = local.init - { - if let hir::Expr { + && let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { kind: hir::ClosureKind::Closure, @@ -2618,11 +2628,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }), .. } = init - && init.span.contains(self.capture_span) - { - self.closure_local_id = Some(*hir_id); - } + && init.span.contains(self.capture_span) + { + self.closure_local_id = Some(*hir_id); } + hir::intravisit::walk_local(self, local); } @@ -2862,7 +2872,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // and `move` will not help here. ( Some(name), - BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _), + BorrowExplanation::UsedLater(_, LaterUseKind::ClosureCapture, var_or_use_span, _), ) if borrow_spans.for_coroutine() || borrow_spans.for_closure() => self .report_escaping_closure_capture( borrow_spans, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 419e72df00b..d9b5fd8b5c1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -30,7 +30,7 @@ use crate::{MirBorrowckCtxt, WriteKind}; #[derive(Debug)] pub(crate) enum BorrowExplanation<'tcx> { - UsedLater(LaterUseKind, Span, Option<Span>), + UsedLater(Local, LaterUseKind, Span, Option<Span>), UsedLaterInLoop(LaterUseKind, Span, Option<Span>), UsedLaterWhenDropped { drop_loc: Location, @@ -99,7 +99,12 @@ impl<'tcx> BorrowExplanation<'tcx> { } } match *self { - BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => { + BorrowExplanation::UsedLater( + dropped_local, + later_use_kind, + var_or_use_span, + path_span, + ) => { let message = match later_use_kind { LaterUseKind::TraitCapture => "captured here by trait object", LaterUseKind::ClosureCapture => "captured here by closure", @@ -107,9 +112,26 @@ impl<'tcx> BorrowExplanation<'tcx> { LaterUseKind::FakeLetRead => "stored here", LaterUseKind::Other => "used here", }; - // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same - if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { - if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { + let local_decl = &body.local_decls[dropped_local]; + + if let &LocalInfo::IfThenRescopeTemp { if_then } = local_decl.local_info() + && let Some((_, hir::Node::Expr(expr))) = tcx.hir().parent_iter(if_then).next() + && let hir::ExprKind::If(cond, conseq, alt) = expr.kind + && let hir::ExprKind::Let(&hir::LetExpr { + span: _, + pat, + init, + // FIXME(#101728): enable rewrite when type ascription is stabilized again + ty: None, + recovered: _, + }) = cond.kind + && pat.span.can_be_used_for_suggestions() + && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span) + { + suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err); + } else if path_span.map_or(true, |path_span| path_span == var_or_use_span) { + // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same + if borrow_span.map_or(true, |sp| !sp.overlaps(var_or_use_span)) { err.span_label( var_or_use_span, format!("{borrow_desc}borrow later {message}"), @@ -255,6 +277,22 @@ impl<'tcx> BorrowExplanation<'tcx> { Applicability::MaybeIncorrect, ); }; + } else if let &LocalInfo::IfThenRescopeTemp { if_then } = + local_decl.local_info() + && let hir::Node::Expr(expr) = tcx.hir_node(if_then) + && let hir::ExprKind::If(cond, conseq, alt) = expr.kind + && let hir::ExprKind::Let(&hir::LetExpr { + span: _, + pat, + init, + // FIXME(#101728): enable rewrite when type ascription is stabilized again + ty: None, + recovered: _, + }) = cond.kind + && pat.span.can_be_used_for_suggestions() + && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span) + { + suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err); } } } @@ -390,6 +428,53 @@ impl<'tcx> BorrowExplanation<'tcx> { } } +fn suggest_rewrite_if_let( + tcx: TyCtxt<'_>, + expr: &hir::Expr<'_>, + pat: &str, + init: &hir::Expr<'_>, + conseq: &hir::Expr<'_>, + alt: Option<&hir::Expr<'_>>, + err: &mut Diag<'_>, +) { + let source_map = tcx.sess.source_map(); + err.span_note( + source_map.end_point(conseq.span), + "lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead", + ); + if expr.span.can_be_used_for_suggestions() && conseq.span.can_be_used_for_suggestions() { + let needs_block = if let Some(hir::Node::Expr(expr)) = + alt.and_then(|alt| tcx.hir().parent_iter(alt.hir_id).next()).map(|(_, node)| node) + { + matches!(expr.kind, hir::ExprKind::If(..)) + } else { + false + }; + let mut sugg = vec![ + ( + expr.span.shrink_to_lo().between(init.span), + if needs_block { "{ match ".into() } else { "match ".into() }, + ), + (conseq.span.shrink_to_lo(), format!(" {{ {pat} => ")), + ]; + let expr_end = expr.span.shrink_to_hi(); + let mut expr_end_code; + if let Some(alt) = alt { + sugg.push((conseq.span.between(alt.span), " _ => ".into())); + expr_end_code = "}".to_string(); + } else { + expr_end_code = " _ => {} }".into(); + } + expr_end_code.push('}'); + sugg.push((expr_end, expr_end_code)); + err.multipart_suggestion( + "consider rewriting the `if` into `match` which preserves the extended lifetime", + sugg, + Applicability::MaybeIncorrect, + ); + } +} + impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { fn free_region_constraint_info( &self, @@ -465,14 +550,21 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { .or_else(|| self.borrow_spans(span, location)); if use_in_later_iteration_of_loop { - let later_use = self.later_use_kind(borrow, spans, use_location); - BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2) + let (later_use_kind, var_or_use_span, path_span) = + self.later_use_kind(borrow, spans, use_location); + BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) } else { // Check if the location represents a `FakeRead`, and adapt the error // message to the `FakeReadCause` it is from: in particular, // the ones inserted in optimized `let var = <expr>` patterns. - let later_use = self.later_use_kind(borrow, spans, location); - BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2) + let (later_use_kind, var_or_use_span, path_span) = + self.later_use_kind(borrow, spans, location); + BorrowExplanation::UsedLater( + borrow.borrowed_place.local, + later_use_kind, + var_or_use_span, + path_span, + ) } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d5f297a5913..58e73030749 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -83,7 +83,7 @@ mod util; pub mod consumers; use borrow_set::{BorrowData, BorrowSet}; -use dataflow::{BorrowIndex, BorrowckFlowState as Flows, BorrowckResults, Borrows}; +use dataflow::{BorrowIndex, BorrowckDomain, BorrowckResults, Borrows}; use nll::PoloniusOutput; use place_ext::PlaceExt; use places_conflict::{places_conflict, PlaceConflictBias}; @@ -602,25 +602,25 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> for MirBorrowckCtxt<'a, '_, 'tcx> { - type FlowState = Flows<'a, 'tcx>; + type Domain = BorrowckDomain<'a, 'tcx>; fn visit_statement_before_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, stmt: &'a Statement<'tcx>, location: Location, ) { - debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, flow_state); + debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state); let span = stmt.source_info.span; - self.check_activations(location, span, flow_state); + self.check_activations(location, span, state); match &stmt.kind { StatementKind::Assign(box (lhs, rhs)) => { - self.consume_rvalue(location, (rhs, span), flow_state); + self.consume_rvalue(location, (rhs, span), state); - self.mutate_place(location, (*lhs, span), Shallow(None), flow_state); + self.mutate_place(location, (*lhs, span), Shallow(None), state); } StatementKind::FakeRead(box (_, place)) => { // Read for match doesn't access any memory and is used to @@ -637,11 +637,11 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } StatementKind::Intrinsic(box kind) => match kind { - NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state), + NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), state), NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( span, "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics", @@ -662,7 +662,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> (Place::from(*local), span), (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, - flow_state, + state, ); } StatementKind::Nop @@ -677,18 +677,18 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> fn visit_terminator_before_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, term: &'a Terminator<'tcx>, loc: Location, ) { - debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, flow_state); + debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state); let span = term.source_info.span; - self.check_activations(loc, span, flow_state); + self.check_activations(loc, span, state); match &term.kind { TerminatorKind::SwitchInt { discr, targets: _ } => { - self.consume_operand(loc, (discr, span), flow_state); + self.consume_operand(loc, (discr, span), state); } TerminatorKind::Drop { place, target: _, unwind: _, replace } => { debug!( @@ -704,7 +704,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> (*place, span), (AccessDepth::Drop, Write(write_kind)), LocalMutationIsAllowed::Yes, - flow_state, + state, ); } TerminatorKind::Call { @@ -716,29 +716,29 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> call_source: _, fn_span: _, } => { - self.consume_operand(loc, (func, span), flow_state); + self.consume_operand(loc, (func, span), state); for arg in args { - self.consume_operand(loc, (&arg.node, arg.span), flow_state); + self.consume_operand(loc, (&arg.node, arg.span), state); } - self.mutate_place(loc, (*destination, span), Deep, flow_state); + self.mutate_place(loc, (*destination, span), Deep, state); } TerminatorKind::TailCall { func, args, fn_span: _ } => { - self.consume_operand(loc, (func, span), flow_state); + self.consume_operand(loc, (func, span), state); for arg in args { - self.consume_operand(loc, (&arg.node, arg.span), flow_state); + self.consume_operand(loc, (&arg.node, arg.span), state); } } TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { - self.consume_operand(loc, (cond, span), flow_state); + self.consume_operand(loc, (cond, span), state); if let AssertKind::BoundsCheck { len, index } = &**msg { - self.consume_operand(loc, (len, span), flow_state); - self.consume_operand(loc, (index, span), flow_state); + self.consume_operand(loc, (len, span), state); + self.consume_operand(loc, (index, span), state); } } TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { - self.consume_operand(loc, (value, span), flow_state); - self.mutate_place(loc, (*resume_arg, span), Deep, flow_state); + self.consume_operand(loc, (value, span), state); + self.mutate_place(loc, (*resume_arg, span), Deep, state); } TerminatorKind::InlineAsm { @@ -752,22 +752,17 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> for op in operands { match op { InlineAsmOperand::In { reg: _, value } => { - self.consume_operand(loc, (value, span), flow_state); + self.consume_operand(loc, (value, span), state); } InlineAsmOperand::Out { reg: _, late: _, place, .. } => { if let Some(place) = place { - self.mutate_place(loc, (*place, span), Shallow(None), flow_state); + self.mutate_place(loc, (*place, span), Shallow(None), state); } } InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => { - self.consume_operand(loc, (in_value, span), flow_state); + self.consume_operand(loc, (in_value, span), state); if let &Some(out_place) = out_place { - self.mutate_place( - loc, - (out_place, span), - Shallow(None), - flow_state, - ); + self.mutate_place(loc, (out_place, span), Shallow(None), state); } } InlineAsmOperand::Const { value: _ } @@ -794,7 +789,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> fn visit_terminator_after_primary_effect( &mut self, _results: &mut R, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, term: &'a Terminator<'tcx>, loc: Location, ) { @@ -805,7 +800,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> if self.movable_coroutine { // Look for any active borrows to locals let borrow_set = self.borrow_set.clone(); - for i in flow_state.borrows.iter() { + for i in state.borrows.iter() { let borrow = &borrow_set[i]; self.check_for_local_borrow(borrow, span); } @@ -821,7 +816,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> // StorageDead, but we don't always emit those (notably on unwind paths), // so this "extra check" serves as a kind of backup. let borrow_set = self.borrow_set.clone(); - for i in flow_state.borrows.iter() { + for i in state.borrows.iter() { let borrow = &borrow_set[i]; self.check_for_invalidation_at_exit(loc, borrow, span); } @@ -989,7 +984,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { place_span: (Place<'tcx>, Span), kind: (AccessDepth, ReadOrWrite), is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { let (sd, rw) = kind; @@ -1020,11 +1015,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { place_span, rw, is_local_mutation_allowed, - flow_state, + state, location, ); - let conflict_error = - self.check_access_for_conflict(location, place_span, sd, rw, flow_state); + let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state); if conflict_error || mutability_error { debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind); @@ -1032,14 +1026,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } - #[instrument(level = "debug", skip(self, flow_state))] + #[instrument(level = "debug", skip(self, state))] fn check_access_for_conflict( &mut self, location: Location, place_span: (Place<'tcx>, Span), sd: AccessDepth, rw: ReadOrWrite, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) -> bool { let mut error_reported = false; let borrow_set = Rc::clone(&self.borrow_set); @@ -1054,7 +1048,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } &polonius_output } else { - &flow_state.borrows + &state.borrows }; each_borrow_involving_path( @@ -1180,17 +1174,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, place_span: (Place<'tcx>, Span), kind: AccessDepth, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { // Write of P[i] or *P requires P init'd. - self.check_if_assigned_path_is_moved(location, place_span, flow_state); + self.check_if_assigned_path_is_moved(location, place_span, state); self.access_place( location, place_span, (kind, Write(WriteKind::Mutate)), LocalMutationIsAllowed::No, - flow_state, + state, ); } @@ -1198,7 +1192,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { &mut self, location: Location, (rvalue, span): (&'a Rvalue<'tcx>, Span), - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { match rvalue { &Rvalue::Ref(_ /*rgn*/, bk, place) => { @@ -1224,7 +1218,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), access_kind, LocalMutationIsAllowed::No, - flow_state, + state, ); let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) { @@ -1237,7 +1231,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location, action, (place.as_ref(), span), - flow_state, + state, ); } @@ -1257,14 +1251,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), access_kind, LocalMutationIsAllowed::No, - flow_state, + state, ); self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Borrow, (place.as_ref(), span), - flow_state, + state, ); } @@ -1275,7 +1269,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | Rvalue::UnaryOp(_ /*un_op*/, operand) | Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) | Rvalue::ShallowInitBox(operand, _ /*ty*/) => { - self.consume_operand(location, (operand, span), flow_state) + self.consume_operand(location, (operand, span), state) } &Rvalue::CopyForDeref(place) => { @@ -1284,7 +1278,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, - flow_state, + state, ); // Finally, check if path was already moved. @@ -1292,7 +1286,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } @@ -1307,19 +1301,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, - flow_state, + state, ); self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => { - self.consume_operand(location, (operand1, span), flow_state); - self.consume_operand(location, (operand2, span), flow_state); + self.consume_operand(location, (operand1, span), state); + self.consume_operand(location, (operand2, span), state); } Rvalue::NullaryOp(_op, _ty) => { @@ -1349,7 +1343,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } for operand in operands { - self.consume_operand(location, (operand, span), flow_state); + self.consume_operand(location, (operand, span), state); } } } @@ -1456,7 +1450,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { &mut self, location: Location, (operand, span): (&'a Operand<'tcx>, Span), - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { match *operand { Operand::Copy(place) => { @@ -1467,7 +1461,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), (Deep, Read(ReadKind::Copy)), LocalMutationIsAllowed::No, - flow_state, + state, ); // Finally, check if path was already moved. @@ -1475,7 +1469,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } Operand::Move(place) => { @@ -1488,7 +1482,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span), (Deep, Write(WriteKind::Move)), LocalMutationIsAllowed::Yes, - flow_state, + state, ); // Finally, check if path was already moved. @@ -1496,7 +1490,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location, InitializationRequiringAction::Use, (place.as_ref(), span), - flow_state, + state, ); } Operand::Constant(_) => {} @@ -1576,7 +1570,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } - fn check_activations(&mut self, location: Location, span: Span, flow_state: &Flows<'a, 'tcx>) { + fn check_activations( + &mut self, + location: Location, + span: Span, + state: &BorrowckDomain<'a, 'tcx>, + ) { // Two-phase borrow support: For each activation that is newly // generated at this statement, check if it interferes with // another borrow. @@ -1595,7 +1594,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (borrow.borrowed_place, span), (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)), LocalMutationIsAllowed::No, - flow_state, + state, ); // We do not need to call `check_if_path_or_subpath_is_moved` // again, as we already called it when we made the @@ -1739,9 +1738,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { - let maybe_uninits = &flow_state.uninits; + let maybe_uninits = &state.uninits; // Bad scenarios: // @@ -1844,9 +1843,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { - let maybe_uninits = &flow_state.uninits; + let maybe_uninits = &state.uninits; // Bad scenarios: // @@ -1863,7 +1862,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // must have been initialized for the use to be sound. // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d` - self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state); + self.check_if_full_path_is_moved(location, desired_action, place_span, state); if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) = place_span.0.last_projection() @@ -1943,7 +1942,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { &mut self, location: Location, (place, span): (Place<'tcx>, Span), - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { debug!("check_if_assigned_path_is_moved place: {:?}", place); @@ -1965,7 +1964,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ProjectionElem::Deref => { self.check_if_full_path_is_moved( location, InitializationRequiringAction::Use, - (place_base, span), flow_state); + (place_base, span), state); // (base initialized; no need to // recur further) break; @@ -1985,7 +1984,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Assignment, - (place_base, span), flow_state); + (place_base, span), state); // (base initialized; no need to // recur further) @@ -1995,7 +1994,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // Once `let s; s.x = V; read(s.x);`, // is allowed, remove this match arm. ty::Adt(..) | ty::Tuple(..) => { - check_parent_of_field(self, location, place_base, span, flow_state); + check_parent_of_field(self, location, place_base, span, state); } _ => {} @@ -2009,7 +2008,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, base: PlaceRef<'tcx>, span: Span, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) { // rust-lang/rust#21232: Until Rust allows reads from the // initialized parts of partially initialized structs, we @@ -2042,7 +2041,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // Shallow so that we'll stop at any dereference; we'll // report errors about issues with such bases elsewhere. - let maybe_uninits = &flow_state.uninits; + let maybe_uninits = &state.uninits; // Find the shortest uninitialized prefix you can reach // without going over a Deref. @@ -2069,12 +2068,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // no move out from an earlier location) then this is an attempt at initialization // of the union - we should error in that case. let tcx = this.infcx.tcx; - if base.ty(this.body(), tcx).ty.is_union() { - if this.move_data.path_map[mpi].iter().any(|moi| { + if base.ty(this.body(), tcx).ty.is_union() + && this.move_data.path_map[mpi].iter().any(|moi| { this.move_data.moves[*moi].source.is_predecessor_of(location, this.body) - }) { - return; - } + }) + { + return; } this.report_use_of_moved_or_uninitialized( @@ -2100,7 +2099,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span): (Place<'tcx>, Span), kind: ReadOrWrite, is_local_mutation_allowed: LocalMutationIsAllowed, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, location: Location, ) -> bool { debug!( @@ -2124,7 +2123,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { }; match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { Ok(root_place) => { - self.add_used_mut(root_place, flow_state); + self.add_used_mut(root_place, state); return false; } Err(place_err) => { @@ -2136,7 +2135,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { Ok(root_place) => { - self.add_used_mut(root_place, flow_state); + self.add_used_mut(root_place, state); return false; } Err(place_err) => { @@ -2194,7 +2193,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // partial initialization, do not complain about mutability // errors except for actual mutation (as opposed to an attempt // to do a partial initialization). - let previously_initialized = self.is_local_ever_initialized(place.local, flow_state); + let previously_initialized = self.is_local_ever_initialized(place.local, state); // at this point, we have set up the error reporting state. if let Some(init_index) = previously_initialized { @@ -2216,22 +2215,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { fn is_local_ever_initialized( &self, local: Local, - flow_state: &Flows<'a, 'tcx>, + state: &BorrowckDomain<'a, 'tcx>, ) -> Option<InitIndex> { let mpi = self.move_data.rev_lookup.find_local(local)?; let ii = &self.move_data.init_path_map[mpi]; - ii.into_iter().find(|&&index| flow_state.ever_inits.contains(index)).copied() + ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied() } /// Adds the place into the used mutable variables set - fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'a, 'tcx>) { + fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain<'a, 'tcx>) { match root_place { RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { // If the local may have been initialized, and it is now currently being // mutated, then it is justified to be annotated with the `mut` // keyword, since the mutation may be a possible reassignment. if is_local_mutation_allowed != LocalMutationIsAllowed::Yes - && self.is_local_ever_initialized(local, flow_state).is_some() + && self.is_local_ever_initialized(local, state).is_some() { self.used_mut.insert(local); } diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index d62f2067729..30dc062ae7c 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -118,10 +118,8 @@ impl LivenessValues { debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location); if let Some(points) = &mut self.points { points.insert(region, point); - } else { - if self.elements.point_in_range(point) { - self.live_regions.as_mut().unwrap().insert(region); - } + } else if self.elements.point_in_range(point) { + self.live_regions.as_mut().unwrap().insert(region); } // When available, record the loans flowing into this region as live at the given point. @@ -137,10 +135,8 @@ impl LivenessValues { debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points); if let Some(this) = &mut self.points { this.union_row(region, points); - } else { - if points.iter().any(|point| self.elements.point_in_range(point)) { - self.live_regions.as_mut().unwrap().insert(region); - } + } else if points.iter().any(|point| self.elements.point_in_range(point)) { + self.live_regions.as_mut().unwrap().insert(region); } // When available, record the loans flowing into this region as live at the given points. diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 4d47863ae76..1ac27573453 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -353,11 +353,11 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { let location = self.cx.elements.to_location(drop_point); debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,); - if self.cx.initialized_at_terminator(location.block, mpi) { - if self.drop_live_at.insert(drop_point) { - self.drop_locations.push(location); - self.stack.push(drop_point); - } + if self.cx.initialized_at_terminator(location.block, mpi) + && self.drop_live_at.insert(drop_point) + { + self.drop_locations.push(location); + self.stack.push(drop_point); } } diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index d6248899655..0e1ec3b3cad 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -235,13 +235,11 @@ pub fn parse_asm_args<'a>( continue; } args.named_args.insert(name, slot); - } else { - if !args.named_args.is_empty() || !args.reg_args.is_empty() { - let named = args.named_args.values().map(|p| args.operands[*p].1).collect(); - let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect(); + } else if !args.named_args.is_empty() || !args.reg_args.is_empty() { + let named = args.named_args.values().map(|p| args.operands[*p].1).collect(); + let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect(); - dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit }); - } + dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit }); } } diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index d770da5a8c4..f2ae9f9c8a6 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -48,6 +48,10 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) { self.location = Some(dbg_loc); } + + fn clear_dbg_loc(&mut self) { + self.location = None; + } } /// Generate the `debug_context` in an MIR Body. diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 09896b89ebf..2ebe0be53aa 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -92,11 +92,9 @@ fn prepare_lto( dcx.emit_err(LtoDylib); return Err(FatalError); } - } else if *crate_type == CrateType::ProcMacro { - if !cgcx.opts.unstable_opts.dylib_lto { - dcx.emit_err(LtoProcMacro); - return Err(FatalError); - } + } else if *crate_type == CrateType::ProcMacro && !cgcx.opts.unstable_opts.dylib_lto { + dcx.emit_err(LtoProcMacro); + return Err(FatalError); } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 01aae24ab56..73c2c15717f 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -27,7 +27,7 @@ use rustc_span::source_map::Spanned; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{HasDataLayout, TargetDataLayout, VariantIdx}; -use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; +use rustc_target::spec::{HasTargetSpec, RelocModel, SmallDataThresholdSupport, Target, TlsModel}; use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; @@ -387,6 +387,24 @@ pub(crate) unsafe fn create_module<'ll>( } } + match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support()) + { + // Set up the small-data optimization limit for architectures that use + // an LLVM module flag to control this. + (Some(threshold), SmallDataThresholdSupport::LlvmModuleFlag(flag)) => { + let flag = SmallCStr::new(flag.as_ref()); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Error, + flag.as_c_str().as_ptr(), + threshold as u32, + ) + } + } + _ => (), + }; + // Insert `llvm.ident` metadata. // // On the wasm targets it will get hooked up to the "producer" sections diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index f5d6fc6f080..842212ac05d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -1,8 +1,8 @@ #![doc = include_str!("doc.md")] use std::cell::{OnceCell, RefCell}; -use std::iter; use std::ops::Range; +use std::{iter, ptr}; use libc::c_uint; use rustc_codegen_ssa::debuginfo::type_names; @@ -209,6 +209,12 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { } } + fn clear_dbg_loc(&mut self) { + unsafe { + llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null()); + } + } + fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { gdb::insert_reference_to_gdb_debug_scripts_section_global(self) } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 3bf4d496408..e84ab0aa538 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1041,7 +1041,7 @@ unsafe extern "C" { pub fn LLVMDisposeBuilder<'a>(Builder: &'a mut Builder<'a>); // Metadata - pub fn LLVMSetCurrentDebugLocation2<'a>(Builder: &Builder<'a>, Loc: &'a Metadata); + pub fn LLVMSetCurrentDebugLocation2<'a>(Builder: &Builder<'a>, Loc: *const Metadata); // Terminators pub fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value; diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 6e4ddbb6f3b..29afe6f6bfc 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -14,7 +14,7 @@ use rustc_middle::bug; use rustc_session::config::{PrintKind, PrintRequest}; use rustc_session::Session; use rustc_span::symbol::Symbol; -use rustc_target::spec::{MergeFunctions, PanicStrategy}; +use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport}; use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES}; use crate::back::write::create_informational_target_machine; @@ -125,6 +125,18 @@ unsafe fn configure_llvm(sess: &Session) { for arg in sess_args { add(&(*arg), true); } + + match ( + sess.opts.unstable_opts.small_data_threshold, + sess.target.small_data_threshold_support(), + ) { + // Set up the small-data optimization limit for architectures that use + // an LLVM argument to control this. + (Some(threshold), SmallDataThresholdSupport::LlvmArg(arg)) => { + add(&format!("--{arg}={threshold}"), false) + } + _ => (), + }; } if sess.opts.unstable_opts.llvm_time_trace { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index dbb65707bd2..40eb35deea5 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -281,12 +281,10 @@ pub fn each_linked_rlib( let used_crate_source = &info.used_crate_source[&cnum]; if let Some((path, _)) = &used_crate_source.rlib { f(cnum, path); + } else if used_crate_source.rmeta.is_some() { + return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name }); } else { - if used_crate_source.rmeta.is_some() { - return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name }); - } else { - return Err(errors::LinkRlibError::NotFound { crate_name }); - } + return Err(errors::LinkRlibError::NotFound { crate_name }); } } Ok(()) @@ -628,12 +626,10 @@ fn link_staticlib( let used_crate_source = &codegen_results.crate_info.used_crate_source[&cnum]; if let Some((path, _)) = &used_crate_source.dylib { all_rust_dylibs.push(&**path); + } else if used_crate_source.rmeta.is_some() { + sess.dcx().emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name }); } else { - if used_crate_source.rmeta.is_some() { - sess.dcx().emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name }); - } else { - sess.dcx().emit_fatal(errors::LinkRlibError::NotFound { crate_name }); - } + sess.dcx().emit_fatal(errors::LinkRlibError::NotFound { crate_name }); } } @@ -1972,10 +1968,8 @@ fn add_late_link_args( if let Some(args) = sess.target.late_link_args_dynamic.get(&flavor) { cmd.verbatim_args(args.iter().map(Deref::deref)); } - } else { - if let Some(args) = sess.target.late_link_args_static.get(&flavor) { - cmd.verbatim_args(args.iter().map(Deref::deref)); - } + } else if let Some(args) = sess.target.late_link_args_static.get(&flavor) { + cmd.verbatim_args(args.iter().map(Deref::deref)); } if let Some(args) = sess.target.late_link_args.get(&flavor) { cmd.verbatim_args(args.iter().map(Deref::deref)); @@ -2635,10 +2629,8 @@ fn add_native_libs_from_crate( if link_static { cmd.link_staticlib_by_name(name, verbatim, false); } - } else { - if link_dynamic { - cmd.link_dylib_by_name(name, verbatim, true); - } + } else if link_dynamic { + cmd.link_dylib_by_name(name, verbatim, true); } } NativeLibKind::Framework { as_needed } => { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index ea71b92de3a..7f5f9f03868 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -791,14 +791,12 @@ impl<'a> Linker for GccLinker<'a> { self.link_arg("-exported_symbols_list").link_arg(path); } else if self.sess.target.is_like_solaris { self.link_arg("-M").link_arg(path); + } else if is_windows { + self.link_arg(path); } else { - if is_windows { - self.link_arg(path); - } else { - let mut arg = OsString::from("--version-script="); - arg.push(path); - self.link_arg(arg).link_arg("--no-undefined-version"); - } + let mut arg = OsString::from("--version-script="); + arg.push(path); + self.link_arg(arg).link_arg("--no-undefined-version"); } } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 4ab20c154cc..9149c602296 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -617,32 +617,29 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // purpose functions as they wouldn't have the right target features // enabled. For that reason we also forbid #[inline(always)] as it can't be // respected. - if !codegen_fn_attrs.target_features.is_empty() { - if codegen_fn_attrs.inline == InlineAttr::Always { - if let Some(span) = inline_span { - tcx.dcx().span_err( - span, - "cannot use `#[inline(always)]` with \ + if !codegen_fn_attrs.target_features.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always + { + if let Some(span) = inline_span { + tcx.dcx().span_err( + span, + "cannot use `#[inline(always)]` with \ `#[target_feature]`", - ); - } + ); } } - if !codegen_fn_attrs.no_sanitize.is_empty() { - if codegen_fn_attrs.inline == InlineAttr::Always { - if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) { - let hir_id = tcx.local_def_id_to_hir_id(did); - tcx.node_span_lint( - lint::builtin::INLINE_NO_SANITIZE, - hir_id, - no_sanitize_span, - |lint| { - lint.primary_message("`no_sanitize` will have no effect after inlining"); - lint.span_note(inline_span, "inlining requested here"); - }, - ) - } + if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always { + if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) { + let hir_id = tcx.local_def_id_to_hir_id(did); + tcx.node_span_lint( + lint::builtin::INLINE_NO_SANITIZE, + hir_id, + no_sanitize_span, + |lint| { + lint.primary_message("`no_sanitize` will have no effect after inlining"); + lint.span_note(inline_span, "inlining requested here"); + }, + ) } } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 5103b2f3158..e34fbfe3f76 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -236,15 +236,13 @@ fn push_debuginfo_type_name<'tcx>( let has_enclosing_parens = if cpp_like_debuginfo { output.push_str("dyn$<"); false + } else if trait_data.len() > 1 && auto_traits.len() != 0 { + // We need enclosing parens because there is more than one trait + output.push_str("(dyn "); + true } else { - if trait_data.len() > 1 && auto_traits.len() != 0 { - // We need enclosing parens because there is more than one trait - output.push_str("(dyn "); - true - } else { - output.push_str("dyn "); - false - } + output.push_str("dyn "); + false }; if let Some(principal) = trait_data.principal() { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 75692540c03..ab08ef72a69 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -547,6 +547,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(bx, var.source_info); let base = Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx); + bx.clear_dbg_loc(); bx.dbg_var_addr( dbg_var, diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index 31104e5749b..5fbe97214fb 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -80,6 +80,7 @@ pub trait DebugInfoBuilderMethods: BackendTypes { fragment: Option<Range<Size>>, ); fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation); + fn clear_dbg_loc(&mut self); fn insert_reference_to_gdb_debug_scripts_section_global(&mut self); fn set_var_name(&mut self, value: Self::Value, name: &str); } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 594b98f34ef..337eab7a1c2 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -73,12 +73,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( // This can't use `init_stack_frame` since `body` is not a function, // so computing its ABI would fail. It's also not worth it since there are no arguments to pass. - ecx.push_stack_frame_raw( - cid.instance, - body, - &ret.clone().into(), - StackPopCleanup::Root { cleanup: false }, - )?; + ecx.push_stack_frame_raw(cid.instance, body, &ret, StackPopCleanup::Root { cleanup: false })?; ecx.storage_live_for_always_live_locals()?; // The main interpreter loop. diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 419d412b063..0f2b22f035b 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -823,7 +823,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { (Abi::Rust, fn_abi), &[FnArg::Copy(arg.into())], false, - &ret.into(), + &ret, Some(target), unwind, ) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index dd744c51f23..16d40fcceb6 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -16,7 +16,7 @@ use rustc_span::Span; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; use rustc_trait_selection::traits::ObligationCtxt; -use tracing::{debug, trace}; +use tracing::{debug, instrument, trace}; use super::{ err_inval, throw_inval, throw_ub, throw_ub_custom, Frame, FrameInfo, GlobalId, InterpErrorInfo, @@ -315,6 +315,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Check if the two things are equal in the current param_env, using an infctx to get proper /// equality checks. + #[instrument(level = "trace", skip(self), ret)] pub(super) fn eq_in_param_env<T>(&self, a: T, b: T) -> bool where T: PartialEq + TypeFoldable<TyCtxt<'tcx>> + ToTrace<'tcx>, @@ -330,13 +331,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // equate the two trait refs after normalization let a = ocx.normalize(&cause, self.param_env, a); let b = ocx.normalize(&cause, self.param_env, b); - if ocx.eq(&cause, self.param_env, a, b).is_ok() { - if ocx.select_all_or_error().is_empty() { - // All good. - return true; - } + + if let Err(terr) = ocx.eq(&cause, self.param_env, a, b) { + trace!(?terr); + return false; + } + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + trace!(?errors); + return false; } - return false; + + // All good. + true } /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index bedc56de0da..8a07f90c951 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -384,8 +384,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::simd_insert => { let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); let elem = &args[2]; - let (input, input_len) = self.operand_to_simd(&args[0])?; - let (dest, dest_len) = self.mplace_to_simd(dest)?; + let (input, input_len) = self.project_to_simd(&args[0])?; + let (dest, dest_len) = self.project_to_simd(dest)?; assert_eq!(input_len, dest_len, "Return vector length must match input length"); // Bounds are not checked by typeck so we have to do it ourselves. if index >= input_len { @@ -406,7 +406,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } sym::simd_extract => { let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); - let (input, input_len) = self.operand_to_simd(&args[0])?; + let (input, input_len) = self.project_to_simd(&args[0])?; // Bounds are not checked by typeck so we have to do it ourselves. if index >= input_len { throw_ub_format!( diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index bb7e58b83ac..2e02d1001c8 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -681,30 +681,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(str) } - /// Converts a repr(simd) operand into an operand where `place_index` accesses the SIMD elements. - /// Also returns the number of elements. - /// - /// Can (but does not always) trigger UB if `op` is uninitialized. - pub fn operand_to_simd( - &self, - op: &OpTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { - // Basically we just transmute this place into an array following simd_size_and_type. - // This only works in memory, but repr(simd) types should never be immediates anyway. - assert!(op.layout.ty.is_simd()); - match op.as_mplace_or_imm() { - Left(mplace) => self.mplace_to_simd(&mplace), - Right(imm) => match *imm { - Immediate::Uninit => { - throw_ub!(InvalidUninitBytes(None)) - } - Immediate::Scalar(..) | Immediate::ScalarPair(..) => { - bug!("arrays/slices can never have Scalar/ScalarPair layout") - } - }, - } - } - /// Read from a local of the current frame. /// Will not access memory, instead an indirect `Operand` is returned. /// diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 1eca92812df..9dd9ca80385 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -377,13 +377,15 @@ where Prov: Provenance, M: Machine<'tcx, Provenance = Prov>, { - pub fn ptr_with_meta_to_mplace( + fn ptr_with_meta_to_mplace( &self, ptr: Pointer<Option<M::Provenance>>, meta: MemPlaceMeta<M::Provenance>, layout: TyAndLayout<'tcx>, + unaligned: bool, ) -> MPlaceTy<'tcx, M::Provenance> { - let misaligned = self.is_ptr_misaligned(ptr, layout.align.abi); + let misaligned = + if unaligned { None } else { self.is_ptr_misaligned(ptr, layout.align.abi) }; MPlaceTy { mplace: MemPlace { ptr, meta, misaligned }, layout } } @@ -393,7 +395,16 @@ where layout: TyAndLayout<'tcx>, ) -> MPlaceTy<'tcx, M::Provenance> { assert!(layout.is_sized()); - self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout) + self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout, /*unaligned*/ false) + } + + pub fn ptr_to_mplace_unaligned( + &self, + ptr: Pointer<Option<M::Provenance>>, + layout: TyAndLayout<'tcx>, + ) -> MPlaceTy<'tcx, M::Provenance> { + assert!(layout.is_sized()); + self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout, /*unaligned*/ true) } /// Take a value, which represents a (thin or wide) reference, and make it a place. @@ -414,7 +425,7 @@ where // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced; // we hence can't call `size_and_align_of` since that asserts more validity than we want. let ptr = ptr.to_pointer(self)?; - Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout)) + Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false)) } /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space. @@ -484,23 +495,6 @@ where Ok(a) } - /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements. - /// Also returns the number of elements. - pub fn mplace_to_simd( - &self, - mplace: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { - // Basically we want to transmute this place into an array following simd_size_and_type. - let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx); - // Some SIMD types have padding, so `len` many `e_ty` does not cover the entire place. - // Therefore we cannot transmute, and instead we project at offset 0, which side-steps - // the size check. - let array_layout = self.layout_of(Ty::new_array(self.tcx.tcx, e_ty, len))?; - assert!(array_layout.size <= mplace.layout.size); - let mplace = mplace.offset(Size::ZERO, array_layout, self)?; - Ok((mplace, len)) - } - /// Turn a local in the current frame into a place. pub fn local_to_place( &self, @@ -986,7 +980,7 @@ where span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known") }; let ptr = self.allocate_ptr(size, align, kind)?; - Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout)) + Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false)) } pub fn allocate( @@ -1021,7 +1015,12 @@ where }; let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); let layout = self.layout_of(self.tcx.types.str_).unwrap(); - Ok(self.ptr_with_meta_to_mplace(ptr.into(), MemPlaceMeta::Meta(meta), layout)) + Ok(self.ptr_with_meta_to_mplace( + ptr.into(), + MemPlaceMeta::Meta(meta), + layout, + /*unaligned*/ false, + )) } pub fn raw_const_to_mplace( diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index dd8dd21e0e8..641ed5bb7c0 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -244,6 +244,19 @@ where base.offset(offset, field_layout, self) } + /// Converts a repr(simd) value into an array of the right size, such that `project_index` + /// accesses the SIMD elements. Also returns the number of elements. + pub fn project_to_simd<P: Projectable<'tcx, M::Provenance>>( + &self, + base: &P, + ) -> InterpResult<'tcx, (P, u64)> { + assert!(base.layout().ty.ty_adt_def().unwrap().repr().simd()); + // SIMD types must be newtypes around arrays, so all we have to do is project to their only field. + let array = self.project_field(base, 0)?; + let len = array.len(self)?; + Ok((array, len)) + } + fn project_constant_index<P: Projectable<'tcx, M::Provenance>>( &self, base: &P, diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 6f5bcebbbb6..490355f416c 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{ }; use tracing::debug; -use super::{throw_inval, InterpCx, MPlaceTy, MemPlaceMeta, MemoryKind}; +use super::{throw_inval, InterpCx, MPlaceTy, MemoryKind}; use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult}; /// Checks whether a type contains generic parameters which must be instantiated. @@ -103,5 +103,5 @@ pub(crate) fn create_static_alloc<'tcx>( assert_eq!(ecx.machine.static_root_ids, None); ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); - Ok(ecx.ptr_with_meta_to_mplace(Pointer::from(alloc_id).into(), MemPlaceMeta::None, layout)) + Ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout)) } diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index c973fcec0e1..74225d646bd 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -222,10 +222,8 @@ impl<'tcx> PrintExtra<'tcx> { } pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { - if ppm.needs_analysis() { - if ex.tcx().analysis(()).is_err() { - FatalError.raise(); - } + if ppm.needs_analysis() && ex.tcx().analysis(()).is_err() { + FatalError.raise(); } let (src, src_name) = get_source(sess); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 412a2c17081..7a4d8dba179 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -681,10 +681,10 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { " ".repeat(expected_padding), expected_label ))]; - msg.extend(expected.0.into_iter()); + msg.extend(expected.0); msg.push(StringPart::normal(format!("`{expected_extra}\n"))); msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label))); - msg.extend(found.0.into_iter()); + msg.extend(found.0); msg.push(StringPart::normal(format!("`{found_extra}"))); // For now, just attach these as notes. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 3254dab9a03..6ed5ea9f8bb 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -193,8 +193,6 @@ declare_features! ( (unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None), /// Allows identifying the `compiler_builtins` crate. (internal, compiler_builtins, "1.13.0", None), - /// Gating for a new desugaring of const arguments of usages of const parameters - (internal, const_arg_path, "1.81.0", None), /// Allows writing custom MIR (internal, custom_mir, "1.65.0", None), /// Outputs useful `assert!` messages @@ -497,6 +495,8 @@ declare_features! ( (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)), /// Allows `if let` guard in match arms. (unstable, if_let_guard, "1.47.0", Some(51114)), + /// Rescoping temporaries in `if let` to align with Rust 2024. + (unstable, if_let_rescope, "CURRENT_RUSTC_VERSION", Some(124085)), /// Allows `impl Trait` to be used inside associated types (RFC 2515). (unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063)), /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index d7b2510a1df..1d686878eab 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1151,42 +1151,40 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { "type has conflicting packed and align representation hints" ) .emit(); - } else { - if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) { - let mut err = struct_span_code_err!( - tcx.dcx(), - sp, - E0588, - "packed type cannot transitively contain a `#[repr(align)]` type" - ); + } else if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) { + let mut err = struct_span_code_err!( + tcx.dcx(), + sp, + E0588, + "packed type cannot transitively contain a `#[repr(align)]` type" + ); - err.span_note( - tcx.def_span(def_spans[0].0), - format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)), - ); + err.span_note( + tcx.def_span(def_spans[0].0), + format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)), + ); - if def_spans.len() > 2 { - let mut first = true; - for (adt_def, span) in def_spans.iter().skip(1).rev() { - let ident = tcx.item_name(*adt_def); - err.span_note( - *span, - if first { - format!( - "`{}` contains a field of type `{}`", - tcx.type_of(def.did()).instantiate_identity(), - ident - ) - } else { - format!("...which contains a field of type `{ident}`") - }, - ); - first = false; - } + if def_spans.len() > 2 { + let mut first = true; + for (adt_def, span) in def_spans.iter().skip(1).rev() { + let ident = tcx.item_name(*adt_def); + err.span_note( + *span, + if first { + format!( + "`{}` contains a field of type `{}`", + tcx.type_of(def.did()).instantiate_identity(), + ident + ) + } else { + format!("...which contains a field of type `{ident}`") + }, + ); + first = false; } - - err.emit(); } + + err.emit(); } } } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 6820a44f141..dbdad2eb41d 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -186,17 +186,15 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) && alloc.inner().provenance().ptrs().len() != 0 - { - if attrs + && attrs .link_section .map(|link_section| !link_section.as_str().starts_with(".init_array")) .unwrap() - { - let msg = "statics with a custom `#[link_section]` must be a \ + { + let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ extra levels of indirection such as references"; - tcx.dcx().span_err(tcx.def_span(id), msg); - } + tcx.dcx().span_err(tcx.def_span(id), msg); } } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 2d6147cff2a..33e58a92e37 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -472,7 +472,12 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, Some(otherwise)) => { let expr_cx = visitor.cx; - visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen }); + let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope { + ScopeData::IfThenRescope + } else { + ScopeData::IfThen + }; + visitor.enter_scope(Scope { id: then.hir_id.local_id, data }); visitor.cx.var_parent = visitor.cx.parent; visitor.visit_expr(cond); visitor.visit_expr(then); @@ -482,7 +487,12 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h hir::ExprKind::If(cond, then, None) => { let expr_cx = visitor.cx; - visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen }); + let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope { + ScopeData::IfThenRescope + } else { + ScopeData::IfThen + }; + visitor.enter_scope(Scope { id: then.hir_id.local_id, data }); visitor.cx.var_parent = visitor.cx.parent; visitor.visit_expr(cond); visitor.visit_expr(then); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 3627faf8dfc..10b3fe380ab 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1602,7 +1602,7 @@ fn check_fn_or_method<'tcx>( function: def_id, // Note that the `param_idx` of the output type is // one greater than the index of the last input type. - param_idx: idx.try_into().unwrap(), + param_idx: idx, }), ty, ) @@ -1611,7 +1611,7 @@ fn check_fn_or_method<'tcx>( for (idx, ty) in sig.inputs_and_output.iter().enumerate() { wfcx.register_wf_obligation( arg_span(idx), - Some(WellFormedLoc::Param { function: def_id, param_idx: idx.try_into().unwrap() }), + Some(WellFormedLoc::Param { function: def_id, param_idx: idx }), ty.into(), ); } diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index db809e4837d..f2a97d06771 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -53,17 +53,15 @@ fn enforce_trait_manually_implementable( ) -> Result<(), ErrorGuaranteed> { let impl_header_span = tcx.def_span(impl_def_id); - if tcx.is_lang_item(trait_def_id, LangItem::Freeze) { - if !tcx.features().freeze_impls { - feature_err( - &tcx.sess, - sym::freeze_impls, - impl_header_span, - "explicit impls for the `Freeze` trait are not permitted", - ) - .with_span_label(impl_header_span, format!("impl of `Freeze` not allowed")) - .emit(); - } + if tcx.is_lang_item(trait_def_id, LangItem::Freeze) && !tcx.features().freeze_impls { + feature_err( + &tcx.sess, + sym::freeze_impls, + impl_header_span, + "explicit impls for the `Freeze` trait are not permitted", + ) + .with_span_label(impl_header_span, format!("impl of `Freeze` not allowed")) + .emit(); } // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]` diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 7f4a8208faa..2afb29abd68 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -381,24 +381,22 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( } mir_opaque_ty.ty + } else if let Some(guar) = tables.tainted_by_errors { + // Some error in the owner fn prevented us from populating + // the `concrete_opaque_types` table. + Ty::new_error(tcx, guar) } else { - if let Some(guar) = tables.tainted_by_errors { - // Some error in the owner fn prevented us from populating - // the `concrete_opaque_types` table. - Ty::new_error(tcx, guar) + // Fall back to the RPIT we inferred during HIR typeck + if let Some(hir_opaque_ty) = hir_opaque_ty { + hir_opaque_ty.ty } else { - // Fall back to the RPIT we inferred during HIR typeck - if let Some(hir_opaque_ty) = hir_opaque_ty { - hir_opaque_ty.ty - } else { - // We failed to resolve the opaque type or it - // resolves to itself. We interpret this as the - // no values of the hidden type ever being constructed, - // so we can just make the hidden type be `!`. - // For backwards compatibility reasons, we fall back to - // `()` until we the diverging default is changed. - Ty::new_diverging_default(tcx) - } + // We failed to resolve the opaque type or it + // resolves to itself. We interpret this as the + // no values of the hidden type ever being constructed, + // so we can just make the hidden type be `!`. + // For backwards compatibility reasons, we fall back to + // `()` until we the diverging default is changed. + Ty::new_diverging_default(tcx) } } } diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index da89f5769d1..97402dd1109 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -827,20 +827,18 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args == num_trait_generics_except_self + && let Some(span) = self.gen_args.span_ext() + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - if let Some(span) = self.gen_args.span_ext() - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) - { - let sugg = vec![ - ( - self.path_segment.ident.span, - format!("{}::{}", snippet, self.path_segment.ident), - ), - (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()), - ]; + let sugg = vec![ + ( + self.path_segment.ident.span, + format!("{}::{}", snippet, self.path_segment.ident), + ), + (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()), + ]; - err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); - } + err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); } } } 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 ac5bd825b18..7163352e8a4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -562,13 +562,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.const_param_default(param.def_id) .instantiate(tcx, preceding_args) .into() + } else if infer_args { + self.lowerer.ct_infer(Some(param), self.span).into() } else { - if infer_args { - self.lowerer.ct_infer(Some(param), self.span).into() - } else { - // We've already errored above about the mismatch. - ty::Const::new_misc_error(tcx).into() - } + // We've already errored above about the mismatch. + ty::Const::new_misc_error(tcx).into() } } } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9863d036449..3dc8759a9ed 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -58,7 +58,7 @@ pub(crate) fn check_legal_trait_for_method_call( enum CallStep<'tcx> { Builtin(Ty<'tcx>), DeferredClosure(LocalDefId, ty::FnSig<'tcx>), - /// E.g., enum variant constructors. + /// Call overloading when callee implements one of the Fn* traits. Overloaded(MethodCallee<'tcx>), } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 1e1e007862e..36892aaf80c 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -732,12 +732,11 @@ impl<'a, 'tcx> CastCheck<'tcx> { } _ => return Err(CastError::NonScalar), }; - if let ty::Adt(adt_def, _) = *self.expr_ty.kind() { - if adt_def.did().krate != LOCAL_CRATE { - if adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) { - return Err(CastError::ForeignNonExhaustiveAdt); - } - } + if let ty::Adt(adt_def, _) = *self.expr_ty.kind() + && adt_def.did().krate != LOCAL_CRATE + && adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) + { + return Err(CastError::ForeignNonExhaustiveAdt); } match (t_from, t_cast) { // These types have invariants! can't cast into them. diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 80a179fce03..6fd509ed32f 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1780,16 +1780,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Make sure the programmer specified correct number of fields. - if adt_kind == AdtKind::Union { - if hir_fields.len() != 1 { - struct_span_code_err!( - self.dcx(), - span, - E0784, - "union expressions should have exactly one field", - ) - .emit(); - } + if adt_kind == AdtKind::Union && hir_fields.len() != 1 { + struct_span_code_err!( + self.dcx(), + span, + E0784, + "union expressions should have exactly one field", + ) + .emit(); } // If check_expr_struct_fields hit an error, do not attempt to populate @@ -2904,21 +2902,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_fields.iter().map(|path| format!("{unwrap}{path}")), Applicability::MaybeIncorrect, ); - } else { - if let Some(field_name) = find_best_match_for_name(&field_names, field.name, None) { - err.span_suggestion_verbose( - field.span, - "a field with a similar name exists", - format!("{unwrap}{}", field_name), - Applicability::MaybeIncorrect, - ); - } else if !field_names.is_empty() { - let is = if field_names.len() == 1 { " is" } else { "s are" }; - err.note(format!( - "available field{is}: {}", - self.name_series_display(field_names), - )); - } + } else if let Some(field_name) = + find_best_match_for_name(&field_names, field.name, None) + { + err.span_suggestion_verbose( + field.span, + "a field with a similar name exists", + format!("{unwrap}{}", field_name), + Applicability::MaybeIncorrect, + ); + } else if !field_names.is_empty() { + let is = if field_names.len() == 1 { " is" } else { "s are" }; + err.note( + format!("available field{is}: {}", self.name_series_display(field_names),), + ); } } err diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 15e3ba4ffc2..8348c6e9a16 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -506,6 +506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_def_id, call_span, call_expr, + tuple_arguments, ); } } @@ -520,6 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_def_id: Option<DefId>, call_span: Span, call_expr: &'tcx hir::Expr<'tcx>, + tuple_arguments: TupleArgumentsFlag, ) -> ErrorGuaranteed { // Next, let's construct the error let (error_span, call_ident, full_call_span, call_name, is_method) = match &call_expr.kind { @@ -865,6 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &matched_inputs, &formal_and_expected_inputs, is_method, + tuple_arguments, ); suggest_confusable(&mut err); return err.emit(); @@ -1001,6 +1004,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &matched_inputs, &formal_and_expected_inputs, is_method, + tuple_arguments, ); suggest_confusable(&mut err); return err.emit(); @@ -1448,6 +1452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &matched_inputs, &formal_and_expected_inputs, is_method, + tuple_arguments, ); // And add a suggestion block for all of the parameters @@ -2219,21 +2224,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>, formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, is_method: bool, + tuple_arguments: TupleArgumentsFlag, ) { let Some(mut def_id) = callable_def_id else { return; }; + // If we're calling a method of a Fn/FnMut/FnOnce trait object implicitly + // (eg invoking a closure) we want to point at the underlying callable, + // not the method implicitly invoked (eg call_once). if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) - // Possibly points at either impl or trait item, so try to get it - // to point to trait item, then get the parent. - // This parent might be an impl in the case of an inherent function, - // but the next check will fail. + // Since this is an associated item, it might point at either an impl or a trait item. + // We want it to always point to the trait item. + // If we're pointing at an inherent function, we don't need to do anything, + // so we fetch the parent and verify if it's a trait item. && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id) && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id) // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce" && let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id) && let Some(callee_ty) = callee_ty + // TupleArguments is set only when this is an implicit call (my_closure(...)) rather than explicit (my_closure.call(...)) + && tuple_arguments == TupleArguments { let callee_ty = callee_ty.peel_refs(); match *callee_ty.kind() { @@ -2303,166 +2314,173 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let mut spans: MultiSpan = def_span.into(); - let params_with_generics = self.get_hir_params_with_generics(def_id, is_method); - let mut generics_with_unmatched_params = Vec::new(); + if let Some(params_with_generics) = self.get_hir_params_with_generics(def_id, is_method) + { + debug_assert_eq!(params_with_generics.len(), matched_inputs.len()); - let check_for_matched_generics = || { - if matched_inputs.iter().any(|x| x.is_some()) - && params_with_generics.iter().any(|x| x.0.is_some()) - { - for (idx, (generic, _)) in params_with_generics.iter().enumerate() { - // Param has to have a generic and be matched to be relevant - if matched_inputs[idx.into()].is_none() { - continue; - } + let mut generics_with_unmatched_params = Vec::new(); - let Some(generic) = generic else { - continue; - }; + let check_for_matched_generics = || { + if matched_inputs.iter().any(|x| x.is_some()) + && params_with_generics.iter().any(|x| x.0.is_some()) + { + for (idx, (generic, _)) in params_with_generics.iter().enumerate() { + // Param has to have a generic and be matched to be relevant + if matched_inputs[idx.into()].is_none() { + continue; + } - for unmatching_idx in idx + 1..params_with_generics.len() { - if matched_inputs[unmatching_idx.into()].is_none() - && let Some(unmatched_idx_param_generic) = - params_with_generics[unmatching_idx].0 - && unmatched_idx_param_generic.name.ident() == generic.name.ident() - { - // We found a parameter that didn't match that needed to - return true; + let Some(generic) = generic else { + continue; + }; + + for unmatching_idx in idx + 1..params_with_generics.len() { + if matched_inputs[unmatching_idx.into()].is_none() + && let Some(unmatched_idx_param_generic) = + params_with_generics[unmatching_idx].0 + && unmatched_idx_param_generic.name.ident() + == generic.name.ident() + { + // We found a parameter that didn't match that needed to + return true; + } } } } - } - false - }; - - let check_for_matched_generics = check_for_matched_generics(); - - for (idx, (generic_param, param)) in - params_with_generics.iter().enumerate().filter(|(idx, _)| { - check_for_matched_generics - || expected_idx.is_none_or(|expected_idx| expected_idx == *idx) - }) - { - let Some(generic_param) = generic_param else { - spans.push_span_label(param.span, ""); - continue; + false }; - let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics - .iter() - .enumerate() - .filter(|(other_idx, (other_generic_param, _))| { - if *other_idx == idx { - return false; - } - let Some(other_generic_param) = other_generic_param else { - return false; - }; - if matched_inputs[idx.into()].is_none() - && matched_inputs[(*other_idx).into()].is_none() - { - return false; - } - if matched_inputs[idx.into()].is_some() - && matched_inputs[(*other_idx).into()].is_some() - { - return false; - } - other_generic_param.name.ident() == generic_param.name.ident() + let check_for_matched_generics = check_for_matched_generics(); + + for (idx, (generic_param, param)) in + params_with_generics.iter().enumerate().filter(|(idx, _)| { + check_for_matched_generics + || expected_idx.is_none_or(|expected_idx| expected_idx == *idx) }) - .map(|(other_idx, (_, other_param))| (other_idx, *other_param)) - .collect(); + { + let Some(generic_param) = generic_param else { + spans.push_span_label(param.span, ""); + continue; + }; - if !other_params_matched.is_empty() { - let other_param_matched_names: Vec<String> = other_params_matched + let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics .iter() - .map(|(_, other_param)| { - if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind { - format!("`{ident}`") - } else { - "{unknown}".to_string() + .enumerate() + .filter(|(other_idx, (other_generic_param, _))| { + if *other_idx == idx { + return false; + } + let Some(other_generic_param) = other_generic_param else { + return false; + }; + if matched_inputs[idx.into()].is_none() + && matched_inputs[(*other_idx).into()].is_none() + { + return false; } + if matched_inputs[idx.into()].is_some() + && matched_inputs[(*other_idx).into()].is_some() + { + return false; + } + other_generic_param.name.ident() == generic_param.name.ident() }) + .map(|(other_idx, (_, other_param))| (other_idx, *other_param)) .collect(); - let matched_ty = self - .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) - .sort_string(self.tcx); + if !other_params_matched.is_empty() { + let other_param_matched_names: Vec<String> = other_params_matched + .iter() + .map(|(_, other_param)| { + if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind + { + format!("`{ident}`") + } else { + "{unknown}".to_string() + } + }) + .collect(); - if matched_inputs[idx.into()].is_some() { - spans.push_span_label( - param.span, - format!( - "{} {} to match the {} type of this parameter", - display_list_with_comma_and(&other_param_matched_names), + let matched_ty = self + .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) + .sort_string(self.tcx); + + if matched_inputs[idx.into()].is_some() { + spans.push_span_label( + param.span, format!( - "need{}", - pluralize!(if other_param_matched_names.len() == 1 { - 0 - } else { - 1 - }) + "{} {} to match the {} type of this parameter", + display_list_with_comma_and(&other_param_matched_names), + format!( + "need{}", + pluralize!(if other_param_matched_names.len() == 1 { + 0 + } else { + 1 + }) + ), + matched_ty, ), - matched_ty, - ), - ); + ); + } else { + spans.push_span_label( + param.span, + format!( + "this parameter needs to match the {} type of {}", + matched_ty, + display_list_with_comma_and(&other_param_matched_names), + ), + ); + } + generics_with_unmatched_params.push(generic_param); } else { + spans.push_span_label(param.span, ""); + } + } + + for generic_param in self + .tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.generics()) + .into_iter() + .flat_map(|x| x.params) + .filter(|x| { + generics_with_unmatched_params + .iter() + .any(|y| x.name.ident() == y.name.ident()) + }) + { + let param_idents_matching: Vec<String> = params_with_generics + .iter() + .filter(|(generic, _)| { + if let Some(generic) = generic { + generic.name.ident() == generic_param.name.ident() + } else { + false + } + }) + .map(|(_, param)| { + if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind { + format!("`{ident}`") + } else { + "{unknown}".to_string() + } + }) + .collect(); + + if !param_idents_matching.is_empty() { spans.push_span_label( - param.span, + generic_param.span, format!( - "this parameter needs to match the {} type of {}", - matched_ty, - display_list_with_comma_and(&other_param_matched_names), + "{} all reference this parameter {}", + display_list_with_comma_and(¶m_idents_matching), + generic_param.name.ident().name, ), ); } - generics_with_unmatched_params.push(generic_param); - } else { - spans.push_span_label(param.span, ""); } } - - for generic_param in self - .tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.generics()) - .into_iter() - .flat_map(|x| x.params) - .filter(|x| { - generics_with_unmatched_params.iter().any(|y| x.name.ident() == y.name.ident()) - }) - { - let param_idents_matching: Vec<String> = params_with_generics - .iter() - .filter(|(generic, _)| { - if let Some(generic) = generic { - generic.name.ident() == generic_param.name.ident() - } else { - false - } - }) - .map(|(_, param)| { - if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind { - format!("`{ident}`") - } else { - "{unknown}".to_string() - } - }) - .collect(); - - if !param_idents_matching.is_empty() { - spans.push_span_label( - generic_param.span, - format!( - "{} all reference this parameter {}", - display_list_with_comma_and(¶m_idents_matching), - generic_param.name.ident().name, - ), - ); - } - } - err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id) && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind @@ -2535,74 +2553,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; - let params_with_generics = self.get_hir_params_with_generics(def_id, is_method); - - for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() { - if matched_inputs[idx.into()].is_none() { - continue; - } + if let Some(params_with_generics) = self.get_hir_params_with_generics(def_id, is_method) { + debug_assert_eq!(params_with_generics.len(), matched_inputs.len()); + for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() { + if matched_inputs[idx.into()].is_none() { + continue; + } - let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else { - continue; - }; + let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else { + continue; + }; - let Some(generic_param) = generic_param else { - continue; - }; + let Some(generic_param) = generic_param else { + continue; + }; - let mut idxs_matched: Vec<usize> = vec![]; - for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter( - |(other_idx, (other_generic_param, _))| { - if *other_idx == idx { - return false; - } - let Some(other_generic_param) = other_generic_param else { - return false; - }; - if matched_inputs[(*other_idx).into()].is_some() { - return false; - } - other_generic_param.name.ident() == generic_param.name.ident() - }, - ) { - idxs_matched.push(other_idx.into()); - } + let mut idxs_matched: Vec<usize> = vec![]; + for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter( + |(other_idx, (other_generic_param, _))| { + if *other_idx == idx { + return false; + } + let Some(other_generic_param) = other_generic_param else { + return false; + }; + if matched_inputs[(*other_idx).into()].is_some() { + return false; + } + other_generic_param.name.ident() == generic_param.name.ident() + }, + ) { + idxs_matched.push(other_idx); + } - if idxs_matched.is_empty() { - continue; - } + if idxs_matched.is_empty() { + continue; + } - let expected_display_type = self - .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) - .sort_string(self.tcx); - let label = if idxs_matched.len() == params_with_generics.len() - 1 { - format!( - "expected all arguments to be this {} type because they need to match the type of this parameter", - expected_display_type - ) - } else { - format!( - "expected some other arguments to be {} {} type to match the type of this parameter", - a_or_an(&expected_display_type), - expected_display_type, - ) - }; + let expected_display_type = self + .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) + .sort_string(self.tcx); + let label = if idxs_matched.len() == params_with_generics.len() - 1 { + format!( + "expected all arguments to be this {} type because they need to match the type of this parameter", + expected_display_type + ) + } else { + format!( + "expected some other arguments to be {} {} type to match the type of this parameter", + a_or_an(&expected_display_type), + expected_display_type, + ) + }; - err.span_label(*matched_arg_span, label); + err.span_label(*matched_arg_span, label); + } } } + /// Returns the parameters of a function, with their generic parameters if those are the full + /// type of that parameter. Returns `None` if the function body is unavailable (eg is an instrinsic). fn get_hir_params_with_generics( &self, def_id: DefId, is_method: bool, - ) -> Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)> { - let fn_node = self.tcx.hir().get_if_local(def_id); + ) -> Option<Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)>> { + let fn_node = self.tcx.hir().get_if_local(def_id)?; let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_node - .and_then(|node| node.fn_decl()) + .fn_decl()? + .inputs .into_iter() - .flat_map(|decl| decl.inputs) .skip(if is_method { 1 } else { 0 }) .map(|param| { if let hir::TyKind::Path(QPath::Resolved( @@ -2611,7 +2632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )) = param.kind { fn_node - .and_then(|node| node.generics()) + .generics() .into_iter() .flat_map(|generics| generics.params) .find(|param| ¶m.def_id.to_def_id() == res_def_id) @@ -2621,14 +2642,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect(); - let params: Vec<&hir::Param<'_>> = fn_node - .and_then(|node| node.body_id()) + let params: Vec<&hir::Param<'_>> = self + .tcx + .hir() + .body(fn_node.body_id()?) + .params .into_iter() - .flat_map(|id| self.tcx.hir().body(id).params) .skip(if is_method { 1 } else { 0 }) .collect(); - generic_params.into_iter().zip(params).collect() + Some(generic_params.into_iter().zip_eq(params).collect()) } } diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 4ea22884cf3..2f990de7e31 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -158,14 +158,12 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { ), ); } - } else { - if !self.fcx.tcx.features().unsized_locals { - self.fcx.require_type_is_sized( - var_ty, - p.span, - ObligationCauseCode::VariableType(p.hir_id), - ); - } + } else if !self.fcx.tcx.features().unsized_locals { + self.fcx.require_type_is_sized( + var_ty, + p.span, + ObligationCauseCode::VariableType(p.hir_id), + ); } debug!( diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 178d5dce086..9ede809ead2 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1252,11 +1252,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && suggested_bounds.contains(parent) { // We don't suggest `PartialEq` when we already suggest `Eq`. - } else if !suggested_bounds.contains(pred) { - if collect_type_param_suggestions(self_ty, *pred, &p) { - suggested = true; - suggested_bounds.insert(pred); - } + } else if !suggested_bounds.contains(pred) + && collect_type_param_suggestions(self_ty, *pred, &p) + { + suggested = true; + suggested_bounds.insert(pred); } ( match parent_pred { @@ -1267,14 +1267,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !suggested && !suggested_bounds.contains(pred) && !suggested_bounds.contains(parent_pred) - { - if collect_type_param_suggestions( + && collect_type_param_suggestions( self_ty, *parent_pred, &p, - ) { - suggested_bounds.insert(pred); - } + ) + { + suggested_bounds.insert(pred); } format!("`{p}`\nwhich is required by `{parent_p}`") } diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 88cb82f0f37..cef0b23143d 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -417,12 +417,10 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol { if let Some(value) = item.value_str() { value + } else if let Some(ident) = item.ident() { + tcx.dcx().emit_fatal(errors::AssociatedValueExpectedFor { span: item.span(), ident }); } else { - if let Some(ident) = item.ident() { - tcx.dcx().emit_fatal(errors::AssociatedValueExpectedFor { span: item.span(), ident }); - } else { - tcx.dcx().emit_fatal(errors::AssociatedValueExpected { span: item.span() }); - } + tcx.dcx().emit_fatal(errors::AssociatedValueExpected { span: item.span() }); } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 50422df8ee6..080f2a1785a 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -808,7 +808,7 @@ fn test_unstable_options_tracking_hash() { tracked!(mir_opt_level, Some(4)); tracked!(move_size_limit, Some(4096)); tracked!(mutable_noalias, false); - tracked!(next_solver, NextSolverConfig { coherence: true, globally: true }); + tracked!(next_solver, Some(NextSolverConfig { coherence: true, globally: false })); tracked!(no_generate_arange_section, true); tracked!(no_jump_tables, true); tracked!(no_link, true); @@ -847,6 +847,7 @@ fn test_unstable_options_tracking_hash() { tracked!(share_generics, Some(true)); tracked!(show_span, Some(String::from("abc"))); tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc"))); + tracked!(small_data_threshold, Some(16)); tracked!(split_lto_unit, Some(true)); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); tracked!(stack_protector, StackProtector::All); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7d4dee45c26..4aa86944a0b 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -334,6 +334,11 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len -> *[other] {" "}{$identifier_type} } Unicode general security profile +lint_if_let_rescope = `if let` assigns a shorter lifetime since Edition 2024 + .label = this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + .help = the value is now dropped here in Edition 2024 + .suggestion = a `match` with a single arm can preserve the drop order up to Edition 2021 + lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level lint_ill_formed_attribute_input = {$num_suggestions -> diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 7de92a43a9a..8b92180e9bd 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -429,10 +429,8 @@ impl MissingDoc { // Only check publicly-visible items, using the result from the privacy pass. // It's an option so the crate root can also use this function (it doesn't // have a `NodeId`). - if def_id != CRATE_DEF_ID { - if !cx.effective_visibilities.is_exported(def_id) { - return; - } + if def_id != CRATE_DEF_ID && !cx.effective_visibilities.is_exported(def_id) { + return; } let attrs = cx.tcx.hir().attrs(cx.tcx.local_def_id_to_hir_id(def_id)); diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index a60fc0ffbbb..33b8b7c544b 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -3,8 +3,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::query::Providers; -use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt}; use rustc_session::declare_lint; use rustc_span::{sym, Span, Symbol}; use rustc_target::abi::FIRST_VARIANT; @@ -212,7 +211,17 @@ fn structurally_same_type<'tcx>( ckind: types::CItemKind, ) -> bool { let mut seen_types = UnordSet::default(); - structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind) + let result = structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind); + if cfg!(debug_assertions) && result { + // Sanity-check: must have same ABI, size and alignment. + // `extern` blocks cannot be generic, so we'll always get a layout here. + let a_layout = tcx.layout_of(param_env.and(a)).unwrap(); + let b_layout = tcx.layout_of(param_env.and(b)).unwrap(); + assert_eq!(a_layout.abi, b_layout.abi); + assert_eq!(a_layout.size, b_layout.size); + assert_eq!(a_layout.align, b_layout.align); + } + result } fn structurally_same_type_impl<'tcx>( @@ -266,30 +275,21 @@ fn structurally_same_type_impl<'tcx>( // Do a full, depth-first comparison between the two. use rustc_type_ir::TyKind::*; - let compare_layouts = |a, b| -> Result<bool, &'tcx LayoutError<'tcx>> { - debug!("compare_layouts({:?}, {:?})", a, b); - let a_layout = &tcx.layout_of(param_env.and(a))?.layout.abi(); - let b_layout = &tcx.layout_of(param_env.and(b))?.layout.abi(); - debug!( - "comparing layouts: {:?} == {:?} = {}", - a_layout, - b_layout, - a_layout == b_layout - ); - Ok(a_layout == b_layout) - }; - let is_primitive_or_pointer = |ty: Ty<'tcx>| ty.is_primitive() || matches!(ty.kind(), RawPtr(..) | Ref(..)); ensure_sufficient_stack(|| { match (a.kind(), b.kind()) { - (Adt(a_def, _), Adt(b_def, _)) => { - // We can immediately rule out these types as structurally same if - // their layouts differ. - match compare_layouts(a, b) { - Ok(false) => return false, - _ => (), // otherwise, continue onto the full, fields comparison + (&Adt(a_def, _), &Adt(b_def, _)) => { + // Only `repr(C)` types can be compared structurally. + if !(a_def.repr().c() && b_def.repr().c()) { + return false; + } + // If the types differ in their packed-ness, align, or simd-ness they conflict. + let repr_characteristica = + |def: AdtDef<'tcx>| (def.repr().pack, def.repr().align, def.repr().simd()); + if repr_characteristica(a_def) != repr_characteristica(b_def) { + return false; } // Grab a flattened representation of all fields. @@ -311,9 +311,9 @@ fn structurally_same_type_impl<'tcx>( }, ) } - (Array(a_ty, a_const), Array(b_ty, b_const)) => { - // For arrays, we also check the constness of the type. - a_const.kind() == b_const.kind() + (Array(a_ty, a_len), Array(b_ty, b_len)) => { + // For arrays, we also check the length. + a_len == b_len && structurally_same_type_impl( seen_types, tcx, param_env, *a_ty, *b_ty, ckind, ) @@ -357,10 +357,9 @@ fn structurally_same_type_impl<'tcx>( ckind, ) } - (Tuple(a_args), Tuple(b_args)) => { - a_args.iter().eq_by(b_args.iter(), |a_ty, b_ty| { - structurally_same_type_impl(seen_types, tcx, param_env, a_ty, b_ty, ckind) - }) + (Tuple(..), Tuple(..)) => { + // Tuples are not `repr(C)` so these cannot be compared structurally. + false } // For these, it's not quite as easy to define structural-sameness quite so easily. // For the purposes of this lint, take the conservative approach and mark them as @@ -380,24 +379,21 @@ fn structurally_same_type_impl<'tcx>( // An Adt and a primitive or pointer type. This can be FFI-safe if non-null // enum layout optimisation is being applied. (Adt(..), _) if is_primitive_or_pointer(b) => { - if let Some(ty) = types::repr_nullable_ptr(tcx, param_env, a, ckind) { - ty == b + if let Some(a_inner) = types::repr_nullable_ptr(tcx, param_env, a, ckind) { + a_inner == b } else { - compare_layouts(a, b).unwrap_or(false) + false } } (_, Adt(..)) if is_primitive_or_pointer(a) => { - if let Some(ty) = types::repr_nullable_ptr(tcx, param_env, b, ckind) { - ty == a + if let Some(b_inner) = types::repr_nullable_ptr(tcx, param_env, b, ckind) { + b_inner == a } else { - compare_layouts(a, b).unwrap_or(false) + false } } - // Otherwise, just compare the layouts. This may fail to lint for some - // incompatible types, but at the very least, will stop reads into - // uninitialised memory. - _ => compare_layouts(a, b).unwrap_or(false), + _ => false, } }) } diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs new file mode 100644 index 00000000000..5b65541bea6 --- /dev/null +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -0,0 +1,430 @@ +use std::iter::repeat; +use std::ops::ControlFlow; + +use hir::intravisit::Visitor; +use rustc_ast::Recovered; +use rustc_errors::{ + Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, +}; +use rustc_hir::{self as hir, HirIdSet}; +use rustc_macros::LintDiagnostic; +use rustc_middle::ty::TyCtxt; +use rustc_session::lint::{FutureIncompatibilityReason, Level}; +use rustc_session::{declare_lint, impl_lint_pass}; +use rustc_span::edition::Edition; +use rustc_span::Span; + +use crate::{LateContext, LateLintPass}; + +declare_lint! { + /// The `if_let_rescope` lint detects cases where a temporary value with + /// significant drop is generated on the right hand side of `if let` + /// and suggests a rewrite into `match` when possible. + /// + /// ### Example + /// + /// ```rust,edition2021 + /// #![feature(if_let_rescope)] + /// #![warn(if_let_rescope)] + /// #![allow(unused_variables)] + /// + /// struct Droppy; + /// impl Drop for Droppy { + /// fn drop(&mut self) { + /// // Custom destructor, including this `drop` implementation, is considered + /// // significant. + /// // Rust does not check whether this destructor emits side-effects that can + /// // lead to observable change in program semantics, when the drop order changes. + /// // Rust biases to be on the safe side, so that you can apply discretion whether + /// // this change indeed breaches any contract or specification that your code needs + /// // to honour. + /// println!("dropped"); + /// } + /// } + /// impl Droppy { + /// fn get(&self) -> Option<u8> { + /// None + /// } + /// } + /// + /// fn main() { + /// if let Some(value) = Droppy.get() { + /// // do something + /// } else { + /// // do something else + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// With Edition 2024, temporaries generated while evaluating `if let`s + /// will be dropped before the `else` block. + /// This lint captures a possible change in runtime behaviour due to + /// a change in sequence of calls to significant `Drop::drop` destructors. + /// + /// A significant [`Drop::drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html) + /// destructor here refers to an explicit, arbitrary implementation of the `Drop` trait on the type + /// with exceptions including `Vec`, `Box`, `Rc`, `BTreeMap` and `HashMap` + /// that are marked by the compiler otherwise so long that the generic types have + /// no significant destructor recursively. + /// In other words, a type has a significant drop destructor when it has a `Drop` implementation + /// or its destructor invokes a significant destructor on a type. + /// Since we cannot completely reason about the change by just inspecting the existence of + /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default. + /// + /// Whenever possible, a rewrite into an equivalent `match` expression that + /// observe the same order of calls to such destructors is proposed by this lint. + /// Authors may take their own discretion whether the rewrite suggestion shall be + /// accepted, or rejected to continue the use of the `if let` expression. + pub IF_LET_RESCOPE, + Allow, + "`if let` assigns a shorter lifetime to temporary values being pattern-matched against in Edition 2024 and \ + rewriting in `match` is an option to preserve the semantics up to Edition 2021", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), + reference: "issue #124085 <https://github.com/rust-lang/rust/issues/124085>", + }; +} + +/// Lint for potential change in program semantics of `if let`s +#[derive(Default)] +pub(crate) struct IfLetRescope { + skip: HirIdSet, +} + +fn expr_parent_is_else(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { + let Some((_, hir::Node::Expr(expr))) = tcx.hir().parent_iter(hir_id).next() else { + return false; + }; + let hir::ExprKind::If(_cond, _conseq, Some(alt)) = expr.kind else { return false }; + alt.hir_id == hir_id +} + +fn expr_parent_is_stmt(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { + let Some((_, hir::Node::Stmt(stmt))) = tcx.hir().parent_iter(hir_id).next() else { + return false; + }; + let (hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr)) = stmt.kind else { return false }; + expr.hir_id == hir_id +} + +fn match_head_needs_bracket(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> bool { + expr_parent_is_else(tcx, expr.hir_id) && matches!(expr.kind, hir::ExprKind::If(..)) +} + +impl IfLetRescope { + fn probe_if_cascade<'tcx>(&mut self, cx: &LateContext<'tcx>, mut expr: &'tcx hir::Expr<'tcx>) { + if self.skip.contains(&expr.hir_id) { + return; + } + let tcx = cx.tcx; + let source_map = tcx.sess.source_map(); + let expr_end = expr.span.shrink_to_hi(); + let mut add_bracket_to_match_head = match_head_needs_bracket(tcx, expr); + let mut significant_droppers = vec![]; + let mut lifetime_ends = vec![]; + let mut closing_brackets = 0; + let mut alt_heads = vec![]; + let mut match_heads = vec![]; + let mut consequent_heads = vec![]; + let mut first_if_to_lint = None; + let mut first_if_to_rewrite = false; + let mut empty_alt = false; + while let hir::ExprKind::If(cond, conseq, alt) = expr.kind { + self.skip.insert(expr.hir_id); + // We are interested in `let` fragment of the condition. + // Otherwise, we probe into the `else` fragment. + if let hir::ExprKind::Let(&hir::LetExpr { + span, + pat, + init, + ty: ty_ascription, + recovered: Recovered::No, + }) = cond.kind + { + let if_let_pat = expr.span.shrink_to_lo().between(init.span); + // The consequent fragment is always a block. + let before_conseq = conseq.span.shrink_to_lo(); + let lifetime_end = source_map.end_point(conseq.span); + + if let ControlFlow::Break(significant_dropper) = + (FindSignificantDropper { cx }).visit_expr(init) + { + first_if_to_lint = first_if_to_lint.or_else(|| Some((span, expr.hir_id))); + significant_droppers.push(significant_dropper); + lifetime_ends.push(lifetime_end); + if ty_ascription.is_some() + || !expr.span.can_be_used_for_suggestions() + || !pat.span.can_be_used_for_suggestions() + { + // Our `match` rewrites does not support type ascription, + // so we just bail. + // Alternatively when the span comes from proc macro expansion, + // we will also bail. + // FIXME(#101728): change this when type ascription syntax is stabilized again + } else if let Ok(pat) = source_map.span_to_snippet(pat.span) { + let emit_suggestion = |alt_span| { + first_if_to_rewrite = true; + if add_bracket_to_match_head { + closing_brackets += 2; + match_heads.push(SingleArmMatchBegin::WithOpenBracket(if_let_pat)); + } else { + // Sometimes, wrapping `match` into a block is undesirable, + // because the scrutinee temporary lifetime is shortened and + // the proposed fix will not work. + closing_brackets += 1; + match_heads + .push(SingleArmMatchBegin::WithoutOpenBracket(if_let_pat)); + } + consequent_heads.push(ConsequentRewrite { span: before_conseq, pat }); + if let Some(alt_span) = alt_span { + alt_heads.push(AltHead(alt_span)); + } + }; + if let Some(alt) = alt { + let alt_head = conseq.span.between(alt.span); + if alt_head.can_be_used_for_suggestions() { + // We lint only when the `else` span is user code, too. + emit_suggestion(Some(alt_head)); + } + } else { + // This is the end of the `if .. else ..` cascade. + // We can stop here. + emit_suggestion(None); + empty_alt = true; + break; + } + } + } + } + // At this point, any `if let` fragment in the cascade is definitely preceeded by `else`, + // so a opening bracket is mandatory before each `match`. + add_bracket_to_match_head = true; + if let Some(alt) = alt { + expr = alt; + } else { + break; + } + } + if let Some((span, hir_id)) = first_if_to_lint { + tcx.emit_node_span_lint( + IF_LET_RESCOPE, + hir_id, + span, + IfLetRescopeLint { + significant_droppers, + lifetime_ends, + rewrite: first_if_to_rewrite.then_some(IfLetRescopeRewrite { + match_heads, + consequent_heads, + closing_brackets: ClosingBrackets { + span: expr_end, + count: closing_brackets, + empty_alt, + }, + alt_heads, + }), + }, + ); + } + } +} + +impl_lint_pass!( + IfLetRescope => [IF_LET_RESCOPE] +); + +impl<'tcx> LateLintPass<'tcx> for IfLetRescope { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope { + return; + } + if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) { + return; + } + if expr_parent_is_stmt(cx.tcx, expr.hir_id) + && matches!(expr.kind, hir::ExprKind::If(_cond, _conseq, None)) + { + // `if let` statement without an `else` branch has no observable change + // so we can skip linting it + return; + } + self.probe_if_cascade(cx, expr); + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_if_let_rescope)] +struct IfLetRescopeLint { + #[label] + significant_droppers: Vec<Span>, + #[help] + lifetime_ends: Vec<Span>, + #[subdiagnostic] + rewrite: Option<IfLetRescopeRewrite>, +} + +// #[derive(Subdiagnostic)] +struct IfLetRescopeRewrite { + match_heads: Vec<SingleArmMatchBegin>, + consequent_heads: Vec<ConsequentRewrite>, + closing_brackets: ClosingBrackets, + alt_heads: Vec<AltHead>, +} + +impl Subdiagnostic for IfLetRescopeRewrite { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + let mut suggestions = vec![]; + for match_head in self.match_heads { + match match_head { + SingleArmMatchBegin::WithOpenBracket(span) => { + suggestions.push((span, "{ match ".into())) + } + SingleArmMatchBegin::WithoutOpenBracket(span) => { + suggestions.push((span, "match ".into())) + } + } + } + for ConsequentRewrite { span, pat } in self.consequent_heads { + suggestions.push((span, format!("{{ {pat} => "))); + } + for AltHead(span) in self.alt_heads { + suggestions.push((span, " _ => ".into())); + } + let closing_brackets = self.closing_brackets; + suggestions.push(( + closing_brackets.span, + closing_brackets + .empty_alt + .then_some(" _ => {}".chars()) + .into_iter() + .flatten() + .chain(repeat('}').take(closing_brackets.count)) + .collect(), + )); + let msg = f(diag, crate::fluent_generated::lint_suggestion.into()); + diag.multipart_suggestion_with_style( + msg, + suggestions, + Applicability::MachineApplicable, + SuggestionStyle::ShowCode, + ); + } +} + +struct AltHead(Span); + +struct ConsequentRewrite { + span: Span, + pat: String, +} + +struct ClosingBrackets { + span: Span, + count: usize, + empty_alt: bool, +} +enum SingleArmMatchBegin { + WithOpenBracket(Span), + WithoutOpenBracket(Span), +} + +struct FindSignificantDropper<'tcx, 'a> { + cx: &'a LateContext<'tcx>, +} + +impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> { + type Result = ControlFlow<Span>; + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result { + if self + .cx + .typeck_results() + .expr_ty(expr) + .has_significant_drop(self.cx.tcx, self.cx.param_env) + { + return ControlFlow::Break(expr.span); + } + match expr.kind { + hir::ExprKind::ConstBlock(_) + | hir::ExprKind::Lit(_) + | hir::ExprKind::Path(_) + | hir::ExprKind::Assign(_, _, _) + | hir::ExprKind::AssignOp(_, _, _) + | hir::ExprKind::Break(_, _) + | hir::ExprKind::Continue(_) + | hir::ExprKind::Ret(_) + | hir::ExprKind::Become(_) + | hir::ExprKind::InlineAsm(_) + | hir::ExprKind::OffsetOf(_, _) + | hir::ExprKind::Repeat(_, _) + | hir::ExprKind::Err(_) + | hir::ExprKind::Struct(_, _, _) + | hir::ExprKind::Closure(_) + | hir::ExprKind::Block(_, _) + | hir::ExprKind::DropTemps(_) + | hir::ExprKind::Loop(_, _, _, _) => ControlFlow::Continue(()), + + hir::ExprKind::Tup(exprs) | hir::ExprKind::Array(exprs) => { + for expr in exprs { + self.visit_expr(expr)?; + } + ControlFlow::Continue(()) + } + hir::ExprKind::Call(callee, args) => { + self.visit_expr(callee)?; + for expr in args { + self.visit_expr(expr)?; + } + ControlFlow::Continue(()) + } + hir::ExprKind::MethodCall(_, receiver, args, _) => { + self.visit_expr(receiver)?; + for expr in args { + self.visit_expr(expr)?; + } + ControlFlow::Continue(()) + } + hir::ExprKind::Index(left, right, _) | hir::ExprKind::Binary(_, left, right) => { + self.visit_expr(left)?; + self.visit_expr(right) + } + hir::ExprKind::Unary(_, expr) + | hir::ExprKind::Cast(expr, _) + | hir::ExprKind::Type(expr, _) + | hir::ExprKind::Yield(expr, _) + | hir::ExprKind::AddrOf(_, _, expr) + | hir::ExprKind::Match(expr, _, _) + | hir::ExprKind::Field(expr, _) + | hir::ExprKind::Let(&hir::LetExpr { + init: expr, + span: _, + pat: _, + ty: _, + recovered: Recovered::No, + }) => self.visit_expr(expr), + hir::ExprKind::Let(_) => ControlFlow::Continue(()), + + hir::ExprKind::If(cond, _, _) => { + if let hir::ExprKind::Let(hir::LetExpr { + init, + span: _, + pat: _, + ty: _, + recovered: Recovered::No, + }) = cond.kind + { + self.visit_expr(init)?; + } + ControlFlow::Continue(()) + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4139ac4e3e9..5c67e21687f 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -56,6 +56,7 @@ mod expect; mod for_loops_over_fallibles; mod foreign_modules; pub mod hidden_unicode_codepoints; +mod if_let_rescope; mod impl_trait_overcaptures; mod internal; mod invalid_from_utf8; @@ -94,6 +95,7 @@ use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; +use if_let_rescope::IfLetRescope; use impl_trait_overcaptures::ImplTraitOvercaptures; use internal::*; use invalid_from_utf8::*; @@ -243,6 +245,7 @@ late_lint_methods!( NonLocalDefinitions: NonLocalDefinitions::default(), ImplTraitOvercaptures: ImplTraitOvercaptures, TailExprDropOrder: TailExprDropOrder, + IfLetRescope: IfLetRescope::default(), ] ] ); diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 6ef1801717c..999743ed73b 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -96,6 +96,7 @@ impl fmt::Debug for Scope { ScopeData::Arguments => write!(fmt, "Arguments({:?})", self.id), ScopeData::Destruction => write!(fmt, "Destruction({:?})", self.id), ScopeData::IfThen => write!(fmt, "IfThen({:?})", self.id), + ScopeData::IfThenRescope => write!(fmt, "IfThen[edition2024]({:?})", self.id), ScopeData::Remainder(fsi) => write!( fmt, "Remainder {{ block: {:?}, first_statement_index: {}}}", @@ -126,6 +127,11 @@ pub enum ScopeData { /// Used for variables introduced in an if-let expression. IfThen, + /// Scope of the condition and then block of an if expression + /// Used for variables introduced in an if-let expression, + /// whose lifetimes do not cross beyond this scope. + IfThenRescope, + /// Scope following a `let id = expr;` binding in a block. Remainder(FirstStatementIndex), } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 3b8861378e0..86dca27f04f 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -444,10 +444,11 @@ impl<'tcx> TyCtxt<'tcx> { // the `-Z force-unstable-if-unmarked` flag present (we're // compiling a compiler crate), then let this missing feature // annotation slide. - if feature == sym::rustc_private && issue == NonZero::new(27812) { - if self.sess.opts.unstable_opts.force_unstable_if_unmarked { - return EvalResult::Allow; - } + if feature == sym::rustc_private + && issue == NonZero::new(27812) + && self.sess.opts.unstable_opts.force_unstable_if_unmarked + { + return EvalResult::Allow; } if matches!(allow_unstable, AllowUnstable::Yes) { diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index fc38f27137e..4c5da188860 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -448,22 +448,20 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> bad: uninit_range, })) })?; - if !Prov::OFFSET_IS_ADDR { - if !self.provenance.range_empty(range, cx) { - // Find the provenance. - let (offset, _prov) = self - .provenance - .range_get_ptrs(range, cx) - .first() - .copied() - .expect("there must be provenance somewhere here"); - let start = offset.max(range.start); // the pointer might begin before `range`! - let end = (offset + cx.pointer_size()).min(range.end()); // the pointer might end after `range`! - return Err(AllocError::ReadPointerAsInt(Some(BadBytesAccess { - access: range, - bad: AllocRange::from(start..end), - }))); - } + if !Prov::OFFSET_IS_ADDR && !self.provenance.range_empty(range, cx) { + // Find the provenance. + let (offset, _prov) = self + .provenance + .range_get_ptrs(range, cx) + .first() + .copied() + .expect("there must be provenance somewhere here"); + let start = offset.max(range.start); // the pointer might begin before `range`! + let end = (offset + cx.pointer_size()).min(range.end()); // the pointer might end after `range`! + return Err(AllocError::ReadPointerAsInt(Some(BadBytesAccess { + access: range, + bad: AllocRange::from(start..end), + }))); } Ok(self.get_bytes_unchecked(range)) } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 26addb1e357..e312e65cc21 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1084,6 +1084,9 @@ pub enum LocalInfo<'tcx> { /// (with no intervening statement context). // FIXME(matthewjasper) Don't store in this in `Body` BlockTailTemp(BlockTailInfo), + /// A temporary created during evaluating `if` predicate, possibly for pattern matching for `let`s, + /// and subject to Edition 2024 temporary lifetime rules + IfThenRescopeTemp { if_then: HirId }, /// A temporary created during the pass `Derefer` to avoid it's retagging DerefTemp, /// A temporary created for borrow checking. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index a98e6943d68..d66d0be1009 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -208,12 +208,10 @@ fn dump_path<'tcx>( let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number { String::new() + } else if pass_num { + format!(".{:03}-{:03}", body.phase.phase_index(), body.pass_count) } else { - if pass_num { - format!(".{:03}-{:03}", body.phase.phase_index(), body.pass_count) - } else { - ".-------".to_string() - } + ".-------".to_string() }; let crate_name = tcx.crate_name(source.def_id().krate); diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 362ff8e988d..6708ae60562 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -295,20 +295,12 @@ impl<'tcx> Const<'tcx> { _ => expr, }; - if let hir::ExprKind::Path( - qpath @ hir::QPath::Resolved( - _, - &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, - ), - ) = expr.kind + if let hir::ExprKind::Path(hir::QPath::Resolved( + _, + &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, + )) = expr.kind { - if tcx.features().const_arg_path { - span_bug!( - expr.span, - "try_from_lit: received const param which shouldn't be possible" - ); - } - return Some(Const::from_param(tcx, qpath, expr.hir_id)); + span_bug!(expr.span, "try_from_lit: received const param which shouldn't be possible"); }; let lit_input = match expr.kind { @@ -396,7 +388,7 @@ impl<'tcx> Const<'tcx> { Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c)) } Ok(Err(bad_ty)) => Err(Either::Left(bad_ty)), - Err(err) => Err(Either::Right(err.into())), + Err(err) => Err(Either::Right(err)), } } ConstKind::Value(ty, val) => Ok((ty, val)), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1c8916b255e..5ec7e80ee45 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2606,33 +2606,31 @@ impl<'tcx> TyCtxt<'tcx> { /// With `cfg(debug_assertions)`, assert that args are compatible with their generics, /// and print out the args if not. pub fn debug_assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) { - if cfg!(debug_assertions) { - if !self.check_args_compatible(def_id, args) { - if let DefKind::AssocTy = self.def_kind(def_id) - && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) - { - bug!( - "args not compatible with generics for {}: args={:#?}, generics={:#?}", - self.def_path_str(def_id), - args, - // Make `[Self, GAT_ARGS...]` (this could be simplified) - self.mk_args_from_iter( - [self.types.self_param.into()].into_iter().chain( - self.generics_of(def_id) - .own_args(ty::GenericArgs::identity_for_item(self, def_id)) - .iter() - .copied() - ) + if cfg!(debug_assertions) && !self.check_args_compatible(def_id, args) { + if let DefKind::AssocTy = self.def_kind(def_id) + && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) + { + bug!( + "args not compatible with generics for {}: args={:#?}, generics={:#?}", + self.def_path_str(def_id), + args, + // Make `[Self, GAT_ARGS...]` (this could be simplified) + self.mk_args_from_iter( + [self.types.self_param.into()].into_iter().chain( + self.generics_of(def_id) + .own_args(ty::GenericArgs::identity_for_item(self, def_id)) + .iter() + .copied() ) - ); - } else { - bug!( - "args not compatible with generics for {}: args={:#?}, generics={:#?}", - self.def_path_str(def_id), - args, - ty::GenericArgs::identity_for_item(self, def_id) - ); - } + ) + ); + } else { + bug!( + "args not compatible with generics for {}: args={:#?}, generics={:#?}", + self.def_path_str(def_id), + args, + ty::GenericArgs::identity_for_item(self, def_id) + ); } } } @@ -3132,11 +3130,11 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn next_trait_solver_globally(self) -> bool { - self.sess.opts.unstable_opts.next_solver.globally + self.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.globally) } pub fn next_trait_solver_in_coherence(self) -> bool { - self.sess.opts.unstable_opts.next_solver.coherence + self.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.coherence) } pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 8cec8eac189..254a0119920 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1183,10 +1183,10 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) -> // // This is not part of `codegen_fn_attrs` as it can differ between crates // and therefore cannot be computed in core. - if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort { - if tcx.is_lang_item(did, LangItem::DropInPlace) { - return false; - } + if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort + && tcx.is_lang_item(did, LangItem::DropInPlace) + { + return false; } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f1ff90831b0..988516d100f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1526,7 +1526,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let precedence = |binop: rustc_middle::mir::BinOp| { use rustc_ast::util::parser::AssocOp; - AssocOp::from_ast_binop(binop.to_hir_binop().into()).precedence() + AssocOp::from_ast_binop(binop.to_hir_binop()).precedence() }; let op_precedence = precedence(op); let formatted_op = op.to_hir_binop().as_str(); @@ -3361,10 +3361,8 @@ pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap<Symbol> { // name. // // Any stable ordering would be fine here though. - if *v.get() != symbol { - if v.get().as_str() > symbol.as_str() { - v.insert(symbol); - } + if *v.get() != symbol && v.get().as_str() > symbol.as_str() { + v.insert(symbol); } } Vacant(v) => { diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs index bcab54cf8ba..37dcf7c0d64 100644 --- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs +++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs @@ -41,7 +41,15 @@ impl RvalueScopes { debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]"); return Some(id); } - _ => id = p, + ScopeData::IfThenRescope => { + debug!("temporary_scope({expr_id:?}) = {p:?} [enclosing]"); + return Some(p); + } + ScopeData::Node + | ScopeData::CallSite + | ScopeData::Arguments + | ScopeData::IfThen + | ScopeData::Remainder(_) => id = p, } } diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs index 3aa6e708476..6019a93e787 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -268,10 +268,9 @@ impl Builder<'_, '_> { pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) { if let Some(coverage_info) = self.coverage_info.as_mut() && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut() + && mcdc_info.state.decision_ctx_stack.pop().is_none() { - if mcdc_info.state.decision_ctx_stack.pop().is_none() { - bug!("Unexpected empty decision stack"); - } + bug!("Unexpected empty decision stack"); }; } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index af5940ff50e..b8b5e4634ed 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -1,7 +1,9 @@ //! See docs in build/expr/mod.rs use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_hir::HirId; use rustc_middle::middle::region; +use rustc_middle::middle::region::{Scope, ScopeData}; use rustc_middle::mir::*; use rustc_middle::thir::*; use tracing::{debug, instrument}; @@ -73,11 +75,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ if let Some(tail_info) = this.block_context.currently_in_block_tail() => { LocalInfo::BlockTailTemp(tail_info) } + + _ if let Some(Scope { data: ScopeData::IfThenRescope, id }) = temp_lifetime => { + LocalInfo::IfThenRescopeTemp { + if_then: HirId { owner: this.hir_id.owner, local_id: id }, + } + } + _ => LocalInfo::Boring, }; **local_decl.local_info.as_mut().assert_crate_local() = local_info; this.local_decls.push(local_decl) }; + debug!(?temp); if deduplicate_temps { this.fixed_temps.insert(expr_id, temp); } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 89f98a40201..aa8ccc8b7dd 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -706,7 +706,13 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::If(cond, then, else_opt) => ExprKind::If { if_then_scope: region::Scope { id: then.hir_id.local_id, - data: region::ScopeData::IfThen, + data: { + if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope { + region::ScopeData::IfThenRescope + } else { + region::ScopeData::IfThen + } + }, }, cond: self.mirror_expr(cond), then: self.mirror_expr(then), diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index ba4a7d76511..88a9a78f8ad 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -42,14 +42,14 @@ pub trait Direction { ) where A: GenKillAnalysis<'tcx>; - fn visit_results_in_block<'mir, 'tcx, F, R>( - state: &mut F, + fn visit_results_in_block<'mir, 'tcx, D, R>( + state: &mut D, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, ) where - R: ResultsVisitable<'tcx, FlowState = F>; + R: ResultsVisitable<'tcx, Domain = D>; fn join_state_into_successors_of<'tcx, A>( analysis: &mut A, @@ -186,14 +186,14 @@ impl Direction for Backward { analysis.apply_statement_effect(state, statement, location); } - fn visit_results_in_block<'mir, 'tcx, F, R>( - state: &mut F, + fn visit_results_in_block<'mir, 'tcx, D, R>( + state: &mut D, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, ) where - R: ResultsVisitable<'tcx, FlowState = F>, + R: ResultsVisitable<'tcx, Domain = D>, { results.reset_to_block_entry(state, block); @@ -444,9 +444,9 @@ impl Direction for Forward { block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = F>, ) where - R: ResultsVisitable<'tcx, FlowState = F>, + R: ResultsVisitable<'tcx, Domain = F>, { results.reset_to_block_entry(state, block); diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 0bab03b0271..54206501d9f 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -57,7 +57,7 @@ where &mut self, body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator<Item = BasicBlock>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>, ) { visit_results(body, blocks, self, vis) } @@ -65,7 +65,7 @@ where pub fn visit_reachable_with<'mir>( &mut self, body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>, ) { let blocks = mir::traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 2e860e2d841..e72dca2c834 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -544,15 +544,15 @@ where A: Analysis<'tcx>, A::Domain: DebugWithContext<A>, { - type FlowState = A::Domain; + type Domain = A::Domain; - fn visit_block_start(&mut self, state: &Self::FlowState) { + fn visit_block_start(&mut self, state: &Self::Domain) { if A::Direction::IS_FORWARD { self.prev_state.clone_from(state); } } - fn visit_block_end(&mut self, state: &Self::FlowState) { + fn visit_block_end(&mut self, state: &Self::Domain) { if A::Direction::IS_BACKWARD { self.prev_state.clone_from(state); } @@ -561,7 +561,7 @@ where fn visit_statement_before_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { @@ -574,7 +574,7 @@ where fn visit_statement_after_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { @@ -585,7 +585,7 @@ where fn visit_terminator_before_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { @@ -598,7 +598,7 @@ where fn visit_terminator_after_primary_effect( &mut self, results: &mut Results<'tcx, A>, - state: &Self::FlowState, + state: &Self::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 8b8a16bda99..3d6b008a684 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -4,15 +4,15 @@ use super::{Analysis, Direction, Results}; /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the /// dataflow state at that location. -pub fn visit_results<'mir, 'tcx, F, R>( +pub fn visit_results<'mir, 'tcx, D, R>( body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator<Item = BasicBlock>, results: &mut R, - vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>, ) where - R: ResultsVisitable<'tcx, FlowState = F>, + R: ResultsVisitable<'tcx, Domain = D>, { - let mut state = results.new_flow_state(body); + let mut state = results.bottom_value(body); #[cfg(debug_assertions)] let reachable_blocks = mir::traversal::reachable_as_bitset(body); @@ -29,16 +29,16 @@ pub fn visit_results<'mir, 'tcx, F, R>( /// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being /// visited. pub trait ResultsVisitor<'mir, 'tcx, R> { - type FlowState; + type Domain; - fn visit_block_start(&mut self, _state: &Self::FlowState) {} + fn visit_block_start(&mut self, _state: &Self::Domain) {} /// Called with the `before_statement_effect` of the given statement applied to `state` but not /// its `statement_effect`. fn visit_statement_before_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _statement: &'mir mir::Statement<'tcx>, _location: Location, ) { @@ -49,7 +49,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { fn visit_statement_after_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _statement: &'mir mir::Statement<'tcx>, _location: Location, ) { @@ -60,7 +60,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { fn visit_terminator_before_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _terminator: &'mir mir::Terminator<'tcx>, _location: Location, ) { @@ -73,13 +73,13 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { fn visit_terminator_after_primary_effect( &mut self, _results: &mut R, - _state: &Self::FlowState, + _state: &Self::Domain, _terminator: &'mir mir::Terminator<'tcx>, _location: Location, ) { } - fn visit_block_end(&mut self, _state: &Self::FlowState) {} + fn visit_block_end(&mut self, _state: &Self::Domain) {} } /// Things that can be visited by a `ResultsVisitor`. @@ -88,40 +88,40 @@ pub trait ResultsVisitor<'mir, 'tcx, R> { /// simultaneously. pub trait ResultsVisitable<'tcx> { type Direction: Direction; - type FlowState; + type Domain; - /// Creates an empty `FlowState` to hold the transient state for these dataflow results. + /// Creates an empty `Domain` to hold the transient state for these dataflow results. /// - /// The value of the newly created `FlowState` will be overwritten by `reset_to_block_entry` + /// The value of the newly created `Domain` will be overwritten by `reset_to_block_entry` /// before it can be observed by a `ResultsVisitor`. - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState; + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain; - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock); + fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock); fn reconstruct_before_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ); fn reconstruct_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ); fn reconstruct_before_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ); fn reconstruct_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ); @@ -131,21 +131,20 @@ impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A> where A: Analysis<'tcx>, { - type FlowState = A::Domain; - + type Domain = A::Domain; type Direction = A::Direction; - fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { + fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { self.analysis.bottom_value(body) } - fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { + fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) { state.clone_from(self.entry_set_for_block(block)); } fn reconstruct_before_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -154,7 +153,7 @@ where fn reconstruct_statement_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { @@ -163,7 +162,7 @@ where fn reconstruct_before_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { @@ -172,7 +171,7 @@ where fn reconstruct_terminator_effect( &mut self, - state: &mut Self::FlowState, + state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index e8e78fb8a89..8b082ef2667 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -11,7 +11,7 @@ use crate::{AnalysisDomain, GenKill, GenKillAnalysis}; /// At present, this is used as a very limited form of alias analysis. For example, /// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for /// immovable coroutines. -#[derive(Clone, Copy)] +#[derive(Clone)] pub struct MaybeBorrowedLocals; impl MaybeBorrowedLocals { diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 24a4b32ceb7..1559c131a37 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -217,7 +217,6 @@ impl DefUse { /// This is basically written for dead store elimination and nothing else. /// /// All of the caveats of `MaybeLiveLocals` apply. -#[derive(Clone, Copy)] pub struct MaybeTransitiveLiveLocals<'a> { always_live: &'a BitSet<Local>, } diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 9f2f0187698..6bf54c8db41 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -7,7 +7,6 @@ use rustc_middle::mir::*; use super::MaybeBorrowedLocals; use crate::{GenKill, ResultsCursor}; -#[derive(Clone)] pub struct MaybeStorageLive<'a> { always_live_locals: Cow<'a, BitSet<Local>>, } @@ -80,7 +79,6 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { } } -#[derive(Clone)] pub struct MaybeStorageDead<'a> { always_live_locals: Cow<'a, BitSet<Local>>, } diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index 4be7492366a..adfa94464a0 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -102,7 +102,7 @@ pub fn save_as_intervals<'tcx, N, R>( ) -> SparseIntervalMatrix<N, PointIndex> where N: Idx, - R: ResultsVisitable<'tcx, FlowState = BitSet<N>>, + R: ResultsVisitable<'tcx, Domain = BitSet<N>>, { let values = SparseIntervalMatrix::new(elements.num_points()); let mut visitor = Visitor { elements, values }; @@ -124,12 +124,12 @@ impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N> where N: Idx, { - type FlowState = BitSet<N>; + type Domain = BitSet<N>; fn visit_statement_after_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, + state: &Self::Domain, _statement: &'mir mir::Statement<'tcx>, location: Location, ) { @@ -143,7 +143,7 @@ where fn visit_terminator_after_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, + state: &Self::Domain, _terminator: &'mir mir::Terminator<'tcx>, location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 8c3e6f49b16..ac9b853f21b 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -229,7 +229,7 @@ trait RustcPeekAt<'tcx>: Analysis<'tcx> { &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &Self::Domain, + state: &Self::Domain, call: PeekCall, ); } @@ -243,12 +243,12 @@ where &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &Self::Domain, + state: &Self::Domain, call: PeekCall, ) { match self.move_data().rev_lookup.find(place.as_ref()) { LookupResult::Exact(peek_mpi) => { - let bit_state = flow_state.contains(peek_mpi); + let bit_state = state.contains(peek_mpi); debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state); if !bit_state { tcx.dcx().emit_err(PeekBitNotSet { span: call.span }); @@ -267,7 +267,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &BitSet<Local>, + state: &BitSet<Local>, call: PeekCall, ) { info!(?place, "peek_at"); @@ -276,7 +276,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { return; }; - if !flow_state.contains(local) { + if !state.contains(local) { tcx.dcx().emit_err(PeekBitNotSet { span: call.span }); } } diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 048dd9ccb8f..9c3cbbe1fc9 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -95,19 +95,19 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { // Check for assignment to fields of a constant // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error, // so emitting a lint would be redundant. - if !lhs.projection.is_empty() { - if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) - && let Some((lint_root, span, item)) = - self.should_lint_const_item_usage(lhs, def_id, loc) - { - self.tcx.emit_node_span_lint( - CONST_ITEM_MUTATION, - lint_root, - span, - errors::ConstMutate::Modify { konst: item }, - ); - } + if !lhs.projection.is_empty() + && let Some(def_id) = self.is_const_item_without_destructor(lhs.local) + && let Some((lint_root, span, item)) = + self.should_lint_const_item_usage(lhs, def_id, loc) + { + self.tcx.emit_node_span_lint( + CONST_ITEM_MUTATION, + lint_root, + span, + errors::ConstMutate::Modify { konst: item }, + ); } + // We are looking for MIR of the form: // // ``` diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 90243cd2910..1fb74f5d82c 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -885,12 +885,12 @@ struct StorageConflictVisitor<'a, 'tcx> { impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> for StorageConflictVisitor<'a, 'tcx> { - type FlowState = BitSet<Local>; + type Domain = BitSet<Local>; fn visit_statement_before_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, + state: &Self::Domain, _statement: &'a Statement<'tcx>, loc: Location, ) { @@ -900,7 +900,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> fn visit_terminator_before_primary_effect( &mut self, _results: &mut R, - state: &Self::FlowState, + state: &Self::Domain, _terminator: &'a Terminator<'tcx>, loc: Location, ) { @@ -909,13 +909,13 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R> } impl StorageConflictVisitor<'_, '_> { - fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) { + fn apply_state(&mut self, state: &BitSet<Local>, loc: Location) { // Ignore unreachable blocks. if let TerminatorKind::Unreachable = self.body.basic_blocks[loc.block].terminator().kind { return; } - self.eligible_storage_live.clone_from(flow_state); + self.eligible_storage_live.clone_from(state); self.eligible_storage_live.intersect(&**self.saved_locals); for local in self.eligible_storage_live.iter() { diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 1c240366afa..7e3ecad1bce 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -155,12 +155,14 @@ impl CoverageCounters { BcbCounter::Expression { id } } - /// Variant of `make_expression` that makes `lhs` optional and assumes [`Op::Add`]. + /// Creates a counter that is the sum of the given counters. /// - /// This is useful when using [`Iterator::fold`] to build an arbitrary-length sum. - fn make_sum_expression(&mut self, lhs: Option<BcbCounter>, rhs: BcbCounter) -> BcbCounter { - let Some(lhs) = lhs else { return rhs }; - self.make_expression(lhs, Op::Add, rhs) + /// Returns `None` if the given list of counters was empty. + fn make_sum(&mut self, counters: &[BcbCounter]) -> Option<BcbCounter> { + counters + .iter() + .copied() + .reduce(|accum, counter| self.make_expression(accum, Op::Add, counter)) } pub(super) fn num_counters(&self) -> usize { @@ -315,20 +317,17 @@ impl<'a> MakeBcbCounters<'a> { // For each out-edge other than the one that was chosen to get an expression, // ensure that it has a counter (existing counter/expression or a new counter), // and accumulate the corresponding counters into a single sum expression. - let sum_of_all_other_out_edges: BcbCounter = { - let _span = debug_span!("sum_of_all_other_out_edges", ?expression_to_bcb).entered(); - successors - .iter() - .copied() - // Skip the chosen edge, since we'll calculate its count from this sum. - .filter(|&to_bcb| to_bcb != expression_to_bcb) - .fold(None, |accum, to_bcb| { - let _span = debug_span!("to_bcb", ?accum, ?to_bcb).entered(); - let edge_counter = self.get_or_make_edge_counter(from_bcb, to_bcb); - Some(self.coverage_counters.make_sum_expression(accum, edge_counter)) - }) - .expect("there must be at least one other out-edge") - }; + let other_out_edge_counters = successors + .iter() + .copied() + // Skip the chosen edge, since we'll calculate its count from this sum. + .filter(|&to_bcb| to_bcb != expression_to_bcb) + .map(|to_bcb| self.get_or_make_edge_counter(from_bcb, to_bcb)) + .collect::<Vec<_>>(); + let sum_of_all_other_out_edges: BcbCounter = self + .coverage_counters + .make_sum(&other_out_edge_counters) + .expect("there must be at least one other out-edge"); // Now create an expression for the chosen edge, by taking the counter // for its source node and subtracting the sum of its sibling out-edges. @@ -375,20 +374,15 @@ impl<'a> MakeBcbCounters<'a> { // A BCB with multiple incoming edges can compute its count by ensuring that counters // exist for each of those edges, and then adding them up to get a total count. - let sum_of_in_edges: BcbCounter = { - let _span = debug_span!("sum_of_in_edges", ?bcb).entered(); - // We avoid calling `self.bcb_predecessors` here so that we can - // call methods on `&mut self` inside the fold. - self.basic_coverage_blocks.predecessors[bcb] - .iter() - .copied() - .fold(None, |accum, from_bcb| { - let _span = debug_span!("from_bcb", ?accum, ?from_bcb).entered(); - let edge_counter = self.get_or_make_edge_counter(from_bcb, bcb); - Some(self.coverage_counters.make_sum_expression(accum, edge_counter)) - }) - .expect("there must be at least one in-edge") - }; + let in_edge_counters = self.basic_coverage_blocks.predecessors[bcb] + .iter() + .copied() + .map(|from_bcb| self.get_or_make_edge_counter(from_bcb, bcb)) + .collect::<Vec<_>>(); + let sum_of_in_edges: BcbCounter = self + .coverage_counters + .make_sum(&in_edge_counters) + .expect("there must be at least one in-edge"); debug!("{bcb:?} gets a new counter (sum of predecessor counters): {sum_of_in_edges:?}"); self.coverage_counters.set_bcb_counter(bcb, sum_of_in_edges) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 7ac019ce812..ad9f9162606 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -724,13 +724,13 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>> for Collector<'tcx, '_> { - type FlowState = State<FlatSet<Scalar>>; + type Domain = State<FlatSet<Scalar>>; #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_before_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, - state: &Self::FlowState, + state: &Self::Domain, statement: &'mir Statement<'tcx>, location: Location, ) { @@ -752,7 +752,7 @@ impl<'mir, 'tcx> fn visit_statement_after_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, - state: &Self::FlowState, + state: &Self::Domain, statement: &'mir Statement<'tcx>, location: Location, ) { @@ -777,7 +777,7 @@ impl<'mir, 'tcx> fn visit_terminator_before_primary_effect( &mut self, results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>, - state: &Self::FlowState, + state: &Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, ) { diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index c645bbee08a..c0cb0e641ac 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -168,17 +168,16 @@ pub(super) fn deduced_param_attrs<'tcx>( // Codegen won't use this information for anything if all the function parameters are passed // directly. Detect that and bail, for compilation speed. let fn_ty = tcx.type_of(def_id).instantiate_identity(); - if matches!(fn_ty.kind(), ty::FnDef(..)) { - if fn_ty + if matches!(fn_ty.kind(), ty::FnDef(..)) + && fn_ty .fn_sig(tcx) .inputs() .skip_binder() .iter() .cloned() .all(type_will_always_be_passed_directly) - { - return &[]; - } + { + return &[]; } // Don't deduce any attributes for functions that have no MIR. diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 46b17c3c7e0..f123f39bf42 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -378,19 +378,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if let (Some(l), Some(r)) = (l, r) && l.layout.ty.is_integral() && op.is_overflowing() - { - if self.use_ecx(|this| { + && self.use_ecx(|this| { let (_res, overflow) = this.ecx.binary_op(op, &l, &r)?.to_scalar_pair(); overflow.to_bool() - })? { - self.report_assert_as_lint( - location, - AssertLintKind::ArithmeticOverflow, - AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()), - ); - return None; - } + })? + { + self.report_assert_as_lint( + location, + AssertLintKind::ArithmeticOverflow, + AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()), + ); + return None; } + Some(()) } diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 60ece5e7db9..29f8b4f6e4d 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -42,7 +42,7 @@ fn to_profiler_name(type_name: &'static str) -> &'static str { // const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }` const fn c_name(name: &'static str) -> &'static str { - // FIXME Simplify the implementation once more `str` methods get const-stable. + // FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable. // and inline into call site let bytes = name.as_bytes(); let mut i = bytes.len(); @@ -61,7 +61,7 @@ const fn c_name(name: &'static str) -> &'static str { /// loop that goes over each available MIR and applies `run_pass`. pub(super) trait MirPass<'tcx> { fn name(&self) -> &'static str { - // FIXME Simplify the implementation once more `str` methods get const-stable. + // FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable. // See copypaste in `MirLint` const { let name = std::any::type_name::<Self>(); @@ -89,7 +89,7 @@ pub(super) trait MirPass<'tcx> { /// disabled (via the `Lint` adapter). pub(super) trait MirLint<'tcx> { fn name(&self) -> &'static str { - // FIXME Simplify the implementation once more `str` methods get const-stable. + // FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable. // See copypaste in `MirPass` const { let name = std::any::type_name::<Self>(); diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 0d295b8f280..2d9dbdbaec2 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -504,10 +504,8 @@ fn compute_inlined_overlap<'tcx>(cgu1: &CodegenUnit<'tcx>, cgu2: &CodegenUnit<'t let mut overlap = 0; for (item, data) in src_cgu.items().iter() { - if data.inlined { - if dst_cgu.items().contains_key(item) { - overlap += data.size_estimate; - } + if data.inlined && dst_cgu.items().contains_key(item) { + overlap += data.size_estimate; } } overlap diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 394518daa42..196ddeb2443 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -185,10 +185,8 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { for var in var_infos.iter_mut() { // We simply put all regions from the input into the highest // compressed universe, so we only deal with them at the end. - if !var.is_region() { - if is_existential == var.is_existential() { - update_uv(var, orig_uv, is_existential) - } + if !var.is_region() && is_existential == var.is_existential() { + update_uv(var, orig_uv, is_existential) } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 1c00f5f8b41..5acfec3dee3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -122,6 +122,21 @@ where (certainty, NestedNormalizationGoals::empty()) }; + if let Certainty::Maybe(cause @ MaybeCause::Overflow { .. }) = certainty { + // If we have overflow, it's probable that we're substituting a type + // into itself infinitely and any partial substitutions in the query + // response are probably not useful anyways, so just return an empty + // query response. + // + // This may prevent us from potentially useful inference, e.g. + // 2 candidates, one ambiguous and one overflow, which both + // have the same inference constraints. + // + // Changing this to retain some constraints in the future + // won't be a breaking change, so this is good enough for now. + return Ok(self.make_ambiguous_response_no_constraints(cause)); + } + let external_constraints = self.compute_external_query_constraints(certainty, normalization_nested_goals); let (var_values, mut external_constraints) = (self.var_values, external_constraints) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 3f2f34d3255..15b123ebdf9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -17,7 +17,7 @@ use crate::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ - CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, GoalSource, MaybeCause, + CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, GoalSource, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, SolverMode, FIXPOINT_STEP_LIMIT, }; @@ -370,7 +370,7 @@ where canonical_goal, &mut goal_evaluation, ); - let canonical_response = match canonical_response { + let response = match canonical_response { Err(e) => { self.inspect.goal_evaluation(goal_evaluation); return Err(e); @@ -378,12 +378,11 @@ where Ok(response) => response, }; - let (normalization_nested_goals, certainty, has_changed) = self - .instantiate_response_discarding_overflow( - goal.param_env, - orig_values, - canonical_response, - ); + let has_changed = !response.value.var_values.is_identity_modulo_regions() + || !response.value.external_constraints.opaque_types.is_empty(); + + let (normalization_nested_goals, certainty) = + self.instantiate_and_apply_query_response(goal.param_env, orig_values, response); self.inspect.goal_evaluation(goal_evaluation); // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. @@ -398,24 +397,6 @@ where Ok((normalization_nested_goals, has_changed, certainty)) } - fn instantiate_response_discarding_overflow( - &mut self, - param_env: I::ParamEnv, - original_values: Vec<I::GenericArg>, - response: CanonicalResponse<I>, - ) -> (NestedNormalizationGoals<I>, Certainty, bool) { - if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty { - return (NestedNormalizationGoals::empty(), response.value.certainty, false); - } - - let has_changed = !response.value.var_values.is_identity_modulo_regions() - || !response.value.external_constraints.opaque_types.is_empty(); - - let (normalization_nested_goals, certainty) = - self.instantiate_and_apply_query_response(param_env, original_values, response); - (normalization_nested_goals, certainty, has_changed) - } - fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> { let Goal { param_env, predicate } = goal; let kind = predicate.kind(); diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 683d8dab3b2..73d9b5e8a4e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -883,7 +883,6 @@ where .into_iter() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { elaborate::supertrait_def_ids(self.cx(), principal_def_id) - .into_iter() .filter(|def_id| self.cx().trait_is_auto(*def_id)) })) .collect(); diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 205cca830b2..6a241be0a15 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -383,7 +383,7 @@ impl<'a> Parser<'a> { self.capture_state .parser_replacements .drain(parser_replacements_start..parser_replacements_end) - .chain(inner_attr_parser_replacements.into_iter()) + .chain(inner_attr_parser_replacements) .map(|(parser_range, data)| { (NodeRange::new(parser_range, collect_pos.start_pos), data) }) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index ecc4cd96faf..2d6edad2977 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2554,13 +2554,12 @@ impl<'a> Parser<'a> { let maybe_fatarrow = self.token.clone(); let block = if self.check(&token::OpenDelim(Delimiter::Brace)) { self.parse_block()? + } else if let Some(block) = recover_block_from_condition(self) { + block } else { - if let Some(block) = recover_block_from_condition(self) { - block - } else { - self.error_on_extra_if(&cond)?; - // Parse block, which will always fail, but we can add a nice note to the error - self.parse_block().map_err(|mut err| { + self.error_on_extra_if(&cond)?; + // Parse block, which will always fail, but we can add a nice note to the error + self.parse_block().map_err(|mut err| { if self.prev_token == token::Semi && self.token == token::AndAnd && let maybe_let = self.look_ahead(1, |t| t.clone()) @@ -2592,7 +2591,6 @@ impl<'a> Parser<'a> { } err })? - } }; self.error_on_if_block_attrs(lo, false, block.span, attrs); block diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 83d10dea6a8..104678e081c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1588,7 +1588,7 @@ impl<'a> Parser<'a> { (thin_vec![], Recovered::Yes(guar)) } }; - VariantData::Struct { fields, recovered: recovered.into() } + VariantData::Struct { fields, recovered } } else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) { let body = match this.parse_tuple_struct_body() { Ok(body) => body, @@ -1672,7 +1672,7 @@ impl<'a> Parser<'a> { class_name.span, generics.where_clause.has_where_token, )?; - VariantData::Struct { fields, recovered: recovered.into() } + VariantData::Struct { fields, recovered } } // No `where` so: `struct Foo<T>;` } else if self.eat(&token::Semi) { @@ -1684,7 +1684,7 @@ impl<'a> Parser<'a> { class_name.span, generics.where_clause.has_where_token, )?; - VariantData::Struct { fields, recovered: recovered.into() } + VariantData::Struct { fields, recovered } // Tuple-style struct definition with optional where-clause. } else if self.token == token::OpenDelim(Delimiter::Parenthesis) { let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID); @@ -1713,14 +1713,14 @@ impl<'a> Parser<'a> { class_name.span, generics.where_clause.has_where_token, )?; - VariantData::Struct { fields, recovered: recovered.into() } + VariantData::Struct { fields, recovered } } else if self.token == token::OpenDelim(Delimiter::Brace) { let (fields, recovered) = self.parse_record_struct_body( "union", class_name.span, generics.where_clause.has_where_token, )?; - VariantData::Struct { fields, recovered: recovered.into() } + VariantData::Struct { fields, recovered } } else { let token_str = super::token_descr(&self.token); let msg = format!("expected `where` or `{{` after union name, found {token_str}"); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3ee6e742d1b..9d9265d5318 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1359,13 +1359,11 @@ impl<'a> Parser<'a> { fn parse_attr_args(&mut self) -> PResult<'a, AttrArgs> { Ok(if let Some(args) = self.parse_delim_args_inner() { AttrArgs::Delimited(args) + } else if self.eat(&token::Eq) { + let eq_span = self.prev_token.span; + AttrArgs::Eq(eq_span, AttrArgsEq::Ast(self.parse_expr_force_collect()?)) } else { - if self.eat(&token::Eq) { - let eq_span = self.prev_token.span; - AttrArgs::Eq(eq_span, AttrArgsEq::Ast(self.parse_expr_force_collect()?)) - } else { - AttrArgs::Empty - } + AttrArgs::Empty }) } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index cbd35ffdfa9..daced411b8f 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1336,21 +1336,19 @@ impl<'a> Parser<'a> { vec![(first_etc_span, String::new())], Applicability::MachineApplicable, ); - } else { - if let Some(last_non_comma_dotdot_span) = last_non_comma_dotdot_span { - // We have `.., x`. - err.multipart_suggestion( - "move the `..` to the end of the field list", - vec![ - (first_etc_span, String::new()), - ( - self.token.span.to(last_non_comma_dotdot_span.shrink_to_hi()), - format!("{} .. }}", if ate_comma { "" } else { "," }), - ), - ], - Applicability::MachineApplicable, - ); - } + } else if let Some(last_non_comma_dotdot_span) = last_non_comma_dotdot_span { + // We have `.., x`. + err.multipart_suggestion( + "move the `..` to the end of the field list", + vec![ + (first_etc_span, String::new()), + ( + self.token.span.to(last_non_comma_dotdot_span.shrink_to_hi()), + format!("{} .. }}", if ate_comma { "" } else { "," }), + ), + ], + Applicability::MachineApplicable, + ); } } err.emit(); diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 8ee40ecd77e..42039c621d6 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -671,12 +671,12 @@ impl<'a> Parser<'a> { err.emit(); continue; } - if !self.token.kind.should_end_const_arg() { - if self.handle_ambiguous_unbraced_const_arg(&mut args)? { - // We've managed to (partially) recover, so continue trying to parse - // arguments. - continue; - } + if !self.token.kind.should_end_const_arg() + && self.handle_ambiguous_unbraced_const_arg(&mut args)? + { + // We've managed to (partially) recover, so continue trying to parse + // arguments. + continue; } break; } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index fce41bd90be..f2121c3243a 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -192,13 +192,11 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: ); } } - } else { - if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { - psess.dcx().emit_err(errors::InvalidAttrUnsafe { - span: unsafe_span, - name: attr_item.path.clone(), - }); - } + } else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { + psess.dcx().emit_err(errors::InvalidAttrUnsafe { + span: unsafe_span, + name: attr_item.path.clone(), + }); } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4fb9b93b80c..ee892c17376 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2169,17 +2169,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr.span, errors::MacroExport::TooManyItems, ); - } else { - if meta_item_list[0].name_or_empty() != sym::local_inner_macros { - self.tcx.emit_node_span_lint( - INVALID_MACRO_EXPORT_ARGUMENTS, - hir_id, - meta_item_list[0].span(), - errors::MacroExport::UnknownItem { - name: meta_item_list[0].name_or_empty(), - }, - ); - } + } else if meta_item_list[0].name_or_empty() != sym::local_inner_macros { + self.tcx.emit_node_span_lint( + INVALID_MACRO_EXPORT_ARGUMENTS, + hir_id, + meta_item_list[0].span(), + errors::MacroExport::UnknownItem { name: meta_item_list[0].name_or_empty() }, + ); } } else { // special case when `#[macro_export]` is applied to a macro 2.0 diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index db3eaea68b5..959b7ad147b 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1500,15 +1500,13 @@ impl<'tcx> Liveness<'_, 'tcx> { ); } } - } else { - if let Some(name) = self.should_warn(var) { - self.ir.tcx.emit_node_span_lint( - lint::builtin::UNUSED_VARIABLES, - var_hir_id, - vec![span], - errors::UnusedVarMaybeCaptureRef { name }, - ); - } + } else if let Some(name) = self.should_warn(var) { + self.ir.tcx.emit_node_span_lint( + lint::builtin::UNUSED_VARIABLES, + var_hir_id, + vec![span], + errors::UnusedVarMaybeCaptureRef { name }, + ); } } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index ba4c300ea61..e2c9067c0b9 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -174,16 +174,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI, // check if the function/method is const or the parent impl block is const - if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig) { - if fn_sig.header.abi != Abi::RustIntrinsic && !fn_sig.header.is_const() { - if !self.in_trait_impl - || (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id())) - { - self.tcx - .dcx() - .emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span, const_span }); - } - } + if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig) + && fn_sig.header.abi != Abi::RustIntrinsic + && !fn_sig.header.is_const() + && (!self.in_trait_impl || !self.tcx.is_const_fn_raw(def_id.to_def_id())) + { + self.tcx + .dcx() + .emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span, const_span }); } // `impl const Trait for Type` items forward their const stability to their diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3ea782b62f1..f87f3cdde4c 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -39,10 +39,10 @@ use crate::{ type Res = def::Res<NodeId>; -impl<'a, Id: Into<DefId>> ToNameBinding<'a> - for (Module<'a>, ty::Visibility<Id>, Span, LocalExpnId) +impl<'ra, Id: Into<DefId>> ToNameBinding<'ra> + for (Module<'ra>, ty::Visibility<Id>, Span, LocalExpnId) { - fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> NameBinding<'a> { + fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Module(self.0), ambiguity: None, @@ -54,8 +54,8 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a> } } -impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span, LocalExpnId) { - fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> NameBinding<'a> { +impl<'ra, Id: Into<DefId>> ToNameBinding<'ra> for (Res, ty::Visibility<Id>, Span, LocalExpnId) { + fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Res(self.0), ambiguity: None, @@ -67,12 +67,12 @@ impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span, } } -impl<'a, 'tcx> Resolver<'a, 'tcx> { +impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; /// otherwise, reports an error. - pub(crate) fn define<T>(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def: T) + pub(crate) fn define<T>(&mut self, parent: Module<'ra>, ident: Ident, ns: Namespace, def: T) where - T: ToNameBinding<'a>, + T: ToNameBinding<'ra>, { let binding = def.to_name_binding(self.arenas); let key = self.new_disambiguated_key(ident, ns); @@ -97,7 +97,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`, /// but they cannot use def-site hygiene, so the assumption holds /// (<https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508>). - pub(crate) fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> { + pub(crate) fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'ra> { loop { match self.get_module(def_id) { Some(module) => return module, @@ -106,14 +106,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - pub(crate) fn expect_module(&mut self, def_id: DefId) -> Module<'a> { + pub(crate) fn expect_module(&mut self, def_id: DefId) -> Module<'ra> { self.get_module(def_id).expect("argument `DefId` is not a module") } /// If `def_id` refers to a module (in resolver's sense, i.e. a module item, crate root, enum, /// or trait), then this function returns that module's resolver representation, otherwise it /// returns `None`. - pub(crate) fn get_module(&mut self, def_id: DefId) -> Option<Module<'a>> { + pub(crate) fn get_module(&mut self, def_id: DefId) -> Option<Module<'ra>> { if let module @ Some(..) = self.module_map.get(&def_id) { return module.copied(); } @@ -143,7 +143,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None } - pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { + pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'ra> { match expn_id.expn_data().macro_def_id { Some(def_id) => self.macro_def_scope(def_id), None => expn_id @@ -153,7 +153,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - pub(crate) fn macro_def_scope(&mut self, def_id: DefId) -> Module<'a> { + pub(crate) fn macro_def_scope(&mut self, def_id: DefId) -> Module<'ra> { if let Some(id) = def_id.as_local() { self.local_macro_def_scopes[&id] } else { @@ -186,15 +186,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn build_reduced_graph( &mut self, fragment: &AstFragment, - parent_scope: ParentScope<'a>, - ) -> MacroRulesScopeRef<'a> { + parent_scope: ParentScope<'ra>, + ) -> MacroRulesScopeRef<'ra> { collect_definitions(self, fragment, parent_scope.expansion); let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope }; fragment.visit_with(&mut visitor); visitor.parent_scope.macro_rules } - pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'a>) { + pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'ra>) { for child in self.tcx.module_children(module.def_id()) { let parent_scope = ParentScope::module(module, self); self.build_reduced_graph_for_external_crate_res(child, parent_scope) @@ -205,7 +205,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn build_reduced_graph_for_external_crate_res( &mut self, child: &ModChild, - parent_scope: ParentScope<'a>, + parent_scope: ParentScope<'ra>, ) { let parent = parent_scope.module; let ModChild { ident, res, vis, ref reexport_chain } = *child; @@ -273,18 +273,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } -struct BuildReducedGraphVisitor<'a, 'b, 'tcx> { - r: &'b mut Resolver<'a, 'tcx>, - parent_scope: ParentScope<'a>, +struct BuildReducedGraphVisitor<'a, 'ra, 'tcx> { + r: &'a mut Resolver<'ra, 'tcx>, + parent_scope: ParentScope<'ra>, } -impl<'a, 'tcx> AsMut<Resolver<'a, 'tcx>> for BuildReducedGraphVisitor<'a, '_, 'tcx> { - fn as_mut(&mut self) -> &mut Resolver<'a, 'tcx> { +impl<'ra, 'tcx> AsMut<Resolver<'ra, 'tcx>> for BuildReducedGraphVisitor<'_, 'ra, 'tcx> { + fn as_mut(&mut self) -> &mut Resolver<'ra, 'tcx> { self.r } } -impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { +impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { fn res(&self, def_id: impl Into<DefId>) -> Res { let def_id = def_id.into(); Res::Def(self.r.tcx.def_kind(def_id), def_id) @@ -424,7 +424,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { fn add_import( &mut self, module_path: Vec<Segment>, - kind: ImportKind<'a>, + kind: ImportKind<'ra>, span: Span, item: &ast::Item, root_span: Span, @@ -752,7 +752,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } /// Constructs the reduced graph for one item. - fn build_reduced_graph_for_item(&mut self, item: &'b Item) { + fn build_reduced_graph_for_item(&mut self, item: &'a Item) { let parent_scope = &self.parent_scope; let parent = parent_scope.module; let expansion = parent_scope.expansion; @@ -918,7 +918,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { item: &Item, local_def_id: LocalDefId, vis: ty::Visibility, - parent: Module<'a>, + parent: Module<'ra>, ) { let ident = item.ident; let sp = item.span; @@ -1040,7 +1040,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { fn add_macro_use_binding( &mut self, name: Symbol, - binding: NameBinding<'a>, + binding: NameBinding<'ra>, span: Span, allow_shadowing: bool, ) { @@ -1050,7 +1050,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } /// Returns `true` if we should consider the underlying `extern crate` to be used. - fn process_macro_use_imports(&mut self, item: &Item, module: Module<'a>) -> bool { + fn process_macro_use_imports(&mut self, item: &Item, module: Module<'ra>) -> bool { let mut import_all = None; let mut single_imports = Vec::new(); for attr in &item.attrs { @@ -1188,7 +1188,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { /// Visit invocation in context in which it can emit a named item (possibly `macro_rules`) /// directly into its parent scope's module. - fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> { + fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'ra> { let invoc_id = self.visit_invoc(id); self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id); self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)) @@ -1221,7 +1221,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> { + fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'ra> { let parent_scope = self.parent_scope; let expansion = parent_scope.expansion; let feed = self.r.feed(item.id); @@ -1308,7 +1308,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { macro_rules! method { ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => { - fn $visit(&mut self, node: &'b $ty) { + fn $visit(&mut self, node: &'a $ty) { if let $invoc(..) = node.kind { self.visit_invoc(node.id); } else { @@ -1318,12 +1318,12 @@ macro_rules! method { }; } -impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { +impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { method!(visit_expr: ast::Expr, ast::ExprKind::MacCall, walk_expr); method!(visit_pat: ast::Pat, ast::PatKind::MacCall, walk_pat); method!(visit_ty: ast::Ty, ast::TyKind::MacCall, walk_ty); - fn visit_item(&mut self, item: &'b Item) { + fn visit_item(&mut self, item: &'a Item) { let orig_module_scope = self.parent_scope.module; self.parent_scope.macro_rules = match item.kind { ItemKind::MacroDef(..) => { @@ -1357,7 +1357,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.parent_scope.module = orig_module_scope; } - fn visit_stmt(&mut self, stmt: &'b ast::Stmt) { + fn visit_stmt(&mut self, stmt: &'a ast::Stmt) { if let ast::StmtKind::MacCall(..) = stmt.kind { self.parent_scope.macro_rules = self.visit_invoc_in_module(stmt.id); } else { @@ -1365,7 +1365,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn visit_foreign_item(&mut self, foreign_item: &'b ForeignItem) { + fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { if let ForeignItemKind::MacCall(_) = foreign_item.kind { self.visit_invoc_in_module(foreign_item.id); return; @@ -1375,7 +1375,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { visit::walk_item(self, foreign_item); } - fn visit_block(&mut self, block: &'b Block) { + fn visit_block(&mut self, block: &'a Block) { let orig_current_module = self.parent_scope.module; let orig_current_macro_rules_scope = self.parent_scope.macro_rules; self.build_reduced_graph_for_block(block); @@ -1384,7 +1384,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.parent_scope.macro_rules = orig_current_macro_rules_scope; } - fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) { + fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { if let AssocItemKind::MacCall(_) = item.kind { match ctxt { AssocCtxt::Trait => { @@ -1440,7 +1440,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { visit::walk_assoc_item(self, item, ctxt); } - fn visit_attribute(&mut self, attr: &'b ast::Attribute) { + fn visit_attribute(&mut self, attr: &'a ast::Attribute) { if !attr.is_doc_comment() && attr::is_builtin_attr(attr) { self.r .builtin_attrs @@ -1449,7 +1449,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { visit::walk_attribute(self, attr); } - fn visit_arm(&mut self, arm: &'b ast::Arm) { + fn visit_arm(&mut self, arm: &'a ast::Arm) { if arm.is_placeholder { self.visit_invoc(arm.id); } else { @@ -1457,7 +1457,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn visit_expr_field(&mut self, f: &'b ast::ExprField) { + fn visit_expr_field(&mut self, f: &'a ast::ExprField) { if f.is_placeholder { self.visit_invoc(f.id); } else { @@ -1465,7 +1465,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn visit_pat_field(&mut self, fp: &'b ast::PatField) { + fn visit_pat_field(&mut self, fp: &'a ast::PatField) { if fp.is_placeholder { self.visit_invoc(fp.id); } else { @@ -1473,7 +1473,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn visit_generic_param(&mut self, param: &'b ast::GenericParam) { + fn visit_generic_param(&mut self, param: &'a ast::GenericParam) { if param.is_placeholder { self.visit_invoc(param.id); } else { @@ -1481,7 +1481,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn visit_param(&mut self, p: &'b ast::Param) { + fn visit_param(&mut self, p: &'a ast::Param) { if p.is_placeholder { self.visit_invoc(p.id); } else { @@ -1489,7 +1489,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn visit_field_def(&mut self, sf: &'b ast::FieldDef) { + fn visit_field_def(&mut self, sf: &'a ast::FieldDef) { if sf.is_placeholder { self.visit_invoc(sf.id); } else { @@ -1501,7 +1501,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { // Constructs the reduced graph for one variant. Variants exist in the // type and value namespaces. - fn visit_variant(&mut self, variant: &'b ast::Variant) { + fn visit_variant(&mut self, variant: &'a ast::Variant) { if variant.is_placeholder { self.visit_invoc_in_module(variant.id); return; @@ -1542,7 +1542,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { visit::walk_variant(self, variant); } - fn visit_crate(&mut self, krate: &'b ast::Crate) { + fn visit_crate(&mut self, krate: &'a ast::Crate) { if krate.is_placeholder { self.visit_invoc_in_module(krate.id); } else { diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 1cee876b80f..8c434007f2c 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -52,8 +52,8 @@ impl UnusedImport { } } -struct UnusedImportCheckVisitor<'a, 'b, 'tcx> { - r: &'a mut Resolver<'b, 'tcx>, +struct UnusedImportCheckVisitor<'a, 'ra, 'tcx> { + r: &'a mut Resolver<'ra, 'tcx>, /// All the (so far) unused imports, grouped path list unused_imports: FxIndexMap<ast::NodeId, UnusedImport>, extern_crate_items: Vec<ExternCrateToLint>, @@ -78,7 +78,7 @@ struct ExternCrateToLint { renames: bool, } -impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { +impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { // We have information about whether `use` (import) items are actually // used now. If an import is not used at all, we signal a lint error. fn check_import(&mut self, id: ast::NodeId) { @@ -212,7 +212,7 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { } } -impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { +impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> { fn visit_item(&mut self, item: &'a ast::Item) { match item.kind { // Ignore is_public import statements because there's no way to be sure diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 0fedb998463..6458c888431 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -12,28 +12,43 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use tracing::debug; -use crate::{ImplTraitContext, Resolver}; +use crate::{ImplTraitContext, InvocationParent, PendingAnonConstInfo, Resolver}; pub(crate) fn collect_definitions( resolver: &mut Resolver<'_, '_>, fragment: &AstFragment, expansion: LocalExpnId, ) { - let (parent_def, impl_trait_context, in_attr) = resolver.invocation_parents[&expansion]; - let mut visitor = DefCollector { resolver, parent_def, expansion, impl_trait_context, in_attr }; + let InvocationParent { parent_def, pending_anon_const_info, impl_trait_context, in_attr } = + resolver.invocation_parents[&expansion]; + let mut visitor = DefCollector { + resolver, + parent_def, + pending_anon_const_info, + expansion, + impl_trait_context, + in_attr, + }; fragment.visit_with(&mut visitor); } /// Creates `DefId`s for nodes in the AST. -struct DefCollector<'a, 'b, 'tcx> { - resolver: &'a mut Resolver<'b, 'tcx>, +struct DefCollector<'a, 'ra, 'tcx> { + resolver: &'a mut Resolver<'ra, 'tcx>, parent_def: LocalDefId, + /// If we have an anon const that consists of a macro invocation, e.g. `Foo<{ m!() }>`, + /// we need to wait until we know what the macro expands to before we create the def for + /// the anon const. That's because we lower some anon consts into `hir::ConstArgKind::Path`, + /// which don't have defs. + /// + /// See `Self::visit_anon_const()`. + pending_anon_const_info: Option<PendingAnonConstInfo>, impl_trait_context: ImplTraitContext, in_attr: bool, expansion: LocalExpnId, } -impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { +impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { fn create_def( &mut self, node_id: NodeId, @@ -111,15 +126,21 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { fn visit_macro_invoc(&mut self, id: NodeId) { let id = id.placeholder_to_expn_id(); - let old_parent = self - .resolver - .invocation_parents - .insert(id, (self.parent_def, self.impl_trait_context, self.in_attr)); + let pending_anon_const_info = self.pending_anon_const_info.take(); + let old_parent = self.resolver.invocation_parents.insert( + id, + InvocationParent { + parent_def: self.parent_def, + pending_anon_const_info, + impl_trait_context: self.impl_trait_context, + in_attr: self.in_attr, + }, + ); assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation"); } } -impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { +impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { fn visit_item(&mut self, i: &'a Item) { // Pick the def data. This need not be unique, but the more // information we encapsulate into, the better @@ -326,46 +347,65 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { } fn visit_anon_const(&mut self, constant: &'a AnonConst) { - if self.resolver.tcx.features().const_arg_path - && constant.value.is_potential_trivial_const_arg() - { - // HACK(min_generic_const_args): don't create defs for anon consts if we think they will - // later be turned into ConstArgKind::Path's. because this is before resolve is done, we - // may accidentally identify a construction of a unit struct as a param and not create a - // def. we'll then create a def later in ast lowering in this case. the parent of nested - // items will be messed up, but that's ok because there can't be any if we're just looking - // for bare idents. - visit::walk_anon_const(self, constant) - } else { - let def = - self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span); - self.with_parent(def, |this| visit::walk_anon_const(this, constant)); + // HACK(min_generic_const_args): don't create defs for anon consts if we think they will + // later be turned into ConstArgKind::Path's. because this is before resolve is done, we + // may accidentally identify a construction of a unit struct as a param and not create a + // def. we'll then create a def later in ast lowering in this case. the parent of nested + // 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() { + return visit::walk_anon_const(self, constant); } + + let def = self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span); + self.with_parent(def, |this| visit::walk_anon_const(this, constant)); } fn visit_expr(&mut self, expr: &'a Expr) { - let parent_def = match expr.kind { - ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id), - ExprKind::Closure(..) | ExprKind::Gen(..) => { - self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) - } - ExprKind::ConstBlock(ref constant) => { - for attr in &expr.attrs { - visit::walk_attribute(self, attr); - } - let def = self.create_def( - constant.id, - kw::Empty, - DefKind::InlineConst, - constant.value.span, - ); - self.with_parent(def, |this| visit::walk_anon_const(this, constant)); - return; + if matches!(expr.kind, ExprKind::MacCall(..)) { + return self.visit_macro_invoc(expr.id); + } + + 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() { + self.create_def(pending_anon.id, kw::Empty, DefKind::AnonConst, pending_anon.span) + } else { + self.parent_def } - _ => self.parent_def, + } else { + self.parent_def }; - self.with_parent(parent_def, |this| visit::walk_expr(this, expr)); + self.with_parent(grandparent_def, |this| { + let parent_def = match expr.kind { + ExprKind::Closure(..) | ExprKind::Gen(..) => { + this.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) + } + ExprKind::ConstBlock(ref constant) => { + for attr in &expr.attrs { + visit::walk_attribute(this, attr); + } + let def = this.create_def( + constant.id, + kw::Empty, + DefKind::InlineConst, + constant.value.span, + ); + this.with_parent(def, |this| visit::walk_anon_const(this, constant)); + return; + } + _ => this.parent_def, + }; + + this.with_parent(parent_def, |this| visit::walk_expr(this, expr)) + }) } fn visit_ty(&mut self, ty: &'a Ty) { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 182577b82c4..3b69ecee357 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -123,7 +123,7 @@ fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span { sm.span_until_whitespace(impl_span) } -impl<'a, 'tcx> Resolver<'a, 'tcx> { +impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> { self.tcx.dcx() } @@ -208,8 +208,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { parent: Module<'_>, ident: Ident, ns: Namespace, - new_binding: NameBinding<'a>, - old_binding: NameBinding<'a>, + new_binding: NameBinding<'ra>, + old_binding: NameBinding<'ra>, ) { // Error on the second of two conflicting names if old_binding.span.lo() > new_binding.span.lo() { @@ -531,7 +531,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn add_module_candidates( &mut self, - module: Module<'a>, + module: Module<'ra>, names: &mut Vec<TypoSuggestion>, filter_fn: &impl Fn(Res) -> bool, ctxt: Option<SyntaxContext>, @@ -553,7 +553,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn report_error( &mut self, span: Span, - resolution_error: ResolutionError<'a>, + resolution_error: ResolutionError<'ra>, ) -> ErrorGuaranteed { self.into_struct_error(span, resolution_error).emit() } @@ -561,7 +561,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn into_struct_error( &mut self, span: Span, - resolution_error: ResolutionError<'a>, + resolution_error: ResolutionError<'ra>, ) -> Diag<'_> { match resolution_error { ResolutionError::GenericParamsFromOuterItem( @@ -1020,8 +1020,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Lookup typo candidate in scope for a macro or import. fn early_lookup_typo_candidate( &mut self, - scope_set: ScopeSet<'a>, - parent_scope: &ParentScope<'a>, + scope_set: ScopeSet<'ra>, + parent_scope: &ParentScope<'ra>, ident: Ident, filter_fn: &impl Fn(Res) -> bool, ) -> Option<TypoSuggestion> { @@ -1156,8 +1156,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, lookup_ident: Ident, namespace: Namespace, - parent_scope: &ParentScope<'a>, - start_module: Module<'a>, + parent_scope: &ParentScope<'ra>, + start_module: Module<'ra>, crate_path: ThinVec<ast::PathSegment>, filter_fn: FilterFn, ) -> Vec<ImportSuggestion> @@ -1233,64 +1233,63 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && ns == namespace && in_module != parent_scope.module && !ident.span.normalize_to_macros_2_0().from_expansion() + && filter_fn(res) { - if filter_fn(res) { - // create the path - let mut segms = if lookup_ident.span.at_least_rust_2018() { - // crate-local absolute paths start with `crate::` in edition 2018 - // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660) - crate_path.clone() - } else { - ThinVec::new() - }; - segms.append(&mut path_segments.clone()); + // create the path + let mut segms = if lookup_ident.span.at_least_rust_2018() { + // crate-local absolute paths start with `crate::` in edition 2018 + // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660) + crate_path.clone() + } else { + ThinVec::new() + }; + segms.append(&mut path_segments.clone()); - segms.push(ast::PathSegment::from_ident(ident)); - let path = Path { span: name_binding.span, segments: segms, tokens: None }; + segms.push(ast::PathSegment::from_ident(ident)); + let path = Path { span: name_binding.span, segments: segms, tokens: None }; - if child_accessible { - // Remove invisible match if exists - if let Some(idx) = candidates - .iter() - .position(|v: &ImportSuggestion| v.did == did && !v.accessible) - { - candidates.remove(idx); - } + if child_accessible { + // Remove invisible match if exists + if let Some(idx) = candidates + .iter() + .position(|v: &ImportSuggestion| v.did == did && !v.accessible) + { + candidates.remove(idx); } + } - if candidates.iter().all(|v: &ImportSuggestion| v.did != did) { - // See if we're recommending TryFrom, TryInto, or FromIterator and add - // a note about editions - let note = if let Some(did) = did { - let requires_note = !did.is_local() - && this.tcx.get_attrs(did, sym::rustc_diagnostic_item).any( - |attr| { - [sym::TryInto, sym::TryFrom, sym::FromIterator] - .map(|x| Some(x)) - .contains(&attr.value_str()) - }, - ); - - requires_note.then(|| { - format!( - "'{}' is included in the prelude starting in Edition 2021", - path_names_to_string(&path) - ) - }) - } else { - None - }; - - candidates.push(ImportSuggestion { - did, - descr: res.descr(), - path, - accessible: child_accessible, - doc_visible: child_doc_visible, - note, - via_import, - }); - } + if candidates.iter().all(|v: &ImportSuggestion| v.did != did) { + // See if we're recommending TryFrom, TryInto, or FromIterator and add + // a note about editions + let note = if let Some(did) = did { + let requires_note = !did.is_local() + && this.tcx.get_attrs(did, sym::rustc_diagnostic_item).any( + |attr| { + [sym::TryInto, sym::TryFrom, sym::FromIterator] + .map(|x| Some(x)) + .contains(&attr.value_str()) + }, + ); + + requires_note.then(|| { + format!( + "'{}' is included in the prelude starting in Edition 2021", + path_names_to_string(&path) + ) + }) + } else { + None + }; + + candidates.push(ImportSuggestion { + did, + descr: res.descr(), + path, + accessible: child_accessible, + doc_visible: child_doc_visible, + note, + via_import, + }); } } @@ -1343,7 +1342,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, lookup_ident: Ident, namespace: Namespace, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, filter_fn: FilterFn, ) -> Vec<ImportSuggestion> where @@ -1421,7 +1420,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, err: &mut Diag<'_>, macro_kind: MacroKind, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, ident: Ident, krate: &Crate, ) { @@ -1749,7 +1748,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None } - fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'a>) { + fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { let PrivacyError { ident, binding, outermost_res, parent_scope, single_nested, dedup_span } = *privacy_error; @@ -1954,7 +1953,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn find_similarly_named_module_or_crate( &mut self, ident: Symbol, - current_module: Module<'a>, + current_module: Module<'ra>, ) -> Option<Symbol> { let mut candidates = self .extern_prelude @@ -1982,11 +1981,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import - parent_scope: &ParentScope<'a>, - ribs: Option<&PerNS<Vec<Rib<'a>>>>, - ignore_binding: Option<NameBinding<'a>>, - ignore_import: Option<Import<'a>>, - module: Option<ModuleOrUniformRoot<'a>>, + parent_scope: &ParentScope<'ra>, + ribs: Option<&PerNS<Vec<Rib<'ra>>>>, + ignore_binding: Option<NameBinding<'ra>>, + ignore_import: Option<Import<'ra>>, + module: Option<ModuleOrUniformRoot<'ra>>, failed_segment_idx: usize, ident: Ident, ) -> (String, Option<Suggestion>) { @@ -2228,7 +2227,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, span: Span, mut path: Vec<Segment>, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, ) -> Option<(Vec<Segment>, Option<String>)> { debug!("make_path_suggestion: span={:?} path={:?}", span, path); @@ -2263,7 +2262,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn make_missing_self_suggestion( &mut self, mut path: Vec<Segment>, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, ) -> Option<(Vec<Segment>, Option<String>)> { // Replace first ident with `self` and check if that is valid. path[0].ident.name = kw::SelfLower; @@ -2282,7 +2281,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn make_missing_crate_suggestion( &mut self, mut path: Vec<Segment>, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, ) -> Option<(Vec<Segment>, Option<String>)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Crate; @@ -2313,7 +2312,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn make_missing_super_suggestion( &mut self, mut path: Vec<Segment>, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, ) -> Option<(Vec<Segment>, Option<String>)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Super; @@ -2335,7 +2334,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn make_external_crate_suggestion( &mut self, mut path: Vec<Segment>, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, ) -> Option<(Vec<Segment>, Option<String>)> { if path[1].ident.span.is_rust_2015() { return None; @@ -2378,8 +2377,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// ``` pub(crate) fn check_for_module_export_macro( &mut self, - import: Import<'a>, - module: ModuleOrUniformRoot<'a>, + import: Import<'ra>, + module: ModuleOrUniformRoot<'ra>, ident: Ident, ) -> Option<(Option<Suggestion>, Option<String>)> { let ModuleOrUniformRoot::Module(mut crate_module) = module else { diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 5ee495da2d9..c91eed0e39b 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -11,9 +11,9 @@ use tracing::info; use crate::{NameBinding, NameBindingKind, Resolver}; #[derive(Clone, Copy)] -enum ParentId<'a> { +enum ParentId<'ra> { Def(LocalDefId), - Import(NameBinding<'a>), + Import(NameBinding<'ra>), } impl ParentId<'_> { @@ -25,13 +25,13 @@ impl ParentId<'_> { } } -pub(crate) struct EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { - r: &'r mut Resolver<'a, 'tcx>, +pub(crate) struct EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { + r: &'a mut Resolver<'ra, 'tcx>, def_effective_visibilities: EffectiveVisibilities, /// While walking import chains we need to track effective visibilities per-binding, and def id /// keys in `Resolver::effective_visibilities` are not enough for that, because multiple /// bindings can correspond to a single def id in imports. So we keep a separate table. - import_effective_visibilities: EffectiveVisibilities<NameBinding<'a>>, + import_effective_visibilities: EffectiveVisibilities<NameBinding<'ra>>, // It's possible to recalculate this at any point, but it's relatively expensive. current_private_vis: Visibility, changed: bool, @@ -63,14 +63,14 @@ impl Resolver<'_, '_> { } } -impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { +impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { /// Fills the `Resolver::effective_visibilities` table with public & exported items /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we /// need access to a TyCtxt for that. Returns the set of ambiguous re-exports. pub(crate) fn compute_effective_visibilities<'c>( - r: &'r mut Resolver<'a, 'tcx>, + r: &'a mut Resolver<'ra, 'tcx>, krate: &'c Crate, - ) -> FxHashSet<NameBinding<'a>> { + ) -> FxHashSet<NameBinding<'ra>> { let mut visitor = EffectiveVisibilitiesVisitor { r, def_effective_visibilities: Default::default(), @@ -127,7 +127,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { // leading to it into the table. They are used by the `ambiguous_glob_reexports` // lint. For all bindings added to the table this way `is_ambiguity` returns true. let is_ambiguity = - |binding: NameBinding<'a>, warn: bool| binding.ambiguity.is_some() && !warn; + |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; let mut parent_id = ParentId::Def(module_id); let mut warn_ambiguity = binding.warn_ambiguity; while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { @@ -153,7 +153,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } } - fn effective_vis_or_private(&mut self, parent_id: ParentId<'a>) -> EffectiveVisibility { + fn effective_vis_or_private(&mut self, parent_id: ParentId<'ra>) -> EffectiveVisibility { // Private nodes are only added to the table for caching, they could be added or removed at // any moment without consequences, so we don't set `changed` to true when adding them. *match parent_id { @@ -190,7 +190,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } } - fn update_import(&mut self, binding: NameBinding<'a>, parent_id: ParentId<'a>) { + fn update_import(&mut self, binding: NameBinding<'ra>, parent_id: ParentId<'ra>) { let nominal_vis = binding.vis.expect_local(); let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); @@ -205,7 +205,12 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { ); } - fn update_def(&mut self, def_id: LocalDefId, nominal_vis: Visibility, parent_id: ParentId<'a>) { + fn update_def( + &mut self, + def_id: LocalDefId, + nominal_vis: Visibility, + parent_id: ParentId<'ra>, + ) { let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); let tcx = self.r.tcx; @@ -224,8 +229,8 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } } -impl<'r, 'ast, 'tcx> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r, 'tcx> { - fn visit_item(&mut self, item: &'ast ast::Item) { +impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { + fn visit_item(&mut self, item: &'a ast::Item) { let def_id = self.r.local_def_id(item.id); // Update effective visibilities of nested items. // If it's a mod, also make the visitor walk all of its items diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 87f8e51f282..61df051ec1e 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -38,16 +38,16 @@ impl From<UsePrelude> for bool { } } -impl<'a, 'tcx> Resolver<'a, 'tcx> { +impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. /// If the callback returns `Some` result, we stop visiting scopes and return it. pub(crate) fn visit_scopes<T>( &mut self, - scope_set: ScopeSet<'a>, - parent_scope: &ParentScope<'a>, + scope_set: ScopeSet<'ra>, + parent_scope: &ParentScope<'ra>, ctxt: SyntaxContext, - mut visitor: impl FnMut(&mut Self, Scope<'a>, UsePrelude, SyntaxContext) -> Option<T>, + mut visitor: impl FnMut(&mut Self, Scope<'ra>, UsePrelude, SyntaxContext) -> Option<T>, ) -> Option<T> { // General principles: // 1. Not controlled (user-defined) names should have higher priority than controlled names @@ -218,10 +218,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn hygienic_lexical_parent( &mut self, - module: Module<'a>, + module: Module<'ra>, ctxt: &mut SyntaxContext, derive_fallback_lint_id: Option<NodeId>, - ) -> Option<(Module<'a>, Option<NodeId>)> { + ) -> Option<(Module<'ra>, Option<NodeId>)> { if !module.expansion.outer_expn_is_descendant_of(*ctxt) { return Some((self.expn_def_scope(ctxt.remove_mark()), None)); } @@ -286,11 +286,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, mut ident: Ident, ns: Namespace, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, finalize: Option<Finalize>, - ribs: &[Rib<'a>], - ignore_binding: Option<NameBinding<'a>>, - ) -> Option<LexicalScopeBinding<'a>> { + ribs: &[Rib<'ra>], + ignore_binding: Option<NameBinding<'ra>>, + ) -> Option<LexicalScopeBinding<'ra>> { assert!(ns == TypeNS || ns == ValueNS); let orig_ident = ident; if ident.name == kw::Empty { @@ -381,13 +381,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn early_resolve_ident_in_lexical_scope( &mut self, orig_ident: Ident, - scope_set: ScopeSet<'a>, - parent_scope: &ParentScope<'a>, + scope_set: ScopeSet<'ra>, + parent_scope: &ParentScope<'ra>, finalize: Option<Finalize>, force: bool, - ignore_binding: Option<NameBinding<'a>>, - ignore_import: Option<Import<'a>>, - ) -> Result<NameBinding<'a>, Determinacy> { + ignore_binding: Option<NameBinding<'ra>>, + ignore_import: Option<Import<'ra>>, + ) -> Result<NameBinding<'ra>, Determinacy> { bitflags::bitflags! { #[derive(Clone, Copy)] struct Flags: u8 { @@ -742,12 +742,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { #[instrument(level = "debug", skip(self))] pub(crate) fn maybe_resolve_ident_in_module( &mut self, - module: ModuleOrUniformRoot<'a>, + module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, - parent_scope: &ParentScope<'a>, - ignore_import: Option<Import<'a>>, - ) -> Result<NameBinding<'a>, Determinacy> { + parent_scope: &ParentScope<'ra>, + ignore_import: Option<Import<'ra>>, + ) -> Result<NameBinding<'ra>, Determinacy> { self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, None, ignore_import) .map_err(|(determinacy, _)| determinacy) } @@ -755,14 +755,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { #[instrument(level = "debug", skip(self))] pub(crate) fn resolve_ident_in_module( &mut self, - module: ModuleOrUniformRoot<'a>, + module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, finalize: Option<Finalize>, - ignore_binding: Option<NameBinding<'a>>, - ignore_import: Option<Import<'a>>, - ) -> Result<NameBinding<'a>, Determinacy> { + ignore_binding: Option<NameBinding<'ra>>, + ignore_import: Option<Import<'ra>>, + ) -> Result<NameBinding<'ra>, Determinacy> { self.resolve_ident_in_module_ext( module, ident, @@ -778,14 +778,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn resolve_ident_in_module_ext( &mut self, - module: ModuleOrUniformRoot<'a>, + module: ModuleOrUniformRoot<'ra>, mut ident: Ident, ns: Namespace, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, finalize: Option<Finalize>, - ignore_binding: Option<NameBinding<'a>>, - ignore_import: Option<Import<'a>>, - ) -> Result<NameBinding<'a>, (Determinacy, Weak)> { + ignore_binding: Option<NameBinding<'ra>>, + ignore_import: Option<Import<'ra>>, + ) -> Result<NameBinding<'ra>, (Determinacy, Weak)> { let tmp_parent_scope; let mut adjusted_parent_scope = parent_scope; match module { @@ -818,14 +818,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn resolve_ident_in_module_unadjusted( &mut self, - module: ModuleOrUniformRoot<'a>, + module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, finalize: Option<Finalize>, - ignore_binding: Option<NameBinding<'a>>, - ignore_import: Option<Import<'a>>, - ) -> Result<NameBinding<'a>, Determinacy> { + ignore_binding: Option<NameBinding<'ra>>, + ignore_import: Option<Import<'ra>>, + ) -> Result<NameBinding<'ra>, Determinacy> { self.resolve_ident_in_module_unadjusted_ext( module, ident, @@ -844,17 +844,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn resolve_ident_in_module_unadjusted_ext( &mut self, - module: ModuleOrUniformRoot<'a>, + module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, restricted_shadowing: bool, finalize: Option<Finalize>, // This binding should be ignored during in-module resolution, so that we don't get // "self-confirming" import resolutions during import validation and checking. - ignore_binding: Option<NameBinding<'a>>, - ignore_import: Option<Import<'a>>, - ) -> Result<NameBinding<'a>, (Determinacy, Weak)> { + ignore_binding: Option<NameBinding<'ra>>, + ignore_import: Option<Import<'ra>>, + ) -> Result<NameBinding<'ra>, (Determinacy, Weak)> { let module = match module { ModuleOrUniformRoot::Module(module) => module, ModuleOrUniformRoot::CrateRootAndExternPrelude => { @@ -958,19 +958,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }); } - if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT { - if let NameBindingKind::Import { import, .. } = binding.kind - && matches!(import.kind, ImportKind::MacroExport) - { - self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); - } + if !restricted_shadowing + && binding.expansion != LocalExpnId::ROOT + && let NameBindingKind::Import { import, .. } = binding.kind + && matches!(import.kind, ImportKind::MacroExport) + { + self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } self.record_use(ident, binding, used); return Ok(binding); } - let check_usable = |this: &mut Self, binding: NameBinding<'a>| { + let check_usable = |this: &mut Self, binding: NameBinding<'ra>| { let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; @@ -1151,7 +1151,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { mut res: Res, finalize: Option<Span>, original_rib_ident_def: Ident, - all_ribs: &[Rib<'a>], + all_ribs: &[Rib<'ra>], ) -> Res { debug!("validate_res_from_ribs({:?})", res); let ribs = &all_ribs[rib_index + 1..]; @@ -1436,9 +1436,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import - parent_scope: &ParentScope<'a>, - ignore_import: Option<Import<'a>>, - ) -> PathResult<'a> { + parent_scope: &ParentScope<'ra>, + ignore_import: Option<Import<'ra>>, + ) -> PathResult<'ra> { self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None, ignore_import) } @@ -1447,11 +1447,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, finalize: Option<Finalize>, - ignore_binding: Option<NameBinding<'a>>, - ignore_import: Option<Import<'a>>, - ) -> PathResult<'a> { + ignore_binding: Option<NameBinding<'ra>>, + ignore_import: Option<Import<'ra>>, + ) -> PathResult<'ra> { self.resolve_path_with_ribs( path, opt_ns, @@ -1467,12 +1467,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, finalize: Option<Finalize>, - ribs: Option<&PerNS<Vec<Rib<'a>>>>, - ignore_binding: Option<NameBinding<'a>>, - ignore_import: Option<Import<'a>>, - ) -> PathResult<'a> { + ribs: Option<&PerNS<Vec<Rib<'ra>>>>, + ignore_binding: Option<NameBinding<'ra>>, + ignore_import: Option<Import<'ra>>, + ) -> PathResult<'ra> { let mut module = None; let mut allow_super = true; let mut second_binding = None; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 42171edf757..67ee377fd54 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -43,7 +43,7 @@ type Res = def::Res<NodeId>; /// Contains data for specific kinds of imports. #[derive(Clone)] -pub(crate) enum ImportKind<'a> { +pub(crate) enum ImportKind<'ra> { Single { /// `source` in `use prefix::source as target`. source: Ident, @@ -51,9 +51,9 @@ pub(crate) enum ImportKind<'a> { /// It will directly use `source` when the format is `use prefix::source`. target: Ident, /// Bindings to which `source` refers to. - source_bindings: PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>, + source_bindings: PerNS<Cell<Result<NameBinding<'ra>, Determinacy>>>, /// Bindings introduced by `target`. - target_bindings: PerNS<Cell<Option<NameBinding<'a>>>>, + target_bindings: PerNS<Cell<Option<NameBinding<'ra>>>>, /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` @@ -93,7 +93,7 @@ pub(crate) enum ImportKind<'a> { /// Manually implement `Debug` for `ImportKind` because the `source/target_bindings` /// contain `Cell`s which can introduce infinite loops while printing. -impl<'a> std::fmt::Debug for ImportKind<'a> { +impl<'ra> std::fmt::Debug for ImportKind<'ra> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use ImportKind::*; match self { @@ -142,8 +142,8 @@ impl<'a> std::fmt::Debug for ImportKind<'a> { /// One import. #[derive(Debug, Clone)] -pub(crate) struct ImportData<'a> { - pub kind: ImportKind<'a>, +pub(crate) struct ImportData<'ra> { + pub kind: ImportKind<'ra>, /// Node ID of the "root" use item -- this is always the same as `ImportKind`'s `id` /// (if it exists) except in the case of "nested" use trees, in which case @@ -171,18 +171,18 @@ pub(crate) struct ImportData<'a> { /// Span of the *root* use tree (see `root_id`). pub root_span: Span, - pub parent_scope: ParentScope<'a>, + pub parent_scope: ParentScope<'ra>, pub module_path: Vec<Segment>, /// The resolution of `module_path`. - pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>, + pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>, pub vis: ty::Visibility, } /// All imports are unique and allocated on a same arena, /// so we can use referential equality to compare them. -pub(crate) type Import<'a> = Interned<'a, ImportData<'a>>; +pub(crate) type Import<'ra> = Interned<'ra, ImportData<'ra>>; -impl<'a> ImportData<'a> { +impl<'ra> ImportData<'ra> { pub(crate) fn is_glob(&self) -> bool { matches!(self.kind, ImportKind::Glob { .. }) } @@ -217,18 +217,18 @@ impl<'a> ImportData<'a> { /// Records information about the resolution of a name in a namespace of a module. #[derive(Clone, Default, Debug)] -pub(crate) struct NameResolution<'a> { +pub(crate) struct NameResolution<'ra> { /// Single imports that may define the name in the namespace. /// Imports are arena-allocated, so it's ok to use pointers as keys. - pub single_imports: FxHashSet<Import<'a>>, + pub single_imports: FxHashSet<Import<'ra>>, /// The least shadowable known binding for this name, or None if there are no known bindings. - pub binding: Option<NameBinding<'a>>, - pub shadowed_glob: Option<NameBinding<'a>>, + pub binding: Option<NameBinding<'ra>>, + pub shadowed_glob: Option<NameBinding<'ra>>, } -impl<'a> NameResolution<'a> { +impl<'ra> NameResolution<'ra> { /// Returns the binding for the name if it is known or None if it not known. - pub(crate) fn binding(&self) -> Option<NameBinding<'a>> { + pub(crate) fn binding(&self) -> Option<NameBinding<'ra>> { self.binding.and_then(|binding| { if !binding.is_glob_import() || self.single_imports.is_empty() { Some(binding) @@ -270,10 +270,14 @@ fn pub_use_of_private_extern_crate_hack( } } -impl<'a, 'tcx> Resolver<'a, 'tcx> { +impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Given a binding and an import that resolves to it, /// return the corresponding binding defined by the import. - pub(crate) fn import(&self, binding: NameBinding<'a>, import: Import<'a>) -> NameBinding<'a> { + pub(crate) fn import( + &self, + binding: NameBinding<'ra>, + import: Import<'ra>, + ) -> NameBinding<'ra> { let import_vis = import.vis.to_def_id(); let vis = if binding.vis.is_at_least(import_vis, self.tcx) || pub_use_of_private_extern_crate_hack(import, binding).is_some() @@ -305,11 +309,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// `update` indicates if the definition is a redefinition of an existing binding. pub(crate) fn try_define( &mut self, - module: Module<'a>, + module: Module<'ra>, key: BindingKey, - binding: NameBinding<'a>, + binding: NameBinding<'ra>, warn_ambiguity: bool, - ) -> Result<(), NameBinding<'a>> { + ) -> Result<(), NameBinding<'ra>> { let res = binding.res(); self.check_reserved_macro_name(key.ident, res); self.set_binding_parent_module(binding, module); @@ -394,16 +398,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn new_ambiguity_binding( &self, ambiguity_kind: AmbiguityKind, - primary_binding: NameBinding<'a>, - secondary_binding: NameBinding<'a>, + primary_binding: NameBinding<'ra>, + secondary_binding: NameBinding<'ra>, warn_ambiguity: bool, - ) -> NameBinding<'a> { + ) -> NameBinding<'ra> { let ambiguity = Some((secondary_binding, ambiguity_kind)); let data = NameBindingData { ambiguity, warn_ambiguity, ..*primary_binding }; self.arenas.alloc_name_binding(data) } - fn new_warn_ambiguity_binding(&self, binding: NameBinding<'a>) -> NameBinding<'a> { + fn new_warn_ambiguity_binding(&self, binding: NameBinding<'ra>) -> NameBinding<'ra> { assert!(binding.is_ambiguity_recursive()); self.arenas.alloc_name_binding(NameBindingData { warn_ambiguity: true, ..*binding }) } @@ -412,13 +416,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // If the resolution becomes a success, define it in the module's glob importers. fn update_resolution<T, F>( &mut self, - module: Module<'a>, + module: Module<'ra>, key: BindingKey, warn_ambiguity: bool, f: F, ) -> T where - F: FnOnce(&mut Resolver<'a, 'tcx>, &mut NameResolution<'a>) -> T, + F: FnOnce(&mut Resolver<'ra, 'tcx>, &mut NameResolution<'ra>) -> T, { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. @@ -466,7 +470,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics. - fn import_dummy_binding(&mut self, import: Import<'a>, is_indeterminate: bool) { + fn import_dummy_binding(&mut self, import: Import<'ra>, is_indeterminate: bool) { if let ImportKind::Single { target, ref target_bindings, .. } = import.kind { if !(is_indeterminate || target_bindings.iter().all(|binding| binding.get().is_none())) { @@ -599,7 +603,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn check_hidden_glob_reexports( &mut self, - exported_ambiguities: FxHashSet<NameBinding<'a>>, + exported_ambiguities: FxHashSet<NameBinding<'ra>>, ) { for module in self.arenas.local_modules().iter() { for (key, resolution) in self.resolutions(*module).borrow().iter() { @@ -759,7 +763,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// /// Meanwhile, if resolve successful, the resolved bindings are written /// into the module. - fn resolve_import(&mut self, import: Import<'a>) -> usize { + fn resolve_import(&mut self, import: Import<'ra>) -> usize { debug!( "(resolving import for module) resolving import `{}::...` in `{}`", Segment::names_to_string(&import.module_path), @@ -847,7 +851,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// /// Optionally returns an unresolved import error. This error is buffered and used to /// consolidate multiple unresolved import errors into a single diagnostic. - fn finalize_import(&mut self, import: Import<'a>) -> Option<UnresolvedImportError> { + fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportError> { let ignore_binding = match &import.kind { ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(), _ => None, @@ -1256,28 +1260,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { extern_crate_span: self.tcx.source_span(self.local_def_id(extern_crate_id)), }, ); + } else if ns == TypeNS { + let err = if crate_private_reexport { + self.dcx() + .create_err(CannotBeReexportedCratePublicNS { span: import.span, ident }) + } else { + self.dcx().create_err(CannotBeReexportedPrivateNS { span: import.span, ident }) + }; + err.emit(); } else { - if ns == TypeNS { - let err = if crate_private_reexport { - self.dcx().create_err(CannotBeReexportedCratePublicNS { - span: import.span, - ident, - }) - } else { - self.dcx() - .create_err(CannotBeReexportedPrivateNS { span: import.span, ident }) - }; - err.emit(); + let mut err = if crate_private_reexport { + self.dcx() + .create_err(CannotBeReexportedCratePublic { span: import.span, ident }) } else { - let mut err = if crate_private_reexport { - self.dcx() - .create_err(CannotBeReexportedCratePublic { span: import.span, ident }) - } else { - self.dcx() - .create_err(CannotBeReexportedPrivate { span: import.span, ident }) - }; + self.dcx().create_err(CannotBeReexportedPrivate { span: import.span, ident }) + }; - match binding.kind { + match binding.kind { NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id)) // exclude decl_macro if self.get_macro_by_def_id(def_id).macro_rules => @@ -1293,8 +1292,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }); } } - err.emit(); - } + err.emit(); } } @@ -1323,7 +1321,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None } - pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'a>) -> bool { + pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'ra>) -> bool { // This function is only called for single imports. let ImportKind::Single { source, target, ref source_bindings, ref target_bindings, id, .. @@ -1398,7 +1396,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { false } - fn resolve_glob_import(&mut self, import: Import<'a>) { + fn resolve_glob_import(&mut self, import: Import<'ra>) { // This function is only called for glob imports. let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() }; @@ -1458,7 +1456,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Miscellaneous post-processing, including recording re-exports, // reporting conflicts, and reporting unresolved imports. - fn finalize_resolutions_in(&mut self, module: Module<'a>) { + fn finalize_resolutions_in(&mut self, module: Module<'ra>) { // Since import resolution is finished, globs will not define any more names. *module.globs.borrow_mut() = Vec::new(); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 40a6ac70bfd..0aa351cad40 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -172,7 +172,7 @@ enum RecordPartialRes { /// The rib kind restricts certain accesses, /// e.g. to a `Res::Local` of an outer item. #[derive(Copy, Clone, Debug)] -pub(crate) enum RibKind<'a> { +pub(crate) enum RibKind<'ra> { /// No restriction needs to be applied. Normal, @@ -195,7 +195,7 @@ pub(crate) enum RibKind<'a> { ConstantItem(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>), /// We passed through a module. - Module(Module<'a>), + Module(Module<'ra>), /// We passed through a `macro_rules!` statement MacroDefinition(DefId), @@ -260,13 +260,13 @@ impl RibKind<'_> { /// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When /// resolving, the name is looked up from inside out. #[derive(Debug)] -pub(crate) struct Rib<'a, R = Res> { +pub(crate) struct Rib<'ra, R = Res> { pub bindings: IdentMap<R>, - pub kind: RibKind<'a>, + pub kind: RibKind<'ra>, } -impl<'a, R> Rib<'a, R> { - fn new(kind: RibKind<'a>) -> Rib<'a, R> { +impl<'ra, R> Rib<'ra, R> { + fn new(kind: RibKind<'ra>) -> Rib<'ra, R> { Rib { bindings: Default::default(), kind } } } @@ -584,8 +584,8 @@ impl MaybeExported<'_> { /// Used for recording UnnecessaryQualification. #[derive(Debug)] -pub(crate) struct UnnecessaryQualification<'a> { - pub binding: LexicalScopeBinding<'a>, +pub(crate) struct UnnecessaryQualification<'ra> { + pub binding: LexicalScopeBinding<'ra>, pub node_id: NodeId, pub path_span: Span, pub removal_span: Span, @@ -659,20 +659,20 @@ struct DiagMetadata<'ast> { current_elision_failures: Vec<MissingLifetime>, } -struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { - r: &'b mut Resolver<'a, 'tcx>, +struct LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { + r: &'a mut Resolver<'ra, 'tcx>, /// The module that represents the current item scope. - parent_scope: ParentScope<'a>, + parent_scope: ParentScope<'ra>, /// The current set of local scopes for types and values. - ribs: PerNS<Vec<Rib<'a>>>, + ribs: PerNS<Vec<Rib<'ra>>>, /// Previous popped `rib`, only used for diagnostic. - last_block_rib: Option<Rib<'a>>, + last_block_rib: Option<Rib<'ra>>, /// The current set of local scopes, for labels. - label_ribs: Vec<Rib<'a, NodeId>>, + label_ribs: Vec<Rib<'ra, NodeId>>, /// The current set of local scopes for lifetimes. lifetime_ribs: Vec<LifetimeRib>, @@ -685,7 +685,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { lifetime_elision_candidates: Option<Vec<(LifetimeRes, LifetimeElisionCandidate)>>, /// The trait that the current context can refer to. - current_trait_ref: Option<(Module<'a>, TraitRef)>, + current_trait_ref: Option<(Module<'ra>, TraitRef)>, /// Fields used to add information to diagnostic errors. diag_metadata: Box<DiagMetadata<'ast>>, @@ -702,7 +702,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. -impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, 'tcx> { +impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn visit_attribute(&mut self, _: &'ast Attribute) { // We do not want to resolve expressions that appear in attributes, // as they do not correspond to actual code. @@ -1316,8 +1316,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, } } -impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { - fn new(resolver: &'b mut Resolver<'a, 'tcx>) -> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { +impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { + fn new(resolver: &'a mut Resolver<'ra, 'tcx>) -> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. let graph_root = resolver.graph_root; @@ -1347,7 +1347,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { &mut self, ident: Ident, ns: Namespace, - ) -> Option<LexicalScopeBinding<'a>> { + ) -> Option<LexicalScopeBinding<'ra>> { self.r.resolve_ident_in_lexical_scope( ident, ns, @@ -1363,8 +1363,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ident: Ident, ns: Namespace, finalize: Option<Finalize>, - ignore_binding: Option<NameBinding<'a>>, - ) -> Option<LexicalScopeBinding<'a>> { + ignore_binding: Option<NameBinding<'ra>>, + ) -> Option<LexicalScopeBinding<'ra>> { self.r.resolve_ident_in_lexical_scope( ident, ns, @@ -1380,7 +1380,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { path: &[Segment], opt_ns: Option<Namespace>, // `None` indicates a module path in import finalize: Option<Finalize>, - ) -> PathResult<'a> { + ) -> PathResult<'ra> { self.r.resolve_path_with_ribs( path, opt_ns, @@ -1414,7 +1414,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { fn with_rib<T>( &mut self, ns: Namespace, - kind: RibKind<'a>, + kind: RibKind<'ra>, work: impl FnOnce(&mut Self) -> T, ) -> T { self.ribs[ns].push(Rib::new(kind)); @@ -2266,14 +2266,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { /// Visits a type to find all the &references, and determines the /// set of lifetimes for all of those references where the referent /// contains Self. - struct FindReferenceVisitor<'r, 'a, 'tcx> { - r: &'r Resolver<'a, 'tcx>, + struct FindReferenceVisitor<'a, 'ra, 'tcx> { + r: &'a Resolver<'ra, 'tcx>, impl_self: Option<Res>, lifetime: Set1<LifetimeRes>, } - impl<'a> Visitor<'a> for FindReferenceVisitor<'_, '_, '_> { - fn visit_ty(&mut self, ty: &'a Ty) { + impl<'ra> Visitor<'ra> for FindReferenceVisitor<'_, '_, '_> { + fn visit_ty(&mut self, ty: &'ra Ty) { trace!("FindReferenceVisitor considering ty={:?}", ty); if let TyKind::Ref(lt, _) = ty.kind { // See if anything inside the &thing contains Self @@ -2299,13 +2299,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // A type may have an expression as a const generic argument. // We do not want to recurse into those. - fn visit_expr(&mut self, _: &'a Expr) {} + fn visit_expr(&mut self, _: &'ra Expr) {} } /// Visitor which checks the referent of a &Thing to see if the /// Thing contains Self - struct SelfVisitor<'r, 'a, 'tcx> { - r: &'r Resolver<'a, 'tcx>, + struct SelfVisitor<'a, 'ra, 'tcx> { + r: &'a Resolver<'ra, 'tcx>, impl_self: Option<Res>, self_found: bool, } @@ -2327,8 +2327,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } } - impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> { - fn visit_ty(&mut self, ty: &'a Ty) { + impl<'ra> Visitor<'ra> for SelfVisitor<'_, '_, '_> { + fn visit_ty(&mut self, ty: &'ra Ty) { trace!("SelfVisitor considering ty={:?}", ty); if self.is_self_ty(ty) { trace!("SelfVisitor found Self"); @@ -2339,7 +2339,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // A type may have an expression as a const generic argument. // We do not want to recurse into those. - fn visit_expr(&mut self, _: &'a Expr) {} + fn visit_expr(&mut self, _: &'ra Expr) {} } let impl_self = self @@ -2371,7 +2371,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved /// label and reports an error if the label is not found or is unreachable. - fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'a>> { + fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'ra>> { let mut suggestion = None; for i in (0..self.label_ribs.len()).rev() { @@ -2712,7 +2712,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { fn with_generic_param_rib<'c, F>( &'c mut self, params: &'c [GenericParam], - kind: RibKind<'a>, + kind: RibKind<'ra>, lifetime_kind: LifetimeRibKind, f: F, ) where @@ -2878,7 +2878,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } } - fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) { + fn with_label_rib(&mut self, kind: RibKind<'ra>, f: impl FnOnce(&mut Self)) { self.label_ribs.push(Rib::new(kind)); f(self); self.label_ribs.pop(); @@ -3306,7 +3306,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { seen_trait_items: &mut FxHashMap<DefId, Span>, err: F, ) where - F: FnOnce(Ident, String, Option<Symbol>) -> ResolutionError<'a>, + F: FnOnce(Ident, String, Option<Symbol>) -> ResolutionError<'ra>, { // If there is a TraitRef in scope for an impl, then the method must be in the trait. let Some((module, _)) = self.current_trait_ref else { @@ -4010,101 +4010,102 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // about possible missing imports. // // Similar thing, for types, happens in `report_errors` above. - let report_errors_for_call = |this: &mut Self, parent_err: Spanned<ResolutionError<'a>>| { - // Before we start looking for candidates, we have to get our hands - // on the type user is trying to perform invocation on; basically: - // we're transforming `HashMap::new` into just `HashMap`. - let (following_seg, prefix_path) = match path.split_last() { - Some((last, path)) if !path.is_empty() => (Some(last), path), - _ => return Some(parent_err), - }; + let report_errors_for_call = + |this: &mut Self, parent_err: Spanned<ResolutionError<'ra>>| { + // Before we start looking for candidates, we have to get our hands + // on the type user is trying to perform invocation on; basically: + // we're transforming `HashMap::new` into just `HashMap`. + let (following_seg, prefix_path) = match path.split_last() { + Some((last, path)) if !path.is_empty() => (Some(last), path), + _ => return Some(parent_err), + }; - let (mut err, candidates) = this.smart_resolve_report_errors( - prefix_path, - following_seg, - path_span, - PathSource::Type, - None, - ); + let (mut err, candidates) = this.smart_resolve_report_errors( + prefix_path, + following_seg, + path_span, + PathSource::Type, + None, + ); - // There are two different error messages user might receive at - // this point: - // - E0412 cannot find type `{}` in this scope - // - E0433 failed to resolve: use of undeclared type or module `{}` - // - // The first one is emitted for paths in type-position, and the - // latter one - for paths in expression-position. - // - // Thus (since we're in expression-position at this point), not to - // confuse the user, we want to keep the *message* from E0433 (so - // `parent_err`), but we want *hints* from E0412 (so `err`). - // - // And that's what happens below - we're just mixing both messages - // into a single one. - let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node); - - // overwrite all properties with the parent's error message - err.messages = take(&mut parent_err.messages); - err.code = take(&mut parent_err.code); - swap(&mut err.span, &mut parent_err.span); - err.children = take(&mut parent_err.children); - err.sort_span = parent_err.sort_span; - err.is_lint = parent_err.is_lint.clone(); - - // merge the parent's suggestions with the typo suggestions - fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) { - match res1 { - Ok(vec1) => match res2 { - Ok(mut vec2) => vec1.append(&mut vec2), - Err(e) => *res1 = Err(e), - }, - Err(_) => (), - }; - } - append_result(&mut err.suggestions, parent_err.suggestions.clone()); + // There are two different error messages user might receive at + // this point: + // - E0412 cannot find type `{}` in this scope + // - E0433 failed to resolve: use of undeclared type or module `{}` + // + // The first one is emitted for paths in type-position, and the + // latter one - for paths in expression-position. + // + // Thus (since we're in expression-position at this point), not to + // confuse the user, we want to keep the *message* from E0433 (so + // `parent_err`), but we want *hints* from E0412 (so `err`). + // + // And that's what happens below - we're just mixing both messages + // into a single one. + let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node); + + // overwrite all properties with the parent's error message + err.messages = take(&mut parent_err.messages); + err.code = take(&mut parent_err.code); + swap(&mut err.span, &mut parent_err.span); + err.children = take(&mut parent_err.children); + err.sort_span = parent_err.sort_span; + err.is_lint = parent_err.is_lint.clone(); + + // merge the parent's suggestions with the typo suggestions + fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) { + match res1 { + Ok(vec1) => match res2 { + Ok(mut vec2) => vec1.append(&mut vec2), + Err(e) => *res1 = Err(e), + }, + Err(_) => (), + }; + } + append_result(&mut err.suggestions, parent_err.suggestions.clone()); - parent_err.cancel(); + parent_err.cancel(); - let def_id = this.parent_scope.module.nearest_parent_mod(); + let def_id = this.parent_scope.module.nearest_parent_mod(); - if this.should_report_errs() { - if candidates.is_empty() { - if path.len() == 2 - && let [segment] = prefix_path - { - // Delay to check whether methond name is an associated function or not - // ``` - // let foo = Foo {}; - // foo::bar(); // possibly suggest to foo.bar(); - //``` - err.stash(segment.ident.span, rustc_errors::StashKey::CallAssocMethod); + if this.should_report_errs() { + if candidates.is_empty() { + if path.len() == 2 + && let [segment] = prefix_path + { + // Delay to check whether methond name is an associated function or not + // ``` + // let foo = Foo {}; + // foo::bar(); // possibly suggest to foo.bar(); + //``` + err.stash(segment.ident.span, rustc_errors::StashKey::CallAssocMethod); + } else { + // When there is no suggested imports, we can just emit the error + // and suggestions immediately. Note that we bypass the usually error + // reporting routine (ie via `self.r.report_error`) because we need + // to post-process the `ResolutionError` above. + err.emit(); + } } else { - // When there is no suggested imports, we can just emit the error - // and suggestions immediately. Note that we bypass the usually error - // reporting routine (ie via `self.r.report_error`) because we need - // to post-process the `ResolutionError` above. - err.emit(); + // If there are suggested imports, the error reporting is delayed + this.r.use_injections.push(UseError { + err, + candidates, + def_id, + instead: false, + suggestion: None, + path: prefix_path.into(), + is_call: source.is_call(), + }); } } else { - // If there are suggested imports, the error reporting is delayed - this.r.use_injections.push(UseError { - err, - candidates, - def_id, - instead: false, - suggestion: None, - path: prefix_path.into(), - is_call: source.is_call(), - }); + err.cancel(); } - } else { - err.cancel(); - } - // We don't return `Some(parent_err)` here, because the error will - // be already printed either immediately or as part of the `use` injections - None - }; + // We don't return `Some(parent_err)` here, because the error will + // be already printed either immediately or as part of the `use` injections + None + }; let partial_res = match self.resolve_qpath_anywhere( qself, @@ -4205,7 +4206,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { /// A wrapper around [`Resolver::report_error`]. /// /// This doesn't emit errors for function bodies if this is rustdoc. - fn report_error(&mut self, span: Span, resolution_error: ResolutionError<'a>) { + fn report_error(&mut self, span: Span, resolution_error: ResolutionError<'ra>) { if self.should_report_errs() { self.r.report_error(span, resolution_error); } @@ -4229,7 +4230,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { span: Span, defer_to_typeck: bool, finalize: Finalize, - ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'a>>> { + ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> { let mut fin_res = None; for (i, &ns) in [primary_ns, TypeNS, ValueNS].iter().enumerate() { @@ -4271,7 +4272,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { path: &[Segment], ns: Namespace, finalize: Finalize, - ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'a>>> { + ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> { debug!( "resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})", qself, path, ns, finalize, @@ -4781,16 +4782,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { if let Some(res) = res && let Some(def_id) = res.opt_def_id() && !def_id.is_local() + && self.r.tcx.crate_types().contains(&CrateType::ProcMacro) + && matches!( + self.r.tcx.sess.opts.resolve_doc_links, + ResolveDocLinks::ExportedMetadata + ) { - if self.r.tcx.crate_types().contains(&CrateType::ProcMacro) - && matches!( - self.r.tcx.sess.opts.resolve_doc_links, - ResolveDocLinks::ExportedMetadata - ) - { - // Encoding foreign def ids in proc macro crate metadata will ICE. - return None; - } + // Encoding foreign def ids in proc macro crate metadata will ICE. + return None; } res }); @@ -4922,8 +4921,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { /// Walks the whole crate in DFS order, visiting each item, counting the declared number of /// lifetime generic parameters and function parameters. -struct ItemInfoCollector<'a, 'b, 'tcx> { - r: &'b mut Resolver<'a, 'tcx>, +struct ItemInfoCollector<'a, 'ra, 'tcx> { + r: &'a mut Resolver<'ra, 'tcx>, } impl ItemInfoCollector<'_, '_, '_> { @@ -4990,7 +4989,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { } } -impl<'a, 'tcx> Resolver<'a, 'tcx> { +impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) { visit::walk_crate(&mut ItemInfoCollector { r: self }, krate); let mut late_resolution_visitor = LateResolutionVisitor::new(self); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 098509cd1d5..1c584bf8338 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -170,7 +170,7 @@ impl TypoCandidate { } } -impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { +impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn make_base_error( &mut self, path: &[Segment], @@ -2255,30 +2255,29 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn let_binding_suggestion(&mut self, err: &mut Diag<'_>, ident_span: Span) -> bool { if let Some(Expr { kind: ExprKind::Assign(lhs, ..), .. }) = self.diag_metadata.in_assignment && let ast::ExprKind::Path(None, ref path) = lhs.kind + && !ident_span.from_expansion() { - if !ident_span.from_expansion() { - let (span, text) = match path.segments.first() { - Some(seg) if let Some(name) = seg.ident.as_str().strip_prefix("let") => { - // a special case for #117894 - let name = name.strip_prefix('_').unwrap_or(name); - (ident_span, format!("let {name}")) - } - _ => (ident_span.shrink_to_lo(), "let ".to_string()), - }; + let (span, text) = match path.segments.first() { + Some(seg) if let Some(name) = seg.ident.as_str().strip_prefix("let") => { + // a special case for #117894 + let name = name.strip_prefix('_').unwrap_or(name); + (ident_span, format!("let {name}")) + } + _ => (ident_span.shrink_to_lo(), "let ".to_string()), + }; - err.span_suggestion_verbose( - span, - "you might have meant to introduce a new binding", - text, - Applicability::MaybeIncorrect, - ); - return true; - } + err.span_suggestion_verbose( + span, + "you might have meant to introduce a new binding", + text, + Applicability::MaybeIncorrect, + ); + return true; } false } - fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> { + fn find_module(&mut self, def_id: DefId) -> Option<(Module<'ra>, ImportSuggestion)> { let mut result = None; let mut seen_modules = FxHashSet::default(); let root_did = self.r.graph_root.def_id(); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8ffd00d1b2e..c05bd9e72ea 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -113,14 +113,14 @@ impl Determinacy { /// This enum is currently used only for early resolution (imports and macros), /// but not for late resolution yet. #[derive(Clone, Copy, Debug)] -enum Scope<'a> { +enum Scope<'ra> { DeriveHelpers(LocalExpnId), DeriveHelpersCompat, - MacroRules(MacroRulesScopeRef<'a>), + MacroRules(MacroRulesScopeRef<'ra>), CrateRoot, // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` // lint if it should be reported. - Module(Module<'a>, Option<NodeId>), + Module(Module<'ra>, Option<NodeId>), MacroUsePrelude, BuiltinAttrs, ExternPrelude, @@ -134,7 +134,7 @@ enum Scope<'a> { /// This enum is currently used only for early resolution (imports and macros), /// but not for late resolution yet. #[derive(Clone, Copy, Debug)] -enum ScopeSet<'a> { +enum ScopeSet<'ra> { /// All scopes with the given namespace. All(Namespace), /// Crate root, then extern prelude (used for mixed 2015-2018 mode in macros). @@ -143,7 +143,7 @@ enum ScopeSet<'a> { Macro(MacroKind), /// All scopes with the given namespace, used for partially performing late resolution. /// The node id enables lints and is used for reporting them. - Late(Namespace, Module<'a>, Option<NodeId>), + Late(Namespace, Module<'ra>, Option<NodeId>), } /// Everything you need to know about a name's location to resolve it. @@ -151,17 +151,17 @@ enum ScopeSet<'a> { /// This struct is currently used only for early resolution (imports and macros), /// but not for late resolution yet. #[derive(Clone, Copy, Debug)] -struct ParentScope<'a> { - module: Module<'a>, +struct ParentScope<'ra> { + module: Module<'ra>, expansion: LocalExpnId, - macro_rules: MacroRulesScopeRef<'a>, - derives: &'a [ast::Path], + macro_rules: MacroRulesScopeRef<'ra>, + derives: &'ra [ast::Path], } -impl<'a> ParentScope<'a> { +impl<'ra> ParentScope<'ra> { /// Creates a parent scope with the passed argument used as the module scope component, /// and other scope components set to default empty values. - fn module(module: Module<'a>, resolver: &Resolver<'a, '_>) -> ParentScope<'a> { + fn module(module: Module<'ra>, resolver: &Resolver<'ra, '_>) -> ParentScope<'ra> { ParentScope { module, expansion: LocalExpnId::ROOT, @@ -172,6 +172,29 @@ impl<'a> ParentScope<'a> { } #[derive(Copy, Debug, Clone)] +struct InvocationParent { + parent_def: LocalDefId, + pending_anon_const_info: Option<PendingAnonConstInfo>, + impl_trait_context: ImplTraitContext, + in_attr: bool, +} + +impl InvocationParent { + const ROOT: Self = Self { + parent_def: CRATE_DEF_ID, + pending_anon_const_info: None, + impl_trait_context: ImplTraitContext::Existential, + in_attr: false, + }; +} + +#[derive(Copy, Debug, Clone)] +struct PendingAnonConstInfo { + id: NodeId, + span: Span, +} + +#[derive(Copy, Debug, Clone)] enum ImplTraitContext { Existential, Universal, @@ -203,7 +226,7 @@ struct BindingError { } #[derive(Debug)] -enum ResolutionError<'a> { +enum ResolutionError<'ra> { /// Error E0401: can't use type or const parameters from outer item. GenericParamsFromOuterItem(Res, HasGenericParams, DefKind), /// Error E0403: the name is already used for a type or const parameter in this generic @@ -216,7 +239,7 @@ enum ResolutionError<'a> { /// Error E0438: const is not a member of trait. ConstNotMemberOfTrait(Ident, String, Option<Symbol>), /// Error E0408: variable `{}` is not bound in all patterns. - VariableNotBoundInPattern(BindingError, ParentScope<'a>), + VariableNotBoundInPattern(BindingError, ParentScope<'ra>), /// Error E0409: variable `{}` is bound in inconsistent ways within the same match arm. VariableBoundWithDifferentMode(Symbol, Span), /// Error E0415: identifier is bound more than once in this parameter list. @@ -236,7 +259,7 @@ enum ResolutionError<'a> { segment: Option<Symbol>, label: String, suggestion: Option<Suggestion>, - module: Option<ModuleOrUniformRoot<'a>>, + module: Option<ModuleOrUniformRoot<'ra>>, }, /// Error E0434: can't capture dynamic environment in a fn item. CannotCaptureDynamicEnvironmentInFnItem, @@ -377,12 +400,12 @@ impl<'a> From<&'a ast::PathSegment> for Segment { /// items are visible in their whole block, while `Res`es only from the place they are defined /// forward. #[derive(Debug, Copy, Clone)] -enum LexicalScopeBinding<'a> { - Item(NameBinding<'a>), +enum LexicalScopeBinding<'ra> { + Item(NameBinding<'ra>), Res(Res), } -impl<'a> LexicalScopeBinding<'a> { +impl<'ra> LexicalScopeBinding<'ra> { fn res(self) -> Res { match self { LexicalScopeBinding::Item(binding) => binding.res(), @@ -392,9 +415,9 @@ impl<'a> LexicalScopeBinding<'a> { } #[derive(Copy, Clone, PartialEq, Debug)] -enum ModuleOrUniformRoot<'a> { +enum ModuleOrUniformRoot<'ra> { /// Regular module. - Module(Module<'a>), + Module(Module<'ra>), /// Virtual module that denotes resolution in crate root with fallback to extern prelude. CrateRootAndExternPrelude, @@ -410,8 +433,8 @@ enum ModuleOrUniformRoot<'a> { } #[derive(Debug)] -enum PathResult<'a> { - Module(ModuleOrUniformRoot<'a>), +enum PathResult<'ra> { + Module(ModuleOrUniformRoot<'ra>), NonModule(PartialRes), Indeterminate, Failed { @@ -432,20 +455,20 @@ enum PathResult<'a> { /// ``` /// /// In this case, `module` will point to `a`. - module: Option<ModuleOrUniformRoot<'a>>, + module: Option<ModuleOrUniformRoot<'ra>>, /// The segment name of target segment_name: Symbol, }, } -impl<'a> PathResult<'a> { +impl<'ra> PathResult<'ra> { fn failed( ident: Ident, is_error_from_last_segment: bool, finalize: bool, - module: Option<ModuleOrUniformRoot<'a>>, + module: Option<ModuleOrUniformRoot<'ra>>, label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>), - ) -> PathResult<'a> { + ) -> PathResult<'ra> { let (label, suggestion) = if finalize { label_and_suggestion() } else { (String::new(), None) }; PathResult::Failed { @@ -518,7 +541,7 @@ impl BindingKey { } } -type Resolutions<'a> = RefCell<FxIndexMap<BindingKey, &'a RefCell<NameResolution<'a>>>>; +type Resolutions<'ra> = RefCell<FxIndexMap<BindingKey, &'ra RefCell<NameResolution<'ra>>>>; /// One node in the tree of modules. /// @@ -531,15 +554,15 @@ type Resolutions<'a> = RefCell<FxIndexMap<BindingKey, &'a RefCell<NameResolution /// * curly-braced block with statements /// /// You can use [`ModuleData::kind`] to determine the kind of module this is. -struct ModuleData<'a> { +struct ModuleData<'ra> { /// The direct parent module (it may not be a `mod`, however). - parent: Option<Module<'a>>, + parent: Option<Module<'ra>>, /// What kind of module this is, because this may not be a `mod`. kind: ModuleKind, /// Mapping between names and their (possibly in-progress) resolutions in this module. /// Resolutions in modules from other crates are not populated until accessed. - lazy_resolutions: Resolutions<'a>, + lazy_resolutions: Resolutions<'ra>, /// True if this is a module from other crate that needs to be populated on access. populate_on_access: Cell<bool>, @@ -549,11 +572,11 @@ struct ModuleData<'a> { /// Whether `#[no_implicit_prelude]` is active. no_implicit_prelude: bool, - glob_importers: RefCell<Vec<Import<'a>>>, - globs: RefCell<Vec<Import<'a>>>, + glob_importers: RefCell<Vec<Import<'ra>>>, + globs: RefCell<Vec<Import<'ra>>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: RefCell<Option<Box<[(Ident, NameBinding<'a>)]>>>, + traits: RefCell<Option<Box<[(Ident, NameBinding<'ra>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -565,11 +588,11 @@ struct ModuleData<'a> { /// so we can use referential equality to compare them. #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[rustc_pass_by_value] -struct Module<'a>(Interned<'a, ModuleData<'a>>); +struct Module<'ra>(Interned<'ra, ModuleData<'ra>>); -impl<'a> ModuleData<'a> { +impl<'ra> ModuleData<'ra> { fn new( - parent: Option<Module<'a>>, + parent: Option<Module<'ra>>, kind: ModuleKind, expansion: ExpnId, span: Span, @@ -595,11 +618,11 @@ impl<'a> ModuleData<'a> { } } -impl<'a> Module<'a> { +impl<'ra> Module<'ra> { fn for_each_child<'tcx, R, F>(self, resolver: &mut R, mut f: F) where - R: AsMut<Resolver<'a, 'tcx>>, - F: FnMut(&mut R, Ident, Namespace, NameBinding<'a>), + R: AsMut<Resolver<'ra, 'tcx>>, + F: FnMut(&mut R, Ident, Namespace, NameBinding<'ra>), { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().binding { @@ -611,7 +634,7 @@ impl<'a> Module<'a> { /// This modifies `self` in place. The traits will be stored in `self.traits`. fn ensure_traits<'tcx, R>(self, resolver: &mut R) where - R: AsMut<Resolver<'a, 'tcx>>, + R: AsMut<Resolver<'ra, 'tcx>>, { let mut traits = self.traits.borrow_mut(); if traits.is_none() { @@ -656,7 +679,7 @@ impl<'a> Module<'a> { matches!(self.kind, ModuleKind::Def(DefKind::Trait, _, _)) } - fn nearest_item_scope(self) -> Module<'a> { + fn nearest_item_scope(self) -> Module<'ra> { match self.kind { ModuleKind::Def(DefKind::Enum | DefKind::Trait, ..) => { self.parent.expect("enum or trait module without a parent") @@ -686,15 +709,15 @@ impl<'a> Module<'a> { } } -impl<'a> std::ops::Deref for Module<'a> { - type Target = ModuleData<'a>; +impl<'ra> std::ops::Deref for Module<'ra> { + type Target = ModuleData<'ra>; fn deref(&self) -> &Self::Target { &self.0 } } -impl<'a> fmt::Debug for Module<'a> { +impl<'ra> fmt::Debug for Module<'ra> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.res()) } @@ -702,9 +725,9 @@ impl<'a> fmt::Debug for Module<'a> { /// Records a possibly-private value, type, or module definition. #[derive(Clone, Copy, Debug)] -struct NameBindingData<'a> { - kind: NameBindingKind<'a>, - ambiguity: Option<(NameBinding<'a>, AmbiguityKind)>, +struct NameBindingData<'ra> { + kind: NameBindingKind<'ra>, + ambiguity: Option<(NameBinding<'ra>, AmbiguityKind)>, /// Produce a warning instead of an error when reporting ambiguities inside this binding. /// May apply to indirect ambiguities under imports, so `ambiguity.is_some()` is not required. warn_ambiguity: bool, @@ -715,26 +738,26 @@ struct NameBindingData<'a> { /// All name bindings are unique and allocated on a same arena, /// so we can use referential equality to compare them. -type NameBinding<'a> = Interned<'a, NameBindingData<'a>>; +type NameBinding<'ra> = Interned<'ra, NameBindingData<'ra>>; -trait ToNameBinding<'a> { - fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> NameBinding<'a>; +trait ToNameBinding<'ra> { + fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra>; } -impl<'a> ToNameBinding<'a> for NameBinding<'a> { - fn to_name_binding(self, _: &'a ResolverArenas<'a>) -> NameBinding<'a> { +impl<'ra> ToNameBinding<'ra> for NameBinding<'ra> { + fn to_name_binding(self, _: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { self } } #[derive(Clone, Copy, Debug)] -enum NameBindingKind<'a> { +enum NameBindingKind<'ra> { Res(Res), - Module(Module<'a>), - Import { binding: NameBinding<'a>, import: Import<'a> }, + Module(Module<'ra>), + Import { binding: NameBinding<'ra>, import: Import<'ra> }, } -impl<'a> NameBindingKind<'a> { +impl<'ra> NameBindingKind<'ra> { /// Is this a name binding of an import? fn is_import(&self) -> bool { matches!(*self, NameBindingKind::Import { .. }) @@ -742,12 +765,12 @@ impl<'a> NameBindingKind<'a> { } #[derive(Debug)] -struct PrivacyError<'a> { +struct PrivacyError<'ra> { ident: Ident, - binding: NameBinding<'a>, + binding: NameBinding<'ra>, dedup_span: Span, outermost_res: Option<(Res, Ident)>, - parent_scope: ParentScope<'a>, + parent_scope: ParentScope<'ra>, /// Is the format `use a::{b,c}`? single_nested: bool, } @@ -812,18 +835,18 @@ enum AmbiguityErrorMisc { None, } -struct AmbiguityError<'a> { +struct AmbiguityError<'ra> { kind: AmbiguityKind, ident: Ident, - b1: NameBinding<'a>, - b2: NameBinding<'a>, + b1: NameBinding<'ra>, + b2: NameBinding<'ra>, misc1: AmbiguityErrorMisc, misc2: AmbiguityErrorMisc, warning: bool, } -impl<'a> NameBindingData<'a> { - fn module(&self) -> Option<Module<'a>> { +impl<'ra> NameBindingData<'ra> { + fn module(&self) -> Option<Module<'ra>> { match self.kind { NameBindingKind::Module(module) => Some(module), NameBindingKind::Import { binding, .. } => binding.module(), @@ -947,8 +970,8 @@ impl<'a> NameBindingData<'a> { } #[derive(Default, Clone)] -struct ExternPreludeEntry<'a> { - binding: Option<NameBinding<'a>>, +struct ExternPreludeEntry<'ra> { + binding: Option<NameBinding<'ra>>, introduced_by_item: bool, } @@ -985,16 +1008,16 @@ impl MacroData { /// The main resolver class. /// /// This is the visitor that walks the whole crate. -pub struct Resolver<'a, 'tcx> { +pub struct Resolver<'ra, 'tcx> { tcx: TyCtxt<'tcx>, /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. expn_that_defined: FxHashMap<LocalDefId, ExpnId>, - graph_root: Module<'a>, + graph_root: Module<'ra>, - prelude: Option<Module<'a>>, - extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'a>>, + prelude: Option<Module<'ra>>, + extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'ra>>, /// N.B., this is used only for better diagnostics, not name resolution itself. field_names: LocalDefIdMap<Vec<Ident>>, @@ -1004,10 +1027,10 @@ pub struct Resolver<'a, 'tcx> { field_visibility_spans: FxHashMap<DefId, Vec<Span>>, /// All imports known to succeed or fail. - determined_imports: Vec<Import<'a>>, + determined_imports: Vec<Import<'ra>>, /// All non-determined imports. - indeterminate_imports: Vec<Import<'a>>, + indeterminate_imports: Vec<Import<'ra>>, // Spans for local variables found during pattern resolution. // Used for suggestions during error reporting. @@ -1018,7 +1041,7 @@ pub struct Resolver<'a, 'tcx> { /// Resolutions for import nodes, which have multiple resolutions in different namespaces. import_res_map: NodeMap<PerNS<Option<Res>>>, /// An import will be inserted into this map if it has been used. - import_use_map: FxHashMap<Import<'a>, Used>, + import_use_map: FxHashMap<Import<'ra>, Used>, /// Resolutions for labels (node IDs of their corresponding blocks or loops). label_res_map: NodeMap<NodeId>, /// Resolutions for lifetimes. @@ -1045,13 +1068,13 @@ pub struct Resolver<'a, 'tcx> { /// /// There will be an anonymous module created around `g` with the ID of the /// entry block for `f`. - block_map: NodeMap<Module<'a>>, + block_map: NodeMap<Module<'ra>>, /// A fake module that contains no definition and no prelude. Used so that /// some AST passes can generate identifiers that only resolve to local or /// lang items. - empty_module: Module<'a>, - module_map: FxHashMap<DefId, Module<'a>>, - binding_parent_modules: FxHashMap<NameBinding<'a>, Module<'a>>, + empty_module: Module<'ra>, + module_map: FxHashMap<DefId, Module<'ra>>, + binding_parent_modules: FxHashMap<NameBinding<'ra>, Module<'ra>>, underscore_disambiguator: u32, /// Disambiguator for anonymous adts. @@ -1065,57 +1088,57 @@ pub struct Resolver<'a, 'tcx> { maybe_unused_trait_imports: FxIndexSet<LocalDefId>, /// Privacy errors are delayed until the end in order to deduplicate them. - privacy_errors: Vec<PrivacyError<'a>>, + privacy_errors: Vec<PrivacyError<'ra>>, /// Ambiguity errors are delayed for deduplication. - ambiguity_errors: Vec<AmbiguityError<'a>>, + ambiguity_errors: Vec<AmbiguityError<'ra>>, /// `use` injections are delayed for better placement and deduplication. use_injections: Vec<UseError<'tcx>>, /// Crate-local macro expanded `macro_export` referred to by a module-relative path. macro_expanded_macro_export_errors: BTreeSet<(Span, Span)>, - arenas: &'a ResolverArenas<'a>, - dummy_binding: NameBinding<'a>, - builtin_types_bindings: FxHashMap<Symbol, NameBinding<'a>>, - builtin_attrs_bindings: FxHashMap<Symbol, NameBinding<'a>>, - registered_tool_bindings: FxHashMap<Ident, NameBinding<'a>>, + arenas: &'ra ResolverArenas<'ra>, + dummy_binding: NameBinding<'ra>, + builtin_types_bindings: FxHashMap<Symbol, NameBinding<'ra>>, + builtin_attrs_bindings: FxHashMap<Symbol, NameBinding<'ra>>, + registered_tool_bindings: FxHashMap<Ident, NameBinding<'ra>>, /// Binding for implicitly declared names that come with a module, /// like `self` (not yet used), or `crate`/`$crate` (for root modules). - module_self_bindings: FxHashMap<Module<'a>, NameBinding<'a>>, + module_self_bindings: FxHashMap<Module<'ra>, NameBinding<'ra>>, used_extern_options: FxHashSet<Symbol>, macro_names: FxHashSet<Ident>, builtin_macros: FxHashMap<Symbol, BuiltinMacroState>, registered_tools: &'tcx RegisteredTools, - macro_use_prelude: FxHashMap<Symbol, NameBinding<'a>>, + macro_use_prelude: FxHashMap<Symbol, NameBinding<'ra>>, macro_map: FxHashMap<DefId, MacroData>, dummy_ext_bang: Lrc<SyntaxExtension>, dummy_ext_derive: Lrc<SyntaxExtension>, non_macro_attr: MacroData, - local_macro_def_scopes: FxHashMap<LocalDefId, Module<'a>>, - ast_transform_scopes: FxHashMap<LocalExpnId, Module<'a>>, + local_macro_def_scopes: FxHashMap<LocalDefId, Module<'ra>>, + ast_transform_scopes: FxHashMap<LocalExpnId, Module<'ra>>, unused_macros: FxHashMap<LocalDefId, (NodeId, Ident)>, unused_macro_rules: FxHashMap<(LocalDefId, usize), (Ident, Span)>, proc_macro_stubs: FxHashSet<LocalDefId>, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: - Vec<(Ident, MacroKind, ParentScope<'a>, Option<NameBinding<'a>>)>, + Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>)>, multi_segment_macro_resolutions: - Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>, Option<Res>, Namespace)>, - builtin_attrs: Vec<(Ident, ParentScope<'a>)>, + Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>, + builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, /// `derive(Copy)` marks items they are applied to so they are treated specially later. /// Derive macros cannot modify the item themselves and have to store the markers in the global /// context, so they attach the markers to derive container IDs using this resolver table. containers_deriving_copy: FxHashSet<LocalExpnId>, /// Parent scopes in which the macros were invoked. /// FIXME: `derives` are missing in these parent scopes and need to be taken from elsewhere. - invocation_parent_scopes: FxHashMap<LocalExpnId, ParentScope<'a>>, + invocation_parent_scopes: FxHashMap<LocalExpnId, ParentScope<'ra>>, /// `macro_rules` scopes *produced* by expanding the macro invocations, /// include all the `macro_rules` items and other invocations generated by them. - output_macro_rules_scopes: FxHashMap<LocalExpnId, MacroRulesScopeRef<'a>>, + output_macro_rules_scopes: FxHashMap<LocalExpnId, MacroRulesScopeRef<'ra>>, /// `macro_rules` scopes produced by `macro_rules` item definitions. - macro_rules_scopes: FxHashMap<LocalDefId, MacroRulesScopeRef<'a>>, + macro_rules_scopes: FxHashMap<LocalDefId, MacroRulesScopeRef<'ra>>, /// Helper attributes that are in scope for the given expansion. - helper_attrs: FxHashMap<LocalExpnId, Vec<(Ident, NameBinding<'a>)>>, + helper_attrs: FxHashMap<LocalExpnId, Vec<(Ident, NameBinding<'ra>)>>, /// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute /// with the given `ExpnId`. derive_data: FxHashMap<LocalExpnId, DeriveData>, @@ -1123,9 +1146,9 @@ pub struct Resolver<'a, 'tcx> { /// Avoid duplicated errors for "name already defined". name_already_seen: FxHashMap<Symbol, Span>, - potentially_unused_imports: Vec<Import<'a>>, + potentially_unused_imports: Vec<Import<'ra>>, - potentially_unnecessary_qualifications: Vec<UnnecessaryQualification<'a>>, + potentially_unnecessary_qualifications: Vec<UnnecessaryQualification<'ra>>, /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. @@ -1144,7 +1167,7 @@ pub struct Resolver<'a, 'tcx> { /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId` /// we know what parent node that fragment should be attached to thanks to this table, /// and how the `impl Trait` fragments were introduced. - invocation_parents: FxHashMap<LocalExpnId, (LocalDefId, ImplTraitContext, bool /*in_attr*/)>, + invocation_parents: FxHashMap<LocalExpnId, InvocationParent>, /// Some way to know that we are in a *trait* impl in `visit_assoc_item`. /// FIXME: Replace with a more general AST map (together with some other fields). @@ -1186,28 +1209,29 @@ pub struct Resolver<'a, 'tcx> { current_crate_outer_attr_insert_span: Span, } -/// Nothing really interesting here; it just provides memory for the rest of the crate. +/// This provides memory for the rest of the crate. The `'ra` lifetime that is +/// used by many types in this crate is an abbreviation of `ResolverArenas`. #[derive(Default)] -pub struct ResolverArenas<'a> { - modules: TypedArena<ModuleData<'a>>, - local_modules: RefCell<Vec<Module<'a>>>, - imports: TypedArena<ImportData<'a>>, - name_resolutions: TypedArena<RefCell<NameResolution<'a>>>, +pub struct ResolverArenas<'ra> { + modules: TypedArena<ModuleData<'ra>>, + local_modules: RefCell<Vec<Module<'ra>>>, + imports: TypedArena<ImportData<'ra>>, + name_resolutions: TypedArena<RefCell<NameResolution<'ra>>>, ast_paths: TypedArena<ast::Path>, dropless: DroplessArena, } -impl<'a> ResolverArenas<'a> { +impl<'ra> ResolverArenas<'ra> { fn new_module( - &'a self, - parent: Option<Module<'a>>, + &'ra self, + parent: Option<Module<'ra>>, kind: ModuleKind, expn_id: ExpnId, span: Span, no_implicit_prelude: bool, - module_map: &mut FxHashMap<DefId, Module<'a>>, - module_self_bindings: &mut FxHashMap<Module<'a>, NameBinding<'a>>, - ) -> Module<'a> { + module_map: &mut FxHashMap<DefId, Module<'ra>>, + module_self_bindings: &mut FxHashMap<Module<'ra>, NameBinding<'ra>>, + ) -> Module<'ra> { let module = Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new( parent, kind, @@ -1227,37 +1251,37 @@ impl<'a> ResolverArenas<'a> { } module } - fn local_modules(&'a self) -> std::cell::Ref<'a, Vec<Module<'a>>> { + fn local_modules(&'ra self) -> std::cell::Ref<'ra, Vec<Module<'ra>>> { self.local_modules.borrow() } - fn alloc_name_binding(&'a self, name_binding: NameBindingData<'a>) -> NameBinding<'a> { + fn alloc_name_binding(&'ra self, name_binding: NameBindingData<'ra>) -> NameBinding<'ra> { Interned::new_unchecked(self.dropless.alloc(name_binding)) } - fn alloc_import(&'a self, import: ImportData<'a>) -> Import<'a> { + fn alloc_import(&'ra self, import: ImportData<'ra>) -> Import<'ra> { Interned::new_unchecked(self.imports.alloc(import)) } - fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> { + fn alloc_name_resolution(&'ra self) -> &'ra RefCell<NameResolution<'ra>> { self.name_resolutions.alloc(Default::default()) } - fn alloc_macro_rules_scope(&'a self, scope: MacroRulesScope<'a>) -> MacroRulesScopeRef<'a> { + fn alloc_macro_rules_scope(&'ra self, scope: MacroRulesScope<'ra>) -> MacroRulesScopeRef<'ra> { Interned::new_unchecked(self.dropless.alloc(Cell::new(scope))) } fn alloc_macro_rules_binding( - &'a self, - binding: MacroRulesBinding<'a>, - ) -> &'a MacroRulesBinding<'a> { + &'ra self, + binding: MacroRulesBinding<'ra>, + ) -> &'ra MacroRulesBinding<'ra> { self.dropless.alloc(binding) } - fn alloc_ast_paths(&'a self, paths: &[ast::Path]) -> &'a [ast::Path] { + fn alloc_ast_paths(&'ra self, paths: &[ast::Path]) -> &'ra [ast::Path] { self.ast_paths.alloc_from_iter(paths.iter().cloned()) } - fn alloc_pattern_spans(&'a self, spans: impl Iterator<Item = Span>) -> &'a [Span] { + fn alloc_pattern_spans(&'ra self, spans: impl Iterator<Item = Span>) -> &'ra [Span] { self.dropless.alloc_from_iter(spans) } } -impl<'a, 'tcx> AsMut<Resolver<'a, 'tcx>> for Resolver<'a, 'tcx> { - fn as_mut(&mut self) -> &mut Resolver<'a, 'tcx> { +impl<'ra, 'tcx> AsMut<Resolver<'ra, 'tcx>> for Resolver<'ra, 'tcx> { + fn as_mut(&mut self) -> &mut Resolver<'ra, 'tcx> { self } } @@ -1341,14 +1365,14 @@ impl<'tcx> Resolver<'_, 'tcx> { } } -impl<'a, 'tcx> Resolver<'a, 'tcx> { +impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub fn new( tcx: TyCtxt<'tcx>, attrs: &[ast::Attribute], crate_span: Span, current_crate_outer_attr_insert_span: Span, - arenas: &'a ResolverArenas<'a>, - ) -> Resolver<'a, 'tcx> { + arenas: &'ra ResolverArenas<'ra>, + ) -> Resolver<'ra, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); let mut module_map = FxHashMap::default(); let mut module_self_bindings = FxHashMap::default(); @@ -1381,8 +1405,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { node_id_to_def_id.insert(CRATE_NODE_ID, crate_feed); let mut invocation_parents = FxHashMap::default(); - invocation_parents - .insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential, false)); + invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT); let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = tcx .sess @@ -1541,12 +1564,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn new_module( &mut self, - parent: Option<Module<'a>>, + parent: Option<Module<'ra>>, kind: ModuleKind, expn_id: ExpnId, span: Span, no_implicit_prelude: bool, - ) -> Module<'a> { + ) -> Module<'ra> { let module_map = &mut self.module_map; let module_self_bindings = &mut self.module_self_bindings; self.arenas.new_module( @@ -1578,7 +1601,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self.lint_buffer } - pub fn arenas() -> ResolverArenas<'a> { + pub fn arenas() -> ResolverArenas<'ra> { Default::default() } @@ -1719,8 +1742,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn traits_in_scope( &mut self, - current_trait: Option<Module<'a>>, - parent_scope: &ParentScope<'a>, + current_trait: Option<Module<'ra>>, + parent_scope: &ParentScope<'ra>, ctxt: SyntaxContext, assoc_item: Option<(Symbol, Namespace)>, ) -> Vec<TraitCandidate> { @@ -1754,7 +1777,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn traits_in_module( &mut self, - module: Module<'a>, + module: Module<'ra>, assoc_item: Option<(Symbol, Namespace)>, found_traits: &mut Vec<TraitCandidate>, ) { @@ -1776,7 +1799,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // associated items. fn trait_may_have_item( &mut self, - trait_module: Option<Module<'a>>, + trait_module: Option<Module<'ra>>, assoc_item: Option<(Symbol, Namespace)>, ) -> bool { match (trait_module, assoc_item) { @@ -1822,7 +1845,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { BindingKey { ident, ns, disambiguator } } - fn resolutions(&mut self, module: Module<'a>) -> &'a Resolutions<'a> { + fn resolutions(&mut self, module: Module<'ra>) -> &'ra Resolutions<'ra> { if module.populate_on_access.get() { module.populate_on_access.set(false); self.build_reduced_graph_external(module); @@ -1832,9 +1855,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn resolution( &mut self, - module: Module<'a>, + module: Module<'ra>, key: BindingKey, - ) -> &'a RefCell<NameResolution<'a>> { + ) -> &'ra RefCell<NameResolution<'ra>> { *self .resolutions(module) .borrow_mut() @@ -1860,14 +1883,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { false } - fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, used: Used) { + fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'ra>, used: Used) { self.record_use_inner(ident, used_binding, used, used_binding.warn_ambiguity); } fn record_use_inner( &mut self, ident: Ident, - used_binding: NameBinding<'a>, + used_binding: NameBinding<'ra>, used: Used, warn_ambiguity: bool, ) { @@ -1929,7 +1952,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn resolve_crate_root(&mut self, ident: Ident) -> Module<'a> { + fn resolve_crate_root(&mut self, ident: Ident) -> Module<'ra> { debug!("resolve_crate_root({:?})", ident); let mut ctxt = ident.span.ctxt(); let mark = if ident.name == kw::DollarCrate { @@ -2002,7 +2025,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { module } - fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Module<'a> { + fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'ra>) -> Module<'ra> { let mut module = self.expect_module(module.nearest_parent_mod()); while module.span.ctxt().normalize_to_macros_2_0() != *ctxt { let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark())); @@ -2026,12 +2049,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn is_accessible_from( &self, vis: ty::Visibility<impl Into<DefId>>, - module: Module<'a>, + module: Module<'ra>, ) -> bool { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } - fn set_binding_parent_module(&mut self, binding: NameBinding<'a>, module: Module<'a>) { + fn set_binding_parent_module(&mut self, binding: NameBinding<'ra>, module: Module<'ra>) { if let Some(old_module) = self.binding_parent_modules.insert(binding, module) { if module != old_module { span_bug!(binding.span, "parent module is reset for binding"); @@ -2041,8 +2064,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn disambiguate_macro_rules_vs_modularized( &self, - macro_rules: NameBinding<'a>, - modularized: NameBinding<'a>, + macro_rules: NameBinding<'ra>, + modularized: NameBinding<'ra>, ) -> bool { // Some non-controversial subset of ambiguities "modularized macro name" vs "macro_rules" // is disambiguated to mitigate regressions from macro modularization. @@ -2059,7 +2082,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBinding<'a>> { + fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> { if ident.is_path_segment_keyword() { // Make sure `self`, `super` etc produce an error when passed to here. return None; @@ -2108,7 +2131,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, path_str: &str, ns: Namespace, - parent_scope: ParentScope<'a>, + parent_scope: ParentScope<'ra>, ) -> Option<Res> { let mut segments = Vec::from_iter(path_str.split("::").map(Ident::from_str).map(Segment::from_ident)); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 7203fbe4a0c..b4f277c4244 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -42,9 +42,9 @@ use crate::errors::{ use crate::imports::Import; use crate::Namespace::*; use crate::{ - BindingKey, BuiltinMacroState, DeriveData, Determinacy, Finalize, MacroData, ModuleKind, - ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, ScopeSet, Segment, ToNameBinding, Used, + BindingKey, BuiltinMacroState, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, + ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, + ResolutionError, Resolver, ScopeSet, Segment, ToNameBinding, Used, }; type Res = def::Res<NodeId>; @@ -52,10 +52,10 @@ type Res = def::Res<NodeId>; /// Binding produced by a `macro_rules` item. /// Not modularized, can shadow previous `macro_rules` bindings, etc. #[derive(Debug)] -pub(crate) struct MacroRulesBinding<'a> { - pub(crate) binding: NameBinding<'a>, +pub(crate) struct MacroRulesBinding<'ra> { + pub(crate) binding: NameBinding<'ra>, /// `macro_rules` scope into which the `macro_rules` item was planted. - pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'a>, + pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'ra>, pub(crate) ident: Ident, } @@ -65,11 +65,11 @@ pub(crate) struct MacroRulesBinding<'a> { /// Some macro invocations need to introduce `macro_rules` scopes too because they /// can potentially expand into macro definitions. #[derive(Copy, Clone, Debug)] -pub(crate) enum MacroRulesScope<'a> { +pub(crate) enum MacroRulesScope<'ra> { /// Empty "root" scope at the crate start containing no names. Empty, /// The scope introduced by a `macro_rules!` macro definition. - Binding(&'a MacroRulesBinding<'a>), + Binding(&'ra MacroRulesBinding<'ra>), /// The scope introduced by a macro invocation that can potentially /// create a `macro_rules!` macro definition. Invocation(LocalExpnId), @@ -81,7 +81,7 @@ pub(crate) enum MacroRulesScope<'a> { /// This helps to avoid uncontrollable growth of `macro_rules!` scope chains, /// which usually grow linearly with the number of macro invocations /// in a module (including derives) and hurt performance. -pub(crate) type MacroRulesScopeRef<'a> = Interned<'a, Cell<MacroRulesScope<'a>>>; +pub(crate) type MacroRulesScopeRef<'ra> = Interned<'ra, Cell<MacroRulesScope<'ra>>>; /// Macro namespace is separated into two sub-namespaces, one for bang macros and /// one for attribute-like macros (attributes, derives). @@ -177,13 +177,13 @@ fn soft_custom_inner_attributes_gate(path: &ast::Path, invoc: &Invocation) -> bo false } -impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { +impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { fn next_node_id(&mut self) -> NodeId { self.next_node_id() } fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId { - self.invocation_parents[&id].0 + self.invocation_parents[&id].parent_def } fn resolve_dollar_crates(&mut self) { @@ -303,12 +303,12 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { .invocation_parents .get(&invoc_id) .or_else(|| self.invocation_parents.get(&eager_expansion_root)) - .filter(|&&(mod_def_id, _, in_attr)| { + .filter(|&&InvocationParent { parent_def: mod_def_id, in_attr, .. }| { in_attr && invoc.fragment_kind == AstFragmentKind::Expr && self.tcx.def_kind(mod_def_id) == DefKind::Mod }) - .map(|&(mod_def_id, ..)| mod_def_id); + .map(|&InvocationParent { parent_def: mod_def_id, .. }| mod_def_id); let (ext, res) = self.smart_resolve_macro_path( path, kind, @@ -528,7 +528,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { } } -impl<'a, 'tcx> Resolver<'a, 'tcx> { +impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Resolve macro path with error reporting and recovery. /// Uses dummy syntax extensions for unresolved macros or macros with unexpected resolutions /// for better error recovery. @@ -538,7 +538,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { kind: MacroKind, supports_macro_expansion: SupportsMacroExpansion, inner_attr: bool, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, node_id: NodeId, force: bool, soft_custom_inner_attributes_gate: bool, @@ -704,10 +704,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, path: &ast::Path, kind: Option<MacroKind>, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, trace: bool, force: bool, - ignore_import: Option<Import<'a>>, + ignore_import: Option<Import<'ra>>, ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> { self.resolve_macro_or_delegation_path( path, @@ -725,12 +725,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &mut self, ast_path: &ast::Path, kind: Option<MacroKind>, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, trace: bool, force: bool, deleg_impl: Option<LocalDefId>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, - ignore_import: Option<Import<'a>>, + ignore_import: Option<Import<'ra>>, ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> { let path_span = ast_path.span; let mut path = Segment::from_path(ast_path); @@ -951,7 +951,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let node_id = self .invocation_parents .get(&parent_scope.expansion) - .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]); + .map_or(ast::CRATE_NODE_ID, |parent| { + self.def_id_to_node_id[parent.parent_def] + }); self.lint_buffer.buffer_lint( LEGACY_DERIVE_HELPERS, node_id, @@ -1045,7 +1047,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn prohibit_imported_non_macro_attrs( &self, - binding: Option<NameBinding<'a>>, + binding: Option<NameBinding<'ra>>, res: Option<Res>, span: Span, ) { @@ -1065,9 +1067,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn report_out_of_scope_macro_calls( &mut self, path: &ast::Path, - parent_scope: &ParentScope<'a>, + parent_scope: &ParentScope<'ra>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, - binding: Option<NameBinding<'a>>, + binding: Option<NameBinding<'ra>>, ) { if let Some((mod_def_id, node_id)) = invoc_in_mod_inert_attr && let Some(binding) = binding diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 976c4acb212..bed3baa30fb 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -270,12 +270,10 @@ fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, Malfor // Give a helpful error message instead of completely ignoring the angle brackets. return Err(MalformedGenerics::HasFullyQualifiedSyntax); } + } else if param_depth == 0 { + stripped_segment.push(c); } else { - if param_depth == 0 { - stripped_segment.push(c); - } else { - latest_generics_chunk.push(c); - } + latest_generics_chunk.push(c); } } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 45057a3530c..a0a0dd058ff 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -207,14 +207,12 @@ fn encode_fnsig<'tcx>( if fn_sig.c_variadic { s.push('z'); } + } else if fn_sig.c_variadic { + s.push('z'); } else { - if fn_sig.c_variadic { - s.push('z'); - } else { - // Empty parameter lists, whether declared as () or conventionally as (void), are - // encoded with a void parameter specifier "v". - s.push('v') - } + // Empty parameter lists, whether declared as () or conventionally as (void), are + // encoded with a void parameter specifier "v". + s.push('v') } // Close the "F..E" pair diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 01c371ee498..a4fbab8477b 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -113,6 +113,8 @@ session_split_lto_unit_requires_lto = `-Zsplit-lto-unit` requires `-Clto`, `-Clt session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no` +session_target_small_data_threshold_not_supported = `-Z small-data-threshold` is not supported for target {$target_triple} and will be ignored + session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored session_unleashed_feature_help_named = skipping check for `{$gate}` feature diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f3e3b36111c..908d50a041e 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -842,11 +842,6 @@ pub struct NextSolverConfig { /// This is only `true` if `coherence` is also enabled. pub globally: bool, } -impl Default for NextSolverConfig { - fn default() -> Self { - NextSolverConfig { coherence: true, globally: false } - } -} #[derive(Clone)] pub enum Input { diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 15bbd4ff7bf..462e2a97c33 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -183,6 +183,12 @@ pub(crate) struct StackProtectorNotSupportedForTarget<'a> { } #[derive(Diagnostic)] +#[diag(session_target_small_data_threshold_not_supported)] +pub(crate) struct SmallDataThresholdNotSupportedForTarget<'a> { + pub(crate) target_triple: &'a TargetTriple, +} + +#[derive(Diagnostic)] #[diag(session_branch_protection_requires_aarch64)] pub(crate) struct BranchProtectionRequiresAArch64; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 982a3d5cf11..e487a2501e3 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -403,7 +403,7 @@ mod desc { pub(crate) const parse_unpretty: &str = "`string` or `string=string`"; pub(crate) const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; pub(crate) const parse_next_solver_config: &str = - "either `globally` (when used without an argument), `coherence` (default) or `no`"; + "a comma separated list of solver configurations: `globally` (default), and `coherence`"; pub(crate) const parse_lto: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted"; pub(crate) const parse_linker_plugin_lto: &str = @@ -1105,16 +1105,27 @@ mod parse { } } - pub(crate) fn parse_next_solver_config(slot: &mut NextSolverConfig, v: Option<&str>) -> bool { + pub(crate) fn parse_next_solver_config( + slot: &mut Option<NextSolverConfig>, + v: Option<&str>, + ) -> bool { if let Some(config) = v { - *slot = match config { - "no" => NextSolverConfig { coherence: false, globally: false }, - "coherence" => NextSolverConfig { coherence: true, globally: false }, - "globally" => NextSolverConfig { coherence: true, globally: true }, - _ => return false, - }; + let mut coherence = false; + let mut globally = true; + for c in config.split(',') { + match c { + "globally" => globally = true, + "coherence" => { + globally = false; + coherence = true; + } + _ => return false, + } + } + + *slot = Some(NextSolverConfig { coherence: coherence || globally, globally }); } else { - *slot = NextSolverConfig { coherence: true, globally: true }; + *slot = Some(NextSolverConfig { coherence: true, globally: true }); } true @@ -1867,7 +1878,7 @@ options! { "the size at which the `large_assignments` lint starts to be emitted"), mutable_noalias: bool = (true, parse_bool, [TRACKED], "emit noalias metadata for mutable references (default: yes)"), - next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED], + next_solver: Option<NextSolverConfig> = (None, parse_next_solver_config, [TRACKED], "enable and configure the next generation trait solver used by rustc"), nll_facts: bool = (false, parse_bool, [UNTRACKED], "dump facts from NLL analysis into side files (default: no)"), @@ -2014,6 +2025,8 @@ written to standard error output)"), simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \ to rust's source base directory. only meant for testing purposes"), + small_data_threshold: Option<usize> = (None, parse_opt_number, [TRACKED], + "Set the threshold for objects to be stored in a \"small data\" section"), span_debug: bool = (false, parse_bool, [UNTRACKED], "forward proc_macro::Span's `Debug` impl to `Span`"), /// o/w tests have closure@path diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index d6c58e9d1be..1db31f5b0a7 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -340,4 +340,8 @@ impl ParseSess { pub fn dcx(&self) -> DiagCtxtHandle<'_> { self.dcx.handle() } + + pub fn set_dcx(&mut self, dcx: DiagCtxt) { + self.dcx = dcx; + } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 70430d82ab5..387ae1b78c4 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -30,8 +30,8 @@ use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{FileNameDisplayPreference, RealFileName, Span, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{ - CodeModel, DebuginfoKind, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, - StackProtector, Target, TargetTriple, TlsModel, + CodeModel, DebuginfoKind, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, + SmallDataThresholdSupport, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel, }; use crate::code_stats::CodeStats; @@ -1278,6 +1278,14 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } + if sess.opts.unstable_opts.small_data_threshold.is_some() { + if sess.target.small_data_threshold_support() == SmallDataThresholdSupport::None { + sess.dcx().emit_warn(errors::SmallDataThresholdNotSupportedForTarget { + target_triple: &sess.opts.target_triple, + }) + } + } + if sess.opts.unstable_opts.branch_protection.is_some() && sess.target.arch != "aarch64" { sess.dcx().emit_err(errors::BranchProtectionRequiresAArch64); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 28d18f2dfcc..cbe2bafef21 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -599,7 +599,6 @@ symbols! { conservative_impl_trait, console, const_allocate, - const_arg_path, const_async_blocks, const_closures, const_compare_raw_pointers, @@ -1017,6 +1016,7 @@ symbols! { ident, if_let, if_let_guard, + if_let_rescope, if_while_or_patterns, ignore, impl_header_lifetime_elision, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 75f4499352b..ba35a37c32c 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -381,7 +381,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { let consts = [ start.unwrap_or(self.tcx.consts.unit), end.unwrap_or(self.tcx.consts.unit), - ty::Const::from_bool(self.tcx, include_end).into(), + ty::Const::from_bool(self.tcx, include_end), ]; // HACK: Represent as tuple until we have something better. // HACK: constants are used in arrays, even if the types don't match. diff --git a/compiler/rustc_target/src/abi/call/xtensa.rs b/compiler/rustc_target/src/abi/call/xtensa.rs index cb61bf2c56b..d7b5fe9d4cc 100644 --- a/compiler/rustc_target/src/abi/call/xtensa.rs +++ b/compiler/rustc_target/src/abi/call/xtensa.rs @@ -69,29 +69,27 @@ where if must_use_stack { arg.make_indirect_byval(None); - } else { - if is_xtensa_aggregate(arg) { - // Aggregates which are <= max_size will be passed in - // registers if possible, so coerce to integers. + } else if is_xtensa_aggregate(arg) { + // Aggregates which are <= max_size will be passed in + // registers if possible, so coerce to integers. - // Use a single `xlen` int if possible, 2 * `xlen` if 2 * `xlen` alignment - // is required, and a 2-element `xlen` array if only `xlen` alignment is - // required. - if size <= 32 { - arg.cast_to(Reg::i32()); - } else { - let reg = if needed_align == 2 * 32 { Reg::i64() } else { Reg::i32() }; - let total = Size::from_bits(((size + 32 - 1) / 32) * 32); - arg.cast_to(Uniform::new(reg, total)); - } + // Use a single `xlen` int if possible, 2 * `xlen` if 2 * `xlen` alignment + // is required, and a 2-element `xlen` array if only `xlen` alignment is + // required. + if size <= 32 { + arg.cast_to(Reg::i32()); } else { - // All integral types are promoted to `xlen` - // width. - // - // We let the LLVM backend handle integral types >= xlen. - if size < 32 { - arg.extend_integer_width_to(32); - } + let reg = if needed_align == 2 * 32 { Reg::i64() } else { Reg::i32() }; + let total = Size::from_bits(((size + 32 - 1) / 32) * 32); + arg.cast_to(Uniform::new(reg, total)); + } + } else { + // All integral types are promoted to `xlen` + // width. + // + // We let the LLVM backend handle integral types >= xlen. + if size < 32 { + arg.extend_integer_width_to(32); } } } diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index b1fe49f76ca..e78e3222115 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -168,7 +168,26 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs { ["-platform_version".into(), platform_name, min_version, sdk_version].into_iter(), ); - if abi != TargetAbi::MacCatalyst { + // We need to communicate four things to the C compiler to be able to link: + // - The architecture. + // - The operating system (and that it's an Apple platform). + // - The deployment target. + // - The environment / ABI. + // + // We'd like to use `-target` everywhere, since that can uniquely + // communicate all of these, but that doesn't work on GCC, and since we + // don't know whether the `cc` compiler is Clang, GCC, or something else, + // we fall back to other options that also work on GCC when compiling for + // macOS. + // + // Targets other than macOS are ill-supported by GCC (it doesn't even + // support e.g. `-miphoneos-version-min`), so in those cases we can fairly + // safely use `-target`. See also the following, where it is made explicit + // that the recommendation by LLVM developers is to use `-target`: + // <https://github.com/llvm/llvm-project/issues/88271> + if os == "macos" { + // `-arch` communicates the architecture. + // // CC forwards the `-arch` to the linker, so we use the same value // here intentionally. add_link_args( @@ -176,6 +195,15 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs { LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-arch", arch.ld_arch()], ); + // The presence of `-mmacosx-version-min` makes CC default to macOS, + // and it sets the deployment target. + let (major, minor, patch) = deployment_target(os, arch, abi); + let opt = format!("-mmacosx-version-min={major}.{minor}.{patch}").into(); + add_link_args_iter(&mut args, LinkerFlavor::Darwin(Cc::Yes, Lld::No), [opt].into_iter()); + // macOS has no environment, so with these two, we've told CC all the + // desired parameters. + // + // We avoid `-m32`/`-m64`, as this is already encoded by `-arch`. } else { add_link_args_iter( &mut args, @@ -323,12 +351,18 @@ fn deployment_target(os: &str, arch: Arch, abi: TargetAbi) -> (u16, u8, u8) { }; // On certain targets it makes sense to raise the minimum OS version. + // + // This matches what LLVM does, see: + // <https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L1900-L1932> let min = match (os, arch, abi) { - // Use 11.0 on Aarch64 as that's the earliest version with M1 support. ("macos", Arch::Arm64 | Arch::Arm64e, _) => (11, 0, 0), - ("ios", Arch::Arm64e, _) => (14, 0, 0), + ("ios", Arch::Arm64 | Arch::Arm64e, TargetAbi::MacCatalyst) => (14, 0, 0), + ("ios", Arch::Arm64 | Arch::Arm64e, TargetAbi::Simulator) => (14, 0, 0), + ("ios", Arch::Arm64e, TargetAbi::Normal) => (14, 0, 0), // Mac Catalyst defaults to 13.1 in Clang. ("ios", _, TargetAbi::MacCatalyst) => (13, 1, 0), + ("tvos", Arch::Arm64 | Arch::Arm64e, TargetAbi::Simulator) => (14, 0, 0), + ("watchos", Arch::Arm64 | Arch::Arm64e, TargetAbi::Simulator) => (7, 0, 0), _ => os_min, }; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c3e7f74c564..f12e3e595ad 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -855,6 +855,43 @@ impl ToJson for RelroLevel { } } +#[derive(Clone, Debug, PartialEq, Hash)] +pub enum SmallDataThresholdSupport { + None, + DefaultForArch, + LlvmModuleFlag(StaticCow<str>), + LlvmArg(StaticCow<str>), +} + +impl FromStr for SmallDataThresholdSupport { + type Err = (); + + fn from_str(s: &str) -> Result<Self, Self::Err> { + if s == "none" { + Ok(Self::None) + } else if s == "default-for-arch" { + Ok(Self::DefaultForArch) + } else if let Some(flag) = s.strip_prefix("llvm-module-flag=") { + Ok(Self::LlvmModuleFlag(flag.to_string().into())) + } else if let Some(arg) = s.strip_prefix("llvm-arg=") { + Ok(Self::LlvmArg(arg.to_string().into())) + } else { + Err(()) + } + } +} + +impl ToJson for SmallDataThresholdSupport { + fn to_json(&self) -> Value { + match self { + Self::None => "none".to_json(), + Self::DefaultForArch => "default-for-arch".to_json(), + Self::LlvmModuleFlag(flag) => format!("llvm-module-flag={flag}").to_json(), + Self::LlvmArg(arg) => format!("llvm-arg={arg}").to_json(), + } + } +} + #[derive(Clone, Copy, Debug, PartialEq, Hash)] pub enum MergeFunctions { Disabled, @@ -2392,6 +2429,9 @@ pub struct TargetOptions { /// Whether the target supports XRay instrumentation. pub supports_xray: bool, + + /// Whether the targets supports -Z small-data-threshold + small_data_threshold_support: SmallDataThresholdSupport, } /// Add arguments for the given flavor and also for its "twin" flavors @@ -2609,6 +2649,7 @@ impl Default for TargetOptions { entry_name: "main".into(), entry_abi: Conv::C, supports_xray: false, + small_data_threshold_support: SmallDataThresholdSupport::DefaultForArch, } } } @@ -2884,6 +2925,15 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); + ($key_name:ident, SmallDataThresholdSupport) => ( { + obj.remove("small-data-threshold-support").and_then(|o| o.as_str().and_then(|s| { + match s.parse::<SmallDataThresholdSupport>() { + Ok(support) => base.small_data_threshold_support = support, + _ => return Some(Err(format!("'{s}' is not a valid value for small-data-threshold-support."))), + } + Some(Ok(())) + })).unwrap_or(Ok(())) + } ); ($key_name:ident, PanicStrategy) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { @@ -3321,6 +3371,7 @@ impl Target { key!(supported_sanitizers, SanitizerSet)?; key!(generate_arange_section, bool); key!(supports_stack_protector, bool); + key!(small_data_threshold_support, SmallDataThresholdSupport)?; key!(entry_name); key!(entry_abi, Conv)?; key!(supports_xray, bool); @@ -3415,6 +3466,30 @@ impl Target { } } } + + /// Return the target's small data threshold support, converting + /// `DefaultForArch` into a concrete value. + pub fn small_data_threshold_support(&self) -> SmallDataThresholdSupport { + match &self.options.small_data_threshold_support { + // Avoid having to duplicate the small data support in every + // target file by supporting a default value for each + // architecture. + SmallDataThresholdSupport::DefaultForArch => match self.arch.as_ref() { + "mips" | "mips64" | "mips32r6" => { + SmallDataThresholdSupport::LlvmArg("mips-ssection-threshold".into()) + } + "hexagon" => { + SmallDataThresholdSupport::LlvmArg("hexagon-small-data-threshold".into()) + } + "m68k" => SmallDataThresholdSupport::LlvmArg("m68k-ssection-threshold".into()), + "riscv32" | "riscv64" => { + SmallDataThresholdSupport::LlvmModuleFlag("SmallDataLimit".into()) + } + _ => SmallDataThresholdSupport::None, + }, + s => s.clone(), + } + } } impl ToJson for Target { @@ -3577,6 +3652,7 @@ impl ToJson for Target { target_option_val!(c_enum_min_bits); target_option_val!(generate_arange_section); target_option_val!(supports_stack_protector); + target_option_val!(small_data_threshold_support); target_option_val!(entry_name); target_option_val!(entry_abi); target_option_val!(supports_xray); diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs index 67afe35bee4..3e27f1f899b 100644 --- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs @@ -1,10 +1,8 @@ use crate::spec::base::apple::{base, Arch, TargetAbi}; -use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions}; +use crate::spec::{FramePointer, Target, TargetOptions}; pub(crate) fn target() -> Target { - let (mut opts, llvm_target, arch) = base("macos", Arch::I686, TargetAbi::Normal); - opts.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m32"]); - + let (opts, llvm_target, arch) = base("macos", Arch::I686, TargetAbi::Normal); Target { llvm_target, metadata: crate::spec::TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs index d33c7af92c6..0bcbf655bd8 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{base, Target, TargetOptions}; +use crate::spec::{base, CodeModel, Target, TargetOptions}; pub(crate) fn target() -> Target { Target { @@ -13,6 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), arch: "loongarch64".into(), options: TargetOptions { + code_model: Some(CodeModel::Medium), cpu: "generic".into(), features: "+f,+d".into(), llvm_abiname: "lp64d".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs index 5540e71ad4f..223d979a06f 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs @@ -1,4 +1,4 @@ -use crate::spec::{base, Target, TargetOptions}; +use crate::spec::{base, CodeModel, Target, TargetOptions}; pub(crate) fn target() -> Target { Target { @@ -13,6 +13,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), arch: "loongarch64".into(), options: TargetOptions { + code_model: Some(CodeModel::Medium), cpu: "generic".into(), features: "+f,+d".into(), llvm_abiname: "lp64d".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs index 56285190268..db527c8b636 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs @@ -23,7 +23,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, - code_model: Some(CodeModel::Small), + code_model: Some(CodeModel::Medium), ..Default::default() }, } diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs index 7e57715ce7a..221ca02fe3e 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs @@ -24,7 +24,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, - code_model: Some(CodeModel::Small), + code_model: Some(CodeModel::Medium), ..Default::default() }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index e7f14aa9209..4304dfc3f68 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -1,9 +1,8 @@ use crate::spec::base::apple::{base, Arch, TargetAbi}; -use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions}; +use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { - let (mut opts, llvm_target, arch) = base("macos", Arch::X86_64, TargetAbi::Normal); - opts.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); + let (opts, llvm_target, arch) = base("macos", Arch::X86_64, TargetAbi::Normal); Target { llvm_target, metadata: crate::spec::TargetMetadata { diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs index f44bc660a62..9fb5a46187a 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs @@ -1,11 +1,10 @@ use crate::spec::base::apple::{base, Arch, TargetAbi}; -use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions}; +use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub(crate) fn target() -> Target { let (mut opts, llvm_target, arch) = base("macos", Arch::X86_64h, TargetAbi::Normal); opts.max_atomic_width = Some(128); opts.frame_pointer = FramePointer::Always; - opts.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); opts.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 65d21518491..d486416f22a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1323,23 +1323,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { label_or_note(span, terr.to_string(self.tcx)); label_or_note(sp, msg); } - } else { - if let Some(values) = values - && let Some((e, f)) = values.ty() - && let TypeError::ArgumentSorts(..) | TypeError::Sorts(_) = terr - { - let e = self.tcx.erase_regions(e); - let f = self.tcx.erase_regions(f); - let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx)); - let found = with_forced_trimmed_paths!(f.sort_string(self.tcx)); - if expected == found { - label_or_note(span, terr.to_string(self.tcx)); - } else { - label_or_note(span, Cow::from(format!("expected {expected}, found {found}"))); - } - } else { + } else if let Some(values) = values + && let Some((e, f)) = values.ty() + && let TypeError::ArgumentSorts(..) | TypeError::Sorts(_) = terr + { + let e = self.tcx.erase_regions(e); + let f = self.tcx.erase_regions(f); + let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx)); + let found = with_forced_trimmed_paths!(f.sort_string(self.tcx)); + if expected == found { label_or_note(span, terr.to_string(self.tcx)); + } else { + label_or_note(span, Cow::from(format!("expected {expected}, found {found}"))); } + } else { + label_or_note(span, terr.to_string(self.tcx)); } if let Some((expected, found, path)) = expected_found { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 45e157b1080..b13aede509a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3237,16 +3237,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // then the tuple must be the one containing capture types. let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) { false + } else if let ObligationCauseCode::BuiltinDerived(data) = &*data.parent_code { + let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); + let nested_ty = parent_trait_ref.skip_binder().self_ty(); + matches!(nested_ty.kind(), ty::Coroutine(..)) + || matches!(nested_ty.kind(), ty::Closure(..)) } else { - if let ObligationCauseCode::BuiltinDerived(data) = &*data.parent_code { - let parent_trait_ref = - self.resolve_vars_if_possible(data.parent_trait_pred); - let nested_ty = parent_trait_ref.skip_binder().self_ty(); - matches!(nested_ty.kind(), ty::Coroutine(..)) - || matches!(nested_ty.kind(), ty::Closure(..)) - } else { - false - } + false }; if !is_upvar_tys_infer_tuple { diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index f5f36f40f7e..cfc73e2e47e 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -302,7 +302,7 @@ fn fulfillment_error_for_stalled<'tcx>( Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => ( FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }, // Don't look into overflows because we treat overflows weirdly anyways. - // In `instantiate_response_discarding_overflow` we set `has_changed = false`, + // We discard the inference constraints from overflowing goals, so // recomputing the goal again during `find_best_leaf_obligation` may apply // inference guidance that makes other goals go from ambig -> pass, for example. // diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index c8811bc37b3..de1d4ef15ac 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -35,8 +35,10 @@ where if infcx.next_trait_solver() { Box::new(NextFulfillmentCtxt::new(infcx)) } else { + let new_solver_globally = + infcx.tcx.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.globally); assert!( - !infcx.tcx.next_trait_solver_globally(), + !new_solver_globally, "using old solver even though new solver is enabled globally" ); Box::new(FulfillmentContext::new(infcx)) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 630acc91fbe..c27a9285b3a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -408,7 +408,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( debug!("opt_normalize_projection_type: found error"); let result = normalize_to_error(selcx, param_env, projection_term, cause, depth); obligations.extend(result.obligations); - return Ok(Some(result.value.into())); + return Ok(Some(result.value)); } } @@ -478,7 +478,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( } let result = normalize_to_error(selcx, param_env, projection_term, cause, depth); obligations.extend(result.obligations); - Ok(Some(result.value.into())) + Ok(Some(result.value)) } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 77efc2fc2db..3e3589538c7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -426,13 +426,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else if kind == ty::ClosureKind::FnOnce { candidates.vec.push(ClosureCandidate { is_const }); } + } else if kind == ty::ClosureKind::FnOnce { + candidates.vec.push(ClosureCandidate { is_const }); } else { - if kind == ty::ClosureKind::FnOnce { - candidates.vec.push(ClosureCandidate { is_const }); - } else { - // This stays ambiguous until kind+upvars are determined. - candidates.ambiguous = true; - } + // This stays ambiguous until kind+upvars are determined. + candidates.ambiguous = true; } } ty::Infer(ty::TyVar(_)) => { @@ -513,10 +511,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // then there's nothing else to check. if let Some(closure_kind) = self_ty.to_opt_closure_kind() && let Some(goal_kind) = target_kind_ty.to_opt_closure_kind() + && closure_kind.extends(goal_kind) { - if closure_kind.extends(goal_kind) { - candidates.vec.push(AsyncFnKindHelperCandidate); - } + candidates.vec.push(AsyncFnKindHelperCandidate); } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 241c3a3d141..f5cd7273ca2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1334,16 +1334,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - if self.can_use_global_caches(param_env) { - if !trait_pred.has_infer() { - debug!(?trait_pred, ?result, "insert_evaluation_cache global"); - // This may overwrite the cache with the same value - // FIXME: Due to #50507 this overwrites the different values - // This should be changed to use HashMapExt::insert_same - // when that is fixed - self.tcx().evaluation_cache.insert((param_env, trait_pred), dep_node, result); - return; - } + if self.can_use_global_caches(param_env) && !trait_pred.has_infer() { + debug!(?trait_pred, ?result, "insert_evaluation_cache global"); + // This may overwrite the cache with the same value + // FIXME: Due to #50507 this overwrites the different values + // This should be changed to use HashMapExt::insert_same + // when that is fixed + self.tcx().evaluation_cache.insert((param_env, trait_pred), dep_node, result); + return; } debug!(?trait_pred, ?result, "insert_evaluation_cache"); @@ -1584,13 +1582,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if self.can_use_global_caches(param_env) { if let Err(Overflow(OverflowError::Canonical)) = candidate { // Don't cache overflow globally; we only produce this in certain modes. - } else if !pred.has_infer() { - if !candidate.has_infer() { - debug!(?pred, ?candidate, "insert_candidate_cache global"); - // This may overwrite the cache with the same value. - tcx.selection_cache.insert((param_env, pred), dep_node, candidate); - return; - } + } else if !pred.has_infer() && !candidate.has_infer() { + debug!(?pred, ?candidate, "insert_candidate_cache global"); + // This may overwrite the cache with the same value. + tcx.selection_cache.insert((param_env, pred), dep_node, candidate); + return; } } @@ -1980,10 +1976,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // impls have to be always applicable, meaning that the only allowed // region constraints may be constraints also present on the default impl. let tcx = self.tcx(); - if other.evaluation.must_apply_modulo_regions() { - if tcx.specializes((other_def, victim_def)) { - return DropVictim::Yes; - } + if other.evaluation.must_apply_modulo_regions() + && tcx.specializes((other_def, victim_def)) + { + return DropVictim::Yes; } match tcx.impls_are_allowed_to_overlap(other_def, victim_def) { diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index e899284674c..6b24929467b 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -143,10 +143,8 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { match origin { rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {} rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => { - if !in_assoc_ty { - if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) { - return; - } + if !in_assoc_ty && !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) { + return; } } } diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 96998d2ec9f..a0f7658212f 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -117,7 +117,8 @@ impl<I: Interner, P> Goal<I, P> { /// Why a specific goal has to be proven. /// /// This is necessary as we treat nested goals different depending on -/// their source. +/// their source. This is currently mostly used by proof tree visitors +/// but will be used by cycle handling in the future. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum GoalSource { @@ -126,13 +127,6 @@ pub enum GoalSource { /// /// FIXME(-Znext-solver=coinductive): Explain how and why this /// changes whether cycles are coinductive. - /// - /// This also impacts whether we erase constraints on overflow. - /// Erasing constraints is generally very useful for perf and also - /// results in better error messages by avoiding spurious errors. - /// We do not erase overflow constraints in `normalizes-to` goals unless - /// they are from an impl where-clause. This is necessary due to - /// backwards compatibility, cc trait-system-refactor-initiatitive#70. ImplWhereBound, /// Instantiating a higher-ranked goal and re-proving it. InstantiateHigherRanked, |
