Skip to content

Commit ba747cd

Browse files
committed
extract unexposed attributes
1 parent 7fa654c commit ba747cd

15 files changed

+477
-40
lines changed

Diff for: src/clang.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,7 @@ impl Drop for Index {
10591059
}
10601060

10611061
/// A token emitted by clang's lexer.
1062-
#[derive(Debug)]
1062+
#[derive(Debug, Clone)]
10631063
pub struct Token {
10641064
/// The kind of token this is.
10651065
pub kind: CXTokenKind,

Diff for: src/codegen/helpers.rs

+43
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,25 @@ pub mod attributes {
2626
aster::AstBuilder::new().attr().word("inline")
2727
}
2828

29+
pub fn cold() -> ast::Attribute {
30+
aster::AstBuilder::new().attr().word("cold")
31+
}
32+
33+
pub fn deprecated(_: Option<&str>) -> ast::Attribute {
34+
aster::AstBuilder::new().attr().word("deprecated")
35+
}
36+
2937
pub fn doc(comment: &str) -> ast::Attribute {
3038
aster::AstBuilder::new().attr().doc(comment)
3139
}
3240

3341
pub fn link_name(name: &str) -> ast::Attribute {
3442
aster::AstBuilder::new().attr().name_value("link_name").str(name)
3543
}
44+
45+
pub fn allow(rules: Vec<&str>) -> ast::Attribute {
46+
aster::AstBuilder::new().attr().allow(rules)
47+
}
3648
}
3749

3850
/// Generates a proper type for a field or type with a given `Layout`, that is,
@@ -75,12 +87,15 @@ impl BlobTyBuilder {
7587
}
7688

7789
pub mod ast_ty {
90+
use std::str;
7891
use aster;
7992
use ir::context::BindgenContext;
8093
use ir::function::FunctionSig;
8194
use ir::ty::FloatKind;
95+
use ir::attr;
8296
use syntax::ast;
8397
use syntax::ptr::P;
98+
use super::attributes;
8499

85100
pub fn raw_type(ctx: &BindgenContext, name: &str) -> P<ast::Ty> {
86101
let ident = ctx.rust_ident_raw(&name);
@@ -187,4 +202,32 @@ pub mod ast_ty {
187202
})
188203
.collect::<Vec<_>>()
189204
}
205+
206+
pub fn attribute_to_rust(attribute: &attr::Attribute) -> ast::Attribute {
207+
match *attribute {
208+
attr::Attribute::Deprecated(ref text) => attributes::deprecated(text.as_ref().map(|s| s.as_str())),
209+
attr::Attribute::Unused => attributes::allow(vec!["dead_code"]),
210+
attr::Attribute::Used => attributes::doc("#[doc = \"__attribute__(unused)\"]"),
211+
attr::Attribute::Cold => attributes::cold(),
212+
attr::Attribute::Const => attributes::doc("#[doc = \"__attribute__(const)\"]"),
213+
attr::Attribute::Constructor(_) => attributes::doc("#[doc = \"__attribute__(constructor)\"]"),
214+
attr::Attribute::Destructor(_) => attributes::doc("#[doc = \"__attribute__(destructor)\"]"),
215+
attr::Attribute::Aligned(ref tokens) => {
216+
let s = tokens.iter()
217+
.map(|ref token| unsafe { str::from_utf8_unchecked(&token.raw) })
218+
.fold(String::new(), |acc, ref s| { acc + &s });
219+
let t = format!("#[doc = \"__attribute__(aligned{})\"]", s.as_str());
220+
221+
attributes::doc(&t)
222+
}
223+
attr::Attribute::Unexposed(ref name, ref tokens) => {
224+
let s = tokens.iter()
225+
.map(|ref token| unsafe { str::from_utf8_unchecked(&token.raw) })
226+
.fold(String::new(), |acc, ref s| { acc + &s });
227+
let t = format!("#[doc = \"__attribute__({}{})\"]", name, s);
228+
229+
attributes::doc(&t)
230+
}
231+
}
232+
}
190233
}

Diff for: src/codegen/mod.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -426,11 +426,19 @@ impl CodeGenerator for Var {
426426
result.saw_var(&canonical_name);
427427

428428
let ty = self.ty().to_rust_ty(ctx);
429+
let mut attrs = vec![];
430+
431+
if ctx.options().generate_comments {
432+
for attr in self.attributes() {
433+
attrs.push(helpers::ast_ty::attribute_to_rust(attr));
434+
}
435+
}
429436

430437
if let Some(val) = self.val() {
431438
let const_item = aster::AstBuilder::new()
432439
.item()
433440
.pub_()
441+
.with_attrs(attrs)
434442
.const_(canonical_name)
435443
.expr();
436444
let item = match *val {
@@ -474,7 +482,6 @@ impl CodeGenerator for Var {
474482

475483
result.push(item);
476484
} else {
477-
let mut attrs = vec![];
478485
if let Some(mangled) = self.mangled_name() {
479486
attrs.push(attributes::link_name(mangled));
480487
} else if canonical_name != self.name() {
@@ -877,6 +884,9 @@ impl CodeGenerator for CompInfo {
877884
if let Some(comment) = item.comment() {
878885
attributes.push(attributes::doc(comment));
879886
}
887+
for attr in self.attributes() {
888+
attributes.push(helpers::ast_ty::attribute_to_rust(attr));
889+
}
880890
}
881891
if self.packed() {
882892
attributes.push(attributes::repr_list(&["C", "packed"]));
@@ -1091,6 +1101,9 @@ impl CodeGenerator for CompInfo {
10911101
if let Some(comment) = field.comment() {
10921102
attrs.push(attributes::doc(comment));
10931103
}
1104+
for attr in field.attributes() {
1105+
attrs.push(helpers::ast_ty::attribute_to_rust(attr));
1106+
}
10941107
}
10951108
let field_name = match field.name() {
10961109
Some(name) => ctx.rust_mangle(name).into_owned(),
@@ -1791,6 +1804,9 @@ impl CodeGenerator for Enum {
17911804
if let Some(comment) = item.comment() {
17921805
builder = builder.with_attr(attributes::doc(comment));
17931806
}
1807+
for attr in self.attributes() {
1808+
builder = builder.with_attr(helpers::ast_ty::attribute_to_rust(attr));
1809+
}
17941810
}
17951811

17961812
if !is_constified_enum {
@@ -2217,6 +2233,9 @@ impl CodeGenerator for Function {
22172233
if let Some(comment) = item.comment() {
22182234
attributes.push(attributes::doc(comment));
22192235
}
2236+
for attr in self.attributes() {
2237+
attributes.push(helpers::ast_ty::attribute_to_rust(attr));
2238+
}
22202239
}
22212240

22222241
if let Some(mangled) = mangled_name {

Diff for: src/ir/attr.rs

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
//! Intermediate representation for attributes.
2+
use std::str;
3+
4+
use clang::Cursor;
5+
use clang_sys::{CXCursor_UnexposedAttr, CXChildVisit_Continue};
6+
use cexpr::token::{Token, Kind};
7+
8+
use super::context::BindgenContext;
9+
10+
/// The special attribute
11+
#[derive(Clone, Debug)]
12+
pub enum Attribute {
13+
/// This attribute results in a warning if the type is used anywhere in the source file.
14+
Deprecated(Option<String>),
15+
/// This attribute means that variables of that type are meant to appear possibly unused.
16+
Unused,
17+
/// This attribute attached to a function, means that code must be emitted for the function
18+
/// even if it appears that the function is not referenced.
19+
Used,
20+
/// This attribute on functions is used to inform the compiler that the function is unlikely to be executed.
21+
Cold,
22+
/// Many functions do not examine any values except their arguments,
23+
/// and have no effects except the return value.
24+
Const,
25+
/// This attribute causes the function to be called automatically before execution enters main ().
26+
Constructor(Option<isize>),
27+
/// This attribute causes the function to be called automatically after main () completes or exit () is called.
28+
Destructor(Option<isize>),
29+
/// This attribute specifies a minimum alignment (in bytes)
30+
Aligned(Vec<Token>),
31+
/// An attribute whose specific kind is not exposed via this interface.
32+
Unexposed(String, Vec<Token>)
33+
}
34+
35+
impl Attribute {
36+
/// Construct a new `Attribute`.
37+
pub fn new(tokens: Vec<Token>) -> Self {
38+
// https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html#Attribute-Syntax
39+
assert!(!tokens.is_empty());
40+
41+
let (token, args) = tokens.split_first().unwrap();
42+
43+
assert_eq!(token.kind, Kind::Identifier);
44+
45+
let name = unsafe { str::from_utf8_unchecked(&token.raw) };
46+
47+
debug!("__attribute__(({}({:?})))", name, args);
48+
49+
match name {
50+
"deprecated" => {
51+
let text = if args.len() == 3 &&
52+
args[0].kind == Kind::Punctuation && args[0].raw.as_ref() == b"(" &&
53+
args[1].kind == Kind::Literal &&
54+
args[2].kind == Kind::Punctuation && args[2].raw.as_ref() == b")" {
55+
str::from_utf8(args[1].raw.as_ref()).ok().map(String::from)
56+
} else {
57+
None
58+
};
59+
60+
Attribute::Deprecated(text)
61+
}
62+
"unused" => Attribute::Unused,
63+
"used" => Attribute::Used,
64+
"cold" => Attribute::Cold,
65+
"const" => Attribute::Const,
66+
"constructor" => {
67+
let priority = if args.len() == 3 &&
68+
args[0].kind == Kind::Punctuation && args[0].raw.as_ref() == b"(" &&
69+
args[1].kind == Kind::Literal &&
70+
args[2].kind == Kind::Punctuation && args[2].raw.as_ref() == b")" {
71+
str::from_utf8(args[1].raw.as_ref()).ok().and_then(|s| s.parse::<isize>().ok())
72+
} else {
73+
None
74+
};
75+
76+
Attribute::Constructor(priority)
77+
}
78+
"destructor" => {
79+
let priority = if args.len() == 3 &&
80+
args[0].kind == Kind::Punctuation && args[0].raw.as_ref() == b"(" &&
81+
args[1].kind == Kind::Literal &&
82+
args[2].kind == Kind::Punctuation && args[2].raw.as_ref() == b")" {
83+
str::from_utf8(args[1].raw.as_ref()).ok().and_then(|s| s.parse::<isize>().ok())
84+
} else {
85+
None
86+
};
87+
88+
Attribute::Destructor(priority)
89+
}
90+
"aligned" => Attribute::Aligned(Vec::from(args)),
91+
_ => Attribute::Unexposed(String::from(name), Vec::from(args)),
92+
}
93+
}
94+
95+
/// Parse a `Cursor` for `Vec<Attribute>`.
96+
pub fn parse(cur: &Cursor, ctx: &BindgenContext) -> Vec<Self> {
97+
let mut attributes = vec![];
98+
99+
if let Some(tokens) = ctx.translation_unit().cexpr_tokens(&cur) {
100+
let mut c = 0;
101+
let mut iter = tokens.iter();
102+
103+
while c >= 0 {
104+
let tokens = iter.by_ref().take_while(|ref token| {
105+
if token.kind == Kind::Punctuation {
106+
c += match token.raw.as_ref() {
107+
b"(" => 1,
108+
b")" => -1,
109+
b"," if c == 0 => return false,
110+
_ => 0,
111+
}
112+
}
113+
114+
c >= 0
115+
}).map(|token| token.clone()).collect::<Vec<Token>>();
116+
117+
if tokens.is_empty() {
118+
break
119+
} else {
120+
attributes.push(Attribute::new(tokens));
121+
}
122+
}
123+
}
124+
125+
attributes
126+
}
127+
128+
/// Extract `Vec<Attribute>` from cursor's children.
129+
pub fn extract(cur: &Cursor, ctx: &BindgenContext) -> Vec<Self> {
130+
let mut attributes = vec![];
131+
132+
cur.visit(|cur| {
133+
match cur.kind() {
134+
CXCursor_UnexposedAttr => {
135+
attributes.append(&mut Attribute::parse(&cur, ctx))
136+
}
137+
_ => {}
138+
}
139+
CXChildVisit_Continue
140+
});
141+
142+
attributes
143+
}
144+
145+
/// Whether this attribute whose specific kind is not exposed.
146+
pub fn is_unexposed(&self) -> bool {
147+
match *self {
148+
Attribute::Unexposed(..) |
149+
Attribute::Aligned(..) => true,
150+
_ => false,
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)