diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index bca119660aa2a..3981d9f0c6453 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,58 @@ 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) { + 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" + ); + + 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) -> 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/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f0e6dfb8775f2..1695d3a8f96b0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3327,8 +3327,6 @@ impl<'a> Parser<'a> { let pats = self.parse_pats()?; self.expect(&token::Eq)?; let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; - self.while_if_let_ambiguity(&expr); - let thn = self.parse_block()?; let (hi, els) = if self.eat_keyword(keywords::Else) { let expr = self.parse_else_expr()?; @@ -3339,56 +3337,6 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs)) } - /// 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) { - if let Some((span, op_kind)) = self.while_if_let_expr_ambiguity(&expr) { - let message = format!("ambigious use of `{}`", op_kind.to_string()); - let mut err = if self.span.edition() >= Edition::Edition2018 { - self.diagnostic().struct_span_err(span, &message) - } else { - self.diagnostic().struct_span_warn(span, &message) - }; - - let note = if self.span.edition() >= Edition::Edition2018 { - "This will be a error until the `let_chains` feature is stabilized." - } else { - "This will be a error in Rust 2018 until the `let_chains` feature is stabilized." - }; - err.note(note); - - if let Ok(snippet) = self.sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, "consider adding parenthesis", 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) -> 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, - } - } - // `move |args| expr` fn parse_lambda_expr(&mut self, attrs: ThinVec) @@ -3489,7 +3437,6 @@ impl<'a> Parser<'a> { let pats = self.parse_pats()?; self.expect(&token::Eq)?; let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; - self.while_if_let_ambiguity(&expr); let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); let span = span_lo.to(body.span); 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 index 06ce23eda7d98..339d49104b021 100644 --- 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 @@ -9,7 +9,6 @@ // except according to those terms. // edition:2015 -// compile-pass // Enabling `ireffutable_let_patterns` isn't necessary for what this tests, but it makes coming up // with examples easier. @@ -20,22 +19,22 @@ fn main() { use std::ops::Range; if let Range { start: _, end: _ } = true..true && false { } - //~^ WARN error in 2018 + //~^ ERROR ambigious use of `&&` if let Range { start: _, end: _ } = true..true || false { } - //~^ WARN error in 2018 + //~^ ERROR ambigious use of `||` while let Range { start: _, end: _ } = true..true && false { } - //~^ WARN error in 2018 + //~^ ERROR ambigious use of `&&` while let Range { start: _, end: _ } = true..true || false { } - //~^ WARN error in 2018 + //~^ ERROR ambigious use of `||` if let true = false && false { } - //~^ WARN error in 2018 + //~^ ERROR ambigious use of `&&` while let true = (1 == 2) && false { } - //~^ WARN error in 2018 + //~^ ERROR ambigious use of `&&` // The following cases are not an error as parenthesis are used to // clarify intent: 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 index a4c3be62ec4c7..0e6ccb5d9d8a7 100644 --- 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 @@ -1,48 +1,50 @@ -warning: ambigious use of `&&` - --> $DIR/syntax-ambiguity-2015.rs:22:47 +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:21:47 | LL | if let Range { start: _, end: _ } = true..true && false { } - | ^^^^^^^^^^^^^ help: consider adding parenthesis: `(true && false)` + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` | - = note: This will be a error in Rust 2018 until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized -warning: ambigious use of `||` - --> $DIR/syntax-ambiguity-2015.rs:25:47 +error: ambigious use of `||` + --> $DIR/syntax-ambiguity-2015.rs:24:47 | LL | if let Range { start: _, end: _ } = true..true || false { } - | ^^^^^^^^^^^^^ help: consider adding parenthesis: `(true || false)` + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` | - = note: This will be a error in Rust 2018 until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized -warning: ambigious use of `&&` - --> $DIR/syntax-ambiguity-2015.rs:28:50 +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:27:50 | LL | while let Range { start: _, end: _ } = true..true && false { } - | ^^^^^^^^^^^^^ help: consider adding parenthesis: `(true && false)` + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` | - = note: This will be a error in Rust 2018 until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized -warning: ambigious use of `||` - --> $DIR/syntax-ambiguity-2015.rs:31:50 +error: ambigious use of `||` + --> $DIR/syntax-ambiguity-2015.rs:30:50 | LL | while let Range { start: _, end: _ } = true..true || false { } - | ^^^^^^^^^^^^^ help: consider adding parenthesis: `(true || false)` + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` | - = note: This will be a error in Rust 2018 until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized -warning: ambigious use of `&&` - --> $DIR/syntax-ambiguity-2015.rs:34:19 +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:33:19 | LL | if let true = false && false { } - | ^^^^^^^^^^^^^^ help: consider adding parenthesis: `(false && false)` + | ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)` | - = note: This will be a error in Rust 2018 until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized -warning: ambigious use of `&&` - --> $DIR/syntax-ambiguity-2015.rs:37:22 +error: ambigious use of `&&` + --> $DIR/syntax-ambiguity-2015.rs:36:22 | LL | while let true = (1 == 2) && false { } - | ^^^^^^^^^^^^^^^^^ help: consider adding parenthesis: `((1 == 2) && false)` + | ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)` | - = note: This will be a error in Rust 2018 until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized + +error: aborting due to 6 previous errors 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 index c472a8904bf65..2bbeda360d755 100644 --- 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 @@ -2,49 +2,49 @@ error: ambigious use of `&&` --> $DIR/syntax-ambiguity-2018.rs:21:47 | LL | if let Range { start: _, end: _ } = true..true && false { } - | ^^^^^^^^^^^^^ help: consider adding parenthesis: `(true && false)` + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` | - = note: This will be a error until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized error: ambigious use of `||` --> $DIR/syntax-ambiguity-2018.rs:24:47 | LL | if let Range { start: _, end: _ } = true..true || false { } - | ^^^^^^^^^^^^^ help: consider adding parenthesis: `(true || false)` + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` | - = note: This will be a error until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized error: ambigious use of `&&` --> $DIR/syntax-ambiguity-2018.rs:27:50 | LL | while let Range { start: _, end: _ } = true..true && false { } - | ^^^^^^^^^^^^^ help: consider adding parenthesis: `(true && false)` + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true && false)` | - = note: This will be a error until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized error: ambigious use of `||` --> $DIR/syntax-ambiguity-2018.rs:30:50 | LL | while let Range { start: _, end: _ } = true..true || false { } - | ^^^^^^^^^^^^^ help: consider adding parenthesis: `(true || false)` + | ^^^^^^^^^^^^^ help: consider adding parentheses: `(true || false)` | - = note: This will be a error until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized error: ambigious use of `&&` --> $DIR/syntax-ambiguity-2018.rs:33:19 | LL | if let true = false && false { } - | ^^^^^^^^^^^^^^ help: consider adding parenthesis: `(false && false)` + | ^^^^^^^^^^^^^^ help: consider adding parentheses: `(false && false)` | - = note: This will be a error until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized error: ambigious use of `&&` --> $DIR/syntax-ambiguity-2018.rs:36:22 | LL | while let true = (1 == 2) && false { } - | ^^^^^^^^^^^^^^^^^ help: consider adding parenthesis: `((1 == 2) && false)` + | ^^^^^^^^^^^^^^^^^ help: consider adding parentheses: `((1 == 2) && false)` | - = note: This will be a error until the `let_chains` feature is stabilized. + = note: this will be a error until the `let_chains` feature is stabilized error: aborting due to 6 previous errors