From e02c5b5930c2c9ba3e5423fe12e2ef0155017297 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 20:31:36 +0200 Subject: Merging upstream version 1.74.1+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_borrowck/messages.ftl | 11 +- compiler/rustc_borrowck/src/borrow_set.rs | 2 +- compiler/rustc_borrowck/src/def_use.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 64 +++-- compiler/rustc_borrowck/src/diagnostics/mod.rs | 13 +- .../src/diagnostics/mutability_errors.rs | 306 ++++++++++++++------- .../src/diagnostics/region_errors.rs | 4 +- .../rustc_borrowck/src/diagnostics/region_name.rs | 18 +- compiler/rustc_borrowck/src/invalidation.rs | 16 +- compiler/rustc_borrowck/src/lib.rs | 44 +-- compiler/rustc_borrowck/src/nll.rs | 6 +- compiler/rustc_borrowck/src/places_conflict.rs | 8 +- compiler/rustc_borrowck/src/prefixes.rs | 3 + compiler/rustc_borrowck/src/region_infer/mod.rs | 9 +- compiler/rustc_borrowck/src/renumber.rs | 23 +- compiler/rustc_borrowck/src/session_diagnostics.rs | 7 + .../rustc_borrowck/src/type_check/canonical.rs | 19 +- compiler/rustc_borrowck/src/type_check/mod.rs | 90 +++--- .../rustc_borrowck/src/type_check/relate_tys.rs | 9 +- compiler/rustc_borrowck/src/universal_regions.rs | 48 ++-- 20 files changed, 433 insertions(+), 269 deletions(-) (limited to 'compiler/rustc_borrowck') diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index 67fdb6717..2c7b97afa 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -74,9 +74,6 @@ borrowck_higher_ranked_subtype_error = borrowck_lifetime_constraints_error = lifetime may not live long enough -borrowck_move_borrowed = - cannot move out of `{$desc}` because it is borrowed - borrowck_move_out_place_here = {$place} is moved here @@ -166,6 +163,8 @@ borrowck_returned_lifetime_wrong = borrowck_returned_ref_escaped = returns a reference to a captured variable which escapes the closure body +borrowck_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item + borrowck_suggest_create_freash_reborrow = consider reborrowing the `Pin` instead of moving it @@ -248,12 +247,6 @@ borrowck_var_move_by_use_in_closure = borrowck_var_move_by_use_in_generator = move occurs due to use in generator -borrowck_var_move_by_use_place_in_closure = - move occurs due to use of {$place} in closure - -borrowck_var_move_by_use_place_in_generator = - move occurs due to use of {$place} in generator - borrowck_var_mutable_borrow_by_use_place_in_closure = mutable borrow occurs due to use of {$place} in closure diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 0b44beeb0..5248a649c 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -71,7 +71,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { let kind = match self.kind { mir::BorrowKind::Shared => "", - mir::BorrowKind::Shallow => "shallow ", + mir::BorrowKind::Fake => "fake ", mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ", // FIXME: differentiate `TwoPhaseBorrow` mir::BorrowKind::Mut { diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index b719a610e..95db93742 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -49,7 +49,7 @@ pub fn categorize(context: PlaceContext) -> Option { // cross suspension points so this behavior is unproblematic. PlaceContext::MutatingUse(MutatingUseContext::Borrow) | PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow) | // `PlaceMention` and `AscribeUserType` both evaluate the place, which must not // contain dangling references. diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index fe4a45b38..ee352e911 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1025,7 +1025,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None) } - (BorrowKind::Mut { .. }, BorrowKind::Shallow) => { + (BorrowKind::Mut { .. }, BorrowKind::Fake) => { if let Some(immutable_section_description) = self.classify_immutable_section(issued_borrow.assigned_place) { @@ -1117,11 +1117,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) } - (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow) - | ( - BorrowKind::Shallow, - BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow, - ) => unreachable!(), + (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Fake) + | (BorrowKind::Fake, BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) => { + unreachable!() + } }; if issued_spans == borrow_spans { @@ -2130,21 +2129,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`. /// We could expand the analysis to suggest hoising all of the relevant parts of /// the users' code to make the code compile, but that could be too much. - struct NestedStatementVisitor { + /// We found the `prop_expr` by the way to check whether the expression is a `FormatArguments`, + /// which is a special case since it's generated by the compiler. + struct NestedStatementVisitor<'tcx> { span: Span, current: usize, found: usize, + prop_expr: Option<&'tcx hir::Expr<'tcx>>, } - impl<'tcx> Visitor<'tcx> for NestedStatementVisitor { - fn visit_block(&mut self, block: &hir::Block<'tcx>) { + impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> { + fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { self.current += 1; walk_block(self, block); self.current -= 1; } - fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if self.span == expr.span.source_callsite() { self.found = self.current; + if self.prop_expr.is_none() { + self.prop_expr = Some(expr); + } } walk_expr(self, expr); } @@ -2162,22 +2167,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { span: proper_span, current: 0, found: 0, + prop_expr: None, }; visitor.visit_stmt(stmt); + + let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); + let expr_ty: Option> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs()); + + let is_format_arguments_item = + if let Some(expr_ty) = expr_ty + && let ty::Adt(adt, _) = expr_ty.kind() { + self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did()) + } else { + false + }; + if visitor.found == 0 && stmt.span.contains(proper_span) && let Some(p) = sm.span_to_margin(stmt.span) && let Ok(s) = sm.span_to_snippet(proper_span) { - let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); - err.multipart_suggestion_verbose( - msg, - vec![ - (stmt.span.shrink_to_lo(), addition), - (proper_span, "binding".to_string()), - ], - Applicability::MaybeIncorrect, - ); + if !is_format_arguments_item { + let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); + err.multipart_suggestion_verbose( + msg, + vec![ + (stmt.span.shrink_to_lo(), addition), + (proper_span, "binding".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } else { + err.note("the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used"); + err.note("to learn more, visit "); + } suggested = true; break; } @@ -2620,7 +2643,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let loan_span = loan_spans.args_or_use(); let descr_place = self.describe_any_place(place.as_ref()); - if loan.kind == BorrowKind::Shallow { + if loan.kind == BorrowKind::Fake { if let Some(section) = self.classify_immutable_section(loan.assigned_place) { let mut err = self.cannot_mutate_in_immutable_section( span, @@ -2804,6 +2827,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } + | ProjectionElem::Subtype(_) | ProjectionElem::Index(_) => kind, }, place_ty.projection_ty(tcx, elem), diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 099e07e88..8d4028de9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -13,7 +13,7 @@ use rustc_index::IndexSlice; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ - AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, + AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; @@ -101,12 +101,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let terminator = self.body[location.block].terminator(); debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator); if let TerminatorKind::Call { - func: Operand::Constant(box Constant { literal, .. }), + func: Operand::Constant(box ConstOperand { const_, .. }), args, .. } = &terminator.kind { - if let ty::FnDef(id, _) = *literal.ty().kind() { + if let ty::FnDef(id, _) = *const_.ty().kind() { debug!("add_moved_or_invoked_closure_note: id={:?}", id); if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() { let closure = match args.first() { @@ -242,6 +242,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ProjectionElem::Downcast(..) if opt.including_downcast => return None, ProjectionElem::Downcast(..) => (), ProjectionElem::OpaqueCast(..) => (), + ProjectionElem::Subtype(..) => (), ProjectionElem::Field(field, _ty) => { // FIXME(project-rfc_2229#36): print capture precisely here. if let Some(field) = self.is_upvar_field_projection(PlaceRef { @@ -322,7 +323,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) } ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), - ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty), + ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => { + PlaceTy::from_ty(*ty) + } ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), }, }; @@ -628,7 +631,7 @@ impl UseSpans<'_> { err.subdiagnostic(match kind { Some(kd) => match kd { rustc_middle::mir::BorrowKind::Shared - | rustc_middle::mir::BorrowKind::Shallow => { + | rustc_middle::mir::BorrowKind::Fake => { CaptureVarKind::Immut { kind_span: capture_kind_span } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index d62541daf..8ca57383e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,9 +1,10 @@ +use hir::ExprKind; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; use rustc_middle::{ hir::place::PlaceBase, mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location}, @@ -158,6 +159,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { [ .., ProjectionElem::Index(_) + | ProjectionElem::Subtype(_) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } @@ -225,17 +227,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } if suggest { borrow_spans.var_subdiag( - None, - &mut err, - Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), - |_kind, var_span| { - let place = self.describe_any_place(access_place.as_ref()); - crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure { - place, - var_span, - } - }, - ); + None, + &mut err, + Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), + |_kind, var_span| { + let place = self.describe_any_place(access_place.as_ref()); + crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure { + place, + var_span, + } + }, + ); } borrow_span } @@ -262,11 +264,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } => { err.span_label(span, format!("cannot {act}")); - if let Some(span) = get_mut_span_in_struct_field( - self.infcx.tcx, - Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty, - *field, - ) { + let place = Place::ty_from(local, proj_base, self.body, self.infcx.tcx); + if let Some(span) = get_mut_span_in_struct_field(self.infcx.tcx, place.ty, *field) { err.span_suggestion_verbose( span, "consider changing this to be mutable", @@ -373,12 +372,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.span_label(span, format!("cannot {act}")); } if suggest { - err.span_suggestion_verbose( - local_decl.source_info.span.shrink_to_lo(), - "consider changing this to be mutable", - "mut ", - Applicability::MachineApplicable, - ); + self.construct_mut_suggestion_for_local_binding_patterns(&mut err, local); let tcx = self.infcx.tcx; if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() { self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err); @@ -494,6 +488,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ), ); + self.suggest_using_iter_mut(&mut err); self.suggest_make_local_mut(&mut err, local, name); } _ => { @@ -713,6 +708,83 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) } + fn construct_mut_suggestion_for_local_binding_patterns( + &self, + err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + local: Local, + ) { + let local_decl = &self.body.local_decls[local]; + debug!("local_decl: {:?}", local_decl); + let pat_span = match *local_decl.local_info() { + LocalInfo::User(BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(Mutability::Not), + opt_ty_info: _, + opt_match_place: _, + pat_span, + })) => pat_span, + _ => local_decl.source_info.span, + }; + + struct BindingFinder { + span: Span, + hir_id: Option, + } + + impl<'tcx> Visitor<'tcx> for BindingFinder { + fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { + if let hir::StmtKind::Local(local) = s.kind { + if local.pat.span == self.span { + self.hir_id = Some(local.hir_id); + } + } + hir::intravisit::walk_stmt(self, s); + } + } + + let hir_map = self.infcx.tcx.hir(); + let def_id = self.body.source.def_id(); + let hir_id = if let Some(local_def_id) = def_id.as_local() + && let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) + { + let body = hir_map.body(body_id); + let mut v = BindingFinder { + span: pat_span, + hir_id: None, + }; + v.visit_body(body); + v.hir_id + } else { + None + }; + + // With ref-binding patterns, the mutability suggestion has to apply to + // the binding, not the reference (which would be a type error): + // + // `let &b = a;` -> `let &(mut b) = a;` + if let Some(hir_id) = hir_id + && let Some(hir::Node::Local(hir::Local { + pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. }, + .. + })) = hir_map.find(hir_id) + && let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span) + { + err.span_suggestion( + pat_span, + "consider changing this to be mutable", + format!("&(mut {name})"), + Applicability::MachineApplicable, + ); + return; + } + + err.span_suggestion_verbose( + local_decl.source_info.span.shrink_to_lo(), + "consider changing this to be mutable", + "mut ", + Applicability::MachineApplicable, + ); + } + // point to span of upvar making closure call require mutable borrow fn show_mutating_upvar( &self, @@ -781,83 +853,88 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Attempt to search similar mutable associated items for suggestion. // In the future, attempt in all path but initially for RHS of for_loop - fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diagnostic) { + fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diagnostic, span: Span) { use hir::{ - Expr, - ExprKind::{Block, Call, DropTemps, Match, MethodCall}, + BorrowKind, Expr, + ExprKind::{AddrOf, Block, Call, MethodCall}, }; let hir_map = self.infcx.tcx.hir(); - if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id()) { - if let Block( - hir::Block { - expr: - Some(Expr { - kind: - DropTemps(Expr { - kind: - Match( - Expr { - kind: - Call( - _, - [ - Expr { - kind: - MethodCall(path_segment, _, _, span), - hir_id, - .. - }, - .., - ], - ), - .. - }, - .., - ), - .. - }), - .. - }), - .. - }, - _, - ) = hir_map.body(body_id).value.kind - { - let opt_suggestions = self - .infcx - .tcx - .typeck(path_segment.hir_id.owner.def_id) - .type_dependent_def_id(*hir_id) - .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) - .map(|def_id| self.infcx.tcx.associated_items(def_id)) - .map(|assoc_items| { - assoc_items - .in_definition_order() - .map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx)) - .filter(|&ident| { - let original_method_ident = path_segment.ident; - original_method_ident != ident - && ident - .as_str() - .starts_with(&original_method_ident.name.to_string()) - }) - .map(|ident| format!("{ident}()")) - .peekable() - }); + struct Finder<'tcx> { + span: Span, + expr: Option<&'tcx Expr<'tcx>>, + } - if let Some(mut suggestions) = opt_suggestions - && suggestions.peek().is_some() - { - err.span_suggestions( - *span, - "use mutable method", - suggestions, - Applicability::MaybeIncorrect, - ); + impl<'tcx> Visitor<'tcx> for Finder<'tcx> { + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + if e.span == self.span && self.expr.is_none() { + self.expr = Some(e); } + hir::intravisit::walk_expr(self, e); } - }; + } + if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id()) + && let Block(block, _) = hir_map.body(body_id).value.kind + { + // `span` corresponds to the expression being iterated, find the `for`-loop desugared + // expression with that span in order to identify potential fixes when encountering a + // read-only iterator that should be mutable. + let mut v = Finder { + span, + expr: None, + }; + v.visit_block(block); + if let Some(expr) = v.expr && let Call(_, [expr]) = expr.kind { + match expr.kind { + MethodCall(path_segment, _, _, span) => { + // We have `for _ in iter.read_only_iter()`, try to + // suggest `for _ in iter.mutable_iter()` instead. + let opt_suggestions = self + .infcx + .tcx + .typeck(path_segment.hir_id.owner.def_id) + .type_dependent_def_id(expr.hir_id) + .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) + .map(|def_id| self.infcx.tcx.associated_items(def_id)) + .map(|assoc_items| { + assoc_items + .in_definition_order() + .map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx)) + .filter(|&ident| { + let original_method_ident = path_segment.ident; + original_method_ident != ident + && ident.as_str().starts_with( + &original_method_ident.name.to_string(), + ) + }) + .map(|ident| format!("{ident}()")) + .peekable() + }); + + if let Some(mut suggestions) = opt_suggestions + && suggestions.peek().is_some() + { + err.span_suggestions( + span, + "use mutable method", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } + AddrOf(BorrowKind::Ref, Mutability::Not, expr) => { + // We have `for _ in &i`, suggest `for _ in &mut i`. + err.span_suggestion_verbose( + expr.span.shrink_to_lo(), + "use a mutable iterator instead", + "mut ".to_string(), + Applicability::MachineApplicable, + ); + } + _ => {} + } + } + } } /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected. @@ -951,6 +1028,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } + fn suggest_using_iter_mut(&self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>) { + let source = self.body.source; + let hir = self.infcx.tcx.hir(); + if let InstanceDef::Item(def_id) = source.instance + && let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id) + && let ExprKind::Closure(closure) = kind && closure.movability == None + && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) { + let mut cur_expr = expr; + while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind { + if path_segment.ident.name == sym::iter { + // check `_ty` has `iter_mut` method + let res = self + .infcx + .tcx + .typeck(path_segment.hir_id.owner.def_id) + .type_dependent_def_id(cur_expr.hir_id) + .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) + .map(|def_id| self.infcx.tcx.associated_items(def_id)) + .map(|assoc_items| { + assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable() + }); + + if let Some(mut res) = res && res.peek().is_some() { + err.span_suggestion_verbose( + path_segment.ident.span, + "you may want to use `iter_mut` here", + "iter_mut", + Applicability::MaybeIncorrect, + ); + } + break; + } else { + cur_expr = recv; + } + } + } + } + fn suggest_make_local_mut( &self, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, @@ -1003,9 +1118,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) { // on for loops, RHS points to the iterator part Some(DesugaringKind::ForLoop) => { - self.suggest_similar_mut_method_for_for_loop(err); + let span = opt_assignment_rhs_span.unwrap(); + self.suggest_similar_mut_method_for_for_loop(err, span); err.span_label( - opt_assignment_rhs_span.unwrap(), + span, format!("this iterator yields `{pointer_sigil}` {pointer_desc}s",), ); None diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 2ea399789..27072a60f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -245,7 +245,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; }; diag.span_note( *trait_span, - format!("due to current limitations in the borrow checker, this implies a `'static` lifetime") + "due to current limitations in the borrow checker, this implies a `'static` lifetime" ); let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local()) else { return; }; let Def(_, trait_res_defid) = trait_ref.path.res else { return; }; @@ -277,7 +277,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if suggestions.len() > 0 { suggestions.dedup(); diag.multipart_suggestion_verbose( - format!("consider restricting the type parameter to the `'static` lifetime"), + "consider restricting the type parameter to the `'static` lifetime", suggestions, Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 337af89b2..55d581b3a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -27,7 +27,7 @@ pub(crate) struct RegionName { /// This helps to print the right kinds of diagnostics. #[derive(Debug, Clone)] pub(crate) enum RegionNameSource { - /// A bound (not free) region that was substituted at the def site (not an HRTB). + /// A bound (not free) region that was instantiated at the def site (not an HRTB). NamedEarlyBoundRegion(Span), /// A free region that the user has a name (`'a`) for. NamedFreeRegion(Span), @@ -302,7 +302,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { if free_region.bound_region.is_named() { // A named region that is actually named. Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) }) - } else if let hir::IsAsync::Async = tcx.asyncness(self.mir_hir_id().owner) { + } else if tcx.asyncness(self.mir_hir_id().owner).is_async() { // If we spuriously thought that the region is named, we should let the // system generate a true name for error messages. Currently this can // happen if we have an elided name in an async fn for example: the @@ -354,7 +354,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { }) } - ty::BoundRegionKind::BrAnon(..) => None, + ty::BoundRegionKind::BrAnon => None, }, ty::ReLateBound(..) @@ -442,8 +442,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { span: Span, counter: usize, ) -> RegionNameHighlight { - let mut highlight = RegionHighlightMode::new(self.infcx.tcx); - highlight.highlighting_region_vid(needle_fr, counter); + let mut highlight = RegionHighlightMode::default(); + highlight.highlighting_region_vid(self.infcx.tcx, needle_fr, counter); let type_name = self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; @@ -516,7 +516,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { // be the same as those of the ADT. // FIXME: We should be able to do something similar to // match_adt_and_segment in this case. - Res::Def(DefKind::TyAlias { .. }, _) => (), + Res::Def(DefKind::TyAlias, _) => (), _ => { if let Some(last_segment) = path.segments.last() { if let Some(highlight) = self.match_adt_and_segment( @@ -619,7 +619,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { // programs, so we need to use delay_span_bug here. See #82126. self.infcx.tcx.sess.delay_span_bug( hir_arg.span(), - format!("unmatched subst and hir arg: found {kind:?} vs {hir_arg:?}"), + format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"), ); } } @@ -804,8 +804,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { return None; } - let mut highlight = RegionHighlightMode::new(tcx); - highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); + let mut highlight = RegionHighlightMode::default(); + highlight.highlighting_region_vid(tcx, fr, *self.next_region_name.try_borrow().unwrap()); let type_name = self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index df5e383ad..2faf1a529 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -159,7 +159,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.mutate_place(location, *resume_arg, Deep); } - TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => { + TerminatorKind::UnwindResume + | TerminatorKind::Return + | TerminatorKind::GeneratorDrop => { // Invalidate all borrows of local places let borrow_set = self.borrow_set; let start = self.location_table.start_index(location); @@ -200,7 +202,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } } TerminatorKind::Goto { target: _ } - | TerminatorKind::Terminate + | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Unreachable | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { @@ -251,8 +253,8 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { match rvalue { &Rvalue::Ref(_ /*rgn*/, bk, place) => { let access_kind = match bk { - BorrowKind::Shallow => { - (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) + BorrowKind::Fake => { + (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk))) } BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), BorrowKind::Mut { .. } => { @@ -374,8 +376,8 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { // have already taken the reservation } - (Read(_), BorrowKind::Shallow | BorrowKind::Shared) - | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { + (Read(_), BorrowKind::Fake | BorrowKind::Shared) + | (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => { // Reads don't invalidate shared or shallow borrows } @@ -420,7 +422,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { - BorrowKind::Shared | BorrowKind::Shallow => false, + BorrowKind::Shared | BorrowKind::Fake => false, BorrowKind::Mut { .. } => true, }); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index efe525c22..1d17df8b7 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -11,7 +11,7 @@ #![feature(trusted_step)] #![feature(try_blocks)] #![recursion_limit = "256"] -#![cfg_attr(not(bootstrap), allow(internal_features))] +#![allow(internal_features)] #[macro_use] extern crate rustc_middle; @@ -603,7 +603,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro fn visit_statement_before_primary_effect( &mut self, - _results: &R, + _results: &mut R, flow_state: &Flows<'cx, 'tcx>, stmt: &'cx Statement<'tcx>, location: Location, @@ -673,7 +673,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro fn visit_terminator_before_primary_effect( &mut self, - _results: &R, + _results: &mut R, flow_state: &Flows<'cx, 'tcx>, term: &'cx Terminator<'tcx>, loc: Location, @@ -770,9 +770,9 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro } TerminatorKind::Goto { target: _ } - | TerminatorKind::Terminate + | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Unreachable - | TerminatorKind::Resume + | TerminatorKind::UnwindResume | TerminatorKind::Return | TerminatorKind::GeneratorDrop | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ } @@ -784,7 +784,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro fn visit_terminator_after_primary_effect( &mut self, - _results: &R, + _results: &mut R, flow_state: &Flows<'cx, 'tcx>, term: &'cx Terminator<'tcx>, loc: Location, @@ -803,7 +803,9 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro } } - TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => { + TerminatorKind::UnwindResume + | TerminatorKind::Return + | TerminatorKind::GeneratorDrop => { // Returning from the function implicitly kills storage for all locals and statics. // Often, the storage will already have been killed by an explicit // StorageDead, but we don't always emit those (notably on unwind paths), @@ -815,7 +817,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro } } - TerminatorKind::Terminate + TerminatorKind::UnwindTerminate(_) | TerminatorKind::Assert { .. } | TerminatorKind::Call { .. } | TerminatorKind::Drop { .. } @@ -835,7 +837,7 @@ use self::ReadOrWrite::{Activation, Read, Reservation, Write}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum ArtificialField { ArrayLength, - ShallowBorrow, + FakeBorrow, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -1074,18 +1076,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Control::Continue } - (Read(_), BorrowKind::Shared | BorrowKind::Shallow) - | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { + (Read(_), BorrowKind::Shared | BorrowKind::Fake) + | (Read(ReadKind::Borrow(BorrowKind::Fake)), BorrowKind::Mut { .. }) => { Control::Continue } - (Reservation(_), BorrowKind::Shallow | BorrowKind::Shared) => { + (Reservation(_), BorrowKind::Fake | BorrowKind::Shared) => { // This used to be a future compatibility warning (to be // disallowed on NLL). See rust-lang/rust#56254 Control::Continue } - (Write(WriteKind::Move), BorrowKind::Shallow) => { + (Write(WriteKind::Move), BorrowKind::Fake) => { // Handled by initialization checks. Control::Continue } @@ -1193,8 +1195,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match rvalue { &Rvalue::Ref(_ /*rgn*/, bk, place) => { let access_kind = match bk { - BorrowKind::Shallow => { - (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) + BorrowKind::Fake => { + (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk))) } BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), BorrowKind::Mut { .. } => { @@ -1215,7 +1217,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { flow_state, ); - let action = if bk == BorrowKind::Shallow { + let action = if bk == BorrowKind::Fake { InitializationRequiringAction::MatchOn } else { InitializationRequiringAction::Borrow @@ -1567,7 +1569,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { - BorrowKind::Shared | BorrowKind::Shallow => false, + BorrowKind::Shared | BorrowKind::Fake => false, BorrowKind::Mut { .. } => true, }); @@ -1801,6 +1803,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { for (place_base, elem) in place.iter_projections().rev() { match elem { ProjectionElem::Index(_/*operand*/) | + ProjectionElem::Subtype(_) | ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } | // assigning to P[i] requires P to be valid. @@ -2000,14 +2003,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | WriteKind::Replace | WriteKind::StorageDeadOrDrop | WriteKind::MutableBorrow(BorrowKind::Shared) - | WriteKind::MutableBorrow(BorrowKind::Shallow), + | WriteKind::MutableBorrow(BorrowKind::Fake), ) | Write( WriteKind::Move | WriteKind::Replace | WriteKind::StorageDeadOrDrop | WriteKind::MutableBorrow(BorrowKind::Shared) - | WriteKind::MutableBorrow(BorrowKind::Shallow), + | WriteKind::MutableBorrow(BorrowKind::Fake), ) => { if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err() && !self.has_buffered_errors() @@ -2031,7 +2034,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return false; } Read( - ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow) + ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) | ReadKind::Copy, ) => { // Access authorized @@ -2189,6 +2192,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } + | ProjectionElem::Subtype(..) | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Downcast(..) => { let upvar_field_projection = self.is_upvar_field_projection(place); diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 679a19710..3f60f5aca 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -10,6 +10,7 @@ use rustc_middle::mir::{ Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted, START_BLOCK, }; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt}; use rustc_span::symbol::sym; use std::env; @@ -441,7 +442,10 @@ fn for_each_region_constraint<'tcx>( let subject = match req.subject { ClosureOutlivesSubject::Region(subject) => format!("{subject:?}"), ClosureOutlivesSubject::Ty(ty) => { - format!("{:?}", ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid))) + with_no_trimmed_paths!(format!( + "{}", + ty.instantiate(tcx, |vid| ty::Region::new_var(tcx, vid)) + )) } }; with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?; diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index c02f6f3b6..777ebf0d4 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -204,7 +204,7 @@ fn place_components_conflict<'tcx>( match (elem, &base_ty.kind(), access) { (_, _, Shallow(Some(ArtificialField::ArrayLength))) - | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { + | (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => { // The array length is like additional fields on the // type; it does not overlap any existing data there. // Furthermore, if cannot actually be a prefix of any @@ -249,6 +249,7 @@ fn place_components_conflict<'tcx>( | (ProjectionElem::ConstantIndex { .. }, _, _) | (ProjectionElem::Subslice { .. }, _, _) | (ProjectionElem::OpaqueCast { .. }, _, _) + | (ProjectionElem::Subtype(_), _, _) | (ProjectionElem::Downcast { .. }, _, _) => { // Recursive case. This can still be disjoint on a // further iteration if this a shallow access and @@ -272,10 +273,10 @@ fn place_components_conflict<'tcx>( // If the second example, where we did, then we still know // that the borrow can access a *part* of our place that // our access cares about, so we still have a conflict. - if borrow_kind == BorrowKind::Shallow + if borrow_kind == BorrowKind::Fake && borrow_place.projection.len() < access_place.projection.len() { - debug!("borrow_conflicts_with_place: shallow borrow"); + debug!("borrow_conflicts_with_place: fake borrow"); false } else { debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); @@ -508,6 +509,7 @@ fn place_projection_conflict<'tcx>( | ProjectionElem::Field(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subtype(_) | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index 6f2813498..e9c9709bd 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -89,6 +89,9 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { cursor = cursor_base; continue 'cursor; } + ProjectionElem::Subtype(..) => { + panic!("Subtype projection is not allowed before borrow check") + } ProjectionElem::Deref => { // (handled below) } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b8cd94e54..852935676 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -2249,7 +2249,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { } pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> { - self.universe_causes[&universe].clone() + // Query canonicalization can create local superuniverses (for example in + // `InferCtx::query_response_instantiation_guess`), but they don't have an associated + // `UniverseInfo` explaining why they were created. + // This can cause ICEs if these causes are accessed in diagnostics, for example in issue + // #114907 where this happens via liveness and dropck outlives results. + // Therefore, we return a default value in case that happens, which should at worst emit a + // suboptimal error, instead of the ICE. + self.universe_causes.get(&universe).cloned().unwrap_or_else(|| UniverseInfo::other()) } /// Tries to find the terminator of the loop in which the region 'r' resides. diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 4c69ea843..5d6f5cc89 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -4,11 +4,10 @@ use crate::BorrowckInferCtxt; use rustc_index::IndexSlice; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::visit::{MutVisitor, TyContext}; -use rustc_middle::mir::Constant; -use rustc_middle::mir::{Body, Location, Promoted}; +use rustc_middle::mir::{Body, ConstOperand, Location, Promoted}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_span::{Span, Symbol}; +use rustc_span::Symbol; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. @@ -29,21 +28,15 @@ pub fn renumber_mir<'tcx>( renumberer.visit_body(body); } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -pub(crate) enum BoundRegionInfo { - Name(Symbol), - Span(Span), -} - #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub(crate) enum RegionCtxt { Location(Location), TyContext(TyContext), Free(Symbol), - Bound(BoundRegionInfo), - LateBound(BoundRegionInfo), + Bound(Symbol), + LateBound(Symbol), Existential(Option), - Placeholder(BoundRegionInfo), + Placeholder(Symbol), Unknown, } @@ -117,9 +110,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) { - let literal = constant.literal; - constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(location)); + fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { + let const_ = constant.const_; + constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location)); debug!("constant: {:#?}", constant); } } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index d1d8cfa74..ca3ccf439 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -452,3 +452,10 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> { #[note(borrowck_ty_no_impl_copy)] Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str }, } + +#[derive(Diagnostic)] +#[diag(borrowck_simd_shuffle_last_const)] +pub(crate) struct SimdShuffleLastConst { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 16f5e68a0..b7adc314f 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -9,7 +9,7 @@ use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; use rustc_trait_selection::traits::ObligationCause; -use crate::diagnostics::{ToUniverseInfo, UniverseInfo}; +use crate::diagnostics::ToUniverseInfo; use super::{Locations, NormalizeLocation, TypeChecker}; @@ -46,13 +46,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.push_region_constraints(locations, category, data); } + // If the query has created new universes and errors are going to be emitted, register the + // cause of these new universes for improved diagnostics. let universe = self.infcx.universe(); - - if old_universe != universe { - let universe_info = match error_info { - Some(error_info) => error_info.to_universe_info(old_universe), - None => UniverseInfo::other(), - }; + if old_universe != universe && let Some(error_info) = error_info { + let universe_info = error_info.to_universe_info(old_universe); for u in (old_universe + 1)..=universe { self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone()); } @@ -69,15 +67,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { where T: TypeFoldable>, { - let old_universe = self.infcx.universe(); - let (instantiated, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); - - for u in (old_universe + 1)..=self.infcx.universe() { - self.borrowck_context.constraints.universe_causes.insert(u, UniverseInfo::other()); - } - instantiated } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 50d875dfa..1f383e533 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -50,7 +50,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; -use crate::session_diagnostics::MoveUnsized; +use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst}; use crate::{ borrow_set::BorrowSet, constraints::{OutlivesConstraint, OutlivesConstraintSet}, @@ -163,10 +163,6 @@ pub(crate) fn type_check<'mir, 'tcx>( debug!(?normalized_inputs_and_output); - for u in ty::UniverseIndex::ROOT..=infcx.universe() { - constraints.universe_causes.insert(u, UniverseInfo::other()); - } - let mut borrowck_context = BorrowCheckContext { universal_regions, location_table, @@ -306,11 +302,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { self.sanitize_place(place, location, context); } - fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { debug!(?constant, ?location, "visit_constant"); self.super_constant(constant, location); - let ty = self.sanitize_type(constant, constant.literal.ty()); + let ty = self.sanitize_type(constant, constant.const_.ty()); self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { let live_region_vid = @@ -332,7 +328,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( - constant.literal.ty(), + constant.const_.ty(), ty::Variance::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, locations, @@ -344,20 +340,20 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { constant, "bad constant user type {:?} vs {:?}: {:?}", annotation, - constant.literal.ty(), + constant.const_.ty(), terr, ); } } else { let tcx = self.tcx(); - let maybe_uneval = match constant.literal { - ConstantKind::Ty(ct) => match ct.kind() { + let maybe_uneval = match constant.const_ { + Const::Ty(ct) => match ct.kind() { ty::ConstKind::Unevaluated(_) => { - bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct) + bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct) } _ => None, }, - ConstantKind::Unevaluated(uv, _) => Some(uv), + Const::Unevaluated(uv, _) => Some(uv), _ => None, }; @@ -388,7 +384,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { check_err(self, promoted_body, ty, promoted_ty); } else { self.cx.ascribe_user_type( - constant.literal.ty(), + constant.const_.ty(), UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }), locations.span(&self.cx.body), ); @@ -396,7 +392,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); let normalized_ty = self.cx.normalize(unnormalized_ty, locations); - let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty; + let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty; if let Err(terr) = self.cx.eq_types( literal_ty, @@ -408,7 +404,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } } - if let ty::FnDef(def_id, args) = *constant.literal.ty().kind() { + if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args); self.cx.normalize_and_prove_instantiated_predicates( def_id, @@ -720,6 +716,9 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } PlaceTy::from_ty(fty) } + ProjectionElem::Subtype(_) => { + bug!("ProjectionElem::Subtype shouldn't exist in borrowck") + } ProjectionElem::OpaqueCast(ty) => { let ty = self.sanitize_type(place, ty); let ty = self.cx.normalize(ty, location); @@ -749,7 +748,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { PlaceContext::MutatingUse(_) => ty::Invariant, PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant, PlaceContext::NonMutatingUse( - Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | AddressOf + Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | AddressOf | Projection, ) => ty::Covariant, PlaceContext::NonUse(AscribeUserTy(variance)) => variance, @@ -1011,7 +1010,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } pub(super) fn register_predefined_opaques_in_new_solver(&mut self) { - // OK to use the identity substitutions for each opaque type key, since + // OK to use the identity arguments for each opaque type key, since // we remap opaques from HIR typeck back to their definition params. let opaques: Vec<_> = self .infcx @@ -1333,8 +1332,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!("terminator kind: {:?}", term.kind); match &term.kind { TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Terminate + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Return | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable @@ -1371,14 +1370,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; let (sig, map) = tcx.replace_late_bound_regions(sig, |br| { - use crate::renumber::{BoundRegionInfo, RegionCtxt}; + use crate::renumber::RegionCtxt; let region_ctxt_fn = || { let reg_info = match br.kind { - ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span), - ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(sym::anon), - ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name), - ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env), + ty::BoundRegionKind::BrAnon => sym::anon, + ty::BoundRegionKind::BrNamed(_, name) => name, + ty::BoundRegionKind::BrEnv => sym::env, }; RegionCtxt::LateBound(reg_info) @@ -1430,7 +1428,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .add_element(region_vid, term_location); } - self.check_call_inputs(body, term, &sig, args, term_location, *call_source); + self.check_call_inputs(body, term, func, &sig, args, term_location, *call_source); } TerminatorKind::Assert { cond, msg, .. } => { self.check_operand(cond, term_location); @@ -1550,25 +1548,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self, body, term, func, term_location, call_source))] fn check_call_inputs( &mut self, body: &Body<'tcx>, term: &Terminator<'tcx>, + func: &Operand<'tcx>, sig: &ty::FnSig<'tcx>, args: &[Operand<'tcx>], term_location: Location, call_source: CallSource, ) { - debug!("check_call_inputs({:?}, {:?})", sig, args); if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } - let func_ty = if let TerminatorKind::Call { func, .. } = &term.kind { - Some(func.ty(body, self.infcx.tcx)) - } else { - None - }; + let func_ty = func.ty(body, self.infcx.tcx); + if let ty::FnDef(def_id, _) = *func_ty.kind() { + if self.tcx().is_intrinsic(def_id) { + match self.tcx().item_name(def_id) { + sym::simd_shuffle => { + if !matches!(args[2], Operand::Constant(_)) { + self.tcx() + .sess + .emit_err(SimdShuffleLastConst { span: term.source_info.span }); + } + } + _ => {} + } + } + } debug!(?func_ty); for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { @@ -1576,7 +1585,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let op_arg_ty = self.normalize(op_arg_ty, term_location); let category = if call_source.from_hir_call() { - ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty)) + ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty))) } else { ConstraintCategory::Boring }; @@ -1608,12 +1617,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.assert_iscleanup(body, block_data, *target, is_cleanup); } } - TerminatorKind::Resume => { + TerminatorKind::UnwindResume => { if !is_cleanup { span_mirbug!(self, block_data, "resume on non-cleanup block!") } } - TerminatorKind::Terminate => { + TerminatorKind::UnwindTerminate(_) => { if !is_cleanup { span_mirbug!(self, block_data, "abort on non-cleanup block!") } @@ -1697,7 +1706,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { span_mirbug!(self, ctxt, "unwind on cleanup block") } } - UnwindAction::Unreachable | UnwindAction::Terminate => (), + UnwindAction::Unreachable | UnwindAction::Terminate(_) => (), } } @@ -1794,9 +1803,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!(?op, ?location, "check_operand"); if let Operand::Constant(constant) = op { - let maybe_uneval = match constant.literal { - ConstantKind::Val(..) | ConstantKind::Ty(_) => None, - ConstantKind::Unevaluated(uv, _) => Some(uv), + let maybe_uneval = match constant.const_ { + Const::Val(..) | Const::Ty(_) => None, + Const::Unevaluated(uv, _) => Some(uv), }; if let Some(uv) = maybe_uneval { @@ -2557,6 +2566,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | ProjectionElem::Subslice { .. } => { // other field access } + ProjectionElem::Subtype(_) => { + bug!("ProjectionElem::Subtype shouldn't exist in borrowck") + } } } } diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index e0c629562..c1f82e19c 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -11,7 +11,7 @@ use rustc_span::{Span, Symbol}; use crate::constraints::OutlivesConstraint; use crate::diagnostics::UniverseInfo; -use crate::renumber::{BoundRegionInfo, RegionCtxt}; +use crate::renumber::RegionCtxt; use crate::type_check::{InstantiateOpaqueType, Locations, TypeChecker}; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { @@ -126,10 +126,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> .placeholder_region(self.type_checker.infcx, placeholder); let reg_info = match placeholder.bound.kind { - ty::BoundRegionKind::BrAnon(Some(span)) => BoundRegionInfo::Span(span), - ty::BoundRegionKind::BrAnon(..) => BoundRegionInfo::Name(sym::anon), - ty::BoundRegionKind::BrNamed(_, name) => BoundRegionInfo::Name(name), - ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env), + ty::BoundRegionKind::BrAnon => sym::anon, + ty::BoundRegionKind::BrNamed(_, name) => name, + ty::BoundRegionKind::BrEnv => sym::env, }; if cfg!(debug_assertions) { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 56945f43f..af437f36b 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -21,13 +21,14 @@ use rustc_hir::BodyOwnerKind; use rustc_index::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_span::symbol::{kw, sym}; use rustc_span::Symbol; use std::iter; -use crate::renumber::{BoundRegionInfo, RegionCtxt}; +use crate::renumber::RegionCtxt; use crate::BorrowckInferCtxt; #[derive(Debug)] @@ -332,10 +333,16 @@ impl<'tcx> UniversalRegions<'tcx> { pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) { match self.defining_ty { DefiningTy::Closure(def_id, args) => { + let v = with_no_trimmed_paths!( + args[tcx.generics_of(def_id).parent_count..] + .iter() + .map(|arg| arg.to_string()) + .collect::>() + ); err.note(format!( - "defining type: {} with closure args {:#?}", + "defining type: {} with closure args [\n {},\n]", tcx.def_path_str_with_args(def_id, args), - &args[tcx.generics_of(def_id).parent_count..], + v.join(",\n "), )); // FIXME: It'd be nice to print the late-bound regions @@ -348,10 +355,16 @@ impl<'tcx> UniversalRegions<'tcx> { }); } DefiningTy::Generator(def_id, args, _) => { + let v = with_no_trimmed_paths!( + args[tcx.generics_of(def_id).parent_count..] + .iter() + .map(|arg| arg.to_string()) + .collect::>() + ); err.note(format!( - "defining type: {} with generator args {:#?}", + "defining type: {} with generator args [\n {},\n]", tcx.def_path_str_with_args(def_id, args), - &args[tcx.generics_of(def_id).parent_count..], + v.join(",\n "), )); // FIXME: As above, we'd like to print out the region @@ -433,9 +446,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { if !indices.indices.contains_key(&r) { let region_vid = { let name = r.get_name_or_anon(); - self.infcx.next_nll_region_var(FR, || { - RegionCtxt::LateBound(BoundRegionInfo::Name(name)) - }) + self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) }; debug!(?region_vid); @@ -467,9 +478,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { if !indices.indices.contains_key(&r) { let region_vid = { let name = r.get_name_or_anon(); - self.infcx.next_nll_region_var(FR, || { - RegionCtxt::LateBound(BoundRegionInfo::Name(name)) - }) + self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) }; debug!(?region_vid); @@ -567,7 +576,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } } - BodyOwnerKind::Const | BodyOwnerKind::Static(..) => { + BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => { let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); if self.mir_def.to_def_id() == typeck_root_def_id { let args = @@ -630,10 +639,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { }; let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); - let subst_mapping = - iter::zip(identity_args.regions(), fr_args.regions().map(|r| r.as_var())); + let arg_mapping = iter::zip(identity_args.regions(), fr_args.regions().map(|r| r.as_var())); - UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect(), fr_static } + UniversalRegionIndices { indices: global_mapping.chain(arg_mapping).collect(), fr_static } } fn compute_inputs_and_output( @@ -783,7 +791,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { _ => sym::anon, }; - self.next_nll_region_var(origin, || RegionCtxt::Bound(BoundRegionInfo::Name(name))) + self.next_nll_region_var(origin, || RegionCtxt::Bound(name)) }; indices.insert_late_bound_region(liberated_region, region_vid.as_var()); @@ -813,9 +821,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { if !indices.indices.contains_key(&r) { let region_vid = { let name = r.get_name_or_anon(); - self.next_nll_region_var(FR, || { - RegionCtxt::LateBound(BoundRegionInfo::Name(name)) - }) + self.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) }; debug!(?region_vid); @@ -835,9 +841,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { if !indices.indices.contains_key(&r) { let region_vid = { let name = r.get_name_or_anon(); - self.next_nll_region_var(FR, || { - RegionCtxt::LateBound(BoundRegionInfo::Name(name)) - }) + self.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) }; indices.insert_late_bound_region(r, region_vid.as_var()); -- cgit v1.2.3