Allow unsizing pattern types with pointer base
This commit is contained in:
@@ -131,6 +131,11 @@ pub(crate) fn coerce_unsized_into<'tcx>(
|
|||||||
dst.write_cvalue(fx, CValue::by_val_pair(base, info, dst.layout()));
|
dst.write_cvalue(fx, CValue::by_val_pair(base, info, dst.layout()));
|
||||||
};
|
};
|
||||||
match (&src_ty.kind(), &dst_ty.kind()) {
|
match (&src_ty.kind(), &dst_ty.kind()) {
|
||||||
|
(ty::Pat(a, _), ty::Pat(b, _)) => {
|
||||||
|
let src = src.cast_pat_ty_to_base(fx.layout_of(*a));
|
||||||
|
let dst = dst.place_transmute_type(fx, *b);
|
||||||
|
return coerce_unsized_into(fx, src, dst);
|
||||||
|
}
|
||||||
(&ty::Ref(..), &ty::Ref(..))
|
(&ty::Ref(..), &ty::Ref(..))
|
||||||
| (&ty::Ref(..), &ty::RawPtr(..))
|
| (&ty::Ref(..), &ty::RawPtr(..))
|
||||||
| (&ty::RawPtr(..), &ty::RawPtr(..)) => coerce_ptr(),
|
| (&ty::RawPtr(..), &ty::RawPtr(..)) => coerce_ptr(),
|
||||||
|
|||||||
@@ -342,6 +342,14 @@ impl<'tcx> CValue<'tcx> {
|
|||||||
assert_eq!(self.layout().backend_repr, layout.backend_repr);
|
assert_eq!(self.layout().backend_repr, layout.backend_repr);
|
||||||
CValue(self.0, layout)
|
CValue(self.0, layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn cast_pat_ty_to_base(self, layout: TyAndLayout<'tcx>) -> Self {
|
||||||
|
let ty::Pat(base, _) = *self.layout().ty.kind() else {
|
||||||
|
panic!("not a pattern type: {:#?}", self.layout())
|
||||||
|
};
|
||||||
|
assert_eq!(layout.ty, base);
|
||||||
|
CValue(self.0, layout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A place where you can write a value to or read a value from
|
/// A place where you can write a value to or read a value from
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ pub(crate) fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||||||
) -> (Bx::Value, Bx::Value) {
|
) -> (Bx::Value, Bx::Value) {
|
||||||
debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
|
debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
|
||||||
match (src_ty.kind(), dst_ty.kind()) {
|
match (src_ty.kind(), dst_ty.kind()) {
|
||||||
|
(&ty::Pat(a, _), &ty::Pat(b, _)) => unsize_ptr(bx, src, a, b, old_info),
|
||||||
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
|
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
|
||||||
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => {
|
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => {
|
||||||
assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());
|
assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());
|
||||||
|
|||||||
@@ -466,6 +466,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
|
trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
|
||||||
match (src.layout.ty.kind(), cast_ty.ty.kind()) {
|
match (src.layout.ty.kind(), cast_ty.ty.kind()) {
|
||||||
|
(&ty::Pat(_, s_pat), &ty::Pat(cast_ty, c_pat)) if s_pat == c_pat => {
|
||||||
|
let src = self.project_field(src, FieldIdx::ZERO)?;
|
||||||
|
let dest = self.project_field(dest, FieldIdx::ZERO)?;
|
||||||
|
let cast_ty = self.layout_of(cast_ty)?;
|
||||||
|
self.unsize_into(&src, cast_ty, &dest)
|
||||||
|
}
|
||||||
(&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _))
|
(&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _))
|
||||||
| (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, s, c),
|
| (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, s, c),
|
||||||
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
|
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
|
||||||
|
|||||||
@@ -103,6 +103,8 @@ hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applica
|
|||||||
|
|
||||||
hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout
|
hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout
|
||||||
|
|
||||||
|
hir_analysis_coerce_same_pat_kind = only pattern types with the same pattern can be coerced between each other
|
||||||
|
|
||||||
hir_analysis_coerce_unsized_field_validity = for `{$ty}` to have a valid implementation of `{$trait_name}`, it must be possible to coerce the field of type `{$field_ty}`
|
hir_analysis_coerce_unsized_field_validity = for `{$ty}` to have a valid implementation of `{$trait_name}`, it must be possible to coerce the field of type `{$field_ty}`
|
||||||
.label = `{$field_ty}` must be a pointer, reference, or smart pointer that is allowed to be unsized
|
.label = `{$field_ty}` must be a pointer, reference, or smart pointer that is allowed to be unsized
|
||||||
|
|
||||||
|
|||||||
@@ -243,6 +243,18 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
|
|||||||
// in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
|
// in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
|
||||||
// even if they do not carry that attribute.
|
// even if they do not carry that attribute.
|
||||||
match (source.kind(), target.kind()) {
|
match (source.kind(), target.kind()) {
|
||||||
|
(&ty::Pat(_, pat_a), &ty::Pat(_, pat_b)) => {
|
||||||
|
if pat_a != pat_b {
|
||||||
|
return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
|
||||||
|
span,
|
||||||
|
trait_name,
|
||||||
|
pat_a: pat_a.to_string(),
|
||||||
|
pat_b: pat_b.to_string(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
(&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
|
(&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
|
||||||
if r_a == *r_b && mutbl_a == *mutbl_b =>
|
if r_a == *r_b && mutbl_a == *mutbl_b =>
|
||||||
{
|
{
|
||||||
@@ -408,6 +420,18 @@ pub(crate) fn coerce_unsized_info<'tcx>(
|
|||||||
(mt_a.ty, mt_b.ty, unsize_trait, None, span)
|
(mt_a.ty, mt_b.ty, unsize_trait, None, span)
|
||||||
};
|
};
|
||||||
let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
|
let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
|
||||||
|
(&ty::Pat(ty_a, pat_a), &ty::Pat(ty_b, pat_b)) => {
|
||||||
|
if pat_a != pat_b {
|
||||||
|
return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
|
||||||
|
span,
|
||||||
|
trait_name,
|
||||||
|
pat_a: pat_a.to_string(),
|
||||||
|
pat_b: pat_b.to_string(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
(ty_a, ty_b, coerce_unsized_trait, None, span)
|
||||||
|
}
|
||||||
|
|
||||||
(&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
|
(&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
|
||||||
infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a);
|
infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a);
|
||||||
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
|
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
|
||||||
|
|||||||
@@ -206,12 +206,8 @@ pub(crate) fn orphan_check_impl(
|
|||||||
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
|
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Pat(..) => (
|
|
||||||
LocalImpl::Disallow { problematic_kind: "pattern type" },
|
|
||||||
NonlocalImpl::DisallowOther,
|
|
||||||
),
|
|
||||||
|
|
||||||
ty::Bool
|
ty::Bool
|
||||||
|
| ty::Pat(..)
|
||||||
| ty::Char
|
| ty::Char
|
||||||
| ty::Int(..)
|
| ty::Int(..)
|
||||||
| ty::Uint(..)
|
| ty::Uint(..)
|
||||||
|
|||||||
@@ -1258,6 +1258,16 @@ pub(crate) struct CoerceUnsizedNonStruct {
|
|||||||
pub trait_name: &'static str,
|
pub trait_name: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis_coerce_same_pat_kind)]
|
||||||
|
pub(crate) struct CoerceSamePatKind {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub trait_name: &'static str,
|
||||||
|
pub pat_a: String,
|
||||||
|
pub pat_b: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
|
#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
|
||||||
pub(crate) struct CoerceSameStruct {
|
pub(crate) struct CoerceSameStruct {
|
||||||
|
|||||||
@@ -160,6 +160,9 @@ pub enum SelectionCandidate<'tcx> {
|
|||||||
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
|
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
|
||||||
FnPointerCandidate,
|
FnPointerCandidate,
|
||||||
|
|
||||||
|
/// Builtin impl of the `PointerLike` trait.
|
||||||
|
PointerLikeCandidate,
|
||||||
|
|
||||||
TraitAliasCandidate,
|
TraitAliasCandidate,
|
||||||
|
|
||||||
/// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
|
/// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
|
||||||
|
|||||||
@@ -695,6 +695,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
check_equal(self, location, *f_ty);
|
check_equal(self, location, *f_ty);
|
||||||
}
|
}
|
||||||
|
// Debug info is allowed to project into pattern types
|
||||||
|
ty::Pat(base, _) => check_equal(self, location, *base),
|
||||||
ty::Adt(adt_def, args) => {
|
ty::Adt(adt_def, args) => {
|
||||||
// see <https://github.com/rust-lang/rust/blob/7601adcc764d42c9f2984082b49948af652df986/compiler/rustc_middle/src/ty/layout.rs#L861-L864>
|
// see <https://github.com/rust-lang/rust/blob/7601adcc764d42c9f2984082b49948af652df986/compiler/rustc_middle/src/ty/layout.rs#L861-L864>
|
||||||
if self.tcx.is_lang_item(adt_def.did(), LangItem::DynMetadata) {
|
if self.tcx.is_lang_item(adt_def.did(), LangItem::DynMetadata) {
|
||||||
|
|||||||
@@ -1145,6 +1145,7 @@ fn find_tails_for_unsizing<'tcx>(
|
|||||||
debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic");
|
debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic");
|
||||||
|
|
||||||
match (source_ty.kind(), target_ty.kind()) {
|
match (source_ty.kind(), target_ty.kind()) {
|
||||||
|
(&ty::Pat(source, _), &ty::Pat(target, _)) => find_tails_for_unsizing(tcx, source, target),
|
||||||
(
|
(
|
||||||
&ty::Ref(_, source_pointee, _),
|
&ty::Ref(_, source_pointee, _),
|
||||||
&ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _),
|
&ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _),
|
||||||
|
|||||||
@@ -115,6 +115,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PointerLikeCandidate => {
|
||||||
|
let data = self.confirm_pointer_like_candidate(obligation);
|
||||||
|
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||||
|
}
|
||||||
|
|
||||||
TraitAliasCandidate => {
|
TraitAliasCandidate => {
|
||||||
let data = self.confirm_trait_alias_candidate(obligation);
|
let data = self.confirm_trait_alias_candidate(obligation);
|
||||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||||
@@ -631,6 +636,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
Ok(nested)
|
Ok(nested)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn confirm_pointer_like_candidate(
|
||||||
|
&mut self,
|
||||||
|
obligation: &PolyTraitObligation<'tcx>,
|
||||||
|
) -> PredicateObligations<'tcx> {
|
||||||
|
debug!(?obligation, "confirm_pointer_like_candidate");
|
||||||
|
let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
|
||||||
|
let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
|
||||||
|
let ty::Pat(base, _) = *self_ty.kind() else { bug!() };
|
||||||
|
let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
|
||||||
|
|
||||||
|
self.collect_predicates_for_types(
|
||||||
|
obligation.param_env,
|
||||||
|
cause,
|
||||||
|
obligation.recursion_depth + 1,
|
||||||
|
placeholder_predicate.def_id(),
|
||||||
|
vec![base],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn confirm_trait_alias_candidate(
|
fn confirm_trait_alias_candidate(
|
||||||
&mut self,
|
&mut self,
|
||||||
obligation: &PolyTraitObligation<'tcx>,
|
obligation: &PolyTraitObligation<'tcx>,
|
||||||
|
|||||||
@@ -2036,6 +2036,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||||||
| TraitUpcastingUnsizeCandidate(_)
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
|
| PointerLikeCandidate
|
||||||
| BikeshedGuaranteedNoDropCandidate => false,
|
| BikeshedGuaranteedNoDropCandidate => false,
|
||||||
// Non-global param candidates have already been handled, global
|
// Non-global param candidates have already been handled, global
|
||||||
// where-bounds get ignored.
|
// where-bounds get ignored.
|
||||||
|
|||||||
@@ -116,6 +116,7 @@
|
|||||||
#![feature(link_cfg)]
|
#![feature(link_cfg)]
|
||||||
#![feature(offset_of_enum)]
|
#![feature(offset_of_enum)]
|
||||||
#![feature(panic_internals)]
|
#![feature(panic_internals)]
|
||||||
|
#![feature(pattern_type_macro)]
|
||||||
#![feature(ptr_alignment_type)]
|
#![feature(ptr_alignment_type)]
|
||||||
#![feature(ptr_metadata)]
|
#![feature(ptr_metadata)]
|
||||||
#![feature(set_ptr_value)]
|
#![feature(set_ptr_value)]
|
||||||
@@ -171,6 +172,7 @@
|
|||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(no_core)]
|
#![feature(no_core)]
|
||||||
#![feature(optimize_attribute)]
|
#![feature(optimize_attribute)]
|
||||||
|
#![feature(pattern_types)]
|
||||||
#![feature(prelude_import)]
|
#![feature(prelude_import)]
|
||||||
#![feature(reborrow)]
|
#![feature(reborrow)]
|
||||||
#![feature(repr_simd)]
|
#![feature(repr_simd)]
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
//! Helper module for exporting the `pattern_type` macro
|
//! Helper module for exporting the `pattern_type` macro
|
||||||
|
|
||||||
|
use crate::marker::{Freeze, PointeeSized, Unsize};
|
||||||
|
use crate::ops::{CoerceUnsized, DispatchFromDyn};
|
||||||
|
|
||||||
/// Creates a pattern type.
|
/// Creates a pattern type.
|
||||||
/// ```ignore (cannot test this from within core yet)
|
/// ```ignore (cannot test this from within core yet)
|
||||||
/// type Positive = std::pat::pattern_type!(i32 is 1..);
|
/// type Positive = std::pat::pattern_type!(i32 is 1..);
|
||||||
@@ -73,3 +76,16 @@ impl const RangePattern for char {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<pattern_type!(*const U is !null)> for pattern_type!(*const T is !null) where
|
||||||
|
T: Unsize<U>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<pattern_type!(U is !null)> for pattern_type!(T is !null) {}
|
||||||
|
|
||||||
|
impl<T: PointeeSized> Unpin for pattern_type!(*const T is !null) {}
|
||||||
|
|
||||||
|
unsafe impl<T: PointeeSized> Freeze for pattern_type!(*const T is !null) {}
|
||||||
|
|
||||||
|
unsafe impl<T: PointeeSized> Freeze for pattern_type!(*mut T is !null) {}
|
||||||
|
|||||||
18
src/tools/miri/tests/pass/pattern-types.rs
Normal file
18
src/tools/miri/tests/pass/pattern-types.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#![feature(pattern_types, pattern_type_macro, sized_hierarchy)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::marker::PointeeSized;
|
||||||
|
use std::mem::transmute;
|
||||||
|
|
||||||
|
pub struct NonNull<T: PointeeSized> {
|
||||||
|
pointer: std::pat::pattern_type!(*const T is !null),
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Trait {}
|
||||||
|
impl Trait for () {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
let _: NonNull<dyn Trait> = NonNull { pointer: transmute(&mut () as *mut dyn Trait) };
|
||||||
|
}
|
||||||
|
}
|
||||||
18
tests/ui/type/pattern_types/unsize.rs
Normal file
18
tests/ui/type/pattern_types/unsize.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//! Show that pattern-types with pointer base types can be part of unsizing coercions
|
||||||
|
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![feature(pattern_type_macro, pattern_types)]
|
||||||
|
|
||||||
|
use std::pat::pattern_type;
|
||||||
|
|
||||||
|
type NonNull<T> = pattern_type!(*const T is !null);
|
||||||
|
|
||||||
|
trait Trait {}
|
||||||
|
impl Trait for u32 {}
|
||||||
|
impl Trait for i32 {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x: NonNull<u32> = unsafe { std::mem::transmute(std::ptr::dangling::<u32>()) };
|
||||||
|
let x: NonNull<dyn Trait> = x;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user