Skip to content

Commit 9036b10

Browse files
committed
fix: correctly handle abi and unsafety
1 parent ea82940 commit 9036b10

File tree

1 file changed

+174
-104
lines changed

1 file changed

+174
-104
lines changed

bindgen/codegen/postprocessing/merge_cfg_attributes.rs

+174-104
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,128 @@
1+
use crate::HashMap;
2+
use crate::HashSet;
3+
use itertools::Itertools;
14
use proc_macro2::Span;
25
use quote::{quote, ToTokens};
6+
use syn::token::Unsafe;
7+
use syn::Abi;
38
use syn::{
4-
Attribute, File, ForeignItem, Ident, Item, ItemConst, ItemEnum, ItemFn, ItemForeignMod,
5-
ItemImpl, ItemMod, ItemStatic, ItemStruct, ItemType, ItemUnion, ItemUse,
9+
Attribute, File, ForeignItem, Ident, Item, ItemConst, ItemEnum, ItemFn,
10+
ItemForeignMod, ItemImpl, ItemMod, ItemStatic, ItemStruct, ItemType,
11+
ItemUnion, ItemUse,
612
};
7-
use itertools::Itertools;
8-
use crate::HashMap;
9-
use crate::HashSet;
1013

1114
pub fn merge_cfg_attributes(file: &mut File) {
1215
let mut visitor = Visitor::new();
1316
visitor.visit_file(file);
1417
}
1518

19+
struct SyntheticMod {
20+
attrs: AttributeSet,
21+
unsafety: Option<Unsafe>,
22+
abi: Option<Abi>,
23+
items: Vec<Item>,
24+
}
25+
26+
impl SyntheticMod {
27+
pub fn new(attrs: AttributeSet) -> Self {
28+
Self {
29+
attrs,
30+
unsafety: None,
31+
abi: None,
32+
items: vec![],
33+
}
34+
}
35+
}
36+
37+
#[derive(Default, Clone)]
38+
struct AttributeSet {
39+
cfg_attrs: HashSet<Attribute>,
40+
cc_attrs: HashSet<Attribute>,
41+
other_attrs: HashSet<Attribute>,
42+
unsafety: Option<Unsafe>,
43+
abi: Option<Abi>,
44+
}
45+
46+
impl AttributeSet {
47+
fn new(
48+
attrs: &[Attribute],
49+
unsafety: Option<Unsafe>,
50+
abi: Option<Abi>,
51+
) -> Self {
52+
let mut attribute_set = AttributeSet::default();
53+
54+
for attr in attrs {
55+
let target_set = if let Some(ident) = attr.path().get_ident() {
56+
match ident.to_string().as_str() {
57+
"cfg" => &mut attribute_set.cfg_attrs,
58+
"link" => &mut attribute_set.cc_attrs,
59+
_ => &mut attribute_set.other_attrs,
60+
}
61+
} else {
62+
&mut attribute_set.other_attrs
63+
};
64+
target_set.insert(attr.clone());
65+
}
66+
attribute_set.unsafety = unsafety;
67+
attribute_set.abi = abi;
68+
69+
attribute_set
70+
}
71+
72+
fn extend(
73+
&mut self,
74+
attrs: &[Attribute],
75+
unsafety: Option<Unsafe>,
76+
abi: Option<Abi>,
77+
) {
78+
let other = AttributeSet::new(attrs, unsafety, abi);
79+
self.other_attrs.extend(other.other_attrs);
80+
self.cfg_attrs.extend(other.cfg_attrs);
81+
self.cc_attrs.extend(other.cc_attrs);
82+
83+
self.unsafety = other.unsafety.or(self.unsafety);
84+
self.abi = other.abi.or(self.abi.clone());
85+
}
86+
87+
fn ident(&self) -> Ident {
88+
Ident::new(
89+
Itertools::intersperse(
90+
self.unsafety
91+
.map(|r#unsafe| r#unsafe.to_token_stream().to_string())
92+
.into_iter()
93+
.chain(
94+
self.abi
95+
.as_ref()
96+
.map(|abi| abi.to_token_stream().to_string()),
97+
)
98+
.chain(
99+
self.cfg_attrs
100+
.iter()
101+
.chain(self.cc_attrs.iter())
102+
.map(|attr| attr.to_token_stream().to_string())
103+
.sorted(),
104+
),
105+
"_".to_string(),
106+
)
107+
.collect::<String>()
108+
.replace(|c| !c.is_alphanumeric(), "_")
109+
.chars()
110+
.coalesce(|a, b| {
111+
if a == '_' && b == '_' {
112+
Ok(a)
113+
} else {
114+
Err((a, b))
115+
}
116+
})
117+
.collect::<String>()
118+
.trim_matches('_'),
119+
Span::call_site(),
120+
)
121+
}
122+
}
123+
16124
struct Visitor {
17-
synthetic_mods: HashMap<Ident, (AttributeSet, Vec<Item>)>,
125+
synthetic_mods: HashMap<Ident, SyntheticMod>,
18126
new_items: Vec<Item>,
19127
}
20128

@@ -29,28 +137,39 @@ impl Visitor {
29137
fn visit_file(&mut self, file: &mut File) {
30138
self.visit_items(&mut file.items);
31139

32-
for (ident, (attr_set, items)) in self.synthetic_mods.drain() {
33-
let cfg_attrs: Vec<_> = attr_set.cfg_attrs.iter().collect();
34-
let cc_attrs: Vec<_> = attr_set.cc_attrs.iter().collect();
35-
let block = if cc_attrs.is_empty() {
140+
for (
141+
ref mut ident,
142+
SyntheticMod {
143+
ref mut attrs,
144+
ref mut unsafety,
145+
ref mut abi,
146+
ref mut items,
147+
},
148+
) in self.synthetic_mods.drain()
149+
{
150+
let cfg_attrs = attrs.cfg_attrs.iter().collect::<Vec<_>>();
151+
let cc_attrs = attrs.cc_attrs.iter().collect::<Vec<_>>();
152+
let synthetic_mod = if abi.is_some() {
36153
quote! {
37-
#(#items)*
154+
#(#cfg_attrs)*
155+
pub mod #ident {
156+
#(#cc_attrs)*
157+
#unsafety #abi {
158+
#(#items)*
159+
}
160+
}
38161
}
39162
} else {
40-
// TODO: Don't swallow abi/unsafety :(
41163
quote! {
42-
#(#cc_attrs)*
43-
unsafe extern "C" {
164+
#(#cfg_attrs)*
165+
pub mod #ident {
44166
#(#items)*
45167
}
46168
}
47169
};
48170

49171
self.new_items.push(Item::Verbatim(quote! {
50-
#(#cfg_attrs)*
51-
pub mod #ident {
52-
#block
53-
}
172+
#synthetic_mod
54173

55174
#(#cfg_attrs)*
56175
pub use #ident::*;
@@ -63,17 +182,17 @@ impl Visitor {
63182
fn visit_items(&mut self, items: &mut Vec<Item>) {
64183
for mut item in std::mem::take(items) {
65184
match &mut item {
66-
Item::Const(ItemConst { ref mut attrs, .. })
67-
| Item::Struct(ItemStruct { ref mut attrs, .. })
68-
| Item::Enum(ItemEnum { ref mut attrs, .. })
69-
| Item::Fn(ItemFn { ref mut attrs, .. })
70-
| Item::Union(ItemUnion { ref mut attrs, .. })
71-
| Item::Type(ItemType { ref mut attrs, .. })
72-
| Item::Impl(ItemImpl { ref mut attrs, .. })
73-
| Item::Mod(ItemMod { ref mut attrs, .. })
74-
| Item::Use(ItemUse { ref mut attrs, .. })
75-
| Item::Static(ItemStatic { ref mut attrs, .. }) => {
76-
let attr_set = partition_attributes(attrs);
185+
Item::Const(ItemConst { ref mut attrs, .. }) |
186+
Item::Struct(ItemStruct { ref mut attrs, .. }) |
187+
Item::Enum(ItemEnum { ref mut attrs, .. }) |
188+
Item::Union(ItemUnion { ref mut attrs, .. }) |
189+
Item::Type(ItemType { ref mut attrs, .. }) |
190+
Item::Use(ItemUse { ref mut attrs, .. }) |
191+
Item::Static(ItemStatic { ref mut attrs, .. }) |
192+
Item::Mod(ItemMod { ref mut attrs, .. }) |
193+
Item::Impl(ItemImpl { ref mut attrs, .. }) |
194+
Item::Fn(ItemFn { ref mut attrs, .. }) => {
195+
let attr_set = AttributeSet::new(attrs, None, None);
77196
*attrs = attr_set.other_attrs.iter().cloned().collect();
78197
self.insert_item_into_mod(attr_set, item);
79198
}
@@ -89,19 +208,23 @@ impl Visitor {
89208

90209
fn visit_foreign_mod(&mut self, foreign_mod: &mut ItemForeignMod) {
91210
for mut foreign_item in std::mem::take(&mut foreign_mod.items) {
92-
let mut attr_set = partition_attributes(&foreign_mod.attrs);
93-
let inner_attrs = match &mut foreign_item {
94-
ForeignItem::Fn(f) => &mut f.attrs,
95-
ForeignItem::Static(s) => &mut s.attrs,
96-
ForeignItem::Type(t) => &mut t.attrs,
97-
ForeignItem::Macro(m) => &mut m.attrs,
98-
_ => &mut Vec::new(),
99-
};
100-
101-
let inner_attr_set = partition_attributes(inner_attrs);
102-
attr_set.other_attrs.extend(inner_attr_set.other_attrs);
103-
attr_set.cfg_attrs.extend(inner_attr_set.cfg_attrs);
104-
attr_set.cc_attrs.extend(inner_attr_set.cc_attrs);
211+
let (inner_attrs, inner_unsafety, inner_abi) =
212+
match &mut foreign_item {
213+
ForeignItem::Fn(f) => {
214+
(&mut f.attrs, f.sig.unsafety, f.sig.abi.clone())
215+
}
216+
ForeignItem::Static(s) => (&mut s.attrs, None, None),
217+
ForeignItem::Type(t) => (&mut t.attrs, None, None),
218+
ForeignItem::Macro(m) => (&mut m.attrs, None, None),
219+
_ => (&mut Vec::new(), None, None),
220+
};
221+
222+
let mut attr_set = AttributeSet::new(
223+
&foreign_mod.attrs,
224+
foreign_mod.unsafety,
225+
Some(foreign_mod.abi.clone()),
226+
);
227+
attr_set.extend(inner_attrs, inner_unsafety, inner_abi);
105228
*inner_attrs = attr_set.other_attrs.iter().cloned().collect();
106229

107230
self.insert_item_into_mod(
@@ -113,70 +236,17 @@ impl Visitor {
113236

114237
fn insert_item_into_mod(&mut self, attr_set: AttributeSet, item: Item) {
115238
if !attr_set.cfg_attrs.is_empty() || !attr_set.cc_attrs.is_empty() {
116-
let (_, items) = self.synthetic_mods
117-
.entry(attr_set.ident())
118-
.or_insert_with(|| (attr_set, Vec::new()));
119-
items.push(item);
239+
let ident = attr_set.ident();
240+
let synthetic_mod = self
241+
.synthetic_mods
242+
.entry(ident)
243+
.or_insert_with(|| SyntheticMod::new(attr_set.clone()));
244+
synthetic_mod.items.push(item);
245+
synthetic_mod.unsafety = attr_set.unsafety;
246+
synthetic_mod.abi = attr_set.abi.clone();
247+
synthetic_mod.attrs = attr_set;
120248
} else {
121249
self.new_items.push(item);
122250
}
123251
}
124252
}
125-
126-
#[derive(Default)]
127-
struct AttributeSet {
128-
cfg_attrs: HashSet<Attribute>,
129-
cc_attrs: HashSet<Attribute>,
130-
other_attrs: HashSet<Attribute>,
131-
}
132-
133-
impl AttributeSet {
134-
fn ident(&self) -> Ident {
135-
assert!(!self.cfg_attrs.is_empty() || !self.cc_attrs.is_empty());
136-
137-
Ident::new(
138-
self.cfg_attrs
139-
.iter()
140-
.chain(self.cc_attrs.iter())
141-
.map(|attr| attr.to_token_stream().to_string())
142-
.sorted()
143-
.map(|s| {
144-
s.replace('=', "_eq_").replace(
145-
|c: char| !c.is_alphanumeric() && c != '_',
146-
"_",
147-
)
148-
})
149-
.join("_")
150-
.chars()
151-
.coalesce(|a, b| {
152-
if a == '_' && b == '_' {
153-
Ok(a)
154-
} else {
155-
Err((a, b))
156-
}
157-
})
158-
.collect::<String>()
159-
.trim_matches('_'),
160-
Span::call_site(),
161-
)
162-
}
163-
}
164-
165-
fn partition_attributes(attrs: &[Attribute]) -> AttributeSet {
166-
let mut attribute_set = AttributeSet::default();
167-
168-
for attr in attrs {
169-
let target_set = if let Some(ident) = attr.path().get_ident() {
170-
match ident.to_string().as_str() {
171-
"cfg" => &mut attribute_set.cfg_attrs,
172-
"link" => &mut attribute_set.cc_attrs,
173-
_ => &mut attribute_set.other_attrs,
174-
}
175-
} else {
176-
&mut attribute_set.other_attrs
177-
};
178-
target_set.insert(attr.clone());
179-
}
180-
181-
attribute_set
182-
}

0 commit comments

Comments
 (0)