Skip to content

Commit 27f1f4d

Browse files
authored
Rollup merge of rust-lang#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 rust-lang#139812 Fixes rust-lang#74451, which I didn't think was interesting enough to add another test. r? oli-obk
2 parents ca0b7f4 + 3df7882 commit 27f1f4d

File tree

3 files changed

+64
-73
lines changed

3 files changed

+64
-73
lines changed

Diff for: compiler/rustc_monomorphize/src/collector.rs

+32-31
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
688688
let target_ty = self.monomorphize(target_ty);
689689
let source_ty = self.monomorphize(source_ty);
690690
let (source_ty, target_ty) =
691-
find_vtable_types_for_unsizing(self.tcx.at(span), source_ty, target_ty);
691+
find_tails_for_unsizing(self.tcx.at(span), source_ty, target_ty);
692692
// This could also be a different Unsize instruction, like
693693
// from a fixed sized array to a slice. But we are only
694694
// interested in things that produce a vtable.
@@ -1037,36 +1037,35 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) ->
10371037
///
10381038
/// Finally, there is also the case of custom unsizing coercions, e.g., for
10391039
/// smart pointers such as `Rc` and `Arc`.
1040-
fn find_vtable_types_for_unsizing<'tcx>(
1040+
fn find_tails_for_unsizing<'tcx>(
10411041
tcx: TyCtxtAt<'tcx>,
10421042
source_ty: Ty<'tcx>,
10431043
target_ty: Ty<'tcx>,
10441044
) -> (Ty<'tcx>, Ty<'tcx>) {
1045-
let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
1046-
let typing_env = ty::TypingEnv::fully_monomorphized();
1047-
if tcx.type_has_metadata(inner_source, typing_env) {
1048-
(inner_source, inner_target)
1049-
} else {
1050-
tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, typing_env)
1051-
}
1052-
};
1045+
let typing_env = ty::TypingEnv::fully_monomorphized();
1046+
debug_assert!(!source_ty.has_param(), "{source_ty} should be fully monomorphic");
1047+
debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic");
10531048

10541049
match (source_ty.kind(), target_ty.kind()) {
1055-
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
1056-
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b),
1050+
(
1051+
&ty::Ref(_, source_pointee, _),
1052+
&ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _),
1053+
)
1054+
| (&ty::RawPtr(source_pointee, _), &ty::RawPtr(target_pointee, _)) => {
1055+
tcx.struct_lockstep_tails_for_codegen(source_pointee, target_pointee, typing_env)
1056+
}
1057+
1058+
// `Box<T>` could go through the ADT code below, b/c it'll unpeel to `Unique<T>`,
1059+
// and eventually bottom out in a raw ref, but we can micro-optimize it here.
10571060
(_, _)
10581061
if let Some(source_boxed) = source_ty.boxed_ty()
10591062
&& let Some(target_boxed) = target_ty.boxed_ty() =>
10601063
{
1061-
ptr_vtable(source_boxed, target_boxed)
1064+
tcx.struct_lockstep_tails_for_codegen(source_boxed, target_boxed, typing_env)
10621065
}
10631066

1064-
// T as dyn* Trait
1065-
(_, &ty::Dynamic(_, _, ty::DynStar)) => ptr_vtable(source_ty, target_ty),
1066-
10671067
(&ty::Adt(source_adt_def, source_args), &ty::Adt(target_adt_def, target_args)) => {
10681068
assert_eq!(source_adt_def, target_adt_def);
1069-
10701069
let CustomCoerceUnsized::Struct(coerce_index) =
10711070
match crate::custom_coerce_unsize_info(tcx, source_ty, target_ty) {
10721071
Ok(ccu) => ccu,
@@ -1075,21 +1074,23 @@ fn find_vtable_types_for_unsizing<'tcx>(
10751074
return (e, e);
10761075
}
10771076
};
1077+
let coerce_field = &source_adt_def.non_enum_variant().fields[coerce_index];
1078+
// We're getting a possibly unnormalized type, so normalize it.
1079+
let source_field =
1080+
tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, source_args));
1081+
let target_field =
1082+
tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, target_args));
1083+
find_tails_for_unsizing(tcx, source_field, target_field)
1084+
}
10781085

1079-
let source_fields = &source_adt_def.non_enum_variant().fields;
1080-
let target_fields = &target_adt_def.non_enum_variant().fields;
1081-
1082-
assert!(
1083-
coerce_index.index() < source_fields.len()
1084-
&& source_fields.len() == target_fields.len()
1085-
);
1086+
// `T` as `dyn* Trait` unsizes *directly*.
1087+
//
1088+
// FIXME(dyn_star): This case is a bit awkward, b/c we're not really computing
1089+
// a tail here. We probably should handle this separately in the *caller* of
1090+
// this function, rather than returning something that is semantically different
1091+
// than what we return above.
1092+
(_, &ty::Dynamic(_, _, ty::DynStar)) => (source_ty, target_ty),
10861093

1087-
find_vtable_types_for_unsizing(
1088-
tcx,
1089-
source_fields[coerce_index].ty(*tcx, source_args),
1090-
target_fields[coerce_index].ty(*tcx, target_args),
1091-
)
1092-
}
10931094
_ => bug!(
10941095
"find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}",
10951096
source_ty,
@@ -1308,7 +1309,7 @@ fn visit_mentioned_item<'tcx>(
13081309
}
13091310
MentionedItem::UnsizeCast { source_ty, target_ty } => {
13101311
let (source_ty, target_ty) =
1311-
find_vtable_types_for_unsizing(tcx.at(span), source_ty, target_ty);
1312+
find_tails_for_unsizing(tcx.at(span), source_ty, target_ty);
13121313
// This could also be a different Unsize instruction, like
13131314
// from a fixed sized array to a slice. But we are only
13141315
// interested in things that produce a vtable.

Diff for: tests/crashes/74451.rs

-42
This file was deleted.
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ build-pass
2+
3+
// Regression test for <https://github.com/rust-lang/rust/issues/139812>.
4+
5+
// Make sure that the unsize coercion we collect in mono for `Signal<i32> -> Signal<dyn Any>`
6+
// doesn't choke on the fact that the inner unsized field of `Signal<T>` is a (trivial) alias.
7+
// This exercises a normalize call that is necessary since we're getting a type from the type
8+
// system, which isn't guaranteed to be normalized after substitution.
9+
10+
#![feature(coerce_unsized)]
11+
12+
use std::ops::CoerceUnsized;
13+
14+
trait Mirror {
15+
type Assoc: ?Sized;
16+
}
17+
impl<T: ?Sized> Mirror for T {
18+
type Assoc = T;
19+
}
20+
21+
trait Any {}
22+
impl<T> Any for T {}
23+
24+
struct Signal<'a, T: ?Sized>(<&'a T as Mirror>::Assoc);
25+
26+
// This `CoerceUnsized` impl isn't special; it's a bit more restricted than we'd see in the wild,
27+
// but this ICE also reproduces if we were to make it general over `Signal<T> -> Signal<U>`.
28+
impl<'a> CoerceUnsized<Signal<'a, dyn Any>> for Signal<'a, i32> {}
29+
30+
fn main() {
31+
Signal(&1i32) as Signal<dyn Any>;
32+
}

0 commit comments

Comments
 (0)