diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 9eb934c0c9e74..13ffdf04c46b2 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -222,6 +222,15 @@ pub enum AngleBracketedArg {
     Constraint(AssocTyConstraint),
 }
 
+impl AngleBracketedArg {
+    pub fn span(&self) -> Span {
+        match self {
+            AngleBracketedArg::Arg(arg) => arg.span(),
+            AngleBracketedArg::Constraint(constraint) => constraint.span,
+        }
+    }
+}
+
 impl Into<Option<P<GenericArgs>>> for AngleBracketedArgs {
     fn into(self) -> Option<P<GenericArgs>> {
         Some(P(GenericArgs::AngleBracketed(self)))
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index d991027cb4573..2bba7e618c050 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -303,6 +303,13 @@ impl TokenKind {
             _ => None,
         }
     }
+
+    pub fn should_end_const_arg(&self) -> bool {
+        match self {
+            Gt | Ge | BinOp(Shr) | BinOpEq(Shr) => true,
+            _ => false,
+        }
+    }
 }
 
 impl Token {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index c4df0bba726cb..ef5034e218da4 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -490,7 +490,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
     let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env()).val;
 
     // FIXME(eddyb) doesn't look like everything below checks that `a.ty == b.ty`.
-    // We could probably always assert it early, as `const` generic parameters
+    // We could probably always assert it early, as const generic parameters
     // are not allowed to depend on other generic parameters, i.e. are concrete.
     // (although there could be normalization differences)
 
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 1ea01d95a134e..52cbba9d2bf7d 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1,13 +1,14 @@
 use super::ty::AllowPlus;
-use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType};
+use super::TokenType;
+use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType};
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Lit, LitKind, TokenKind};
 use rustc_ast::util::parser::AssocOp;
 use rustc_ast::{
-    self as ast, AngleBracketedArgs, AttrVec, BinOpKind, BindingMode, Block, BlockCheckMode, Expr,
-    ExprKind, Item, ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty,
-    TyKind,
+    self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
+    Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item, ItemKind, Mutability, Param, Pat,
+    PatKind, Path, PathSegment, QSelf, Ty, TyKind,
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
@@ -1774,4 +1775,142 @@ impl<'a> Parser<'a> {
             }
         }
     }
+
+    /// Handle encountering a symbol in a generic argument list that is not a `,` or `>`. In this
+    /// case, we emit an error and try to suggest enclosing a const argument in braces if it looks
+    /// like the user has forgotten them.
+    pub fn handle_ambiguous_unbraced_const_arg(
+        &mut self,
+        args: &mut Vec<AngleBracketedArg>,
+    ) -> PResult<'a, bool> {
+        // If we haven't encountered a closing `>`, then the argument is malformed.
+        // It's likely that the user has written a const expression without enclosing it
+        // in braces, so we try to recover here.
+        let arg = args.pop().unwrap();
+        // FIXME: for some reason using `unexpected` or `expected_one_of_not_found` has
+        // adverse side-effects to subsequent errors and seems to advance the parser.
+        // We are causing this error here exclusively in case that a `const` expression
+        // could be recovered from the current parser state, even if followed by more
+        // arguments after a comma.
+        let mut err = self.struct_span_err(
+            self.token.span,
+            &format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
+        );
+        err.span_label(self.token.span, "expected one of `,` or `>`");
+        match self.recover_const_arg(arg.span(), err) {
+            Ok(arg) => {
+                args.push(AngleBracketedArg::Arg(arg));
+                if self.eat(&token::Comma) {
+                    return Ok(true); // Continue
+                }
+            }
+            Err(mut err) => {
+                args.push(arg);
+                // We will emit a more generic error later.
+                err.delay_as_bug();
+            }
+        }
+        return Ok(false); // Don't continue.
+    }
+
+    /// Handle a generic const argument that had not been enclosed in braces, and suggest enclosing
+    /// it braces. In this situation, unlike in `handle_ambiguous_unbraced_const_arg`, this is
+    /// almost certainly a const argument, so we always offer a suggestion.
+    pub fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> {
+        let start = self.token.span;
+        let expr = self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| {
+            err.span_label(
+                start.shrink_to_lo(),
+                "while parsing a const generic argument starting here",
+            );
+            err
+        })?;
+        if !self.expr_is_valid_const_arg(&expr) {
+            self.struct_span_err(
+                expr.span,
+                "expressions must be enclosed in braces to be used as const generic \
+                    arguments",
+            )
+            .multipart_suggestion(
+                "enclose the `const` expression in braces",
+                vec![
+                    (expr.span.shrink_to_lo(), "{ ".to_string()),
+                    (expr.span.shrink_to_hi(), " }".to_string()),
+                ],
+                Applicability::MachineApplicable,
+            )
+            .emit();
+        }
+        Ok(expr)
+    }
+
+    /// Try to recover from possible generic const argument without `{` and `}`.
+    ///
+    /// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest
+    /// `foo::<{ bar + 3 }>` and `foo::<{ bar - baz }>`, respectively. We only provide a suggestion
+    /// if we think that that the resulting expression would be well formed.
+    pub fn recover_const_arg(
+        &mut self,
+        start: Span,
+        mut err: DiagnosticBuilder<'a>,
+    ) -> PResult<'a, GenericArg> {
+        let is_op = AssocOp::from_token(&self.token)
+            .and_then(|op| {
+                if let AssocOp::Greater
+                | AssocOp::Less
+                | AssocOp::ShiftRight
+                | AssocOp::GreaterEqual
+                // Don't recover from `foo::<bar = baz>`, because this could be an attempt to
+                // assign a value to a defaulted generic parameter.
+                | AssocOp::Assign
+                | AssocOp::AssignOp(_) = op
+                {
+                    None
+                } else {
+                    Some(op)
+                }
+            })
+            .is_some();
+        // 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 {
+            // We perform these checks and early return to avoid taking a snapshot unnecessarily.
+            return Err(err);
+        }
+        let snapshot = self.clone();
+        if is_op {
+            self.bump();
+        }
+        match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
+            Ok(expr) => {
+                if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() {
+                    // Avoid the following output by checking that we consumed a full const arg:
+                    // help: expressions must be enclosed in braces to be used as const generic
+                    //       arguments
+                    //    |
+                    // 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 }));
+                }
+            }
+            Err(mut err) => {
+                err.cancel();
+            }
+        }
+        *self = snapshot;
+        Err(err)
+    }
 }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 698a7e7d9cde8..3bb0cfd81d70c 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -359,6 +359,18 @@ impl<'a> Parser<'a> {
     /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
     fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
         let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) {
+            // When parsing const expressions, stop parsing when encountering `>`.
+            (
+                Some(
+                    AssocOp::ShiftRight
+                    | AssocOp::Greater
+                    | AssocOp::GreaterEqual
+                    | AssocOp::AssignOp(token::BinOpToken::Shr),
+                ),
+                _,
+            ) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
+                return None;
+            }
             (Some(op), _) => (op, self.token.span),
             (None, Some((Ident { name: sym::and, span }, false))) => {
                 self.error_bad_logical_op("and", "&&", "conjunction");
@@ -1715,7 +1727,7 @@ impl<'a> Parser<'a> {
         let lo = self.prev_token.span;
         let pat = self.parse_top_pat(GateOr::No)?;
         self.expect(&token::Eq)?;
-        let expr = self.with_res(Restrictions::NO_STRUCT_LITERAL, |this| {
+        let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| {
             this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
         })?;
         let span = lo.to(expr.span);
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index fb825256d92cd..ca7a627ef1874 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -36,6 +36,7 @@ bitflags::bitflags! {
     struct Restrictions: u8 {
         const STMT_EXPR         = 1 << 0;
         const NO_STRUCT_LITERAL = 1 << 1;
+        const CONST_EXPR        = 1 << 2;
     }
 }
 
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 66ce015d02e4c..06760547eba0c 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -397,6 +397,13 @@ impl<'a> Parser<'a> {
         while let Some(arg) = self.parse_angle_arg()? {
             args.push(arg);
             if !self.eat(&token::Comma) {
+                if !self.token.kind.should_end_const_arg() {
+                    if self.handle_ambiguous_unbraced_const_arg(&mut args)? {
+                        // We've managed to (partially) recover, so continue trying to parse
+                        // arguments.
+                        continue;
+                    }
+                }
                 break;
             }
         }
@@ -476,41 +483,50 @@ impl<'a> Parser<'a> {
         Ok(self.mk_ty(span, ast::TyKind::Err))
     }
 
+    /// We do not permit arbitrary expressions as const arguments. They must be one of:
+    /// - An expression surrounded in `{}`.
+    /// - A literal.
+    /// - A numeric literal prefixed by `-`.
+    pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool {
+        match &expr.kind {
+            ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true,
+            ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind {
+                ast::ExprKind::Lit(_) => true,
+                _ => false,
+            },
+            _ => false,
+        }
+    }
+
     /// Parse a generic argument in a path segment.
     /// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
     fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
+        let start = self.token.span;
         let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
             // Parse lifetime argument.
             GenericArg::Lifetime(self.expect_lifetime())
         } else if self.check_const_arg() {
             // Parse const argument.
-            let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
+            let value = if let token::OpenDelim(token::Brace) = self.token.kind {
                 self.parse_block_expr(
                     None,
                     self.token.span,
                     BlockCheckMode::Default,
                     ast::AttrVec::new(),
                 )?
-            } else if self.token.is_ident() {
-                // FIXME(const_generics): to distinguish between idents for types and consts,
-                // we should introduce a GenericArg::Ident in the AST and distinguish when
-                // lowering to the HIR. For now, idents for const args are not permitted.
-                if self.token.is_bool_lit() {
-                    self.parse_literal_maybe_minus()?
-                } else {
-                    let span = self.token.span;
-                    let msg = "identifiers may currently not be used for const generics";
-                    self.struct_span_err(span, msg).emit();
-                    let block = self.mk_block_err(span);
-                    self.mk_expr(span, ast::ExprKind::Block(block, None), ast::AttrVec::new())
-                }
             } else {
-                self.parse_literal_maybe_minus()?
+                self.handle_unambiguous_unbraced_const_arg()?
             };
-            GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: expr })
+            GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
         } else if self.check_type() {
             // Parse type argument.
-            GenericArg::Type(self.parse_ty()?)
+            match self.parse_ty() {
+                Ok(ty) => GenericArg::Type(ty),
+                Err(err) => {
+                    // Try to recover from possible `const` arg without braces.
+                    return self.recover_const_arg(start, err).map(Some);
+                }
+            }
         } else {
             return Ok(None);
         };
diff --git a/src/test/ui/const-generics/closing-args-token.full.stderr b/src/test/ui/const-generics/closing-args-token.full.stderr
new file mode 100644
index 0000000000000..1c3ddd345a533
--- /dev/null
+++ b/src/test/ui/const-generics/closing-args-token.full.stderr
@@ -0,0 +1,52 @@
+error: expressions must be enclosed in braces to be used as const generic arguments
+  --> $DIR/closing-args-token.rs:11:9
+   |
+LL |     S::<5 + 2 >> 7>;
+   |         ^^^^^
+   |
+help: enclose the `const` expression in braces
+   |
+LL |     S::<{ 5 + 2 } >> 7>;
+   |         ^       ^
+
+error: comparison operators cannot be chained
+  --> $DIR/closing-args-token.rs:11:16
+   |
+LL |     S::<5 + 2 >> 7>;
+   |                ^  ^
+   |
+help: split the comparison into two
+   |
+LL |     S::<5 + 2 >> 7 && 7>;
+   |                    ^^^^
+
+error: comparison operators cannot be chained
+  --> $DIR/closing-args-token.rs:17:20
+   |
+LL |     S::<{ 5 + 2 } >> 7>;
+   |                    ^  ^
+   |
+help: split the comparison into two
+   |
+LL |     S::<{ 5 + 2 } >> 7 && 7>;
+   |                        ^^^^
+
+error: expected expression, found `;`
+  --> $DIR/closing-args-token.rs:22:16
+   |
+LL |     T::<0 >= 3>;
+   |                ^ expected expression
+
+error: comparison operators cannot be chained
+  --> $DIR/closing-args-token.rs:28:12
+   |
+LL |     T::<x >>= 2 > 0>;
+   |            ^^   ^
+   |
+help: split the comparison into two
+   |
+LL |     T::<x >>= 2 && 2 > 0>;
+   |                 ^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/const-generics/closing-args-token.min.stderr b/src/test/ui/const-generics/closing-args-token.min.stderr
new file mode 100644
index 0000000000000..1c3ddd345a533
--- /dev/null
+++ b/src/test/ui/const-generics/closing-args-token.min.stderr
@@ -0,0 +1,52 @@
+error: expressions must be enclosed in braces to be used as const generic arguments
+  --> $DIR/closing-args-token.rs:11:9
+   |
+LL |     S::<5 + 2 >> 7>;
+   |         ^^^^^
+   |
+help: enclose the `const` expression in braces
+   |
+LL |     S::<{ 5 + 2 } >> 7>;
+   |         ^       ^
+
+error: comparison operators cannot be chained
+  --> $DIR/closing-args-token.rs:11:16
+   |
+LL |     S::<5 + 2 >> 7>;
+   |                ^  ^
+   |
+help: split the comparison into two
+   |
+LL |     S::<5 + 2 >> 7 && 7>;
+   |                    ^^^^
+
+error: comparison operators cannot be chained
+  --> $DIR/closing-args-token.rs:17:20
+   |
+LL |     S::<{ 5 + 2 } >> 7>;
+   |                    ^  ^
+   |
+help: split the comparison into two
+   |
+LL |     S::<{ 5 + 2 } >> 7 && 7>;
+   |                        ^^^^
+
+error: expected expression, found `;`
+  --> $DIR/closing-args-token.rs:22:16
+   |
+LL |     T::<0 >= 3>;
+   |                ^ expected expression
+
+error: comparison operators cannot be chained
+  --> $DIR/closing-args-token.rs:28:12
+   |
+LL |     T::<x >>= 2 > 0>;
+   |            ^^   ^
+   |
+help: split the comparison into two
+   |
+LL |     T::<x >>= 2 && 2 > 0>;
+   |                 ^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/const-generics/closing-args-token.rs b/src/test/ui/const-generics/closing-args-token.rs
new file mode 100644
index 0000000000000..8699637c54e94
--- /dev/null
+++ b/src/test/ui/const-generics/closing-args-token.rs
@@ -0,0 +1,32 @@
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+struct S<const X: u32>;
+struct T<const X: bool>;
+
+fn bad_args_1() {
+    S::<5 + 2 >> 7>;
+    //~^ ERROR expressions must be enclosed in braces to be used as const generic arguments
+    //~| ERROR comparison operators cannot be chained
+}
+
+fn bad_args_2() {
+    S::<{ 5 + 2 } >> 7>;
+    //~^ ERROR comparison operators cannot be chained
+}
+
+fn bad_args_3() {
+    T::<0 >= 3>;
+    //~^ ERROR expected expression, found `;`
+}
+
+fn bad_args_4() {
+    let mut x = 0;
+    T::<x >>= 2 > 0>;
+    //~^ ERROR comparison operators cannot be chained
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const-expression-parameter.full.stderr b/src/test/ui/const-generics/const-expression-parameter.full.stderr
index 496af9c6e02e0..0615a4c206d80 100644
--- a/src/test/ui/const-generics/const-expression-parameter.full.stderr
+++ b/src/test/ui/const-generics/const-expression-parameter.full.stderr
@@ -1,8 +1,13 @@
-error: expected one of `,` or `>`, found `+`
-  --> $DIR/const-expression-parameter.rs:16:22
+error: expressions must be enclosed in braces to be used as const generic arguments
+  --> $DIR/const-expression-parameter.rs:16:20
    |
 LL |     i32_identity::<1 + 2>();
-   |                      ^ expected one of `,` or `>`
+   |                    ^^^^^
+   |
+help: enclose the `const` expression in braces
+   |
+LL |     i32_identity::<{ 1 + 2 }>();
+   |                    ^       ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const-expression-parameter.min.stderr b/src/test/ui/const-generics/const-expression-parameter.min.stderr
index 496af9c6e02e0..0615a4c206d80 100644
--- a/src/test/ui/const-generics/const-expression-parameter.min.stderr
+++ b/src/test/ui/const-generics/const-expression-parameter.min.stderr
@@ -1,8 +1,13 @@
-error: expected one of `,` or `>`, found `+`
-  --> $DIR/const-expression-parameter.rs:16:22
+error: expressions must be enclosed in braces to be used as const generic arguments
+  --> $DIR/const-expression-parameter.rs:16:20
    |
 LL |     i32_identity::<1 + 2>();
-   |                      ^ expected one of `,` or `>`
+   |                    ^^^^^
+   |
+help: enclose the `const` expression in braces
+   |
+LL |     i32_identity::<{ 1 + 2 }>();
+   |                    ^       ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const-expression-parameter.rs b/src/test/ui/const-generics/const-expression-parameter.rs
index 7a1eaf9f93908..3ef7c8b32e035 100644
--- a/src/test/ui/const-generics/const-expression-parameter.rs
+++ b/src/test/ui/const-generics/const-expression-parameter.rs
@@ -13,7 +13,7 @@ fn foo_a() {
 }
 
 fn foo_b() {
-    i32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+`
+    i32_identity::<1 + 2>(); //~ ERROR expressions must be enclosed in braces
 }
 
 fn foo_c() {
diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.rs b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.rs
new file mode 100644
index 0000000000000..b9afd2264307e
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.rs
@@ -0,0 +1,49 @@
+#![feature(min_const_generics)]
+
+fn foo<const C: usize>() {}
+
+const BAR: usize = 42;
+
+fn a() {
+    foo<BAR + 3>(); //~ ERROR comparison operators cannot be chained
+}
+fn b() {
+    foo<BAR + BAR>(); //~ ERROR comparison operators cannot be chained
+}
+fn c() {
+    foo<3 + 3>(); //~ ERROR comparison operators cannot be chained
+}
+fn d() {
+    foo<BAR - 3>(); //~ ERROR comparison operators cannot be chained
+}
+fn e() {
+    foo<BAR - BAR>(); //~ ERROR comparison operators cannot be chained
+}
+fn f() {
+    foo<100 - BAR>(); //~ ERROR comparison operators cannot be chained
+}
+fn g() {
+    foo<bar<i32>()>(); //~ ERROR comparison operators cannot be chained
+    //~^ ERROR expected one of `;` or `}`, found `>`
+}
+fn h() {
+    foo<bar::<i32>()>(); //~ ERROR comparison operators cannot be chained
+}
+fn i() {
+    foo<bar::<i32>() + BAR>(); //~ ERROR comparison operators cannot be chained
+}
+fn j() {
+    foo<bar::<i32>() - BAR>(); //~ ERROR comparison operators cannot be chained
+}
+fn k() {
+    foo<BAR - bar::<i32>()>(); //~ ERROR comparison operators cannot be chained
+}
+fn l() {
+    foo<BAR - bar::<i32>()>(); //~ ERROR comparison operators cannot be chained
+}
+
+const fn bar<const C: usize>() -> usize {
+    C
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.stderr b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.stderr
new file mode 100644
index 0000000000000..103a295fced51
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.stderr
@@ -0,0 +1,140 @@
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:8:8
+   |
+LL |     foo<BAR + 3>();
+   |        ^       ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<BAR + 3>();
+   |        ^^
+
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:11:8
+   |
+LL |     foo<BAR + BAR>();
+   |        ^         ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<BAR + BAR>();
+   |        ^^
+
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:14:8
+   |
+LL |     foo<3 + 3>();
+   |        ^     ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<3 + 3>();
+   |        ^^
+
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:17:8
+   |
+LL |     foo<BAR - 3>();
+   |        ^       ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<BAR - 3>();
+   |        ^^
+
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:20:8
+   |
+LL |     foo<BAR - BAR>();
+   |        ^         ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<BAR - BAR>();
+   |        ^^
+
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:23:8
+   |
+LL |     foo<100 - BAR>();
+   |        ^         ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<100 - BAR>();
+   |        ^^
+
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:26:8
+   |
+LL |     foo<bar<i32>()>();
+   |        ^   ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<bar<i32>()>();
+   |        ^^
+
+error: expected one of `;` or `}`, found `>`
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:26:19
+   |
+LL |     foo<bar<i32>()>();
+   |                   ^ expected one of `;` or `}`
+
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:30:8
+   |
+LL |     foo<bar::<i32>()>();
+   |        ^            ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<bar::<i32>()>();
+   |        ^^
+
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:33:8
+   |
+LL |     foo<bar::<i32>() + BAR>();
+   |        ^                  ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<bar::<i32>() + BAR>();
+   |        ^^
+
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:36:8
+   |
+LL |     foo<bar::<i32>() - BAR>();
+   |        ^                  ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<bar::<i32>() - BAR>();
+   |        ^^
+
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:39:8
+   |
+LL |     foo<BAR - bar::<i32>()>();
+   |        ^                  ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<BAR - bar::<i32>()>();
+   |        ^^
+
+error: comparison operators cannot be chained
+  --> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:42:8
+   |
+LL |     foo<BAR - bar::<i32>()>();
+   |        ^                  ^
+   |
+help: use `::<...>` instead of `<...>` to specify type arguments
+   |
+LL |     foo::<BAR - bar::<i32>()>();
+   |        ^^
+
+error: aborting due to 13 previous errors
+
diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
new file mode 100644
index 0000000000000..aea3def5aeb23
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
@@ -0,0 +1,55 @@
+#![feature(min_const_generics)]
+
+fn foo<const C: usize>() {}
+
+const BAR: usize = 42;
+
+fn a() {
+    foo::<BAR + 3>(); //~ ERROR expected one of
+}
+fn b() {
+    // FIXME(const_generics): these diagnostics are awful, because trait objects without `dyn` were
+    // a terrible mistake.
+    foo::<BAR + BAR>();
+    //~^ ERROR expected trait, found constant `BAR`
+    //~| ERROR expected trait, found constant `BAR`
+    //~| ERROR wrong number of const arguments: expected 1, found 0
+    //~| ERROR wrong number of type arguments: expected 0, found 1
+    //~| WARN trait objects without an explicit `dyn` are deprecated
+}
+fn c() {
+    foo::<3 + 3>(); //~ ERROR expressions must be enclosed in braces
+}
+fn d() {
+    foo::<BAR - 3>(); //~ ERROR expected one of
+}
+fn e() {
+    foo::<BAR - BAR>(); //~ ERROR expected one of
+}
+fn f() {
+    foo::<100 - BAR>(); //~ ERROR expressions must be enclosed in braces
+}
+fn g() {
+    foo::<bar<i32>()>(); //~ ERROR expected one of
+}
+fn h() {
+    foo::<bar::<i32>()>(); //~ ERROR expected one of
+}
+fn i() {
+    foo::<bar::<i32>() + BAR>(); //~ ERROR expected one of
+}
+fn j() {
+    foo::<bar::<i32>() - BAR>(); //~ ERROR expected one of
+}
+fn k() {
+    foo::<BAR - bar::<i32>()>(); //~ ERROR expected one of
+}
+fn l() {
+    foo::<BAR - bar::<i32>()>(); //~ ERROR expected one of
+}
+
+const fn bar<const C: usize>() -> usize {
+    C
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
new file mode 100644
index 0000000000000..47e9dc034efff
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
@@ -0,0 +1,157 @@
+error: expected one of `,` or `>`, found `3`
+  --> $DIR/const-expression-suggest-missing-braces.rs:8:17
+   |
+LL |     foo::<BAR + 3>();
+   |                 ^ expected one of `,` or `>`
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     foo::<{ BAR + 3 }>();
+   |           ^         ^
+
+error: expressions must be enclosed in braces to be used as const generic arguments
+  --> $DIR/const-expression-suggest-missing-braces.rs:21:11
+   |
+LL |     foo::<3 + 3>();
+   |           ^^^^^
+   |
+help: enclose the `const` expression in braces
+   |
+LL |     foo::<{ 3 + 3 }>();
+   |           ^       ^
+
+error: expected one of `,` or `>`, found `-`
+  --> $DIR/const-expression-suggest-missing-braces.rs:24:15
+   |
+LL |     foo::<BAR - 3>();
+   |               ^ expected one of `,` or `>`
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     foo::<{ BAR - 3 }>();
+   |           ^         ^
+
+error: expected one of `,` or `>`, found `-`
+  --> $DIR/const-expression-suggest-missing-braces.rs:27:15
+   |
+LL |     foo::<BAR - BAR>();
+   |               ^ expected one of `,` or `>`
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     foo::<{ BAR - BAR }>();
+   |           ^           ^
+
+error: expressions must be enclosed in braces to be used as const generic arguments
+  --> $DIR/const-expression-suggest-missing-braces.rs:30:11
+   |
+LL |     foo::<100 - BAR>();
+   |           ^^^^^^^^^
+   |
+help: enclose the `const` expression in braces
+   |
+LL |     foo::<{ 100 - BAR }>();
+   |           ^           ^
+
+error: expected one of `,` or `>`, found `(`
+  --> $DIR/const-expression-suggest-missing-braces.rs:33:19
+   |
+LL |     foo::<bar<i32>()>();
+   |                   ^ expected one of `,` or `>`
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     foo::<{ bar<i32>() }>();
+   |           ^            ^
+
+error: expected one of `,` or `>`, found `(`
+  --> $DIR/const-expression-suggest-missing-braces.rs:36:21
+   |
+LL |     foo::<bar::<i32>()>();
+   |                     ^ expected one of `,` or `>`
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     foo::<{ bar::<i32>() }>();
+   |           ^              ^
+
+error: expected one of `,` or `>`, found `(`
+  --> $DIR/const-expression-suggest-missing-braces.rs:39:21
+   |
+LL |     foo::<bar::<i32>() + BAR>();
+   |                     ^ expected one of `,` or `>`
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     foo::<{ bar::<i32>() + BAR }>();
+   |           ^                    ^
+
+error: expected one of `,` or `>`, found `(`
+  --> $DIR/const-expression-suggest-missing-braces.rs:42:21
+   |
+LL |     foo::<bar::<i32>() - BAR>();
+   |                     ^ expected one of `,` or `>`
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     foo::<{ bar::<i32>() - BAR }>();
+   |           ^                    ^
+
+error: expected one of `,` or `>`, found `-`
+  --> $DIR/const-expression-suggest-missing-braces.rs:45:15
+   |
+LL |     foo::<BAR - bar::<i32>()>();
+   |               ^ expected one of `,` or `>`
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     foo::<{ BAR - bar::<i32>() }>();
+   |           ^                    ^
+
+error: expected one of `,` or `>`, found `-`
+  --> $DIR/const-expression-suggest-missing-braces.rs:48:15
+   |
+LL |     foo::<BAR - bar::<i32>()>();
+   |               ^ expected one of `,` or `>`
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     foo::<{ BAR - bar::<i32>() }>();
+   |           ^                    ^
+
+error[E0404]: expected trait, found constant `BAR`
+  --> $DIR/const-expression-suggest-missing-braces.rs:13:11
+   |
+LL |     foo::<BAR + BAR>();
+   |           ^^^ not a trait
+
+error[E0404]: expected trait, found constant `BAR`
+  --> $DIR/const-expression-suggest-missing-braces.rs:13:17
+   |
+LL |     foo::<BAR + BAR>();
+   |                 ^^^ not a trait
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/const-expression-suggest-missing-braces.rs:13:11
+   |
+LL |     foo::<BAR + BAR>();
+   |           ^^^^^^^^^ help: use `dyn`: `dyn BAR + BAR`
+   |
+   = note: `#[warn(bare_trait_objects)]` on by default
+
+error[E0107]: wrong number of const arguments: expected 1, found 0
+  --> $DIR/const-expression-suggest-missing-braces.rs:13:5
+   |
+LL |     foo::<BAR + BAR>();
+   |     ^^^^^^^^^^^^^^^^ expected 1 const argument
+
+error[E0107]: wrong number of type arguments: expected 0, found 1
+  --> $DIR/const-expression-suggest-missing-braces.rs:13:11
+   |
+LL |     foo::<BAR + BAR>();
+   |           ^^^^^^^^^ unexpected type argument
+
+error: aborting due to 15 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0107, E0404.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
index 25c7fe760d339..aeee27a151e82 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -233,6 +233,8 @@ fn inside_const_generic_arguments() {
     // admit non-IDENT expressions in const generic arguments.
 
     if A::<
-        true && let 1 = 1 //~ ERROR expected one of `,` or `>`, found `&&`
+        true && let 1 = 1
+        //~^ ERROR `let` expressions are not supported here
+        //~| ERROR  expressions must be enclosed in braces
     >::O == 5 {}
 }
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index bd39650702c7c..11155038a9139 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -1,8 +1,13 @@
-error: expected one of `,` or `>`, found `&&`
-  --> $DIR/disallowed-positions.rs:236:14
+error: expressions must be enclosed in braces to be used as const generic arguments
+  --> $DIR/disallowed-positions.rs:236:9
    |
 LL |         true && let 1 = 1
-   |              ^^ expected one of `,` or `>`
+   |         ^^^^^^^^^^^^^^^^^
+   |
+help: enclose the `const` expression in braces
+   |
+LL |         { true && let 1 = 1 }
+   |         ^                   ^
 
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:32:9
@@ -499,6 +504,15 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if`- and `while`-expressions
    = note: as well as when nested within `&&` and parenthesis in those conditions
 
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:236:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if`- and `while`-expressions
+   = note: as well as when nested within `&&` and parenthesis in those conditions
+
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/disallowed-positions.rs:20:12
    |
@@ -961,7 +975,7 @@ LL |         let 0 = 0?;
    = help: the trait `Try` is not implemented for `{integer}`
    = note: required by `into_result`
 
-error: aborting due to 103 previous errors; 2 warnings emitted
+error: aborting due to 104 previous errors; 2 warnings emitted
 
 Some errors have detailed explanations: E0277, E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0277`.