//! Implementation of the `#[cfg_accessible(path)]` attribute macro. use crate::errors; use rustc_ast as ast; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; use rustc_span::symbol::sym; use rustc_span::Span; pub(crate) struct Expander; fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> { use errors::CfgAccessibleInvalid::*; match mi.meta_item_list() { None => {} Some([]) => { ecx.emit_err(UnspecifiedPath(mi.span)); } Some([_, .., l]) => { ecx.emit_err(MultiplePaths(l.span())); } Some([nmi]) => match nmi.meta_item() { None => { ecx.emit_err(LiteralPath(nmi.span())); } Some(mi) => { if !mi.is_word() { ecx.emit_err(HasArguments(mi.span)); } return Some(&mi.path); } }, } None } impl MultiItemModifier for Expander { fn expand( &self, ecx: &mut ExtCtxt<'_>, span: Span, meta_item: &ast::MetaItem, item: Annotatable, _is_derive_const: bool, ) -> ExpandResult, Annotatable> { let template = AttributeTemplate { list: Some("path"), ..Default::default() }; validate_attr::check_builtin_meta_item( &ecx.sess.parse_sess, &meta_item, ast::AttrStyle::Outer, sym::cfg_accessible, template, ); let Some(path) = validate_input(ecx, meta_item) else { return ExpandResult::Ready(Vec::new()); }; match ecx.resolver.cfg_accessible(ecx.current_expansion.id, path) { Ok(true) => ExpandResult::Ready(vec![item]), Ok(false) => ExpandResult::Ready(Vec::new()), Err(Indeterminate) if ecx.force_mode => { ecx.emit_err(errors::CfgAccessibleIndeterminate { span }); ExpandResult::Ready(vec![item]) } Err(Indeterminate) => ExpandResult::Retry(item), } } }