Equate types instead of using Unsize

This commit is contained in:
Maybe Lapkin 2024-07-05 22:35:14 +02:00
parent 56de9da1f8
commit 073f3a263b
6 changed files with 68 additions and 87 deletions

View File

@ -38,6 +38,7 @@
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::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 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
&& 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 @@ fn fully_perform(
}
}
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))
}

View File

@ -34,8 +34,7 @@
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 @@ fn check_ptr_ptr_cast(
(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 @@ fn check_ptr_ptr_cast(
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.

View File

@ -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
}

View File

@ -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>`
| ^^^^^^ expected type parameter `T`, found `X`
|
= 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<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`.

View File

@ -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'

View File

@ -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`.