Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Vec<_>>();
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 {
Expand Down
34 changes: 34 additions & 0 deletions tests/ui/reborrow/coerce_shared_phantom_field_names.rs
Original file line number Diff line number Diff line change
@@ -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<Dest<'a>> 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);
}
Loading