Skip to content

Commit

Permalink
Rollup merge of #130944 - lukas-code:ptr-ptr-sub, r=compiler-errors
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
matthiaskrgr authored Sep 28, 2024
2 parents 6b5cd4e + 53f45c4 commit 58d0730
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 7 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2437,7 +2437,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {

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

self.eq_types(
self.sub_types(
src_obj,
dst_obj,
location.to_locations(),
Expand Down
6 changes: 6 additions & 0 deletions tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ fn change_lt_ba<'a, 'b: 'a>(x: *mut dyn Trait<'a>) -> *mut dyn Trait<'b> {
x as _ //~ error: lifetime may not live long enough
}

fn change_lt_hr<'a>(x: *mut dyn Trait<'a>) -> *mut dyn for<'b> Trait<'b> {
x as _ //~ error: lifetime may not live long enough
//~^ error: mismatched types
//~| one type is more general than the other
}

trait Assocked {
type Assoc: ?Sized;
}
Expand Down
35 changes: 29 additions & 6 deletions tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,29 @@ LL | x as _
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: lifetime may not live long enough
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:25:5
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:19:5
|
LL | fn change_lt_hr<'a>(x: *mut dyn Trait<'a>) -> *mut dyn for<'b> Trait<'b> {
| -- lifetime `'a` defined here
LL | x as _
| ^^^^^^ cast requires that `'a` must outlive `'static`
|
help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound
|
LL | fn change_lt_hr<'a>(x: *mut dyn Trait<'a>) -> *mut dyn for<'b> Trait<'b> + 'a {
| ++++

error[E0308]: mismatched types
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:19:5
|
LL | x as _
| ^^^^^^ one type is more general than the other
|
= note: expected trait object `dyn for<'b> Trait<'b>`
found trait object `dyn Trait<'_>`

error: lifetime may not live long enough
--> $DIR/ptr-to-trait-obj-different-regions-misc.rs:31:5
|
LL | fn change_assoc_0<'a, 'b>(
| -- -- lifetime `'b` defined here
Expand All @@ -77,7 +99,7 @@ LL | x as _
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

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

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

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

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

error: aborting due to 9 previous errors
error: aborting due to 11 previous errors

For more information about this error, try `rustc --explain E0308`.
29 changes: 29 additions & 0 deletions tests/ui/cast/ptr-to-trait-obj-ok.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,37 @@ fn cast_inherent_lt<'a, 'b>(x: *mut (dyn Trait<'static> + 'a)) -> *mut (dyn Trai
x as _
}

fn cast_away_higher_ranked<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut dyn Trait<'a> {
x as _
}

fn unprincipled<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut (dyn Sync + 'b) {
x as _
}

// If it is possible to coerce from the source to the target type modulo
// regions, then we skip the HIR checks for ptr-to-ptr casts and possibly
// insert an unsizing coercion into the MIR before the ptr-to-ptr cast.
// By wrapping the target type, we ensure that no coercion happens
// and also test the non-coercion cast behavior.
struct Wrapper<T: ?Sized>(T);

fn remove_auto_wrap<'a>(x: *mut (dyn Trait<'a> + Send)) -> *mut Wrapper<dyn Trait<'a>> {
x as _
}

fn cast_inherent_lt_wrap<'a, 'b>(
x: *mut (dyn Trait<'static> + 'a),
) -> *mut Wrapper<dyn Trait<'static> + 'b> {
x as _
}

fn cast_away_higher_ranked_wrap<'a>(x: *mut dyn for<'b> Trait<'b>) -> *mut Wrapper<dyn Trait<'a>> {
x as _
}

fn unprincipled_wrap<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut Wrapper<dyn Sync + 'b> {
x as _
}

fn main() {}

0 comments on commit 58d0730

Please sign in to comment.