Detect and provide suggestion for &raw EXPR

This commit is contained in:
Michael Goulet 2025-04-04 21:36:03 +00:00
parent 82eb03ec62
commit 6dfbe7c986
6 changed files with 189 additions and 1 deletions

View file

@ -609,6 +609,8 @@ impl<'a> Parser<'a> {
// FIXME: translation requires list formatting (for `expect`)
let mut err = self.dcx().struct_span_err(self.token.span, msg_exp);
self.label_expected_raw_ref(&mut err);
// Look for usages of '=>' where '>=' was probably intended
if self.token == token::FatArrow
&& expected.iter().any(|tok| matches!(tok, TokenType::Operator | TokenType::Le))
@ -750,6 +752,25 @@ impl<'a> Parser<'a> {
Err(err)
}
/// Adds a label when `&raw EXPR` was written instead of `&raw const EXPR`/`&raw mut EXPR`.
///
/// Given that not all parser diagnostics flow through `expected_one_of_not_found`, this
/// label may need added to other diagnostics emission paths as needed.
pub(super) fn label_expected_raw_ref(&mut self, err: &mut Diag<'_>) {
if self.prev_token.is_keyword(kw::Raw)
&& self.expected_token_types.contains(TokenType::KwMut)
&& self.expected_token_types.contains(TokenType::KwConst)
&& self.token.can_begin_expr()
{
err.span_suggestions(
self.prev_token.span.shrink_to_hi(),
"`&raw` must be followed by `const` or `mut` to be a raw reference expression",
[" const".to_string(), " mut".to_string()],
Applicability::MaybeIncorrect,
);
}
}
/// Checks if the current token or the previous token are misspelled keywords
/// and adds a helpful suggestion.
fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) {

View file

@ -829,6 +829,18 @@ impl<'a> Parser<'a> {
if let Some(lt) = lifetime {
self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
}
// Add expected tokens if we parsed `&raw` as an expression.
// This will make sure we see "expected `const`, `mut`", and
// guides recovery in case we write `&raw expr`.
if borrow_kind == ast::BorrowKind::Ref
&& mutbl == ast::Mutability::Not
&& matches!(&expr.kind, ExprKind::Path(None, p) if p.is_ident(kw::Raw))
{
self.expected_token_types.insert(TokenType::KwMut);
self.expected_token_types.insert(TokenType::KwConst);
}
Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
}

View file

@ -516,7 +516,11 @@ impl<'a> Parser<'a> {
let prev = self.prev_token.span;
let sp = self.token.span;
let mut e = self.dcx().struct_span_err(sp, msg);
let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
self.label_expected_raw_ref(&mut e);
let do_not_suggest_help = self.token.is_keyword(kw::In)
|| self.token == token::Colon
|| self.prev_token.is_keyword(kw::Raw);
// Check to see if the user has written something like
//