@@ -8,12 +8,12 @@ use std::fmt::{Debug, Display};
88
99use rustc_ast:: token:: { self , Delimiter , MetaVarKind } ;
1010use rustc_ast:: tokenstream:: TokenStream ;
11- use rustc_ast:: { AttrArgs , Expr , ExprKind , LitKind , MetaItemLit , NormalAttr , Path } ;
11+ use rustc_ast:: { AttrArgs , Expr , ExprKind , LitKind , MetaItemLit , NormalAttr , Path , StmtKind , UnOp } ;
1212use rustc_ast_pretty:: pprust;
1313use rustc_errors:: { Diag , PResult } ;
1414use rustc_hir:: { self as hir, AttrPath } ;
1515use rustc_parse:: exp;
16- use rustc_parse:: parser:: { Parser , PathStyle , token_descr} ;
16+ use rustc_parse:: parser:: { ForceCollect , Parser , PathStyle , token_descr} ;
1717use rustc_session:: errors:: { create_lit_error, report_lit_error} ;
1818use rustc_session:: parse:: ParseSess ;
1919use rustc_span:: { ErrorGuaranteed , Ident , Span , Symbol , sym} ;
@@ -488,33 +488,55 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
488488 descr : token_descr ( & self . parser . token ) ,
489489 quote_ident_sugg : None ,
490490 remove_neg_sugg : None ,
491+ label : None ,
491492 } ;
492493
494+ if let token:: OpenInvisible ( _) = self . parser . token . kind {
495+ // Do not attempt to suggest anything when encountered as part of a macro expansion.
496+ return self . parser . dcx ( ) . create_err ( err) ;
497+ }
498+
493499 // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
494500 // don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
495501 // when macro metavariables are involved.
496- if self . parser . prev_token == token:: Eq
497- && let token:: Ident ( ..) = self . parser . token . kind
498- {
499- let before = self . parser . token . span . shrink_to_lo ( ) ;
500- while let token:: Ident ( ..) = self . parser . token . kind {
501- self . parser . bump ( ) ;
502+ let snapshot = self . parser . create_snapshot_for_diagnostic ( ) ;
503+ let stmt = self . parser . parse_stmt_without_recovery ( false , ForceCollect :: No , false ) ;
504+ match stmt {
505+ Ok ( Some ( stmt) ) => {
506+ // The user tried to write something like
507+ // `#[deprecated(note = concat!("a", "b"))]`.
508+ err. descr = stmt. kind . descr ( ) . to_string ( ) ;
509+ err. label = Some ( stmt. span ) ;
510+ err. span = stmt. span ;
511+ if let StmtKind :: Expr ( expr) = & stmt. kind
512+ && let ExprKind :: Unary ( UnOp :: Neg , val) = & expr. kind
513+ && let ExprKind :: Lit ( _) = val. kind
514+ {
515+ err. remove_neg_sugg = Some ( InvalidMetaItemRemoveNegSugg {
516+ negative_sign : expr. span . until ( val. span ) ,
517+ } ) ;
518+ } else if let StmtKind :: Expr ( expr) = & stmt. kind
519+ && let ExprKind :: Path ( None , Path { segments, .. } ) = & expr. kind
520+ && segments. len ( ) == 1
521+ {
522+ while let token:: Ident ( ..) | token:: Literal ( _) | token:: Dot =
523+ self . parser . token . kind
524+ {
525+ // We've got a word, so we try to consume the rest of a potential sentence.
526+ // We include `.` to correctly handle things like `A sentence here.`.
527+ self . parser . bump ( ) ;
528+ }
529+ err. quote_ident_sugg = Some ( InvalidMetaItemQuoteIdentSugg {
530+ before : expr. span . shrink_to_lo ( ) ,
531+ after : self . parser . prev_token . span . shrink_to_hi ( ) ,
532+ } ) ;
533+ }
534+ }
535+ Ok ( None ) => { }
536+ Err ( e) => {
537+ e. cancel ( ) ;
538+ self . parser . restore_snapshot ( snapshot) ;
502539 }
503- err. quote_ident_sugg = Some ( InvalidMetaItemQuoteIdentSugg {
504- before,
505- after : self . parser . prev_token . span . shrink_to_hi ( ) ,
506- } ) ;
507- }
508-
509- if self . parser . token == token:: Minus
510- && self
511- . parser
512- . look_ahead ( 1 , |t| matches ! ( t. kind, rustc_ast:: token:: TokenKind :: Literal { .. } ) )
513- {
514- err. remove_neg_sugg =
515- Some ( InvalidMetaItemRemoveNegSugg { negative_sign : self . parser . token . span } ) ;
516- self . parser . bump ( ) ;
517- self . parser . bump ( ) ;
518540 }
519541
520542 self . parser . dcx ( ) . create_err ( err)
0 commit comments