Skip to content

Commit 58d0730

Browse files
authored
Rollup merge of #130944 - lukas-code:ptr-ptr-sub, r=compiler-errors
Allow instantiating trait object binder in ptr-to-ptr casts For unsizing coercions between trait objects with the same principal, we already allow instantiating the for binder. For example, coercing `Box<dyn for<'a> Trait<'a>` to `Box<dyn Trait<'static>>` is allowed. Since ptr-to-ptr casts will insert an unsizing coercion before the cast if possible, this has the consequence that the following compiles already: ```rust // This compiles today. fn cast<'b>(x: *mut dyn for<'a> Trait<'a>) -> *mut dyn Trait<'b> { // lowered as (roughly) // tmp: *mut dyn Trait<'?0> = Unsize(x) // requires dyn for<'a> Trait<'a> <: dyn Trait<'?0> // ret: *mut dyn Trait<'b> = PtrToPtr(tmp) // requires dyn Trait<'?0> == dyn Trait<'b> x as _ } ``` However, if no unsizing coercion is inserted then this currently fails to compile as one type is more general than the other. This PR will allow this code to compile, too, by changing ptr-to-ptr casts of pointers with vtable metadata to use sutyping instead of type equality. ```rust // This will compile after this PR. fn cast<'b>(x: *mut dyn for<'a> Trait<'a>) -> *mut Wrapper<dyn Trait<'b>> { // lowered as (roughly) // no Unsize here! // ret: *mut Wrapper<dyn Trait<'b>> = PtrToPtr(x) // requires dyn for<'a> Trait<'a> == dyn Trait<'b> x as _ } ``` Note that it is already possible to work around the current restrictions and make the code compile before this PR by splitting the cast in two, so this shouldn't allow a new class of programs to compile: ```rust // Workaround that compiles today. fn cast<'b>(x: *mut dyn for<'a> Trait<'a>) -> *mut Wrapper<dyn Trait<'b>> { x as *mut dyn Trait<'_> as _ } ``` r? `@compiler-errors` cc `@WaffleLapkin`
2 parents 6b5cd4e + 53f45c4 commit 58d0730

File tree

4 files changed

+65
-7
lines changed

4 files changed

+65
-7
lines changed

Diff for: compiler/rustc_borrowck/src/type_check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2437,7 +2437,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
24372437

24382438
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
24392439

2440-
self.eq_types(
2440+
self.sub_types(
24412441
src_obj,
24422442
dst_obj,
24432443
location.to_locations(),

Diff for: tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ fn change_lt_ba<'a, 'b: 'a>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
1515
x as _ //~ error: lifetime may not live long enough
1616
}
1717

18+
fn change_lt_hr<'a>(x: *mut dyn Trait<'a>) -> *mut dyn for<'b> Trait<'b> {
19+
x as _ //~ error: lifetime may not live long enough
20+
//~^ error: mismatched types
21+
//~| one type is more general than the other
22+
}
23+
1824
trait Assocked {
1925
type Assoc: ?Sized;
2026
}

Diff for: tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr

+29-6
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,29 @@ LL | x as _
6161
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
6262

6363
error: lifetime may not live long enough
64-
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:25:5
64+
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:19:5
65+
|
66+
LL | fn change_lt_hr<'a>(x: *mut dyn Trait<'a>) -> *mut dyn for<'b> Trait<'b> {
67+
| -- lifetime `'a` defined here
68+
LL | x as _
69+
| ^^^^^^ cast requires that `'a` must outlive `'static`
70+
|
71+
help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound
72+
|
73+
LL | fn change_lt_hr<'a>(x: *mut dyn Trait<'a>) -> *mut dyn for<'b> Trait<'b> + 'a {
74+
| ++++
75+
76+
error[E0308]: mismatched types
77+
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:19:5
78+
|
79+
LL | x as _
80+
| ^^^^^^ one type is more general than the other
81+
|
82+
= note: expected trait object `dyn for<'b> Trait<'b>`
83+
found trait object `dyn Trait<'_>`
84+
85+
error: lifetime may not live long enough
86+
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:31:5
6587
|
6688
LL | fn change_assoc_0<'a, 'b>(
6789
| -- -- lifetime `'b` defined here
@@ -77,7 +99,7 @@ LL | x as _
7799
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
78100

79101
error: lifetime may not live long enough
80-
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:25:5
102+
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:31:5
81103
|
82104
LL | fn change_assoc_0<'a, 'b>(
83105
| -- -- lifetime `'b` defined here
@@ -97,7 +119,7 @@ help: `'b` and `'a` must be the same: replace one with the other
97119
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
98120

99121
error: lifetime may not live long enough
100-
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:32:5
122+
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:38:5
101123
|
102124
LL | fn change_assoc_1<'a, 'b>(
103125
| -- -- lifetime `'b` defined here
@@ -113,7 +135,7 @@ LL | x as _
113135
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
114136

115137
error: lifetime may not live long enough
116-
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:32:5
138+
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:38:5
117139
|
118140
LL | fn change_assoc_1<'a, 'b>(
119141
| -- -- lifetime `'b` defined here
@@ -133,12 +155,13 @@ help: `'b` and `'a` must be the same: replace one with the other
133155
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
134156

135157
error: lifetime may not live long enough
136-
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:39:20
158+
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:45:20
137159
|
138160
LL | fn extend_to_static<'a>(ptr: *const dyn Trait<'a>) {
139161
| -- lifetime `'a` defined here
140162
LL | require_static(ptr as _)
141163
| ^^^^^^^^ cast requires that `'a` must outlive `'static`
142164

143-
error: aborting due to 9 previous errors
165+
error: aborting due to 11 previous errors
144166

167+
For more information about this error, try `rustc --explain E0308`.

Diff for: tests/ui/cast/ptr-to-trait-obj-ok.rs

+29
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,37 @@ fn cast_inherent_lt<'a, 'b>(x: *mut (dyn Trait<'static> + 'a)) -> *mut (dyn Trai
1010
x as _
1111
}
1212

13+
fn cast_away_higher_ranked<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut dyn Trait<'a> {
14+
x as _
15+
}
16+
1317
fn unprincipled<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut (dyn Sync + 'b) {
1418
x as _
1519
}
1620

21+
// If it is possible to coerce from the source to the target type modulo
22+
// regions, then we skip the HIR checks for ptr-to-ptr casts and possibly
23+
// insert an unsizing coercion into the MIR before the ptr-to-ptr cast.
24+
// By wrapping the target type, we ensure that no coercion happens
25+
// and also test the non-coercion cast behavior.
26+
struct Wrapper<T: ?Sized>(T);
27+
28+
fn remove_auto_wrap<'a>(x: *mut (dyn Trait<'a> + Send)) -> *mut Wrapper<dyn Trait<'a>> {
29+
x as _
30+
}
31+
32+
fn cast_inherent_lt_wrap<'a, 'b>(
33+
x: *mut (dyn Trait<'static> + 'a),
34+
) -> *mut Wrapper<dyn Trait<'static> + 'b> {
35+
x as _
36+
}
37+
38+
fn cast_away_higher_ranked_wrap<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut Wrapper<dyn Trait<'a>> {
39+
x as _
40+
}
41+
42+
fn unprincipled_wrap<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut Wrapper<dyn Sync + 'b> {
43+
x as _
44+
}
45+
1746
fn main() {}

0 commit comments

Comments
 (0)