Skip to content

Commit 3f0676c

Browse files
Rollup merge of rust-lang#157079 - qaijuang:raw-expr-list-recovery, r=Kivooeo
Don't recover `&raw EXPR` as a missing comma The parser already has a targeted suggestion for `&raw EXPR`, added in rust-lang#139392, telling the user that `&raw` must be followed by `const` or `mut`. In comma-separated expression lists, the generic missing-comma recovery would then treat the expression after `raw` as the next list element. That produced follow-up diagnostics like: - `help: missing ','` - `cannot find value raw in this scope` - an arity error for calls such as `takes_raw_ptr(&raw x)` This PR avoids that comma recovery when we are already in the `&raw` missing-`const`/`mut` diagnostic path. For function calls, it preserves the call expression with a single error argument, so useful later diagnostics such as `cannot find function f` are still emitted. Fixes rust-lang#157015.
2 parents 55885d4 + 68381b1 commit 3f0676c

7 files changed

Lines changed: 88 additions & 45 deletions

File tree

compiler/rustc_parse/src/parser/diagnostics.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -752,16 +752,19 @@ impl<'a> Parser<'a> {
752752
Err(err)
753753
}
754754

755+
pub(super) fn is_expected_raw_ref_mut(&self) -> bool {
756+
self.prev_token.is_keyword(kw::Raw)
757+
&& self.expected_token_types.contains(TokenType::KwMut)
758+
&& self.expected_token_types.contains(TokenType::KwConst)
759+
&& self.token.can_begin_expr()
760+
}
761+
755762
/// Adds a label when `&raw EXPR` was written instead of `&raw const EXPR`/`&raw mut EXPR`.
756763
///
757764
/// Given that not all parser diagnostics flow through `expected_one_of_not_found`, this
758765
/// label may need added to other diagnostics emission paths as needed.
759766
pub(super) fn label_expected_raw_ref(&mut self, err: &mut Diag<'_>) {
760-
if self.prev_token.is_keyword(kw::Raw)
761-
&& self.expected_token_types.contains(TokenType::KwMut)
762-
&& self.expected_token_types.contains(TokenType::KwConst)
763-
&& self.token.can_begin_expr()
764-
{
767+
if self.is_expected_raw_ref_mut() {
765768
err.span_suggestions(
766769
self.prev_token.span.shrink_to_hi(),
767770
"`&raw` must be followed by `const` or `mut` to be a raw reference expression",

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,15 +1279,38 @@ impl<'a> Parser<'a> {
12791279
};
12801280
let open_paren = self.token.span;
12811281

1282-
let seq = self
1283-
.parse_expr_paren_seq()
1284-
.map(|args| self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args)));
1282+
let seq = match self.parse_expr_paren_seq() {
1283+
Ok(args) => Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))),
1284+
Err(err) if self.is_expected_raw_ref_mut() => {
1285+
let guar = err.emit();
1286+
// Preserve the call expression so later passes can still diagnose the callee,
1287+
// while treating the malformed `&raw <expr>` argument as an error expression.
1288+
let args = self.recover_raw_ref_call_args(guar);
1289+
return self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args));
1290+
}
1291+
Err(err) => Err(err),
1292+
};
12851293
match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) {
12861294
Ok(expr) => expr,
12871295
Err(err) => self.recover_seq_parse_error(exp!(OpenParen), exp!(CloseParen), lo, err),
12881296
}
12891297
}
12901298

1299+
fn recover_raw_ref_call_args(&mut self, guar: ErrorGuaranteed) -> ThinVec<Box<Expr>> {
1300+
let err_span = self.prev_token.span.to(self.token.span);
1301+
let mut args = thin_vec![self.mk_expr_err(err_span, guar)];
1302+
while self.token != token::Eof && self.token != token::CloseParen {
1303+
if self.eat(exp!(Comma)) && self.token != token::Eof && self.token != token::CloseParen
1304+
{
1305+
args.push(self.mk_expr_err(self.prev_token.span.shrink_to_hi(), guar));
1306+
} else {
1307+
self.parse_token_tree();
1308+
}
1309+
}
1310+
let _ = self.eat(exp!(CloseParen));
1311+
args
1312+
}
1313+
12911314
/// If we encounter a parser state that looks like the user has written a `struct` literal with
12921315
/// parentheses instead of braces, recover the parser state and provide suggestions.
12931316
#[instrument(skip(self, seq, snapshot), level = "trace")]

compiler/rustc_parse/src/parser/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,13 @@ impl<'a> Parser<'a> {
917917
}
918918

919919
// Attempt to keep parsing if it was an omitted separator.
920+
// `&raw <expr>` already has a specific suggestion for missing
921+
// `const`/`mut`, so don't recover `<expr>` as the next element in
922+
// a comma-separated list.
923+
if exp.token_type == TokenType::Comma && self.is_expected_raw_ref_mut()
924+
{
925+
return Err(expect_err);
926+
}
920927
self.last_unexpected_token_span = None;
921928
match f(self) {
922929
Ok(t) => {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Regression test for https://github.com/rust-lang/rust/issues/157015.
2+
3+
fn takes_raw_ptr(_: *const u32) {}
4+
fn takes_raw_ptr_args(_: *const u32, _: *const u32) {}
5+
6+
fn main() {
7+
let x = 0u32;
8+
takes_raw_ptr(&raw x);
9+
//~^ ERROR expected one of
10+
takes_raw_ptr_args(&raw x, &raw x);
11+
//~^ ERROR expected one of
12+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `const`, `mut`, `{`, or an operator, found `x`
2+
--> $DIR/raw-no-const-mut-arg-list.rs:8:24
3+
|
4+
LL | takes_raw_ptr(&raw x);
5+
| ^ expected one of 10 possible tokens
6+
|
7+
help: `&raw` must be followed by `const` or `mut` to be a raw reference expression
8+
|
9+
LL | takes_raw_ptr(&raw const x);
10+
| +++++
11+
LL | takes_raw_ptr(&raw mut x);
12+
| +++
13+
14+
error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `const`, `mut`, `{`, or an operator, found `x`
15+
--> $DIR/raw-no-const-mut-arg-list.rs:10:29
16+
|
17+
LL | takes_raw_ptr_args(&raw x, &raw x);
18+
| ^ expected one of 10 possible tokens
19+
|
20+
help: `&raw` must be followed by `const` or `mut` to be a raw reference expression
21+
|
22+
LL | takes_raw_ptr_args(&raw const x, &raw x);
23+
| +++++
24+
LL | takes_raw_ptr_args(&raw mut x, &raw x);
25+
| +++
26+
27+
error: aborting due to 2 previous errors
28+

tests/ui/parser/recover/raw-no-const-mut.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ fn a() {
66
fn b() {
77
[&raw const 1, &raw 2]
88
//~^ ERROR expected one of
9-
//~| ERROR cannot find value `raw` in this scope
10-
//~| ERROR cannot take address of a temporary
119
}
1210

1311
fn c() {
@@ -18,7 +16,6 @@ fn c() {
1816
fn d() {
1917
f(&raw 2);
2018
//~^ ERROR expected one of
21-
//~| ERROR cannot find value `raw` in this scope
2219
//~| ERROR cannot find function `f` in this scope
2320
}
2421

tests/ui/parser/recover/raw-no-const-mut.stderr

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,15 @@ LL | [&raw const 1, &raw const 2]
2323
| +++++
2424
LL | [&raw const 1, &raw mut 2]
2525
| +++
26-
help: missing `,`
27-
|
28-
LL | [&raw const 1, &raw, 2]
29-
| +
3026

3127
error: expected `{`, found `z`
32-
--> $DIR/raw-no-const-mut.rs:14:18
28+
--> $DIR/raw-no-const-mut.rs:12:18
3329
|
3430
LL | if x == &raw z {}
3531
| ^ expected `{`
3632
|
3733
note: the `if` expression is missing a block after this condition
38-
--> $DIR/raw-no-const-mut.rs:14:8
34+
--> $DIR/raw-no-const-mut.rs:12:8
3935
|
4036
LL | if x == &raw z {}
4137
| ^^^^^^^^^
@@ -47,7 +43,7 @@ LL | if x == &raw mut z {}
4743
| +++
4844

4945
error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `const`, `mut`, `{`, or an operator, found `2`
50-
--> $DIR/raw-no-const-mut.rs:19:12
46+
--> $DIR/raw-no-const-mut.rs:17:12
5147
|
5248
LL | f(&raw 2);
5349
| ^ expected one of 10 possible tokens
@@ -58,13 +54,9 @@ LL | f(&raw const 2);
5854
| +++++
5955
LL | f(&raw mut 2);
6056
| +++
61-
help: missing `,`
62-
|
63-
LL | f(&raw, 2);
64-
| +
6557

6658
error: expected one of `!`, `.`, `::`, `;`, `?`, `const`, `mut`, `{`, `}`, or an operator, found `1`
67-
--> $DIR/raw-no-const-mut.rs:27:14
59+
--> $DIR/raw-no-const-mut.rs:24:14
6860
|
6961
LL | x = &raw 1;
7062
| ^ expected one of 10 possible tokens
@@ -76,26 +68,8 @@ LL | x = &raw const 1;
7668
LL | x = &raw mut 1;
7769
| +++
7870

79-
error[E0425]: cannot find value `raw` in this scope
80-
--> $DIR/raw-no-const-mut.rs:7:21
81-
|
82-
LL | [&raw const 1, &raw 2]
83-
| ^^^ not found in this scope
84-
85-
error[E0425]: cannot find value `raw` in this scope
86-
--> $DIR/raw-no-const-mut.rs:19:8
87-
|
88-
LL | f(&raw 2);
89-
| ^^^ not found in this scope
90-
91-
error[E0745]: cannot take address of a temporary
92-
--> $DIR/raw-no-const-mut.rs:7:17
93-
|
94-
LL | [&raw const 1, &raw 2]
95-
| ^ temporary value
96-
9771
error[E0425]: cannot find function `f` in this scope
98-
--> $DIR/raw-no-const-mut.rs:19:5
72+
--> $DIR/raw-no-const-mut.rs:17:5
9973
|
10074
LL | fn a() {
10175
| ------ similarly named function `a` defined here
@@ -109,7 +83,6 @@ LL - f(&raw 2);
10983
LL + a(&raw 2);
11084
|
11185

112-
error: aborting due to 9 previous errors
86+
error: aborting due to 6 previous errors
11387

114-
Some errors have detailed explanations: E0425, E0745.
115-
For more information about an error, try `rustc --explain E0425`.
88+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)