Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 20b1e05

Browse files
committedOct 27, 2020
Auto merge of #77502 - varkor:const-generics-suggest-enclosing-braces, r=petrochenkov
Suggest that expressions that look like const generic arguments should be enclosed in brackets I pulled out the changes for const expressions from #71592 (without the trait object diagnostic changes) and made some small changes; the implementation is `@estebank's.` We're also going to want to make some changes separately to account for trait objects (they result in poor diagnostics, as is evident from one of the test cases here), such as an adaption of #72273. Fixes #70753. r? `@petrochenkov`
2 parents 824f900 + ac14540 commit 20b1e05

19 files changed

+782
-35
lines changed
 

‎compiler/rustc_ast/src/ast.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,15 @@ pub enum AngleBracketedArg {
222222
Constraint(AssocTyConstraint),
223223
}
224224

225+
impl AngleBracketedArg {
226+
pub fn span(&self) -> Span {
227+
match self {
228+
AngleBracketedArg::Arg(arg) => arg.span(),
229+
AngleBracketedArg::Constraint(constraint) => constraint.span,
230+
}
231+
}
232+
}
233+
225234
impl Into<Option<P<GenericArgs>>> for AngleBracketedArgs {
226235
fn into(self) -> Option<P<GenericArgs>> {
227236
Some(P(GenericArgs::AngleBracketed(self)))

‎compiler/rustc_ast/src/token.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,13 @@ impl TokenKind {
303303
_ => None,
304304
}
305305
}
306+
307+
pub fn should_end_const_arg(&self) -> bool {
308+
match self {
309+
Gt | Ge | BinOp(Shr) | BinOpEq(Shr) => true,
310+
_ => false,
311+
}
312+
}
306313
}
307314

308315
impl Token {

‎compiler/rustc_middle/src/ty/relate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
490490
let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env()).val;
491491

492492
// FIXME(eddyb) doesn't look like everything below checks that `a.ty == b.ty`.
493-
// We could probably always assert it early, as `const` generic parameters
493+
// We could probably always assert it early, as const generic parameters
494494
// are not allowed to depend on other generic parameters, i.e. are concrete.
495495
// (although there could be normalization differences)
496496

‎compiler/rustc_parse/src/parser/diagnostics.rs

Lines changed: 143 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use super::ty::AllowPlus;
2-
use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType};
2+
use super::TokenType;
3+
use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType};
34

45
use rustc_ast::ptr::P;
56
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
67
use rustc_ast::util::parser::AssocOp;
78
use rustc_ast::{
8-
self as ast, AngleBracketedArgs, AttrVec, BinOpKind, BindingMode, Block, BlockCheckMode, Expr,
9-
ExprKind, Item, ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty,
10-
TyKind,
9+
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
10+
Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item, ItemKind, Mutability, Param, Pat,
11+
PatKind, Path, PathSegment, QSelf, Ty, TyKind,
1112
};
1213
use rustc_ast_pretty::pprust;
1314
use rustc_data_structures::fx::FxHashSet;
@@ -1780,4 +1781,142 @@ impl<'a> Parser<'a> {
17801781
}
17811782
}
17821783
}
1784+
1785+
/// Handle encountering a symbol in a generic argument list that is not a `,` or `>`. In this
1786+
/// case, we emit an error and try to suggest enclosing a const argument in braces if it looks
1787+
/// like the user has forgotten them.
1788+
pub fn handle_ambiguous_unbraced_const_arg(
1789+
&mut self,
1790+
args: &mut Vec<AngleBracketedArg>,
1791+
) -> PResult<'a, bool> {
1792+
// If we haven't encountered a closing `>`, then the argument is malformed.
1793+
// It's likely that the user has written a const expression without enclosing it
1794+
// in braces, so we try to recover here.
1795+
let arg = args.pop().unwrap();
1796+
// FIXME: for some reason using `unexpected` or `expected_one_of_not_found` has
1797+
// adverse side-effects to subsequent errors and seems to advance the parser.
1798+
// We are causing this error here exclusively in case that a `const` expression
1799+
// could be recovered from the current parser state, even if followed by more
1800+
// arguments after a comma.
1801+
let mut err = self.struct_span_err(
1802+
self.token.span,
1803+
&format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
1804+
);
1805+
err.span_label(self.token.span, "expected one of `,` or `>`");
1806+
match self.recover_const_arg(arg.span(), err) {
1807+
Ok(arg) => {
1808+
args.push(AngleBracketedArg::Arg(arg));
1809+
if self.eat(&token::Comma) {
1810+
return Ok(true); // Continue
1811+
}
1812+
}
1813+
Err(mut err) => {
1814+
args.push(arg);
1815+
// We will emit a more generic error later.
1816+
err.delay_as_bug();
1817+
}
1818+
}
1819+
return Ok(false); // Don't continue.
1820+
}
1821+
1822+
/// Handle a generic const argument that had not been enclosed in braces, and suggest enclosing
1823+
/// it braces. In this situation, unlike in `handle_ambiguous_unbraced_const_arg`, this is
1824+
/// almost certainly a const argument, so we always offer a suggestion.
1825+
pub fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> {
1826+
let start = self.token.span;
1827+
let expr = self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| {
1828+
err.span_label(
1829+
start.shrink_to_lo(),
1830+
"while parsing a const generic argument starting here",
1831+
);
1832+
err
1833+
})?;
1834+
if !self.expr_is_valid_const_arg(&expr) {
1835+
self.struct_span_err(
1836+
expr.span,
1837+
"expressions must be enclosed in braces to be used as const generic \
1838+
arguments",
1839+
)
1840+
.multipart_suggestion(
1841+
"enclose the `const` expression in braces",
1842+
vec![
1843+
(expr.span.shrink_to_lo(), "{ ".to_string()),
1844+
(expr.span.shrink_to_hi(), " }".to_string()),
1845+
],
1846+
Applicability::MachineApplicable,
1847+
)
1848+
.emit();
1849+
}
1850+
Ok(expr)
1851+
}
1852+
1853+
/// Try to recover from possible generic const argument without `{` and `}`.
1854+
///
1855+
/// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest
1856+
/// `foo::<{ bar + 3 }>` and `foo::<{ bar - baz }>`, respectively. We only provide a suggestion
1857+
/// if we think that that the resulting expression would be well formed.
1858+
pub fn recover_const_arg(
1859+
&mut self,
1860+
start: Span,
1861+
mut err: DiagnosticBuilder<'a>,
1862+
) -> PResult<'a, GenericArg> {
1863+
let is_op = AssocOp::from_token(&self.token)
1864+
.and_then(|op| {
1865+
if let AssocOp::Greater
1866+
| AssocOp::Less
1867+
| AssocOp::ShiftRight
1868+
| AssocOp::GreaterEqual
1869+
// Don't recover from `foo::<bar = baz>`, because this could be an attempt to
1870+
// assign a value to a defaulted generic parameter.
1871+
| AssocOp::Assign
1872+
| AssocOp::AssignOp(_) = op
1873+
{
1874+
None
1875+
} else {
1876+
Some(op)
1877+
}
1878+
})
1879+
.is_some();
1880+
// This will be true when a trait object type `Foo +` or a path which was a `const fn` with
1881+
// type params has been parsed.
1882+
let was_op =
1883+
matches!(self.prev_token.kind, token::BinOp(token::Plus | token::Shr) | token::Gt);
1884+
if !is_op && !was_op {
1885+
// We perform these checks and early return to avoid taking a snapshot unnecessarily.
1886+
return Err(err);
1887+
}
1888+
let snapshot = self.clone();
1889+
if is_op {
1890+
self.bump();
1891+
}
1892+
match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
1893+
Ok(expr) => {
1894+
if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() {
1895+
// Avoid the following output by checking that we consumed a full const arg:
1896+
// help: expressions must be enclosed in braces to be used as const generic
1897+
// arguments
1898+
// |
1899+
// LL | let sr: Vec<{ (u32, _, _) = vec![] };
1900+
// | ^ ^
1901+
err.multipart_suggestion(
1902+
"expressions must be enclosed in braces to be used as const generic \
1903+
arguments",
1904+
vec![
1905+
(start.shrink_to_lo(), "{ ".to_string()),
1906+
(expr.span.shrink_to_hi(), " }".to_string()),
1907+
],
1908+
Applicability::MaybeIncorrect,
1909+
);
1910+
let value = self.mk_expr_err(start.to(expr.span));
1911+
err.emit();
1912+
return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
1913+
}
1914+
}
1915+
Err(mut err) => {
1916+
err.cancel();
1917+
}
1918+
}
1919+
*self = snapshot;
1920+
Err(err)
1921+
}
17831922
}

‎compiler/rustc_parse/src/parser/expr.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,18 @@ impl<'a> Parser<'a> {
359359
/// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
360360
fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
361361
let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) {
362+
// When parsing const expressions, stop parsing when encountering `>`.
363+
(
364+
Some(
365+
AssocOp::ShiftRight
366+
| AssocOp::Greater
367+
| AssocOp::GreaterEqual
368+
| AssocOp::AssignOp(token::BinOpToken::Shr),
369+
),
370+
_,
371+
) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
372+
return None;
373+
}
362374
(Some(op), _) => (op, self.token.span),
363375
(None, Some((Ident { name: sym::and, span }, false))) => {
364376
self.error_bad_logical_op("and", "&&", "conjunction");
@@ -1715,7 +1727,7 @@ impl<'a> Parser<'a> {
17151727
let lo = self.prev_token.span;
17161728
let pat = self.parse_top_pat(GateOr::No)?;
17171729
self.expect(&token::Eq)?;
1718-
let expr = self.with_res(Restrictions::NO_STRUCT_LITERAL, |this| {
1730+
let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| {
17191731
this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
17201732
})?;
17211733
let span = lo.to(expr.span);

‎compiler/rustc_parse/src/parser/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ bitflags::bitflags! {
3636
struct Restrictions: u8 {
3737
const STMT_EXPR = 1 << 0;
3838
const NO_STRUCT_LITERAL = 1 << 1;
39+
const CONST_EXPR = 1 << 2;
3940
}
4041
}
4142

‎compiler/rustc_parse/src/parser/path.rs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,13 @@ impl<'a> Parser<'a> {
397397
while let Some(arg) = self.parse_angle_arg()? {
398398
args.push(arg);
399399
if !self.eat(&token::Comma) {
400+
if !self.token.kind.should_end_const_arg() {
401+
if self.handle_ambiguous_unbraced_const_arg(&mut args)? {
402+
// We've managed to (partially) recover, so continue trying to parse
403+
// arguments.
404+
continue;
405+
}
406+
}
400407
break;
401408
}
402409
}
@@ -476,41 +483,50 @@ impl<'a> Parser<'a> {
476483
Ok(self.mk_ty(span, ast::TyKind::Err))
477484
}
478485

486+
/// We do not permit arbitrary expressions as const arguments. They must be one of:
487+
/// - An expression surrounded in `{}`.
488+
/// - A literal.
489+
/// - A numeric literal prefixed by `-`.
490+
pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool {
491+
match &expr.kind {
492+
ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true,
493+
ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind {
494+
ast::ExprKind::Lit(_) => true,
495+
_ => false,
496+
},
497+
_ => false,
498+
}
499+
}
500+
479501
/// Parse a generic argument in a path segment.
480502
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
481503
fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
504+
let start = self.token.span;
482505
let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
483506
// Parse lifetime argument.
484507
GenericArg::Lifetime(self.expect_lifetime())
485508
} else if self.check_const_arg() {
486509
// Parse const argument.
487-
let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
510+
let value = if let token::OpenDelim(token::Brace) = self.token.kind {
488511
self.parse_block_expr(
489512
None,
490513
self.token.span,
491514
BlockCheckMode::Default,
492515
ast::AttrVec::new(),
493516
)?
494-
} else if self.token.is_ident() {
495-
// FIXME(const_generics): to distinguish between idents for types and consts,
496-
// we should introduce a GenericArg::Ident in the AST and distinguish when
497-
// lowering to the HIR. For now, idents for const args are not permitted.
498-
if self.token.is_bool_lit() {
499-
self.parse_literal_maybe_minus()?
500-
} else {
501-
let span = self.token.span;
502-
let msg = "identifiers may currently not be used for const generics";
503-
self.struct_span_err(span, msg).emit();
504-
let block = self.mk_block_err(span);
505-
self.mk_expr(span, ast::ExprKind::Block(block, None), ast::AttrVec::new())
506-
}
507517
} else {
508-
self.parse_literal_maybe_minus()?
518+
self.handle_unambiguous_unbraced_const_arg()?
509519
};
510-
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: expr })
520+
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
511521
} else if self.check_type() {
512522
// Parse type argument.
513-
GenericArg::Type(self.parse_ty()?)
523+
match self.parse_ty() {
524+
Ok(ty) => GenericArg::Type(ty),
525+
Err(err) => {
526+
// Try to recover from possible `const` arg without braces.
527+
return self.recover_const_arg(start, err).map(Some);
528+
}
529+
}
514530
} else {
515531
return Ok(None);
516532
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
error: expressions must be enclosed in braces to be used as const generic arguments
2+
--> $DIR/closing-args-token.rs:11:9
3+
|
4+
LL | S::<5 + 2 >> 7>;
5+
| ^^^^^
6+
|
7+
help: enclose the `const` expression in braces
8+
|
9+
LL | S::<{ 5 + 2 } >> 7>;
10+
| ^ ^
11+
12+
error: comparison operators cannot be chained
13+
--> $DIR/closing-args-token.rs:11:16
14+
|
15+
LL | S::<5 + 2 >> 7>;
16+
| ^ ^
17+
|
18+
help: split the comparison into two
19+
|
20+
LL | S::<5 + 2 >> 7 && 7>;
21+
| ^^^^
22+
23+
error: comparison operators cannot be chained
24+
--> $DIR/closing-args-token.rs:17:20
25+
|
26+
LL | S::<{ 5 + 2 } >> 7>;
27+
| ^ ^
28+
|
29+
help: split the comparison into two
30+
|
31+
LL | S::<{ 5 + 2 } >> 7 && 7>;
32+
| ^^^^
33+
34+
error: expected expression, found `;`
35+
--> $DIR/closing-args-token.rs:22:16
36+
|
37+
LL | T::<0 >= 3>;
38+
| ^ expected expression
39+
40+
error: comparison operators cannot be chained
41+
--> $DIR/closing-args-token.rs:28:12
42+
|
43+
LL | T::<x >>= 2 > 0>;
44+
| ^^ ^
45+
|
46+
help: split the comparison into two
47+
|
48+
LL | T::<x >>= 2 && 2 > 0>;
49+
| ^^^^
50+
51+
error: aborting due to 5 previous errors
52+
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
error: expressions must be enclosed in braces to be used as const generic arguments
2+
--> $DIR/closing-args-token.rs:11:9
3+
|
4+
LL | S::<5 + 2 >> 7>;
5+
| ^^^^^
6+
|
7+
help: enclose the `const` expression in braces
8+
|
9+
LL | S::<{ 5 + 2 } >> 7>;
10+
| ^ ^
11+
12+
error: comparison operators cannot be chained
13+
--> $DIR/closing-args-token.rs:11:16
14+
|
15+
LL | S::<5 + 2 >> 7>;
16+
| ^ ^
17+
|
18+
help: split the comparison into two
19+
|
20+
LL | S::<5 + 2 >> 7 && 7>;
21+
| ^^^^
22+
23+
error: comparison operators cannot be chained
24+
--> $DIR/closing-args-token.rs:17:20
25+
|
26+
LL | S::<{ 5 + 2 } >> 7>;
27+
| ^ ^
28+
|
29+
help: split the comparison into two
30+
|
31+
LL | S::<{ 5 + 2 } >> 7 && 7>;
32+
| ^^^^
33+
34+
error: expected expression, found `;`
35+
--> $DIR/closing-args-token.rs:22:16
36+
|
37+
LL | T::<0 >= 3>;
38+
| ^ expected expression
39+
40+
error: comparison operators cannot be chained
41+
--> $DIR/closing-args-token.rs:28:12
42+
|
43+
LL | T::<x >>= 2 > 0>;
44+
| ^^ ^
45+
|
46+
help: split the comparison into two
47+
|
48+
LL | T::<x >>= 2 && 2 > 0>;
49+
| ^^^^
50+
51+
error: aborting due to 5 previous errors
52+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// revisions: full min
2+
3+
#![cfg_attr(full, feature(const_generics))]
4+
#![cfg_attr(full, allow(incomplete_features))]
5+
#![cfg_attr(min, feature(min_const_generics))]
6+
7+
struct S<const X: u32>;
8+
struct T<const X: bool>;
9+
10+
fn bad_args_1() {
11+
S::<5 + 2 >> 7>;
12+
//~^ ERROR expressions must be enclosed in braces to be used as const generic arguments
13+
//~| ERROR comparison operators cannot be chained
14+
}
15+
16+
fn bad_args_2() {
17+
S::<{ 5 + 2 } >> 7>;
18+
//~^ ERROR comparison operators cannot be chained
19+
}
20+
21+
fn bad_args_3() {
22+
T::<0 >= 3>;
23+
//~^ ERROR expected expression, found `;`
24+
}
25+
26+
fn bad_args_4() {
27+
let mut x = 0;
28+
T::<x >>= 2 > 0>;
29+
//~^ ERROR comparison operators cannot be chained
30+
}
31+
32+
fn main() {}
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
error: expected one of `,` or `>`, found `+`
2-
--> $DIR/const-expression-parameter.rs:16:22
1+
error: expressions must be enclosed in braces to be used as const generic arguments
2+
--> $DIR/const-expression-parameter.rs:16:20
33
|
44
LL | i32_identity::<1 + 2>();
5-
| ^ expected one of `,` or `>`
5+
| ^^^^^
6+
|
7+
help: enclose the `const` expression in braces
8+
|
9+
LL | i32_identity::<{ 1 + 2 }>();
10+
| ^ ^
611

712
error: aborting due to previous error
813

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
error: expected one of `,` or `>`, found `+`
2-
--> $DIR/const-expression-parameter.rs:16:22
1+
error: expressions must be enclosed in braces to be used as const generic arguments
2+
--> $DIR/const-expression-parameter.rs:16:20
33
|
44
LL | i32_identity::<1 + 2>();
5-
| ^ expected one of `,` or `>`
5+
| ^^^^^
6+
|
7+
help: enclose the `const` expression in braces
8+
|
9+
LL | i32_identity::<{ 1 + 2 }>();
10+
| ^ ^
611

712
error: aborting due to previous error
813

‎src/test/ui/const-generics/const-expression-parameter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn foo_a() {
1313
}
1414

1515
fn foo_b() {
16-
i32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+`
16+
i32_identity::<1 + 2>(); //~ ERROR expressions must be enclosed in braces
1717
}
1818

1919
fn foo_c() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#![feature(min_const_generics)]
2+
3+
fn foo<const C: usize>() {}
4+
5+
const BAR: usize = 42;
6+
7+
fn a() {
8+
foo<BAR + 3>(); //~ ERROR comparison operators cannot be chained
9+
}
10+
fn b() {
11+
foo<BAR + BAR>(); //~ ERROR comparison operators cannot be chained
12+
}
13+
fn c() {
14+
foo<3 + 3>(); //~ ERROR comparison operators cannot be chained
15+
}
16+
fn d() {
17+
foo<BAR - 3>(); //~ ERROR comparison operators cannot be chained
18+
}
19+
fn e() {
20+
foo<BAR - BAR>(); //~ ERROR comparison operators cannot be chained
21+
}
22+
fn f() {
23+
foo<100 - BAR>(); //~ ERROR comparison operators cannot be chained
24+
}
25+
fn g() {
26+
foo<bar<i32>()>(); //~ ERROR comparison operators cannot be chained
27+
//~^ ERROR expected one of `;` or `}`, found `>`
28+
}
29+
fn h() {
30+
foo<bar::<i32>()>(); //~ ERROR comparison operators cannot be chained
31+
}
32+
fn i() {
33+
foo<bar::<i32>() + BAR>(); //~ ERROR comparison operators cannot be chained
34+
}
35+
fn j() {
36+
foo<bar::<i32>() - BAR>(); //~ ERROR comparison operators cannot be chained
37+
}
38+
fn k() {
39+
foo<BAR - bar::<i32>()>(); //~ ERROR comparison operators cannot be chained
40+
}
41+
fn l() {
42+
foo<BAR - bar::<i32>()>(); //~ ERROR comparison operators cannot be chained
43+
}
44+
45+
const fn bar<const C: usize>() -> usize {
46+
C
47+
}
48+
49+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
error: comparison operators cannot be chained
2+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:8:8
3+
|
4+
LL | foo<BAR + 3>();
5+
| ^ ^
6+
|
7+
help: use `::<...>` instead of `<...>` to specify type arguments
8+
|
9+
LL | foo::<BAR + 3>();
10+
| ^^
11+
12+
error: comparison operators cannot be chained
13+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:11:8
14+
|
15+
LL | foo<BAR + BAR>();
16+
| ^ ^
17+
|
18+
help: use `::<...>` instead of `<...>` to specify type arguments
19+
|
20+
LL | foo::<BAR + BAR>();
21+
| ^^
22+
23+
error: comparison operators cannot be chained
24+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:14:8
25+
|
26+
LL | foo<3 + 3>();
27+
| ^ ^
28+
|
29+
help: use `::<...>` instead of `<...>` to specify type arguments
30+
|
31+
LL | foo::<3 + 3>();
32+
| ^^
33+
34+
error: comparison operators cannot be chained
35+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:17:8
36+
|
37+
LL | foo<BAR - 3>();
38+
| ^ ^
39+
|
40+
help: use `::<...>` instead of `<...>` to specify type arguments
41+
|
42+
LL | foo::<BAR - 3>();
43+
| ^^
44+
45+
error: comparison operators cannot be chained
46+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:20:8
47+
|
48+
LL | foo<BAR - BAR>();
49+
| ^ ^
50+
|
51+
help: use `::<...>` instead of `<...>` to specify type arguments
52+
|
53+
LL | foo::<BAR - BAR>();
54+
| ^^
55+
56+
error: comparison operators cannot be chained
57+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:23:8
58+
|
59+
LL | foo<100 - BAR>();
60+
| ^ ^
61+
|
62+
help: use `::<...>` instead of `<...>` to specify type arguments
63+
|
64+
LL | foo::<100 - BAR>();
65+
| ^^
66+
67+
error: comparison operators cannot be chained
68+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:26:8
69+
|
70+
LL | foo<bar<i32>()>();
71+
| ^ ^
72+
|
73+
help: use `::<...>` instead of `<...>` to specify type arguments
74+
|
75+
LL | foo::<bar<i32>()>();
76+
| ^^
77+
78+
error: expected one of `;` or `}`, found `>`
79+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:26:19
80+
|
81+
LL | foo<bar<i32>()>();
82+
| ^ expected one of `;` or `}`
83+
84+
error: comparison operators cannot be chained
85+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:30:8
86+
|
87+
LL | foo<bar::<i32>()>();
88+
| ^ ^
89+
|
90+
help: use `::<...>` instead of `<...>` to specify type arguments
91+
|
92+
LL | foo::<bar::<i32>()>();
93+
| ^^
94+
95+
error: comparison operators cannot be chained
96+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:33:8
97+
|
98+
LL | foo<bar::<i32>() + BAR>();
99+
| ^ ^
100+
|
101+
help: use `::<...>` instead of `<...>` to specify type arguments
102+
|
103+
LL | foo::<bar::<i32>() + BAR>();
104+
| ^^
105+
106+
error: comparison operators cannot be chained
107+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:36:8
108+
|
109+
LL | foo<bar::<i32>() - BAR>();
110+
| ^ ^
111+
|
112+
help: use `::<...>` instead of `<...>` to specify type arguments
113+
|
114+
LL | foo::<bar::<i32>() - BAR>();
115+
| ^^
116+
117+
error: comparison operators cannot be chained
118+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:39:8
119+
|
120+
LL | foo<BAR - bar::<i32>()>();
121+
| ^ ^
122+
|
123+
help: use `::<...>` instead of `<...>` to specify type arguments
124+
|
125+
LL | foo::<BAR - bar::<i32>()>();
126+
| ^^
127+
128+
error: comparison operators cannot be chained
129+
--> $DIR/const-expression-suggest-missing-braces-without-turbofish.rs:42:8
130+
|
131+
LL | foo<BAR - bar::<i32>()>();
132+
| ^ ^
133+
|
134+
help: use `::<...>` instead of `<...>` to specify type arguments
135+
|
136+
LL | foo::<BAR - bar::<i32>()>();
137+
| ^^
138+
139+
error: aborting due to 13 previous errors
140+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#![feature(min_const_generics)]
2+
3+
fn foo<const C: usize>() {}
4+
5+
const BAR: usize = 42;
6+
7+
fn a() {
8+
foo::<BAR + 3>(); //~ ERROR expected one of
9+
}
10+
fn b() {
11+
// FIXME(const_generics): these diagnostics are awful, because trait objects without `dyn` were
12+
// a terrible mistake.
13+
foo::<BAR + BAR>();
14+
//~^ ERROR expected trait, found constant `BAR`
15+
//~| ERROR expected trait, found constant `BAR`
16+
//~| ERROR wrong number of const arguments: expected 1, found 0
17+
//~| ERROR wrong number of type arguments: expected 0, found 1
18+
//~| WARN trait objects without an explicit `dyn` are deprecated
19+
}
20+
fn c() {
21+
foo::<3 + 3>(); //~ ERROR expressions must be enclosed in braces
22+
}
23+
fn d() {
24+
foo::<BAR - 3>(); //~ ERROR expected one of
25+
}
26+
fn e() {
27+
foo::<BAR - BAR>(); //~ ERROR expected one of
28+
}
29+
fn f() {
30+
foo::<100 - BAR>(); //~ ERROR expressions must be enclosed in braces
31+
}
32+
fn g() {
33+
foo::<bar<i32>()>(); //~ ERROR expected one of
34+
}
35+
fn h() {
36+
foo::<bar::<i32>()>(); //~ ERROR expected one of
37+
}
38+
fn i() {
39+
foo::<bar::<i32>() + BAR>(); //~ ERROR expected one of
40+
}
41+
fn j() {
42+
foo::<bar::<i32>() - BAR>(); //~ ERROR expected one of
43+
}
44+
fn k() {
45+
foo::<BAR - bar::<i32>()>(); //~ ERROR expected one of
46+
}
47+
fn l() {
48+
foo::<BAR - bar::<i32>()>(); //~ ERROR expected one of
49+
}
50+
51+
const fn bar<const C: usize>() -> usize {
52+
C
53+
}
54+
55+
fn main() {}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
error: expected one of `,` or `>`, found `3`
2+
--> $DIR/const-expression-suggest-missing-braces.rs:8:17
3+
|
4+
LL | foo::<BAR + 3>();
5+
| ^ expected one of `,` or `>`
6+
|
7+
help: expressions must be enclosed in braces to be used as const generic arguments
8+
|
9+
LL | foo::<{ BAR + 3 }>();
10+
| ^ ^
11+
12+
error: expressions must be enclosed in braces to be used as const generic arguments
13+
--> $DIR/const-expression-suggest-missing-braces.rs:21:11
14+
|
15+
LL | foo::<3 + 3>();
16+
| ^^^^^
17+
|
18+
help: enclose the `const` expression in braces
19+
|
20+
LL | foo::<{ 3 + 3 }>();
21+
| ^ ^
22+
23+
error: expected one of `,` or `>`, found `-`
24+
--> $DIR/const-expression-suggest-missing-braces.rs:24:15
25+
|
26+
LL | foo::<BAR - 3>();
27+
| ^ expected one of `,` or `>`
28+
|
29+
help: expressions must be enclosed in braces to be used as const generic arguments
30+
|
31+
LL | foo::<{ BAR - 3 }>();
32+
| ^ ^
33+
34+
error: expected one of `,` or `>`, found `-`
35+
--> $DIR/const-expression-suggest-missing-braces.rs:27:15
36+
|
37+
LL | foo::<BAR - BAR>();
38+
| ^ expected one of `,` or `>`
39+
|
40+
help: expressions must be enclosed in braces to be used as const generic arguments
41+
|
42+
LL | foo::<{ BAR - BAR }>();
43+
| ^ ^
44+
45+
error: expressions must be enclosed in braces to be used as const generic arguments
46+
--> $DIR/const-expression-suggest-missing-braces.rs:30:11
47+
|
48+
LL | foo::<100 - BAR>();
49+
| ^^^^^^^^^
50+
|
51+
help: enclose the `const` expression in braces
52+
|
53+
LL | foo::<{ 100 - BAR }>();
54+
| ^ ^
55+
56+
error: expected one of `,` or `>`, found `(`
57+
--> $DIR/const-expression-suggest-missing-braces.rs:33:19
58+
|
59+
LL | foo::<bar<i32>()>();
60+
| ^ expected one of `,` or `>`
61+
|
62+
help: expressions must be enclosed in braces to be used as const generic arguments
63+
|
64+
LL | foo::<{ bar<i32>() }>();
65+
| ^ ^
66+
67+
error: expected one of `,` or `>`, found `(`
68+
--> $DIR/const-expression-suggest-missing-braces.rs:36:21
69+
|
70+
LL | foo::<bar::<i32>()>();
71+
| ^ expected one of `,` or `>`
72+
|
73+
help: expressions must be enclosed in braces to be used as const generic arguments
74+
|
75+
LL | foo::<{ bar::<i32>() }>();
76+
| ^ ^
77+
78+
error: expected one of `,` or `>`, found `(`
79+
--> $DIR/const-expression-suggest-missing-braces.rs:39:21
80+
|
81+
LL | foo::<bar::<i32>() + BAR>();
82+
| ^ expected one of `,` or `>`
83+
|
84+
help: expressions must be enclosed in braces to be used as const generic arguments
85+
|
86+
LL | foo::<{ bar::<i32>() + BAR }>();
87+
| ^ ^
88+
89+
error: expected one of `,` or `>`, found `(`
90+
--> $DIR/const-expression-suggest-missing-braces.rs:42:21
91+
|
92+
LL | foo::<bar::<i32>() - BAR>();
93+
| ^ expected one of `,` or `>`
94+
|
95+
help: expressions must be enclosed in braces to be used as const generic arguments
96+
|
97+
LL | foo::<{ bar::<i32>() - BAR }>();
98+
| ^ ^
99+
100+
error: expected one of `,` or `>`, found `-`
101+
--> $DIR/const-expression-suggest-missing-braces.rs:45:15
102+
|
103+
LL | foo::<BAR - bar::<i32>()>();
104+
| ^ expected one of `,` or `>`
105+
|
106+
help: expressions must be enclosed in braces to be used as const generic arguments
107+
|
108+
LL | foo::<{ BAR - bar::<i32>() }>();
109+
| ^ ^
110+
111+
error: expected one of `,` or `>`, found `-`
112+
--> $DIR/const-expression-suggest-missing-braces.rs:48:15
113+
|
114+
LL | foo::<BAR - bar::<i32>()>();
115+
| ^ expected one of `,` or `>`
116+
|
117+
help: expressions must be enclosed in braces to be used as const generic arguments
118+
|
119+
LL | foo::<{ BAR - bar::<i32>() }>();
120+
| ^ ^
121+
122+
error[E0404]: expected trait, found constant `BAR`
123+
--> $DIR/const-expression-suggest-missing-braces.rs:13:11
124+
|
125+
LL | foo::<BAR + BAR>();
126+
| ^^^ not a trait
127+
128+
error[E0404]: expected trait, found constant `BAR`
129+
--> $DIR/const-expression-suggest-missing-braces.rs:13:17
130+
|
131+
LL | foo::<BAR + BAR>();
132+
| ^^^ not a trait
133+
134+
warning: trait objects without an explicit `dyn` are deprecated
135+
--> $DIR/const-expression-suggest-missing-braces.rs:13:11
136+
|
137+
LL | foo::<BAR + BAR>();
138+
| ^^^^^^^^^ help: use `dyn`: `dyn BAR + BAR`
139+
|
140+
= note: `#[warn(bare_trait_objects)]` on by default
141+
142+
error[E0107]: wrong number of const arguments: expected 1, found 0
143+
--> $DIR/const-expression-suggest-missing-braces.rs:13:5
144+
|
145+
LL | foo::<BAR + BAR>();
146+
| ^^^^^^^^^^^^^^^^ expected 1 const argument
147+
148+
error[E0107]: wrong number of type arguments: expected 0, found 1
149+
--> $DIR/const-expression-suggest-missing-braces.rs:13:11
150+
|
151+
LL | foo::<BAR + BAR>();
152+
| ^^^^^^^^^ unexpected type argument
153+
154+
error: aborting due to 15 previous errors; 1 warning emitted
155+
156+
Some errors have detailed explanations: E0107, E0404.
157+
For more information about an error, try `rustc --explain E0107`.

‎src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ fn inside_const_generic_arguments() {
233233
// admit non-IDENT expressions in const generic arguments.
234234

235235
if A::<
236-
true && let 1 = 1 //~ ERROR expected one of `,` or `>`, found `&&`
236+
true && let 1 = 1
237+
//~^ ERROR `let` expressions are not supported here
238+
//~| ERROR expressions must be enclosed in braces
237239
>::O == 5 {}
238240
}

‎src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
error: expected one of `,` or `>`, found `&&`
2-
--> $DIR/disallowed-positions.rs:236:14
1+
error: expressions must be enclosed in braces to be used as const generic arguments
2+
--> $DIR/disallowed-positions.rs:236:9
33
|
44
LL | true && let 1 = 1
5-
| ^^ expected one of `,` or `>`
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
help: enclose the `const` expression in braces
8+
|
9+
LL | { true && let 1 = 1 }
10+
| ^ ^
611

712
error: `let` expressions are not supported here
813
--> $DIR/disallowed-positions.rs:32:9
@@ -499,6 +504,15 @@ LL | true && let 1 = 1
499504
= note: only supported directly in conditions of `if`- and `while`-expressions
500505
= note: as well as when nested within `&&` and parenthesis in those conditions
501506

507+
error: `let` expressions are not supported here
508+
--> $DIR/disallowed-positions.rs:236:17
509+
|
510+
LL | true && let 1 = 1
511+
| ^^^^^^^^^
512+
|
513+
= note: only supported directly in conditions of `if`- and `while`-expressions
514+
= note: as well as when nested within `&&` and parenthesis in those conditions
515+
502516
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
503517
--> $DIR/disallowed-positions.rs:20:12
504518
|
@@ -961,7 +975,7 @@ LL | let 0 = 0?;
961975
= help: the trait `Try` is not implemented for `{integer}`
962976
= note: required by `into_result`
963977

964-
error: aborting due to 103 previous errors; 2 warnings emitted
978+
error: aborting due to 104 previous errors; 2 warnings emitted
965979

966980
Some errors have detailed explanations: E0277, E0308, E0600, E0614.
967981
For more information about an error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)
Please sign in to comment.