diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 3c576316f6230..39cda360afb14 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2571,6 +2571,9 @@ pub enum TyPatKind {
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
Range(Option
>, Option
>, Spanned),
+ /// A `!null` pattern for raw pointers.
+ NotNull,
+
Or(ThinVec>),
/// Placeholder for a pattern that wasn't syntactically well formed in some way.
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 37fcc0d2167b2..1f29abb8c682c 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -1208,7 +1208,7 @@ macro_rules! common_visitor_and_walkers {
try_visit!(visit_span(vis, span));
}
TyPatKind::Or(variants) => walk_list!(vis, visit_ty_pat, variants),
- TyPatKind::Err(_) => {}
+ TyPatKind::NotNull | TyPatKind::Err(_) => {}
}
visit_span(vis, span)
}
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index e444062104813..e7c7471611ee3 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -143,7 +143,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
// return inner to be processed in next loop
PatKind::Paren(inner) => pattern = inner,
- PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
+ PatKind::MacCall(_) => {
+ panic!("{pattern:#?} shouldn't exist here")
+ }
PatKind::Err(guar) => break hir::PatKind::Err(*guar),
}
};
@@ -460,6 +462,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
}),
),
+ TyPatKind::NotNull => hir::TyPatKind::NotNull,
TyPatKind::Or(variants) => {
hir::TyPatKind::Or(self.arena.alloc_from_iter(
variants.iter().map(|pat| self.lower_ty_pat_mut(pat, base_type)),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index aff98c63bcb41..f3bb40d9dade8 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1226,6 +1226,7 @@ impl<'a> State<'a> {
self.print_expr_anon_const(end, &[]);
}
}
+ rustc_ast::TyPatKind::NotNull => self.word("!null"),
rustc_ast::TyPatKind::Or(variants) => {
let mut first = true;
for pat in variants {
diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs
index b61af0b0aaa12..9768646e5f919 100644
--- a/compiler/rustc_builtin_macros/src/pattern_type.rs
+++ b/compiler/rustc_builtin_macros/src/pattern_type.rs
@@ -28,15 +28,21 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P
let ty = parser.parse_ty()?;
parser.expect_keyword(exp!(Is))?;
- let pat = pat_to_ty_pat(
- cx,
- *parser.parse_pat_no_top_guard(
- None,
- RecoverComma::No,
- RecoverColon::No,
- CommaRecoveryMode::EitherTupleOrPipe,
- )?,
- );
+ let start = parser.token.span;
+ let pat = if parser.eat(exp!(Bang)) {
+ parser.expect_keyword(exp!(Null))?;
+ ty_pat(TyPatKind::NotNull, start.to(parser.token.span))
+ } else {
+ pat_to_ty_pat(
+ cx,
+ *parser.parse_pat_no_top_guard(
+ None,
+ RecoverComma::No,
+ RecoverColon::No,
+ CommaRecoveryMode::EitherTupleOrPipe,
+ )?,
+ )
+ };
if parser.token != token::Eof {
parser.unexpected()?;
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index 2aee0b2e97424..2dba3a0fa6f1e 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -133,6 +133,11 @@ pub(crate) fn coerce_unsized_into<'tcx>(
dst.write_cvalue(fx, CValue::by_val_pair(base, info, dst.layout()));
};
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::RawPtr(..))
| (&ty::RawPtr(..), &ty::RawPtr(..)) => coerce_ptr(),
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 9d73f200afe2b..0c98c4f33f80d 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -342,6 +342,14 @@ impl<'tcx> CValue<'tcx> {
assert_eq!(self.layout().backend_repr, layout.backend_repr);
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
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 18581f854b664..dc50041203b3e 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -227,6 +227,7 @@ pub(crate) fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
) -> (Bx::Value, Bx::Value) {
debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
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::RawPtr(a, _), &ty::RawPtr(b, _)) => {
assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 7a73d70fc85dc..179d6d8d5cfbd 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -459,6 +459,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) -> InterpResult<'tcx> {
trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
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::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, s, c),
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index fc4d13af8c42a..ad2a1a42b9e09 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -1249,9 +1249,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
// When you extend this match, make sure to also add tests to
// tests/ui/type/pattern_types/validity.rs((
match **pat {
- // Range patterns are precisely reflected into `valid_range` and thus
+ // Range and non-null patterns are precisely reflected into `valid_range` and thus
// handled fully by `visit_scalar` (called below).
ty::PatternKind::Range { .. } => {},
+ ty::PatternKind::NotNull => {},
// FIXME(pattern_types): check that the value is covered by one of the variants.
// For now, we rely on layout computation setting the scalar's `valid_range` to
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 0f6f81d7964c4..501593929f858 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1823,6 +1823,9 @@ pub enum TyPatKind<'hir> {
/// A range pattern (e.g., `1..=2` or `1..2`).
Range(&'hir ConstArg<'hir>, &'hir ConstArg<'hir>),
+ /// A pattern that excludes null pointers
+ NotNull,
+
/// A list of patterns where only one needs to be satisfied
Or(&'hir [TyPat<'hir>]),
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 1bb8f7ad8945a..77208e7bc40fc 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -726,7 +726,7 @@ pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>)
try_visit!(visitor.visit_const_arg_unambig(upper_bound));
}
TyPatKind::Or(patterns) => walk_list!(visitor, visit_pattern_type_pattern, patterns),
- TyPatKind::Err(_) => (),
+ TyPatKind::NotNull | TyPatKind::Err(_) => (),
}
V::Result::output()
}
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 529d3578985ae..2c97e23077714 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -106,6 +106,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_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}`
.label = `{$field_ty}` must be a pointer, reference, or smart pointer that is allowed to be unsized
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 8356a0af63c35..68085f095a945 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -248,6 +248,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)
// even if they do not carry that attribute.
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))
if r_a == *r_b && mutbl_a == *mutbl_b =>
{
@@ -413,6 +425,18 @@ pub(crate) fn coerce_unsized_info<'tcx>(
(mt_a.ty, mt_b.ty, unsize_trait, None, span)
};
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)) => {
infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a);
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index c75fef9f716d6..6660ed4181084 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -206,12 +206,8 @@ pub(crate) fn orphan_check_impl(
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
}
- ty::Pat(..) => (
- LocalImpl::Disallow { problematic_kind: "pattern type" },
- NonlocalImpl::DisallowOther,
- ),
-
ty::Bool
+ | ty::Pat(..)
| ty::Char
| ty::Int(..)
| ty::Uint(..)
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index c1c828392126f..b283ea95e4365 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1279,6 +1279,16 @@ pub(crate) struct CoerceUnsizedNonStruct {
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)]
#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
pub(crate) struct CoerceSameStruct {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 20d165897e2a3..181b440dfdde9 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2579,6 +2579,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.span_delayed_bug(ty_span, "invalid base type for range pattern")),
}
}
+ hir::TyPatKind::NotNull => Ok(ty::PatternKind::NotNull),
hir::TyPatKind::Or(patterns) => {
self.tcx()
.mk_patterns_from_iter(patterns.iter().map(|pat| {
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 960ec7f66ab15..09da0e2ec6511 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -340,6 +340,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
self.add_constraints_from_const(current, start, variance);
self.add_constraints_from_const(current, end, variance);
}
+ ty::PatternKind::NotNull => {}
ty::PatternKind::Or(patterns) => {
for pat in patterns {
self.add_constraints_from_pat(current, variance, pat)
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 3a525021f6fc9..30c94a3cfed38 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1874,6 +1874,10 @@ impl<'a> State<'a> {
self.word("..=");
self.print_const_arg(end);
}
+ TyPatKind::NotNull => {
+ self.word_space("not");
+ self.word("null");
+ }
TyPatKind::Or(patterns) => {
self.popen();
let mut first = true;
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index e41bc8f852e58..adbfac7cc7ea8 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -905,6 +905,7 @@ fn pat_ty_is_known_nonnull<'tcx>(
// to ensure we aren't wrapping over zero.
start > 0 && end >= start
}
+ ty::PatternKind::NotNull => true,
ty::PatternKind::Or(patterns) => {
patterns.iter().all(|pat| pat_ty_is_known_nonnull(tcx, typing_env, pat))
}
@@ -1066,7 +1067,9 @@ fn get_nullable_type_from_pat<'tcx>(
pat: ty::Pattern<'tcx>,
) -> Option> {
match *pat {
- ty::PatternKind::Range { .. } => get_nullable_type(tcx, typing_env, base),
+ ty::PatternKind::NotNull | ty::PatternKind::Range { .. } => {
+ get_nullable_type(tcx, typing_env, base)
+ }
ty::PatternKind::Or(patterns) => {
let first = get_nullable_type_from_pat(tcx, typing_env, base, patterns[0])?;
for &pat in &patterns[1..] {
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index c498e6b3c83da..34b5aafc6aec7 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -154,6 +154,9 @@ pub enum SelectionCandidate<'tcx> {
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
FnPointerCandidate,
+ /// Builtin impl of the `PointerLike` trait.
+ PointerLikeCandidate,
+
TraitAliasCandidate,
/// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 809717513c795..a99049ff92dcc 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -808,11 +808,21 @@ where
| ty::FnDef(..)
| ty::CoroutineWitness(..)
| ty::Foreign(..)
- | ty::Pat(_, _)
| ty::Dynamic(_, _, ty::Dyn) => {
bug!("TyAndLayout::field({:?}): not applicable", this)
}
+ // May contain wide pointers
+ ty::Pat(base, pat) => match *pat {
+ ty::PatternKind::NotNull => {
+ assert_eq!(i, 0);
+ TyMaybeWithLayout::Ty(base)
+ }
+ ty::PatternKind::Range { .. } | ty::PatternKind::Or(_) => {
+ bug!("TyAndLayout::field({this:?}): only applicable to !null patterns")
+ }
+ },
+
ty::UnsafeBinder(bound_ty) => {
let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
field_ty_or_layout(TyAndLayout { ty, ..this }, cx, i)
diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs
index 5af9b17dd7777..335e5c0647435 100644
--- a/compiler/rustc_middle/src/ty/pattern.rs
+++ b/compiler/rustc_middle/src/ty/pattern.rs
@@ -30,6 +30,7 @@ impl<'tcx> Flags for Pattern<'tcx> {
}
flags
}
+ ty::PatternKind::NotNull => rustc_type_ir::TypeFlags::empty(),
}
}
@@ -45,6 +46,7 @@ impl<'tcx> Flags for Pattern<'tcx> {
}
idx
}
+ ty::PatternKind::NotNull => rustc_type_ir::INNERMOST,
}
}
}
@@ -91,6 +93,7 @@ impl<'tcx> IrPrint> for TyCtxt<'tcx> {
write!(f, "..={end}")
}
+ PatternKind::NotNull => write!(f, "!null"),
PatternKind::Or(patterns) => {
write!(f, "(")?;
let mut first = true;
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index dc1d60f3d43c1..a4d7423818ea2 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -59,6 +59,7 @@ impl<'tcx> Relate> for ty::Pattern<'tcx> {
let end = relation.relate(end_a, end_b)?;
Ok(tcx.mk_pat(ty::PatternKind::Range { start, end }))
}
+ (ty::PatternKind::NotNull, ty::PatternKind::NotNull) => Ok(a),
(&ty::PatternKind::Or(a), &ty::PatternKind::Or(b)) => {
if a.len() != b.len() {
return Err(TypeError::Mismatch);
@@ -67,7 +68,10 @@ impl<'tcx> Relate> for ty::Pattern<'tcx> {
let patterns = tcx.mk_patterns_from_iter(v)?;
Ok(tcx.mk_pat(ty::PatternKind::Or(patterns)))
}
- (ty::PatternKind::Range { .. } | ty::PatternKind::Or(_), _) => Err(TypeError::Mismatch),
+ (
+ ty::PatternKind::NotNull | ty::PatternKind::Range { .. } | ty::PatternKind::Or(_),
+ _,
+ ) => Err(TypeError::Mismatch),
}
}
}
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index cbb9bbfd12f9f..05847139ddf91 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -707,6 +707,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
};
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) => {
// see
if self.tcx.is_lang_item(adt_def.did(), LangItem::DynMetadata) {
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 131064f9832c0..7d068a6a0ddc3 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1070,6 +1070,7 @@ fn find_tails_for_unsizing<'tcx>(
debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic");
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(_, target_pointee, _) | &ty::RawPtr(target_pointee, _),
diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs
index b91548196a305..1d7ff549f1b09 100644
--- a/compiler/rustc_parse/src/parser/token_type.rs
+++ b/compiler/rustc_parse/src/parser/token_type.rs
@@ -139,6 +139,7 @@ pub enum TokenType {
SymNomem,
SymNoreturn,
SymNostack,
+ SymNull,
SymOptions,
SymOut,
SymPreservesFlags,
@@ -273,6 +274,7 @@ impl TokenType {
SymNomem,
SymNoreturn,
SymNostack,
+ SymNull,
SymOptions,
SymOut,
SymPreservesFlags,
@@ -348,6 +350,7 @@ impl TokenType {
TokenType::SymNomem => Some(sym::nomem),
TokenType::SymNoreturn => Some(sym::noreturn),
TokenType::SymNostack => Some(sym::nostack),
+ TokenType::SymNull => Some(sym::null),
TokenType::SymOptions => Some(sym::options),
TokenType::SymOut => Some(sym::out),
TokenType::SymPreservesFlags => Some(sym::preserves_flags),
@@ -562,6 +565,7 @@ macro_rules! exp {
(Nomem) => { exp!(@sym, nomem, SymNomem) };
(Noreturn) => { exp!(@sym, noreturn, SymNoreturn) };
(Nostack) => { exp!(@sym, nostack, SymNostack) };
+ (Null) => { exp!(@sym, null, SymNull) };
(Options) => { exp!(@sym, options, SymOptions) };
(Out) => { exp!(@sym, out, SymOut) };
(PreservesFlags) => { exp!(@sym, preserves_flags, SymPreservesFlags) };
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 08629090bb109..41f1fa6927124 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -976,7 +976,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc
self.visit_ty_pat(pat)
}
}
- TyPatKind::Err(_) => {}
+ TyPatKind::NotNull | TyPatKind::Err(_) => {}
}
}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 09f01d8704e2a..90a20bca4a504 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1509,6 +1509,7 @@ symbols! {
not,
notable_trait,
note,
+ null,
object_safe_for_dispatch,
of,
off,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index fe0f8e6113ef7..86221decf3df0 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -263,6 +263,9 @@ impl<'tcx> SymbolMangler<'tcx> {
Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?;
}
}
+ ty::PatternKind::NotNull => {
+ self.tcx.types.unit.print(self)?;
+ }
ty::PatternKind::Or(patterns) => {
for pat in patterns {
self.print_pat(pat)?;
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 545531f927a95..1cab0e8dc01d6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -115,6 +115,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, data)
}
+ PointerLikeCandidate => {
+ let data = self.confirm_pointer_like_candidate(obligation);
+ ImplSource::Builtin(BuiltinImplSource::Misc, data)
+ }
+
TraitAliasCandidate => {
let data = self.confirm_trait_alias_candidate(obligation);
ImplSource::Builtin(BuiltinImplSource::Misc, data)
@@ -628,6 +633,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index c9930c69b32cc..6e1b3d2b58ca8 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2002,6 +2002,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| TraitUpcastingUnsizeCandidate(_)
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
+ | PointerLikeCandidate
| BikeshedGuaranteedNoDropCandidate => false,
// Non-global param candidates have already been handled, global
// where-bounds get ignored.
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index d4e6a23f0eb6b..bc33aa408950b 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -704,6 +704,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
check(start);
check(end);
}
+ ty::PatternKind::NotNull => {}
ty::PatternKind::Or(patterns) => {
for pat in patterns {
self.add_wf_preds_for_pat_ty(base_ty, pat)
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 163e2b3088374..cfeb35b050cb3 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -213,9 +213,7 @@ fn layout_of_uncached<'tcx>(
let mut layout = LayoutData::clone(&layout.0);
match *pat {
ty::PatternKind::Range { start, end } => {
- if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
- &mut layout.backend_repr
- {
+ if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
scalar.valid_range_mut().start = extract_const_value(cx, ty, start)?
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
@@ -263,6 +261,31 @@ fn layout_of_uncached<'tcx>(
bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}")
}
}
+ ty::PatternKind::NotNull => {
+ if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
+ &mut layout.backend_repr
+ {
+ scalar.valid_range_mut().start = 1;
+ let niche = Niche {
+ offset: Size::ZERO,
+ value: scalar.primitive(),
+ valid_range: scalar.valid_range(cx),
+ };
+
+ layout.largest_niche = Some(niche);
+ // Make wide pointer pattern types contain only a single field
+ // of the wide pointer type itself.
+ layout.fields = FieldsShape::Arbitrary {
+ offsets: [Size::ZERO].into_iter().collect(),
+ memory_index: [0].into_iter().collect(),
+ }
+ } else {
+ bug!(
+ "pattern type with `!null` pattern but not scalar/pair layout: {ty:?}, {layout:?}"
+ )
+ }
+ }
+
ty::PatternKind::Or(variants) => match *variants[0] {
ty::PatternKind::Range { .. } => {
if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
@@ -279,7 +302,7 @@ fn layout_of_uncached<'tcx>(
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
)),
- ty::PatternKind::Or(_) => {
+ ty::PatternKind::NotNull | ty::PatternKind::Or(_) => {
unreachable!("mixed or patterns are not allowed")
}
})
@@ -344,6 +367,7 @@ fn layout_of_uncached<'tcx>(
)
}
}
+ ty::PatternKind::NotNull => bug!("or patterns can't contain `!null` patterns"),
ty::PatternKind::Or(..) => bug!("patterns cannot have nested or patterns"),
},
}
diff --git a/compiler/rustc_type_ir/src/pattern.rs b/compiler/rustc_type_ir/src/pattern.rs
index 7e56565917c67..8237254f8c44d 100644
--- a/compiler/rustc_type_ir/src/pattern.rs
+++ b/compiler/rustc_type_ir/src/pattern.rs
@@ -14,4 +14,5 @@ use crate::Interner;
pub enum PatternKind {
Range { start: I::Const, end: I::Const },
Or(I::PatList),
+ NotNull,
}
diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs
index 737550eb73e99..d1d707b896f0f 100644
--- a/compiler/rustc_type_ir/src/walk.rs
+++ b/compiler/rustc_type_ir/src/walk.rs
@@ -178,5 +178,6 @@ fn push_ty_pat(stack: &mut TypeWalkerStack, pat: I::Pat) {
push_ty_pat::(stack, pat)
}
}
+ ty::PatternKind::NotNull => {}
}
}
diff --git a/compiler/stable_mir/src/unstable/convert/stable/ty.rs b/compiler/stable_mir/src/unstable/convert/stable/ty.rs
index 366f7ea01d44e..8b564907a24da 100644
--- a/compiler/stable_mir/src/unstable/convert/stable/ty.rs
+++ b/compiler/stable_mir/src/unstable/convert/stable/ty.rs
@@ -497,6 +497,7 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
include_end: true,
},
ty::PatternKind::Or(_) => todo!(),
+ ty::PatternKind::NotNull => todo!(),
}
}
}
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 2f701171505c7..adc0883dfeff8 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -115,6 +115,7 @@
#![feature(link_cfg)]
#![feature(offset_of_enum)]
#![feature(panic_internals)]
+#![feature(pattern_type_macro)]
#![feature(ptr_alignment_type)]
#![feature(ptr_metadata)]
#![feature(set_ptr_value)]
@@ -168,6 +169,7 @@
#![feature(never_type)]
#![feature(no_core)]
#![feature(optimize_attribute)]
+#![feature(pattern_types)]
#![feature(prelude_import)]
#![feature(repr_simd)]
#![feature(rustc_allow_const_fn_unstable)]
diff --git a/library/core/src/pat.rs b/library/core/src/pat.rs
index 91d015b1bc53f..c818b9f77cd6f 100644
--- a/library/core/src/pat.rs
+++ b/library/core/src/pat.rs
@@ -1,5 +1,8 @@
//! Helper module for exporting the `pattern_type` macro
+use crate::marker::{Freeze, PointeeSized, Unsize};
+use crate::ops::{CoerceUnsized, DispatchFromDyn};
+
/// Creates a pattern type.
/// ```ignore (cannot test this from within core yet)
/// type Positive = std::pat::pattern_type!(i32 is 1..);
@@ -74,3 +77,16 @@ impl const RangePattern for char {
}
}
}
+
+impl CoerceUnsized for pattern_type!(*const T is !null) where
+ T: Unsize
+{
+}
+
+impl, U> DispatchFromDyn for pattern_type!(T is !null) {}
+
+impl Unpin for pattern_type!(*const T is !null) {}
+
+unsafe impl Freeze for pattern_type!(*const T is !null) {}
+
+unsafe impl Freeze for pattern_type!(*mut T is !null) {}
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 0ca494f16e31d..743a30b7a5d33 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1122,7 +1122,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_ty_pat(variant);
}
},
- TyPatKind::Err(_) => {},
+ TyPatKind::NotNull | TyPatKind::Err(_) => {},
}
}
diff --git a/src/tools/miri/tests/pass/pattern-types.rs b/src/tools/miri/tests/pass/pattern-types.rs
new file mode 100644
index 0000000000000..90fe0de546915
--- /dev/null
+++ b/src/tools/miri/tests/pass/pattern-types.rs
@@ -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 {
+ pointer: std::pat::pattern_type!(*const T is !null),
+}
+
+trait Trait {}
+impl Trait for () {}
+
+fn main() {
+ unsafe {
+ let _: NonNull = NonNull { pointer: transmute(&mut () as *mut dyn Trait) };
+ }
+}
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 9ee10d8627030..b22a8f31debed 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -1100,7 +1100,7 @@ impl Rewrite for ast::TyPat {
}
Ok(s)
}
- ast::TyPatKind::Err(_) => Err(RewriteError::Unknown),
+ ast::TyPatKind::NotNull | ast::TyPatKind::Err(_) => Err(RewriteError::Unknown),
}
}
}
diff --git a/tests/ui/type/pattern_types/bad_pat.rs b/tests/ui/type/pattern_types/bad_pat.rs
index 549b0d11dd187..7e2b4cb996f27 100644
--- a/tests/ui/type/pattern_types/bad_pat.rs
+++ b/tests/ui/type/pattern_types/bad_pat.rs
@@ -10,4 +10,15 @@ type Positive2 = pattern_type!(i32 is 0..=);
type Wild = pattern_type!(() is _);
//~^ ERROR: pattern not supported in pattern types
+// FIXME: confusing diagnostic because `not` can be a binding
+type NonNull = pattern_type!(*const () is not null);
+//~^ ERROR: expected one of `@` or `|`, found `null`
+//~| ERROR: pattern not supported in pattern types
+
+type NonNull2 = pattern_type!(*const () is !nil);
+//~^ ERROR: expected `null`, found `nil`
+
+// FIXME: reject with a type mismatch
+type Mismatch2 = pattern_type!(() is !null);
+
fn main() {}
diff --git a/tests/ui/type/pattern_types/bad_pat.stderr b/tests/ui/type/pattern_types/bad_pat.stderr
index d2a5a20bf89b6..e72279542280c 100644
--- a/tests/ui/type/pattern_types/bad_pat.stderr
+++ b/tests/ui/type/pattern_types/bad_pat.stderr
@@ -30,6 +30,24 @@ error: pattern not supported in pattern types
LL | type Wild = pattern_type!(() is _);
| ^
-error: aborting due to 3 previous errors
+error: pattern not supported in pattern types
+ --> $DIR/bad_pat.rs:14:43
+ |
+LL | type NonNull = pattern_type!(*const () is not null);
+ | ^^^
+
+error: expected one of `@` or `|`, found `null`
+ --> $DIR/bad_pat.rs:14:47
+ |
+LL | type NonNull = pattern_type!(*const () is not null);
+ | ^^^^ expected one of `@` or `|`
+
+error: expected `null`, found `nil`
+ --> $DIR/bad_pat.rs:18:45
+ |
+LL | type NonNull2 = pattern_type!(*const () is !nil);
+ | ^^^ expected `null`
+
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0586`.
diff --git a/tests/ui/type/pattern_types/non_null.rs b/tests/ui/type/pattern_types/non_null.rs
new file mode 100644
index 0000000000000..7e86b8b684d17
--- /dev/null
+++ b/tests/ui/type/pattern_types/non_null.rs
@@ -0,0 +1,21 @@
+//! Show that pattern-types non-null is the same as libstd's
+
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
+//@ only-64bit
+
+#![feature(pattern_type_macro, pattern_types, rustc_attrs)]
+
+use std::pat::pattern_type;
+
+#[rustc_layout(debug)]
+type NonNull = pattern_type!(*const T is !null); //~ ERROR layout_of
+
+#[rustc_layout(debug)]
+type Test = Option>; //~ ERROR layout_of
+
+#[rustc_layout(debug)]
+type Wide = pattern_type!(*const [u8] is !null); //~ ERROR layout_of
+
+const _: () = assert!(size_of::>() == size_of::