about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-04-14 17:09:03 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-04-19 10:13:44 -0700
commit2f36b54f0f33427e926872935c325a660967af6f (patch)
tree1ed541f3fee0898fef1b7676da1c248effc29f88 /src/libsyntax
parenta2bbf7debaab60be33bd8008a71bca69576945a0 (diff)
downloadrust-2f36b54f0f33427e926872935c325a660967af6f.tar.gz
rust-2f36b54f0f33427e926872935c325a660967af6f.zip
Emit specific error for struct literal in conditions
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/parse/parser.rs57
1 files changed, 52 insertions, 5 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index a5adb37f745..7d130470c6a 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2855,11 +2855,13 @@ impl<'a> Parser<'a> {
                         let (delim, tts) = self.expect_delimited_token_tree()?;
                         hi = self.prev_span;
                         ex = ExprKind::Mac(respan(lo.to(hi), Mac_ { path, tts, delim }));
-                    } else if self.check(&token::OpenDelim(token::Brace)) &&
-                              !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) {
-                        // This is a struct literal, unless we're prohibited
-                        // from parsing struct literals here.
-                        return self.parse_struct_expr(lo, path, attrs);
+                    } else if self.check(&token::OpenDelim(token::Brace)) {
+                        if let Some(expr) = self.should_parse_struct_expr(lo, path.clone(), attrs.clone()) {
+                            return expr;
+                        } else {
+                            hi = path.span;
+                            ex = ExprKind::Path(None, path);
+                        }
                     } else {
                         hi = path.span;
                         ex = ExprKind::Path(None, path);
@@ -2902,6 +2904,51 @@ impl<'a> Parser<'a> {
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
+    fn should_parse_struct_expr(
+        &mut self,
+        lo: Span,
+        path: ast::Path,
+        attrs: ThinVec<Attribute>,
+    ) -> Option<PResult<'a, P<Expr>>> {
+        let could_be_struct = self.look_ahead(1, |t| t.is_ident()) && (
+            self.look_ahead(2, |t| *t == token::Colon)
+            || self.look_ahead(2, |t| *t == token::Comma)
+            // We could also check for `token::CloseDelim(token::Brace)`, but that would
+            // have false positives in the case of `if x == y { z } { a }`.
+        );
+        let mut bad_struct = false;
+        let mut parse_struct = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
+        if self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) && could_be_struct {
+            // This is a struct literal, but we don't can't accept them here
+            bad_struct = true;
+            parse_struct = true;
+        }
+        if parse_struct {
+            match self.parse_struct_expr(lo, path, attrs) {
+                Err(err) => return Some(Err(err)),
+                Ok(expr) => {
+                    if bad_struct {
+                        let mut err = self.diagnostic().struct_span_err(
+                            expr.span,
+                            "struct literals are not allowed here",
+                        );
+                        err.multipart_suggestion(
+                            "surround the struct literal with parenthesis",
+                            vec![
+                                (lo.shrink_to_lo(), "(".to_string()),
+                                (expr.span.shrink_to_hi(), ")".to_string()),
+                            ],
+                            Applicability::MachineApplicable,
+                        );
+                        err.emit();
+                    }
+                    return Some(Ok(expr));
+                }
+            }
+        }
+        None
+    }
+
     fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>)
                          -> PResult<'a, P<Expr>> {
         let struct_sp = lo.to(self.prev_span);