diff options
Diffstat (limited to 'compiler/rustc_builtin_macros/src/cfg_select.rs')
| -rw-r--r-- | compiler/rustc_builtin_macros/src/cfg_select.rs | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs new file mode 100644 index 00000000000..2dc387d5866 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -0,0 +1,63 @@ +use rustc_ast::tokenstream::TokenStream; +use rustc_attr_parsing as attr; +use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; +use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectRule, parse_cfg_select}; +use rustc_span::{Ident, Span, sym}; + +use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable}; + +/// Selects the first arm whose rule evaluates to true. +fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> { + for (cfg, tt, arm_span) in branches.reachable { + if attr::cfg_matches( + &cfg, + &ecx.sess, + ecx.current_expansion.lint_node_id, + Some(ecx.ecfg.features), + ) { + return Some((tt, arm_span)); + } + } + + branches.wildcard.map(|(_, tt, span)| (tt, span)) +} + +pub(super) fn expand_cfg_select<'cx>( + ecx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> MacroExpanderResult<'cx> { + ExpandResult::Ready(match parse_cfg_select(&mut ecx.new_parser_from_tts(tts)) { + Ok(branches) => { + if let Some((underscore, _, _)) = branches.wildcard { + // Warn for every unreachable rule. We store the fully parsed branch for rustfmt. + for (rule, _, _) in &branches.unreachable { + let span = match rule { + CfgSelectRule::Wildcard(underscore) => underscore.span, + CfgSelectRule::Cfg(cfg) => cfg.span(), + }; + let err = CfgSelectUnreachable { span, wildcard_span: underscore.span }; + ecx.dcx().emit_warn(err); + } + } + + if let Some((tts, arm_span)) = select_arm(ecx, branches) { + return ExpandResult::from_tts( + ecx, + tts, + sp, + arm_span, + Ident::with_dummy_span(sym::cfg_select), + ); + } else { + // Emit a compiler error when none of the rules matched. + let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp }); + DummyResult::any(sp, guar) + } + } + Err(err) => { + let guar = err.emit(); + DummyResult::any(sp, guar) + } + }) +} |
