diff options
| author | Jonathan Brouwer <jonathantbrouwer@gmail.com> | 2025-08-28 20:03:58 +0200 |
|---|---|---|
| committer | Jonathan Brouwer <jonathantbrouwer@gmail.com> | 2025-08-28 20:05:04 +0200 |
| commit | f32870927604ab4dbf12ff84681b77e65a096940 (patch) | |
| tree | 20fa0e003a4ccc756fdd98eaa4cb887aa4875824 /compiler/rustc_attr_parsing/src | |
| parent | 2c7dfa91b5b4dcde136880894a9fd4dae70114db (diff) | |
| download | rust-f32870927604ab4dbf12ff84681b77e65a096940.tar.gz rust-f32870927604ab4dbf12ff84681b77e65a096940.zip | |
Improve error messages around invalid literals in attribute arguments
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
Diffstat (limited to 'compiler/rustc_attr_parsing/src')
| -rw-r--r-- | compiler/rustc_attr_parsing/src/parser.rs | 59 |
1 files changed, 36 insertions, 23 deletions
diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 6d3cf684296..4f903594225 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -10,11 +10,11 @@ use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path}; use rustc_ast_pretty::pprust; -use rustc_errors::PResult; +use rustc_errors::{Diag, PResult}; use rustc_hir::{self as hir, AttrPath}; use rustc_parse::exp; use rustc_parse::parser::{Parser, PathStyle, token_descr}; -use rustc_session::errors::report_lit_error; +use rustc_session::errors::{create_lit_error, report_lit_error}; use rustc_session::parse::ParseSess; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym}; use thin_vec::ThinVec; @@ -379,22 +379,23 @@ struct MetaItemListParserContext<'a, 'sess> { impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> { - let uninterpolated_span = self.parser.token_uninterpolated_span(); - let Some(token_lit) = self.parser.eat_token_lit() else { - return self.parser.handle_missing_lit(Parser::mk_meta_item_lit_char); - }; + let Some(token_lit) = self.parser.eat_token_lit() else { return Err(self.expected_lit()) }; + self.unsuffixed_meta_item_from_lit(token_lit) + } + fn unsuffixed_meta_item_from_lit( + &mut self, + token_lit: token::Lit, + ) -> PResult<'sess, MetaItemLit> { let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) { Ok(lit) => lit, Err(err) => { - let guar = - report_lit_error(&self.parser.psess, err, token_lit, uninterpolated_span); - // Pack possible quotes and prefixes from the original literal into - // the error literal's symbol so they can be pretty-printed faithfully. - let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None); - let symbol = Symbol::intern(&suffixless_lit.to_string()); - let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix); - MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap() + return Err(create_lit_error( + &self.parser.psess, + err, + token_lit, + self.parser.prev_token_uninterpolated_span(), + )); } }; @@ -448,16 +449,28 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { } fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> { - match self.parse_unsuffixed_meta_item_lit() { - Ok(lit) => return Ok(MetaItemOrLitParser::Lit(lit)), - Err(err) => err.cancel(), // we provide a better error below - } - - match self.parse_attr_item() { - Ok(mi) => return Ok(MetaItemOrLitParser::MetaItemParser(mi)), - Err(err) => err.cancel(), // we provide a better error below + if let Some(token_lit) = self.parser.eat_token_lit() { + // If a literal token is parsed, we commit to parsing a MetaItemLit for better errors + Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?)) + } else { + let prev_pros = self.parser.approx_token_stream_pos(); + match self.parse_attr_item() { + Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)), + Err(err) => { + // If `parse_attr_item` made any progress, it likely has a more precise error we should prefer + // If it didn't make progress we use the `expected_lit` from below + if self.parser.approx_token_stream_pos() != prev_pros { + Err(err) + } else { + err.cancel(); + Err(self.expected_lit()) + } + } + } } + } + fn expected_lit(&mut self) -> Diag<'sess> { let mut err = InvalidMetaItem { span: self.parser.token.span, descr: token_descr(&self.parser.token), @@ -492,7 +505,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { self.parser.bump(); } - Err(self.parser.dcx().create_err(err)) + self.parser.dcx().create_err(err) } fn parse( |
