From 5d1b22051885b8b517b2dcbda1b59515d0c53d0a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 24 Jun 2025 17:30:04 +0000 Subject: [PATCH 1/2] Fast path for coercions of TY == TY --- compiler/rustc_hir_typeck/src/coercion.rs | 24 +++++++++++++++++++ tests/ui/nll/issue-52663-trait-object.stderr | 1 - ...regions-close-over-type-parameter-2.stderr | 1 - 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 24092c01125fc..2a8d5d200ed4e 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -206,6 +206,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return self.coerce_from_inference_variable(a, b); } + // No coercion needed; types are identical. The only exception is when we have + // a mutable reference, which needs a pair of reborrow adjustments inserted. + if a == b { + if let ty::Ref(_, pointee, ty::Mutability::Mut) = *a.kind() { + return Ok(InferOk { + value: ( + vec![ + Adjustment { kind: Adjust::Deref(None), target: pointee }, + Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { + allow_two_phase_borrow: AllowTwoPhase::No, + })), + target: a, + }, + ], + a, + ), + obligations: Default::default(), + }); + } else { + return Ok(InferOk { value: (vec![], a), obligations: Default::default() }); + } + } + // Consider coercing the subtype to a DST // // NOTE: this is wrapped in a `commit_if_ok` because it creates diff --git a/tests/ui/nll/issue-52663-trait-object.stderr b/tests/ui/nll/issue-52663-trait-object.stderr index fe55d8d49ad77..af5cdb2dd5a03 100644 --- a/tests/ui/nll/issue-52663-trait-object.stderr +++ b/tests/ui/nll/issue-52663-trait-object.stderr @@ -6,7 +6,6 @@ LL | let tmp0 = 3; LL | let tmp1 = &tmp0; | ^^^^^ borrowed value does not live long enough LL | Box::new(tmp1) as Box - | ----------------------------------- borrow later captured here by trait object LL | }; | - `tmp0` dropped here while still borrowed diff --git a/tests/ui/span/regions-close-over-type-parameter-2.stderr b/tests/ui/span/regions-close-over-type-parameter-2.stderr index 3849b9eef08fb..c73d19e71d5ad 100644 --- a/tests/ui/span/regions-close-over-type-parameter-2.stderr +++ b/tests/ui/span/regions-close-over-type-parameter-2.stderr @@ -6,7 +6,6 @@ LL | let tmp0 = 3; LL | let tmp1 = &tmp0; | ^^^^^ borrowed value does not live long enough LL | repeater3(tmp1) - | --------------- borrow later captured here by trait object LL | }; | - `tmp0` dropped here while still borrowed From 34842e54003758e7b79569f5ea97c196cfe25017 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 24 Jun 2025 18:41:02 +0000 Subject: [PATCH 2/2] Restore error message for one case --- .../src/diagnostics/explain_borrow.rs | 27 ++++++++++++------- tests/ui/nll/issue-52663-trait-object.stderr | 1 + 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 095c0df98acc1..afc414f2bb884 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -781,8 +781,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { } else { LaterUseKind::FakeLetRead } - } else if self.was_captured_by_trait_object(borrow) { - LaterUseKind::TraitCapture + } else if let Some(unsize_span) = self.was_captured_by_trait_object(borrow) { + // We drilled down the span to the actual location of the unsize, rather + // than the location of the borrow. + return (LaterUseKind::TraitCapture, unsize_span, None); } else if location.statement_index == block.statements.len() { if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } = &block.terminator().kind @@ -819,7 +821,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// Checks if a borrowed value was captured by a trait object. We do this by /// looking forward in the MIR from the reserve location and checking if we see /// an unsized cast to a trait object on our data. - fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool { + fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> Option { // Start at the reserve location, find the place that we want to see cast to a trait object. let location = borrow.reserve_location; let block = &self.body[location.block]; @@ -835,10 +837,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { if let Some(local) = place.as_local() { local } else { - return false; + return None; } } else { - return false; + return None; }; debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue); @@ -885,7 +887,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { if from == target { debug!("was_captured_by_trait_object: ty={:?}", ty); // Check the type for a trait object. - return match ty.kind() { + let matches = match ty.kind() { // `&dyn Trait` ty::Ref(_, ty, _) if ty.is_trait() => true, // `Box` @@ -898,11 +900,16 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { // Anything else. _ => false, }; + if matches { + return Some(stmt.source_info.span); + } else { + return None; + } } } - return false; + return None; } - _ => return false, + _ => return None, } } _ => {} @@ -926,7 +933,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { ); // 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 Operand::Move(place) | Operand::Copy(place) = arg.node { if let Some(potential) = place.as_local() { potential == target } else { @@ -950,6 +957,6 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { } // We didn't find anything and ran out of locations to check. - false + None } } diff --git a/tests/ui/nll/issue-52663-trait-object.stderr b/tests/ui/nll/issue-52663-trait-object.stderr index af5cdb2dd5a03..fe55d8d49ad77 100644 --- a/tests/ui/nll/issue-52663-trait-object.stderr +++ b/tests/ui/nll/issue-52663-trait-object.stderr @@ -6,6 +6,7 @@ LL | let tmp0 = 3; LL | let tmp1 = &tmp0; | ^^^^^ borrowed value does not live long enough LL | Box::new(tmp1) as Box + | ----------------------------------- borrow later captured here by trait object LL | }; | - `tmp0` dropped here while still borrowed