Normalize ADT fields in find_tails_for_unsizing
This commit is contained in:
parent
c580c498a1
commit
3df7882272
3 changed files with 65 additions and 74 deletions
|
@ -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)
|
||||
}
|
||||
};
|
||||
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.
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
//@ known-bug: #74451
|
||||
//@ compile-flags: -Copt-level=0
|
||||
|
||||
#![feature(specialization)]
|
||||
#![feature(unsize, coerce_unsized)]
|
||||
#![allow(incomplete_features)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
use std::ops::CoerceUnsized;
|
||||
|
||||
pub struct SmartassPtr<A: Smartass+?Sized>(A::Data);
|
||||
|
||||
pub trait Smartass {
|
||||
type Data;
|
||||
type Data2: CoerceUnsized<*const [u8]>;
|
||||
}
|
||||
|
||||
pub trait MaybeObjectSafe {}
|
||||
|
||||
impl MaybeObjectSafe for () {}
|
||||
|
||||
impl<T> Smartass for T {
|
||||
type Data = <Self as Smartass>::Data2;
|
||||
default type Data2 = *const [u8; 0];
|
||||
}
|
||||
|
||||
impl Smartass for () {
|
||||
type Data2 = *const [u8; 1];
|
||||
}
|
||||
|
||||
impl Smartass for dyn MaybeObjectSafe {
|
||||
type Data = *const [u8];
|
||||
type Data2 = *const [u8; 0];
|
||||
}
|
||||
|
||||
impl<U: Smartass+?Sized, T: Smartass+?Sized> CoerceUnsized<SmartassPtr<T>> for SmartassPtr<U>
|
||||
where <U as Smartass>::Data: std::ops::CoerceUnsized<<T as Smartass>::Data>
|
||||
{}
|
||||
|
||||
pub fn conv(s: SmartassPtr<()>) -> SmartassPtr<dyn MaybeObjectSafe> {
|
||||
s // This shouldn't coerce
|
||||
}
|
32
tests/ui/coercion/codegen-smart-pointer-with-alias.rs
Normal file
32
tests/ui/coercion/codegen-smart-pointer-with-alias.rs
Normal file
|
@ -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…
Add table
Add a link
Reference in a new issue