1
Fork 0

Rollup merge of #139818 - compiler-errors:normalize-tails, r=oli-obk

Normalize ADT field in `find_tails_for_unsizing`

See the comment inline and in the test.

TL;DR is that we're getting getting a type from a `type_of` query and then matching on it structurally in codegen, so we're obligated to normalize it. The fact that this wasn't triggered earlier is that all of the types that have `CoerceUnsized` implementations never encounter aliases when peeling the ADT down to their base reference/ptr type.

**NOTE**: I also renamed some things and reorganized the function a bit.

Fixes #139812
Fixes #74451, which I didn't think was interesting enough to add another test.

r? oli-obk
This commit is contained in:
Matthias Krüger 2025-04-15 21:16:03 +02:00 committed by GitHub
commit 27f1f4d27b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 65 additions and 74 deletions

View file

@ -688,7 +688,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
let target_ty = self.monomorphize(target_ty);
let source_ty = self.monomorphize(source_ty);
let (source_ty, target_ty) =
find_vtable_types_for_unsizing(self.tcx.at(span), source_ty, target_ty);
find_tails_for_unsizing(self.tcx.at(span), source_ty, target_ty);
// This could also be a different Unsize instruction, like
// from a fixed sized array to a slice. But we are only
// interested in things that produce a vtable.
@ -1037,36 +1037,35 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) ->
///
/// Finally, there is also the case of custom unsizing coercions, e.g., for
/// smart pointers such as `Rc` and `Arc`.
fn find_vtable_types_for_unsizing<'tcx>(
fn find_tails_for_unsizing<'tcx>(
tcx: TyCtxtAt<'tcx>,
source_ty: Ty<'tcx>,
target_ty: Ty<'tcx>,
) -> (Ty<'tcx>, Ty<'tcx>) {
let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
let typing_env = ty::TypingEnv::fully_monomorphized();
if tcx.type_has_metadata(inner_source, typing_env) {
(inner_source, inner_target)
} else {
tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, typing_env)
}
};
let typing_env = ty::TypingEnv::fully_monomorphized();
debug_assert!(!source_ty.has_param(), "{source_ty} should be fully monomorphic");
debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic");
match (source_ty.kind(), target_ty.kind()) {
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b),
(
&ty::Ref(_, source_pointee, _),
&ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _),
)
| (&ty::RawPtr(source_pointee, _), &ty::RawPtr(target_pointee, _)) => {
tcx.struct_lockstep_tails_for_codegen(source_pointee, target_pointee, typing_env)
}
// `Box<T>` could go through the ADT code below, b/c it'll unpeel to `Unique<T>`,
// and eventually bottom out in a raw ref, but we can micro-optimize it here.
(_, _)
if let Some(source_boxed) = source_ty.boxed_ty()
&& let Some(target_boxed) = target_ty.boxed_ty() =>
{
ptr_vtable(source_boxed, target_boxed)
tcx.struct_lockstep_tails_for_codegen(source_boxed, target_boxed, typing_env)
}
// T as dyn* Trait
(_, &ty::Dynamic(_, _, ty::DynStar)) => ptr_vtable(source_ty, target_ty),
(&ty::Adt(source_adt_def, source_args), &ty::Adt(target_adt_def, target_args)) => {
assert_eq!(source_adt_def, target_adt_def);
let CustomCoerceUnsized::Struct(coerce_index) =
match crate::custom_coerce_unsize_info(tcx, source_ty, target_ty) {
Ok(ccu) => ccu,
@ -1075,21 +1074,23 @@ fn find_vtable_types_for_unsizing<'tcx>(
return (e, e);
}
};
let source_fields = &source_adt_def.non_enum_variant().fields;
let target_fields = &target_adt_def.non_enum_variant().fields;
assert!(
coerce_index.index() < source_fields.len()
&& source_fields.len() == target_fields.len()
);
find_vtable_types_for_unsizing(
tcx,
source_fields[coerce_index].ty(*tcx, source_args),
target_fields[coerce_index].ty(*tcx, target_args),
)
let coerce_field = &source_adt_def.non_enum_variant().fields[coerce_index];
// We're getting a possibly unnormalized type, so normalize it.
let source_field =
tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, source_args));
let target_field =
tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, target_args));
find_tails_for_unsizing(tcx, source_field, target_field)
}
// `T` as `dyn* Trait` unsizes *directly*.
//
// FIXME(dyn_star): This case is a bit awkward, b/c we're not really computing
// a tail here. We probably should handle this separately in the *caller* of
// this function, rather than returning something that is semantically different
// than what we return above.
(_, &ty::Dynamic(_, _, ty::DynStar)) => (source_ty, target_ty),
_ => bug!(
"find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}",
source_ty,
@ -1308,7 +1309,7 @@ fn visit_mentioned_item<'tcx>(
}
MentionedItem::UnsizeCast { source_ty, target_ty } => {
let (source_ty, target_ty) =
find_vtable_types_for_unsizing(tcx.at(span), source_ty, target_ty);
find_tails_for_unsizing(tcx.at(span), source_ty, target_ty);
// This could also be a different Unsize instruction, like
// from a fixed sized array to a slice. But we are only
// interested in things that produce a vtable.