blob: 8006fb963b1987f53c870d4ae172f2d704a0df32 [file] [log] [blame] [edit]
use rustc_ast::token::Token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AttrStyle, NodeId, token};
use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::AttrPath;
use rustc_hir::attrs::CfgEntry;
use rustc_parse::exp;
use rustc_parse::parser::Parser;
use rustc_session::Session;
use rustc_span::{ErrorGuaranteed, Ident, Span};
use crate::parser::MetaItemOrLitParser;
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
pub enum CfgSelectPredicate {
Cfg(CfgEntry),
Wildcard(Token),
}
#[derive(Default)]
pub struct CfgSelectBranches {
/// All the conditional branches.
pub reachable: Vec<(CfgEntry, TokenStream, Span)>,
/// The first wildcard `_ => { ... }` branch.
pub wildcard: Option<(Token, TokenStream, Span)>,
/// All branches after the first wildcard, including further wildcards.
/// These branches are kept for formatting.
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
}
pub fn parse_cfg_select(
p: &mut Parser<'_>,
sess: &Session,
features: Option<&Features>,
lint_node_id: NodeId,
) -> Result<CfgSelectBranches, ErrorGuaranteed> {
let mut branches = CfgSelectBranches::default();
while p.token != token::Eof {
if p.eat_keyword(exp!(Underscore)) {
let underscore = p.prev_token;
p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
let span = underscore.span.to(p.token.span);
match branches.wildcard {
None => branches.wildcard = Some((underscore, tts, span)),
Some(_) => {
branches.unreachable.push((CfgSelectPredicate::Wildcard(underscore), tts, span))
}
}
} else {
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
.map_err(|diag| diag.emit())?;
let cfg_span = meta.span();
let cfg = AttributeParser::parse_single_args(
sess,
cfg_span,
cfg_span,
AttrStyle::Inner,
AttrPath {
segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(),
span: cfg_span,
},
ParsedDescription::Macro,
cfg_span,
lint_node_id,
features,
ShouldEmit::ErrorsAndLints,
&meta,
parse_cfg_entry,
&AttributeTemplate::default(),
)?;
p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
let span = cfg_span.to(p.token.span);
match branches.wildcard {
None => branches.reachable.push((cfg, tts, span)),
Some(_) => branches.unreachable.push((CfgSelectPredicate::Cfg(cfg), tts, span)),
}
}
}
Ok(branches)
}