|  | 
| 1 |  | -use rustc_ast::{LitKind, NodeId}; | 
|  | 1 | +use rustc_ast::token::Delimiter; | 
|  | 2 | +use rustc_ast::tokenstream::DelimSpan; | 
|  | 3 | +use rustc_ast::{AttrItem, Attribute, LitKind, MetaItemInner, NodeId, ast, token}; | 
|  | 4 | +use rustc_errors::PResult; | 
| 2 | 5 | use rustc_feature::{AttributeTemplate, Features, template}; | 
| 3 | 6 | use rustc_hir::RustcVersion; | 
| 4 | 7 | use rustc_hir::attrs::CfgEntry; | 
|  | 8 | +use rustc_parse::parser::{ForceCollect, Parser}; | 
|  | 9 | +use rustc_parse::{exp, parse_in}; | 
| 5 | 10 | use rustc_session::Session; | 
| 6 | 11 | use rustc_session::config::ExpectedValues; | 
| 7 | 12 | use rustc_session::lint::BuiltinLintDiag; | 
| 8 | 13 | use rustc_session::lint::builtin::UNEXPECTED_CFGS; | 
| 9 |  | -use rustc_session::parse::feature_err; | 
|  | 14 | +use rustc_session::parse::{ParseSess, feature_err}; | 
| 10 | 15 | use rustc_span::{Span, Symbol, sym}; | 
| 11 | 16 | use thin_vec::ThinVec; | 
| 12 | 17 | 
 | 
| 13 | 18 | use crate::context::{AcceptContext, ShouldEmit, Stage}; | 
| 14 | 19 | use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser}; | 
|  | 20 | +use crate::session_diagnostics::{CfgAttrBadDelim, MalformedCfgAttr, MetaBadDelimSugg}; | 
| 15 | 21 | use crate::{ | 
| 16 | 22 |  CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg, | 
| 17 | 23 | }; | 
| @@ -301,3 +307,66 @@ impl EvalConfigResult { | 
| 301 | 307 |  } | 
| 302 | 308 | } | 
| 303 | 309 | 
 | 
|  | 310 | +pub fn parse_cfg_attr( | 
|  | 311 | + 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 | + <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>"; | 
|  | 317 | + | 
|  | 318 | + match cfg_attr.get_normal_item().args { | 
|  | 319 | + ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) | 
|  | 320 | + if !tokens.is_empty() => | 
|  | 321 | + { | 
|  | 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) | 
|  | 325 | + }) { | 
|  | 326 | + Ok(r) => return Some(r), | 
|  | 327 | + Err(e) => { | 
|  | 328 | + e.with_help(format!("the valid syntax is `{CFG_ATTR_GRAMMAR_HELP}`")) | 
|  | 329 | + .with_note(CFG_ATTR_NOTE_REF) | 
|  | 330 | + .emit(); | 
|  | 331 | + } | 
|  | 332 | + } | 
|  | 333 | + } | 
|  | 334 | + _ => { | 
|  | 335 | + psess | 
|  | 336 | + .dcx() | 
|  | 337 | + .emit_err(MalformedCfgAttr { span: cfg_attr.span, sugg: CFG_ATTR_GRAMMAR_HELP }); | 
|  | 338 | + } | 
|  | 339 | + } | 
|  | 340 | + None | 
|  | 341 | +} | 
|  | 342 | + | 
|  | 343 | +fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { | 
|  | 344 | + if let Delimiter::Parenthesis = delim { | 
|  | 345 | + return; | 
|  | 346 | + } | 
|  | 347 | + psess.dcx().emit_err(CfgAttrBadDelim { | 
|  | 348 | + span: span.entire(), | 
|  | 349 | + sugg: MetaBadDelimSugg { open: span.open, close: span.close }, | 
|  | 350 | + }); | 
|  | 351 | +} | 
|  | 352 | + | 
|  | 353 | +/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. | 
|  | 354 | +fn parse_cfg_attr_internal<'a>( | 
|  | 355 | + parser: &mut Parser<'a>, | 
|  | 356 | +) -> PResult<'a, (ast::MetaItemInner, Vec<(ast::AttrItem, Span)>)> { | 
|  | 357 | + let cfg_predicate = parser.parse_meta_item_inner()?; | 
|  | 358 | + parser.expect(exp!(Comma))?; | 
|  | 359 | + | 
|  | 360 | + // Presumably, the majority of the time there will only be one attr. | 
|  | 361 | + let mut expanded_attrs = Vec::with_capacity(1); | 
|  | 362 | + while parser.token != token::Eof { | 
|  | 363 | + let lo = parser.token.span; | 
|  | 364 | + let item = parser.parse_attr_item(ForceCollect::Yes)?; | 
|  | 365 | + expanded_attrs.push((item, lo.to(parser.prev_token.span))); | 
|  | 366 | + if !parser.eat(exp!(Comma)) { | 
|  | 367 | + break; | 
|  | 368 | + } | 
|  | 369 | + } | 
|  | 370 | + | 
|  | 371 | + Ok((cfg_predicate, expanded_attrs)) | 
|  | 372 | +} | 
0 commit comments