Skip to content

Commit 39ae744

Browse files
committed
review comments
1 parent 27801f7 commit 39ae744

File tree

7 files changed

+200
-115
lines changed

7 files changed

+200
-115
lines changed

src/libsyntax/ast.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -1255,17 +1255,26 @@ pub enum ExprKind {
12551255
}
12561256

12571257
impl ExprKind {
1258-
/// Whether this expression can appear in a contst argument without being surrounded by braces.
1258+
/// Whether this expression can appear applied to a `const` parameter without being surrounded
1259+
/// by braces.
12591260
///
12601261
/// Only used in error recovery.
1261-
pub(crate) fn is_valid_const_on_its_own(&self) -> bool {
1262+
crate fn is_valid_const_on_its_own(&self) -> bool {
1263+
fn is_const_lit(kind: &ExprKind) -> bool {
1264+
// These are the only literals that can be negated as a bare `const` argument.
1265+
match kind {
1266+
ExprKind::Lit(Lit { node: LitKind::Int(..), ..}) |
1267+
ExprKind::Lit(Lit { node: LitKind::Float(..), ..}) |
1268+
ExprKind::Lit(Lit { node: LitKind::FloatUnsuffixed(..), ..}) => true,
1269+
_ => false,
1270+
}
1271+
}
1272+
12621273
match self {
1263-
ExprKind::Tup(_) |
1264-
ExprKind::Lit(_) |
1265-
ExprKind::Type(..) |
1266-
ExprKind::Path(..) |
1267-
ExprKind::Unary(..) |
1274+
ExprKind::Lit(_) | // `foo::<42>()`
12681275
ExprKind::Err => true,
1276+
// `foo::<-42>()`
1277+
ExprKind::Unary(UnOp::Neg, expr) if is_const_lit(&expr.node) => true,
12691278
_ => false,
12701279
}
12711280
}

src/libsyntax/parse/parser/expr.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,9 @@ impl<'a> Parser<'a> {
355355
(self.restrictions.contains(Restrictions::STMT_EXPR) &&
356356
!classify::expr_requires_semi_to_be_stmt(e)) ||
357357
(self.restrictions.contains(Restrictions::CONST_EXPR_RECOVERY) &&
358-
(self.token == token::Lt || self.token == token::Gt || self.token == token::Comma))
358+
// `<` is necessary here to avoid cases like `foo::< 1 < 3 >()` where we'll fallback
359+
// to a regular parse error without recovery or suggestions.
360+
[token::Lt, token::Gt, token::Comma].contains(&self.token.kind))
359361
}
360362

361363
fn is_at_start_of_range_notation_rhs(&self) -> bool {

src/libsyntax/parse/parser/path.rs

+74-43
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
use super::{Parser, PResult, Restrictions, TokenType};
1+
use super::{P, Parser, PResult, Restrictions, TokenType};
22

33
use crate::{maybe_whole, ThinVec};
4-
use crate::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs};
5-
use crate::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
4+
use crate::ast::{
5+
self, AngleBracketedArgs, AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode,
6+
Expr, GenericArg, Ident, ParenthesizedArgs, Path, PathSegment, QSelf,
7+
};
68
use crate::parse::token::{self, Token};
79
use crate::source_map::{Span, BytePos};
810
use crate::symbol::kw;
@@ -412,54 +414,37 @@ impl<'a> Parser<'a> {
412414
span,
413415
});
414416
assoc_ty_constraints.push(span);
417+
} else if [
418+
token::Not,
419+
token::OpenDelim(token::Paren),
420+
].contains(&self.token.kind) && self.look_ahead(1, |t| t.is_lit() || t.is_bool_lit()) {
421+
// Parse bad `const` argument. `!` is only allowed here to go through
422+
// `recover_bare_const_expr` for better diagnostics when encountering
423+
// `foo::<!false>()`. `(` is allowed for the case `foo::<(1, 2, 3)>()`.
424+
425+
// This can't possibly be a valid const arg, it is likely missing braces.
426+
let value = AnonConst {
427+
id: ast::DUMMY_NODE_ID,
428+
value: self.recover_bare_const_expr()?,
429+
};
430+
args.push(GenericArg::Const(value));
431+
misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
415432
} else if self.check_const_arg() {
416-
// Parse const argument.
433+
// Parse `const` argument.
434+
435+
// `const` arguments that don't require surrunding braces would have a length of
436+
// one token, so anything that *isn't* surrounded by braces and is not
437+
// immediately followed by `,` or `>` is not a valid `const` argument.
417438
let invalid = self.look_ahead(1, |t| t != &token::Lt && t != &token::Comma);
439+
418440
let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
441+
// Parse `const` argument surrounded by braces.
419442
self.parse_block_expr(
420443
None, self.token.span, BlockCheckMode::Default, ThinVec::new()
421444
)?
422445
} else if invalid {
423446
// This can't possibly be a valid const arg, it is likely missing braces.
424-
let snapshot = self.clone();
425-
match self.parse_expr_res(Restrictions::CONST_EXPR_RECOVERY, None) {
426-
Ok(expr) => {
427-
if self.token == token::Comma || self.token == token::Gt {
428-
// We parsed the whole const argument successfully without braces.
429-
if !expr.node.is_valid_const_on_its_own() {
430-
// But it wasn't a literal, so we emit a custom error and
431-
// suggest the appropriate code.
432-
let msg =
433-
"complex const arguments must be surrounded by braces";
434-
let appl = Applicability::MachineApplicable;
435-
self.span_fatal(expr.span, msg)
436-
.multipart_suggestion(
437-
"surround this const argument in braces",
438-
vec![
439-
(expr.span.shrink_to_lo(), "{ ".to_string()),
440-
(expr.span.shrink_to_hi(), " }".to_string()),
441-
],
442-
appl,
443-
)
444-
.emit();
445-
}
446-
expr
447-
} else {
448-
// We parsed *some* expression, but it isn't the whole argument
449-
// so we can't ensure it was a const argument with missing braces.
450-
// Roll-back and emit a regular parser error.
451-
mem::replace(self, snapshot);
452-
self.parse_literal_maybe_minus()?
453-
}
454-
}
455-
Err(mut err) => {
456-
// We couldn't parse an expression successfully.
457-
// Roll-back, hide the error and emit a regular parser error.
458-
err.cancel();
459-
mem::replace(self, snapshot);
460-
self.parse_literal_maybe_minus()?
461-
}
462-
}
447+
self.recover_bare_const_expr()?
463448
} else if self.token.is_ident() {
464449
// FIXME(const_generics): to distinguish between idents for types and consts,
465450
// we should introduce a GenericArg::Ident in the AST and distinguish when
@@ -512,4 +497,50 @@ impl<'a> Parser<'a> {
512497

513498
Ok((args, constraints))
514499
}
500+
501+
fn recover_bare_const_expr(&mut self) -> PResult<'a, P<Expr>> {
502+
let snapshot = self.clone();
503+
debug!("recover_bare_const_expr {:?}", self.token);
504+
match self.parse_expr_res(Restrictions::CONST_EXPR_RECOVERY, None) {
505+
Ok(expr) => {
506+
debug!("recover_bare_const_expr expr {:?} {:?}", expr, expr.node);
507+
if let token::Comma | token::Gt = self.token.kind {
508+
// We parsed the whole const argument successfully without braces.
509+
debug!("recover_bare_const_expr ok");
510+
if !expr.node.is_valid_const_on_its_own() {
511+
// But it wasn't a literal, so we emit a custom error and
512+
// suggest the appropriate code. `foo::<-1>()` is valid but gets parsed
513+
// here, so we need to gate the error only for invalid cases.
514+
self.span_fatal(
515+
expr.span,
516+
"complex const arguments must be surrounded by braces",
517+
).multipart_suggestion(
518+
"surround this const argument in braces",
519+
vec![
520+
(expr.span.shrink_to_lo(), "{ ".to_string()),
521+
(expr.span.shrink_to_hi(), " }".to_string()),
522+
],
523+
Applicability::MachineApplicable,
524+
).emit();
525+
}
526+
Ok(expr)
527+
} else {
528+
debug!("recover_bare_const_expr not");
529+
// We parsed *some* expression, but it isn't the whole argument
530+
// so we can't ensure it was a const argument with missing braces.
531+
// Roll-back and emit a regular parser error.
532+
mem::replace(self, snapshot);
533+
self.parse_literal_maybe_minus()
534+
}
535+
}
536+
Err(mut err) => {
537+
debug!("recover_bare_const_expr err");
538+
// We couldn't parse an expression successfully.
539+
// Roll-back, hide the error and emit a regular parser error.
540+
err.cancel();
541+
mem::replace(self, snapshot);
542+
self.parse_literal_maybe_minus()
543+
}
544+
}
545+
}
515546
}
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
11
#![feature(const_generics)]
22
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
33

4-
fn i32_identity<const X: i32>() -> i32 {
5-
5
6-
}
4+
fn foo<const X: i32>() -> i32 { 5 }
75

8-
fn foo_a() {
9-
i32_identity::<-1>(); // ok
10-
}
6+
fn baz<const X: i32, const Y: i32>() { }
117

12-
fn foo_b() {
13-
i32_identity::<1 + 2>(); //~ ERROR complex const arguments must be surrounded by braces
14-
}
8+
fn bar<const X: bool>() {}
159

16-
fn foo_c() {
17-
i32_identity::< -1 >(); // ok
18-
}
10+
fn bat<const X: (i32, i32, i32)>() {}
1911

20-
fn foo_d() {
21-
i32_identity::<1 + 2, 3 + 4>();
12+
fn main() {
13+
foo::<-1>(); // ok
14+
foo::<1 + 2>(); //~ ERROR complex const arguments must be surrounded by braces
15+
foo::< -1 >(); // ok
16+
foo::<1 + 2, 3 + 4>();
2217
//~^ ERROR complex const arguments must be surrounded by braces
2318
//~| ERROR complex const arguments must be surrounded by braces
2419
//~| ERROR wrong number of const arguments: expected 1, found 2
25-
}
20+
foo::<5>(); // ok
2621

27-
fn baz<const X: i32, const Y: i32>() -> i32 {
28-
42
29-
}
30-
31-
fn foo_e() {
22+
baz::<-1, -2>(); // ok
3223
baz::<1 + 2, 3 + 4>();
3324
//~^ ERROR complex const arguments must be surrounded by braces
3425
//~| ERROR complex const arguments must be surrounded by braces
26+
baz::< -1 , 2 >(); // ok
27+
baz::< -1 , "2" >(); //~ ERROR mismatched types
28+
29+
bat::<(1, 2, 3)>(); //~ ERROR complex const arguments must be surrounded by braces
30+
bat::<(1, 2)>();
31+
//~^ ERROR complex const arguments must be surrounded by braces
32+
//~| ERROR mismatched types
33+
34+
bar::<false>(); // ok
35+
bar::<!false>(); //~ ERROR complex const arguments must be surrounded by braces
3536
}
3637

37-
fn main() {
38-
i32_identity::<5>(); // ok
38+
fn parse_err_1() {
39+
bar::< 3 < 4 >(); //~ ERROR expected one of `,` or `>`, found `<`
3940
}
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
11
error: complex const arguments must be surrounded by braces
2-
--> $DIR/const-expression-parameter.rs:13:20
2+
--> $DIR/const-expression-parameter.rs:14:11
33
|
4-
LL | i32_identity::<1 + 2>();
5-
| ^^^^^
4+
LL | foo::<1 + 2>();
5+
| ^^^^^
66
help: surround this const argument in braces
77
|
8-
LL | i32_identity::<{ 1 + 2 }>();
9-
| ^ ^
8+
LL | foo::<{ 1 + 2 }>();
9+
| ^ ^
1010

1111
error: complex const arguments must be surrounded by braces
12-
--> $DIR/const-expression-parameter.rs:21:20
12+
--> $DIR/const-expression-parameter.rs:16:11
1313
|
14-
LL | i32_identity::<1 + 2, 3 + 4>();
15-
| ^^^^^
14+
LL | foo::<1 + 2, 3 + 4>();
15+
| ^^^^^
1616
help: surround this const argument in braces
1717
|
18-
LL | i32_identity::<{ 1 + 2 }, 3 + 4>();
19-
| ^ ^
18+
LL | foo::<{ 1 + 2 }, 3 + 4>();
19+
| ^ ^
2020

2121
error: complex const arguments must be surrounded by braces
22-
--> $DIR/const-expression-parameter.rs:21:27
22+
--> $DIR/const-expression-parameter.rs:16:18
2323
|
24-
LL | i32_identity::<1 + 2, 3 + 4>();
25-
| ^^^^^
24+
LL | foo::<1 + 2, 3 + 4>();
25+
| ^^^^^
2626
help: surround this const argument in braces
2727
|
28-
LL | i32_identity::<1 + 2, { 3 + 4 }>();
29-
| ^ ^
28+
LL | foo::<1 + 2, { 3 + 4 }>();
29+
| ^ ^
3030

3131
error: complex const arguments must be surrounded by braces
32-
--> $DIR/const-expression-parameter.rs:32:11
32+
--> $DIR/const-expression-parameter.rs:23:11
3333
|
3434
LL | baz::<1 + 2, 3 + 4>();
3535
| ^^^^^
@@ -39,7 +39,7 @@ LL | baz::<{ 1 + 2 }, 3 + 4>();
3939
| ^ ^
4040

4141
error: complex const arguments must be surrounded by braces
42-
--> $DIR/const-expression-parameter.rs:32:18
42+
--> $DIR/const-expression-parameter.rs:23:18
4343
|
4444
LL | baz::<1 + 2, 3 + 4>();
4545
| ^^^^^
@@ -48,6 +48,42 @@ help: surround this const argument in braces
4848
LL | baz::<1 + 2, { 3 + 4 }>();
4949
| ^ ^
5050

51+
error: complex const arguments must be surrounded by braces
52+
--> $DIR/const-expression-parameter.rs:29:11
53+
|
54+
LL | bat::<(1, 2, 3)>();
55+
| ^^^^^^^^^
56+
help: surround this const argument in braces
57+
|
58+
LL | bat::<{ (1, 2, 3) }>();
59+
| ^ ^
60+
61+
error: complex const arguments must be surrounded by braces
62+
--> $DIR/const-expression-parameter.rs:30:11
63+
|
64+
LL | bat::<(1, 2)>();
65+
| ^^^^^^
66+
help: surround this const argument in braces
67+
|
68+
LL | bat::<{ (1, 2) }>();
69+
| ^ ^
70+
71+
error: complex const arguments must be surrounded by braces
72+
--> $DIR/const-expression-parameter.rs:35:11
73+
|
74+
LL | bar::<!false>();
75+
| ^^^^^^
76+
help: surround this const argument in braces
77+
|
78+
LL | bar::<{ !false }>();
79+
| ^ ^
80+
81+
error: expected one of `,` or `>`, found `<`
82+
--> $DIR/const-expression-parameter.rs:39:14
83+
|
84+
LL | bar::< 3 < 4 >();
85+
| ^ expected one of `,` or `>` here
86+
5187
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
5288
--> $DIR/const-expression-parameter.rs:1:12
5389
|
@@ -57,11 +93,30 @@ LL | #![feature(const_generics)]
5793
= note: `#[warn(incomplete_features)]` on by default
5894

5995
error[E0107]: wrong number of const arguments: expected 1, found 2
60-
--> $DIR/const-expression-parameter.rs:21:27
96+
--> $DIR/const-expression-parameter.rs:16:18
97+
|
98+
LL | foo::<1 + 2, 3 + 4>();
99+
| ^^^^^ unexpected const argument
100+
101+
error[E0308]: mismatched types
102+
--> $DIR/const-expression-parameter.rs:27:17
103+
|
104+
LL | baz::< -1 , "2" >();
105+
| ^^^ expected i32, found reference
106+
|
107+
= note: expected type `i32`
108+
found type `&'static str`
109+
110+
error[E0308]: mismatched types
111+
--> $DIR/const-expression-parameter.rs:30:11
112+
|
113+
LL | bat::<(1, 2)>();
114+
| ^^^^^^ expected a tuple with 3 elements, found one with 2 elements
61115
|
62-
LL | i32_identity::<1 + 2, 3 + 4>();
63-
| ^^^^^ unexpected const argument
116+
= note: expected type `(i32, i32, i32)`
117+
found type `(i32, i32)`
64118

65-
error: aborting due to 6 previous errors
119+
error: aborting due to 12 previous errors
66120

67-
For more information about this error, try `rustc --explain E0107`.
121+
Some errors have detailed explanations: E0107, E0308.
122+
For more information about an error, try `rustc --explain E0107`.

0 commit comments

Comments
 (0)