about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-11-18 14:13:36 +0100
committerGitHub <noreply@github.com>2022-11-18 14:13:36 +0100
commit3efbf3022012f3dbebd6743bf8e53f50cb1d0488 (patch)
tree34f9c9a4d5c5c3f7d8901f2963fa1a77d8097ef2
parent741f3cf38331d4644b89d52f54c2683c17f54670 (diff)
parentcd2bde19551234799cd3df3231fb658707b04195 (diff)
downloadrust-3efbf3022012f3dbebd6743bf8e53f50cb1d0488.tar.gz
rust-3efbf3022012f3dbebd6743bf8e53f50cb1d0488.zip
Rollup merge of #103405 - chenyukang:yukang/fix-103381-and-if, r=compiler-errors
Detect incorrect chaining of if and if let conditions and recover

Fixes #103381
-rw-r--r--compiler/rustc_error_messages/locales/en-US/parser.ftl3
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs15
-rw-r--r--src/test/ui/parser/issue-103381.fixed59
-rw-r--r--src/test/ui/parser/issue-103381.rs59
-rw-r--r--src/test/ui/parser/issue-103381.stderr50
6 files changed, 192 insertions, 2 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl
index 4c7ce30097c..1df5bf1a220 100644
--- a/compiler/rustc_error_messages/locales/en-US/parser.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl
@@ -54,6 +54,9 @@ parser_invalid_logical_operator = `{$incorrect}` is not a logical operator
 parser_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
     .suggestion = use `!` to perform bitwise not
 
+parser_unexpected_if_with_if = unexpected `if` in the condition expression
+    .suggestion = remove the `if`
+
 parser_unexpected_token_after_not = unexpected {$negated_desc} after identifier
 parser_unexpected_token_after_not_bitwise = use `!` to perform bitwise not
 parser_unexpected_token_after_not_logical = use `!` to perform logical negation
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 724d92254a4..211450250fd 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1219,3 +1219,11 @@ pub(crate) struct FnPtrWithGenericsSugg {
     pub arity: usize,
     pub for_param_list_exists: bool,
 }
+
+#[derive(Diagnostic)]
+#[diag(parser_unexpected_if_with_if)]
+pub(crate) struct UnexpectedIfWithIf(
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = " ", style = "verbose")]
+    pub Span,
+);
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index c9629ea49e0..634e45c8480 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -21,8 +21,8 @@ use crate::errors::{
     NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub,
     OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
     RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
-    StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
-    UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
+    StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf,
+    UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
 };
 use crate::maybe_recover_from_interpolated_ty_qpath;
 use core::mem;
@@ -2231,6 +2231,7 @@ impl<'a> Parser<'a> {
                 if let Some(block) = recover_block_from_condition(self) {
                     block
                 } else {
+                    self.error_on_extra_if(&cond)?;
                     // Parse block, which will always fail, but we can add a nice note to the error
                     self.parse_block().map_err(|mut err| {
                         err.span_note(
@@ -2367,6 +2368,16 @@ impl<'a> Parser<'a> {
         });
     }
 
+    fn error_on_extra_if(&mut self, cond: &P<Expr>) -> PResult<'a, ()> {
+        if let ExprKind::Binary(Spanned { span: binop_span, node: binop}, _, right) = &cond.kind &&
+            let BinOpKind::And = binop &&
+            let ExprKind::If(cond, ..) = &right.kind {
+                    Err(self.sess.create_err(UnexpectedIfWithIf(binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()))))
+            } else {
+                Ok(())
+            }
+    }
+
     /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
     fn parse_for_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
         // Record whether we are about to parse `for (`.
diff --git a/src/test/ui/parser/issue-103381.fixed b/src/test/ui/parser/issue-103381.fixed
new file mode 100644
index 00000000000..6a9fb991097
--- /dev/null
+++ b/src/test/ui/parser/issue-103381.fixed
@@ -0,0 +1,59 @@
+// run-rustfix
+
+#![feature(let_chains)]
+#![allow(unused_variables)]
+#![allow(dead_code)]
+#![allow(irrefutable_let_patterns)]
+
+fn err_some(b: bool, x: Option<u32>) {
+    if b && let Some(x) = x {}
+    //~^ ERROR unexpected `if` in the condition expression
+}
+
+fn err_none(b: bool, x: Option<u32>) {
+    if b && let None = x {}
+    //~^ ERROR unexpected `if` in the condition expression
+}
+
+fn err_bool_1() {
+    if true && true { true } else { false };
+    //~^ ERROR unexpected `if` in the condition expression
+}
+
+fn err_bool_2() {
+    if true && false { true } else { false };
+    //~^ ERROR unexpected `if` in the condition expression
+}
+
+fn should_ok_1() {
+    if true && if let x = 1 { true } else { true } {}
+}
+
+fn should_ok_2() {
+    if true && if let 1 = 1 { true } else { true } {}
+}
+
+fn should_ok_3() {
+    if true && if true { true } else { false } {}
+}
+
+fn shoule_match_ok() {
+    #[cfg(feature = "full")]
+    {
+        let a = 1;
+        let b = 2;
+        if match a {
+            1 if b == 1 => true,
+            _ => false,
+        } && if a > 1 { true } else { false }
+        {
+            true
+        }
+    }
+}
+
+fn should_ok_in_nested() {
+    if true && if true { true } else { false } { true } else { false };
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-103381.rs b/src/test/ui/parser/issue-103381.rs
new file mode 100644
index 00000000000..bf79e10103e
--- /dev/null
+++ b/src/test/ui/parser/issue-103381.rs
@@ -0,0 +1,59 @@
+// run-rustfix
+
+#![feature(let_chains)]
+#![allow(unused_variables)]
+#![allow(dead_code)]
+#![allow(irrefutable_let_patterns)]
+
+fn err_some(b: bool, x: Option<u32>) {
+    if b && if let Some(x) = x {}
+    //~^ ERROR unexpected `if` in the condition expression
+}
+
+fn err_none(b: bool, x: Option<u32>) {
+    if b && if let None = x {}
+    //~^ ERROR unexpected `if` in the condition expression
+}
+
+fn err_bool_1() {
+    if true && if true { true } else { false };
+    //~^ ERROR unexpected `if` in the condition expression
+}
+
+fn err_bool_2() {
+    if true && if false { true } else { false };
+    //~^ ERROR unexpected `if` in the condition expression
+}
+
+fn should_ok_1() {
+    if true && if let x = 1 { true } else { true } {}
+}
+
+fn should_ok_2() {
+    if true && if let 1 = 1 { true } else { true } {}
+}
+
+fn should_ok_3() {
+    if true && if true { true } else { false } {}
+}
+
+fn shoule_match_ok() {
+    #[cfg(feature = "full")]
+    {
+        let a = 1;
+        let b = 2;
+        if match a {
+            1 if b == 1 => true,
+            _ => false,
+        } && if a > 1 { true } else { false }
+        {
+            true
+        }
+    }
+}
+
+fn should_ok_in_nested() {
+    if true && if true { true } else { false } { true } else { false };
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-103381.stderr b/src/test/ui/parser/issue-103381.stderr
new file mode 100644
index 00000000000..85fcc18e76b
--- /dev/null
+++ b/src/test/ui/parser/issue-103381.stderr
@@ -0,0 +1,50 @@
+error: unexpected `if` in the condition expression
+  --> $DIR/issue-103381.rs:9:12
+   |
+LL |     if b && if let Some(x) = x {}
+   |            ^^^^
+   |
+help: remove the `if`
+   |
+LL -     if b && if let Some(x) = x {}
+LL +     if b && let Some(x) = x {}
+   |
+
+error: unexpected `if` in the condition expression
+  --> $DIR/issue-103381.rs:14:12
+   |
+LL |     if b && if let None = x {}
+   |            ^^^^
+   |
+help: remove the `if`
+   |
+LL -     if b && if let None = x {}
+LL +     if b && let None = x {}
+   |
+
+error: unexpected `if` in the condition expression
+  --> $DIR/issue-103381.rs:19:15
+   |
+LL |     if true && if true { true } else { false };
+   |               ^^^^
+   |
+help: remove the `if`
+   |
+LL -     if true && if true { true } else { false };
+LL +     if true && true { true } else { false };
+   |
+
+error: unexpected `if` in the condition expression
+  --> $DIR/issue-103381.rs:24:15
+   |
+LL |     if true && if false { true } else { false };
+   |               ^^^^
+   |
+help: remove the `if`
+   |
+LL -     if true && if false { true } else { false };
+LL +     if true && false { true } else { false };
+   |
+
+error: aborting due to 4 previous errors
+