Handle module-level cfg attributes

This commit is contained in:
David Tolnay 2022-01-18 00:31:18 -08:00
parent abc64e24d1
commit c1f2176154
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
4 changed files with 48 additions and 22 deletions

View File

@ -16,25 +16,29 @@ impl CfgEvaluator for UnsupportedCfgEvaluator {
}
}
pub(super) fn strip(cx: &mut Errors, cfg_evaluator: &dyn CfgEvaluator, apis: &mut Vec<Api>) {
let mut already_errors = Set::new();
apis.retain(|api| eval(cx, &mut already_errors, cfg_evaluator, api.cfg()));
pub(super) fn strip(
cx: &mut Errors,
cfg_errors: &mut Set<String>,
cfg_evaluator: &dyn CfgEvaluator,
apis: &mut Vec<Api>,
) {
apis.retain(|api| eval(cx, cfg_errors, cfg_evaluator, api.cfg()));
for api in apis {
match api {
Api::Struct(strct) => strct
.fields
.retain(|field| eval(cx, &mut already_errors, cfg_evaluator, &field.cfg)),
.retain(|field| eval(cx, cfg_errors, cfg_evaluator, &field.cfg)),
Api::Enum(enm) => enm
.variants
.retain(|variant| eval(cx, &mut already_errors, cfg_evaluator, &variant.cfg)),
.retain(|variant| eval(cx, cfg_errors, cfg_evaluator, &variant.cfg)),
_ => {}
}
}
}
fn eval(
pub(super) fn eval(
cx: &mut Errors,
already_errors: &mut Set<String>,
cfg_errors: &mut Set<String>,
cfg_evaluator: &dyn CfgEvaluator,
expr: &CfgExpr,
) -> bool {
@ -47,7 +51,7 @@ fn eval(
CfgResult::True => true,
CfgResult::False => false,
CfgResult::Undetermined { msg } => {
if already_errors.insert(msg.clone()) {
if cfg_errors.insert(msg.clone()) {
let span = quote!(#ident #string);
cx.error(span, msg);
}
@ -57,11 +61,11 @@ fn eval(
}
CfgExpr::All(list) => list
.iter()
.all(|expr| eval(cx, already_errors, cfg_evaluator, expr)),
.all(|expr| eval(cx, cfg_errors, cfg_evaluator, expr)),
CfgExpr::Any(list) => list
.iter()
.any(|expr| eval(cx, already_errors, cfg_evaluator, expr)),
CfgExpr::Not(expr) => !eval(cx, already_errors, cfg_evaluator, expr),
.any(|expr| eval(cx, cfg_errors, cfg_evaluator, expr)),
CfgExpr::Not(expr) => !eval(cx, cfg_errors, cfg_evaluator, expr),
}
}

View File

@ -20,8 +20,10 @@ use self::cfg::UnsupportedCfgEvaluator;
use self::error::{format_err, Result};
use self::file::File;
use self::include::Include;
use crate::syntax::cfg::CfgExpr;
use crate::syntax::report::Errors;
use crate::syntax::{self, Types};
use crate::syntax::{self, attrs, Types};
use std::collections::BTreeSet as Set;
use std::path::Path;
pub(super) use self::error::Error;
@ -132,7 +134,19 @@ pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
let ref mut apis = Vec::new();
let ref mut errors = Errors::new();
let ref mut cfg_errors = Set::new();
for bridge in syntax.modules {
let mut cfg = CfgExpr::Unconditional;
attrs::parse(
errors,
bridge.attrs,
attrs::Parser {
cfg: Some(&mut cfg),
ignore_unrecognized: true,
..Default::default()
},
);
if cfg::eval(errors, cfg_errors, opt.cfg_evaluator.as_ref(), &cfg) {
let ref namespace = bridge.namespace;
let trusted = bridge.unsafety.is_some();
apis.extend(syntax::parse_items(
@ -142,8 +156,9 @@ pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
namespace,
));
}
}
cfg::strip(errors, opt.cfg_evaluator.as_ref(), apis);
cfg::strip(errors, cfg_errors, opt.cfg_evaluator.as_ref(), apis);
errors.propagate()?;
let ref types = Types::collect(errors, apis);

View File

@ -36,6 +36,7 @@ pub struct Parser<'a> {
pub cxx_name: Option<&'a mut Option<ForeignName>>,
pub rust_name: Option<&'a mut Option<Ident>>,
pub variants_from_header: Option<&'a mut Option<Attribute>>,
pub ignore_unrecognized: bool,
// Suppress clippy needless_update lint ("struct update has no effect, all
// the fields in the struct have already been specified") when preemptively
@ -172,9 +173,11 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
continue;
}
}
if !parser.ignore_unrecognized {
cx.error(attr, "unsupported attribute");
break;
}
}
OtherAttrs(passthrough_attrs)
}

View File

@ -1,3 +1,4 @@
use crate::syntax::cfg::CfgExpr;
use crate::syntax::namespace::Namespace;
use quote::quote;
use syn::parse::{Error, Parse, ParseStream, Result};
@ -7,6 +8,7 @@ use syn::{
};
pub struct Module {
pub cfg: CfgExpr,
pub namespace: Namespace,
pub attrs: Vec<Attribute>,
pub vis: Visibility,
@ -36,6 +38,7 @@ pub struct ItemForeignMod {
impl Parse for Module {
fn parse(input: ParseStream) -> Result<Self> {
let cfg = CfgExpr::Unconditional;
let namespace = Namespace::ROOT;
let mut attrs = input.call(Attribute::parse_outer)?;
let vis: Visibility = input.parse()?;
@ -62,6 +65,7 @@ impl Parse for Module {
}
Ok(Module {
cfg,
namespace,
attrs,
vis,