diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 1b831c454e6d5..1717d22833768 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2364,6 +2364,8 @@ pub enum TyPatKind {
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
Range(Option
>, Option
>, Spanned),
+ Or(ThinVec>),
+
/// Placeholder for a pattern that wasn't syntactically well formed in some way.
Err(ErrorGuaranteed),
}
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index e4396a50a15eb..87de9d6ce21bd 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -609,6 +609,7 @@ pub fn walk_ty_pat(vis: &mut T, ty: &mut P) {
visit_opt(start, |c| vis.visit_anon_const(c));
visit_opt(end, |c| vis.visit_anon_const(c));
}
+ TyPatKind::Or(variants) => visit_thin_vec(variants, |p| vis.visit_ty_pat(p)),
TyPatKind::Err(_) => {}
}
visit_lazy_tts(vis, tokens);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index cfcb0e23cb5e6..55de0c344ce70 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -565,6 +565,7 @@ pub fn walk_ty_pat<'a, V: Visitor<'a>>(visitor: &mut V, tp: &'a TyPat) -> V::Res
visit_opt!(visitor, visit_anon_const, start);
visit_opt!(visitor, visit_anon_const, end);
}
+ TyPatKind::Or(variants) => walk_list!(visitor, visit_ty_pat, variants),
TyPatKind::Err(_) => {}
}
V::Result::output()
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 07cc64a1358ee..9e871fc611e1d 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -463,6 +463,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
}),
),
+ TyPatKind::Or(variants) => {
+ hir::TyPatKind::Or(self.arena.alloc_from_iter(
+ variants.iter().map(|pat| self.lower_ty_pat_mut(pat, base_type)),
+ ))
+ }
TyPatKind::Err(guar) => hir::TyPatKind::Err(*guar),
};
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index a8eaff7346b7d..a310ca099fcd7 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1166,6 +1166,17 @@ impl<'a> State<'a> {
self.print_expr_anon_const(end, &[]);
}
}
+ rustc_ast::TyPatKind::Or(variants) => {
+ let mut first = true;
+ for pat in variants {
+ if first {
+ first = false
+ } else {
+ self.word(" | ");
+ }
+ self.print_ty_pat(pat);
+ }
+ }
rustc_ast::TyPatKind::Err(_) => {
self.popen();
self.word("/*ERROR*/");
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 9d5022f2bef4c..ea8d0b23d4586 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2174,11 +2174,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
CastKind::Transmute => {
- span_mirbug!(
- self,
- rvalue,
- "Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
- );
+ let ty_from = op.ty(self.body, tcx);
+ match ty_from.kind() {
+ ty::Pat(base, _) if base == ty => {}
+ _ => span_mirbug!(
+ self,
+ rvalue,
+ "Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
+ ),
+ }
}
}
}
diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs
index a55c7e962d098..3529e5525fcd2 100644
--- a/compiler/rustc_builtin_macros/src/pattern_type.rs
+++ b/compiler/rustc_builtin_macros/src/pattern_type.rs
@@ -1,9 +1,10 @@
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast};
+use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token};
use rustc_errors::PResult;
use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
use rustc_parse::exp;
+use rustc_parse::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
use rustc_span::Span;
pub(crate) fn expand<'cx>(
@@ -26,19 +27,42 @@ 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 = parser.parse_pat_no_top_alt(None, None)?.into_inner();
+ let pat = 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()?;
+ }
+
+ Ok((ty, pat))
+}
+
+fn ty_pat(kind: TyPatKind, span: Span) -> P {
+ P(TyPat { id: DUMMY_NODE_ID, kind, span, tokens: None })
+}
+
+fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> P {
let kind = match pat.kind {
ast::PatKind::Range(start, end, include_end) => TyPatKind::Range(
start.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })),
end.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })),
include_end,
),
+ ast::PatKind::Or(variants) => TyPatKind::Or(
+ variants.into_iter().map(|pat| pat_to_ty_pat(cx, pat.into_inner())).collect(),
+ ),
ast::PatKind::Err(guar) => TyPatKind::Err(guar),
_ => TyPatKind::Err(cx.dcx().span_err(pat.span, "pattern not supported in pattern types")),
};
-
- let pat = P(TyPat { id: pat.id, kind, span: pat.span, tokens: pat.tokens });
-
- Ok((ty, pat))
+ ty_pat(kind, pat.span)
}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 98d59f5a8ae06..68a4ff4074a29 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -455,7 +455,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_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 29f819cca1fb6..1eefffac13429 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/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 4ca317e3a1e53..4e725a3b74c3a 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -70,6 +70,9 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
ty::Pat(_, pat) => match **pat {
ty::PatternKind::Range { .. } => ConstValue::from_target_usize(0u64, &tcx),
// Future pattern kinds may have more variants
+ // FIXME(pattern_types): make this report the number of distinct variants used in the
+ // or pattern in case the base type is an enum.
+ ty::PatternKind::Or(_) => ConstValue::from_target_usize(0_u64, &tcx),
},
ty::Bound(_, _) => bug!("bound ty during ctfe"),
ty::Bool
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index eb3f552cd2787..5071da1bc79f4 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -1248,6 +1248,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
// Range patterns are precisely reflected into `valid_range` and thus
// handled fully by `visit_scalar` (called below).
ty::PatternKind::Range { .. } => {},
+
+ // FIXME(pattern_types): check that the value is covered by one of the variants.
+ // The layout may pessimistically cover actually illegal ranges.
+ ty::PatternKind::Or(_patterns) => {}
}
}
_ => {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 53f0194091cdc..23d4116fb2c9f 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1675,6 +1675,9 @@ pub enum TyPatKind<'hir> {
/// A range pattern (e.g., `1..=2` or `1..2`).
Range(&'hir ConstArg<'hir>, &'hir ConstArg<'hir>),
+ /// A list of patterns where only one needs to be satisfied
+ Or(&'hir [TyPat<'hir>]),
+
/// A placeholder for a pattern that wasn't well formed in some way.
Err(ErrorGuaranteed),
}
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 3ef645a5f6172..d5c614a7de18c 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -693,6 +693,7 @@ pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>)
try_visit!(visitor.visit_const_arg_unambig(lower_bound));
try_visit!(visitor.visit_const_arg_unambig(upper_bound));
}
+ TyPatKind::Or(patterns) => walk_list!(visitor, visit_pattern_type_pattern, patterns),
TyPatKind::Err(_) => (),
}
V::Result::output()
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 6936544838c81..f320a0530af14 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -93,10 +93,12 @@ fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: S
}
Node::TyPat(pat) => {
- let hir::TyKind::Pat(ty, p) = tcx.parent_hir_node(pat.hir_id).expect_ty().kind else {
- bug!()
+ let node = match tcx.parent_hir_node(pat.hir_id) {
+ // Or patterns can be nested one level deep
+ Node::TyPat(p) => tcx.parent_hir_node(p.hir_id),
+ other => other,
};
- assert_eq!(p.hir_id, pat.hir_id);
+ let hir::TyKind::Pat(ty, _) = node.expect_ty().kind else { bug!() };
icx.lower_ty(ty)
}
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 5f91f1d7b3e1f..110bd9ce649bb 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2698,30 +2698,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::TyKind::Pat(ty, pat) => {
let ty_span = ty.span;
let ty = self.lower_ty(ty);
- let pat_ty = match pat.kind {
- hir::TyPatKind::Range(start, end) => {
- let (ty, start, end) = match ty.kind() {
- // Keep this list of types in sync with the list of types that
- // the `RangePattern` trait is implemented for.
- ty::Int(_) | ty::Uint(_) | ty::Char => {
- let start = self.lower_const_arg(start, FeedConstTy::No);
- let end = self.lower_const_arg(end, FeedConstTy::No);
- (ty, start, end)
- }
- _ => {
- let guar = self.dcx().span_delayed_bug(
- ty_span,
- "invalid base type for range pattern",
- );
- let errc = ty::Const::new_error(tcx, guar);
- (Ty::new_error(tcx, guar), errc, errc)
- }
- };
-
- let pat = tcx.mk_pat(ty::PatternKind::Range { start, end });
- Ty::new_pat(tcx, ty, pat)
- }
- hir::TyPatKind::Err(e) => Ty::new_error(tcx, e),
+ let pat_ty = match self.lower_pat_ty_pat(ty, ty_span, pat) {
+ Ok(kind) => Ty::new_pat(tcx, ty, tcx.mk_pat(kind)),
+ Err(guar) => Ty::new_error(tcx, guar),
};
self.record_ty(pat.hir_id, ty, pat.span);
pat_ty
@@ -2733,6 +2712,39 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
result_ty
}
+ fn lower_pat_ty_pat(
+ &self,
+ ty: Ty<'tcx>,
+ ty_span: Span,
+ pat: &hir::TyPat<'tcx>,
+ ) -> Result, ErrorGuaranteed> {
+ let tcx = self.tcx();
+ match pat.kind {
+ hir::TyPatKind::Range(start, end) => {
+ match ty.kind() {
+ // Keep this list of types in sync with the list of types that
+ // the `RangePattern` trait is implemented for.
+ ty::Int(_) | ty::Uint(_) | ty::Char => {
+ let start = self.lower_const_arg(start, FeedConstTy::No);
+ let end = self.lower_const_arg(end, FeedConstTy::No);
+ Ok(ty::PatternKind::Range { start, end })
+ }
+ _ => Err(self
+ .dcx()
+ .span_delayed_bug(ty_span, "invalid base type for range pattern")),
+ }
+ }
+ hir::TyPatKind::Or(patterns) => {
+ self.tcx()
+ .mk_patterns_from_iter(patterns.iter().map(|pat| {
+ self.lower_pat_ty_pat(ty, ty_span, pat).map(|pat| tcx.mk_pat(pat))
+ }))
+ .map(ty::PatternKind::Or)
+ }
+ hir::TyPatKind::Err(e) => Err(e),
+ }
+ }
+
/// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR.
#[instrument(level = "debug", skip(self), ret)]
fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> {
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 8475903c68fde..6506b91e2492f 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -251,12 +251,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
}
ty::Pat(typ, pat) => {
- match *pat {
- ty::PatternKind::Range { start, end } => {
- self.add_constraints_from_const(current, start, variance);
- self.add_constraints_from_const(current, end, variance);
- }
- }
+ self.add_constraints_from_pat(current, variance, pat);
self.add_constraints_from_ty(current, typ, variance);
}
@@ -334,6 +329,25 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
}
}
+ fn add_constraints_from_pat(
+ &mut self,
+ current: &CurrentItem,
+ variance: VarianceTermPtr<'a>,
+ pat: ty::Pattern<'tcx>,
+ ) {
+ match *pat {
+ ty::PatternKind::Range { start, end } => {
+ self.add_constraints_from_const(current, start, variance);
+ self.add_constraints_from_const(current, end, variance);
+ }
+ ty::PatternKind::Or(patterns) => {
+ for pat in patterns {
+ self.add_constraints_from_pat(current, variance, pat)
+ }
+ }
+ }
+ }
+
/// Adds constraints appropriate for a nominal type (enum, struct,
/// object, etc) appearing in a context with ambient variance `variance`
fn add_constraints_from_args(
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 163d9a1b9d975..4364285a89859 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1878,6 +1878,19 @@ impl<'a> State<'a> {
self.word("..=");
self.print_const_arg(end);
}
+ TyPatKind::Or(patterns) => {
+ self.popen();
+ let mut first = true;
+ for pat in patterns {
+ if first {
+ first = false;
+ } else {
+ self.word(" | ");
+ }
+ self.print_ty_pat(pat);
+ }
+ self.pclose();
+ }
TyPatKind::Err(_) => {
self.popen();
self.word("/*ERROR*/");
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index fcadbfc3c4a7e..40929ae5e1657 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -879,25 +879,36 @@ fn ty_is_known_nonnull<'tcx>(
}
ty::Pat(base, pat) => {
ty_is_known_nonnull(tcx, typing_env, *base, mode)
- || Option::unwrap_or_default(
- try {
- match **pat {
- ty::PatternKind::Range { start, end } => {
- let start = start.try_to_value()?.try_to_bits(tcx, typing_env)?;
- let end = end.try_to_value()?.try_to_bits(tcx, typing_env)?;
-
- // This also works for negative numbers, as we just need
- // to ensure we aren't wrapping over zero.
- start > 0 && end >= start
- }
- }
- },
- )
+ || pat_ty_is_known_nonnull(tcx, typing_env, *pat)
}
_ => false,
}
}
+fn pat_ty_is_known_nonnull<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ typing_env: ty::TypingEnv<'tcx>,
+ pat: ty::Pattern<'tcx>,
+) -> bool {
+ Option::unwrap_or_default(
+ try {
+ match *pat {
+ ty::PatternKind::Range { start, end } => {
+ let start = start.try_to_value()?.try_to_bits(tcx, typing_env)?;
+ let end = end.try_to_value()?.try_to_bits(tcx, typing_env)?;
+
+ // This also works for negative numbers, as we just need
+ // to ensure we aren't wrapping over zero.
+ start > 0 && end >= start
+ }
+ ty::PatternKind::Or(patterns) => {
+ patterns.iter().all(|pat| pat_ty_is_known_nonnull(tcx, typing_env, pat))
+ }
+ }
+ },
+ )
+}
+
/// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type.
/// If the type passed in was not scalar, returns None.
fn get_nullable_type<'tcx>(
@@ -1039,13 +1050,29 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
}
None
}
- ty::Pat(base, pat) => match **pat {
- ty::PatternKind::Range { .. } => get_nullable_type(tcx, typing_env, *base),
- },
+ ty::Pat(base, pat) => get_nullable_type_from_pat(tcx, typing_env, *base, *pat),
_ => None,
}
}
+fn get_nullable_type_from_pat<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ typing_env: ty::TypingEnv<'tcx>,
+ base: Ty<'tcx>,
+ pat: ty::Pattern<'tcx>,
+) -> Option> {
+ match *pat {
+ 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..] {
+ assert_eq!(first, get_nullable_type_from_pat(tcx, typing_env, base, pat)?);
+ }
+ Some(first)
+ }
+ }
+}
+
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Check if the type is array and emit an unsafe type lint.
fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index fe42a224d9f22..42ec3e80813e5 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -419,6 +419,15 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D>
}
}
+impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List> {
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ let len = decoder.read_usize();
+ decoder.interner().mk_patterns_from_iter(
+ (0..len).map::, _>(|_| Decodable::decode(decoder)),
+ )
+ }
+}
+
impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List> {
fn decode(decoder: &mut D) -> &'tcx Self {
let len = decoder.read_usize();
@@ -482,6 +491,7 @@ impl_decodable_via_ref! {
&'tcx mir::Body<'tcx>,
&'tcx mir::BorrowCheckResult<'tcx>,
&'tcx ty::List,
+ &'tcx ty::List>,
&'tcx ty::ListWithCachedTypeInfo>,
&'tcx ty::List,
&'tcx ty::List<(VariantIdx, FieldIdx)>,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index edba2a2530f68..4fc327eb8605e 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -812,6 +812,7 @@ pub struct CtxtInterners<'tcx> {
captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>,
offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>,
valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>,
+ patterns: InternedSet<'tcx, List>>,
}
impl<'tcx> CtxtInterners<'tcx> {
@@ -848,6 +849,7 @@ impl<'tcx> CtxtInterners<'tcx> {
captures: InternedSet::with_capacity(N),
offset_of: InternedSet::with_capacity(N),
valtree: InternedSet::with_capacity(N),
+ patterns: InternedSet::with_capacity(N),
}
}
@@ -2594,6 +2596,7 @@ slice_interners!(
local_def_ids: intern_local_def_ids(LocalDefId),
captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>),
offset_of: pub mk_offset_of((VariantIdx, FieldIdx)),
+ patterns: pub mk_patterns(Pattern<'tcx>),
);
impl<'tcx> TyCtxt<'tcx> {
@@ -2867,6 +2870,14 @@ impl<'tcx> TyCtxt<'tcx> {
self.intern_local_def_ids(clauses)
}
+ pub fn mk_patterns_from_iter(self, iter: I) -> T::Output
+ where
+ I: Iterator- ,
+ T: CollectAndApply, &'tcx List>>,
+ {
+ T::collect_and_apply(iter, |xs| self.mk_patterns(xs))
+ }
+
pub fn mk_local_def_ids_from_iter(self, iter: I) -> T::Output
where
I: Iterator
- ,
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 0b8f0e8cd41d9..549acef5ecc03 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -219,12 +219,7 @@ impl FlagComputation {
&ty::Pat(ty, pat) => {
self.add_ty(ty);
- match *pat {
- ty::PatternKind::Range { start, end } => {
- self.add_const(start);
- self.add_const(end);
- }
- }
+ self.add_pat(pat);
}
&ty::Slice(tt) => self.add_ty(tt),
@@ -258,6 +253,20 @@ impl FlagComputation {
}
}
+ fn add_pat(&mut self, pat: ty::Pattern<'_>) {
+ match *pat {
+ ty::PatternKind::Range { start, end } => {
+ self.add_const(start);
+ self.add_const(end);
+ }
+ ty::PatternKind::Or(patterns) => {
+ for pat in patterns {
+ self.add_pat(pat);
+ }
+ }
+ }
+ }
+
fn add_predicate(&mut self, binder: ty::Binder<'_, ty::PredicateKind<'_>>) {
self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
}
diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs
index 4cad1ab209916..814d3a9ed3aba 100644
--- a/compiler/rustc_middle/src/ty/pattern.rs
+++ b/compiler/rustc_middle/src/ty/pattern.rs
@@ -51,6 +51,19 @@ impl<'tcx> fmt::Debug for PatternKind<'tcx> {
write!(f, "..={end}")
}
+ PatternKind::Or(patterns) => {
+ write!(f, "(")?;
+ let mut first = true;
+ for pat in patterns {
+ if first {
+ first = false
+ } else {
+ write!(f, " | ")?;
+ }
+ write!(f, "{pat:?}")?;
+ }
+ write!(f, ")")
+ }
}
}
}
@@ -59,4 +72,5 @@ impl<'tcx> fmt::Debug for PatternKind<'tcx> {
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
pub enum PatternKind<'tcx> {
Range { start: ty::Const<'tcx>, end: ty::Const<'tcx> },
+ Or(&'tcx ty::List>),
}
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index b1dfcb80bde57..6ad4e5276b253 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -49,6 +49,7 @@ impl<'tcx> Relate> for ty::Pattern<'tcx> {
a: Self,
b: Self,
) -> RelateResult<'tcx, Self> {
+ let tcx = relation.cx();
match (&*a, &*b) {
(
&ty::PatternKind::Range { start: start_a, end: end_a },
@@ -56,8 +57,17 @@ impl<'tcx> Relate> for ty::Pattern<'tcx> {
) => {
let start = relation.relate(start_a, start_b)?;
let end = relation.relate(end_a, end_b)?;
- Ok(relation.cx().mk_pat(ty::PatternKind::Range { start, end }))
+ Ok(tcx.mk_pat(ty::PatternKind::Range { start, end }))
+ }
+ (&ty::PatternKind::Or(a), &ty::PatternKind::Or(b)) => {
+ if a.len() != b.len() {
+ return Err(TypeError::Mismatch);
+ }
+ let v = iter::zip(a, b).map(|(a, b)| relation.relate(a, b));
+ 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),
}
}
}
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 6c62c04f42e4c..557834bd5739c 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -720,3 +720,12 @@ impl<'tcx> TypeFoldable> for &'tcx ty::List> {
ty::util::fold_list(self, folder, |tcx, v| tcx.mk_place_elems(v))
}
}
+
+impl<'tcx> TypeFoldable> for &'tcx ty::List> {
+ fn try_fold_with>>(
+ self,
+ folder: &mut F,
+ ) -> Result {
+ ty::util::fold_list(self, folder, |tcx, v| tcx.mk_patterns(v))
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index a23316ae6fc88..714da0eee7a9f 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -136,12 +136,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
| ty::Foreign(..) => {}
ty::Pat(ty, pat) => {
- match *pat {
- ty::PatternKind::Range { start, end } => {
- stack.push(end.into());
- stack.push(start.into());
- }
- }
+ push_pat(stack, pat);
stack.push(ty.into());
}
ty::Array(ty, len) => {
@@ -215,3 +210,17 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
},
}
}
+
+fn push_pat<'tcx>(stack: &mut SmallVec<[GenericArg<'tcx>; 8]>, pat: ty::Pattern<'tcx>) {
+ match *pat {
+ ty::PatternKind::Range { start, end } => {
+ stack.push(end.into());
+ stack.push(start.into());
+ }
+ ty::PatternKind::Or(patterns) => {
+ for pat in patterns {
+ push_pat(stack, pat)
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs
index e5d61bc9e556a..d03cabd607ff4 100644
--- a/compiler/rustc_mir_build/src/builder/matches/test.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/test.rs
@@ -141,8 +141,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let success_block = target_block(TestBranch::Success);
let fail_block = target_block(TestBranch::Failure);
- let expect_ty = value.ty();
- let expect = self.literal_operand(test.span, value);
+ let mut expect_ty = value.ty();
+ let mut expect = self.literal_operand(test.span, value);
let mut place = place;
let mut block = block;
@@ -175,6 +175,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place = ref_str;
ty = ref_str_ty;
}
+ &ty::Pat(base, _) => {
+ assert_eq!(ty, value.ty());
+
+ let transmuted_place = self.temp(base, test.span);
+ self.cfg.push_assign(
+ block,
+ self.source_info(scrutinee_span),
+ transmuted_place,
+ Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base),
+ );
+
+ let transmuted_expect = self.temp(base, test.span);
+ self.cfg.push_assign(
+ block,
+ self.source_info(test.span),
+ transmuted_expect,
+ Rvalue::Cast(CastKind::Transmute, expect, base),
+ );
+
+ place = transmuted_place;
+ expect = Operand::Copy(transmuted_expect);
+ ty = base;
+ expect_ty = base;
+ }
_ => {}
}
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 2c3e4bb505cc7..9ccc8867f449f 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -957,6 +957,11 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
self.resolve_anon_const(end, AnonConstKind::ConstArg(IsRepeatExpr::No));
}
}
+ TyPatKind::Or(patterns) => {
+ for pat in patterns {
+ self.visit_ty_pat(pat)
+ }
+ }
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 aa0eac628dd0f..feeb0f53e1be4 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -411,6 +411,7 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
end: Some(end.stable(tables)),
include_end: true,
},
+ ty::PatternKind::Or(_) => todo!(),
}
}
}
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index bc3923e4b4d67..849c88b1a0b4c 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -196,6 +196,22 @@ impl<'tcx> SymbolMangler<'tcx> {
Ok(())
}
+
+ fn print_pat(&mut self, pat: ty::Pattern<'tcx>) -> Result<(), std::fmt::Error> {
+ Ok(match *pat {
+ ty::PatternKind::Range { start, end } => {
+ let consts = [start, end];
+ for ct in consts {
+ Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?;
+ }
+ }
+ ty::PatternKind::Or(patterns) => {
+ for pat in patterns {
+ self.print_pat(pat)?;
+ }
+ }
+ })
+ }
}
impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
@@ -412,20 +428,14 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
ty.print(self)?;
}
- ty::Pat(ty, pat) => match *pat {
- ty::PatternKind::Range { start, end } => {
- let consts = [start, end];
- // HACK: Represent as tuple until we have something better.
- // HACK: constants are used in arrays, even if the types don't match.
- self.push("T");
- ty.print(self)?;
- for ct in consts {
- Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct)
- .print(self)?;
- }
- self.push("E");
- }
- },
+ ty::Pat(ty, pat) => {
+ // HACK: Represent as tuple until we have something better.
+ // HACK: constants are used in arrays, even if the types don't match.
+ self.push("T");
+ ty.print(self)?;
+ self.print_pat(pat)?;
+ self.push("E");
+ }
ty::Array(ty, len) => {
self.push("A");
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 54b6c22b2d821..d93ddb2018eee 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -653,6 +653,50 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
}
}
}
+
+ fn check_pat(&mut self, subty: Ty<'tcx>, pat: ty::Pattern<'tcx>) {
+ let tcx = self.tcx();
+ match *pat {
+ ty::PatternKind::Range { start, end } => {
+ let mut check = |c| {
+ let cause = self.cause(ObligationCauseCode::Misc);
+ self.out.push(traits::Obligation::with_depth(
+ tcx,
+ cause.clone(),
+ self.recursion_depth,
+ self.param_env,
+ ty::Binder::dummy(ty::PredicateKind::Clause(
+ ty::ClauseKind::ConstArgHasType(c, subty),
+ )),
+ ));
+ if !tcx.features().generic_pattern_types() {
+ if c.has_param() {
+ if self.span.is_dummy() {
+ self.tcx()
+ .dcx()
+ .delayed_bug("feature error should be reported elsewhere, too");
+ } else {
+ feature_err(
+ &self.tcx().sess,
+ sym::generic_pattern_types,
+ self.span,
+ "wraparound pattern type ranges cause monomorphization time errors",
+ )
+ .emit();
+ }
+ }
+ }
+ };
+ check(start);
+ check(end);
+ }
+ ty::PatternKind::Or(patterns) => {
+ for pat in patterns {
+ self.check_pat(subty, pat)
+ }
+ }
+ }
+ }
}
impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> {
@@ -707,41 +751,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> {
ty::Pat(subty, pat) => {
self.require_sized(subty, ObligationCauseCode::Misc);
- match *pat {
- ty::PatternKind::Range { start, end } => {
- let mut check = |c| {
- let cause = self.cause(ObligationCauseCode::Misc);
- self.out.push(traits::Obligation::with_depth(
- tcx,
- cause.clone(),
- self.recursion_depth,
- self.param_env,
- ty::Binder::dummy(ty::PredicateKind::Clause(
- ty::ClauseKind::ConstArgHasType(c, subty),
- )),
- ));
- if !tcx.features().generic_pattern_types() {
- if c.has_param() {
- if self.span.is_dummy() {
- self.tcx().dcx().delayed_bug(
- "feature error should be reported elsewhere, too",
- );
- } else {
- feature_err(
- &self.tcx().sess,
- sym::generic_pattern_types,
- self.span,
- "wraparound pattern type ranges cause monomorphization time errors",
- )
- .emit();
- }
- }
- }
- };
- check(start);
- check(end);
- }
- }
+ self.check_pat(subty, pat);
}
ty::Tuple(tys) => {
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 7334beb52c9d5..d200dc2961362 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -255,13 +255,95 @@ fn layout_of_uncached<'tcx>(
};
layout.largest_niche = Some(niche);
-
- tcx.mk_layout(layout)
} else {
bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}")
}
}
+ ty::PatternKind::Or(variants) => match *variants[0] {
+ ty::PatternKind::Range { .. } => {
+ if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
+ let variants: Result, _> = variants
+ .iter()
+ .map(|pat| match *pat {
+ ty::PatternKind::Range { start, end } => Ok((
+ extract_const_value(cx, ty, start)
+ .unwrap()
+ .try_to_bits(tcx, cx.typing_env)
+ .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
+ extract_const_value(cx, ty, end)
+ .unwrap()
+ .try_to_bits(tcx, cx.typing_env)
+ .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
+ )),
+ ty::PatternKind::Or(_) => {
+ unreachable!("mixed or patterns are not allowed")
+ }
+ })
+ .collect();
+ let mut variants = variants?;
+ if !scalar.is_signed() {
+ let guar = tcx.dcx().err(format!(
+ "only signed integer base types are allowed for or-pattern pattern types at present"
+ ));
+
+ return Err(error(cx, LayoutError::ReferencesError(guar)));
+ }
+ variants.sort();
+ if variants.len() != 2 {
+ let guar = tcx
+ .dcx()
+ .err(format!("the only or-pattern types allowed are two range patterns that are directly connected at their overflow site"));
+
+ return Err(error(cx, LayoutError::ReferencesError(guar)));
+ }
+
+ // first is the one starting at the signed in range min
+ let mut first = variants[0];
+ let mut second = variants[1];
+ if second.0
+ == layout.size.truncate(layout.size.signed_int_min() as u128)
+ {
+ (second, first) = (first, second);
+ }
+
+ if layout.size.sign_extend(first.1) >= layout.size.sign_extend(second.0)
+ {
+ let guar = tcx.dcx().err(format!(
+ "only non-overlapping pattern type ranges are allowed at present"
+ ));
+
+ return Err(error(cx, LayoutError::ReferencesError(guar)));
+ }
+ if layout.size.signed_int_max() as u128 != second.1 {
+ let guar = tcx.dcx().err(format!(
+ "one pattern needs to end at `{ty}::MAX`, but was {} instead",
+ second.1
+ ));
+
+ return Err(error(cx, LayoutError::ReferencesError(guar)));
+ }
+
+ // Now generate a wrapping range (which aren't allowed in surface syntax).
+ scalar.valid_range_mut().start = second.0;
+ scalar.valid_range_mut().end = first.1;
+
+ let niche = Niche {
+ offset: Size::ZERO,
+ value: scalar.primitive(),
+ valid_range: scalar.valid_range(cx),
+ };
+
+ layout.largest_niche = Some(niche);
+ } else {
+ bug!(
+ "pattern type with range but not scalar layout: {ty:?}, {layout:?}"
+ )
+ }
+ }
+ ty::PatternKind::Or(..) => bug!("patterns cannot have nested or patterns"),
+ },
}
+ tcx.mk_layout(layout)
}
// Basic scalars.
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 987fa93d59877..b0a7fc5869293 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -183,6 +183,8 @@
#![feature(no_core)]
#![feature(no_sanitize)]
#![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/mod.rs b/library/core/src/num/mod.rs
index 151e128cd78a9..51f440a8be0e5 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -53,6 +53,7 @@ mod wrapping;
/// 100% perma-unstable
#[doc(hidden)]
+#[cfg_attr(bootstrap, path = "niche_types_bootstrap.rs")]
pub mod niche_types;
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/num/niche_types.rs b/library/core/src/num/niche_types.rs
index 47ff4254e533b..b9ca4791ee702 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) {
+ #[allow(non_contiguous_range_endpoints)]
+ if let $pat = val {
// SAFETY: just checked the inclusive range
- Some(unsafe { $name(val) })
+ 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/num/niche_types_bootstrap.rs b/library/core/src/num/niche_types_bootstrap.rs
new file mode 100644
index 0000000000000..47ff4254e533b
--- /dev/null
+++ b/library/core/src/num/niche_types_bootstrap.rs
@@ -0,0 +1,178 @@
+#![unstable(
+ feature = "temporary_niche_types",
+ issue = "none",
+ reason = "for core, alloc, and std internals until pattern types are further along"
+)]
+
+use crate::cmp::Ordering;
+use crate::fmt;
+use crate::hash::{Hash, Hasher};
+use crate::marker::StructuralPartialEq;
+
+macro_rules! define_valid_range_type {
+ ($(
+ $(#[$m:meta])*
+ $vis:vis struct $name:ident($int:ident as $uint:ident in $low:literal..=$high:literal);
+ )+) => {$(
+ #[derive(Clone, Copy, Eq)]
+ #[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>());
+ };
+
+ 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) })
+ } else {
+ None
+ }
+ }
+
+ /// Constructs an instance of this type from the underlying integer
+ /// primitive without checking whether its zero.
+ ///
+ /// # Safety
+ /// Immediate language UB if `val == 0`, 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) }
+ }
+
+ #[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) }
+ }
+ }
+
+ // This is required to allow matching a constant. We don't get it from a derive
+ // because the derived `PartialEq` would do a field projection, which is banned
+ // by .
+ impl StructuralPartialEq for $name {}
+
+ impl PartialEq for $name {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.as_inner() == other.as_inner()
+ }
+ }
+
+ impl Ord for $name {
+ #[inline]
+ fn cmp(&self, other: &Self) -> Ordering {
+ Ord::cmp(&self.as_inner(), &other.as_inner())
+ }
+ }
+
+ impl PartialOrd for $name {
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option {
+ Some(Ord::cmp(self, other))
+ }
+ }
+
+ impl Hash for $name {
+ // Required method
+ fn hash(&self, state: &mut H) {
+ Hash::hash(&self.as_inner(), state);
+ }
+ }
+
+ impl fmt::Debug for $name {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ <$int as fmt::Debug>::fmt(&self.as_inner(), f)
+ }
+ }
+ )+};
+}
+
+define_valid_range_type! {
+ pub struct Nanoseconds(u32 as u32 in 0..=999_999_999);
+}
+
+impl Nanoseconds {
+ // SAFETY: 0 is within the valid range
+ pub const ZERO: Self = unsafe { Nanoseconds::new_unchecked(0) };
+}
+
+impl Default for Nanoseconds {
+ #[inline]
+ fn default() -> Self {
+ Self::ZERO
+ }
+}
+
+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);
+}
+
+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 trait NotAllOnesHelper {
+ type Type;
+}
+pub type NotAllOnes = ::Type;
+impl NotAllOnesHelper for u32 {
+ type Type = U32NotAllOnes;
+}
+impl NotAllOnesHelper for i32 {
+ type Type = I32NotAllOnes;
+}
+impl NotAllOnesHelper for u64 {
+ type Type = U64NotAllOnes;
+}
+impl NotAllOnesHelper for i64 {
+ type Type = I64NotAllOnes;
+}
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 9938e64d24264..c65658cdf8e4d 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1117,6 +1117,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_const_arg(s);
self.hash_const_arg(e);
},
+ TyPatKind::Or(variants) => {
+ for variant in variants.iter() {
+ self.hash_ty_pat(variant)
+ }
+ },
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/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 06a67334086c5..f6e0d7b9bb930 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -1093,6 +1093,19 @@ impl Rewrite for ast::TyPat {
ast::TyPatKind::Range(ref lhs, ref rhs, ref end_kind) => {
rewrite_range_pat(context, shape, lhs, rhs, end_kind, self.span)
}
+ ast::TyPatKind::Or(ref variants) => {
+ let mut first = true;
+ let mut s = String::new();
+ for variant in variants {
+ if first {
+ first = false
+ } else {
+ s.push_str(" | ");
+ }
+ s.push_str(&variant.rewrite_result(context, shape)?);
+ }
+ Ok(s)
+ }
ast::TyPatKind::Err(_) => Err(RewriteError::Unknown),
}
}
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..9369720c6e5a6 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
@@ -45,7 +45,7 @@
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]} }};
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..f20ecbe21d929 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
@@ -45,7 +45,7 @@
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]} }};
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..8751b0d193dd3 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
@@ -45,7 +45,7 @@
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]} }};
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..d67f1a7dfc964 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
@@ -45,7 +45,7 @@
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]} }};
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..df241d46f0115 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
@@ -46,7 +46,7 @@
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 };
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..b4fa37c704404 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
@@ -46,7 +46,7 @@
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 };
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..fde840b4b7616 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
@@ -46,7 +46,7 @@
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 };
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..cf9c9a852b441 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
@@ -46,7 +46,7 @@
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 };
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..5b8fb659eff12 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
@@ -42,7 +42,7 @@
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));
++ _3 = const NonZero::(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
+ _2 = const {0x1 as *mut u8};
StorageDead(_3);
StorageLive(_4);
diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
index 27c85cc8ce41a..1046a00e8023a 100644
--- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr
@@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:59:1
|
LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 1, align: 1) {
@@ -79,7 +79,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:61:1
|
LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
index 2b0ce99a88173..d40ee565b8e1f 100644
--- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
+++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr
@@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:59:1
|
LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 1, align: 1) {
@@ -79,7 +79,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/raw-bytes.rs:61:1
|
LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr
index 0e4926eb49edf..794612e36bbe4 100644
--- a/tests/ui/consts/const-eval/ub-nonnull.stderr
+++ b/tests/ui/consts/const-eval/ub-nonnull.stderr
@@ -19,7 +19,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-nonnull.rs:24:1
|
LL | const NULL_U8: NonZero = unsafe { mem::transmute(0u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
@@ -30,7 +30,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-nonnull.rs:26:1
|
LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
diff --git a/tests/ui/lint/invalid_value.stderr b/tests/ui/lint/invalid_value.stderr
index cc6a2a1c8e532..3dd2a521ff2e1 100644
--- a/tests/ui/lint/invalid_value.stderr
+++ b/tests/ui/lint/invalid_value.stderr
@@ -333,7 +333,6 @@ LL | let _val: (NonZero, i32) = mem::uninitialized();
|
= note: `std::num::NonZero` must be non-null
= note: because `core::num::niche_types::NonZeroU32Inner` must be non-null
- = note: integers must be initialized
error: the type `*const dyn Send` does not permit zero-initialization
--> $DIR/invalid_value.rs:97:37
@@ -430,7 +429,6 @@ note: because `std::num::NonZero` must be non-null (in this field of the on
LL | Banana(NonZero),
| ^^^^^^^^^^^^
= note: because `core::num::niche_types::NonZeroU32Inner` must be non-null
- = note: integers must be initialized
error: the type `bool` does not permit being left uninitialized
--> $DIR/invalid_value.rs:111:26
diff --git a/tests/ui/type/pattern_types/derives.rs b/tests/ui/type/pattern_types/derives.rs
index 3878c47554d98..d93cb9cf1f2eb 100644
--- a/tests/ui/type/pattern_types/derives.rs
+++ b/tests/ui/type/pattern_types/derives.rs
@@ -1,10 +1,14 @@
-//! Check that pattern types don't implement traits of their base automatically
+//! Check that pattern types don't implement traits of their base automatically.
+//! Exceptions are `Clone` and `Copy`.
#![feature(pattern_types)]
#![feature(pattern_type_macro)]
use std::pat::pattern_type;
+// PartialEq works here as a derive, because internally it calls
+// `==` on the field, which causes coercion to coerce the pattern
+// type to its base type first.
#[derive(Clone, Copy, PartialEq)]
#[repr(transparent)]
struct Nanoseconds(NanoI32);
diff --git a/tests/ui/type/pattern_types/derives.stderr b/tests/ui/type/pattern_types/derives.stderr
index 9d4baef621be3..9450e5753446b 100644
--- a/tests/ui/type/pattern_types/derives.stderr
+++ b/tests/ui/type/pattern_types/derives.stderr
@@ -1,5 +1,5 @@
error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
- --> $DIR/derives.rs:10:20
+ --> $DIR/derives.rs:14:20
|
LL | #[derive(Clone, Copy, PartialEq)]
| --------- in this derive macro expansion
diff --git a/tests/ui/type/pattern_types/derives_fail.rs b/tests/ui/type/pattern_types/derives_fail.rs
new file mode 100644
index 0000000000000..0fb1bc0f51818
--- /dev/null
+++ b/tests/ui/type/pattern_types/derives_fail.rs
@@ -0,0 +1,26 @@
+//! Check that pattern types don't implement traits of their base automatically.
+//! Exceptions are `Clone` and `Copy`.
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+#[repr(transparent)]
+struct Nanoseconds(NanoI32);
+//~^ ERROR: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied
+//~| ERROR: `(i32) is 0..=999999999` doesn't implement `Debug`
+//~| ERROR: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied
+//~| ERROR: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied
+//~| ERROR: the trait bound `(i32) is 0..=999999999: Default` is not satisfied
+//~| ERROR: can't compare `(i32) is 0..=999999999` with `_`
+//~| ERROR: `==` cannot be applied
+
+type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999);
+
+fn main() {
+ let x = Nanoseconds(unsafe { std::mem::transmute(42) });
+ let y = x.clone();
+ if y == x {}
+}
diff --git a/tests/ui/type/pattern_types/derives_fail.stderr b/tests/ui/type/pattern_types/derives_fail.stderr
new file mode 100644
index 0000000000000..6c84859eb75e0
--- /dev/null
+++ b/tests/ui/type/pattern_types/derives_fail.stderr
@@ -0,0 +1,85 @@
+error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | --------- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^
+ |
+ = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | -- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ the trait `Eq` is not implemented for `(i32) is 0..=999999999`
+ |
+note: required by a bound in `AssertParamIsEq`
+ --> $SRC_DIR/core/src/cmp.rs:LL:COL
+ = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `(i32) is 0..=999999999` doesn't implement `Debug`
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | ----- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ `(i32) is 0..=999999999` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+ |
+ = help: the trait `Debug` is not implemented for `(i32) is 0..=999999999`
+ = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | --- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ the trait `Ord` is not implemented for `(i32) is 0..=999999999`
+ |
+ = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: can't compare `(i32) is 0..=999999999` with `_`
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | ---------- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ no implementation for `(i32) is 0..=999999999 < _` and `(i32) is 0..=999999999 > _`
+ |
+ = help: the trait `PartialOrd<_>` is not implemented for `(i32) is 0..=999999999`
+ = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | ---- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ the trait `Hash` is not implemented for `(i32) is 0..=999999999`
+ |
+ = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `(i32) is 0..=999999999: Default` is not satisfied
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | ------- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ the trait `Default` is not implemented for `(i32) is 0..=999999999`
+ |
+ = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0277, E0369.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/type/pattern_types/matching.rs b/tests/ui/type/pattern_types/matching.rs
new file mode 100644
index 0000000000000..b8463a8e82298
--- /dev/null
+++ b/tests/ui/type/pattern_types/matching.rs
@@ -0,0 +1,26 @@
+#![feature(pattern_types, pattern_type_macro, structural_match)]
+
+//@ check-pass
+
+use std::marker::StructuralPartialEq;
+use std::pat::pattern_type;
+
+struct Thing(pattern_type!(u32 is 1..));
+
+impl StructuralPartialEq for Thing {}
+impl PartialEq for Thing {
+ fn eq(&self, other: &Thing) -> bool {
+ unsafe { std::mem::transmute::<_, u32>(self.0) == std::mem::transmute::<_, u32>(other.0) }
+ }
+}
+
+impl Eq for Thing {}
+
+const TWO: Thing = Thing(2);
+
+const _: () = match TWO {
+ TWO => {}
+ _ => unreachable!(),
+};
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/matching_fail.rs b/tests/ui/type/pattern_types/matching_fail.rs
new file mode 100644
index 0000000000000..8e2c741e3e0ab
--- /dev/null
+++ b/tests/ui/type/pattern_types/matching_fail.rs
@@ -0,0 +1,25 @@
+#![feature(pattern_types, pattern_type_macro, structural_match)]
+
+use std::pat::pattern_type;
+
+const THREE: pattern_type!(u32 is 1..) = 3;
+
+const _: () = match THREE {
+ THREE => {}
+ //~^ ERROR non-structural type
+ _ => unreachable!(),
+};
+
+const _: () = match THREE {
+ 3 => {}
+ //~^ ERROR mismatched types
+ _ => unreachable!(),
+};
+
+const _: () = match 3 {
+ THREE => {}
+ //~^ ERROR mismatched types
+ _ => unreachable!(),
+};
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/matching_fail.stderr b/tests/ui/type/pattern_types/matching_fail.stderr
new file mode 100644
index 0000000000000..446180d80f24b
--- /dev/null
+++ b/tests/ui/type/pattern_types/matching_fail.stderr
@@ -0,0 +1,43 @@
+error: constant of non-structural type `(u32) is 1..` in a pattern
+ --> $DIR/matching_fail.rs:8:5
+ |
+LL | const THREE: pattern_type!(u32 is 1..) = 3;
+ | -------------------------------------- constant defined here
+...
+LL | THREE => {}
+ | ^^^^^ constant of non-structural type
+ |
+ = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+
+error[E0308]: mismatched types
+ --> $DIR/matching_fail.rs:14:5
+ |
+LL | const _: () = match THREE {
+ | ----- this expression has type `(u32) is 1..`
+LL | 3 => {}
+ | ^ expected `(u32) is 1..`, found integer
+ |
+ = note: expected pattern type `(u32) is 1..`
+ found type `{integer}`
+
+error[E0308]: mismatched types
+ --> $DIR/matching_fail.rs:20:5
+ |
+LL | const THREE: pattern_type!(u32 is 1..) = 3;
+ | -------------------------------------- constant defined here
+...
+LL | const _: () = match 3 {
+ | - this expression has type `{integer}`
+LL | THREE => {}
+ | ^^^^^
+ | |
+ | expected integer, found `(u32) is 1..`
+ | `THREE` is interpreted as a constant, not a new binding
+ | help: introduce a new binding instead: `other_three`
+ |
+ = note: expected type `{integer}`
+ found pattern type `(u32) is 1..`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/type/pattern_types/or_patterns.rs b/tests/ui/type/pattern_types/or_patterns.rs
new file mode 100644
index 0000000000000..25cb1867047aa
--- /dev/null
+++ b/tests/ui/type/pattern_types/or_patterns.rs
@@ -0,0 +1,45 @@
+//! Demonstrate some use cases of or patterns
+
+//@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
+//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
+
+#![feature(
+ pattern_type_macro,
+ pattern_types,
+ rustc_attrs,
+ const_trait_impl,
+ pattern_type_range_trait
+)]
+
+use std::pat::pattern_type;
+
+#[rustc_layout(debug)]
+type NonNullI8 = pattern_type!(i8 is ..0 | 1..);
+//~^ ERROR: layout_of
+
+#[rustc_layout(debug)]
+type NonNegOneI8 = pattern_type!(i8 is ..-1 | 0..);
+//~^ ERROR: layout_of
+
+fn main() {
+ let _: NonNullI8 = 42;
+ let _: NonNullI8 = 1;
+ let _: NonNullI8 = 0;
+ //~^ ERROR: mismatched types
+ let _: NonNullI8 = -1;
+ //~^ ERROR: cannot apply unary operator
+ let _: NonNullI8 = -128;
+ //~^ ERROR: cannot apply unary operator
+ let _: NonNullI8 = 127;
+
+ let _: NonNegOneI8 = 42;
+ let _: NonNegOneI8 = 1;
+ let _: NonNegOneI8 = 0;
+ let _: NonNegOneI8 = -1;
+ //~^ ERROR: cannot apply unary operator
+ let _: NonNegOneI8 = -2;
+ //~^ ERROR: cannot apply unary operator
+ let _: NonNegOneI8 = -128;
+ //~^ ERROR: cannot apply unary operator
+ let _: NonNegOneI8 = 127;
+}
diff --git a/tests/ui/type/pattern_types/or_patterns.stderr b/tests/ui/type/pattern_types/or_patterns.stderr
new file mode 100644
index 0000000000000..58ca585f4a9a3
--- /dev/null
+++ b/tests/ui/type/pattern_types/or_patterns.stderr
@@ -0,0 +1,123 @@
+error[E0308]: mismatched types
+ --> $DIR/or_patterns.rs:27:24
+ |
+LL | let _: NonNullI8 = 0;
+ | --------- ^ expected `(i8) is (i8::MIN..=-1 | 1..)`, found integer
+ | |
+ | expected due to this
+ |
+ = note: expected pattern type `(i8) is (i8::MIN..=-1 | 1..)`
+ found type `{integer}`
+
+error[E0600]: cannot apply unary operator `-` to type `(i8) is (i8::MIN..=-1 | 1..)`
+ --> $DIR/or_patterns.rs:29:24
+ |
+LL | let _: NonNullI8 = -1;
+ | ^^ cannot apply unary operator `-`
+
+error[E0600]: cannot apply unary operator `-` to type `(i8) is (i8::MIN..=-1 | 1..)`
+ --> $DIR/or_patterns.rs:31:24
+ |
+LL | let _: NonNullI8 = -128;
+ | ^^^^ cannot apply unary operator `-`
+
+error[E0600]: cannot apply unary operator `-` to type `(i8) is (i8::MIN..=-2 | 0..)`
+ --> $DIR/or_patterns.rs:38:26
+ |
+LL | let _: NonNegOneI8 = -1;
+ | ^^ cannot apply unary operator `-`
+
+error[E0600]: cannot apply unary operator `-` to type `(i8) is (i8::MIN..=-2 | 0..)`
+ --> $DIR/or_patterns.rs:40:26
+ |
+LL | let _: NonNegOneI8 = -2;
+ | ^^ cannot apply unary operator `-`
+
+error[E0600]: cannot apply unary operator `-` to type `(i8) is (i8::MIN..=-2 | 0..)`
+ --> $DIR/or_patterns.rs:42:26
+ |
+LL | let _: NonNegOneI8 = -128;
+ | ^^^^ cannot apply unary operator `-`
+
+error: layout_of((i8) is (i8::MIN..=-1 | 1..)) = Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $SOME_ALIGN,
+ },
+ backend_repr: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ true,
+ ),
+ valid_range: 1..=255,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I8,
+ true,
+ ),
+ valid_range: 1..=255,
+ },
+ ),
+ uninhabited: false,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: Align(1 bytes),
+ randomization_seed: $SEED,
+ }
+ --> $DIR/or_patterns.rs:17:1
+ |
+LL | type NonNullI8 = pattern_type!(i8 is ..0 | 1..);
+ | ^^^^^^^^^^^^^^
+
+error: layout_of((i8) is (i8::MIN..=-2 | 0..)) = Layout {
+ size: Size(1 bytes),
+ align: AbiAndPrefAlign {
+ abi: Align(1 bytes),
+ pref: $SOME_ALIGN,
+ },
+ backend_repr: Scalar(
+ Initialized {
+ value: Int(
+ I8,
+ true,
+ ),
+ valid_range: 0..=254,
+ },
+ ),
+ fields: Primitive,
+ largest_niche: Some(
+ Niche {
+ offset: Size(0 bytes),
+ value: Int(
+ I8,
+ true,
+ ),
+ valid_range: 0..=254,
+ },
+ ),
+ uninhabited: false,
+ variants: Single {
+ index: 0,
+ },
+ max_repr_align: None,
+ unadjusted_abi_align: Align(1 bytes),
+ randomization_seed: $SEED,
+ }
+ --> $DIR/or_patterns.rs:21:1
+ |
+LL | type NonNegOneI8 = pattern_type!(i8 is ..-1 | 0..);
+ | ^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0308, E0600.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/type/pattern_types/or_patterns_invalid.rs b/tests/ui/type/pattern_types/or_patterns_invalid.rs
new file mode 100644
index 0000000000000..d9068f544c6ab
--- /dev/null
+++ b/tests/ui/type/pattern_types/or_patterns_invalid.rs
@@ -0,0 +1,26 @@
+//! Demonstrate some use cases of or patterns
+
+#![feature(
+ pattern_type_macro,
+ pattern_types,
+ rustc_attrs,
+ const_trait_impl,
+ pattern_type_range_trait
+)]
+
+use std::pat::pattern_type;
+
+fn main() {
+ //@error-pattern: only non-overlapping pattern type ranges are allowed at present
+ let not_adjacent: pattern_type!(i8 is -127..0 | 1..) = unsafe { std::mem::transmute(0) };
+
+ //@error-pattern: one pattern needs to end at `i8::MAX`, but was 29 instead
+ let not_wrapping: pattern_type!(i8 is 10..20 | 20..30) = unsafe { std::mem::transmute(0) };
+
+ //@error-pattern: only signed integer base types are allowed for or-pattern pattern types
+ let not_signed: pattern_type!(u8 is 10.. | 0..5) = unsafe { std::mem::transmute(0) };
+
+ //@error-pattern: allowed are two range patterns that are directly connected
+ let not_simple_enough_for_mvp: pattern_type!(i8 is ..0 | 1..10 | 10..) =
+ unsafe { std::mem::transmute(0) };
+}
diff --git a/tests/ui/type/pattern_types/or_patterns_invalid.stderr b/tests/ui/type/pattern_types/or_patterns_invalid.stderr
new file mode 100644
index 0000000000000..6964788a6c245
--- /dev/null
+++ b/tests/ui/type/pattern_types/or_patterns_invalid.stderr
@@ -0,0 +1,10 @@
+error: only non-overlapping pattern type ranges are allowed at present
+
+error: one pattern needs to end at `i8::MAX`, but was 29 instead
+
+error: only signed integer base types are allowed for or-pattern pattern types at present
+
+error: the only or-pattern types allowed are two range patterns that are directly connected at their overflow site
+
+error: aborting due to 4 previous errors
+