Skip to content

Commit 92fedff

Browse files
committed
Use !null pattern type in libcore
1 parent c4f39f6 commit 92fedff

File tree

41 files changed

+371
-196
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+371
-196
lines changed

compiler/rustc_codegen_ssa/src/base.rs

+1
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ pub(crate) fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
230230
) -> (Bx::Value, Bx::Value) {
231231
debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
232232
match (src_ty.kind(), dst_ty.kind()) {
233+
(&ty::Pat(a, _), &ty::Pat(b, _)) => unsize_ptr(bx, src, a, b, old_info),
233234
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
234235
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => {
235236
assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());

compiler/rustc_codegen_ssa/src/mir/block.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10641064
//
10651065
// This is also relevant for `Pin<&mut Self>`, where we need to peel the
10661066
// `Pin`.
1067+
1068+
loop {
1069+
match *op.layout.ty.kind() {
1070+
ty::Ref(..) | ty::RawPtr(..) => break,
1071+
ty::Pat(inner, _) => op.layout = bx.layout_of(inner),
1072+
_ => {
1073+
let (idx, _) = op.layout.non_1zst_field(bx).expect(
1074+
"not exactly one non-1-ZST field in a `DispatchFromDyn` type",
1075+
);
1076+
op = op.extract_field(self, bx, idx);
1077+
}
1078+
}
1079+
}
10671080
while !op.layout.ty.is_raw_ptr() && !op.layout.ty.is_ref() {
10681081
let (idx, _) = op.layout.non_1zst_field(bx).expect(
10691082
"not exactly one non-1-ZST field in a `DispatchFromDyn` type",

compiler/rustc_const_eval/src/interpret/cast.rs

+14
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
473473
) -> InterpResult<'tcx> {
474474
trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
475475
match (src.layout.ty.kind(), cast_ty.ty.kind()) {
476+
(&ty::Pat(s, s_pat), &ty::Pat(c, c_pat)) if s_pat == c_pat => {
477+
let mut src = src.clone();
478+
src.layout = self.layout_of(s)?;
479+
let mut dest = dest.clone();
480+
dest.layout = self.layout_of(c)?;
481+
let cast_ty = match *cast_ty.ty.kind() {
482+
ty::Pat(base, pat) if pat == c_pat => self.layout_of(base)?,
483+
_ => span_bug!(
484+
self.cur_span(),
485+
"unsize_into: invalid cast ty for pattern type: {cast_ty:#?}"
486+
),
487+
};
488+
self.unsize_into(&src, cast_ty, &dest)
489+
}
476490
(&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _))
477491
| (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, s, c),
478492
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {

compiler/rustc_const_eval/src/interpret/visitor.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,12 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
156156
);
157157
// ... that contains a `NonNull`... (gladly, only a single field here)
158158
assert_eq!(nonnull_ptr.layout().fields.count(), 1);
159-
let raw_ptr = self.ecx().project_field(&nonnull_ptr, 0)?; // the actual raw ptr
159+
let pat_ty = self.ecx().project_field(&nonnull_ptr, 0)?; // `*mut T is !null`
160+
let base = match *pat_ty.layout().ty.kind() {
161+
ty::Pat(base, _) => self.ecx().layout_of(base)?,
162+
_ => unreachable!(),
163+
};
164+
let raw_ptr = pat_ty.transmute(base, self.ecx())?; // The actual raw pointer
160165
// ... whose only field finally is a raw ptr we can dereference.
161166
self.visit_box(ty, &raw_ptr)?;
162167

compiler/rustc_hir_analysis/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ hir_analysis_coerce_unsized_field_validity = for `{$ty}` to have a valid impleme
104104
105105
hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures
106106
107+
hir_analysis_coerce_same_pat_kind = only pattern types with the same pattern can be coerced between each other
108+
107109
hir_analysis_coerce_zero = implementing `{$trait_name}` requires a field to be coerced
108110
109111
hir_analysis_coercion_between_struct_same_note = expected coercion between the same definition; expected `{$source_path}`, found `{$target_path}`

compiler/rustc_hir_analysis/src/coherence/builtin.rs

+33-6
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,18 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
251251
// in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
252252
// even if they do not carry that attribute.
253253
match (source.kind(), target.kind()) {
254+
(&ty::Pat(_, pat_a), &ty::Pat(_, pat_b)) => {
255+
if pat_a != pat_b {
256+
return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
257+
span,
258+
trait_name,
259+
pat_a: pat_a.to_string(),
260+
pat_b: pat_b.to_string(),
261+
}));
262+
}
263+
Ok(())
264+
}
265+
254266
(&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
255267
if r_a == *r_b && mutbl_a == *mutbl_b =>
256268
{
@@ -416,6 +428,18 @@ pub(crate) fn coerce_unsized_info<'tcx>(
416428
(mt_a.ty, mt_b.ty, unsize_trait, None, span)
417429
};
418430
let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
431+
(&ty::Pat(ty_a, pat_a), &ty::Pat(ty_b, pat_b)) => {
432+
if pat_a != pat_b {
433+
return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
434+
span,
435+
trait_name,
436+
pat_a: pat_a.to_string(),
437+
pat_b: pat_b.to_string(),
438+
}));
439+
}
440+
(ty_a, ty_b, coerce_unsized_trait, None, span)
441+
}
442+
419443
(&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
420444
infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
421445
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
@@ -715,13 +739,16 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
715739
let impl_span = tcx.def_span(checker.impl_def_id);
716740
let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
717741

718-
let is_permitted_primitive = match *self_ty.kind() {
719-
ty::Adt(def, _) => def.is_box(),
720-
ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
721-
_ => false,
722-
};
742+
fn is_permitted_primitive(self_ty: Ty<'_>) -> bool {
743+
match *self_ty.kind() {
744+
ty::Adt(def, _) => def.is_box(),
745+
ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
746+
ty::Pat(base, _) => is_permitted_primitive(base),
747+
_ => false,
748+
}
749+
}
723750

724-
if is_permitted_primitive
751+
if is_permitted_primitive(self_ty)
725752
&& let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
726753
&& layout.layout.is_pointer_like(&tcx.data_layout)
727754
{

compiler/rustc_hir_analysis/src/coherence/orphan.rs

+1-5
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

+10
Original file line numberDiff line numberDiff line change
@@ -1280,6 +1280,16 @@ pub(crate) struct CoerceUnsizedNonStruct {
12801280
pub trait_name: &'static str,
12811281
}
12821282

1283+
#[derive(Diagnostic)]
1284+
#[diag(hir_analysis_coerce_same_pat_kind)]
1285+
pub(crate) struct CoerceSamePatKind {
1286+
#[primary_span]
1287+
pub span: Span,
1288+
pub trait_name: &'static str,
1289+
pub pat_a: String,
1290+
pub pat_b: String,
1291+
}
1292+
12831293
#[derive(Diagnostic)]
12841294
#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
12851295
pub(crate) struct CoerceSameStruct {

compiler/rustc_middle/src/traits/select.rs

+3
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ pub enum SelectionCandidate<'tcx> {
159159
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
160160
FnPointerCandidate,
161161

162+
/// Builtin impl of the `PointerLike` trait.
163+
PointerLikeCandidate,
164+
162165
TraitAliasCandidate,
163166

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

compiler/rustc_mir_transform/src/elaborate_box_derefs.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
77
use rustc_middle::mir::visit::MutVisitor;
88
use rustc_middle::mir::*;
99
use rustc_middle::span_bug;
10-
use rustc_middle::ty::{Ty, TyCtxt};
10+
use rustc_middle::ty::{PatternKind, Ty, TyCtxt};
1111

1212
use crate::patch::MirPatch;
1313

@@ -17,13 +17,14 @@ fn build_ptr_tys<'tcx>(
1717
pointee: Ty<'tcx>,
1818
unique_did: DefId,
1919
nonnull_did: DefId,
20-
) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) {
20+
) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) {
2121
let args = tcx.mk_args(&[pointee.into()]);
2222
let unique_ty = tcx.type_of(unique_did).instantiate(tcx, args);
2323
let nonnull_ty = tcx.type_of(nonnull_did).instantiate(tcx, args);
2424
let ptr_ty = Ty::new_imm_ptr(tcx, pointee);
25+
let pat_ty = Ty::new_pat(tcx, ptr_ty, tcx.mk_pat(PatternKind::NotNull));
2526

26-
(unique_ty, nonnull_ty, ptr_ty)
27+
(unique_ty, nonnull_ty, pat_ty, ptr_ty)
2728
}
2829

2930
/// Constructs the projection needed to access a Box's pointer
@@ -63,7 +64,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
6364
{
6465
let source_info = self.local_decls[place.local].source_info;
6566

66-
let (unique_ty, nonnull_ty, ptr_ty) =
67+
let (unique_ty, nonnull_ty, _pat_ty, ptr_ty) =
6768
build_ptr_tys(tcx, boxed_ty, self.unique_did, self.nonnull_did);
6869

6970
let ptr_local = self.patch.new_temp(ptr_ty, source_info.span);
@@ -130,10 +131,11 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
130131
let new_projections =
131132
new_projections.get_or_insert_with(|| base.projection.to_vec());
132133

133-
let (unique_ty, nonnull_ty, ptr_ty) =
134+
let (unique_ty, nonnull_ty, pat_ty, ptr_ty) =
134135
build_ptr_tys(tcx, boxed_ty, unique_did, nonnull_did);
135136

136137
new_projections.extend_from_slice(&build_projection(unique_ty, nonnull_ty));
138+
new_projections.push(PlaceElem::Field(FieldIdx::ZERO, pat_ty));
137139
// While we can't project into `NonNull<_>` in a basic block
138140
// due to MCP#807, this is debug info where it's fine.
139141
new_projections.push(PlaceElem::Field(FieldIdx::ZERO, ptr_ty));

compiler/rustc_mir_transform/src/validate.rs

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

compiler/rustc_monomorphize/src/collector.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,7 @@ fn find_tails_for_unsizing<'tcx>(
10491049
debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic");
10501050

10511051
match (source_ty.kind(), target_ty.kind()) {
1052+
(&ty::Pat(source, _), &ty::Pat(target, _)) => find_tails_for_unsizing(tcx, source, target),
10521053
(
10531054
&ty::Ref(_, source_pointee, _),
10541055
&ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _),

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+13
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
121121
self.assemble_async_iterator_candidates(obligation, &mut candidates);
122122
} else if tcx.is_lang_item(def_id, LangItem::AsyncFnKindHelper) {
123123
self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates);
124+
} else if tcx.is_lang_item(def_id, LangItem::PointerLike) {
125+
self.assemble_pointer_like_candidates(obligation, &mut candidates);
124126
}
125127

126128
// FIXME: Put these into `else if` blocks above, since they're built-in.
@@ -469,6 +471,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
469471
}
470472
}
471473

474+
fn assemble_pointer_like_candidates(
475+
&mut self,
476+
obligation: &PolyTraitObligation<'tcx>,
477+
candidates: &mut SelectionCandidateSet<'tcx>,
478+
) {
479+
match obligation.self_ty().skip_binder().kind() {
480+
ty::Pat(..) => candidates.vec.push(PointerLikeCandidate),
481+
_ => {}
482+
}
483+
}
484+
472485
fn assemble_async_fn_kind_helper_candidates(
473486
&mut self,
474487
obligation: &PolyTraitObligation<'tcx>,

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+24
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
117117
ImplSource::Builtin(BuiltinImplSource::Misc, data)
118118
}
119119

120+
PointerLikeCandidate => {
121+
let data = self.confirm_pointer_like_candidate(obligation);
122+
ImplSource::Builtin(BuiltinImplSource::Misc, data)
123+
}
124+
120125
TraitAliasCandidate => {
121126
let data = self.confirm_trait_alias_candidate(obligation);
122127
ImplSource::Builtin(BuiltinImplSource::Misc, data)
@@ -671,6 +676,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
671676
Ok(nested)
672677
}
673678

679+
fn confirm_pointer_like_candidate(
680+
&mut self,
681+
obligation: &PolyTraitObligation<'tcx>,
682+
) -> PredicateObligations<'tcx> {
683+
debug!(?obligation, "confirm_fn_pointer_candidate");
684+
let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
685+
let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
686+
let ty::Pat(base, _) = *self_ty.kind() else { bug!() };
687+
let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
688+
689+
self.collect_predicates_for_types(
690+
obligation.param_env,
691+
cause,
692+
obligation.recursion_depth + 1,
693+
placeholder_predicate.def_id(),
694+
vec![base],
695+
)
696+
}
697+
674698
fn confirm_trait_alias_candidate(
675699
&mut self,
676700
obligation: &PolyTraitObligation<'tcx>,

compiler/rustc_trait_selection/src/traits/select/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1969,6 +1969,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19691969
| TraitUpcastingUnsizeCandidate(_)
19701970
| BuiltinObjectCandidate
19711971
| BuiltinUnsizeCandidate
1972+
| PointerLikeCandidate
19721973
| BikeshedGuaranteedNoDropCandidate => false,
19731974
// Non-global param candidates have already been handled, global
19741975
// where-bounds get ignored.

compiler/rustc_ty_utils/src/abi.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -724,14 +724,19 @@ fn make_thin_self_ptr<'tcx>(
724724
// To get the type `*mut RcInner<Self>`, we just keep unwrapping newtypes until we
725725
// get a built-in pointer type
726726
let mut wide_pointer_layout = layout;
727-
while !wide_pointer_layout.ty.is_raw_ptr() && !wide_pointer_layout.ty.is_ref() {
728-
wide_pointer_layout = wide_pointer_layout
729-
.non_1zst_field(cx)
730-
.expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type")
731-
.1
727+
loop {
728+
match *wide_pointer_layout.ty.kind() {
729+
ty::Ref(..) | ty::RawPtr(..) => break wide_pointer_layout.ty,
730+
ty::Pat(inner, _) => match inner.kind() {
731+
ty::RawPtr(..) => break inner,
732+
_ => panic!("only raw pointers are allowed in unsized pattern types"),
733+
},
734+
_ => wide_pointer_layout = wide_pointer_layout
735+
.non_1zst_field(cx)
736+
.unwrap_or_else(|| panic!("not exactly one non-1-ZST field in a `DispatchFromDyn` type: {wide_pointer_layout:#?}"))
737+
.1,
738+
}
732739
}
733-
734-
wide_pointer_layout.ty
735740
};
736741

737742
// we now have a type like `*mut RcInner<dyn Trait>`

library/core/src/pat.rs

+23
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
//! Helper module for exporting the `pattern_type` macro
22
3+
#[cfg(not(bootstrap))]
4+
use crate::marker::{Freeze, Unsize};
5+
#[cfg(not(bootstrap))]
6+
use crate::ops::{CoerceUnsized, DispatchFromDyn};
7+
38
/// Creates a pattern type.
49
/// ```ignore (cannot test this from within core yet)
510
/// type Positive = std::pat::pattern_type!(i32 is 1..);
@@ -74,3 +79,21 @@ impl const RangePattern for char {
7479
}
7580
}
7681
}
82+
83+
#[cfg(not(bootstrap))]
84+
impl<T: ?Sized, U: ?Sized> CoerceUnsized<pattern_type!(*const U is !null)> for pattern_type!(*const T is !null) where
85+
T: Unsize<U>
86+
{
87+
}
88+
89+
#[cfg(not(bootstrap))]
90+
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<pattern_type!(U is !null)> for pattern_type!(T is !null) {}
91+
92+
#[cfg(not(bootstrap))]
93+
impl<T: ?Sized> Unpin for pattern_type!(*const T is !null) {}
94+
95+
#[cfg(not(bootstrap))]
96+
unsafe impl<T: ?Sized> Freeze for pattern_type!(*const T is !null) {}
97+
98+
#[cfg(not(bootstrap))]
99+
unsafe impl<T: ?Sized> Freeze for pattern_type!(*mut T is !null) {}

0 commit comments

Comments
 (0)