about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs39
-rw-r--r--compiler/rustc_parse/src/parser/path.rs19
2 files changed, 40 insertions, 18 deletions
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index f1c2dcf10e8..50310b28f9a 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2030,7 +2030,7 @@ impl<'a> Parser<'a> {
         start: Span,
         mut err: DiagnosticBuilder<'a, ErrorReported>,
     ) -> PResult<'a, GenericArg> {
-        let is_op = AssocOp::from_token(&self.token)
+        let is_op_or_dot = AssocOp::from_token(&self.token)
             .and_then(|op| {
                 if let AssocOp::Greater
                 | AssocOp::Less
@@ -2046,17 +2046,18 @@ impl<'a> Parser<'a> {
                     Some(op)
                 }
             })
-            .is_some();
+            .is_some()
+            || self.token.kind == TokenKind::Dot;
         // This will be true when a trait object type `Foo +` or a path which was a `const fn` with
         // type params has been parsed.
         let was_op =
             matches!(self.prev_token.kind, token::BinOp(token::Plus | token::Shr) | token::Gt);
-        if !is_op && !was_op {
+        if !is_op_or_dot && !was_op {
             // We perform these checks and early return to avoid taking a snapshot unnecessarily.
             return Err(err);
         }
         let snapshot = self.clone();
-        if is_op {
+        if is_op_or_dot {
             self.bump();
         }
         match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
@@ -2080,18 +2081,7 @@ impl<'a> Parser<'a> {
                     //    |
                     // LL |     let sr: Vec<{ (u32, _, _) = vec![] };
                     //    |                 ^                      ^
-                    err.multipart_suggestion(
-                        "expressions must be enclosed in braces to be used as const generic \
-                         arguments",
-                        vec![
-                            (start.shrink_to_lo(), "{ ".to_string()),
-                            (expr.span.shrink_to_hi(), " }".to_string()),
-                        ],
-                        Applicability::MaybeIncorrect,
-                    );
-                    let value = self.mk_expr_err(start.to(expr.span));
-                    err.emit();
-                    return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
+                    return Ok(self.dummy_const_arg_needs_braces(err, start.to(expr.span)));
                 }
             }
             Err(err) => {
@@ -2102,6 +2092,23 @@ impl<'a> Parser<'a> {
         Err(err)
     }
 
+    /// Creates a dummy const argument, and reports that the expression must be enclosed in braces
+    pub fn dummy_const_arg_needs_braces(
+        &self,
+        mut err: DiagnosticBuilder<'a, ErrorReported>,
+        span: Span,
+    ) -> GenericArg {
+        err.multipart_suggestion(
+            "expressions must be enclosed in braces to be used as const generic \
+             arguments",
+            vec![(span.shrink_to_lo(), "{ ".to_string()), (span.shrink_to_hi(), " }".to_string())],
+            Applicability::MaybeIncorrect,
+        );
+        let value = self.mk_expr_err(span);
+        err.emit();
+        GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
+    }
+
     /// Get the diagnostics for the cases where `move async` is found.
     ///
     /// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index b5857e05970..0ffc9d09355 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -1,5 +1,5 @@
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{Parser, TokenType};
+use super::{Parser, Restrictions, TokenType};
 use crate::maybe_whole;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Token};
@@ -634,7 +634,22 @@ impl<'a> Parser<'a> {
         } else if self.token.is_keyword(kw::Const) {
             return self.recover_const_param_declaration(ty_generics);
         } else {
-            return Ok(None);
+            // Fall back by trying to parse a const-expr expression. If we successfully do so,
+            // then we should report an error that it needs to be wrapped in braces.
+            let snapshot = self.clone();
+            match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
+                Ok(expr) => {
+                    return Ok(Some(self.dummy_const_arg_needs_braces(
+                        self.struct_span_err(expr.span, "invalid const generic expression"),
+                        expr.span,
+                    )));
+                }
+                Err(err) => {
+                    *self = snapshot;
+                    err.cancel();
+                    return Ok(None);
+                }
+            }
         };
         Ok(Some(arg))
     }