Skip to content

Commit dbf9e89

Browse files
committed
Add not-null pointer patterns to pattern types
1 parent 0d11be5 commit dbf9e89

File tree

29 files changed

+290
-23
lines changed

29 files changed

+290
-23
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2571,6 +2571,9 @@ pub enum TyPatKind {
25712571
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
25722572
Range(Option<P<AnonConst>>, Option<P<AnonConst>>, Spanned<RangeEnd>),
25732573

2574+
/// A `!null` pattern for raw pointers.
2575+
NotNull,
2576+
25742577
Or(ThinVec<P<TyPat>>),
25752578

25762579
/// Placeholder for a pattern that wasn't syntactically well formed in some way.

compiler/rustc_ast/src/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,7 @@ macro_rules! common_visitor_and_walkers {
12081208
try_visit!(visit_span(vis, span));
12091209
}
12101210
TyPatKind::Or(variants) => walk_list!(vis, visit_ty_pat, variants),
1211-
TyPatKind::Err(_) => {}
1211+
TyPatKind::NotNull | TyPatKind::Err(_) => {}
12121212
}
12131213
visit_span(vis, span)
12141214
}

compiler/rustc_ast_lowering/src/pat.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
143143
}
144144
// return inner to be processed in next loop
145145
PatKind::Paren(inner) => pattern = inner,
146-
PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
146+
PatKind::MacCall(_) => {
147+
panic!("{pattern:#?} shouldn't exist here")
148+
}
147149
PatKind::Err(guar) => break hir::PatKind::Err(*guar),
148150
}
149151
};
@@ -460,6 +462,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
460462
)
461463
}),
462464
),
465+
TyPatKind::NotNull => hir::TyPatKind::NotNull,
463466
TyPatKind::Or(variants) => {
464467
hir::TyPatKind::Or(self.arena.alloc_from_iter(
465468
variants.iter().map(|pat| self.lower_ty_pat_mut(pat, base_type)),

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,7 @@ impl<'a> State<'a> {
12261226
self.print_expr_anon_const(end, &[]);
12271227
}
12281228
}
1229+
rustc_ast::TyPatKind::NotNull => self.word("!null"),
12291230
rustc_ast::TyPatKind::Or(variants) => {
12301231
let mut first = true;
12311232
for pat in variants {

compiler/rustc_builtin_macros/src/pattern_type.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,21 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P
2828
let ty = parser.parse_ty()?;
2929
parser.expect_keyword(exp!(Is))?;
3030

31-
let pat = pat_to_ty_pat(
32-
cx,
33-
*parser.parse_pat_no_top_guard(
34-
None,
35-
RecoverComma::No,
36-
RecoverColon::No,
37-
CommaRecoveryMode::EitherTupleOrPipe,
38-
)?,
39-
);
31+
let start = parser.token.span;
32+
let pat = if parser.eat(exp!(Bang)) {
33+
parser.expect_keyword(exp!(Null))?;
34+
ty_pat(TyPatKind::NotNull, start.to(parser.token.span))
35+
} else {
36+
pat_to_ty_pat(
37+
cx,
38+
*parser.parse_pat_no_top_guard(
39+
None,
40+
RecoverComma::No,
41+
RecoverColon::No,
42+
CommaRecoveryMode::EitherTupleOrPipe,
43+
)?,
44+
)
45+
};
4046

4147
if parser.token != token::Eof {
4248
parser.unexpected()?;

compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1249,9 +1249,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
12491249
// When you extend this match, make sure to also add tests to
12501250
// tests/ui/type/pattern_types/validity.rs((
12511251
match **pat {
1252-
// Range patterns are precisely reflected into `valid_range` and thus
1252+
// Range and non-null patterns are precisely reflected into `valid_range` and thus
12531253
// handled fully by `visit_scalar` (called below).
12541254
ty::PatternKind::Range { .. } => {},
1255+
ty::PatternKind::NotNull => {},
12551256

12561257
// FIXME(pattern_types): check that the value is covered by one of the variants.
12571258
// For now, we rely on layout computation setting the scalar's `valid_range` to

compiler/rustc_hir/src/hir.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,6 +1823,9 @@ pub enum TyPatKind<'hir> {
18231823
/// A range pattern (e.g., `1..=2` or `1..2`).
18241824
Range(&'hir ConstArg<'hir>, &'hir ConstArg<'hir>),
18251825

1826+
/// A pattern that excludes null pointers
1827+
NotNull,
1828+
18261829
/// A list of patterns where only one needs to be satisfied
18271830
Or(&'hir [TyPat<'hir>]),
18281831

compiler/rustc_hir/src/intravisit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>)
726726
try_visit!(visitor.visit_const_arg_unambig(upper_bound));
727727
}
728728
TyPatKind::Or(patterns) => walk_list!(visitor, visit_pattern_type_pattern, patterns),
729-
TyPatKind::Err(_) => (),
729+
TyPatKind::NotNull | TyPatKind::Err(_) => (),
730730
}
731731
V::Result::output()
732732
}

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2579,6 +2579,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
25792579
.span_delayed_bug(ty_span, "invalid base type for range pattern")),
25802580
}
25812581
}
2582+
hir::TyPatKind::NotNull => Ok(ty::PatternKind::NotNull),
25822583
hir::TyPatKind::Or(patterns) => {
25832584
self.tcx()
25842585
.mk_patterns_from_iter(patterns.iter().map(|pat| {

compiler/rustc_hir_analysis/src/variance/constraints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
340340
self.add_constraints_from_const(current, start, variance);
341341
self.add_constraints_from_const(current, end, variance);
342342
}
343+
ty::PatternKind::NotNull => {}
343344
ty::PatternKind::Or(patterns) => {
344345
for pat in patterns {
345346
self.add_constraints_from_pat(current, variance, pat)

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,6 +1874,10 @@ impl<'a> State<'a> {
18741874
self.word("..=");
18751875
self.print_const_arg(end);
18761876
}
1877+
TyPatKind::NotNull => {
1878+
self.word_space("not");
1879+
self.word("null");
1880+
}
18771881
TyPatKind::Or(patterns) => {
18781882
self.popen();
18791883
let mut first = true;

compiler/rustc_lint/src/types.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,7 @@ fn pat_ty_is_known_nonnull<'tcx>(
905905
// to ensure we aren't wrapping over zero.
906906
start > 0 && end >= start
907907
}
908+
ty::PatternKind::NotNull => true,
908909
ty::PatternKind::Or(patterns) => {
909910
patterns.iter().all(|pat| pat_ty_is_known_nonnull(tcx, typing_env, pat))
910911
}
@@ -1066,7 +1067,9 @@ fn get_nullable_type_from_pat<'tcx>(
10661067
pat: ty::Pattern<'tcx>,
10671068
) -> Option<Ty<'tcx>> {
10681069
match *pat {
1069-
ty::PatternKind::Range { .. } => get_nullable_type(tcx, typing_env, base),
1070+
ty::PatternKind::NotNull | ty::PatternKind::Range { .. } => {
1071+
get_nullable_type(tcx, typing_env, base)
1072+
}
10701073
ty::PatternKind::Or(patterns) => {
10711074
let first = get_nullable_type_from_pat(tcx, typing_env, base, patterns[0])?;
10721075
for &pat in &patterns[1..] {

compiler/rustc_middle/src/ty/pattern.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ impl<'tcx> Flags for Pattern<'tcx> {
3030
}
3131
flags
3232
}
33+
ty::PatternKind::NotNull => rustc_type_ir::TypeFlags::empty(),
3334
}
3435
}
3536

@@ -45,6 +46,7 @@ impl<'tcx> Flags for Pattern<'tcx> {
4546
}
4647
idx
4748
}
49+
ty::PatternKind::NotNull => rustc_type_ir::INNERMOST,
4850
}
4951
}
5052
}
@@ -91,6 +93,7 @@ impl<'tcx> IrPrint<PatternKind<'tcx>> for TyCtxt<'tcx> {
9193

9294
write!(f, "..={end}")
9395
}
96+
PatternKind::NotNull => write!(f, "!null"),
9497
PatternKind::Or(patterns) => {
9598
write!(f, "(")?;
9699
let mut first = true;

compiler/rustc_middle/src/ty/relate.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'tcx> {
5959
let end = relation.relate(end_a, end_b)?;
6060
Ok(tcx.mk_pat(ty::PatternKind::Range { start, end }))
6161
}
62+
(ty::PatternKind::NotNull, ty::PatternKind::NotNull) => Ok(a),
6263
(&ty::PatternKind::Or(a), &ty::PatternKind::Or(b)) => {
6364
if a.len() != b.len() {
6465
return Err(TypeError::Mismatch);
@@ -67,7 +68,10 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'tcx> {
6768
let patterns = tcx.mk_patterns_from_iter(v)?;
6869
Ok(tcx.mk_pat(ty::PatternKind::Or(patterns)))
6970
}
70-
(ty::PatternKind::Range { .. } | ty::PatternKind::Or(_), _) => Err(TypeError::Mismatch),
71+
(
72+
ty::PatternKind::NotNull | ty::PatternKind::Range { .. } | ty::PatternKind::Or(_),
73+
_,
74+
) => Err(TypeError::Mismatch),
7175
}
7276
}
7377
}

compiler/rustc_parse/src/parser/token_type.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ pub enum TokenType {
139139
SymNomem,
140140
SymNoreturn,
141141
SymNostack,
142+
SymNull,
142143
SymOptions,
143144
SymOut,
144145
SymPreservesFlags,
@@ -273,6 +274,7 @@ impl TokenType {
273274
SymNomem,
274275
SymNoreturn,
275276
SymNostack,
277+
SymNull,
276278
SymOptions,
277279
SymOut,
278280
SymPreservesFlags,
@@ -348,6 +350,7 @@ impl TokenType {
348350
TokenType::SymNomem => Some(sym::nomem),
349351
TokenType::SymNoreturn => Some(sym::noreturn),
350352
TokenType::SymNostack => Some(sym::nostack),
353+
TokenType::SymNull => Some(sym::null),
351354
TokenType::SymOptions => Some(sym::options),
352355
TokenType::SymOut => Some(sym::out),
353356
TokenType::SymPreservesFlags => Some(sym::preserves_flags),
@@ -562,6 +565,7 @@ macro_rules! exp {
562565
(Nomem) => { exp!(@sym, nomem, SymNomem) };
563566
(Noreturn) => { exp!(@sym, noreturn, SymNoreturn) };
564567
(Nostack) => { exp!(@sym, nostack, SymNostack) };
568+
(Null) => { exp!(@sym, null, SymNull) };
565569
(Options) => { exp!(@sym, options, SymOptions) };
566570
(Out) => { exp!(@sym, out, SymOut) };
567571
(PreservesFlags) => { exp!(@sym, preserves_flags, SymPreservesFlags) };

compiler/rustc_resolve/src/late.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc
976976
self.visit_ty_pat(pat)
977977
}
978978
}
979-
TyPatKind::Err(_) => {}
979+
TyPatKind::NotNull | TyPatKind::Err(_) => {}
980980
}
981981
}
982982

compiler/rustc_smir/src/stable_mir/unstable/convert/stable/ty.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
502502
end: Some(end.stable(tables, cx)),
503503
include_end: true,
504504
},
505+
ty::PatternKind::NotNull => todo!(),
505506
ty::PatternKind::Or(_) => todo!(),
506507
}
507508
}

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,7 @@ symbols! {
15091509
not,
15101510
notable_trait,
15111511
note,
1512+
null,
15121513
object_safe_for_dispatch,
15131514
of,
15141515
off,

compiler/rustc_symbol_mangling/src/v0.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ impl<'tcx> SymbolMangler<'tcx> {
263263
Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?;
264264
}
265265
}
266+
ty::PatternKind::NotNull => {
267+
self.tcx.types.unit.print(self)?;
268+
}
266269
ty::PatternKind::Or(patterns) => {
267270
for pat in patterns {
268271
self.print_pat(pat)?;

compiler/rustc_trait_selection/src/traits/wf.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
704704
check(start);
705705
check(end);
706706
}
707+
ty::PatternKind::NotNull => {}
707708
ty::PatternKind::Or(patterns) => {
708709
for pat in patterns {
709710
self.add_wf_preds_for_pat_ty(base_ty, pat)

compiler/rustc_ty_utils/src/layout.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,7 @@ fn layout_of_uncached<'tcx>(
213213
let mut layout = LayoutData::clone(&layout.0);
214214
match *pat {
215215
ty::PatternKind::Range { start, end } => {
216-
if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
217-
&mut layout.backend_repr
218-
{
216+
if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
219217
scalar.valid_range_mut().start = extract_const_value(cx, ty, start)?
220218
.try_to_bits(tcx, cx.typing_env)
221219
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
@@ -263,6 +261,25 @@ fn layout_of_uncached<'tcx>(
263261
bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}")
264262
}
265263
}
264+
ty::PatternKind::NotNull => {
265+
if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
266+
&mut layout.backend_repr
267+
{
268+
scalar.valid_range_mut().start = 1;
269+
let niche = Niche {
270+
offset: Size::ZERO,
271+
value: scalar.primitive(),
272+
valid_range: scalar.valid_range(cx),
273+
};
274+
275+
layout.largest_niche = Some(niche);
276+
} else {
277+
bug!(
278+
"pattern type with `!null` pattern but not scalar/pair layout: {ty:?}, {layout:?}"
279+
)
280+
}
281+
}
282+
266283
ty::PatternKind::Or(variants) => match *variants[0] {
267284
ty::PatternKind::Range { .. } => {
268285
if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
@@ -279,7 +296,7 @@ fn layout_of_uncached<'tcx>(
279296
.try_to_bits(tcx, cx.typing_env)
280297
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
281298
)),
282-
ty::PatternKind::Or(_) => {
299+
ty::PatternKind::NotNull | ty::PatternKind::Or(_) => {
283300
unreachable!("mixed or patterns are not allowed")
284301
}
285302
})
@@ -344,6 +361,7 @@ fn layout_of_uncached<'tcx>(
344361
)
345362
}
346363
}
364+
ty::PatternKind::NotNull => bug!("or patterns can't contain `!null` patterns"),
347365
ty::PatternKind::Or(..) => bug!("patterns cannot have nested or patterns"),
348366
},
349367
}

compiler/rustc_type_ir/src/pattern.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ use crate::Interner;
1414
pub enum PatternKind<I: Interner> {
1515
Range { start: I::Const, end: I::Const },
1616
Or(I::PatList),
17+
NotNull,
1718
}

compiler/rustc_type_ir/src/walk.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,5 +178,6 @@ fn push_ty_pat<I: Interner>(stack: &mut TypeWalkerStack<I>, pat: I::Pat) {
178178
push_ty_pat::<I>(stack, pat)
179179
}
180180
}
181+
ty::PatternKind::NotNull => {}
181182
}
182183
}

src/tools/clippy/clippy_utils/src/hir_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1122,7 +1122,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
11221122
self.hash_ty_pat(variant);
11231123
}
11241124
},
1125-
TyPatKind::Err(_) => {},
1125+
TyPatKind::NotNull | TyPatKind::Err(_) => {},
11261126
}
11271127
}
11281128

src/tools/rustfmt/src/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,7 @@ impl Rewrite for ast::TyPat {
11001100
}
11011101
Ok(s)
11021102
}
1103-
ast::TyPatKind::Err(_) => Err(RewriteError::Unknown),
1103+
ast::TyPatKind::NotNull | ast::TyPatKind::Err(_) => Err(RewriteError::Unknown),
11041104
}
11051105
}
11061106
}

tests/ui/type/pattern_types/bad_pat.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,15 @@ type Positive2 = pattern_type!(i32 is 0..=);
1010
type Wild = pattern_type!(() is _);
1111
//~^ ERROR: pattern not supported in pattern types
1212

13+
// FIXME: confusing diagnostic because `not` can be a binding
14+
type NonNull = pattern_type!(*const () is not null);
15+
//~^ ERROR: expected one of `@` or `|`, found `null`
16+
//~| ERROR: pattern not supported in pattern types
17+
18+
type NonNull2 = pattern_type!(*const () is !nil);
19+
//~^ ERROR: expected `null`, found `nil`
20+
21+
// FIXME: reject with a type mismatch
22+
type Mismatch2 = pattern_type!(() is !null);
23+
1324
fn main() {}

tests/ui/type/pattern_types/bad_pat.stderr

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,24 @@ error: pattern not supported in pattern types
3030
LL | type Wild = pattern_type!(() is _);
3131
| ^
3232

33-
error: aborting due to 3 previous errors
33+
error: pattern not supported in pattern types
34+
--> $DIR/bad_pat.rs:14:43
35+
|
36+
LL | type NonNull = pattern_type!(*const () is not null);
37+
| ^^^
38+
39+
error: expected one of `@` or `|`, found `null`
40+
--> $DIR/bad_pat.rs:14:47
41+
|
42+
LL | type NonNull = pattern_type!(*const () is not null);
43+
| ^^^^ expected one of `@` or `|`
44+
45+
error: expected `null`, found `nil`
46+
--> $DIR/bad_pat.rs:18:45
47+
|
48+
LL | type NonNull2 = pattern_type!(*const () is !nil);
49+
| ^^^ expected `null`
50+
51+
error: aborting due to 6 previous errors
3452

3553
For more information about this error, try `rustc --explain E0586`.

0 commit comments

Comments
 (0)