diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index cf40c3f7f6f8e..82899481f852f 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2512,6 +2512,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 c88aa5c33ea90..d3d3798b79661 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -1030,7 +1030,7 @@ macro_rules! common_visitor_and_walkers {
visit_opt!(vis, visit_anon_const, end);
}
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 58dea472f1d3b..bff1bc01de1f0 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),
}
};
@@ -464,6 +466,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 0990c9b27eb09..0b9b119f42cff 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1218,6 +1218,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 662546e499988..86211dc9be847 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -148,6 +148,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 cbfb215a892a4..4c7ea1d88f3e8 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -379,6 +379,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 c2d6a26de0fd0..5eea2364324e5 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -230,6 +230,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 9e15f4572d7b9..54487b5d9c7df 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -473,6 +473,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 7d76d925ef23e..0998c4151187a 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -1245,9 +1245,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 6f288bb39b953..69d3d613ebe33 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1820,6 +1820,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 bebac3a4b7820..d507eeaf8697d 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -725,7 +725,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 4fcd9f8a646e3..94a080f3f53bb 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -99,6 +99,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 4779f4fb702b7..3e45bfc962df1 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -249,6 +249,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 =>
{
@@ -414,6 +426,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(infer::RelateObjectBound(span), r_b, r_a);
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
@@ -713,13 +737,16 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
let impl_span = tcx.def_span(checker.impl_def_id);
let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
- let is_permitted_primitive = match *self_ty.kind() {
- ty::Adt(def, _) => def.is_box(),
- ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
- _ => false,
- };
+ fn is_permitted_primitive(self_ty: Ty<'_>) -> bool {
+ match *self_ty.kind() {
+ ty::Adt(def, _) => def.is_box(),
+ ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
+ ty::Pat(base, _) => is_permitted_primitive(base),
+ _ => false,
+ }
+ }
- if is_permitted_primitive
+ if is_permitted_primitive(self_ty)
&& let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
&& layout.layout.is_pointer_like(&tcx.data_layout)
{
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 a27d1ed6c532b..31dfaf58dc02f 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1271,6 +1271,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 4c65d0d051021..b7788363fa4f4 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2651,6 +2651,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 b23b3125c59a3..ed2529362d098 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1869,6 +1869,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 fec23354c9122..e276354296154 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -910,6 +910,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))
}
@@ -1071,7 +1072,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 aa2ee756bc502..2025802a217ff 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -159,6 +159,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 c2ae6b06192a9..e7005a5b9666e 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -822,11 +822,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 7dcdd7999f285..0f84645b54094 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 173030e0326e8..7319dfa4fd713 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1067,6 +1067,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 3dc285fdab690..c3c4e01eff101 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -986,7 +986,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
self.visit_ty_pat(pat)
}
}
- TyPatKind::Err(_) => {}
+ TyPatKind::NotNull | TyPatKind::Err(_) => {}
}
}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index b0c9dba78a659..213c15258359f 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -412,6 +412,7 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
end: Some(end.stable(tables)),
include_end: true,
},
+ ty::PatternKind::NotNull => todo!(),
ty::PatternKind::Or(_) => todo!(),
}
}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d66f98871b97d..6a596dd64e5c4 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1503,6 +1503,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 49a5e20d7cf8b..fe1055b80db7f 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -267,6 +267,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/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 97ecf9702e620..da50f7a641b50 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -138,6 +138,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut candidates,
);
}
+ Some(LangItem::PointerLike) => {
+ self.assemble_pointer_like_candidates(obligation, &mut candidates);
+ }
Some(LangItem::AsyncFn | LangItem::AsyncFnMut | LangItem::AsyncFnOnce) => {
self.assemble_async_closure_candidates(obligation, &mut candidates);
}
@@ -501,6 +504,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
+ fn assemble_pointer_like_candidates(
+ &mut self,
+ obligation: &PolyTraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ match obligation.self_ty().skip_binder().kind() {
+ ty::Pat(..) => candidates.vec.push(PointerLikeCandidate),
+ _ => {}
+ }
+ }
+
fn assemble_async_fn_kind_helper_candidates(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 7acf0f990d1b3..c596133c9df4c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -117,6 +117,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)
@@ -665,6 +670,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 3a2f9e8ca179f..d2bc2ff201109 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1983,6 +1983,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 416865e861ea8..85a5f7da01a74 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -696,6 +696,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 9774263e4c951..0ff9dea86e3f5 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/library/Cargo.lock b/library/Cargo.lock
index 966ae72dc2ad1..8e39e7a09f42b 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -353,7 +353,6 @@ name = "std_detect"
version = "0.1.5"
dependencies = [
"cfg-if",
- "compiler_builtins",
"libc",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 88855831788db..b97370c3f2dc6 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -114,6 +114,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..233cca7f17e39 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, 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 c37231d093129..49b818e0760f2 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..b0c35cd1ff4b3
--- /dev/null
+++ b/src/tools/miri/tests/pass/pattern-types.rs
@@ -0,0 +1,17 @@
+#![feature(pattern_types, pattern_type_macro)]
+#![allow(dead_code)]
+
+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 7ec1032dcb421..6b98a67506a80 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -1106,7 +1106,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::