diff options
| author | bors <bors@rust-lang.org> | 2018-09-10 04:05:14 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-09-10 04:05:14 +0000 |
| commit | fb945f0ebba1a6d5d0f9d0b62dedacd6c828fff7 (patch) | |
| tree | 81cfcda6ccea74cbe92e912e37bf1a569301d14a | |
| parent | fdcd4a4a45357f11343d5abe9501a35793a6fd57 (diff) | |
| parent | 0a8cf67e61c884f63f471d3ab7094e383a0d97b3 (diff) | |
| download | rust-fb945f0ebba1a6d5d0f9d0b62dedacd6c828fff7.tar.gz rust-fb945f0ebba1a6d5d0f9d0b62dedacd6c828fff7.zip | |
Auto merge of #53854 - davidtwco:issue-53668, r=nikomatsakis
if- and while-let-chains, take 2 - edition changes Part of #53668. r? @nikomatsakis
5 files changed, 261 insertions, 0 deletions
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index bca119660aa..52d61792ed2 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -22,6 +22,7 @@ use syntax::ast::*; use syntax::attr; use syntax::source_map::Spanned; use syntax::symbol::keywords; +use syntax::ptr::P; use syntax::visit::{self, Visitor}; use syntax_pos::Span; use errors; @@ -167,11 +168,61 @@ impl<'a> AstValidator<'a> { "only lifetime parameters can be used in this context"); } } + + /// With eRFC 2497, we need to check whether an expression is ambigious and warn or error + /// depending on the edition, this function handles that. + fn while_if_let_ambiguity(&self, expr: &P<Expr>) { + if let Some((span, op_kind)) = self.while_if_let_expr_ambiguity(&expr) { + let mut err = self.err_handler().struct_span_err( + span, &format!("ambigious use of `{}`", op_kind.to_string()) + ); + + err.note( + "this will be a error until the `let_chains` feature is stabilized" + ); + err.note( + "see rust-lang/rust#53668 for more information" + ); + + if let Ok(snippet) = self.session.source_map().span_to_snippet(span) { + err.span_suggestion( + span, "consider adding parentheses", format!("({})", snippet), + ); + } + + err.emit(); + } + } + + /// With eRFC 2497 adding if-let chains, there is a requirement that the parsing of + /// `&&` and `||` in a if-let statement be unambigious. This function returns a span and + /// a `BinOpKind` (either `&&` or `||` depending on what was ambigious) if it is determined + /// that the current expression parsed is ambigious and will break in future. + fn while_if_let_expr_ambiguity(&self, expr: &P<Expr>) -> Option<(Span, BinOpKind)> { + debug!("while_if_let_expr_ambiguity: expr.node: {:?}", expr.node); + match &expr.node { + ExprKind::Binary(op, _, _) if op.node == BinOpKind::And || op.node == BinOpKind::Or => { + Some((expr.span, op.node)) + }, + ExprKind::Range(ref lhs, ref rhs, _) => { + let lhs_ambigious = lhs.as_ref() + .and_then(|lhs| self.while_if_let_expr_ambiguity(lhs)); + let rhs_ambigious = rhs.as_ref() + .and_then(|rhs| self.while_if_let_expr_ambiguity(rhs)); + + lhs_ambigious.or(rhs_ambigious) + } + _ => None, + } + } + } impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_expr(&mut self, expr: &'a Expr) { match expr.node { + ExprKind::IfLet(_, ref expr, _, _) | ExprKind::WhileLet(_, ref expr, _, _) => + self.while_if_let_ambiguity(&expr), ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => { span_err!(self.session, expr.span, E0472, "asm! is unsupported on this target"); } diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs new file mode 100644 index 00000000000..339d49104b0 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs @@ -0,0 +1,49 @@ +// Copyright 2016 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. + +// edition:2015 + +// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up +// with examples easier. +#![feature(irrefutable_let_patterns)] + +#[allow(irrefutable_let_patterns)] +fn main() { + use std::ops::Range; + + if let Range { start: _, end: _ } = true..true && false { } + //~^ ERROR ambigious use of `&&` + + if let Range { start: _, end: _ } = true..true || false { } + //~^ ERROR ambigious use of `||` + + while let Range { start: _, end: _ } = true..true && false { } + //~^ ERROR ambigious use of `&&` + + while let Range { start: _, end: _ } = true..true || false { } + //~^ ERROR ambigious use of `||` + + if let true = false && false { } + //~^ ERROR ambigious use of `&&` + + while let true = (1 == 2) && false { } + //~^ ERROR ambigious use of `&&` + + // The following cases are not an error as parenthesis are used to + // clarify intent: + + if let Range { start: _, end: _ } = true..(true || false) { } + + if let Range { start: _, end: _ } = true..(true && false) { } + + while let Range { start: _, end: _ } = true..(true || false) { } + + while let Range { start: _, end: _ } = true..(true && false) { } +} diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr new file mode 100644 index 00000000000..8597294913f --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr @@ -0,0 +1,56 @@ +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:21:47 + | +LL | if let Range { start: _, end: _ } = true..true && false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `||` + --> $DIR/syntax-ambiguity-2015.rs:24:47 + | +LL | if let Range { start: _, end: _ } = true..true || false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:27:50 + | +LL | while let Range { start: _, end: _ } = true..true && false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `||` + --> $DIR/syntax-ambiguity-2015.rs:30:50 + | +LL | while let Range { start: _, end: _ } = true..true || false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:33:19 + | +LL | if let true = false && false { } + | ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:36:22 + | +LL | while let true = (1 == 2) && false { } + | ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs new file mode 100644 index 00000000000..baa90bcf8e9 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs @@ -0,0 +1,49 @@ +// Copyright 2016 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. + +// edition:2018 + +// Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up +// with examples easier. +#![feature(irrefutable_let_patterns)] + +#[allow(irrefutable_let_patterns)] +fn main() { + use std::ops::Range; + + if let Range { start: _, end: _ } = true..true && false { } + //~^ ERROR ambigious use of `&&` + + if let Range { start: _, end: _ } = true..true || false { } + //~^ ERROR ambigious use of `||` + + while let Range { start: _, end: _ } = true..true && false { } + //~^ ERROR ambigious use of `&&` + + while let Range { start: _, end: _ } = true..true || false { } + //~^ ERROR ambigious use of `||` + + if let true = false && false { } + //~^ ERROR ambigious use of `&&` + + while let true = (1 == 2) && false { } + //~^ ERROR ambigious use of `&&` + + // The following cases are not an error as parenthesis are used to + // clarify intent: + + if let Range { start: _, end: _ } = true..(true || false) { } + + if let Range { start: _, end: _ } = true..(true && false) { } + + while let Range { start: _, end: _ } = true..(true || false) { } + + while let Range { start: _, end: _ } = true..(true && false) { } +} diff --git a/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr new file mode 100644 index 00000000000..86ee04747b2 --- /dev/null +++ b/src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr @@ -0,0 +1,56 @@ +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2018.rs:21:47 + | +LL | if let Range { start: _, end: _ } = true..true && false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `||` + --> $DIR/syntax-ambiguity-2018.rs:24:47 + | +LL | if let Range { start: _, end: _ } = true..true || false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2018.rs:27:50 + | +LL | while let Range { start: _, end: _ } = true..true && false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `||` + --> $DIR/syntax-ambiguity-2018.rs:30:50 + | +LL | while let Range { start: _, end: _ } = true..true || false { } + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2018.rs:33:19 + | +LL | if let true = false && false { } + | ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2018.rs:36:22 + | +LL | while let true = (1 == 2) && false { } + | ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)` + | + = note: this will be a error until the `let_chains` feature is stabilized + = note: see rust-lang/rust#53668 for more information + +error: aborting due to 6 previous errors + |
