diff options
| -rw-r--r-- | compiler/rustc_borrowck/src/type_check/mod.rs | 65 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/cast.rs | 25 | ||||
| -rw-r--r-- | tests/ui/cast/ptr-to-trait-obj-different-args.rs | 8 | ||||
| -rw-r--r-- | tests/ui/cast/ptr-to-trait-obj-different-args.stderr | 45 | ||||
| -rw-r--r-- | tests/ui/traits/upcast_soundness_bug.rs | 2 | ||||
| -rw-r--r-- | tests/ui/traits/upcast_soundness_bug.stderr | 10 |
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`. |
