Skip to content

Commit 3209943

Browse files
Add a debug assertion in codegen that unsize casts of the same principal trait def id are truly NOPs
1 parent 8fc8e03 commit 3209943

File tree

3 files changed

+38
-18
lines changed

3 files changed

+38
-18
lines changed

compiler/rustc_codegen_cranelift/src/unsize.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,22 @@ pub(crate) fn unsized_info<'tcx>(
3434
let old_info =
3535
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
3636
if data_a.principal_def_id() == data_b.principal_def_id() {
37-
// A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables.
37+
// Codegen takes advantage of the additional assumption, where if the
38+
// principal trait def id of what's being casted doesn't change,
39+
// then we don't need to adjust the vtable at all. This
40+
// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
41+
// requires that `A = B`; we don't allow *upcasting* objects
42+
// between the same trait with different args. If we, for
43+
// some reason, were to relax the `Unsize` trait, it could become
44+
// unsound, so let's assert here that the trait refs are *equal*.
45+
//
46+
// We can use `assert_eq` because the binders should have been anonymized,
47+
// and because higher-ranked equality now requires the binders are equal.
48+
debug_assert_eq!(
49+
data_a.principal(),
50+
data_b.principal(),
51+
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
52+
);
3853
return old_info;
3954
}
4055

compiler/rustc_codegen_ssa/src/base.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,28 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
125125
let old_info =
126126
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
127127
if data_a.principal_def_id() == data_b.principal_def_id() {
128-
// A NOP cast that doesn't actually change anything, should be allowed even with
129-
// invalid vtables.
128+
// Codegen takes advantage of the additional assumption, where if the
129+
// principal trait def id of what's being casted doesn't change,
130+
// then we don't need to adjust the vtable at all. This
131+
// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
132+
// requires that `A = B`; we don't allow *upcasting* objects
133+
// between the same trait with different args. If we, for
134+
// some reason, were to relax the `Unsize` trait, it could become
135+
// unsound, so let's assert here that the trait refs are *equal*.
136+
//
137+
// We can use `assert_eq` because the binders should have been anonymized,
138+
// and because higher-ranked equality now requires the binders are equal.
139+
debug_assert_eq!(
140+
data_a.principal(),
141+
data_b.principal(),
142+
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
143+
);
144+
145+
// A NOP cast that doesn't actually change anything, let's avoid any
146+
// unnecessary work. This relies on the assumption that if the principal
147+
// traits are equal, then the associated type bounds (`dyn Trait<Assoc=T>`)
148+
// are also equal, which is ensured by the fact that normalization is
149+
// a function and we do not allow overlapping impls.
130150
return old_info;
131151
}
132152

compiler/rustc_mir_transform/src/validate.rs

-15
Original file line numberDiff line numberDiff line change
@@ -1233,21 +1233,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
12331233
)) {
12341234
self.fail(location, format!("Unsize coercion, but `{op_ty}` isn't coercible to `{target_type}`"));
12351235
}
1236-
1237-
// FIXME: Codegen has an additional assumption, where if the
1238-
// principal trait def id of what's being casted doesn't change,
1239-
// then we don't need to adjust the vtable at all. This
1240-
// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
1241-
// requires that `A = B`; we don't allow *upcasting* objects
1242-
// between the same trait with different args. Nothing actually
1243-
// validates this, though. While it's true right now, if we for
1244-
// some reason were to relax the `Unsize` trait, it could become
1245-
// unsound. We should eventually validate that, but it would
1246-
// require peeling `&Box<Struct<.., dyn Tr<A>, ..>>` down to
1247-
// the trait object that's being unsized, and that's rather
1248-
// annoying, and also it would need to be opportunistic since
1249-
// this MIR is not yet fully monomorphized, so we may bottom
1250-
// out in an alias or a projection or something.
12511236
}
12521237
CastKind::PointerCoercion(PointerCoercion::DynStar, _) => {
12531238
// FIXME(dyn-star): make sure nothing needs to be done here.

0 commit comments

Comments
 (0)