Skip to content

Commit 7c3331c

Browse files
committed
Auto merge of rust-lang#92884 - compiler-errors:const-generic-expr-recovery, r=jackh726
Suggest adding `{ .. }` around more bad const generic exprs Fixes rust-lang#92776
2 parents 12b71ed + 6b52ac2 commit 7c3331c

File tree

4 files changed

+121
-18
lines changed

4 files changed

+121
-18
lines changed

compiler/rustc_parse/src/parser/diagnostics.rs

+23-16
Original file line numberDiff line numberDiff line change
@@ -2030,7 +2030,7 @@ impl<'a> Parser<'a> {
20302030
start: Span,
20312031
mut err: DiagnosticBuilder<'a, ErrorReported>,
20322032
) -> PResult<'a, GenericArg> {
2033-
let is_op = AssocOp::from_token(&self.token)
2033+
let is_op_or_dot = AssocOp::from_token(&self.token)
20342034
.and_then(|op| {
20352035
if let AssocOp::Greater
20362036
| AssocOp::Less
@@ -2046,17 +2046,18 @@ impl<'a> Parser<'a> {
20462046
Some(op)
20472047
}
20482048
})
2049-
.is_some();
2049+
.is_some()
2050+
|| self.token.kind == TokenKind::Dot;
20502051
// This will be true when a trait object type `Foo +` or a path which was a `const fn` with
20512052
// type params has been parsed.
20522053
let was_op =
20532054
matches!(self.prev_token.kind, token::BinOp(token::Plus | token::Shr) | token::Gt);
2054-
if !is_op && !was_op {
2055+
if !is_op_or_dot && !was_op {
20552056
// We perform these checks and early return to avoid taking a snapshot unnecessarily.
20562057
return Err(err);
20572058
}
20582059
let snapshot = self.clone();
2059-
if is_op {
2060+
if is_op_or_dot {
20602061
self.bump();
20612062
}
20622063
match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
@@ -2080,18 +2081,7 @@ impl<'a> Parser<'a> {
20802081
// |
20812082
// LL | let sr: Vec<{ (u32, _, _) = vec![] };
20822083
// | ^ ^
2083-
err.multipart_suggestion(
2084-
"expressions must be enclosed in braces to be used as const generic \
2085-
arguments",
2086-
vec![
2087-
(start.shrink_to_lo(), "{ ".to_string()),
2088-
(expr.span.shrink_to_hi(), " }".to_string()),
2089-
],
2090-
Applicability::MaybeIncorrect,
2091-
);
2092-
let value = self.mk_expr_err(start.to(expr.span));
2093-
err.emit();
2094-
return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
2084+
return Ok(self.dummy_const_arg_needs_braces(err, start.to(expr.span)));
20952085
}
20962086
}
20972087
Err(err) => {
@@ -2102,6 +2092,23 @@ impl<'a> Parser<'a> {
21022092
Err(err)
21032093
}
21042094

2095+
/// Creates a dummy const argument, and reports that the expression must be enclosed in braces
2096+
pub fn dummy_const_arg_needs_braces(
2097+
&self,
2098+
mut err: DiagnosticBuilder<'a, ErrorReported>,
2099+
span: Span,
2100+
) -> GenericArg {
2101+
err.multipart_suggestion(
2102+
"expressions must be enclosed in braces to be used as const generic \
2103+
arguments",
2104+
vec![(span.shrink_to_lo(), "{ ".to_string()), (span.shrink_to_hi(), " }".to_string())],
2105+
Applicability::MaybeIncorrect,
2106+
);
2107+
let value = self.mk_expr_err(span);
2108+
err.emit();
2109+
GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
2110+
}
2111+
21052112
/// Get the diagnostics for the cases where `move async` is found.
21062113
///
21072114
/// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword

compiler/rustc_parse/src/parser/path.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
2-
use super::{Parser, TokenType};
2+
use super::{Parser, Restrictions, TokenType};
33
use crate::maybe_whole;
44
use rustc_ast::ptr::P;
55
use rustc_ast::token::{self, Token};
@@ -634,7 +634,22 @@ impl<'a> Parser<'a> {
634634
} else if self.token.is_keyword(kw::Const) {
635635
return self.recover_const_param_declaration(ty_generics);
636636
} else {
637-
return Ok(None);
637+
// Fall back by trying to parse a const-expr expression. If we successfully do so,
638+
// then we should report an error that it needs to be wrapped in braces.
639+
let snapshot = self.clone();
640+
match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
641+
Ok(expr) => {
642+
return Ok(Some(self.dummy_const_arg_needs_braces(
643+
self.struct_span_err(expr.span, "invalid const generic expression"),
644+
expr.span,
645+
)));
646+
}
647+
Err(err) => {
648+
*self = snapshot;
649+
err.cancel();
650+
return Ok(None);
651+
}
652+
}
638653
};
639654
Ok(Some(arg))
640655
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
struct Wow<const N: usize>;
2+
3+
fn main() {
4+
let _: Wow<if true {}>;
5+
//~^ ERROR invalid const generic expression
6+
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
7+
let _: Wow<|| ()>;
8+
//~^ ERROR invalid const generic expression
9+
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
10+
let _: Wow<A.b>;
11+
//~^ ERROR expected one of
12+
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
13+
let _: Wow<A.0>;
14+
//~^ ERROR expected one of
15+
//~| HELP expressions must be enclosed in braces to be used as const generic arguments
16+
17+
// FIXME(compiler-errors): This one is still unsatisfying,
18+
// and probably a case I could see someone typing by accident..
19+
let _: Wow<[12]>;
20+
//~^ ERROR expected type, found
21+
//~| ERROR type provided when a constant was expected
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
error: invalid const generic expression
2+
--> $DIR/bad-const-generic-exprs.rs:4:16
3+
|
4+
LL | let _: Wow<if true {}>;
5+
| ^^^^^^^^^^
6+
|
7+
help: expressions must be enclosed in braces to be used as const generic arguments
8+
|
9+
LL | let _: Wow<{ if true {} }>;
10+
| + +
11+
12+
error: invalid const generic expression
13+
--> $DIR/bad-const-generic-exprs.rs:7:16
14+
|
15+
LL | let _: Wow<|| ()>;
16+
| ^^^^^
17+
|
18+
help: expressions must be enclosed in braces to be used as const generic arguments
19+
|
20+
LL | let _: Wow<{ || () }>;
21+
| + +
22+
23+
error: expected one of `,` or `>`, found `.`
24+
--> $DIR/bad-const-generic-exprs.rs:10:17
25+
|
26+
LL | let _: Wow<A.b>;
27+
| ^ expected one of `,` or `>`
28+
|
29+
help: expressions must be enclosed in braces to be used as const generic arguments
30+
|
31+
LL | let _: Wow<{ A.b }>;
32+
| + +
33+
34+
error: expected one of `,` or `>`, found `.`
35+
--> $DIR/bad-const-generic-exprs.rs:13:17
36+
|
37+
LL | let _: Wow<A.0>;
38+
| ^ expected one of `,` or `>`
39+
|
40+
help: expressions must be enclosed in braces to be used as const generic arguments
41+
|
42+
LL | let _: Wow<{ A.0 }>;
43+
| + +
44+
45+
error: expected type, found `12`
46+
--> $DIR/bad-const-generic-exprs.rs:19:17
47+
|
48+
LL | let _: Wow<[12]>;
49+
| ^^ expected type
50+
51+
error[E0747]: type provided when a constant was expected
52+
--> $DIR/bad-const-generic-exprs.rs:19:16
53+
|
54+
LL | let _: Wow<[12]>;
55+
| ^^^^
56+
57+
error: aborting due to 6 previous errors
58+
59+
For more information about this error, try `rustc --explain E0747`.

0 commit comments

Comments
 (0)