Skip to content

Commit f256f9e

Browse files
Rollup merge of #135228 - compiler-errors:normalizes-ur-dispatch, r=BoxyUwU
Improve `DispatchFromDyn` and `CoerceUnsized` impl validation * Disallow arbitrary 1-ZST fields in `DispatchFromDyn` -- only `PhantomData`, and 1-ZSTs that mention no params (which is needed to support, e.g., the `Global` alloctor in `Box<T, U = Global>`). * Don't allow coercing between non-ZSTs to ZSTs (since the previous check wasn't actually checking the field tys were the same before checking the layout...) * Normalize the field before checking it's `PhantomData`. Fixes#135215Fixes#135214Fixes#135220 r? ```@BoxyUwU``` or reassign
2 parents aa8bc25 + 3cd7581 commit f256f9e

8 files changed

Lines changed: 153 additions & 11 deletions

‎compiler/rustc_hir_analysis/messages.ftl‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait
135135
136136
hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
137137
138-
hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
138+
hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
139139
.note = extra field `{$name}` of type `{$ty}` is not allowed
140140
141141
hir_analysis_drop_impl_negative = negative `Drop` impls are not supported

‎compiler/rustc_hir_analysis/src/coherence/builtin.rs‎

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -259,19 +259,37 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
259259
let coerced_fields = fields
260260
.iter()
261261
.filter(|field| {
262+
// Ignore PhantomData fields
263+
let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
264+
if tcx
265+
.try_normalize_erasing_regions(
266+
ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
267+
unnormalized_ty,
268+
)
269+
.unwrap_or(unnormalized_ty)
270+
.is_phantom_data()
271+
{
272+
returnfalse;
273+
}
274+
262275
let ty_a = field.ty(tcx, args_a);
263276
let ty_b = field.ty(tcx, args_b);
264277

265-
ifletOk(layout) =
266-
tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
267-
{
268-
if layout.is_1zst(){
278+
// FIXME: We could do normalization here, but is it really worth it?
279+
if ty_a == ty_b {
280+
// Allow 1-ZSTs that don't mention type params.
281+
//
282+
// Allowing type params here would allow us to possibly transmute
283+
// between ZSTs, which may be used to create library unsoundness.
284+
ifletOk(layout) =
285+
tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
286+
&& layout.is_1zst()
287+
&& !ty_a.has_non_region_param()
288+
{
269289
// ignore 1-ZST fields
270290
returnfalse;
271291
}
272-
}
273292

274-
if ty_a == ty_b {
275293
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST{
276294
span,
277295
name: field.name,
@@ -460,8 +478,16 @@ pub(crate) fn coerce_unsized_info<'tcx>(
460478
.filter_map(|(i, f)| {
461479
let(a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));
462480

463-
if tcx.type_of(f.did).instantiate_identity().is_phantom_data(){
464-
// Ignore PhantomData fields
481+
// Ignore PhantomData fields
482+
let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
483+
if tcx
484+
.try_normalize_erasing_regions(
485+
ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
486+
unnormalized_ty,
487+
)
488+
.unwrap_or(unnormalized_ty)
489+
.is_phantom_data()
490+
{
465491
returnNone;
466492
}
467493

‎tests/ui/invalid_dispatch_from_dyn_impls.stderr‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
1+
error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
22
--> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1
33
|
44
LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
@@ -35,7 +35,7 @@ LL | | where
3535
LL | | T: Unsize<U>,
3636
| |_________________^
3737

38-
error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
38+
error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
3939
--> $DIR/invalid_dispatch_from_dyn_impls.rs:46:1
4040
|
4141
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// We used to allow erroneous `DispatchFromDyn` impls whose RHS type contained
2+
// fields that weren't ZSTs. I don't believe this was possible to abuse, but
3+
// it's at least nice to give users better errors.
4+
5+
#![feature(arbitrary_self_types)]
6+
#![feature(unsize)]
7+
#![feature(dispatch_from_dyn)]
8+
9+
use std::marker::Unsize;
10+
use std::ops::DispatchFromDyn;
11+
12+
structDispatchable<T: ?Sized,Z>{
13+
_ptr:Box<T>,
14+
z:Z,
15+
}
16+
17+
impl<T,U>DispatchFromDyn<Dispatchable<U,i32>>forDispatchable<T,()>
18+
//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions
19+
where
20+
T:Unsize<U> + ?Sized,
21+
U: ?Sized,
22+
{
23+
}
24+
25+
fnmain(){}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
2+
--> $DIR/dispatch-from-dyn-zst-transmute-zst-nonzst.rs:17:1
3+
|
4+
LL | / impl<T, U> DispatchFromDyn<Dispatchable<U, i32>> for Dispatchable<T, ()>
5+
LL | |
6+
LL | | where
7+
LL | | T: Unsize<U> + ?Sized,
8+
LL | | U: ?Sized,
9+
| |______________^
10+
|
11+
= note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
12+
= note: currently, 2 fields need coercions: `_ptr` (`Box<T>` to `Box<U>`), `z` (`()` to `i32`)
13+
14+
error: aborting due to 1 previous error
15+
16+
For more information about this error, try `rustc --explain E0378`.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![feature(arbitrary_self_types)]
2+
#![feature(unsize)]
3+
#![feature(dispatch_from_dyn)]
4+
5+
use std::marker::PhantomData;
6+
use std::marker::Unsize;
7+
use std::ops::DispatchFromDyn;
8+
use std::ops::Deref;
9+
10+
structIsSendToken<T: ?Sized>(PhantomData<fn(T) -> T>);
11+
12+
structFoo<'a,U: ?Sized>{
13+
token:IsSendToken<U>,
14+
ptr:&'aU,
15+
}
16+
17+
impl<'a,T,U>DispatchFromDyn<Foo<'a,U>>forFoo<'a,T>
18+
//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions
19+
where
20+
T:Unsize<U> + ?Sized,
21+
U: ?Sized{}
22+
23+
traitBar{
24+
fnf(self:Foo<'_,Self>);
25+
}
26+
27+
impl<U: ?Sized>DerefforFoo<'_,U>{
28+
typeTarget = U;
29+
fnderef(&self) -> &U{
30+
self.ptr
31+
}
32+
}
33+
34+
fnmain(){}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
2+
--> $DIR/dispatch-from-dyn-zst-transmute.rs:17:1
3+
|
4+
LL | / impl<'a, T, U> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T>
5+
LL | |
6+
LL | | where
7+
LL | | T: Unsize<U> + ?Sized,
8+
LL | | U: ?Sized {}
9+
| |_____________^
10+
|
11+
= note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
12+
= note: currently, 2 fields need coercions: `token` (`IsSendToken<T>` to `IsSendToken<U>`), `ptr` (`&'a T` to `&'a U`)
13+
14+
error: aborting due to 1 previous error
15+
16+
For more information about this error, try `rustc --explain E0378`.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ check-pass
2+
3+
#![feature(coerce_unsized, dispatch_from_dyn, unsize)]
4+
5+
use std::marker::Unsize;
6+
use std::ops::{CoerceUnsized,DispatchFromDyn};
7+
use std::marker::PhantomData;
8+
9+
traitMirror{
10+
typeAssoc;
11+
}
12+
impl<T>MirrorforT{
13+
typeAssoc = T;
14+
}
15+
16+
structW<T:'static>{
17+
t:&'staticT,
18+
f: <PhantomData<T>asMirror>::Assoc,
19+
}
20+
21+
impl<T,U>CoerceUnsized<W<U>>forW<T>whereT:Unsize<U>{}
22+
23+
impl<T,U>DispatchFromDyn<W<U>>forW<T>whereT:Unsize<U>{}
24+
25+
fnmain(){}

0 commit comments

Comments
 (0)