From 1ad305b0646bc506f96a8f2995824284af80eb13 Mon Sep 17 00:00:00 2001 From: Virginia Senioria Date: Thu, 9 Jul 2026 01:14:52 +0800 Subject: [PATCH] reject reborrowing when the target has no lifetime generic arg suppresses the ICE about hir-typeck passed but Reborrow does not have a lifetime argument, but doesn't fix the problem that reborrowing is conflict with moving. --- compiler/rustc_hir_typeck/src/coercion.rs | 26 ++++++++++++++----- .../reborrow/reborrow-no-lifetime-rejected.rs | 14 ++++++++++ .../reborrow-no-lifetime-rejected.stderr | 8 ++++++ 3 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 tests/ui/reborrow/reborrow-no-lifetime-rejected.rs create mode 100644 tests/ui/reborrow/reborrow-no-lifetime-rejected.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 2ecbb8863bf91..38362f6db057d 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -54,7 +54,7 @@ use rustc_middle::ty::adjustment::{ PointerCoercion, }; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Unnormalized}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, Unnormalized}; use rustc_span::{BytePos, DUMMY_SP, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor}; @@ -950,6 +950,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Ok(coerce) } + /// Get the AdtDefs for the reborrowing if they're reborrowable + fn reborrow_def( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + ) -> RelateResult<'tcx, (AdtDef<'tcx>, AdtDef<'tcx>)> { + let (ty::Adt(a_def, _), ty::Adt(b_def, b_args)) = (*a.kind(), *b.kind()) else { + return Err(TypeError::Mismatch); + }; + match b_args.get(0).map(|r| r.kind()) { + Some(ty::GenericArgKind::Lifetime(_)) => Ok((a_def, b_def)), + _ => Err(TypeError::Mismatch), + } + } + /// Applies generic exclusive reborrowing on type implementing `Reborrow`. #[instrument(skip(self), level = "trace")] fn coerce_reborrow(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { @@ -957,9 +972,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { debug_assert!(self.shallow_resolve(b) == b); // We need to make sure the two types are compatible for reborrow. - let (ty::Adt(a_def, _), ty::Adt(b_def, _)) = (a.kind(), b.kind()) else { - return Err(TypeError::Mismatch); - }; + let (a_def, b_def) = self.reborrow_def(a, b)?; + if a_def.did() == b_def.did() { // Reborrow is applicable here self.unify_and( @@ -982,9 +996,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { debug_assert!(self.shallow_resolve(b) == b); // We need to make sure the two types are compatible for reborrow. - let (ty::Adt(a_def, _), ty::Adt(b_def, _)) = (a.kind(), b.kind()) else { - return Err(TypeError::Mismatch); - }; + let (a_def, b_def) = self.reborrow_def(a, b)?; if a_def.did() == b_def.did() { // CoerceShared cannot be T -> T. return Err(TypeError::Mismatch); diff --git a/tests/ui/reborrow/reborrow-no-lifetime-rejected.rs b/tests/ui/reborrow/reborrow-no-lifetime-rejected.rs new file mode 100644 index 0000000000000..3beb327b8cdab --- /dev/null +++ b/tests/ui/reborrow/reborrow-no-lifetime-rejected.rs @@ -0,0 +1,14 @@ +//@ check-fail + +#![feature(reborrow)] + +use std::marker::Reborrow; + +struct Thing; +impl<'a> Reborrow for Thing {} +//~^ ERROR implementing `Reborrow` does not allow multiple lifetimes or fields to be coerced +fn foo(_: Thing) {} +fn main() { + let x = Thing; + foo(x); +} diff --git a/tests/ui/reborrow/reborrow-no-lifetime-rejected.stderr b/tests/ui/reborrow/reborrow-no-lifetime-rejected.stderr new file mode 100644 index 0000000000000..f147a916f291b --- /dev/null +++ b/tests/ui/reborrow/reborrow-no-lifetime-rejected.stderr @@ -0,0 +1,8 @@ +error: implementing `Reborrow` does not allow multiple lifetimes or fields to be coerced + --> $DIR/reborrow-no-lifetime-rejected.rs:8:1 + | +LL | impl<'a> Reborrow for Thing {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +