Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f1070f2

Browse files
committedMar 11, 2025
Start using pattern types in libcore
1 parent 8b5b516 commit f1070f2

18 files changed

+247
-82
lines changed
 

‎compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,18 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) ->
455455
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id),
456456
},
457457
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
458-
_ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t),
458+
ty::Pat(base, _) => return type_di_node(cx, base),
459+
// FIXME(unsafe_binders): impl debug info
460+
ty::UnsafeBinder(_) => unimplemented!(),
461+
ty::Alias(..)
462+
| ty::Param(_)
463+
| ty::Bound(..)
464+
| ty::Infer(_)
465+
| ty::Placeholder(_)
466+
| ty::CoroutineWitness(..)
467+
| ty::Error(_) => {
468+
bug!("debuginfo: unexpected type in type_di_node(): {:?}", t)
469+
}
459470
};
460471

461472
{

‎library/core/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@
183183
#![feature(no_core)]
184184
#![feature(no_sanitize)]
185185
#![feature(optimize_attribute)]
186+
#![feature(pattern_type_macro)]
187+
#![feature(pattern_types)]
186188
#![feature(prelude_import)]
187189
#![feature(repr_simd)]
188190
#![feature(rustc_allow_const_fn_unstable)]

‎library/core/src/num/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ mod wrapping;
5353

5454
/// 100% perma-unstable
5555
#[doc(hidden)]
56+
#[cfg_attr(bootstrap, path = "niche_types_bootstrap.rs")]
5657
pub mod niche_types;
5758

5859
#[stable(feature = "rust1", since = "1.0.0")]

‎library/core/src/num/niche_types.rs

+39-64
Original file line numberDiff line numberDiff line change
@@ -5,60 +5,48 @@
55
)]
66

77
use crate::cmp::Ordering;
8-
use crate::fmt;
98
use crate::hash::{Hash, Hasher};
109
use crate::marker::StructuralPartialEq;
10+
use crate::{fmt, pattern_type};
1111

1212
macro_rules! define_valid_range_type {
1313
($(
1414
$(#[$m:meta])*
15-
$vis:vis struct $name:ident($int:ident as $uint:ident in $low:literal..=$high:literal);
15+
$vis:vis struct $name:ident($int:ident is $pat:pat);
1616
)+) => {$(
17-
#[derive(Clone, Copy, Eq)]
17+
#[derive(Clone, Copy)]
1818
#[repr(transparent)]
19-
#[rustc_layout_scalar_valid_range_start($low)]
20-
#[rustc_layout_scalar_valid_range_end($high)]
2119
$(#[$m])*
22-
$vis struct $name($int);
23-
24-
const _: () = {
25-
// With the `valid_range` attributes, it's always specified as unsigned
26-
assert!(<$uint>::MIN == 0);
27-
let ulow: $uint = $low;
28-
let uhigh: $uint = $high;
29-
assert!(ulow <= uhigh);
30-
31-
assert!(size_of::<$int>() == size_of::<$uint>());
32-
};
33-
20+
$vis struct $name(pattern_type!($int is $pat));
3421
impl $name {
3522
#[inline]
3623
pub const fn new(val: $int) -> Option<Self> {
37-
if (val as $uint) >= ($low as $uint) && (val as $uint) <= ($high as $uint) {
24+
#[allow(non_contiguous_range_endpoints)]
25+
if let $pat = val {
3826
// SAFETY: just checked the inclusive range
39-
Some(unsafe { $name(val) })
27+
Some(unsafe { $name(crate::mem::transmute(val)) })
4028
} else {
4129
None
4230
}
4331
}
4432

4533
/// Constructs an instance of this type from the underlying integer
46-
/// primitive without checking whether its zero.
34+
/// primitive without checking whether its valid.
4735
///
4836
/// # Safety
49-
/// Immediate language UB if `val == 0`, as it violates the validity
37+
/// Immediate language UB if `val` is not in the range of the pattern type,
38+
/// as it violates the validity
5039
/// invariant of this type.
5140
#[inline]
5241
pub const unsafe fn new_unchecked(val: $int) -> Self {
53-
// SAFETY: Caller promised that `val` is non-zero.
54-
unsafe { $name(val) }
42+
// SAFETY: Caller promised that `val` is in the valid range.
43+
unsafe { $name(crate::mem::transmute(val)) }
5544
}
5645

5746
#[inline]
5847
pub const fn as_inner(self) -> $int {
59-
// SAFETY: This is a transparent wrapper, so unwrapping it is sound
60-
// (Not using `.0` due to MCP#807.)
61-
unsafe { crate::mem::transmute(self) }
48+
// SAFETY: pattern types are always legal values of their base type
49+
unsafe { crate::mem::transmute(self.0) }
6250
}
6351
}
6452

@@ -67,6 +55,8 @@ macro_rules! define_valid_range_type {
6755
// by <https://github.com/rust-lang/compiler-team/issues/807>.
6856
impl StructuralPartialEq for $name {}
6957

58+
impl Eq for $name {}
59+
7060
impl PartialEq for $name {
7161
#[inline]
7262
fn eq(&self, other: &Self) -> bool {
@@ -104,7 +94,7 @@ macro_rules! define_valid_range_type {
10494
}
10595

10696
define_valid_range_type! {
107-
pub struct Nanoseconds(u32 as u32 in 0..=999_999_999);
97+
pub struct Nanoseconds(u32 is 0..=999_999_999);
10898
}
10999

110100
impl Nanoseconds {
@@ -119,45 +109,30 @@ impl Default for Nanoseconds {
119109
}
120110
}
121111

122-
define_valid_range_type! {
123-
pub struct NonZeroU8Inner(u8 as u8 in 1..=0xff);
124-
pub struct NonZeroU16Inner(u16 as u16 in 1..=0xff_ff);
125-
pub struct NonZeroU32Inner(u32 as u32 in 1..=0xffff_ffff);
126-
pub struct NonZeroU64Inner(u64 as u64 in 1..=0xffffffff_ffffffff);
127-
pub struct NonZeroU128Inner(u128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff);
128-
129-
pub struct NonZeroI8Inner(i8 as u8 in 1..=0xff);
130-
pub struct NonZeroI16Inner(i16 as u16 in 1..=0xff_ff);
131-
pub struct NonZeroI32Inner(i32 as u32 in 1..=0xffff_ffff);
132-
pub struct NonZeroI64Inner(i64 as u64 in 1..=0xffffffff_ffffffff);
133-
pub struct NonZeroI128Inner(i128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff);
134-
}
135-
136-
#[cfg(target_pointer_width = "16")]
137-
define_valid_range_type! {
138-
pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff);
139-
pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff);
140-
pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff);
141-
}
142-
#[cfg(target_pointer_width = "32")]
143-
define_valid_range_type! {
144-
pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff);
145-
pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff);
146-
pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff);
147-
}
148-
#[cfg(target_pointer_width = "64")]
149-
define_valid_range_type! {
150-
pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff_ffff_ffff);
151-
pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff_ffff_ffff);
152-
pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff_ffff_ffff);
153-
}
112+
const HALF_USIZE: usize = usize::MAX >> 1;
154113

155114
define_valid_range_type! {
156-
pub struct U32NotAllOnes(u32 as u32 in 0..=0xffff_fffe);
157-
pub struct I32NotAllOnes(i32 as u32 in 0..=0xffff_fffe);
158-
159-
pub struct U64NotAllOnes(u64 as u64 in 0..=0xffff_ffff_ffff_fffe);
160-
pub struct I64NotAllOnes(i64 as u64 in 0..=0xffff_ffff_ffff_fffe);
115+
pub struct NonZeroU8Inner(u8 is 1..);
116+
pub struct NonZeroU16Inner(u16 is 1..);
117+
pub struct NonZeroU32Inner(u32 is 1..);
118+
pub struct NonZeroU64Inner(u64 is 1..);
119+
pub struct NonZeroU128Inner(u128 is 1..);
120+
121+
pub struct NonZeroI8Inner(i8 is ..0 | 1..);
122+
pub struct NonZeroI16Inner(i16 is ..0 | 1..);
123+
pub struct NonZeroI32Inner(i32 is ..0 | 1..);
124+
pub struct NonZeroI64Inner(i64 is ..0 | 1..);
125+
pub struct NonZeroI128Inner(i128 is ..0 | 1..);
126+
127+
pub struct UsizeNoHighBit(usize is 0..=HALF_USIZE);
128+
pub struct NonZeroUsizeInner(usize is 1..);
129+
pub struct NonZeroIsizeInner(isize is ..0 | 1..);
130+
131+
pub struct U32NotAllOnes(u32 is 0..u32::MAX);
132+
pub struct I32NotAllOnes(i32 is ..-1 | 0..);
133+
134+
pub struct U64NotAllOnes(u64 is 0..u64::MAX);
135+
pub struct I64NotAllOnes(i64 is ..-1 | 0..);
161136
}
162137

163138
pub trait NotAllOnesHelper {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
#![unstable(
2+
feature = "temporary_niche_types",
3+
issue = "none",
4+
reason = "for core, alloc, and std internals until pattern types are further along"
5+
)]
6+
7+
use crate::cmp::Ordering;
8+
use crate::fmt;
9+
use crate::hash::{Hash, Hasher};
10+
use crate::marker::StructuralPartialEq;
11+
12+
macro_rules! define_valid_range_type {
13+
($(
14+
$(#[$m:meta])*
15+
$vis:vis struct $name:ident($int:ident as $uint:ident in $low:literal..=$high:literal);
16+
)+) => {$(
17+
#[derive(Clone, Copy, Eq)]
18+
#[repr(transparent)]
19+
#[rustc_layout_scalar_valid_range_start($low)]
20+
#[rustc_layout_scalar_valid_range_end($high)]
21+
$(#[$m])*
22+
$vis struct $name($int);
23+
24+
const _: () = {
25+
// With the `valid_range` attributes, it's always specified as unsigned
26+
assert!(<$uint>::MIN == 0);
27+
let ulow: $uint = $low;
28+
let uhigh: $uint = $high;
29+
assert!(ulow <= uhigh);
30+
31+
assert!(size_of::<$int>() == size_of::<$uint>());
32+
};
33+
34+
impl $name {
35+
#[inline]
36+
pub const fn new(val: $int) -> Option<Self> {
37+
if (val as $uint) >= ($low as $uint) && (val as $uint) <= ($high as $uint) {
38+
// SAFETY: just checked the inclusive range
39+
Some(unsafe { $name(val) })
40+
} else {
41+
None
42+
}
43+
}
44+
45+
/// Constructs an instance of this type from the underlying integer
46+
/// primitive without checking whether its zero.
47+
///
48+
/// # Safety
49+
/// Immediate language UB if `val == 0`, as it violates the validity
50+
/// invariant of this type.
51+
#[inline]
52+
pub const unsafe fn new_unchecked(val: $int) -> Self {
53+
// SAFETY: Caller promised that `val` is non-zero.
54+
unsafe { $name(val) }
55+
}
56+
57+
#[inline]
58+
pub const fn as_inner(self) -> $int {
59+
// SAFETY: This is a transparent wrapper, so unwrapping it is sound
60+
// (Not using `.0` due to MCP#807.)
61+
unsafe { crate::mem::transmute(self) }
62+
}
63+
}
64+
65+
// This is required to allow matching a constant. We don't get it from a derive
66+
// because the derived `PartialEq` would do a field projection, which is banned
67+
// by <https://github.com/rust-lang/compiler-team/issues/807>.
68+
impl StructuralPartialEq for $name {}
69+
70+
impl PartialEq for $name {
71+
#[inline]
72+
fn eq(&self, other: &Self) -> bool {
73+
self.as_inner() == other.as_inner()
74+
}
75+
}
76+
77+
impl Ord for $name {
78+
#[inline]
79+
fn cmp(&self, other: &Self) -> Ordering {
80+
Ord::cmp(&self.as_inner(), &other.as_inner())
81+
}
82+
}
83+
84+
impl PartialOrd for $name {
85+
#[inline]
86+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
87+
Some(Ord::cmp(self, other))
88+
}
89+
}
90+
91+
impl Hash for $name {
92+
// Required method
93+
fn hash<H: Hasher>(&self, state: &mut H) {
94+
Hash::hash(&self.as_inner(), state);
95+
}
96+
}
97+
98+
impl fmt::Debug for $name {
99+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100+
<$int as fmt::Debug>::fmt(&self.as_inner(), f)
101+
}
102+
}
103+
)+};
104+
}
105+
106+
define_valid_range_type! {
107+
pub struct Nanoseconds(u32 as u32 in 0..=999_999_999);
108+
}
109+
110+
impl Nanoseconds {
111+
// SAFETY: 0 is within the valid range
112+
pub const ZERO: Self = unsafe { Nanoseconds::new_unchecked(0) };
113+
}
114+
115+
impl Default for Nanoseconds {
116+
#[inline]
117+
fn default() -> Self {
118+
Self::ZERO
119+
}
120+
}
121+
122+
define_valid_range_type! {
123+
pub struct NonZeroU8Inner(u8 as u8 in 1..=0xff);
124+
pub struct NonZeroU16Inner(u16 as u16 in 1..=0xff_ff);
125+
pub struct NonZeroU32Inner(u32 as u32 in 1..=0xffff_ffff);
126+
pub struct NonZeroU64Inner(u64 as u64 in 1..=0xffffffff_ffffffff);
127+
pub struct NonZeroU128Inner(u128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff);
128+
129+
pub struct NonZeroI8Inner(i8 as u8 in 1..=0xff);
130+
pub struct NonZeroI16Inner(i16 as u16 in 1..=0xff_ff);
131+
pub struct NonZeroI32Inner(i32 as u32 in 1..=0xffff_ffff);
132+
pub struct NonZeroI64Inner(i64 as u64 in 1..=0xffffffff_ffffffff);
133+
pub struct NonZeroI128Inner(i128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff);
134+
}
135+
136+
#[cfg(target_pointer_width = "16")]
137+
define_valid_range_type! {
138+
pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff);
139+
pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff);
140+
pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff);
141+
}
142+
#[cfg(target_pointer_width = "32")]
143+
define_valid_range_type! {
144+
pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff);
145+
pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff);
146+
pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff);
147+
}
148+
#[cfg(target_pointer_width = "64")]
149+
define_valid_range_type! {
150+
pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff_ffff_ffff);
151+
pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff_ffff_ffff);
152+
pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff_ffff_ffff);
153+
}
154+
155+
define_valid_range_type! {
156+
pub struct U32NotAllOnes(u32 as u32 in 0..=0xffff_fffe);
157+
pub struct I32NotAllOnes(i32 as u32 in 0..=0xffff_fffe);
158+
159+
pub struct U64NotAllOnes(u64 as u64 in 0..=0xffff_ffff_ffff_fffe);
160+
pub struct I64NotAllOnes(i64 as u64 in 0..=0xffff_ffff_ffff_fffe);
161+
}
162+
163+
pub trait NotAllOnesHelper {
164+
type Type;
165+
}
166+
pub type NotAllOnes<T> = <T as NotAllOnesHelper>::Type;
167+
impl NotAllOnesHelper for u32 {
168+
type Type = U32NotAllOnes;
169+
}
170+
impl NotAllOnesHelper for i32 {
171+
type Type = I32NotAllOnes;
172+
}
173+
impl NotAllOnesHelper for u64 {
174+
type Type = U64NotAllOnes;
175+
}
176+
impl NotAllOnesHelper for i64 {
177+
type Type = I64NotAllOnes;
178+
}

‎tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
StorageLive(_4);
4646
StorageLive(_5);
4747
StorageLive(_6);
48-
_6 = const NonZero::<usize>(core::num::niche_types::NonZeroUsizeInner(1_usize));
48+
_6 = const NonZero::<usize>(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
4949
StorageLive(_7);
5050
_7 = const {0x1 as *const [bool; 0]};
5151
_5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};

‎tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
StorageLive(_4);
4646
StorageLive(_5);
4747
StorageLive(_6);
48-
_6 = const NonZero::<usize>(core::num::niche_types::NonZeroUsizeInner(1_usize));
48+
_6 = const NonZero::<usize>(core::num::niche_types::NonZeroUsizeInner(1_usize is 1..));
4949
StorageLive(_7);
5050
_7 = const {0x1 as *const [bool; 0]};
5151
_5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.