diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index d50bd18a1d7d8..7cd053a2fa245 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -764,6 +764,8 @@ parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attri parse_sugg_add_let_for_stmt = you might have meant to introduce a new binding +parse_sugg_add_mut_or_const_in_raw_ref = you might have meant to use a raw reference + parse_sugg_add_semi = add `;` here parse_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 9ee6c2fae1ac0..3c084bd3ae6c8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1303,6 +1303,22 @@ impl<'a> Parser<'a> { Err(e) } + /// When writing `&raw` that is missing the following `mut` or `const`, we will + /// encounter a parse error when encountering the next expression. + pub(super) fn suggest_add_mut_or_const_in_raw_ref(&mut self, e: &mut Diag<'_>, expr: &P) { + if let ExprKind::AddrOf(ast::BorrowKind::Ref, ast::Mutability::Not, r) = &expr.kind + && let ast::ExprKind::Path(_, p) = &r.kind + && *p == Symbol::intern("raw") + { + e.span_suggestions( + expr.span.shrink_to_hi(), + fluent::parse_sugg_add_mut_or_const_in_raw_ref, + [" mut".to_string(), " const".to_string()], + Applicability::HasPlaceholders, + ); + } + } + /// Suggest add the missing `let` before the identifier in stmt /// `a: Ty = 1` -> `let a: Ty = 1` pub(super) fn suggest_add_missing_let_for_stmt(&mut self, err: &mut Diag<'a>) { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 7533e75ffe261..9497c0a0d307c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1581,7 +1581,10 @@ impl<'a> Parser<'a> { ExprKind::Array(exprs) } else { // Vector with one element - self.expect(close)?; + self.expect(close).map_err(|mut e| { + self.suggest_add_mut_or_const_in_raw_ref(&mut e, &first_expr); + e + })?; ExprKind::Array(thin_vec![first_expr]) } }; diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1ddb5fc0a1169..ff3990961a727 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -897,6 +897,7 @@ impl<'a> Parser<'a> { res? } else { res.unwrap_or_else(|mut e| { + self.suggest_add_mut_or_const_in_raw_ref(&mut e, expr); self.recover_missing_dot(&mut e); let guar = e.emit(); self.recover_stmt(); @@ -920,6 +921,7 @@ impl<'a> Parser<'a> { LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => { self.check_mistyped_turbofish_with_multiple_type_params(e, expr).map_err( |mut e| { + self.suggest_add_mut_or_const_in_raw_ref(&mut e, expr); self.recover_missing_dot(&mut e); e }, diff --git a/tests/ui/raw-ref-op/missing-modifier/let-stmt.rs b/tests/ui/raw-ref-op/missing-modifier/let-stmt.rs new file mode 100644 index 0000000000000..b20e8a0511d93 --- /dev/null +++ b/tests/ui/raw-ref-op/missing-modifier/let-stmt.rs @@ -0,0 +1,12 @@ +//! Check that `&raw` that isn't followed by `const` or `mut` produces a +//! helpful error message. +//! +//! Related issue: . + +fn main() { + let foo = 2; + let _ = &raw foo; + //~^ ERROR expected one of + //~| HELP you might have meant to use a raw reference + //~| HELP you might have meant to write a field access +} diff --git a/tests/ui/raw-ref-op/missing-modifier/let-stmt.stderr b/tests/ui/raw-ref-op/missing-modifier/let-stmt.stderr new file mode 100644 index 0000000000000..ef2ce3758c680 --- /dev/null +++ b/tests/ui/raw-ref-op/missing-modifier/let-stmt.stderr @@ -0,0 +1,19 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `foo` + --> $DIR/let-stmt.rs:8:18 + | +LL | let _ = &raw foo; + | ^^^ expected one of 8 possible tokens + | +help: you might have meant to use a raw reference + | +LL | let _ = &raw mut foo; + | +++ +LL | let _ = &raw const foo; + | +++++ +help: you might have meant to write a field access + | +LL | let _ = &raw.foo; + | + + +error: aborting due to 1 previous error + diff --git a/tests/ui/raw-ref-op/missing-modifier/nested-array-expr.rs b/tests/ui/raw-ref-op/missing-modifier/nested-array-expr.rs new file mode 100644 index 0000000000000..088a169ba56c3 --- /dev/null +++ b/tests/ui/raw-ref-op/missing-modifier/nested-array-expr.rs @@ -0,0 +1,14 @@ +//! Check that `&raw` that isn't followed by `const` or `mut` produces a +//! helpful error message. +//! +//! Related issue: . + +mod foo { + pub static A: i32 = 0; +} + +fn main() { + [&raw foo::A; 3]; + //~^ ERROR expected one of + //~| HELP you might have meant to use a raw reference +} diff --git a/tests/ui/raw-ref-op/missing-modifier/nested-array-expr.stderr b/tests/ui/raw-ref-op/missing-modifier/nested-array-expr.stderr new file mode 100644 index 0000000000000..9fddef26787c5 --- /dev/null +++ b/tests/ui/raw-ref-op/missing-modifier/nested-array-expr.stderr @@ -0,0 +1,15 @@ +error: expected one of `!`, `,`, `.`, `::`, `;`, `?`, `]`, `{`, or an operator, found `foo` + --> $DIR/nested-array-expr.rs:11:11 + | +LL | [&raw foo::A; 3]; + | ^^^ expected one of 9 possible tokens + | +help: you might have meant to use a raw reference + | +LL | [&raw mut foo::A; 3]; + | +++ +LL | [&raw const foo::A; 3]; + | +++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/raw-ref-op/missing-modifier/return-expr.rs b/tests/ui/raw-ref-op/missing-modifier/return-expr.rs new file mode 100644 index 0000000000000..82ec1f29699b1 --- /dev/null +++ b/tests/ui/raw-ref-op/missing-modifier/return-expr.rs @@ -0,0 +1,16 @@ +//! Check that `&raw` that isn't followed by `const` or `mut` produces a +//! helpful error message. +//! +//! Related issue: . + +mod foo { + pub static A: i32 = 0; +} + +fn get_ref() -> *const i32 { + &raw foo::A + //~^ ERROR expected one of + //~| HELP you might have meant to use a raw reference +} + +fn main() {} diff --git a/tests/ui/raw-ref-op/missing-modifier/return-expr.stderr b/tests/ui/raw-ref-op/missing-modifier/return-expr.stderr new file mode 100644 index 0000000000000..2371312af6a12 --- /dev/null +++ b/tests/ui/raw-ref-op/missing-modifier/return-expr.stderr @@ -0,0 +1,15 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `foo` + --> $DIR/return-expr.rs:11:10 + | +LL | &raw foo::A + | ^^^ expected one of 8 possible tokens + | +help: you might have meant to use a raw reference + | +LL | &raw mut foo::A + | +++ +LL | &raw const foo::A + | +++++ + +error: aborting due to 1 previous error +