Skip to content

Normalize ADT field in find_tails_for_unsizing #139818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 15, 2025
Merged
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
63 changes: 32 additions & 31 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand All @@ -1075,21 +1074,23 @@ fn find_vtable_types_for_unsizing<'tcx>(
return (e, e);
}
};
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)
}

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()
);
// `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),

find_vtable_types_for_unsizing(
tcx,
source_fields[coerce_index].ty(*tcx, source_args),
target_fields[coerce_index].ty(*tcx, target_args),
)
}
_ => bug!(
"find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}",
source_ty,
Expand Down Expand Up @@ -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.
Expand Down
42 changes: 0 additions & 42 deletions tests/crashes/74451.rs

This file was deleted.

32 changes: 32 additions & 0 deletions tests/ui/coercion/codegen-smart-pointer-with-alias.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//@ build-pass

// Regression test for <https://github.com/rust-lang/rust/issues/139812>.

// Make sure that the unsize coercion we collect in mono for `Signal<i32> -> Signal<dyn Any>`
// doesn't choke on the fact that the inner unsized field of `Signal<T>` is a (trivial) alias.
// This exercises a normalize call that is necessary since we're getting a type from the type
// system, which isn't guaranteed to be normalized after substitution.

#![feature(coerce_unsized)]

use std::ops::CoerceUnsized;

trait Mirror {
type Assoc: ?Sized;
}
impl<T: ?Sized> Mirror for T {
type Assoc = T;
}

trait Any {}
impl<T> Any for T {}

struct Signal<'a, T: ?Sized>(<&'a T as Mirror>::Assoc);

// This `CoerceUnsized` impl isn't special; it's a bit more restricted than we'd see in the wild,
// but this ICE also reproduces if we were to make it general over `Signal<T> -> Signal<U>`.
impl<'a> CoerceUnsized<Signal<'a, dyn Any>> for Signal<'a, i32> {}

fn main() {
Signal(&1i32) as Signal<dyn Any>;
}
Loading