From 073f3a263b179ed446a1ab1209da9d9990bc6f74 Mon Sep 17 00:00:00 2001 From: Maybe Lapkin Date: Fri, 5 Jul 2024 22:35:14 +0200 Subject: [PATCH] Equate types instead of using `Unsize` --- compiler/rustc_borrowck/src/type_check/mod.rs | 65 ++++++++----------- compiler/rustc_hir_typeck/src/cast.rs | 25 ++----- .../cast/ptr-to-trait-obj-different-args.rs | 8 +-- .../ptr-to-trait-obj-different-args.stderr | 45 ++++++------- tests/ui/traits/upcast_soundness_bug.rs | 2 +- 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::>(), ), - 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::>(), ), - 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") - }; +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") }; - if region.is_erased() { - return ty; - } - - 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: 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`, 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 = &(); - let y: *const dyn Trait = x as _; //~ error: the trait bound `dyn Trait: Unsize>` is not satisfied + let y: *const dyn Trait = x as _; //~ error: mismatched types _ = (b, y); } fn generic(x: *const dyn Trait, t: *const dyn Trait) { - let _: *const dyn Trait = x as _; //~ error: the trait bound `dyn Trait: Unsize>` is not satisfied - let _: *const dyn Trait = t as _; //~ error: the trait bound `dyn Trait: Unsize>` is not satisfied + let _: *const dyn Trait = x as _; //~ error: mismatched types + let _: *const dyn Trait = t as _; //~ error: mismatched types } trait Assocked { @@ -33,5 +33,5 @@ trait Assocked { } fn change_assoc(x: *mut dyn Assocked) -> *mut dyn Assocked { - x as _ //~ error: the trait bound `dyn Assocked: Unsize>` 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: Unsize>` is not satisfied +error[E0308]: mismatched types --> $DIR/ptr-to-trait-obj-different-args.rs:21:34 | LL | let y: *const dyn Trait = x as _; - | ^^^^^^ the trait `Unsize>` is not implemented for `dyn Trait` + | ^^^^^^ expected `X`, found `Y` | - = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information + = note: expected trait object `dyn Trait` + found trait object `dyn Trait` -error[E0277]: the trait bound `dyn Trait: Unsize>` is not satisfied +error[E0308]: mismatched types --> $DIR/ptr-to-trait-obj-different-args.rs:27:34 | +LL | fn generic(x: *const dyn Trait, t: *const dyn Trait) { + | - found this type parameter LL | let _: *const dyn Trait = x as _; - | ^^^^^^ the trait `Unsize>` is not implemented for `dyn Trait` + | ^^^^^^ expected `X`, found type parameter `T` | - = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | fn generic(x: *const dyn Trait, t: *const dyn Trait) where dyn Trait: Unsize> { - | ++++++++++++++++++++++++++++++++++++++++ + = note: expected trait object `dyn Trait` + found trait object `dyn Trait` -error[E0277]: the trait bound `dyn Trait: Unsize>` is not satisfied +error[E0308]: mismatched types --> $DIR/ptr-to-trait-obj-different-args.rs:28:34 | +LL | fn generic(x: *const dyn Trait, t: *const dyn Trait) { + | - expected this type parameter +LL | let _: *const dyn Trait = x as _; LL | let _: *const dyn Trait = t as _; - | ^^^^^^ the trait `Unsize>` is not implemented for `dyn Trait` + | ^^^^^^ expected type parameter `T`, found `X` | - = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | fn generic(x: *const dyn Trait, t: *const dyn Trait) where dyn Trait: Unsize> { - | ++++++++++++++++++++++++++++++++++++++++ + = note: expected trait object `dyn Trait` + found trait object `dyn Trait` -error[E0277]: the trait bound `dyn Assocked: Unsize>` is not satisfied +error[E0308]: mismatched types --> $DIR/ptr-to-trait-obj-different-args.rs:36:5 | LL | x as _ - | ^^^^^^ the trait `Unsize>` is not implemented for `dyn Assocked` + | ^^^^^^ expected `u8`, found `u32` | - = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information + = note: expected trait object `dyn Assocked` + found trait object `dyn Assocked` 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 { fn main() { let p: *const dyn Trait = &(); let p = p as *const dyn Trait; // <- this is bad! - //~^ error: the trait bound `dyn Trait: Unsize>` is not satisfied + //~^ error: mismatched types let p = p as *const dyn Super; // <- this upcast accesses improper vtable entry // accessing from L__unnamed_2 the position for the 'Super 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: Unsize>` is not satisfied +error[E0308]: mismatched types --> $DIR/upcast_soundness_bug.rs:59:13 | LL | let p = p as *const dyn Trait; // <- this is bad! - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize>` is not implemented for `dyn Trait` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `u16` | - = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information + = note: expected trait object `dyn Trait` + found trait object `dyn Trait` + = help: `dyn Trait` implements `Trait` so you could box the found value and coerce it to the trait object `Box`, 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`.