diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 13983f349d6a5..e9cfe331ed8a8 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2516,8 +2516,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Field-by-field relate_types is expected to work based on the wf-checks that the // CoerceShared trait performs. let ty::Adt(borrowed_adt, borrowed_args) = borrowed_ty.kind() else { unreachable!() }; - let borrowed_fields = borrowed_adt.all_fields().collect::>(); - for dest_field in dest_adt.all_fields() { + // Filter out PhantomData fields to match the coherence check in + // `coerce_shared_info`, which uses `collect_struct_data_fields`. + // Without this filter, PhantomData fields with different names + // between source and dest would be silently skipped, potentially + // dropping lifetime constraints. + let borrowed_fields: Vec<_> = borrowed_adt + .all_fields() + .filter(|f| !f.ty(tcx, borrowed_args).skip_norm_wip().is_phantom_data()) + .collect(); + let dest_data_fields = dest_adt + .all_fields() + .filter(|f| !f.ty(tcx, dest_args).skip_norm_wip().is_phantom_data()); + for dest_field in dest_data_fields { let Some(borrowed_field) = borrowed_fields.iter().find(|f| f.name == dest_field.name) else { diff --git a/tests/ui/reborrow/coerce_shared_phantom_field_names.rs b/tests/ui/reborrow/coerce_shared_phantom_field_names.rs new file mode 100644 index 0000000000000..92ffad7ee0794 --- /dev/null +++ b/tests/ui/reborrow/coerce_shared_phantom_field_names.rs @@ -0,0 +1,34 @@ +//@ run-pass + +// Regression test: CoerceShared borrowck must filter PhantomData fields +// before matching by name, consistent with coherence's +// `collect_struct_data_fields`. Without the filter, differently-named +// PhantomData fields would cause lifetime constraints to be silently dropped. + +#![feature(reborrow)] +#![allow(dead_code)] +use std::marker::{CoerceShared, PhantomData, Reborrow}; + +struct Source<'a> { + data: &'a mut i32, + _marker: PhantomData<&'a ()>, +} +impl<'a> Reborrow for Source<'a> {} + +#[derive(Clone, Copy)] +struct Dest<'a> { + data: &'a i32, + _lifetime: PhantomData<&'a ()>, // Different name from Source's PhantomData field +} +impl<'a> CoerceShared> for Source<'a> {} + +fn use_ref<'a>(s: Dest<'a>) -> &'a i32 { + s.data +} + +fn main() { + let mut val = 42; + let s = Source { data: &mut val, _marker: PhantomData }; + let r = use_ref(s); + assert_eq!(*r, 42); +}