diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index c9a8adec31ae8..1275197470fd9 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2513,6 +2513,9 @@ pub enum TyPatKind {
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
Range(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/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 08726ee6b4115..e3bef18565614 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -507,7 +507,7 @@ pub fn walk_ty_pat(vis: &mut T, ty: &mut TyPat) {
visit_opt(end, |c| vis.visit_anon_const(c));
}
TyPatKind::Or(variants) => visit_thin_vec(variants, |p| vis.visit_ty_pat(p)),
- TyPatKind::Err(_) => {}
+ TyPatKind::NotNull | TyPatKind::Err(_) => {}
}
vis.visit_span(span);
}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 1f7c97380dc27..b85c345e36bb9 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -1043,7 +1043,7 @@ pub fn walk_ty_pat<'a, V: Visitor<'a>>(visitor: &mut V, tp: &'a TyPat) -> V::Res
visit_opt!(visitor, visit_anon_const, end);
}
TyPatKind::Or(variants) => walk_list!(visitor, visit_ty_pat, variants),
- TyPatKind::Err(_) => {}
+ TyPatKind::NotNull | TyPatKind::Err(_) => {}
}
V::Result::output()
}
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 3529e5525fcd2..5d0ee8097455a 100644
--- a/compiler/rustc_builtin_macros/src/pattern_type.rs
+++ b/compiler/rustc_builtin_macros/src/pattern_type.rs
@@ -28,17 +28,23 @@ 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,
- )?
- .into_inner(),
- );
+ 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,
+ )?
+ .into_inner(),
+ )
+ };
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 f8bbb21492015..328a7ec94ce38 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_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 7f3e486ca310d..c7578c58add89 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -459,7 +459,18 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) ->
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id),
},
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
- _ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t),
+ ty::Pat(base, _) => return type_di_node(cx, base),
+ // FIXME(unsafe_binders): impl debug info
+ ty::UnsafeBinder(_) => unimplemented!(),
+ ty::Alias(..)
+ | ty::Param(_)
+ | ty::Bound(..)
+ | ty::Infer(_)
+ | ty::Placeholder(_)
+ | ty::CoroutineWitness(..)
+ | ty::Error(_) => {
+ bug!("debuginfo: unexpected type in type_di_node(): {:?}", t)
+ }
};
{
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index f7863fe4ae264..6a4187463651a 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/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 789baea073463..ba9222cb1173d 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -86,6 +86,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let (_, field) = layout.non_1zst_field(self).unwrap();
self.unfold_transparent(field, may_unfold)
}
+ ty::Pat(base, _) => self.layout_of(*base).expect(
+ "if the layout of a pattern type could be computed, so can the layout of its base",
+ ),
// Not a transparent type, no further unfolding.
_ => layout,
}
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 643a5805019ff..2e90712e2df26 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, 0)?;
+ let dest = self.project_field(dest, 0)?;
+ 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_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index 3647c109a6ed4..1299ff184f93c 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -156,7 +156,12 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
);
// ... that contains a `NonNull`... (gladly, only a single field here)
assert_eq!(nonnull_ptr.layout().fields.count(), 1);
- let raw_ptr = self.ecx().project_field(&nonnull_ptr, 0)?; // the actual raw ptr
+ let pat_ty = self.ecx().project_field(&nonnull_ptr, 0)?; // `*mut T is !null`
+ let base = match *pat_ty.layout().ty.kind() {
+ ty::Pat(base, _) => self.ecx().layout_of(base)?,
+ _ => unreachable!(),
+ };
+ let raw_ptr = pat_ty.transmute(base, self.ecx())?; // The actual raw pointer
// ... whose only field finally is a raw ptr we can dereference.
self.visit_box(ty, &raw_ptr)?;
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 433d5f9882937..d014a07d4fcb0 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1824,6 +1824,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 a3a0e276f74cd..8e39a50399bee 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 b92d1d7104f0a..0f891d76a6d43 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 152714b340731..641b340d7a3b0 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1280,6 +1280,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 2a37a8bdbd47d..0a4cc04a74ec9 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/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index 5c344a806880c..c187503f2f2d8 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
use rustc_middle::mir::visit::MutVisitor;
use rustc_middle::mir::*;
use rustc_middle::span_bug;
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::ty::{PatternKind, Ty, TyCtxt};
use crate::patch::MirPatch;
@@ -17,13 +17,14 @@ fn build_ptr_tys<'tcx>(
pointee: Ty<'tcx>,
unique_did: DefId,
nonnull_did: DefId,
-) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) {
+) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) {
let args = tcx.mk_args(&[pointee.into()]);
let unique_ty = tcx.type_of(unique_did).instantiate(tcx, args);
let nonnull_ty = tcx.type_of(nonnull_did).instantiate(tcx, args);
let ptr_ty = Ty::new_imm_ptr(tcx, pointee);
+ let pat_ty = Ty::new_pat(tcx, ptr_ty, tcx.mk_pat(PatternKind::NotNull));
- (unique_ty, nonnull_ty, ptr_ty)
+ (unique_ty, nonnull_ty, pat_ty, ptr_ty)
}
/// Constructs the projection needed to access a Box's pointer
@@ -63,7 +64,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
{
let source_info = self.local_decls[place.local].source_info;
- let (unique_ty, nonnull_ty, ptr_ty) =
+ let (unique_ty, nonnull_ty, _pat_ty, ptr_ty) =
build_ptr_tys(tcx, boxed_ty, self.unique_did, self.nonnull_did);
let ptr_local = self.patch.new_temp(ptr_ty, source_info.span);
@@ -130,10 +131,11 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
let new_projections =
new_projections.get_or_insert_with(|| base.projection.to_vec());
- let (unique_ty, nonnull_ty, ptr_ty) =
+ let (unique_ty, nonnull_ty, pat_ty, ptr_ty) =
build_ptr_tys(tcx, boxed_ty, unique_did, nonnull_did);
new_projections.extend_from_slice(&build_projection(unique_ty, nonnull_ty));
+ new_projections.push(PlaceElem::Field(FieldIdx::ZERO, pat_ty));
// While we can't project into `NonNull<_>` in a basic block
// due to MCP#807, this is debug info where it's fine.
new_projections.push(PlaceElem::Field(FieldIdx::ZERO, ptr_ty));
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index c8aa7588d03ab..eb9570e53b011 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 1ee977a5457e2..a8b583b7e71b5 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 2a4be5fc3b16e..e5793b16de2ca 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 4e842a8f93a8f..8ab1e240635ba 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1487,6 +1487,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 c9169127e0b90..25bb240489946 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_fn_pointer_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 3018dad8e0916..0c39d180064a9 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..4cec941b4afec 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,29 @@ 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);
+ 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 +300,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 +365,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/core/src/lib.rs b/library/core/src/lib.rs
index f2a5c40bada0b..7f0e8d9412c76 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -168,6 +168,8 @@
#![feature(never_type)]
#![feature(no_core)]
#![feature(optimize_attribute)]
+#![feature(pattern_type_macro)]
+#![feature(pattern_types)]
#![feature(prelude_import)]
#![feature(repr_simd)]
#![feature(rustc_allow_const_fn_unstable)]
diff --git a/library/core/src/num/niche_types.rs b/library/core/src/num/niche_types.rs
index 47ff4254e533b..4d23d3d28b1e4 100644
--- a/library/core/src/num/niche_types.rs
+++ b/library/core/src/num/niche_types.rs
@@ -5,60 +5,48 @@
)]
use crate::cmp::Ordering;
-use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::marker::StructuralPartialEq;
+use crate::{fmt, pattern_type};
macro_rules! define_valid_range_type {
($(
$(#[$m:meta])*
- $vis:vis struct $name:ident($int:ident as $uint:ident in $low:literal..=$high:literal);
+ $vis:vis struct $name:ident($int:ident is $pat:pat);
)+) => {$(
- #[derive(Clone, Copy, Eq)]
+ #[derive(Clone, Copy)]
#[repr(transparent)]
- #[rustc_layout_scalar_valid_range_start($low)]
- #[rustc_layout_scalar_valid_range_end($high)]
$(#[$m])*
- $vis struct $name($int);
-
- const _: () = {
- // With the `valid_range` attributes, it's always specified as unsigned
- assert!(<$uint>::MIN == 0);
- let ulow: $uint = $low;
- let uhigh: $uint = $high;
- assert!(ulow <= uhigh);
-
- assert!(size_of::<$int>() == size_of::<$uint>());
- };
-
+ $vis struct $name(pattern_type!($int is $pat));
impl $name {
#[inline]
pub const fn new(val: $int) -> Option {
- if (val as $uint) >= ($low as $uint) && (val as $uint) <= ($high as $uint) {
- // SAFETY: just checked the inclusive range
- Some(unsafe { $name(val) })
+ #[allow(non_contiguous_range_endpoints)]
+ if let $pat = val {
+ // SAFETY: just checked that the value matches the pattern
+ Some(unsafe { $name(crate::mem::transmute(val)) })
} else {
None
}
}
/// Constructs an instance of this type from the underlying integer
- /// primitive without checking whether its zero.
+ /// primitive without checking whether its valid.
///
/// # Safety
- /// Immediate language UB if `val == 0`, as it violates the validity
+ /// Immediate language UB if `val` is not in the range of the pattern type,
+ /// as it violates the validity
/// invariant of this type.
#[inline]
pub const unsafe fn new_unchecked(val: $int) -> Self {
- // SAFETY: Caller promised that `val` is non-zero.
- unsafe { $name(val) }
+ // SAFETY: Caller promised that `val` is in the valid range.
+ unsafe { $name(crate::mem::transmute(val)) }
}
#[inline]
pub const fn as_inner(self) -> $int {
- // SAFETY: This is a transparent wrapper, so unwrapping it is sound
- // (Not using `.0` due to MCP#807.)
- unsafe { crate::mem::transmute(self) }
+ // SAFETY: pattern types are always legal values of their base type
+ unsafe { crate::mem::transmute(self.0) }
}
}
@@ -67,6 +55,8 @@ macro_rules! define_valid_range_type {
// by .
impl StructuralPartialEq for $name {}
+ impl Eq for $name {}
+
impl PartialEq for $name {
#[inline]
fn eq(&self, other: &Self) -> bool {
@@ -104,7 +94,7 @@ macro_rules! define_valid_range_type {
}
define_valid_range_type! {
- pub struct Nanoseconds(u32 as u32 in 0..=999_999_999);
+ pub struct Nanoseconds(u32 is 0..=999_999_999);
}
impl Nanoseconds {
@@ -119,45 +109,30 @@ impl Default for Nanoseconds {
}
}
-define_valid_range_type! {
- pub struct NonZeroU8Inner(u8 as u8 in 1..=0xff);
- pub struct NonZeroU16Inner(u16 as u16 in 1..=0xff_ff);
- pub struct NonZeroU32Inner(u32 as u32 in 1..=0xffff_ffff);
- pub struct NonZeroU64Inner(u64 as u64 in 1..=0xffffffff_ffffffff);
- pub struct NonZeroU128Inner(u128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff);
-
- pub struct NonZeroI8Inner(i8 as u8 in 1..=0xff);
- pub struct NonZeroI16Inner(i16 as u16 in 1..=0xff_ff);
- pub struct NonZeroI32Inner(i32 as u32 in 1..=0xffff_ffff);
- pub struct NonZeroI64Inner(i64 as u64 in 1..=0xffffffff_ffffffff);
- pub struct NonZeroI128Inner(i128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff);
-}
-
-#[cfg(target_pointer_width = "16")]
-define_valid_range_type! {
- pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff);
- pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff);
- pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff);
-}
-#[cfg(target_pointer_width = "32")]
-define_valid_range_type! {
- pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff);
- pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff);
- pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff);
-}
-#[cfg(target_pointer_width = "64")]
-define_valid_range_type! {
- pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff_ffff_ffff);
- pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff_ffff_ffff);
- pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff_ffff_ffff);
-}
+const HALF_USIZE: usize = usize::MAX >> 1;
define_valid_range_type! {
- pub struct U32NotAllOnes(u32 as u32 in 0..=0xffff_fffe);
- pub struct I32NotAllOnes(i32 as u32 in 0..=0xffff_fffe);
-
- pub struct U64NotAllOnes(u64 as u64 in 0..=0xffff_ffff_ffff_fffe);
- pub struct I64NotAllOnes(i64 as u64 in 0..=0xffff_ffff_ffff_fffe);
+ pub struct NonZeroU8Inner(u8 is 1..);
+ pub struct NonZeroU16Inner(u16 is 1..);
+ pub struct NonZeroU32Inner(u32 is 1..);
+ pub struct NonZeroU64Inner(u64 is 1..);
+ pub struct NonZeroU128Inner(u128 is 1..);
+
+ pub struct NonZeroI8Inner(i8 is ..0 | 1..);
+ pub struct NonZeroI16Inner(i16 is ..0 | 1..);
+ pub struct NonZeroI32Inner(i32 is ..0 | 1..);
+ pub struct NonZeroI64Inner(i64 is ..0 | 1..);
+ pub struct NonZeroI128Inner(i128 is ..0 | 1..);
+
+ pub struct UsizeNoHighBit(usize is 0..=HALF_USIZE);
+ pub struct NonZeroUsizeInner(usize is 1..);
+ pub struct NonZeroIsizeInner(isize is ..0 | 1..);
+
+ pub struct U32NotAllOnes(u32 is 0..u32::MAX);
+ pub struct I32NotAllOnes(i32 is ..-1 | 0..);
+
+ pub struct U64NotAllOnes(u64 is 0..u64::MAX);
+ pub struct I64NotAllOnes(i64 is ..-1 | 0..);
}
pub trait NotAllOnesHelper {
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/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 91b8d1bf9a707..854fa4cd0a684 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -1,6 +1,6 @@
use crate::cmp::Ordering;
use crate::marker::Unsize;
-use crate::mem::{MaybeUninit, SizedTypeProperties};
+use crate::mem::{MaybeUninit, SizedTypeProperties, transmute};
use crate::num::NonZero;
use crate::ops::{CoerceUnsized, DispatchFromDyn};
use crate::pin::PinCoerceUnsized;
@@ -64,13 +64,10 @@ use crate::{fmt, hash, intrinsics, mem, ptr};
/// [null pointer optimization]: crate::option#representation
#[stable(feature = "nonnull", since = "1.25.0")]
#[repr(transparent)]
-#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
#[rustc_diagnostic_item = "NonNull"]
pub struct NonNull {
- // Remember to use `.as_ptr()` instead of `.pointer`, as field projecting to
- // this is banned by .
- pointer: *const T,
+ pointer: crate::pattern_type!(*const T is !null),
}
/// `NonNull` pointers are not `Send` because the data they reference may be aliased.
@@ -93,9 +90,9 @@ impl NonNull {
#[must_use]
#[inline]
pub const fn without_provenance(addr: NonZero) -> Self {
- let pointer = crate::ptr::without_provenance(addr.get());
+ let pointer: *const T = crate::ptr::without_provenance(addr.get());
// SAFETY: we know `addr` is non-zero.
- unsafe { NonNull { pointer } }
+ unsafe { NonNull { pointer: transmute(pointer) } }
}
/// Creates a new `NonNull` that is dangling, but well-aligned.
@@ -225,7 +222,7 @@ impl NonNull {
"NonNull::new_unchecked requires that the pointer is non-null",
(ptr: *mut () = ptr as *mut ()) => !ptr.is_null()
);
- NonNull { pointer: ptr as _ }
+ NonNull { pointer: transmute(ptr) }
}
}
@@ -268,7 +265,7 @@ impl NonNull {
#[inline]
pub const fn from_ref(r: &T) -> Self {
// SAFETY: A reference cannot be null.
- unsafe { NonNull { pointer: r as *const T } }
+ unsafe { NonNull { pointer: transmute(r as *const T) } }
}
/// Converts a mutable reference to a `NonNull` pointer.
@@ -277,7 +274,7 @@ impl NonNull {
#[inline]
pub const fn from_mut(r: &mut T) -> Self {
// SAFETY: A mutable reference cannot be null.
- unsafe { NonNull { pointer: r as *mut T } }
+ unsafe { NonNull { pointer: transmute(r as *mut T) } }
}
/// Performs the same functionality as [`std::ptr::from_raw_parts`], except that a
@@ -488,7 +485,7 @@ impl NonNull {
#[inline]
pub const fn cast(self) -> NonNull {
// SAFETY: `self` is a `NonNull` pointer which is necessarily non-null
- unsafe { NonNull { pointer: self.as_ptr() as *mut U } }
+ unsafe { NonNull { pointer: transmute(self.as_ptr() as *mut U) } }
}
/// Try to cast to a pointer of another type by checking aligment.
@@ -567,7 +564,7 @@ impl NonNull {
// Additionally safety contract of `offset` guarantees that the resulting pointer is
// pointing to an allocation, there can't be an allocation at null, thus it's safe to
// construct `NonNull`.
- unsafe { NonNull { pointer: intrinsics::offset(self.as_ptr(), count) } }
+ unsafe { NonNull { pointer: transmute(intrinsics::offset(self.as_ptr(), count)) } }
}
/// Calculates the offset from a pointer in bytes.
@@ -591,7 +588,7 @@ impl NonNull {
// Additionally safety contract of `offset` guarantees that the resulting pointer is
// pointing to an allocation, there can't be an allocation at null, thus it's safe to
// construct `NonNull`.
- unsafe { NonNull { pointer: self.as_ptr().byte_offset(count) } }
+ unsafe { NonNull { pointer: transmute(self.as_ptr().byte_offset(count)) } }
}
/// Adds an offset to a pointer (convenience for `.offset(count as isize)`).
@@ -643,7 +640,7 @@ impl NonNull {
// Additionally safety contract of `offset` guarantees that the resulting pointer is
// pointing to an allocation, there can't be an allocation at null, thus it's safe to
// construct `NonNull`.
- unsafe { NonNull { pointer: intrinsics::offset(self.as_ptr(), count) } }
+ unsafe { NonNull { pointer: transmute(intrinsics::offset(self.as_ptr(), count)) } }
}
/// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).
@@ -667,7 +664,7 @@ impl NonNull {
// Additionally safety contract of `add` guarantees that the resulting pointer is pointing
// to an allocation, there can't be an allocation at null, thus it's safe to construct
// `NonNull`.
- unsafe { NonNull { pointer: self.as_ptr().byte_add(count) } }
+ unsafe { NonNull { pointer: transmute(self.as_ptr().byte_add(count)) } }
}
/// Subtracts an offset from a pointer (convenience for
@@ -749,7 +746,7 @@ impl NonNull {
// Additionally safety contract of `sub` guarantees that the resulting pointer is pointing
// to an allocation, there can't be an allocation at null, thus it's safe to construct
// `NonNull`.
- unsafe { NonNull { pointer: self.as_ptr().byte_sub(count) } }
+ unsafe { NonNull { pointer: transmute(self.as_ptr().byte_sub(count)) } }
}
/// Calculates the distance between two pointers within the same allocation. The returned value is in
diff --git a/library/std/src/os/unix/io/tests.rs b/library/std/src/os/unix/io/tests.rs
index fc147730578ac..ce5e7aac5a99d 100644
--- a/library/std/src/os/unix/io/tests.rs
+++ b/library/std/src/os/unix/io/tests.rs
@@ -2,8 +2,7 @@ use crate::os::unix::io::RawFd;
#[test]
fn test_raw_fd_layout() {
- // `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start`
- // and `rustc_layout_scalar_valid_range_end`, with values that depend on
+ // `OwnedFd` and `BorrowedFd` use pattern types, with ranges that depend on
// the bit width of `RawFd`. If this ever changes, those values will need
// to be updated.
assert_eq!(size_of::(), 4);
diff --git a/library/std/src/os/wasi/io/tests.rs b/library/std/src/os/wasi/io/tests.rs
index c5c6a19a6c885..d18b9fe10cab0 100644
--- a/library/std/src/os/wasi/io/tests.rs
+++ b/library/std/src/os/wasi/io/tests.rs
@@ -2,8 +2,7 @@ use crate::os::wasi::io::RawFd;
#[test]
fn test_raw_fd_layout() {
- // `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start`
- // and `rustc_layout_scalar_valid_range_end`, with values that depend on
+ // `OwnedFd` and `BorrowedFd` use pattern types with ranges that depend on
// the bit width of `RawFd`. If this ever changes, those values will need
// to be updated.
assert_eq!(size_of::(), 4);
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 26323af312288..81b4946595029 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -242,6 +242,10 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
loop {
ty = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty);
return match *ty.kind() {
+ ty::Pat(base, _) => {
+ ty = base;
+ continue;
+ },
ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => {
ReducedTy::TypeErasure { raw_ptr_only: false }
},
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/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr
index a0b7cc7a521d4..c3b614dae5260 100644
--- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
+error: Undefined Behavior: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1
--> tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs:LL:CC
|
LL | f();
- | ^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
+ | ^^^ constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr
index 6af0e72b9c43f..06ed64ac76f1f 100644
--- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
+error: Undefined Behavior: constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1
--> tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
|
LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue())
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
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/codegen/loads.rs b/tests/codegen/loads.rs
index 88d67642b7250..e19af7a3c2bc1 100644
--- a/tests/codegen/loads.rs
+++ b/tests/codegen/loads.rs
@@ -58,7 +58,7 @@ pub fn load_raw_pointer<'a>(x: &*const i32) -> *const i32 {
// CHECK-LABEL: @load_box
#[no_mangle]
pub fn load_box<'a>(x: Box>) -> Box {
- // CHECK: load ptr, ptr %{{.*}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}}
+ // CHECK: load ptr, ptr %{{.*}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !noundef !{{[0-9]+}}
*x
}
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
index b698d8f373575..f4d395335870a 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
@@ -13,8 +13,8 @@
StorageLive(_1);
- _1 = const 1_usize as std::boxed::Box (Transmute);
- _2 = copy ((_1.0: std::ptr::Unique).0: std::ptr::NonNull) as *const Never (Transmute);
-+ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global);
-+ _2 = const std::ptr::NonNull:: {{ pointer: {0x1 as *const Never} }} as *const Never (Transmute);
++ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} is !null }}, _marker: PhantomData:: }}, std::alloc::Global);
++ _2 = const std::ptr::NonNull:: {{ pointer: {0x1 as *const Never} is !null }} as *const Never (Transmute);
unreachable;
}
}
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
index b698d8f373575..f4d395335870a 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
@@ -13,8 +13,8 @@
StorageLive(_1);
- _1 = const 1_usize as std::boxed::Box (Transmute);
- _2 = copy ((_1.0: std::ptr::Unique).0: std::ptr::NonNull) as *const Never (Transmute);
-+ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global);
-+ _2 = const std::ptr::NonNull:: {{ pointer: {0x1 as *const Never} }} as *const Never (Transmute);
++ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} is !null }}, _marker: PhantomData:: }}, std::alloc::Global);
++ _2 = const std::ptr::NonNull:: {{ pointer: {0x1 as *const Never} is !null }} as *const Never (Transmute);
unreachable;
}
}
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
index 2c89670dcf7d7..4fc66f1bf7200 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
@@ -21,7 +21,7 @@
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
- let _7: *const [bool; 0];
+ let mut _7: (*const [bool; 0]) is !null;
scope 10 {
}
scope 11 (inlined NonZero::::get) {
@@ -45,19 +45,19 @@
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize));
+ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
StorageLive(_7);
- _7 = const {0x1 as *const [bool; 0]};
- _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+ _7 = const {0x1 as *const [bool; 0]} is !null;
+ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }};
StorageDead(_7);
StorageDead(_6);
- _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }}, _marker: PhantomData::<[bool; 0]> }};
StorageDead(_5);
- _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }};
StorageDead(_4);
- _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
StorageDead(_3);
- _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
index 8fecfe224cc69..c9b9d2fb8bc96 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -21,7 +21,7 @@
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
- let _7: *const [bool; 0];
+ let mut _7: (*const [bool; 0]) is !null;
scope 10 {
}
scope 11 (inlined NonZero::::get) {
@@ -45,19 +45,19 @@
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize));
+ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
StorageLive(_7);
- _7 = const {0x1 as *const [bool; 0]};
- _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+ _7 = const {0x1 as *const [bool; 0]} is !null;
+ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }};
StorageDead(_7);
StorageDead(_6);
- _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }}, _marker: PhantomData::<[bool; 0]> }};
StorageDead(_5);
- _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }};
StorageDead(_4);
- _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
StorageDead(_3);
- _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
index 976ea252c2f89..9b455a71afa24 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
@@ -21,7 +21,7 @@
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
- let _7: *const [bool; 0];
+ let mut _7: (*const [bool; 0]) is !null;
scope 10 {
}
scope 11 (inlined NonZero::::get) {
@@ -45,19 +45,19 @@
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize));
+ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
StorageLive(_7);
- _7 = const {0x1 as *const [bool; 0]};
- _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+ _7 = const {0x1 as *const [bool; 0]} is !null;
+ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }};
StorageDead(_7);
StorageDead(_6);
- _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }}, _marker: PhantomData::<[bool; 0]> }};
StorageDead(_5);
- _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }};
StorageDead(_4);
- _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
StorageDead(_3);
- _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
index 6c59f5e3e2e86..fb9e46fa2c517 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -21,7 +21,7 @@
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
- let _7: *const [bool; 0];
+ let mut _7: (*const [bool; 0]) is !null;
scope 10 {
}
scope 11 (inlined NonZero::::get) {
@@ -45,19 +45,19 @@
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize));
+ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
StorageLive(_7);
- _7 = const {0x1 as *const [bool; 0]};
- _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+ _7 = const {0x1 as *const [bool; 0]} is !null;
+ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }};
StorageDead(_7);
StorageDead(_6);
- _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }}, _marker: PhantomData::<[bool; 0]> }};
StorageDead(_5);
- _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }};
StorageDead(_4);
- _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
StorageDead(_3);
- _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
index 1f9cf6d6aca83..c8548a9f9a4b6 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
@@ -21,7 +21,7 @@
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
- let _7: *const [bool; 0];
+ let mut _7: (*const [bool; 0]) is !null;
scope 10 {
}
scope 11 (inlined NonZero::::get) {
@@ -46,25 +46,25 @@
StorageLive(_5);
StorageLive(_6);
- _6 = const std::ptr::Alignment::of::<[bool; 0]>::{constant#0} as std::num::NonZero (Transmute);
-+ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize));
++ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
StorageLive(_7);
-- _7 = copy _6 as *const [bool; 0] (Transmute);
-- _5 = NonNull::<[bool; 0]> { pointer: copy _7 };
-+ _7 = const {0x1 as *const [bool; 0]};
-+ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+- _7 = copy _6 as (*const [bool; 0]) is !null (Transmute);
+- _5 = NonNull::<[bool; 0]> { pointer: move _7 };
++ _7 = const {0x1 as *const [bool; 0]} is !null;
++ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }};
StorageDead(_7);
StorageDead(_6);
- _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
-+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
++ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }}, _marker: PhantomData::<[bool; 0]> }};
StorageDead(_5);
- _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
-+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
++ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }};
StorageDead(_4);
- _2 = Box::<[bool]>(copy _3, const std::alloc::Global);
-+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
++ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
StorageDead(_3);
- _1 = A { foo: move _2 };
-+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
++ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
index a8760285fac11..5417d6555fc76 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
@@ -21,7 +21,7 @@
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
- let _7: *const [bool; 0];
+ let mut _7: (*const [bool; 0]) is !null;
scope 10 {
}
scope 11 (inlined NonZero::::get) {
@@ -46,25 +46,25 @@
StorageLive(_5);
StorageLive(_6);
- _6 = const std::ptr::Alignment::of::<[bool; 0]>::{constant#0} as std::num::NonZero (Transmute);
-+ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize));
++ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
StorageLive(_7);
-- _7 = copy _6 as *const [bool; 0] (Transmute);
-- _5 = NonNull::<[bool; 0]> { pointer: copy _7 };
-+ _7 = const {0x1 as *const [bool; 0]};
-+ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+- _7 = copy _6 as (*const [bool; 0]) is !null (Transmute);
+- _5 = NonNull::<[bool; 0]> { pointer: move _7 };
++ _7 = const {0x1 as *const [bool; 0]} is !null;
++ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }};
StorageDead(_7);
StorageDead(_6);
- _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
-+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
++ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }}, _marker: PhantomData::<[bool; 0]> }};
StorageDead(_5);
- _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
-+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
++ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }};
StorageDead(_4);
- _2 = Box::<[bool]>(copy _3, const std::alloc::Global);
-+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
++ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
StorageDead(_3);
- _1 = A { foo: move _2 };
-+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
++ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
index c398ae70a1a3e..e046cc38ea331 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
@@ -21,7 +21,7 @@
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
- let _7: *const [bool; 0];
+ let mut _7: (*const [bool; 0]) is !null;
scope 10 {
}
scope 11 (inlined NonZero::::get) {
@@ -46,25 +46,25 @@
StorageLive(_5);
StorageLive(_6);
- _6 = const std::ptr::Alignment::of::<[bool; 0]>::{constant#0} as std::num::NonZero (Transmute);
-+ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize));
++ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
StorageLive(_7);
-- _7 = copy _6 as *const [bool; 0] (Transmute);
-- _5 = NonNull::<[bool; 0]> { pointer: copy _7 };
-+ _7 = const {0x1 as *const [bool; 0]};
-+ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+- _7 = copy _6 as (*const [bool; 0]) is !null (Transmute);
+- _5 = NonNull::<[bool; 0]> { pointer: move _7 };
++ _7 = const {0x1 as *const [bool; 0]} is !null;
++ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }};
StorageDead(_7);
StorageDead(_6);
- _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
-+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
++ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }}, _marker: PhantomData::<[bool; 0]> }};
StorageDead(_5);
- _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
-+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
++ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }};
StorageDead(_4);
- _2 = Box::<[bool]>(copy _3, const std::alloc::Global);
-+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
++ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
StorageDead(_3);
- _1 = A { foo: move _2 };
-+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
++ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind unreachable];
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
index 02934c02587d2..91cb8622b45ea 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
@@ -21,7 +21,7 @@
scope 8 (inlined std::ptr::Alignment::as_nonzero) {
}
scope 9 (inlined NonNull::<[bool; 0]>::without_provenance) {
- let _7: *const [bool; 0];
+ let mut _7: (*const [bool; 0]) is !null;
scope 10 {
}
scope 11 (inlined NonZero::::get) {
@@ -46,25 +46,25 @@
StorageLive(_5);
StorageLive(_6);
- _6 = const std::ptr::Alignment::of::<[bool; 0]>::{constant#0} as std::num::NonZero (Transmute);
-+ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize));
++ _6 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
StorageLive(_7);
-- _7 = copy _6 as *const [bool; 0] (Transmute);
-- _5 = NonNull::<[bool; 0]> { pointer: copy _7 };
-+ _7 = const {0x1 as *const [bool; 0]};
-+ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+- _7 = copy _6 as (*const [bool; 0]) is !null (Transmute);
+- _5 = NonNull::<[bool; 0]> { pointer: move _7 };
++ _7 = const {0x1 as *const [bool; 0]} is !null;
++ _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }};
StorageDead(_7);
StorageDead(_6);
- _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
-+ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
++ _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} is !null }}, _marker: PhantomData::<[bool; 0]> }};
StorageDead(_5);
- _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize, Implicit));
-+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
++ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }};
StorageDead(_4);
- _2 = Box::<[bool]>(copy _3, const std::alloc::Global);
-+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
++ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
StorageDead(_3);
- _1 = A { foo: move _2 };
-+ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
++ _1 = const A {{ foo: Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: (*const [bool]) is !null }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }};
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb1, unwind: bb2];
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
index fa6c2e29e072e..802d6daa1a27d 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
@@ -12,7 +12,7 @@
bb0: {
StorageLive(_1);
- _1 = const 1_usize as std::boxed::Box (Transmute);
-+ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global);
++ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} is !null }}, _marker: PhantomData:: }}, std::alloc::Global);
_2 = copy ((_1.0: std::ptr::Unique).0: std::ptr::NonNull) as *const Never (Transmute);
unreachable;
}
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
index fa6c2e29e072e..802d6daa1a27d 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
@@ -12,7 +12,7 @@
bb0: {
StorageLive(_1);
- _1 = const 1_usize as std::boxed::Box (Transmute);
-+ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData:: }}, std::alloc::Global);
++ _1 = const Box::(Unique:: {{ pointer: NonNull:: {{ pointer: {0x1 as *const Never} is !null }}, _marker: PhantomData:: }}, std::alloc::Global);
_2 = copy ((_1.0: std::ptr::Unique).0: std::ptr::NonNull) as *const Never (Transmute);
unreachable;
}
diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff
index 25ffff619e60b..16a3dffcce07d 100644
--- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff
@@ -10,7 +10,7 @@
let mut _8: *const [()];
let mut _9: std::boxed::Box<()>;
let mut _10: *const ();
- let mut _23: usize;
+ let mut _25: usize;
scope 1 {
debug vp_ctx => _1;
let _4: *const ();
@@ -47,7 +47,9 @@
scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) {
scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) {
scope 13 (inlined NonNull::<[u8]>::cast::) {
- let mut _22: *mut [u8];
+ let mut _22: (*const u8) is !null;
+ let mut _23: *mut u8;
+ let mut _24: *mut [u8];
scope 14 (inlined NonNull::<[u8]>::as_ptr) {
}
}
@@ -105,8 +107,14 @@
bb4: {
_17 = copy ((_15 as Ok).0: std::ptr::NonNull<[u8]>);
StorageLive(_22);
- _22 = copy _17 as *mut [u8] (Transmute);
- _13 = copy _22 as *mut u8 (PtrToPtr);
+ StorageLive(_23);
+ StorageLive(_24);
+ _24 = copy _17 as *mut [u8] (Transmute);
+ _23 = move _24 as *mut u8 (PtrToPtr);
+ StorageDead(_24);
+ _22 = move _23 as (*const u8) is !null (Transmute);
+ StorageDead(_23);
+ _13 = copy _22 as *mut u8 (Transmute);
StorageDead(_22);
StorageDead(_15);
StorageDead(_17);
@@ -129,11 +137,11 @@
StorageLive(_6);
- _6 = copy _4;
+ _6 = copy _10;
- StorageLive(_23);
- _23 = const 1_usize;
-- _5 = *const [()] from (copy _6, copy _23);
+ StorageLive(_25);
+ _25 = const 1_usize;
+- _5 = *const [()] from (copy _6, copy _25);
+ _5 = *const [()] from (copy _10, const 1_usize);
- StorageDead(_23);
+ StorageDead(_25);
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff
index 839b53e3b0b3b..592734e01e5a0 100644
--- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff
@@ -10,7 +10,7 @@
let mut _8: *const [()];
let mut _9: std::boxed::Box<()>;
let mut _10: *const ();
- let mut _23: usize;
+ let mut _25: usize;
scope 1 {
debug vp_ctx => _1;
let _4: *const ();
@@ -47,7 +47,9 @@
scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) {
scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) {
scope 13 (inlined NonNull::<[u8]>::cast::) {
- let mut _22: *mut [u8];
+ let mut _22: (*const u8) is !null;
+ let mut _23: *mut u8;
+ let mut _24: *mut [u8];
scope 14 (inlined NonNull::<[u8]>::as_ptr) {
}
}
@@ -105,8 +107,14 @@
bb4: {
_17 = copy ((_15 as Ok).0: std::ptr::NonNull<[u8]>);
StorageLive(_22);
- _22 = copy _17 as *mut [u8] (Transmute);
- _13 = copy _22 as *mut u8 (PtrToPtr);
+ StorageLive(_23);
+ StorageLive(_24);
+ _24 = copy _17 as *mut [u8] (Transmute);
+ _23 = move _24 as *mut u8 (PtrToPtr);
+ StorageDead(_24);
+ _22 = move _23 as (*const u8) is !null (Transmute);
+ StorageDead(_23);
+ _13 = copy _22 as *mut u8 (Transmute);
StorageDead(_22);
StorageDead(_15);
StorageDead(_17);
@@ -129,11 +137,11 @@
StorageLive(_6);
- _6 = copy _4;
+ _6 = copy _10;
- StorageLive(_23);
- _23 = const 1_usize;
-- _5 = *const [()] from (copy _6, copy _23);
+ StorageLive(_25);
+ _25 = const 1_usize;
+- _5 = *const [()] from (copy _6, copy _25);
+ _5 = *const [()] from (copy _10, const 1_usize);
- StorageDead(_23);
+ StorageDead(_25);
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
diff --git a/tests/mir-opt/elaborate_box_deref_in_debuginfo.pointee.ElaborateBoxDerefs.diff b/tests/mir-opt/elaborate_box_deref_in_debuginfo.pointee.ElaborateBoxDerefs.diff
index 279c1a1990dc8..6075d7895eeb3 100644
--- a/tests/mir-opt/elaborate_box_deref_in_debuginfo.pointee.ElaborateBoxDerefs.diff
+++ b/tests/mir-opt/elaborate_box_deref_in_debuginfo.pointee.ElaborateBoxDerefs.diff
@@ -3,7 +3,7 @@
fn pointee(_1: Box) -> () {
- debug foo => (*_1);
-+ debug foo => (*(((_1.0: std::ptr::Unique).0: std::ptr::NonNull).0: *const i32));
++ debug foo => (*((((_1.0: std::ptr::Unique).0: std::ptr::NonNull).0: (*const i32) is !null).0: *const i32));
let mut _0: ();
bb0: {
diff --git a/tests/mir-opt/gvn_ptr_eq_with_constant.main.GVN.diff b/tests/mir-opt/gvn_ptr_eq_with_constant.main.GVN.diff
index f56af33ea603f..55fea9aef9101 100644
--- a/tests/mir-opt/gvn_ptr_eq_with_constant.main.GVN.diff
+++ b/tests/mir-opt/gvn_ptr_eq_with_constant.main.GVN.diff
@@ -12,6 +12,7 @@
scope 5 (inlined std::ptr::Alignment::as_nonzero) {
}
scope 6 (inlined NonNull::::without_provenance) {
+ let mut _4: (*const u8) is !null;
scope 7 {
}
scope 8 (inlined NonZero::::get) {
@@ -29,9 +30,9 @@
}
}
scope 12 (inlined Foo::::cmp_ptr) {
- let mut _4: *const u8;
- let mut _5: *mut u8;
- let mut _6: *const u8;
+ let mut _5: *const u8;
+ let mut _6: *mut u8;
+ let mut _7: *const u8;
scope 13 (inlined std::ptr::eq::) {
}
}
@@ -39,26 +40,29 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
+ StorageLive(_4);
StorageLive(_3);
- _3 = const std::ptr::Alignment::of::::{constant#0} as std::num::NonZero (Transmute);
-- _2 = copy _3 as *mut u8 (Transmute);
-+ _3 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize));
-+ _2 = const {0x1 as *mut u8};
+- _4 = copy _3 as (*const u8) is !null (Transmute);
++ _3 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
++ _4 = const {0x1 as *const u8} is !null;
StorageDead(_3);
- StorageLive(_4);
+- _2 = copy _4 as *mut u8 (Transmute);
++ _2 = const {0x1 as *const u8} is !null as *mut u8 (Transmute);
+ StorageDead(_4);
StorageLive(_5);
-- _5 = copy _2;
-- _4 = copy _2 as *const u8 (PtrToPtr);
-+ _5 = const {0x1 as *mut u8};
-+ _4 = const {0x1 as *const u8};
- StorageDead(_5);
StorageLive(_6);
-- _6 = const Foo::::SENTINEL as *const u8 (PtrToPtr);
-- _1 = Eq(copy _4, copy _6);
-+ _6 = const {0x1 as *const u8};
-+ _1 = const true;
+ _6 = copy _2;
+- _5 = copy _2 as *const u8 (PtrToPtr);
++ _5 = const {0x1 as *const u8} is !null as *const u8 (Transmute);
StorageDead(_6);
- StorageDead(_4);
+ StorageLive(_7);
+- _7 = const Foo::::SENTINEL as *const u8 (PtrToPtr);
+- _1 = Eq(copy _5, copy _7);
++ _7 = const {0x1 as *const u8};
++ _1 = Eq(copy _5, const {0x1 as *const u8});
+ StorageDead(_7);
+ StorageDead(_5);
StorageDead(_2);
StorageDead(_1);
_0 = const ();
diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
index f6c111a2228a9..e75984b98fbe4 100644
--- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
@@ -19,9 +19,10 @@
+ scope 4 (inlined alloc::raw_vec::RawVec::::ptr) {
+ scope 5 (inlined alloc::raw_vec::RawVecInner::ptr::) {
+ scope 6 (inlined alloc::raw_vec::RawVecInner::non_null::) {
-+ let mut _11: std::ptr::NonNull;
++ let mut _12: std::ptr::NonNull;
+ scope 7 (inlined Unique::::cast::) {
+ scope 8 (inlined NonNull::::cast::) {
++ let mut _11: (*const A) is !null;
+ scope 9 (inlined NonNull::::as_ptr) {
+ }
+ }
@@ -39,15 +40,15 @@
+ }
+ }
+ scope 14 (inlined drop_in_place::<[A]> - shim(Some([A]))) {
-+ let mut _12: usize;
-+ let mut _13: *mut A;
-+ let mut _14: bool;
++ let mut _13: usize;
++ let mut _14: *mut A;
++ let mut _15: bool;
+ }
+ }
+ }
+ scope 15 (inlined drop_in_place::