diff options
| author | Folkert de Vries <flokkievids@gmail.com> | 2025-08-03 10:44:41 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-03 10:44:41 +0000 |
| commit | c691374cc19d583103f3da5d655efb308a1648b9 (patch) | |
| tree | 767496caef5b54e56f46a834d0d612705ce5e488 /compiler/rustc_borrowck/src | |
| parent | daa742afe5970109c1e15b391226f78087b10439 (diff) | |
| parent | 49aa0ecc7b251003e61c38a56471195a2d3dabee (diff) | |
| download | rust-c691374cc19d583103f3da5d655efb308a1648b9.tar.gz rust-c691374cc19d583103f3da5d655efb308a1648b9.zip | |
Merge pull request #1889 from rust-lang/rustc-pull
Rustc pull update
Diffstat (limited to 'compiler/rustc_borrowck/src')
9 files changed, 444 insertions, 360 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 040a0607db5..be8b3f0bc1e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1290,6 +1290,58 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { span, format!("if `{ty}` implemented `Clone`, you could clone the value"), ); + } else if let ty::Adt(_, _) = ty.kind() + && let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait() + { + // For cases like `Option<NonClone>`, where `Option<T>: Clone` if `T: Clone`, we point + // at the types that should be `Clone`. + let ocx = ObligationCtxt::new_with_diagnostics(self.infcx); + let cause = ObligationCause::misc(expr.span, self.mir_def_id()); + ocx.register_bound(cause, self.infcx.param_env, ty, clone_trait); + let errors = ocx.select_all_or_error(); + if errors.iter().all(|error| { + match error.obligation.predicate.as_clause().and_then(|c| c.as_trait_clause()) { + Some(clause) => match clause.self_ty().skip_binder().kind() { + ty::Adt(def, _) => def.did().is_local() && clause.def_id() == clone_trait, + _ => false, + }, + None => false, + } + }) { + let mut type_spans = vec![]; + let mut types = FxIndexSet::default(); + for clause in errors + .iter() + .filter_map(|e| e.obligation.predicate.as_clause()) + .filter_map(|c| c.as_trait_clause()) + { + let ty::Adt(def, _) = clause.self_ty().skip_binder().kind() else { continue }; + type_spans.push(self.infcx.tcx.def_span(def.did())); + types.insert( + self.infcx + .tcx + .short_string(clause.self_ty().skip_binder(), &mut err.long_ty_path()), + ); + } + let mut span: MultiSpan = type_spans.clone().into(); + for sp in type_spans { + span.push_span_label(sp, "consider implementing `Clone` for this type"); + } + span.push_span_label(expr.span, "you could clone this value"); + let types: Vec<_> = types.into_iter().collect(); + let msg = match &types[..] { + [only] => format!("`{only}`"), + [head @ .., last] => format!( + "{} and `{last}`", + head.iter().map(|t| format!("`{t}`")).collect::<Vec<_>>().join(", ") + ), + [] => unreachable!(), + }; + err.span_note( + span, + format!("if {msg} implemented `Clone`, you could clone the value"), + ); + } } } @@ -2332,7 +2384,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let Some(body_expr) = finder.body_expr && let Some(loop_span) = finder.loop_span && let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id) - && let Some(trait_did) = tcx.trait_of_item(def_id) + && let Some(trait_did) = tcx.trait_of_assoc(def_id) && tcx.is_diagnostic_item(sym::Iterator, trait_did) { if let Some(loop_bind) = finder.loop_bind { @@ -2481,13 +2533,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // Check that the parent of the closure is a method call, // with receiver matching with local's type (modulo refs) - if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id) { - if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind { - let recv_ty = typeck_results.expr_ty(recv); + if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id) + && let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind + { + let recv_ty = typeck_results.expr_ty(recv); - if recv_ty.peel_refs() != local_ty { - return; - } + if recv_ty.peel_refs() != local_ty { + return; } } @@ -2753,16 +2805,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // With the place of a union and a field access into it, we traverse the second // borrowed place and look for an access to a different field of the same union. for (place_base, elem) in second_borrowed_place.iter_projections().rev() { - if let ProjectionElem::Field(field, _) = elem { - if let Some(union_ty) = union_ty(place_base) { - if field != target_field && place_base == target_base { - return Some(( - self.describe_any_place(place_base), - self.describe_any_place(first_borrowed_place.as_ref()), - self.describe_any_place(second_borrowed_place.as_ref()), - union_ty.to_string(), - )); - } + if let ProjectionElem::Field(field, _) = elem + && let Some(union_ty) = union_ty(place_base) + { + if field != target_field && place_base == target_base { + return Some(( + self.describe_any_place(place_base), + self.describe_any_place(first_borrowed_place.as_ref()), + self.describe_any_place(second_borrowed_place.as_ref()), + union_ty.to_string(), + )); } } } @@ -2949,16 +3001,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { from_closure: false, .. } = explanation - { - if let Err(diag) = self.try_report_cannot_return_reference_to_local( + && let Err(diag) = self.try_report_cannot_return_reference_to_local( borrow, borrow_span, span, category, opt_place_desc.as_ref(), - ) { - return diag; - } + ) + { + return diag; } let name = format!("`{name}`"); @@ -3720,30 +3771,30 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let loan_span = loan_spans.args_or_use(); let descr_place = self.describe_any_place(place.as_ref()); - if let BorrowKind::Fake(_) = loan.kind { - if let Some(section) = self.classify_immutable_section(loan.assigned_place) { - let mut err = self.cannot_mutate_in_immutable_section( - span, - loan_span, - &descr_place, - section, - "assign", - ); + if let BorrowKind::Fake(_) = loan.kind + && let Some(section) = self.classify_immutable_section(loan.assigned_place) + { + let mut err = self.cannot_mutate_in_immutable_section( + span, + loan_span, + &descr_place, + section, + "assign", + ); - loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - match kind { - hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - BorrowUseInClosure { var_span } - } + loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + match kind { + hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + BorrowUseInClosure { var_span } } - }); + } + }); - self.buffer_error(err); + self.buffer_error(err); - return; - } + return; } let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place); @@ -3996,119 +4047,116 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}", target, stmt ); - if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind { - if let Some(assigned_to) = place.as_local() { - debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} \ + if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind + && let Some(assigned_to) = place.as_local() + { + debug!( + "annotate_argument_and_return_for_borrow: assigned_to={:?} \ rvalue={:?}", - assigned_to, rvalue - ); - // Check if our `target` was captured by a closure. - if let Rvalue::Aggregate( - box AggregateKind::Closure(def_id, args), - operands, - ) = rvalue - { - let def_id = def_id.expect_local(); - for operand in operands { - let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = - operand - else { - continue; - }; - debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from - ); + assigned_to, rvalue + ); + // Check if our `target` was captured by a closure. + if let Rvalue::Aggregate(box AggregateKind::Closure(def_id, args), operands) = + rvalue + { + let def_id = def_id.expect_local(); + for operand in operands { + let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = + operand + else { + continue; + }; + debug!( + "annotate_argument_and_return_for_borrow: assigned_from={:?}", + assigned_from + ); - // Find the local from the operand. - let Some(assigned_from_local) = - assigned_from.local_or_deref_local() - else { - continue; - }; + // Find the local from the operand. + let Some(assigned_from_local) = assigned_from.local_or_deref_local() + else { + continue; + }; - if assigned_from_local != target { - continue; - } + if assigned_from_local != target { + continue; + } - // If a closure captured our `target` and then assigned - // into a place then we should annotate the closure in - // case it ends up being assigned into the return place. - annotated_closure = - self.annotate_fn_sig(def_id, args.as_closure().sig()); - debug!( - "annotate_argument_and_return_for_borrow: \ + // If a closure captured our `target` and then assigned + // into a place then we should annotate the closure in + // case it ends up being assigned into the return place. + annotated_closure = + self.annotate_fn_sig(def_id, args.as_closure().sig()); + debug!( + "annotate_argument_and_return_for_borrow: \ annotated_closure={:?} assigned_from_local={:?} \ assigned_to={:?}", - annotated_closure, assigned_from_local, assigned_to - ); + annotated_closure, assigned_from_local, assigned_to + ); - if assigned_to == mir::RETURN_PLACE { - // If it was assigned directly into the return place, then - // return now. - return annotated_closure; - } else { - // Otherwise, update the target. - target = assigned_to; - } + if assigned_to == mir::RETURN_PLACE { + // If it was assigned directly into the return place, then + // return now. + return annotated_closure; + } else { + // Otherwise, update the target. + target = assigned_to; } - - // If none of our closure's operands matched, then skip to the next - // statement. - continue; } - // Otherwise, look at other types of assignment. - let assigned_from = match rvalue { - Rvalue::Ref(_, _, assigned_from) => assigned_from, - Rvalue::Use(operand) => match operand { - Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { - assigned_from - } - _ => continue, - }, + // If none of our closure's operands matched, then skip to the next + // statement. + continue; + } + + // Otherwise, look at other types of assignment. + let assigned_from = match rvalue { + Rvalue::Ref(_, _, assigned_from) => assigned_from, + Rvalue::Use(operand) => match operand { + Operand::Copy(assigned_from) | Operand::Move(assigned_from) => { + assigned_from + } _ => continue, - }; - debug!( - "annotate_argument_and_return_for_borrow: \ + }, + _ => continue, + }; + debug!( + "annotate_argument_and_return_for_borrow: \ assigned_from={:?}", - assigned_from, - ); + assigned_from, + ); - // Find the local from the rvalue. - let Some(assigned_from_local) = assigned_from.local_or_deref_local() else { - continue; - }; - debug!( - "annotate_argument_and_return_for_borrow: \ + // Find the local from the rvalue. + let Some(assigned_from_local) = assigned_from.local_or_deref_local() else { + continue; + }; + debug!( + "annotate_argument_and_return_for_borrow: \ assigned_from_local={:?}", - assigned_from_local, - ); + assigned_from_local, + ); - // Check if our local matches the target - if so, we've assigned our - // borrow to a new place. - if assigned_from_local != target { - continue; - } + // Check if our local matches the target - if so, we've assigned our + // borrow to a new place. + if assigned_from_local != target { + continue; + } - // If we assigned our `target` into a new place, then we should - // check if it was the return place. - debug!( - "annotate_argument_and_return_for_borrow: \ + // If we assigned our `target` into a new place, then we should + // check if it was the return place. + debug!( + "annotate_argument_and_return_for_borrow: \ assigned_from_local={:?} assigned_to={:?}", - assigned_from_local, assigned_to - ); - if assigned_to == mir::RETURN_PLACE { - // If it was then return the annotated closure if there was one, - // else, annotate this function. - return annotated_closure.or_else(fallback); - } - - // If we didn't assign into the return place, then we just update - // the target. - target = assigned_to; + assigned_from_local, assigned_to + ); + if assigned_to == mir::RETURN_PLACE { + // If it was then return the annotated closure if there was one, + // else, annotate this function. + return annotated_closure.or_else(fallback); } + + // If we didn't assign into the return place, then we just update + // the target. + target = assigned_to; } } @@ -4120,32 +4168,31 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ); if let TerminatorKind::Call { destination, target: Some(_), args, .. } = &terminator.kind + && let Some(assigned_to) = destination.as_local() { - if let Some(assigned_to) = destination.as_local() { + debug!( + "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", + assigned_to, args + ); + for operand in args { + let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = + &operand.node + else { + continue; + }; debug!( - "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}", - assigned_to, args + "annotate_argument_and_return_for_borrow: assigned_from={:?}", + assigned_from, ); - for operand in args { - let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) = - &operand.node - else { - continue; - }; + + if let Some(assigned_from_local) = assigned_from.local_or_deref_local() { debug!( - "annotate_argument_and_return_for_borrow: assigned_from={:?}", - assigned_from, + "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", + assigned_from_local, ); - if let Some(assigned_from_local) = assigned_from.local_or_deref_local() { - debug!( - "annotate_argument_and_return_for_borrow: assigned_from_local={:?}", - assigned_from_local, - ); - - if assigned_to == mir::RETURN_PLACE && assigned_from_local == target { - return annotated_closure.or_else(fallback); - } + if assigned_to == mir::RETURN_PLACE && assigned_from_local == target { + return annotated_closure.or_else(fallback); } } } @@ -4244,10 +4291,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // as the HIR doesn't have full types for closure arguments. let return_ty = sig.output().skip_binder(); let mut return_span = fn_decl.output.span(); - if let hir::FnRetTy::Return(ty) = &fn_decl.output { - if let hir::TyKind::Ref(lifetime, _) = ty.kind { - return_span = lifetime.ident.span; - } + if let hir::FnRetTy::Return(ty) = &fn_decl.output + && let hir::TyKind::Ref(lifetime, _) = ty.kind + { + return_span = lifetime.ident.span; } Some(AnnotatedBorrowFnSignature::NamedFunction { diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index f9e52239d6f..fdca6b56540 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -341,7 +341,7 @@ impl<'tcx> BorrowExplanation<'tcx> { } } } else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() { - let sp = info.span.find_oldest_ancestor_in_same_ctxt(); + let sp = info.span.find_ancestor_not_from_macro().unwrap_or(info.span); if info.tail_result_is_ignored { // #85581: If the first mutable borrow's scope contains // the second borrow, this suggestion isn't helpful. @@ -917,30 +917,29 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { if let TerminatorKind::Call { destination, target: Some(block), args, .. } = &terminator.kind + && let Some(dest) = destination.as_local() { - if let Some(dest) = destination.as_local() { - debug!( - "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", - target, dest, args - ); - // Check if one of the arguments to this function is the target place. - let found_target = args.iter().any(|arg| { - if let Operand::Move(place) = arg.node { - if let Some(potential) = place.as_local() { - potential == target - } else { - false - } + debug!( + "was_captured_by_trait_object: target={:?} dest={:?} args={:?}", + target, dest, args + ); + // Check if one of the arguments to this function is the target place. + let found_target = args.iter().any(|arg| { + if let Operand::Move(place) = arg.node { + if let Some(potential) = place.as_local() { + potential == target } else { false } - }); - - // If it is, follow this to the next block and update the target. - if found_target { - target = dest; - queue.push(block.start_location()); + } else { + false } + }); + + // If it is, follow this to the next block and update the target. + if found_target { + target = dest; + queue.push(block.start_location()); } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 9ad91d605a7..56fdaf1c724 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -266,48 +266,44 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { args, .. } = &terminator.kind + && let ty::FnDef(id, _) = *const_.ty().kind() { - if let ty::FnDef(id, _) = *const_.ty().kind() { - debug!("add_moved_or_invoked_closure_note: id={:?}", id); - if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) { - let closure = match args.first() { - Some(Spanned { - node: Operand::Copy(place) | Operand::Move(place), .. - }) if target == place.local_or_deref_local() => { - place.local_or_deref_local().unwrap() - } - _ => return false, - }; + debug!("add_moved_or_invoked_closure_note: id={:?}", id); + if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) { + let closure = match args.first() { + Some(Spanned { node: Operand::Copy(place) | Operand::Move(place), .. }) + if target == place.local_or_deref_local() => + { + place.local_or_deref_local().unwrap() + } + _ => return false, + }; - debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); - if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() { - let did = did.expect_local(); - if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { - diag.subdiagnostic(OnClosureNote::InvokedTwice { - place_name: &ty::place_to_string_for_capture( - self.infcx.tcx, - hir_place, - ), - span: *span, - }); - return true; - } + debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); + if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() { + let did = did.expect_local(); + if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { + diag.subdiagnostic(OnClosureNote::InvokedTwice { + place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place), + span: *span, + }); + return true; } } } } // Check if we are just moving a closure after it has been invoked. - if let Some(target) = target { - if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() { - let did = did.expect_local(); - if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { - diag.subdiagnostic(OnClosureNote::MovedTwice { - place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place), - span: *span, - }); - return true; - } + if let Some(target) = target + && let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() + { + let did = did.expect_local(); + if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { + diag.subdiagnostic(OnClosureNote::MovedTwice { + place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place), + span: *span, + }); + return true; } } false @@ -942,7 +938,7 @@ impl<'tcx> BorrowedContentSource<'tcx> { fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> { match *func.kind() { ty::FnDef(def_id, args) => { - let trait_id = tcx.trait_of_item(def_id)?; + let trait_id = tcx.trait_of_assoc(def_id)?; if tcx.is_lang_item(trait_id, LangItem::Deref) || tcx.is_lang_item(trait_id, LangItem::DerefMut) diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 447bf7d091a..1067f1e40ef 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -115,10 +115,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { fn append_to_grouped_errors( &self, grouped_errors: &mut Vec<GroupedMoveError<'tcx>>, - error: MoveError<'tcx>, + MoveError { place: original_path, location, kind }: MoveError<'tcx>, ) { - let MoveError { place: original_path, location, kind } = error; - // Note: that the only time we assign a place isn't a temporary // to a user variable is when initializing it. // If that ever stops being the case, then the ever initialized @@ -128,36 +126,35 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .statements .get(location.statement_index) .map(|stmt| &stmt.kind) + && let Some(local) = place.as_local() { - if let Some(local) = place.as_local() { - let local_decl = &self.body.local_decls[local]; - // opt_match_place is the - // match_span is the span of the expression being matched on - // match *x.y { ... } match_place is Some(*x.y) - // ^^^^ match_span is the span of *x.y - // - // opt_match_place is None for let [mut] x = ... statements, - // whether or not the right-hand side is a place expression - if let LocalInfo::User(BindingForm::Var(VarBindingForm { - opt_match_place: Some((opt_match_place, match_span)), - binding_mode: _, - opt_ty_info: _, - pat_span: _, - })) = *local_decl.local_info() - { - let stmt_source_info = self.body.source_info(location); - self.append_binding_error( - grouped_errors, - kind, - original_path, - *move_from, - local, - opt_match_place, - match_span, - stmt_source_info.span, - ); - return; - } + let local_decl = &self.body.local_decls[local]; + // opt_match_place is the + // match_span is the span of the expression being matched on + // match *x.y { ... } match_place is Some(*x.y) + // ^^^^ match_span is the span of *x.y + // + // opt_match_place is None for let [mut] x = ... statements, + // whether or not the right-hand side is a place expression + if let LocalInfo::User(BindingForm::Var(VarBindingForm { + opt_match_place: Some((opt_match_place, match_span)), + binding_mode: _, + opt_ty_info: _, + pat_span: _, + })) = *local_decl.local_info() + { + let stmt_source_info = self.body.source_info(location); + self.append_binding_error( + grouped_errors, + kind, + original_path, + *move_from, + local, + opt_match_place, + match_span, + stmt_source_info.span, + ); + return; } } @@ -251,54 +248,47 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } fn report(&mut self, error: GroupedMoveError<'tcx>) { - let (mut err, err_span) = { - let (span, use_spans, original_path, kind) = match error { - GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. } - | GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => { - (span, None, original_path, kind) - } - GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => { - (use_spans.args_or_use(), Some(use_spans), original_path, kind) - } - }; - debug!( - "report: original_path={:?} span={:?}, kind={:?} \ - original_path.is_upvar_field_projection={:?}", - original_path, - span, - kind, - self.is_upvar_field_projection(original_path.as_ref()) - ); - if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) { - // If the type may implement Copy, skip the error. - // It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check - self.dcx().span_delayed_bug( + let (span, use_spans, original_path, kind) = match error { + GroupedMoveError::MovesFromPlace { span, original_path, ref kind, .. } + | GroupedMoveError::MovesFromValue { span, original_path, ref kind, .. } => { + (span, None, original_path, kind) + } + GroupedMoveError::OtherIllegalMove { use_spans, original_path, ref kind } => { + (use_spans.args_or_use(), Some(use_spans), original_path, kind) + } + }; + debug!( + "report: original_path={:?} span={:?}, kind={:?} \ + original_path.is_upvar_field_projection={:?}", + original_path, + span, + kind, + self.is_upvar_field_projection(original_path.as_ref()) + ); + if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) { + // If the type may implement Copy, skip the error. + // It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check + self.dcx() + .span_delayed_bug(span, "Type may implement copy, but there is no other error."); + return; + } + let mut err = match kind { + &IllegalMoveOriginKind::BorrowedContent { target_place } => self + .report_cannot_move_from_borrowed_content( + original_path, + target_place, span, - "Type may implement copy, but there is no other error.", - ); - return; + use_spans, + ), + &IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { + self.cannot_move_out_of_interior_of_drop(span, ty) + } + &IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => { + self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index)) } - ( - match kind { - &IllegalMoveOriginKind::BorrowedContent { target_place } => self - .report_cannot_move_from_borrowed_content( - original_path, - target_place, - span, - use_spans, - ), - &IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { - self.cannot_move_out_of_interior_of_drop(span, ty) - } - &IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => { - self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index)) - } - }, - span, - ) }; - self.add_move_hints(error, &mut err, err_span); + self.add_move_hints(error, &mut err, span); self.buffer_error(err); } @@ -483,7 +473,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.cannot_move_out_of_interior_noncopy(span, ty, None) } ty::Closure(def_id, closure_args) - if def_id.as_local() == Some(self.mir_def_id()) && upvar_field.is_some() => + if def_id.as_local() == Some(self.mir_def_id()) + && let Some(upvar_field) = upvar_field => { let closure_kind_ty = closure_args.as_closure().kind_ty(); let closure_kind = match closure_kind_ty.to_opt_closure_kind() { @@ -496,7 +487,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let capture_description = format!("captured variable in an `{closure_kind}` closure"); - let upvar = &self.upvars[upvar_field.unwrap().index()]; + let upvar = &self.upvars[upvar_field.index()]; let upvar_hir_id = upvar.get_root_variable(); let upvar_name = upvar.to_string(tcx); let upvar_span = tcx.hir_span(upvar_hir_id); @@ -606,7 +597,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } // No binding. Nothing to suggest. GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => { - let use_span = use_spans.var_or_use(); + let mut use_span = use_spans.var_or_use(); let place_ty = original_path.ty(self.body, self.infcx.tcx).ty; let place_desc = match self.describe_place(original_path.as_ref()) { Some(desc) => format!("`{desc}`"), @@ -623,6 +614,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ); } + if let Some(upvar_field) = self + .prefixes(original_path.as_ref(), PrefixSet::All) + .find_map(|p| self.is_upvar_field_projection(p)) + { + // Look for the introduction of the original binding being moved. + let upvar = &self.upvars[upvar_field.index()]; + let upvar_hir_id = upvar.get_root_variable(); + use_span = match self.infcx.tcx.parent_hir_node(upvar_hir_id) { + hir::Node::Param(param) => { + // Instead of pointing at the path where we access the value within a + // closure, we point at the type of the outer `fn` argument. + param.ty_span + } + hir::Node::LetStmt(stmt) => match (stmt.ty, stmt.init) { + // We point at the type of the outer let-binding. + (Some(ty), _) => ty.span, + // We point at the initializer of the outer let-binding, but only if it + // isn't something that spans multiple lines, like a closure, as the + // ASCII art gets messy. + (None, Some(init)) + if !self.infcx.tcx.sess.source_map().is_multiline(init.span) => + { + init.span + } + _ => use_span, + }, + _ => use_span, + }; + } + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, ty: place_ty, @@ -630,12 +651,22 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { span: use_span, }); + let mut pointed_at_span = false; use_spans.args_subdiag(err, |args_span| { + if args_span == span || args_span == use_span { + pointed_at_span = true; + } crate::session_diagnostics::CaptureArgLabel::MoveOutPlace { - place: place_desc, + place: place_desc.clone(), args_span, } }); + if !pointed_at_span && use_span != span { + err.subdiagnostic(crate::session_diagnostics::CaptureArgLabel::MoveOutPlace { + place: place_desc, + args_span: span, + }); + } self.add_note_for_packed_struct_derive(err, original_path.local); } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index a06540f8325..5d9416b59fc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -682,7 +682,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } let my_def = self.body.source.def_id(); let Some(td) = - self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x)) + self.infcx.tcx.impl_of_assoc(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x)) else { return (false, false, None); }; @@ -880,7 +880,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let opt_suggestions = tcx .typeck(path_segment.hir_id.owner.def_id) .type_dependent_def_id(expr.hir_id) - .and_then(|def_id| tcx.impl_of_method(def_id)) + .and_then(|def_id| tcx.impl_of_assoc(def_id)) .map(|def_id| tcx.associated_items(def_id)) .map(|assoc_items| { assoc_items @@ -1056,7 +1056,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .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)) + .and_then(|def_id| self.infcx.tcx.impl_of_assoc(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() diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index edd14d155f6..517f9e88cd9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -528,15 +528,15 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { // match_adt_and_segment in this case. Res::Def(DefKind::TyAlias, _) => (), _ => { - if let Some(last_segment) = path.segments.last() { - if let Some(highlight) = self.match_adt_and_segment( + if let Some(last_segment) = path.segments.last() + && let Some(highlight) = self.match_adt_and_segment( args, needle_fr, last_segment, search_stack, - ) { - return Some(highlight); - } + ) + { + return Some(highlight); } } } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 5f1b655c6b6..68f1637e07e 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -822,10 +822,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { continue; } - if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements { - if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) { - continue; - } + if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements + && self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) + { + continue; } // Type-test failed. Report the error. @@ -1479,40 +1479,36 @@ impl<'tcx> RegionInferenceContext<'tcx> { shorter_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>, ) -> RegionRelationCheckResult { - if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { + if let Some(propagated_outlives_requirements) = propagated_outlives_requirements // Shrink `longer_fr` until we find a non-local region (if we do). // We'll call it `fr-` -- it's ever so slightly smaller than // `longer_fr`. - if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr) - { - debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus); + && let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr) + { + debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus); - let blame_span_category = self.find_outlives_blame_span( - longer_fr, - NllRegionVariableOrigin::FreeRegion, - shorter_fr, - ); + let blame_span_category = self.find_outlives_blame_span( + longer_fr, + NllRegionVariableOrigin::FreeRegion, + shorter_fr, + ); - // Grow `shorter_fr` until we find some non-local regions. (We - // always will.) We'll call them `shorter_fr+` -- they're ever - // so slightly larger than `shorter_fr`. - let shorter_fr_plus = - self.universal_region_relations.non_local_upper_bounds(shorter_fr); - debug!( - "try_propagate_universal_region_error: shorter_fr_plus={:?}", - shorter_fr_plus - ); - for fr in shorter_fr_plus { - // Push the constraint `fr-: shorter_fr+` - propagated_outlives_requirements.push(ClosureOutlivesRequirement { - subject: ClosureOutlivesSubject::Region(fr_minus), - outlived_free_region: fr, - blame_span: blame_span_category.1.span, - category: blame_span_category.0, - }); - } - return RegionRelationCheckResult::Propagated; + // Grow `shorter_fr` until we find some non-local regions. (We + // always will.) We'll call them `shorter_fr+` -- they're ever + // so slightly larger than `shorter_fr`. + let shorter_fr_plus = + self.universal_region_relations.non_local_upper_bounds(shorter_fr); + debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus); + for fr in shorter_fr_plus { + // Push the constraint `fr-: shorter_fr+` + propagated_outlives_requirements.push(ClosureOutlivesRequirement { + subject: ClosureOutlivesSubject::Region(fr_minus), + outlived_free_region: fr, + blame_span: blame_span_category.1.span, + category: blame_span_category.0, + }); } + return RegionRelationCheckResult::Propagated; } RegionRelationCheckResult::Error @@ -2085,11 +2081,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { let locations = self.scc_values.locations_outlived_by(scc); for location in locations { let bb = &body[location.block]; - if let Some(terminator) = &bb.terminator { + if let Some(terminator) = &bb.terminator // terminator of a loop should be TerminatorKind::FalseUnwind - if let TerminatorKind::FalseUnwind { .. } = terminator.kind { - return Some(location); - } + && let TerminatorKind::FalseUnwind { .. } = terminator.kind + { + return Some(location); } } None diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d500088c259..f5fedbf95c1 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -669,24 +669,24 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } - if let Some(annotation_index) = self.rvalue_user_ty(rv) { - if let Err(terr) = self.relate_type_and_user_type( + if let Some(annotation_index) = self.rvalue_user_ty(rv) + && let Err(terr) = self.relate_type_and_user_type( rv_ty, ty::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, location.to_locations(), ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg), - ) { - let annotation = &self.user_type_annotations[annotation_index]; - span_mirbug!( - self, - stmt, - "bad user type on rvalue ({:?} = {:?}): {:?}", - annotation, - rv_ty, - terr - ); - } + ) + { + let annotation = &self.user_type_annotations[annotation_index]; + span_mirbug!( + self, + stmt, + "bad user type on rvalue ({:?} = {:?}): {:?}", + annotation, + rv_ty, + terr + ); } if !self.unsized_feature_enabled() { @@ -1761,7 +1761,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); assert!(!matches!( - tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)), + tcx.impl_of_assoc(def_id).map(|imp| tcx.def_kind(imp)), Some(DefKind::Impl { of_trait: true }) )); self.prove_predicates( diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index f138f265320..240c9a5223b 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -969,13 +969,28 @@ fn for_each_late_bound_region_in_item<'tcx>( mir_def_id: LocalDefId, mut f: impl FnMut(ty::Region<'tcx>), ) { - if !tcx.def_kind(mir_def_id).is_fn_like() { - return; - } + let bound_vars = match tcx.def_kind(mir_def_id) { + DefKind::Fn | DefKind::AssocFn => { + tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id)) + } + // We extract the bound vars from the deduced closure signature, since we may have + // only deduced that a param in the closure signature is late-bound from a constraint + // that we discover during typeck. + DefKind::Closure => { + let ty = tcx.type_of(mir_def_id).instantiate_identity(); + match *ty.kind() { + ty::Closure(_, args) => args.as_closure().sig().bound_vars(), + ty::CoroutineClosure(_, args) => { + args.as_coroutine_closure().coroutine_closure_sig().bound_vars() + } + ty::Coroutine(_, _) | ty::Error(_) => return, + _ => unreachable!("unexpected type for closure: {ty}"), + } + } + _ => return, + }; - for (idx, bound_var) in - tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id)).iter().enumerate() - { + for (idx, bound_var) in bound_vars.iter().enumerate() { if let ty::BoundVariableKind::Region(kind) = bound_var { let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind); let liberated_region = ty::Region::new_late_param(tcx, mir_def_id.to_def_id(), kind); |
