Skip to content

Commit 56c68e7

Browse files
Rollup merge of #145853 - JonathanBrouwer:fix-lit-parsing, r=jdonszelmann
Improve error messages around invalid literals in attribute arguments r? `@jdonszelmann` This previously created two errors, which is a bit ugly and the second one didn't add any value Blocked on #143193
2 parents 9e4a283 + e0bdc46 commit 56c68e7

File tree

5 files changed

+64
-71
lines changed

5 files changed

+64
-71
lines changed

compiler/rustc_attr_parsing/src/parser.rs

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ use rustc_ast::token::{self, Delimiter, MetaVarKind};
1010
use rustc_ast::tokenstream::TokenStream;
1111
use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path};
1212
use rustc_ast_pretty::pprust;
13-
use rustc_errors::PResult;
13+
use rustc_errors::{Diag, PResult};
1414
use rustc_hir::{self as hir, AttrPath};
1515
use rustc_parse::exp;
1616
use rustc_parse::parser::{Parser, PathStyle, token_descr};
17-
use rustc_session::errors::report_lit_error;
17+
use rustc_session::errors::{create_lit_error, report_lit_error};
1818
use rustc_session::parse::ParseSess;
1919
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
2020
use thin_vec::ThinVec;
@@ -379,22 +379,23 @@ struct MetaItemListParserContext<'a, 'sess> {
379379

380380
impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
381381
fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> {
382-
let uninterpolated_span = self.parser.token_uninterpolated_span();
383-
let Some(token_lit) = self.parser.eat_token_lit() else {
384-
return self.parser.handle_missing_lit(Parser::mk_meta_item_lit_char);
385-
};
382+
let Some(token_lit) = self.parser.eat_token_lit() else { return Err(self.expected_lit()) };
383+
self.unsuffixed_meta_item_from_lit(token_lit)
384+
}
386385

386+
fn unsuffixed_meta_item_from_lit(
387+
&mut self,
388+
token_lit: token::Lit,
389+
) -> PResult<'sess, MetaItemLit> {
387390
let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) {
388391
Ok(lit) => lit,
389392
Err(err) => {
390-
let guar =
391-
report_lit_error(&self.parser.psess, err, token_lit, uninterpolated_span);
392-
// Pack possible quotes and prefixes from the original literal into
393-
// the error literal's symbol so they can be pretty-printed faithfully.
394-
let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None);
395-
let symbol = Symbol::intern(&suffixless_lit.to_string());
396-
let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix);
397-
MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap()
393+
return Err(create_lit_error(
394+
&self.parser.psess,
395+
err,
396+
token_lit,
397+
self.parser.prev_token_uninterpolated_span(),
398+
));
398399
}
399400
};
400401

@@ -448,16 +449,28 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
448449
}
449450

450451
fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> {
451-
match self.parse_unsuffixed_meta_item_lit() {
452-
Ok(lit) => return Ok(MetaItemOrLitParser::Lit(lit)),
453-
Err(err) => err.cancel(), // we provide a better error below
454-
}
455-
456-
match self.parse_attr_item() {
457-
Ok(mi) => return Ok(MetaItemOrLitParser::MetaItemParser(mi)),
458-
Err(err) => err.cancel(), // we provide a better error below
452+
if let Some(token_lit) = self.parser.eat_token_lit() {
453+
// If a literal token is parsed, we commit to parsing a MetaItemLit for better errors
454+
Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?))
455+
} else {
456+
let prev_pros = self.parser.approx_token_stream_pos();
457+
match self.parse_attr_item() {
458+
Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)),
459+
Err(err) => {
460+
// If `parse_attr_item` made any progress, it likely has a more precise error we should prefer
461+
// If it didn't make progress we use the `expected_lit` from below
462+
if self.parser.approx_token_stream_pos() != prev_pros {
463+
Err(err)
464+
} else {
465+
err.cancel();
466+
Err(self.expected_lit())
467+
}
468+
}
469+
}
459470
}
471+
}
460472

473+
fn expected_lit(&mut self) -> Diag<'sess> {
461474
let mut err = InvalidMetaItem {
462475
span: self.parser.token.span,
463476
descr: token_descr(&self.parser.token),
@@ -492,7 +505,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
492505
self.parser.bump();
493506
}
494507

495-
Err(self.parser.dcx().create_err(err))
508+
self.parser.dcx().create_err(err)
496509
}
497510

498511
fn parse(

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,7 +2077,7 @@ impl<'a> Parser<'a> {
20772077
(token::Lit { symbol: name, suffix: None, kind: token::Char }, span)
20782078
}
20792079

2080-
pub fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
2080+
fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
20812081
ast::MetaItemLit {
20822082
symbol: name,
20832083
suffix: None,
@@ -2086,7 +2086,7 @@ impl<'a> Parser<'a> {
20862086
}
20872087
}
20882088

2089-
pub fn handle_missing_lit<L>(
2089+
fn handle_missing_lit<L>(
20902090
&mut self,
20912091
mk_lit_char: impl FnOnce(Symbol, Span) -> L,
20922092
) -> PResult<'a, L> {

compiler/rustc_session/src/errors.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,10 @@ pub fn report_lit_error(
384384
lit: token::Lit,
385385
span: Span,
386386
) -> ErrorGuaranteed {
387+
create_lit_error(psess, err, lit, span).emit()
388+
}
389+
390+
pub fn create_lit_error(psess: &ParseSess, err: LitError, lit: token::Lit, span: Span) -> Diag<'_> {
387391
// Checks if `s` looks like i32 or u1234 etc.
388392
fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
389393
s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit())
@@ -414,32 +418,32 @@ pub fn report_lit_error(
414418
let dcx = psess.dcx();
415419
match err {
416420
LitError::InvalidSuffix(suffix) => {
417-
dcx.emit_err(InvalidLiteralSuffix { span, kind: lit.kind.descr(), suffix })
421+
dcx.create_err(InvalidLiteralSuffix { span, kind: lit.kind.descr(), suffix })
418422
}
419423
LitError::InvalidIntSuffix(suffix) => {
420424
let suf = suffix.as_str();
421425
if looks_like_width_suffix(&['i', 'u'], suf) {
422426
// If it looks like a width, try to be helpful.
423-
dcx.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() })
427+
dcx.create_err(InvalidIntLiteralWidth { span, width: suf[1..].into() })
424428
} else if let Some(fixed) = fix_base_capitalisation(lit.symbol.as_str(), suf) {
425-
dcx.emit_err(InvalidNumLiteralBasePrefix { span, fixed })
429+
dcx.create_err(InvalidNumLiteralBasePrefix { span, fixed })
426430
} else {
427-
dcx.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() })
431+
dcx.create_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() })
428432
}
429433
}
430434
LitError::InvalidFloatSuffix(suffix) => {
431435
let suf = suffix.as_str();
432436
if looks_like_width_suffix(&['f'], suf) {
433437
// If it looks like a width, try to be helpful.
434-
dcx.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() })
438+
dcx.create_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() })
435439
} else {
436-
dcx.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() })
440+
dcx.create_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() })
437441
}
438442
}
439443
LitError::NonDecimalFloat(base) => match base {
440-
16 => dcx.emit_err(HexadecimalFloatLiteralNotSupported { span }),
441-
8 => dcx.emit_err(OctalFloatLiteralNotSupported { span }),
442-
2 => dcx.emit_err(BinaryFloatLiteralNotSupported { span }),
444+
16 => dcx.create_err(HexadecimalFloatLiteralNotSupported { span }),
445+
8 => dcx.create_err(OctalFloatLiteralNotSupported { span }),
446+
2 => dcx.create_err(BinaryFloatLiteralNotSupported { span }),
443447
_ => unreachable!(),
444448
},
445449
LitError::IntTooLarge(base) => {
@@ -450,7 +454,7 @@ pub fn report_lit_error(
450454
16 => format!("{max:#x}"),
451455
_ => format!("{max}"),
452456
};
453-
dcx.emit_err(IntLiteralTooLarge { span, limit })
457+
dcx.create_err(IntLiteralTooLarge { span, limit })
454458
}
455459
}
456460
}

tests/ui/parser/bad-lit-suffixes.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,14 @@ fn g() {}
3838

3939
#[link(name = "string"suffix)]
4040
//~^ ERROR suffixes on string literals are invalid
41-
//~| ERROR malformed `link` attribute input
4241
extern "C" {}
4342

4443
#[rustc_layout_scalar_valid_range_start(0suffix)]
4544
//~^ ERROR invalid suffix `suffix` for number literal
46-
//~| ERROR malformed `rustc_layout_scalar_valid_range_start` attribute input
4745
struct S;
46+
47+
impl S {
48+
#[rustc_confusables("blah"suffix)]
49+
//~^ ERROR suffixes on string literals are invalid
50+
fn woof() { }
51+
}

tests/ui/parser/bad-lit-suffixes.stderr

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -160,48 +160,20 @@ error: suffixes on string literals are invalid
160160
LL | #[link(name = "string"suffix)]
161161
| ^^^^^^^^^^^^^^ invalid suffix `suffix`
162162

163-
error[E0539]: malformed `link` attribute input
164-
--> $DIR/bad-lit-suffixes.rs:39:1
165-
|
166-
LL | #[link(name = "string"suffix)]
167-
| ^^^^^^^---------------------^^
168-
| |
169-
| expected this to be of the form `name = "..."`
170-
|
171-
= note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
172-
help: try changing it to one of the following valid forms of the attribute
173-
|
174-
LL - #[link(name = "string"suffix)]
175-
LL + #[link(name = "...")]
176-
|
177-
LL - #[link(name = "string"suffix)]
178-
LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]
179-
|
180-
LL - #[link(name = "string"suffix)]
181-
LL + #[link(name = "...", kind = "dylib|static|...")]
182-
|
183-
LL - #[link(name = "string"suffix)]
184-
LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]
185-
|
186-
= and 1 other candidate
187-
188163
error: invalid suffix `suffix` for number literal
189-
--> $DIR/bad-lit-suffixes.rs:44:41
164+
--> $DIR/bad-lit-suffixes.rs:43:41
190165
|
191166
LL | #[rustc_layout_scalar_valid_range_start(0suffix)]
192167
| ^^^^^^^ invalid suffix `suffix`
193168
|
194169
= help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
195170

196-
error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input
197-
--> $DIR/bad-lit-suffixes.rs:44:1
171+
error: suffixes on string literals are invalid
172+
--> $DIR/bad-lit-suffixes.rs:48:25
198173
|
199-
LL | #[rustc_layout_scalar_valid_range_start(0suffix)]
200-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^
201-
| | |
202-
| | expected an integer literal here
203-
| help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]`
174+
LL | #[rustc_confusables("blah"suffix)]
175+
| ^^^^^^^^^^^^ invalid suffix `suffix`
204176

205-
error: aborting due to 23 previous errors; 2 warnings emitted
177+
error: aborting due to 22 previous errors; 2 warnings emitted
206178

207179
For more information about this error, try `rustc --explain E0539`.

0 commit comments

Comments
 (0)