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:
parent
1d2726726f
commit
ac1454001c
19 changed files with 782 additions and 35 deletions
|
@ -222,6 +222,15 @@ pub enum AngleBracketedArg {
|
||||||
Constraint(AssocTyConstraint),
|
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 {
|
impl Into<Option<P<GenericArgs>>> for AngleBracketedArgs {
|
||||||
fn into(self) -> Option<P<GenericArgs>> {
|
fn into(self) -> Option<P<GenericArgs>> {
|
||||||
Some(P(GenericArgs::AngleBracketed(self)))
|
Some(P(GenericArgs::AngleBracketed(self)))
|
||||||
|
|
|
@ -303,6 +303,13 @@ impl TokenKind {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn should_end_const_arg(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Gt | Ge | BinOp(Shr) | BinOpEq(Shr) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
|
|
|
@ -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;
|
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`.
|
// 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.
|
// are not allowed to depend on other generic parameters, i.e. are concrete.
|
||||||
// (although there could be normalization differences)
|
// (although there could be normalization differences)
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use super::ty::AllowPlus;
|
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::ptr::P;
|
||||||
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
|
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
|
||||||
use rustc_ast::util::parser::AssocOp;
|
use rustc_ast::util::parser::AssocOp;
|
||||||
use rustc_ast::{
|
use rustc_ast::{
|
||||||
self as ast, AngleBracketedArgs, AttrVec, BinOpKind, BindingMode, Block, BlockCheckMode, Expr,
|
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
|
||||||
ExprKind, Item, ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty,
|
Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item, ItemKind, Mutability, Param, Pat,
|
||||||
TyKind,
|
PatKind, Path, PathSegment, QSelf, Ty, TyKind,
|
||||||
};
|
};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,6 +359,18 @@ impl<'a> Parser<'a> {
|
||||||
/// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
|
/// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
|
||||||
fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
|
fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
|
||||||
let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) {
|
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),
|
(Some(op), _) => (op, self.token.span),
|
||||||
(None, Some((Ident { name: sym::and, span }, false))) => {
|
(None, Some((Ident { name: sym::and, span }, false))) => {
|
||||||
self.error_bad_logical_op("and", "&&", "conjunction");
|
self.error_bad_logical_op("and", "&&", "conjunction");
|
||||||
|
@ -1715,7 +1727,7 @@ impl<'a> Parser<'a> {
|
||||||
let lo = self.prev_token.span;
|
let lo = self.prev_token.span;
|
||||||
let pat = self.parse_top_pat(GateOr::No)?;
|
let pat = self.parse_top_pat(GateOr::No)?;
|
||||||
self.expect(&token::Eq)?;
|
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())
|
this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
|
||||||
})?;
|
})?;
|
||||||
let span = lo.to(expr.span);
|
let span = lo.to(expr.span);
|
||||||
|
|
|
@ -36,6 +36,7 @@ bitflags::bitflags! {
|
||||||
struct Restrictions: u8 {
|
struct Restrictions: u8 {
|
||||||
const STMT_EXPR = 1 << 0;
|
const STMT_EXPR = 1 << 0;
|
||||||
const NO_STRUCT_LITERAL = 1 << 1;
|
const NO_STRUCT_LITERAL = 1 << 1;
|
||||||
|
const CONST_EXPR = 1 << 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -397,6 +397,13 @@ impl<'a> Parser<'a> {
|
||||||
while let Some(arg) = self.parse_angle_arg()? {
|
while let Some(arg) = self.parse_angle_arg()? {
|
||||||
args.push(arg);
|
args.push(arg);
|
||||||
if !self.eat(&token::Comma) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,41 +483,50 @@ impl<'a> Parser<'a> {
|
||||||
Ok(self.mk_ty(span, ast::TyKind::Err))
|
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.
|
/// Parse a generic argument in a path segment.
|
||||||
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
|
/// 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>> {
|
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()) {
|
let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
|
||||||
// Parse lifetime argument.
|
// Parse lifetime argument.
|
||||||
GenericArg::Lifetime(self.expect_lifetime())
|
GenericArg::Lifetime(self.expect_lifetime())
|
||||||
} else if self.check_const_arg() {
|
} else if self.check_const_arg() {
|
||||||
// Parse const argument.
|
// 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(
|
self.parse_block_expr(
|
||||||
None,
|
None,
|
||||||
self.token.span,
|
self.token.span,
|
||||||
BlockCheckMode::Default,
|
BlockCheckMode::Default,
|
||||||
ast::AttrVec::new(),
|
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 {
|
} else {
|
||||||
let span = self.token.span;
|
self.handle_unambiguous_unbraced_const_arg()?
|
||||||
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()?
|
|
||||||
};
|
};
|
||||||
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: expr })
|
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
|
||||||
} else if self.check_type() {
|
} else if self.check_type() {
|
||||||
// Parse type argument.
|
// 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 {
|
} else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
52
src/test/ui/const-generics/closing-args-token.full.stderr
Normal file
52
src/test/ui/const-generics/closing-args-token.full.stderr
Normal 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
|
||||||
|
|
52
src/test/ui/const-generics/closing-args-token.min.stderr
Normal file
52
src/test/ui/const-generics/closing-args-token.min.stderr
Normal 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
|
||||||
|
|
32
src/test/ui/const-generics/closing-args-token.rs
Normal file
32
src/test/ui/const-generics/closing-args-token.rs
Normal 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() {}
|
|
@ -1,8 +1,13 @@
|
||||||
error: expected one of `,` or `>`, found `+`
|
error: expressions must be enclosed in braces to be used as const generic arguments
|
||||||
--> $DIR/const-expression-parameter.rs:16:22
|
--> $DIR/const-expression-parameter.rs:16:20
|
||||||
|
|
|
|
||||||
LL | i32_identity::<1 + 2>();
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
error: expected one of `,` or `>`, found `+`
|
error: expressions must be enclosed in braces to be used as const generic arguments
|
||||||
--> $DIR/const-expression-parameter.rs:16:22
|
--> $DIR/const-expression-parameter.rs:16:20
|
||||||
|
|
|
|
||||||
LL | i32_identity::<1 + 2>();
|
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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ fn foo_a() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo_b() {
|
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() {
|
fn foo_c() {
|
||||||
|
|
|
@ -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() {}
|
|
@ -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
|
||||||
|
|
|
@ -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() {}
|
|
@ -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`.
|
|
@ -233,6 +233,8 @@ fn inside_const_generic_arguments() {
|
||||||
// admit non-IDENT expressions in const generic arguments.
|
// admit non-IDENT expressions in const generic arguments.
|
||||||
|
|
||||||
if A::<
|
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 {}
|
>::O == 5 {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
error: expected one of `,` or `>`, found `&&`
|
error: expressions must be enclosed in braces to be used as const generic arguments
|
||||||
--> $DIR/disallowed-positions.rs:236:14
|
--> $DIR/disallowed-positions.rs:236:9
|
||||||
|
|
|
|
||||||
LL | true && let 1 = 1
|
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
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/disallowed-positions.rs:32:9
|
--> $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: only supported directly in conditions of `if`- and `while`-expressions
|
||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= 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
|
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
|
--> $DIR/disallowed-positions.rs:20:12
|
||||||
|
|
|
|
||||||
|
@ -961,7 +975,7 @@ LL | let 0 = 0?;
|
||||||
= help: the trait `Try` is not implemented for `{integer}`
|
= help: the trait `Try` is not implemented for `{integer}`
|
||||||
= note: required by `into_result`
|
= 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.
|
Some errors have detailed explanations: E0277, E0308, E0600, E0614.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
For more information about an error, try `rustc --explain E0277`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue