From 387b4871ba7b7b6a1640e78a423b275fa1721e92 Mon Sep 17 00:00:00 2001 From: Pieter-Louis Schoeman Date: Wed, 20 May 2026 19:26:53 +0200 Subject: [PATCH] Preserve generic reborrow while fixing identity moves Ordinary identity move/coercion contexts should not become Adjust::GenericReborrow merely because the target ADT implements Reborrow. Try ordinary unification first in the ordinary identity-move path, while preserving intended generic Reborrow behavior for implicit argument reborrows. This keeps custom Reborrow tests such as repeated by-value use of marker and mutable wrapper types working as before. The fix is intentionally limited to typeck ordering and does not redesign the Reborrow representation. --- compiler/rustc_hir_typeck/src/coercion.rs | 11 ++++++++++ tests/ui/reborrow/identity_move.rs | 26 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/ui/reborrow/identity_move.rs diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 7a25b5e5e7a4e..4e424aec84c03 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -313,6 +313,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ) .must_apply_modulo_regions() => { + // Ordinary non-argument coercion contexts should keep an identity use + // as a move/copy when normal unification is sufficient. Argument + // coercions use this path for implicit generic reborrows, so preserve + // the existing reborrow-first behavior there. + if self.allow_two_phase == AllowTwoPhase::No { + let plain_unify = self.commit_if_ok(|_| self.unify(a, b, ForceLeakCheck::No)); + if plain_unify.is_ok() { + return plain_unify; + } + } + let reborrow_coerce = self.commit_if_ok(|_| self.coerce_reborrow(a, b)); if reborrow_coerce.is_ok() { return reborrow_coerce; diff --git a/tests/ui/reborrow/identity_move.rs b/tests/ui/reborrow/identity_move.rs new file mode 100644 index 0000000000000..df0bc6ae09b4e --- /dev/null +++ b/tests/ui/reborrow/identity_move.rs @@ -0,0 +1,26 @@ +//@ run-pass + +#![feature(reborrow)] + +use std::marker::Reborrow; + +struct Thing<'a>(&'a mut usize); + +impl<'a> Reborrow for Thing<'a> {} + +impl Drop for Thing<'_> { + fn drop(&mut self) { + *self.0 += 1; + } +} + +fn main() { + let mut drops = 0; + + { + let thing = Thing(&mut drops); + let _moved: Thing<'_> = thing; + } + + assert_eq!(drops, 1); +}