about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-09-28 09:35:12 +0200
committerGitHub <noreply@github.com>2024-09-28 09:35:12 +0200
commit58d0730fb82463d68b622903aab694c69f4e7c5e (patch)
treed67781b7adf007cdaabf03eb035fadb4a0aec15c
parent6b5cd4e84e3e4c169af73e3b54b278985313d1cd (diff)
parent53f45c4332fa3703bc6866699a40df5fba2fd8ca (diff)
downloadrust-58d0730fb82463d68b622903aab694c69f4e7c5e.tar.gz
rust-58d0730fb82463d68b622903aab694c69f4e7c5e.zip
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`
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs2
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs6
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr35
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-ok.rs29
4 files changed, 65 insertions, 7 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 16e51e82f85..6b17879de26 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -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(),
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs
index d7c6c50d8be..18566acc07f 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.rs
@@ -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;
 }
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
index 6069f4f3b55..6f590585c4a 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-misc.stderr
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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`.
diff --git a/tests/ui/cast/ptr-to-trait-obj-ok.rs b/tests/ui/cast/ptr-to-trait-obj-ok.rs
index 656c99c58dc..dbeee9d2944 100644
--- a/tests/ui/cast/ptr-to-trait-obj-ok.rs
+++ b/tests/ui/cast/ptr-to-trait-obj-ok.rs
@@ -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() {}