@@ -16,7 +16,7 @@ use rustc_errors::{Diag, PResult};
1616use rustc_hir:: { self as hir, AttrPath } ;
1717use rustc_parse:: exp;
1818use rustc_parse:: parser:: { ForceCollect , Parser , PathStyle , token_descr} ;
19- use rustc_session:: errors:: { create_lit_error, report_lit_error } ;
19+ use rustc_session:: errors:: create_lit_error;
2020use rustc_session:: parse:: ParseSess ;
2121use rustc_span:: { Ident , Span , Symbol , sym} ;
2222use thin_vec:: ThinVec ;
@@ -113,16 +113,29 @@ impl ArgParser {
113113 Some ( match value {
114114 AttrArgs :: Empty => Self :: NoArgs ,
115115 AttrArgs :: Delimited ( args) => {
116- // The arguments of rustc_dummy and diagnostic::do_not_recommend are not validated
117- // if the arguments are delimited.
118- // See https://doc.rust-lang.org/reference/attributes/diagnostics.html#r-attributes.diagnostic.namespace.unknown-invalid-syntax
119- if parts == & [ sym:: rustc_dummy]
120- || parts == & [ sym:: diagnostic, sym:: do_not_recommend]
121- {
122- return Some ( ArgParser :: List ( MetaItemListParser {
123- sub_parsers : ThinVec :: new ( ) ,
124- span : args. dspan . entire ( ) ,
125- } ) ) ;
116+ // Diagnostic attributes can't error if they encounter non meta item syntax.
117+ // However, the current syntax for diagnostic attributes is meta item syntax.
118+ // Therefore we can substitute with a dummy value on invalid syntax.
119+ if matches ! ( parts, [ sym:: rustc_dummy] | [ sym:: diagnostic, ..] ) {
120+ match MetaItemListParser :: new (
121+ & args. tokens ,
122+ args. dspan . entire ( ) ,
123+ psess,
124+ ShouldEmit :: ErrorsAndLints { recover : false } ,
125+ ) {
126+ Ok ( p) => return Some ( ArgParser :: List ( p) ) ,
127+ Err ( e) => {
128+ // We can just dispose of the diagnostic and not bother with a lint,
129+ // because this will look like `#[diagnostic::attr()]` was used. This
130+ // is invalid for all diagnostic attrs, so a lint explaining the proper
131+ // form will be issued later.
132+ e. cancel ( ) ;
133+ return Some ( ArgParser :: List ( MetaItemListParser {
134+ sub_parsers : ThinVec :: new ( ) ,
135+ span : args. dspan . entire ( ) ,
136+ } ) ) ;
137+ }
138+ }
126139 }
127140
128141 if args. delim != Delimiter :: Parenthesis {
@@ -141,7 +154,9 @@ impl ArgParser {
141154 }
142155 AttrArgs :: Eq { eq_span, expr } => Self :: NameValue ( NameValueParser {
143156 eq_span : * eq_span,
144- value : expr_to_lit ( psess, & expr, expr. span , should_emit) ?,
157+ value : expr_to_lit ( psess, & expr, expr. span , should_emit)
158+ . map_err ( |e| should_emit. emit_err ( e) )
159+ . ok ( ) ??,
145160 value_span : expr. span ,
146161 } ) ,
147162 } )
@@ -336,58 +351,53 @@ impl NameValueParser {
336351 }
337352}
338353
339- fn expr_to_lit (
340- psess : & ParseSess ,
354+ fn expr_to_lit < ' sess > (
355+ psess : & ' sess ParseSess ,
341356 expr : & Expr ,
342357 span : Span ,
343358 should_emit : ShouldEmit ,
344- ) -> Option < MetaItemLit > {
359+ ) -> PResult < ' sess , Option < MetaItemLit > > {
345360 if let ExprKind :: Lit ( token_lit) = expr. kind {
346361 let res = MetaItemLit :: from_token_lit ( token_lit, expr. span ) ;
347362 match res {
348363 Ok ( lit) => {
349364 if token_lit. suffix . is_some ( ) {
350- should_emit. emit_err (
351- psess. dcx ( ) . create_err ( SuffixedLiteralInAttribute { span : lit. span } ) ,
352- ) ;
353- None
365+ Err ( psess. dcx ( ) . create_err ( SuffixedLiteralInAttribute { span : lit. span } ) )
354366 } else {
355- if !lit. kind . is_unsuffixed ( ) {
356- // Emit error and continue, we can still parse the attribute as if the suffix isn't there
357- should_emit. emit_err (
358- psess. dcx ( ) . create_err ( SuffixedLiteralInAttribute { span : lit. span } ) ,
359- ) ;
367+ if lit. kind . is_unsuffixed ( ) {
368+ Ok ( Some ( lit) )
369+ } else {
370+ Err ( psess. dcx ( ) . create_err ( SuffixedLiteralInAttribute { span : lit. span } ) )
360371 }
361-
362- Some ( lit)
363372 }
364373 }
365374 Err ( err) => {
366- let guar = report_lit_error ( psess, err, token_lit, expr. span ) ;
367- let lit = MetaItemLit {
368- symbol : token_lit. symbol ,
369- suffix : token_lit. suffix ,
370- kind : LitKind :: Err ( guar) ,
371- span : expr. span ,
372- } ;
373- Some ( lit)
375+ let err = create_lit_error ( psess, err, token_lit, expr. span ) ;
376+ if matches ! ( should_emit, ShouldEmit :: ErrorsAndLints { recover: false } ) {
377+ Err ( err)
378+ } else {
379+ let lit = MetaItemLit {
380+ symbol : token_lit. symbol ,
381+ suffix : token_lit. suffix ,
382+ kind : LitKind :: Err ( err. emit ( ) ) ,
383+ span : expr. span ,
384+ } ;
385+ Ok ( Some ( lit) )
386+ }
374387 }
375388 }
376389 } else {
377390 if matches ! ( should_emit, ShouldEmit :: Nothing ) {
378- return None ;
391+ return Ok ( None ) ;
379392 }
380393
381394 // Example cases:
382395 // - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
383396 // - `#[foo = include_str!("nonexistent-file.rs")]`:
384- // results in `ast::ExprKind::Err`. In that case we delay
385- // the error because an earlier error will have already
386- // been reported.
397+ // results in `ast::ExprKind::Err`.
387398 let msg = "attribute value must be a literal" ;
388399 let err = psess. dcx ( ) . struct_span_err ( span, msg) ;
389- should_emit. emit_err ( err) ;
390- None
400+ Err ( err)
391401 }
392402}
393403
@@ -420,9 +430,12 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
420430
421431 if !lit. kind . is_unsuffixed ( ) {
422432 // Emit error and continue, we can still parse the attribute as if the suffix isn't there
423- self . should_emit . emit_err (
424- self . parser . dcx ( ) . create_err ( SuffixedLiteralInAttribute { span : lit. span } ) ,
425- ) ;
433+ let err = self . parser . dcx ( ) . create_err ( SuffixedLiteralInAttribute { span : lit. span } ) ;
434+ if matches ! ( self . should_emit, ShouldEmit :: ErrorsAndLints { recover: false } ) {
435+ return Err ( err) ;
436+ } else {
437+ self . should_emit . emit_err ( err)
438+ } ;
426439 }
427440
428441 Ok ( lit)
0 commit comments