11use  rustc_ast:: token:: Delimiter ; 
22use  rustc_ast:: tokenstream:: DelimSpan ; 
3- use  rustc_ast:: { AttrItem ,  Attribute ,  LitKind ,   MetaItemInner ,  NodeId ,  ast,  token} ; 
4- use  rustc_errors:: PResult ; 
3+ use  rustc_ast:: { AttrItem ,  Attribute ,  CRATE_NODE_ID ,   LitKind ,  NodeId ,  ast,  token} ; 
4+ use  rustc_errors:: { Applicability ,   PResult } ; 
55use  rustc_feature:: { AttributeTemplate ,  Features ,  template} ; 
6- use  rustc_hir:: RustcVersion ; 
76use  rustc_hir:: attrs:: CfgEntry ; 
7+ use  rustc_hir:: { AttrPath ,  RustcVersion } ; 
88use  rustc_parse:: parser:: { ForceCollect ,  Parser } ; 
99use  rustc_parse:: { exp,  parse_in} ; 
1010use  rustc_session:: Session ; 
@@ -17,16 +17,24 @@ use thin_vec::ThinVec;
1717
1818use  crate :: context:: { AcceptContext ,  ShouldEmit ,  Stage } ; 
1919use  crate :: parser:: { ArgParser ,  MetaItemListParser ,  MetaItemOrLitParser ,  NameValueParser } ; 
20- use  crate :: session_diagnostics:: { CfgAttrBadDelim ,  MalformedCfgAttr ,  MetaBadDelimSugg } ; 
20+ use  crate :: session_diagnostics:: { 
21+  AttributeParseError ,  AttributeParseErrorReason ,  CfgAttrBadDelim ,  MetaBadDelimSugg , 
22+ } ; 
2123use  crate :: { 
22-  CfgMatchesLintEmitter ,  fluent_generated,  parse_version,  session_diagnostics,  try_gate_cfg, 
24+  AttributeParser ,  CfgMatchesLintEmitter ,  fluent_generated,  parse_version,  session_diagnostics, 
25+  try_gate_cfg, 
2326} ; 
2427
2528pub  const  CFG_TEMPLATE :  AttributeTemplate  = template ! ( 
2629 List :  & [ "predicate" ] , 
2730 "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute" 
2831) ; 
2932
33+ const  CFG_ATTR_TEMPLATE :  AttributeTemplate  = template ! ( 
34+  List :  & [ "predicate, attr1, attr2, ..." ] , 
35+  "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute" 
36+ ) ; 
37+ 
3038pub  fn  parse_cfg < ' c ,  S :  Stage > ( 
3139 cx :  & ' c  mut  AcceptContext < ' _ ,  ' _ ,  S > , 
3240 args :  & ' c  ArgParser < ' _ > , 
@@ -76,9 +84,7 @@ pub(crate) fn parse_cfg_entry<S: Stage>(
7684 } , 
7785 a @ ( ArgParser :: NoArgs  | ArgParser :: NameValue ( _) )  => { 
7886 let  Some ( name)  = meta. path ( ) . word_sym ( )  else  { 
79-  cx. emit_err ( session_diagnostics:: CfgPredicateIdentifier  { 
80-  span :  meta. path ( ) . span ( ) , 
81-  } ) ; 
87+  cx. expected_identifier ( meta. path ( ) . span ( ) ) ; 
8288 return  None ; 
8389 } ; 
8490 parse_name_value ( name,  meta. path ( ) . span ( ) ,  a. name_value ( ) ,  meta. span ( ) ,  cx) ?
@@ -87,7 +93,7 @@ pub(crate) fn parse_cfg_entry<S: Stage>(
8793 MetaItemOrLitParser :: Lit ( lit)  => match  lit. kind  { 
8894 LitKind :: Bool ( b)  => CfgEntry :: Bool ( b,  lit. span ) , 
8995 _ => { 
90-  cx. emit_err ( session_diagnostics :: CfgPredicateIdentifier   {   span :   lit. span   } ) ; 
96+  cx. expected_identifier ( lit. span ) ; 
9197 return  None ; 
9298 } 
9399 } , 
@@ -155,9 +161,7 @@ fn parse_cfg_entry_target<S: Stage>(
155161
156162 // Then, parse it as a name-value item 
157163 let  Some ( name)  = sub_item. path ( ) . word_sym ( )  else  { 
158-  cx. emit_err ( session_diagnostics:: CfgPredicateIdentifier  { 
159-  span :  sub_item. path ( ) . span ( ) , 
160-  } ) ; 
164+  cx. expected_identifier ( sub_item. path ( ) . span ( ) ) ; 
161165 return  None ; 
162166 } ; 
163167 let  name = Symbol :: intern ( & format ! ( "target_{name}" ) ) ; 
@@ -309,32 +313,51 @@ impl EvalConfigResult {
309313
310314pub  fn  parse_cfg_attr ( 
311315 cfg_attr :  & Attribute , 
312-  psess :  & ParseSess , 
313- )  -> Option < ( MetaItemInner ,  Vec < ( AttrItem ,  Span ) > ) >  { 
314-  const  CFG_ATTR_GRAMMAR_HELP :  & str  = "#[cfg_attr(condition, attribute, other_attribute, ...)]" ; 
315-  const  CFG_ATTR_NOTE_REF :  & str  = "for more information, visit \  
316- ; 
317- 
316+  sess :  & Session , 
317+  features :  Option < & Features > , 
318+ )  -> Option < ( CfgEntry ,  Vec < ( AttrItem ,  Span ) > ) >  { 
318319 match  cfg_attr. get_normal_item ( ) . args  { 
319320 ast:: AttrArgs :: Delimited ( ast:: DelimArgs  {  dspan,  delim,  ref  tokens } ) 
320321 if  !tokens. is_empty ( )  =>
321322 { 
322-  check_cfg_attr_bad_delim ( psess,  dspan,  delim) ; 
323-  match  parse_in ( psess,  tokens. clone ( ) ,  "`cfg_attr` input" ,  |p| { 
324-  parse_cfg_attr_internal ( p) 
323+  check_cfg_attr_bad_delim ( & sess . psess ,  dspan,  delim) ; 
324+  match  parse_in ( & sess . psess ,  tokens. clone ( ) ,  "`cfg_attr` input" ,  |p| { 
325+  parse_cfg_attr_internal ( p,  sess ,  features ,  cfg_attr ) 
325326 } )  { 
326327 Ok ( r)  => return  Some ( r) , 
327328 Err ( e)  => { 
328-  e. with_help ( format ! ( "the valid syntax is `{CFG_ATTR_GRAMMAR_HELP}`" ) ) 
329-  . with_note ( CFG_ATTR_NOTE_REF ) 
330-  . emit ( ) ; 
329+  let  suggestions = CFG_ATTR_TEMPLATE . suggestions ( cfg_attr. style ,  sym:: cfg_attr) ; 
330+  e. with_span_suggestions ( 
331+  cfg_attr. span , 
332+  "must be of the form" , 
333+  suggestions, 
334+  Applicability :: HasPlaceholders , 
335+  ) 
336+  . with_note ( format ! ( 
337+  "for more information, visit <{}>" , 
338+  CFG_ATTR_TEMPLATE . docs. expect( "cfg_attr has docs" ) 
339+  ) ) 
340+  . emit ( ) ; 
331341 } 
332342 } 
333343 } 
334344 _ => { 
335-  psess
336-  . dcx ( ) 
337-  . emit_err ( MalformedCfgAttr  {  span :  cfg_attr. span ,  sugg :  CFG_ATTR_GRAMMAR_HELP  } ) ; 
345+  let  ( span,  reason)  = if  let  ast:: AttrArgs :: Delimited ( ast:: DelimArgs  {  dspan,  .. } )  =
346+  cfg_attr. get_normal_item ( ) . args 
347+  { 
348+  ( dspan. entire ( ) ,  AttributeParseErrorReason :: ExpectedAtLeastOneArgument ) 
349+  }  else  { 
350+  ( cfg_attr. span ,  AttributeParseErrorReason :: ExpectedList ) 
351+  } ; 
352+ 
353+  sess. dcx ( ) . emit_err ( AttributeParseError  { 
354+  span, 
355+  attr_span :  cfg_attr. span , 
356+  template :  CFG_ATTR_TEMPLATE , 
357+  attribute :  AttrPath :: from_ast ( & cfg_attr. get_normal_item ( ) . path ) , 
358+  reason, 
359+  attr_style :  cfg_attr. style , 
360+  } ) ; 
338361 } 
339362 } 
340363 None 
@@ -353,8 +376,42 @@ fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter
353376/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. 
354377fn  parse_cfg_attr_internal < ' a > ( 
355378 parser :  & mut  Parser < ' a > , 
356- )  -> PResult < ' a ,  ( ast:: MetaItemInner ,  Vec < ( ast:: AttrItem ,  Span ) > ) >  { 
357-  let  cfg_predicate = parser. parse_meta_item_inner ( ) ?; 
379+  sess :  & ' a  Session , 
380+  features :  Option < & Features > , 
381+  attribute :  & Attribute , 
382+ )  -> PResult < ' a ,  ( CfgEntry ,  Vec < ( ast:: AttrItem ,  Span ) > ) >  { 
383+  // Parse cfg predicate 
384+  let  pred_start = parser. token . span ; 
385+  let  meta = MetaItemOrLitParser :: parse_single ( parser,  ShouldEmit :: ErrorsAndLints ) ?; 
386+  let  pred_span = pred_start. with_hi ( parser. token . span . hi ( ) ) ; 
387+ 
388+  let  cfg_predicate = AttributeParser :: parse_single_args ( 
389+  sess, 
390+  attribute. span , 
391+  attribute. style , 
392+  AttrPath  { 
393+  segments :  attribute
394+  . ident_path ( ) 
395+  . expect ( "cfg_attr is not a doc comment" ) 
396+  . into_boxed_slice ( ) , 
397+  span :  attribute. span , 
398+  } , 
399+  pred_span, 
400+  CRATE_NODE_ID , 
401+  features, 
402+  ShouldEmit :: ErrorsAndLints , 
403+  & meta, 
404+  parse_cfg_entry, 
405+  & CFG_ATTR_TEMPLATE , 
406+  ) 
407+  . ok_or_else ( || { 
408+  let  mut  diag = sess. dcx ( ) . struct_err ( 
409+  "cfg_entry parsing failing with `ShouldEmit::ErrorsAndLints` should emit a error." , 
410+  ) ; 
411+  diag. downgrade_to_delayed_bug ( ) ; 
412+  diag
413+  } ) ?; 
414+ 
358415 parser. expect ( exp ! ( Comma ) ) ?; 
359416
360417 // Presumably, the majority of the time there will only be one attr. 
0 commit comments