Skip to content

Commit

Permalink
Rollup merge of rust-lang#42886 - durka:pplmm-mwe, r=petrochenkov
Browse files Browse the repository at this point in the history
syntax: allow negative integer literal expression to be interpolated as pattern

Fixes rust-lang#42820.

r? @jseyfried
  • Loading branch information
Ariel Ben-Yehuda authored Jun 29, 2017
2 parents 4bae0d8 + 0dfd9c3 commit effd1e0
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 8 deletions.
10 changes: 3 additions & 7 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,13 +684,9 @@ fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) {
// These may occur in patterns
// and can maybe contain float literals
ExprKind::Unary(_, ref f) => fl_lit_check_expr(cx, f),
// These may occur in patterns
// and can't contain float literals
ExprKind::Path(..) => (),
// If something unhandled is encountered, we need to expand the
// search or ignore more ExprKinds.
_ => span_bug!(expr.span, "Unhandled expression {:?} in float lit pattern lint",
expr.node),
// Other kinds of exprs can't occur in patterns so we don't have to check them
// (ast_validation will emit an error if they occur)
_ => (),
}
}

Expand Down
26 changes: 26 additions & 0 deletions src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ impl<'a> AstValidator<'a> {
}
}
}

/// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus)
fn check_expr_within_pat(&self, expr: &Expr) {
match expr.node {
ExprKind::Lit(..) | ExprKind::Path(..) => {}
ExprKind::Unary(UnOp::Neg, ref inner)
if match inner.node { ExprKind::Lit(_) => true, _ => false } => {}
_ => self.err_handler().span_err(expr.span, "arbitrary expressions aren't allowed \
in patterns")
}
}
}

impl<'a> Visitor<'a> for AstValidator<'a> {
Expand Down Expand Up @@ -308,6 +319,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
visit::walk_generics(self, g)
}

fn visit_pat(&mut self, pat: &'a Pat) {
match pat.node {
PatKind::Lit(ref expr) => {
self.check_expr_within_pat(expr);
}
PatKind::Range(ref start, ref end, _) => {
self.check_expr_within_pat(start);
self.check_expr_within_pat(end);
}
_ => {}
}

visit::walk_pat(self, pat)
}
}

pub fn check_crate(session: &Session, krate: &Crate) {
Expand Down
4 changes: 3 additions & 1 deletion src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1659,8 +1659,10 @@ impl<'a> Parser<'a> {
Ok(codemap::Spanned { node: lit, span: lo.to(self.prev_span) })
}

/// matches '-' lit | lit
/// matches '-' lit | lit (cf. ast_validation::AstValidator::check_expr_within_pat)
pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
maybe_whole_expr!(self);

let minus_lo = self.span;
let minus_present = self.eat(&token::BinOp(token::Minus));
let lo = self.span;
Expand Down
36 changes: 36 additions & 0 deletions src/test/compile-fail/patkind-litrange-no-expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

macro_rules! enum_number {
($name:ident { $($variant:ident = $value:expr, )* }) => {
enum $name {
$($variant = $value,)*
}

fn foo(value: i32) -> Option<$name> {
match value {
$( $value => Some($name::$variant), )* // PatKind::Lit
$( $value ... 42 => Some($name::$variant), )* // PatKind::Range
_ => None
}
}
}
}

enum_number!(Change {
Pos = 1,
Neg = -1,
Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns
//~^ ERROR arbitrary expressions aren't allowed in patterns
//~^^ ERROR only char and numeric types are allowed in range patterns
});

fn main() {}

35 changes: 35 additions & 0 deletions src/test/run-pass/macro-pat-neg-lit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

macro_rules! enum_number {
($name:ident { $($variant:ident = $value:expr, )* }) => {
enum $name {
$($variant = $value,)*
}

fn foo(value: i32) -> Option<$name> {
match value {
$( $value => Some($name::$variant), )*
_ => None
}
}
}
}

enum_number!(Change {
Down = -1,
None = 0,
Up = 1,
});

fn main() {
if let Some(Change::Down) = foo(-1) {} else { panic!() }
}

0 comments on commit effd1e0

Please sign in to comment.