diff --git a/gen/src/nested.rs b/gen/src/nested.rs index 2129d10fe..32cc5f152 100644 --- a/gen/src/nested.rs +++ b/gen/src/nested.rs @@ -52,6 +52,7 @@ fn sort_by_inner_namespace(apis: Vec<&Api>, depth: usize) -> NamespaceEntries { mod tests { use super::NamespaceEntries; use crate::syntax::attrs::OtherAttrs; + use crate::syntax::cfg::CfgExpr; use crate::syntax::namespace::Namespace; use crate::syntax::{Api, Doc, ExternType, ForeignName, Lang, Lifetimes, Pair}; use proc_macro2::{Ident, Span}; @@ -128,6 +129,7 @@ mod tests { fn make_api(ns: Option<&str>, ident: &str) -> Api { let ns = ns.map_or(Namespace::ROOT, |ns| syn::parse_str(ns).unwrap()); Api::CxxType(ExternType { + cfg: CfgExpr::Unconditional, lang: Lang::Rust, doc: Doc::new(), derives: Vec::new(), diff --git a/macro/src/expand.rs b/macro/src/expand.rs index 4d8cdb86b..3d84fb567 100644 --- a/macro/src/expand.rs +++ b/macro/src/expand.rs @@ -1,5 +1,6 @@ use crate::syntax::atom::Atom::*; use crate::syntax::attrs::{self, OtherAttrs}; +use crate::syntax::cfg::CfgExpr; use crate::syntax::file::Module; use crate::syntax::instantiate::{ImplKey, NamedImplKey}; use crate::syntax::qualified::QualifiedName; @@ -19,11 +20,13 @@ use syn::{parse_quote, punctuated, Generics, Lifetime, Result, Token}; pub fn bridge(mut ffi: Module) -> Result { let ref mut errors = Errors::new(); + let mut cfg = CfgExpr::Unconditional; let mut doc = Doc::new(); let attrs = attrs::parse( errors, mem::take(&mut ffi.attrs), attrs::Parser { + cfg: Some(&mut cfg), doc: Some(&mut doc), ..Default::default() }, diff --git a/syntax/attrs.rs b/syntax/attrs.rs index 208cee5ab..61a7e8f41 100644 --- a/syntax/attrs.rs +++ b/syntax/attrs.rs @@ -1,3 +1,4 @@ +use crate::syntax::cfg::CfgExpr; use crate::syntax::namespace::Namespace; use crate::syntax::report::Errors; use crate::syntax::Atom::{self, *}; @@ -27,6 +28,7 @@ use syn::{parenthesized, token, Attribute, Error, LitStr, Path, Result, Token}; // #[derive(Default)] pub struct Parser<'a> { + pub cfg: Option<&'a mut CfgExpr>, pub doc: Option<&'a mut Doc>, pub derives: Option<&'a mut Vec>, pub repr: Option<&'a mut Option>, @@ -128,11 +130,12 @@ pub fn parse(cx: &mut Errors, attrs: Vec, mut parser: Parser) -> Othe } else if attr.path.is_ident("cfg") { match cfg::parse_attribute.parse2(attr.tokens.clone()) { Ok(cfg_expr) => { - // TODO - let _ = cfg_expr; - cx.error(&attr, "support for cfg attribute is not implemented yet"); - passthrough_attrs.push(attr); - continue; + if let Some(cfg) = &mut parser.cfg { + cfg.merge(cfg_expr); + cx.error(&attr, "support for cfg attribute is not implemented yet"); + passthrough_attrs.push(attr); + continue; + } } Err(err) => { cx.push(err); diff --git a/syntax/cfg.rs b/syntax/cfg.rs index 02217696a..760f70fd9 100644 --- a/syntax/cfg.rs +++ b/syntax/cfg.rs @@ -1,14 +1,30 @@ use proc_macro2::Ident; +use std::mem; use syn::parse::{Error, ParseStream, Result}; use syn::{parenthesized, token, LitStr, Token}; +#[derive(Clone)] pub enum CfgExpr { + Unconditional, Eq(Ident, Option), All(Vec), Any(Vec), Not(Box), } +impl CfgExpr { + pub fn merge(&mut self, expr: CfgExpr) { + if let CfgExpr::Unconditional = self { + *self = expr; + } else if let CfgExpr::All(list) = self { + list.push(expr); + } else { + let prev = mem::replace(self, CfgExpr::Unconditional); + *self = CfgExpr::All(vec![prev, expr]); + } + } +} + pub fn parse_attribute(input: ParseStream) -> Result { let content; parenthesized!(content in input); diff --git a/syntax/impls.rs b/syntax/impls.rs index 06d68dc22..22c5441b5 100644 --- a/syntax/impls.rs +++ b/syntax/impls.rs @@ -8,12 +8,14 @@ use std::ops::{Deref, DerefMut}; impl PartialEq for Include { fn eq(&self, other: &Self) -> bool { let Include { + cfg: _, path, kind, begin_span: _, end_span: _, } = self; let Include { + cfg: _, path: path2, kind: kind2, begin_span: _, @@ -335,6 +337,7 @@ impl PartialEq for Signature { && args.len() == args2.len() && args.iter().zip(args2).all(|(arg, arg2)| { let Var { + cfg: _, doc: _, attrs: _, visibility: _, @@ -343,6 +346,7 @@ impl PartialEq for Signature { ty, } = arg; let Var { + cfg: _, doc: _, attrs: _, visibility: _, @@ -372,6 +376,7 @@ impl Hash for Signature { receiver.hash(state); for arg in args { let Var { + cfg: _, doc: _, attrs: _, visibility: _, diff --git a/syntax/mod.rs b/syntax/mod.rs index e11c97fb6..2fb9b6c40 100644 --- a/syntax/mod.rs +++ b/syntax/mod.rs @@ -2,7 +2,7 @@ pub mod atom; pub mod attrs; -mod cfg; +pub mod cfg; pub mod check; pub mod derive; mod discriminant; @@ -31,6 +31,7 @@ pub mod types; mod visit; use self::attrs::OtherAttrs; +use self::cfg::CfgExpr; use self::namespace::Namespace; use self::parse::kw; use self::symbol::Symbol; @@ -60,6 +61,7 @@ pub enum Api { } pub struct Include { + pub cfg: CfgExpr, pub path: String, pub kind: IncludeKind, pub begin_span: Span, @@ -76,6 +78,7 @@ pub enum IncludeKind { } pub struct ExternType { + pub cfg: CfgExpr, pub lang: Lang, pub doc: Doc, pub derives: Vec, @@ -91,6 +94,7 @@ pub struct ExternType { } pub struct Struct { + pub cfg: CfgExpr, pub doc: Doc, pub derives: Vec, pub attrs: OtherAttrs, @@ -103,6 +107,7 @@ pub struct Struct { } pub struct Enum { + pub cfg: CfgExpr, pub doc: Doc, pub derives: Vec, pub attrs: OtherAttrs, @@ -130,6 +135,7 @@ pub enum EnumRepr { } pub struct ExternFn { + pub cfg: CfgExpr, pub lang: Lang, pub doc: Doc, pub attrs: OtherAttrs, @@ -141,6 +147,7 @@ pub struct ExternFn { } pub struct TypeAlias { + pub cfg: CfgExpr, pub doc: Doc, pub derives: Vec, pub attrs: OtherAttrs, @@ -183,6 +190,7 @@ pub struct Signature { } pub struct Var { + pub cfg: CfgExpr, pub doc: Doc, pub attrs: OtherAttrs, pub visibility: Token![pub], @@ -205,6 +213,7 @@ pub struct Receiver { } pub struct Variant { + pub cfg: CfgExpr, pub doc: Doc, pub attrs: OtherAttrs, pub name: Pair, diff --git a/syntax/parse.rs b/syntax/parse.rs index 85a414c28..ee1266bf4 100644 --- a/syntax/parse.rs +++ b/syntax/parse.rs @@ -1,4 +1,5 @@ use crate::syntax::attrs::OtherAttrs; +use crate::syntax::cfg::CfgExpr; use crate::syntax::discriminant::DiscriminantSet; use crate::syntax::file::{Item, ItemForeignMod}; use crate::syntax::report::Errors; @@ -55,6 +56,7 @@ pub fn parse_items( } fn parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> Result { + let mut cfg = CfgExpr::Unconditional; let mut doc = Doc::new(); let mut derives = Vec::new(); let mut namespace = namespace.clone(); @@ -64,6 +66,7 @@ fn parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> cx, mem::take(&mut item.attrs), attrs::Parser { + cfg: Some(&mut cfg), doc: Some(&mut doc), derives: Some(&mut derives), namespace: Some(&mut namespace), @@ -124,6 +127,7 @@ fn parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> let mut fields = Vec::new(); for field in named_fields.named { let ident = field.ident.unwrap(); + let mut cfg = CfgExpr::Unconditional; let mut doc = Doc::new(); let mut cxx_name = None; let mut rust_name = None; @@ -131,6 +135,7 @@ fn parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> cx, field.attrs, attrs::Parser { + cfg: Some(&mut cfg), doc: Some(&mut doc), cxx_name: Some(&mut cxx_name), rust_name: Some(&mut rust_name), @@ -148,6 +153,7 @@ fn parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> let name = pair(Namespace::default(), &ident, cxx_name, rust_name); let colon_token = field.colon_token.unwrap(); fields.push(Var { + cfg, doc, attrs, visibility, @@ -168,6 +174,7 @@ fn parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> let brace_token = named_fields.brace_token; Ok(Api::Struct(Struct { + cfg, doc, derives, attrs, @@ -181,6 +188,7 @@ fn parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> } fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api { + let mut cfg = CfgExpr::Unconditional; let mut doc = Doc::new(); let mut derives = Vec::new(); let mut repr = None; @@ -192,6 +200,7 @@ fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api { cx, item.attrs, attrs::Parser { + cfg: Some(&mut cfg), doc: Some(&mut doc), derives: Some(&mut derives), repr: Some(&mut repr), @@ -254,6 +263,7 @@ fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api { let variants_from_header = variants_from_header_attr.is_some(); Api::Enum(Enum { + cfg, doc, derives, attrs, @@ -275,6 +285,7 @@ fn parse_variant( mut variant: RustVariant, discriminants: &mut DiscriminantSet, ) -> Result { + let mut cfg = CfgExpr::Unconditional; let mut doc = Doc::new(); let mut cxx_name = None; let mut rust_name = None; @@ -282,6 +293,7 @@ fn parse_variant( cx, mem::take(&mut variant.attrs), attrs::Parser { + cfg: Some(&mut cfg), doc: Some(&mut doc), cxx_name: Some(&mut cxx_name), rust_name: Some(&mut rust_name), @@ -311,6 +323,7 @@ fn parse_variant( let expr = variant.discriminant.map(|(_, expr)| expr); Ok(Variant { + cfg, doc, attrs, name, @@ -345,11 +358,13 @@ fn parse_foreign_mod( let trusted = trusted || foreign_mod.unsafety.is_some(); + let mut cfg = CfgExpr::Unconditional; let mut namespace = namespace.clone(); attrs::parse( cx, foreign_mod.attrs, attrs::Parser { + cfg: Some(&mut cfg), namespace: Some(&mut namespace), ..Default::default() }, @@ -359,23 +374,26 @@ fn parse_foreign_mod( for foreign in foreign_mod.items { match foreign { ForeignItem::Type(foreign) => { - let ety = parse_extern_type(cx, foreign, lang, trusted, &namespace); + let ety = parse_extern_type(cx, foreign, lang, trusted, &cfg, &namespace); items.push(ety); } ForeignItem::Fn(foreign) => { - match parse_extern_fn(cx, foreign, lang, trusted, &namespace) { + match parse_extern_fn(cx, foreign, lang, trusted, &cfg, &namespace) { Ok(efn) => items.push(efn), Err(err) => cx.push(err), } } ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => { match foreign.mac.parse_body_with(parse_include) { - Ok(include) => items.push(Api::Include(include)), + Ok(mut include) => { + include.cfg = cfg.clone(); + items.push(Api::Include(include)); + } Err(err) => cx.push(err), } } ForeignItem::Verbatim(tokens) => { - match parse_extern_verbatim(cx, tokens, lang, trusted, &namespace) { + match parse_extern_verbatim(cx, tokens, lang, trusted, &cfg, &namespace) { Ok(api) => items.push(api), Err(err) => cx.push(err), } @@ -443,8 +461,10 @@ fn parse_extern_type( foreign_type: ForeignItemType, lang: Lang, trusted: bool, + extern_block_cfg: &CfgExpr, namespace: &Namespace, ) -> Api { + let mut cfg = extern_block_cfg.clone(); let mut doc = Doc::new(); let mut derives = Vec::new(); let mut namespace = namespace.clone(); @@ -454,6 +474,7 @@ fn parse_extern_type( cx, foreign_type.attrs, attrs::Parser { + cfg: Some(&mut cfg), doc: Some(&mut doc), derives: Some(&mut derives), namespace: Some(&mut namespace), @@ -479,6 +500,7 @@ fn parse_extern_type( Lang::Cxx => Api::CxxType, Lang::Rust => Api::RustType, })(ExternType { + cfg, lang, doc, derives, @@ -499,8 +521,10 @@ fn parse_extern_fn( mut foreign_fn: ForeignItemFn, lang: Lang, trusted: bool, + extern_block_cfg: &CfgExpr, namespace: &Namespace, ) -> Result { + let mut cfg = extern_block_cfg.clone(); let mut doc = Doc::new(); let mut namespace = namespace.clone(); let mut cxx_name = None; @@ -509,6 +533,7 @@ fn parse_extern_fn( cx, mem::take(&mut foreign_fn.attrs), attrs::Parser { + cfg: Some(&mut cfg), doc: Some(&mut doc), namespace: Some(&mut namespace), cxx_name: Some(&mut cxx_name), @@ -591,12 +616,14 @@ fn parse_extern_fn( }; let ty = parse_type(&arg.ty)?; if ident != "self" { + let cfg = CfgExpr::Unconditional; let doc = Doc::new(); let attrs = OtherAttrs::none(); let visibility = Token![pub](ident.span()); let name = pair(Namespace::default(), &ident, None, None); let colon_token = arg.colon_token; args.push_value(Var { + cfg, doc, attrs, visibility, @@ -647,6 +674,7 @@ fn parse_extern_fn( Lang::Cxx => Api::CxxFunction, Lang::Rust => Api::RustFunction, }(ExternFn { + cfg, lang, doc, attrs, @@ -673,13 +701,23 @@ fn parse_extern_verbatim( tokens: TokenStream, lang: Lang, trusted: bool, + extern_block_cfg: &CfgExpr, namespace: &Namespace, ) -> Result { |input: ParseStream| -> Result { let attrs = input.call(Attribute::parse_outer)?; let visibility: Visibility = input.parse()?; if input.peek(Token![type]) { - parse_extern_verbatim_type(cx, attrs, visibility, input, lang, trusted, namespace) + parse_extern_verbatim_type( + cx, + attrs, + visibility, + input, + lang, + trusted, + extern_block_cfg, + namespace, + ) } else if input.peek(Token![fn]) { parse_extern_verbatim_fn(input) } else { @@ -700,6 +738,7 @@ fn parse_extern_verbatim_type( input: ParseStream, lang: Lang, trusted: bool, + extern_block_cfg: &CfgExpr, namespace: &Namespace, ) -> Result { let type_token: Token![type] = input.parse()?; @@ -746,12 +785,31 @@ fn parse_extern_verbatim_type( if lookahead.peek(Token![=]) { // type Alias = crate::path::to::Type; parse_type_alias( - cx, attrs, visibility, type_token, ident, lifetimes, input, lang, namespace, + cx, + attrs, + visibility, + type_token, + ident, + lifetimes, + input, + lang, + extern_block_cfg, + namespace, ) } else if lookahead.peek(Token![:]) || lookahead.peek(Token![;]) { // type Opaque: Bound2 + Bound2; parse_extern_type_bounded( - cx, attrs, visibility, type_token, ident, lifetimes, input, lang, trusted, namespace, + cx, + attrs, + visibility, + type_token, + ident, + lifetimes, + input, + lang, + trusted, + extern_block_cfg, + namespace, ) } else { Err(lookahead.error()) @@ -773,12 +831,14 @@ fn parse_type_alias( generics: Lifetimes, input: ParseStream, lang: Lang, + extern_block_cfg: &CfgExpr, namespace: &Namespace, ) -> Result { let eq_token: Token![=] = input.parse()?; let ty: RustType = input.parse()?; let semi_token: Token![;] = input.parse()?; + let mut cfg = extern_block_cfg.clone(); let mut doc = Doc::new(); let mut derives = Vec::new(); let mut namespace = namespace.clone(); @@ -788,6 +848,7 @@ fn parse_type_alias( cx, attrs, attrs::Parser { + cfg: Some(&mut cfg), doc: Some(&mut doc), derives: Some(&mut derives), namespace: Some(&mut namespace), @@ -807,6 +868,7 @@ fn parse_type_alias( let name = pair(namespace, &ident, cxx_name, rust_name); Ok(Api::TypeAlias(TypeAlias { + cfg, doc, derives, attrs, @@ -830,6 +892,7 @@ fn parse_extern_type_bounded( input: ParseStream, lang: Lang, trusted: bool, + extern_block_cfg: &CfgExpr, namespace: &Namespace, ) -> Result { let mut bounds = Vec::new(); @@ -865,6 +928,7 @@ fn parse_extern_type_bounded( } let semi_token: Token![;] = input.parse()?; + let mut cfg = extern_block_cfg.clone(); let mut doc = Doc::new(); let mut derives = Vec::new(); let mut namespace = namespace.clone(); @@ -874,6 +938,7 @@ fn parse_extern_type_bounded( cx, attrs, attrs::Parser { + cfg: Some(&mut cfg), doc: Some(&mut doc), derives: Some(&mut derives), namespace: Some(&mut namespace), @@ -890,6 +955,7 @@ fn parse_extern_type_bounded( Lang::Cxx => Api::CxxType, Lang::Rust => Api::RustType, }(ExternType { + cfg, lang, doc, derives, @@ -1008,6 +1074,7 @@ fn parse_include(input: ParseStream) -> Result { let lit: LitStr = input.parse()?; let span = lit.span(); return Ok(Include { + cfg: CfgExpr::Unconditional, path: lit.value(), kind: IncludeKind::Quoted, begin_span: span, @@ -1037,6 +1104,7 @@ fn parse_include(input: ParseStream) -> Result { let rangle: Token![>] = input.parse()?; return Ok(Include { + cfg: CfgExpr::Unconditional, path, kind: IncludeKind::Bracketed, begin_span: langle.span, @@ -1297,11 +1365,13 @@ fn parse_type_fn(ty: &TypeBareFn) -> Result { } }; let ty = parse_type(&arg.ty)?; + let cfg = CfgExpr::Unconditional; let doc = Doc::new(); let attrs = OtherAttrs::none(); let visibility = Token![pub](ident.span()); let name = pair(Namespace::default(), &ident, None, None); Ok(Var { + cfg, doc, attrs, visibility, diff --git a/syntax/tokens.rs b/syntax/tokens.rs index 1e1374394..2bd16b6e9 100644 --- a/syntax/tokens.rs +++ b/syntax/tokens.rs @@ -39,6 +39,7 @@ impl ToTokens for Type { impl ToTokens for Var { fn to_tokens(&self, tokens: &mut TokenStream) { let Var { + cfg: _, doc: _, attrs: _, visibility: _,