Suggest expressions that look like const generic arguments should be enclosed in brackets

Co-Authored-By: Esteban Kuber <github@kuber.com.ar>
This commit is contained in:
varkor 2020-10-03 19:30:32 +01:00
parent 1d2726726f
commit ac1454001c
19 changed files with 782 additions and 35 deletions

View File

@ -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)))

View File

@ -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 {

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);
};

View File

@ -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

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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

View File

@ -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() {

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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`.

View File

@ -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 {}
}

View File

@ -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`.