rustc_builtin_macros/
cfg.rs

1//! The compiler code necessary to support the cfg! extension, which expands to
2//! a literal `true` or `false` based on whether the given cfg matches the
3//! current compilation environment.
4
5use rustc_ast::token;
6use rustc_ast::tokenstream::TokenStream;
7use rustc_errors::PResult;
8use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
9use rustc_parse::exp;
10use rustc_span::Span;
11use {rustc_ast as ast, rustc_attr_parsing as attr};
12
13use crate::errors;
14
15pub(crate) fn expand_cfg(
16    cx: &mut ExtCtxt<'_>,
17    sp: Span,
18    tts: TokenStream,
19) -> MacroExpanderResult<'static> {
20    let sp = cx.with_def_site_ctxt(sp);
21
22    ExpandResult::Ready(match parse_cfg(cx, sp, tts) {
23        Ok(cfg) => {
24            let matches_cfg = attr::cfg_matches(
25                &cfg,
26                &cx.sess,
27                cx.current_expansion.lint_node_id,
28                Some(cx.ecfg.features),
29            );
30            MacEager::expr(cx.expr_bool(sp, matches_cfg))
31        }
32        Err(err) => {
33            let guar = err.emit();
34            DummyResult::any(sp, guar)
35        }
36    })
37}
38
39fn parse_cfg<'a>(
40    cx: &ExtCtxt<'a>,
41    span: Span,
42    tts: TokenStream,
43) -> PResult<'a, ast::MetaItemInner> {
44    let mut p = cx.new_parser_from_tts(tts);
45
46    if p.token == token::Eof {
47        return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
48    }
49
50    let cfg = p.parse_meta_item_inner()?;
51
52    let _ = p.eat(exp!(Comma));
53
54    if !p.eat(exp!(Eof)) {
55        return Err(cx.dcx().create_err(errors::OneCfgPattern { span }));
56    }
57
58    Ok(cfg)
59}