about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs65
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs25
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-args.rs8
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-args.stderr45
-rw-r--r--tests/ui/traits/upcast_soundness_bug.rs2
-rw-r--r--tests/ui/traits/upcast_soundness_bug.stderr10
6 files changed, 68 insertions, 87 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 6fd49c8027b..a457283ab7d 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -38,6 +38,7 @@ use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use rustc_span::DUMMY_SP;
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
 use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
 use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
@@ -49,6 +50,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::ResultsCursor;
 
+use crate::renumber::RegionCtxt;
 use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
 use crate::{
     borrow_set::BorrowSet,
@@ -2335,51 +2337,39 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                     && src_tty.principal().is_some()
                                     && dst_tty.principal().is_some()
                                 {
-                                    // Erase trait object lifetimes, to allow casts like `*mut dyn FnOnce()` -> `*mut dyn FnOnce() + 'static`
-                                    // and remove auto traits.
+                                    // Remove auto traits.
+                                    // Auto trait checks are handled in `rustc_hir_typeck` as FCW.
                                     let src_obj = tcx.mk_ty_from_kind(ty::Dynamic(
                                         tcx.mk_poly_existential_predicates(
                                             &src_tty.without_auto_traits().collect::<Vec<_>>(),
                                         ),
-                                        tcx.lifetimes.re_erased,
+                                        tcx.lifetimes.re_static,
                                         ty::Dyn,
                                     ));
                                     let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic(
                                         tcx.mk_poly_existential_predicates(
                                             &dst_tty.without_auto_traits().collect::<Vec<_>>(),
                                         ),
-                                        tcx.lifetimes.re_erased,
+                                        tcx.lifetimes.re_static,
                                         ty::Dyn,
                                     ));
 
-                                    // FIXME:
-                                    // this currently does nothing, but once we make `ptr_cast_add_auto_to_object`
-                                    // into a hard error, we can remove the above removal of auto traits and only
-                                    // keep this.
-                                    let src_obj = erase_single_trait_object_lifetime(tcx, src_obj);
-                                    let dst_obj = erase_single_trait_object_lifetime(tcx, dst_obj);
-
-                                    let trait_ref = ty::TraitRef::new(
-                                        tcx,
-                                        tcx.require_lang_item(LangItem::Unsize, Some(span)),
-                                        [src_obj, dst_obj],
-                                    );
+                                    // Replace trait object lifetimes with fresh vars, to allow casts like
+                                    // `*mut dyn FnOnce() + 'a` -> `*mut dyn FnOnce() + 'static`,
+                                    let src_obj =
+                                        freshen_single_trait_object_lifetime(self.infcx, src_obj);
+                                    let dst_obj =
+                                        freshen_single_trait_object_lifetime(self.infcx, dst_obj);
 
                                     debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
 
-                                    self.prove_trait_ref(
-                                        trait_ref,
+                                    self.eq_types(
+                                        src_obj,
+                                        dst_obj,
                                         location.to_locations(),
-                                        ConstraintCategory::Cast {
-                                            unsize_to: Some(tcx.fold_regions(dst_obj, |r, _| {
-                                                if let ty::ReVar(_) = r.kind() {
-                                                    tcx.lifetimes.re_erased
-                                                } else {
-                                                    r
-                                                }
-                                            })),
-                                        },
-                                    );
+                                        ConstraintCategory::Cast { unsize_to: None },
+                                    )
+                                    .unwrap();
                                 }
                             }
                             _ => {
@@ -2905,14 +2895,15 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
     }
 }
 
-fn erase_single_trait_object_lifetime<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-    let &ty::Dynamic(tty, region, dyn_kind @ ty::Dyn) = ty.kind() else {
-        bug!("expected trait object")
-    };
-
-    if region.is_erased() {
-        return ty;
-    }
+fn freshen_single_trait_object_lifetime<'tcx>(
+    infcx: &BorrowckInferCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Ty<'tcx> {
+    let &ty::Dynamic(tty, _, dyn_kind @ ty::Dyn) = ty.kind() else { bug!("expected trait object") };
 
-    tcx.mk_ty_from_kind(ty::Dynamic(tty, tcx.lifetimes.re_erased, dyn_kind))
+    let fresh = infcx
+        .next_region_var(rustc_infer::infer::RegionVariableOrigin::MiscVariable(DUMMY_SP), || {
+            RegionCtxt::Unknown
+        });
+    infcx.tcx.mk_ty_from_kind(ty::Dynamic(tty, fresh, dyn_kind))
 }
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index c78d9e57802..7b27a4b3ba7 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -34,8 +34,7 @@ use crate::errors;
 use crate::type_error_struct;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{codes::*, Applicability, Diag, ErrorGuaranteed};
-use rustc_hir::{self as hir, ExprKind, LangItem};
-use rustc_infer::traits::Obligation;
+use rustc_hir::{self as hir, ExprKind};
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::bug;
 use rustc_middle::mir::Mutability;
@@ -835,9 +834,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     (Some(src_principal), Some(dst_principal)) => {
                         let tcx = fcx.tcx;
 
-                        // Check that the traits are actually the same
-                        // (this is required as the `Unsize` check below would allow upcasting, etc)
-                        // N.B.: this is only correct as long as we don't support `trait A<T>: A<()>`.
+                        // Check that the traits are actually the same.
+                        // The `dyn Src = dyn Dst` check below would suffice,
+                        // but this may produce a better diagnostic.
                         //
                         // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
                         // and is unaffected by this check.
@@ -867,20 +866,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                             ty::Dyn,
                         ));
 
-                        // `dyn Src: Unsize<dyn Dst>`, this checks for matching generics
-                        let cause = fcx.misc(self.span);
-                        let obligation = Obligation::new(
-                            tcx,
-                            cause,
-                            fcx.param_env,
-                            ty::TraitRef::new(
-                                tcx,
-                                tcx.require_lang_item(LangItem::Unsize, Some(self.span)),
-                                [src_obj, dst_obj],
-                            ),
-                        );
-
-                        fcx.register_predicate(obligation);
+                        // `dyn Src = dyn Dst`, this checks for matching traits/generics
+                        fcx.demand_eqtype(self.span, src_obj, dst_obj);
 
                         // Check that `SrcAuto` is a superset of `DstAuto`.
                         // Emit an FCW otherwise.
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-args.rs b/tests/ui/cast/ptr-to-trait-obj-different-args.rs
index 88632f5506b..c6038cfe864 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-args.rs
+++ b/tests/ui/cast/ptr-to-trait-obj-different-args.rs
@@ -18,14 +18,14 @@ fn main() {
     let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid
 
     let x: *const dyn Trait<X> = &();
-    let y: *const dyn Trait<Y> = x as _; //~ error: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied
+    let y: *const dyn Trait<Y> = x as _; //~ error: mismatched types
 
     _ = (b, y);
 }
 
 fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
-    let _: *const dyn Trait<T> = x as _; //~ error: the trait bound `dyn Trait<X>: Unsize<dyn Trait<T>>` is not satisfied
-    let _: *const dyn Trait<X> = t as _; //~ error: the trait bound `dyn Trait<T>: Unsize<dyn Trait<X>>` is not satisfied
+    let _: *const dyn Trait<T> = x as _; //~ error: mismatched types
+    let _: *const dyn Trait<X> = t as _; //~ error: mismatched types
 }
 
 trait Assocked {
@@ -33,5 +33,5 @@ trait Assocked {
 }
 
 fn change_assoc(x: *mut dyn Assocked<Assoc = u8>) -> *mut dyn Assocked<Assoc = u32> {
-    x as _ //~ error: the trait bound `dyn Assocked<Assoc = u8>: Unsize<dyn Assocked<Assoc = u32>>` is not satisfied
+    x as _ //~ error: mismatched types
 }
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
index 65f0be8541f..b04289ae747 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
@@ -6,47 +6,48 @@ LL |     let b: *const dyn B = a as _;
    |
    = note: vtable kinds may not match
 
-error[E0277]: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied
+error[E0308]: mismatched types
   --> $DIR/ptr-to-trait-obj-different-args.rs:21:34
    |
 LL |     let y: *const dyn Trait<Y> = x as _;
-   |                                  ^^^^^^ the trait `Unsize<dyn Trait<Y>>` is not implemented for `dyn Trait<X>`
+   |                                  ^^^^^^ expected `X`, found `Y`
    |
-   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
+   = note: expected trait object `dyn Trait<X>`
+              found trait object `dyn Trait<Y>`
 
-error[E0277]: the trait bound `dyn Trait<X>: Unsize<dyn Trait<T>>` is not satisfied
+error[E0308]: mismatched types
   --> $DIR/ptr-to-trait-obj-different-args.rs:27:34
    |
+LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
+   |            - found this type parameter
 LL |     let _: *const dyn Trait<T> = x as _;
-   |                                  ^^^^^^ the trait `Unsize<dyn Trait<T>>` is not implemented for `dyn Trait<X>`
+   |                                  ^^^^^^ expected `X`, found type parameter `T`
    |
-   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) where dyn Trait<X>: Unsize<dyn Trait<T>> {
-   |                                                               ++++++++++++++++++++++++++++++++++++++++
+   = note: expected trait object `dyn Trait<X>`
+              found trait object `dyn Trait<T>`
 
-error[E0277]: the trait bound `dyn Trait<T>: Unsize<dyn Trait<X>>` is not satisfied
+error[E0308]: mismatched types
   --> $DIR/ptr-to-trait-obj-different-args.rs:28:34
    |
+LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
+   |            - expected this type parameter
+LL |     let _: *const dyn Trait<T> = x as _;
 LL |     let _: *const dyn Trait<X> = t as _;
-   |                                  ^^^^^^ the trait `Unsize<dyn Trait<X>>` is not implemented for `dyn Trait<T>`
-   |
-   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |                                  ^^^^^^ expected type parameter `T`, found `X`
    |
-LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) where dyn Trait<T>: Unsize<dyn Trait<X>> {
-   |                                                               ++++++++++++++++++++++++++++++++++++++++
+   = note: expected trait object `dyn Trait<T>`
+              found trait object `dyn Trait<X>`
 
-error[E0277]: the trait bound `dyn Assocked<Assoc = u8>: Unsize<dyn Assocked<Assoc = u32>>` is not satisfied
+error[E0308]: mismatched types
   --> $DIR/ptr-to-trait-obj-different-args.rs:36:5
    |
 LL |     x as _
-   |     ^^^^^^ the trait `Unsize<dyn Assocked<Assoc = u32>>` is not implemented for `dyn Assocked<Assoc = u8>`
+   |     ^^^^^^ expected `u8`, found `u32`
    |
-   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
+   = note: expected trait object `dyn Assocked<Assoc = u8>`
+              found trait object `dyn Assocked<Assoc = u32>`
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0277, E0606.
-For more information about an error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0308, E0606.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/upcast_soundness_bug.rs b/tests/ui/traits/upcast_soundness_bug.rs
index dd59f8cee50..5eaa58f7efe 100644
--- a/tests/ui/traits/upcast_soundness_bug.rs
+++ b/tests/ui/traits/upcast_soundness_bug.rs
@@ -57,7 +57,7 @@ pub fn user2() -> &'static dyn Trait<u8, u16> {
 fn main() {
     let p: *const dyn Trait<u8, u8> = &();
     let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
-    //~^ error: the trait bound `dyn Trait<u8, u8>: Unsize<dyn Trait<u8, u16>>` is not satisfied
+    //~^ error: mismatched types
     let p = p as *const dyn Super<u16>; // <- this upcast accesses improper vtable entry
     // accessing from L__unnamed_2 the position for the 'Super<u16> vtable (pointer)',
     // thus reading 'null pointer for missing_method'
diff --git a/tests/ui/traits/upcast_soundness_bug.stderr b/tests/ui/traits/upcast_soundness_bug.stderr
index ef2aeb3b1ec..5864abcdb41 100644
--- a/tests/ui/traits/upcast_soundness_bug.stderr
+++ b/tests/ui/traits/upcast_soundness_bug.stderr
@@ -1,11 +1,13 @@
-error[E0277]: the trait bound `dyn Trait<u8, u8>: Unsize<dyn Trait<u8, u16>>` is not satisfied
+error[E0308]: mismatched types
   --> $DIR/upcast_soundness_bug.rs:59:13
    |
 LL |     let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<dyn Trait<u8, u16>>` is not implemented for `dyn Trait<u8, u8>`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
    |
-   = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
+   = note: expected trait object `dyn Trait<u8, u8>`
+              found trait object `dyn Trait<u8, u16>`
+   = help: `dyn Trait<u8, u16>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.