Skip to content

Commit e17e611

Browse files
authored
Unrolled build for rust-lang#139392
Rollup merge of rust-lang#139392 - compiler-errors:raw-expr, r=oli-obk Detect and provide suggestion for `&raw EXPR` When emitting an error in the parser, and we detect that the previous token was `raw` and we *could* have consumed `const`/`mut`, suggest that this may have been a mistyped raw ref expr. To do this, we add `const`/`mut` to the expected token set when parsing `&raw` as an expression (which does not affect the "good path" of parsing, for the record). This is kind of a rudimentary error improvement, since it doesn't actually attempt to recover anything, leading to some other knock-on errors b/c we still treat `&raw` as the expression that was parsed... but at least we add the suggestion! I don't think the parser grammar means we can faithfully recover `&raw EXPR` early, i.e. during `parse_expr_borrow`. Fixes rust-lang#133231
2 parents 07d3fd1 + 6dfbe7c commit e17e611

File tree

6 files changed

+189
-1
lines changed

6 files changed

+189
-1
lines changed

compiler/rustc_ast/src/ast.rs

+11
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,17 @@ impl Path {
120120
Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None }
121121
}
122122

123+
pub fn is_ident(&self, name: Symbol) -> bool {
124+
if let [segment] = self.segments.as_ref()
125+
&& segment.args.is_none()
126+
&& segment.ident.name == name
127+
{
128+
true
129+
} else {
130+
false
131+
}
132+
}
133+
123134
pub fn is_global(&self) -> bool {
124135
self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot)
125136
}

compiler/rustc_parse/src/parser/diagnostics.rs

+21
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,8 @@ impl<'a> Parser<'a> {
609609
// FIXME: translation requires list formatting (for `expect`)
610610
let mut err = self.dcx().struct_span_err(self.token.span, msg_exp);
611611

612+
self.label_expected_raw_ref(&mut err);
613+
612614
// Look for usages of '=>' where '>=' was probably intended
613615
if self.token == token::FatArrow
614616
&& expected.iter().any(|tok| matches!(tok, TokenType::Operator | TokenType::Le))
@@ -750,6 +752,25 @@ impl<'a> Parser<'a> {
750752
Err(err)
751753
}
752754

755+
/// Adds a label when `&raw EXPR` was written instead of `&raw const EXPR`/`&raw mut EXPR`.
756+
///
757+
/// Given that not all parser diagnostics flow through `expected_one_of_not_found`, this
758+
/// label may need added to other diagnostics emission paths as needed.
759+
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+
{
765+
err.span_suggestions(
766+
self.prev_token.span.shrink_to_hi(),
767+
"`&raw` must be followed by `const` or `mut` to be a raw reference expression",
768+
[" const".to_string(), " mut".to_string()],
769+
Applicability::MaybeIncorrect,
770+
);
771+
}
772+
}
773+
753774
/// Checks if the current token or the previous token are misspelled keywords
754775
/// and adds a helpful suggestion.
755776
fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) {

compiler/rustc_parse/src/parser/expr.rs

+12
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,18 @@ impl<'a> Parser<'a> {
827827
if let Some(lt) = lifetime {
828828
self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
829829
}
830+
831+
// Add expected tokens if we parsed `&raw` as an expression.
832+
// This will make sure we see "expected `const`, `mut`", and
833+
// guides recovery in case we write `&raw expr`.
834+
if borrow_kind == ast::BorrowKind::Ref
835+
&& mutbl == ast::Mutability::Not
836+
&& matches!(&expr.kind, ExprKind::Path(None, p) if p.is_ident(kw::Raw))
837+
{
838+
self.expected_token_types.insert(TokenType::KwMut);
839+
self.expected_token_types.insert(TokenType::KwConst);
840+
}
841+
830842
Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
831843
}
832844

compiler/rustc_parse/src/parser/stmt.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,11 @@ impl<'a> Parser<'a> {
518518
let prev = self.prev_token.span;
519519
let sp = self.token.span;
520520
let mut e = self.dcx().struct_span_err(sp, msg);
521-
let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
521+
self.label_expected_raw_ref(&mut e);
522+
523+
let do_not_suggest_help = self.token.is_keyword(kw::In)
524+
|| self.token == token::Colon
525+
|| self.prev_token.is_keyword(kw::Raw);
522526

523527
// Check to see if the user has written something like
524528
//
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
fn a() {
2+
let x = &raw 1;
3+
//~^ ERROR expected one of
4+
}
5+
6+
fn b() {
7+
[&raw const 1, &raw 2]
8+
//~^ ERROR expected one of
9+
//~| ERROR cannot find value `raw` in this scope
10+
//~| ERROR cannot take address of a temporary
11+
}
12+
13+
fn c() {
14+
if x == &raw z {}
15+
//~^ ERROR expected `{`
16+
}
17+
18+
fn d() {
19+
f(&raw 2);
20+
//~^ ERROR expected one of
21+
//~| ERROR cannot find value `raw` in this scope
22+
//~| ERROR cannot find function `f` in this scope
23+
}
24+
25+
fn e() {
26+
let x;
27+
x = &raw 1;
28+
//~^ ERROR expected one of
29+
}
30+
31+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
error: expected one of `!`, `.`, `::`, `;`, `?`, `const`, `else`, `mut`, `{`, or an operator, found `1`
2+
--> $DIR/raw-no-const-mut.rs:2:18
3+
|
4+
LL | let x = &raw 1;
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 | let x = &raw const 1;
10+
| +++++
11+
LL | let x = &raw mut 1;
12+
| +++
13+
14+
error: expected one of `!`, `,`, `.`, `::`, `?`, `]`, `const`, `mut`, `{`, or an operator, found `2`
15+
--> $DIR/raw-no-const-mut.rs:7:25
16+
|
17+
LL | [&raw const 1, &raw 2]
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 | [&raw const 1, &raw const 2]
23+
| +++++
24+
LL | [&raw const 1, &raw mut 2]
25+
| +++
26+
help: missing `,`
27+
|
28+
LL | [&raw const 1, &raw, 2]
29+
| +
30+
31+
error: expected `{`, found `z`
32+
--> $DIR/raw-no-const-mut.rs:14:18
33+
|
34+
LL | if x == &raw z {}
35+
| ^ expected `{`
36+
|
37+
note: the `if` expression is missing a block after this condition
38+
--> $DIR/raw-no-const-mut.rs:14:8
39+
|
40+
LL | if x == &raw z {}
41+
| ^^^^^^^^^
42+
help: `&raw` must be followed by `const` or `mut` to be a raw reference expression
43+
|
44+
LL | if x == &raw const z {}
45+
| +++++
46+
LL | if x == &raw mut z {}
47+
| +++
48+
49+
error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `const`, `mut`, `{`, or an operator, found `2`
50+
--> $DIR/raw-no-const-mut.rs:19:12
51+
|
52+
LL | f(&raw 2);
53+
| ^ expected one of 10 possible tokens
54+
|
55+
help: `&raw` must be followed by `const` or `mut` to be a raw reference expression
56+
|
57+
LL | f(&raw const 2);
58+
| +++++
59+
LL | f(&raw mut 2);
60+
| +++
61+
help: missing `,`
62+
|
63+
LL | f(&raw, 2);
64+
| +
65+
66+
error: expected one of `!`, `.`, `::`, `;`, `?`, `const`, `mut`, `{`, `}`, or an operator, found `1`
67+
--> $DIR/raw-no-const-mut.rs:27:14
68+
|
69+
LL | x = &raw 1;
70+
| ^ expected one of 10 possible tokens
71+
|
72+
help: `&raw` must be followed by `const` or `mut` to be a raw reference expression
73+
|
74+
LL | x = &raw const 1;
75+
| +++++
76+
LL | x = &raw mut 1;
77+
| +++
78+
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+
97+
error[E0425]: cannot find function `f` in this scope
98+
--> $DIR/raw-no-const-mut.rs:19:5
99+
|
100+
LL | fn a() {
101+
| ------ similarly named function `a` defined here
102+
...
103+
LL | f(&raw 2);
104+
| ^ help: a function with a similar name exists: `a`
105+
106+
error: aborting due to 9 previous errors
107+
108+
Some errors have detailed explanations: E0425, E0745.
109+
For more information about an error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)