1
Fork 0

Use ast::NestedMetaItem when evaluating cfg predicate

This commit is contained in:
Urgau 2024-09-18 17:44:32 +02:00
parent c3ce4e66a5
commit 57b9b1f974
11 changed files with 62 additions and 37 deletions

View file

@ -523,7 +523,7 @@ pub struct Condition {
/// Tests if a cfg-pattern matches the cfg set /// Tests if a cfg-pattern matches the cfg set
pub fn cfg_matches( pub fn cfg_matches(
cfg: &ast::MetaItem, cfg: &ast::NestedMetaItem,
sess: &Session, sess: &Session,
lint_node_id: NodeId, lint_node_id: NodeId,
features: Option<&Features>, features: Option<&Features>,
@ -594,12 +594,26 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
/// evaluate individual items. /// evaluate individual items.
pub fn eval_condition( pub fn eval_condition(
cfg: &ast::MetaItem, cfg: &ast::NestedMetaItem,
sess: &Session, sess: &Session,
features: Option<&Features>, features: Option<&Features>,
eval: &mut impl FnMut(Condition) -> bool, eval: &mut impl FnMut(Condition) -> bool,
) -> bool { ) -> bool {
let dcx = sess.dcx(); let dcx = sess.dcx();
let cfg = match cfg {
ast::NestedMetaItem::MetaItem(meta_item) => meta_item,
_ => {
dcx.emit_err(session_diagnostics::UnsupportedLiteral {
span: cfg.span(),
reason: UnsupportedLiteralReason::Generic,
is_bytestr: false,
start_point_span: sess.source_map().start_point(cfg.span()),
});
return false;
}
};
match &cfg.kind { match &cfg.kind {
ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
try_gate_cfg(sym::version, cfg.span, sess, features); try_gate_cfg(sym::version, cfg.span, sess, features);
@ -653,23 +667,19 @@ pub fn eval_condition(
.iter() .iter()
// We don't use any() here, because we want to evaluate all cfg condition // We don't use any() here, because we want to evaluate all cfg condition
// as eval_condition can (and does) extra checks // as eval_condition can (and does) extra checks
.fold(false, |res, mi| { .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
res | eval_condition(mi.meta_item().unwrap(), sess, features, eval)
}),
sym::all => mis sym::all => mis
.iter() .iter()
// We don't use all() here, because we want to evaluate all cfg condition // We don't use all() here, because we want to evaluate all cfg condition
// as eval_condition can (and does) extra checks // as eval_condition can (and does) extra checks
.fold(true, |res, mi| { .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
res & eval_condition(mi.meta_item().unwrap(), sess, features, eval)
}),
sym::not => { sym::not => {
let [mi] = mis.as_slice() else { let [mi] = mis.as_slice() else {
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
return false; return false;
}; };
!eval_condition(mi.meta_item().unwrap(), sess, features, eval) !eval_condition(mi, sess, features, eval)
} }
sym::target => { sym::target => {
if let Some(features) = features if let Some(features) = features
@ -690,7 +700,12 @@ pub fn eval_condition(
seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
} }
res & eval_condition(&mi, sess, features, eval) res & eval_condition(
&ast::NestedMetaItem::MetaItem(mi),
sess,
features,
eval,
)
}) })
} }
_ => { _ => {

View file

@ -6,7 +6,6 @@ use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_errors::PResult; use rustc_errors::PResult;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_parse::parser::attr::AllowLeadingUnsafe;
use rustc_span::Span; use rustc_span::Span;
use {rustc_ast as ast, rustc_attr as attr}; use {rustc_ast as ast, rustc_attr as attr};
@ -36,14 +35,18 @@ pub(crate) fn expand_cfg(
}) })
} }
fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> { fn parse_cfg<'a>(
cx: &ExtCtxt<'a>,
span: Span,
tts: TokenStream,
) -> PResult<'a, ast::NestedMetaItem> {
let mut p = cx.new_parser_from_tts(tts); let mut p = cx.new_parser_from_tts(tts);
if p.token == token::Eof { if p.token == token::Eof {
return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span })); return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
} }
let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?; let cfg = p.parse_meta_item_inner()?;
let _ = p.eat(&token::Comma); let _ = p.eat(&token::Comma);

View file

@ -156,7 +156,7 @@ pub struct NativeLib {
pub kind: NativeLibKind, pub kind: NativeLibKind,
pub name: Symbol, pub name: Symbol,
pub filename: Option<Symbol>, pub filename: Option<Symbol>,
pub cfg: Option<ast::MetaItem>, pub cfg: Option<ast::NestedMetaItem>,
pub verbatim: bool, pub verbatim: bool,
pub dll_imports: Vec<cstore::DllImport>, pub dll_imports: Vec<cstore::DllImport>,
} }

View file

@ -5,7 +5,9 @@ use rustc_ast::token::{Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::{ use rustc_ast::tokenstream::{
AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree, AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
}; };
use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId}; use rustc_ast::{
self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NestedMetaItem, NodeId,
};
use rustc_attr as attr; use rustc_attr as attr;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_feature::{ use rustc_feature::{
@ -449,7 +451,7 @@ impl<'a> StripUnconfigured<'a> {
} }
} }
pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> { pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a NestedMetaItem> {
let span = meta_item.span; let span = meta_item.span;
match meta_item.meta_item_list() { match meta_item.meta_item_list() {
None => { None => {
@ -464,9 +466,9 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta
sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() }); sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
None None
} }
Some([single]) => match single.meta_item() { Some([single]) => match single.is_meta_item() {
Some(meta_item) => Some(meta_item), true => Some(single),
None => { false => {
sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() }); sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() });
None None
} }

View file

@ -1,7 +1,7 @@
use std::ops::ControlFlow; use std::ops::ControlFlow;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use rustc_ast::{CRATE_NODE_ID, NestedMetaItem}; use rustc_ast::CRATE_NODE_ID;
use rustc_attr as attr; use rustc_attr as attr;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_middle::query::LocalCrate; use rustc_middle::query::LocalCrate;
@ -304,7 +304,12 @@ impl<'tcx> Collector<'tcx> {
sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() }); sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
continue; continue;
}; };
let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else { let [link_cfg] = link_cfg else {
sess.dcx()
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
continue;
};
if !link_cfg.is_meta_item() {
sess.dcx() sess.dcx()
.emit_err(errors::LinkCfgSinglePredicate { span: item.span() }); .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
continue; continue;

View file

@ -18,7 +18,7 @@ use std::path::Path;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AttrItem, Attribute, MetaItem, token}; use rustc_ast::{AttrItem, Attribute, NestedMetaItem, token};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_errors::{Diag, FatalError, PResult}; use rustc_errors::{Diag, FatalError, PResult};
@ -160,7 +160,7 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok
pub fn parse_cfg_attr( pub fn parse_cfg_attr(
cfg_attr: &Attribute, cfg_attr: &Attribute,
psess: &ParseSess, psess: &ParseSess,
) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { ) -> Option<(NestedMetaItem, Vec<(AttrItem, Span)>)> {
const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
<https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>"; <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";

View file

@ -356,8 +356,10 @@ impl<'a> Parser<'a> {
} }
/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { pub fn parse_cfg_attr(
let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?; &mut self,
) -> PResult<'a, (ast::NestedMetaItem, Vec<(ast::AttrItem, Span)>)> {
let cfg_predicate = self.parse_meta_item_inner()?;
self.expect(&token::Comma)?; self.expect(&token::Comma)?;
// Presumably, the majority of the time there will only be one attr. // Presumably, the majority of the time there will only be one attr.
@ -452,7 +454,7 @@ impl<'a> Parser<'a> {
/// ```ebnf /// ```ebnf
/// MetaItemInner = UNSUFFIXED_LIT | MetaItem ; /// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
/// ``` /// ```
fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { pub fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
match self.parse_unsuffixed_meta_item_lit() { match self.parse_unsuffixed_meta_item_lit() {
Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)), Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)),
Err(err) => err.cancel(), // we provide a better error below Err(err) => err.cancel(), // we provide a better error below

View file

@ -72,7 +72,7 @@ pub struct NativeLib {
pub name: Symbol, pub name: Symbol,
/// If packed_bundled_libs enabled, actual filename of library is stored. /// If packed_bundled_libs enabled, actual filename of library is stored.
pub filename: Option<Symbol>, pub filename: Option<Symbol>,
pub cfg: Option<ast::MetaItem>, pub cfg: Option<ast::NestedMetaItem>,
pub foreign_module: Option<DefId>, pub foreign_module: Option<DefId>,
pub verbatim: Option<bool>, pub verbatim: Option<bool>,
pub dll_imports: Vec<DllImport>, pub dll_imports: Vec<DllImport>,

View file

@ -1,7 +1,7 @@
use std::iter; use std::iter;
use std::path::PathBuf; use std::path::PathBuf;
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, MetaItem, NestedMetaItem}; use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::codes::*; use rustc_errors::codes::*;
use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
@ -282,7 +282,7 @@ pub struct OnUnimplementedFormatString {
#[derive(Debug)] #[derive(Debug)]
pub struct OnUnimplementedDirective { pub struct OnUnimplementedDirective {
pub condition: Option<MetaItem>, pub condition: Option<NestedMetaItem>,
pub subcommands: Vec<OnUnimplementedDirective>, pub subcommands: Vec<OnUnimplementedDirective>,
pub message: Option<OnUnimplementedFormatString>, pub message: Option<OnUnimplementedFormatString>,
pub label: Option<OnUnimplementedFormatString>, pub label: Option<OnUnimplementedFormatString>,
@ -413,9 +413,7 @@ impl<'tcx> OnUnimplementedDirective {
} else { } else {
let cond = item_iter let cond = item_iter
.next() .next()
.ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))? .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?;
.meta_item()
.ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| { attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| {
if let Some(value) = cfg.value if let Some(value) = cfg.value
&& let Err(guar) = parse_value(value, cfg.span) && let Err(guar) = parse_value(value, cfg.span)
@ -558,8 +556,8 @@ impl<'tcx> OnUnimplementedDirective {
IgnoredDiagnosticOption::maybe_emit_warning( IgnoredDiagnosticOption::maybe_emit_warning(
tcx, tcx,
item_def_id, item_def_id,
directive.condition.as_ref().map(|i| i.span), directive.condition.as_ref().map(|i| i.span()),
aggr.condition.as_ref().map(|i| i.span), aggr.condition.as_ref().map(|i| i.span()),
"condition", "condition",
); );
IgnoredDiagnosticOption::maybe_emit_warning( IgnoredDiagnosticOption::maybe_emit_warning(

View file

@ -1,6 +1,6 @@
fn main() { fn main() {
cfg!(); //~ ERROR macro requires a cfg-pattern cfg!(); //~ ERROR macro requires a cfg-pattern
cfg!(123); //~ ERROR expected identifier cfg!(123); //~ ERROR unsupported literal
cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string
cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern
} }

View file

@ -6,11 +6,11 @@ LL | cfg!();
| |
= note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected identifier, found `123` error[E0565]: unsupported literal
--> $DIR/cfg.rs:3:10 --> $DIR/cfg.rs:3:10
| |
LL | cfg!(123); LL | cfg!(123);
| ^^^ expected identifier | ^^^
error[E0565]: literal in `cfg` predicate value must be a string error[E0565]: literal in `cfg` predicate value must be a string
--> $DIR/cfg.rs:4:16 --> $DIR/cfg.rs:4:16