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); +}