Skip to content

Commit 3b66729

Browse files
committed
Allow unsizing pattern types with pointer base
1 parent 9d7db1a commit 3b66729

File tree

17 files changed

+142
-5
lines changed

17 files changed

+142
-5
lines changed

compiler/rustc_codegen_cranelift/src/unsize.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ pub(crate) fn coerce_unsized_into<'tcx>(
131131
dst.write_cvalue(fx, CValue::by_val_pair(base, info, dst.layout()));
132132
};
133133
match (&src_ty.kind(), &dst_ty.kind()) {
134+
(ty::Pat(a, _), ty::Pat(b, _)) => {
135+
let src = src.cast_pat_ty_to_base(fx.layout_of(*a));
136+
let dst = dst.place_transmute_type(fx, *b);
137+
return coerce_unsized_into(fx, src, dst);
138+
}
134139
(&ty::Ref(..), &ty::Ref(..))
135140
| (&ty::Ref(..), &ty::RawPtr(..))
136141
| (&ty::RawPtr(..), &ty::RawPtr(..)) => coerce_ptr(),

compiler/rustc_codegen_cranelift/src/value_and_place.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,14 @@ impl<'tcx> CValue<'tcx> {
342342
assert_eq!(self.layout().backend_repr, layout.backend_repr);
343343
CValue(self.0, layout)
344344
}
345+
346+
pub(crate) fn cast_pat_ty_to_base(self, layout: TyAndLayout<'tcx>) -> Self {
347+
let ty::Pat(base, _) = *self.layout().ty.kind() else {
348+
panic!("not a pattern type: {:#?}", self.layout())
349+
};
350+
assert_eq!(layout.ty, base);
351+
CValue(self.0, layout)
352+
}
345353
}
346354

347355
/// A place where you can write a value to or read a value from

compiler/rustc_codegen_ssa/src/base.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ pub(crate) fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
226226
) -> (Bx::Value, Bx::Value) {
227227
debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
228228
match (src_ty.kind(), dst_ty.kind()) {
229+
(&ty::Pat(a, _), &ty::Pat(b, _)) => unsize_ptr(bx, src, a, b, old_info),
229230
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
230231
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => {
231232
assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());

compiler/rustc_const_eval/src/interpret/cast.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
466466
) -> InterpResult<'tcx> {
467467
trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
468468
match (src.layout.ty.kind(), cast_ty.ty.kind()) {
469+
(&ty::Pat(_, s_pat), &ty::Pat(cast_ty, c_pat)) if s_pat == c_pat => {
470+
let src = self.project_field(src, FieldIdx::ZERO)?;
471+
let dest = self.project_field(dest, FieldIdx::ZERO)?;
472+
let cast_ty = self.layout_of(cast_ty)?;
473+
self.unsize_into(&src, cast_ty, &dest)
474+
}
469475
(&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _))
470476
| (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, s, c),
471477
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applica
106106
107107
hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout
108108
109+
hir_analysis_coerce_same_pat_kind = only pattern types with the same pattern can be coerced between each other
110+
109111
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}`
110112
.label = `{$field_ty}` must be a pointer, reference, or smart pointer that is allowed to be unsized
111113

compiler/rustc_hir_analysis/src/coherence/builtin.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,18 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
243243
// in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
244244
// even if they do not carry that attribute.
245245
match (source.kind(), target.kind()) {
246+
(&ty::Pat(_, pat_a), &ty::Pat(_, pat_b)) => {
247+
if pat_a != pat_b {
248+
return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
249+
span,
250+
trait_name,
251+
pat_a: pat_a.to_string(),
252+
pat_b: pat_b.to_string(),
253+
}));
254+
}
255+
Ok(())
256+
}
257+
246258
(&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
247259
if r_a == *r_b && mutbl_a == *mutbl_b =>
248260
{
@@ -408,6 +420,18 @@ pub(crate) fn coerce_unsized_info<'tcx>(
408420
(mt_a.ty, mt_b.ty, unsize_trait, None, span)
409421
};
410422
let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
423+
(&ty::Pat(ty_a, pat_a), &ty::Pat(ty_b, pat_b)) => {
424+
if pat_a != pat_b {
425+
return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
426+
span,
427+
trait_name,
428+
pat_a: pat_a.to_string(),
429+
pat_b: pat_b.to_string(),
430+
}));
431+
}
432+
(ty_a, ty_b, coerce_unsized_trait, None, span)
433+
}
434+
411435
(&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
412436
infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a);
413437
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };

compiler/rustc_hir_analysis/src/coherence/orphan.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,8 @@ pub(crate) fn orphan_check_impl(
206206
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
207207
}
208208

209-
ty::Pat(..) => (
210-
LocalImpl::Disallow { problematic_kind: "pattern type" },
211-
NonlocalImpl::DisallowOther,
212-
),
213-
214209
ty::Bool
210+
| ty::Pat(..)
215211
| ty::Char
216212
| ty::Int(..)
217213
| ty::Uint(..)

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,16 @@ pub(crate) struct CoerceUnsizedNonStruct {
12581258
pub trait_name: &'static str,
12591259
}
12601260

1261+
#[derive(Diagnostic)]
1262+
#[diag(hir_analysis_coerce_same_pat_kind)]
1263+
pub(crate) struct CoerceSamePatKind {
1264+
#[primary_span]
1265+
pub span: Span,
1266+
pub trait_name: &'static str,
1267+
pub pat_a: String,
1268+
pub pat_b: String,
1269+
}
1270+
12611271
#[derive(Diagnostic)]
12621272
#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
12631273
pub(crate) struct CoerceSameStruct {

compiler/rustc_middle/src/traits/select.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ pub enum SelectionCandidate<'tcx> {
154154
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
155155
FnPointerCandidate,
156156

157+
/// Builtin impl of the `PointerLike` trait.
158+
PointerLikeCandidate,
159+
157160
TraitAliasCandidate,
158161

159162
/// Matching `dyn Trait` with a supertrait of `Trait`. The index is the

compiler/rustc_mir_transform/src/validate.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
708708
};
709709
check_equal(self, location, *f_ty);
710710
}
711+
// Debug info is allowed to project into pattern types
712+
ty::Pat(base, _) => check_equal(self, location, *base),
711713
ty::Adt(adt_def, args) => {
712714
// see <https://github.com/rust-lang/rust/blob/7601adcc764d42c9f2984082b49948af652df986/compiler/rustc_middle/src/ty/layout.rs#L861-L864>
713715
if self.tcx.is_lang_item(adt_def.did(), LangItem::DynMetadata) {

0 commit comments

Comments
 (0)