Skip to content

Commit effd1e0

Browse files
author
Ariel Ben-Yehuda
authored
Rollup merge of rust-lang#42886 - durka:pplmm-mwe, r=petrochenkov
syntax: allow negative integer literal expression to be interpolated as pattern Fixes rust-lang#42820. r? @jseyfried
2 parents 4bae0d8 + 0dfd9c3 commit effd1e0

File tree

5 files changed

+103
-8
lines changed

5 files changed

+103
-8
lines changed

src/librustc_lint/builtin.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -684,13 +684,9 @@ fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) {
684684
// These may occur in patterns
685685
// and can maybe contain float literals
686686
ExprKind::Unary(_, ref f) => fl_lit_check_expr(cx, f),
687-
// These may occur in patterns
688-
// and can't contain float literals
689-
ExprKind::Path(..) => (),
690-
// If something unhandled is encountered, we need to expand the
691-
// search or ignore more ExprKinds.
692-
_ => span_bug!(expr.span, "Unhandled expression {:?} in float lit pattern lint",
693-
expr.node),
687+
// Other kinds of exprs can't occur in patterns so we don't have to check them
688+
// (ast_validation will emit an error if they occur)
689+
_ => (),
694690
}
695691
}
696692

src/librustc_passes/ast_validation.rs

+26
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ impl<'a> AstValidator<'a> {
9393
}
9494
}
9595
}
96+
97+
/// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus)
98+
fn check_expr_within_pat(&self, expr: &Expr) {
99+
match expr.node {
100+
ExprKind::Lit(..) | ExprKind::Path(..) => {}
101+
ExprKind::Unary(UnOp::Neg, ref inner)
102+
if match inner.node { ExprKind::Lit(_) => true, _ => false } => {}
103+
_ => self.err_handler().span_err(expr.span, "arbitrary expressions aren't allowed \
104+
in patterns")
105+
}
106+
}
96107
}
97108

98109
impl<'a> Visitor<'a> for AstValidator<'a> {
@@ -308,6 +319,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
308319
}
309320
visit::walk_generics(self, g)
310321
}
322+
323+
fn visit_pat(&mut self, pat: &'a Pat) {
324+
match pat.node {
325+
PatKind::Lit(ref expr) => {
326+
self.check_expr_within_pat(expr);
327+
}
328+
PatKind::Range(ref start, ref end, _) => {
329+
self.check_expr_within_pat(start);
330+
self.check_expr_within_pat(end);
331+
}
332+
_ => {}
333+
}
334+
335+
visit::walk_pat(self, pat)
336+
}
311337
}
312338

313339
pub fn check_crate(session: &Session, krate: &Crate) {

src/libsyntax/parse/parser.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1659,8 +1659,10 @@ impl<'a> Parser<'a> {
16591659
Ok(codemap::Spanned { node: lit, span: lo.to(self.prev_span) })
16601660
}
16611661

1662-
/// matches '-' lit | lit
1662+
/// matches '-' lit | lit (cf. ast_validation::AstValidator::check_expr_within_pat)
16631663
pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
1664+
maybe_whole_expr!(self);
1665+
16641666
let minus_lo = self.span;
16651667
let minus_present = self.eat(&token::BinOp(token::Minus));
16661668
let lo = self.span;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
macro_rules! enum_number {
12+
($name:ident { $($variant:ident = $value:expr, )* }) => {
13+
enum $name {
14+
$($variant = $value,)*
15+
}
16+
17+
fn foo(value: i32) -> Option<$name> {
18+
match value {
19+
$( $value => Some($name::$variant), )* // PatKind::Lit
20+
$( $value ... 42 => Some($name::$variant), )* // PatKind::Range
21+
_ => None
22+
}
23+
}
24+
}
25+
}
26+
27+
enum_number!(Change {
28+
Pos = 1,
29+
Neg = -1,
30+
Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns
31+
//~^ ERROR arbitrary expressions aren't allowed in patterns
32+
//~^^ ERROR only char and numeric types are allowed in range patterns
33+
});
34+
35+
fn main() {}
36+
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
macro_rules! enum_number {
12+
($name:ident { $($variant:ident = $value:expr, )* }) => {
13+
enum $name {
14+
$($variant = $value,)*
15+
}
16+
17+
fn foo(value: i32) -> Option<$name> {
18+
match value {
19+
$( $value => Some($name::$variant), )*
20+
_ => None
21+
}
22+
}
23+
}
24+
}
25+
26+
enum_number!(Change {
27+
Down = -1,
28+
None = 0,
29+
Up = 1,
30+
});
31+
32+
fn main() {
33+
if let Some(Change::Down) = foo(-1) {} else { panic!() }
34+
}
35+

0 commit comments

Comments
 (0)