rustc_attr_parsing/attributes/
cfg_select.rs

1use rustc_ast::token::Token;
2use rustc_ast::tokenstream::TokenStream;
3use rustc_ast::{AttrStyle, NodeId, token};
4use rustc_feature::{AttributeTemplate, Features};
5use rustc_hir::AttrPath;
6use rustc_hir::attrs::CfgEntry;
7use rustc_parse::exp;
8use rustc_parse::parser::Parser;
9use rustc_session::Session;
10use rustc_span::{ErrorGuaranteed, Ident, Span};
11
12use crate::parser::MetaItemOrLitParser;
13use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
14
15pub enum CfgSelectPredicate {
16    Cfg(CfgEntry),
17    Wildcard(Token),
18}
19
20#[derive(Default)]
21pub struct CfgSelectBranches {
22    /// All the conditional branches.
23    pub reachable: Vec<(CfgEntry, TokenStream, Span)>,
24    /// The first wildcard `_ => { ... }` branch.
25    pub wildcard: Option<(Token, TokenStream, Span)>,
26    /// All branches after the first wildcard, including further wildcards.
27    /// These branches are kept for formatting.
28    pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
29}
30
31pub fn parse_cfg_select(
32    p: &mut Parser<'_>,
33    sess: &Session,
34    features: Option<&Features>,
35    lint_node_id: NodeId,
36) -> Result<CfgSelectBranches, ErrorGuaranteed> {
37    let mut branches = CfgSelectBranches::default();
38
39    while p.token != token::Eof {
40        if p.eat_keyword(exp!(Underscore)) {
41            let underscore = p.prev_token;
42            p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
43
44            let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
45            let span = underscore.span.to(p.token.span);
46
47            match branches.wildcard {
48                None => branches.wildcard = Some((underscore, tts, span)),
49                Some(_) => {
50                    branches.unreachable.push((CfgSelectPredicate::Wildcard(underscore), tts, span))
51                }
52            }
53        } else {
54            let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
55                .map_err(|diag| diag.emit())?;
56            let cfg_span = meta.span();
57            let cfg = AttributeParser::parse_single_args(
58                sess,
59                cfg_span,
60                cfg_span,
61                AttrStyle::Inner,
62                AttrPath {
63                    segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(),
64                    span: cfg_span,
65                },
66                ParsedDescription::Macro,
67                cfg_span,
68                lint_node_id,
69                features,
70                ShouldEmit::ErrorsAndLints,
71                &meta,
72                parse_cfg_entry,
73                &AttributeTemplate::default(),
74            )?;
75
76            p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
77
78            let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
79            let span = cfg_span.to(p.token.span);
80
81            match branches.wildcard {
82                None => branches.reachable.push((cfg, tts, span)),
83                Some(_) => branches.unreachable.push((CfgSelectPredicate::Cfg(cfg), tts, span)),
84            }
85        }
86    }
87
88    Ok(branches)
89}