зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1341102: Revendor rust dependencies on a CLOSED TREE. r=red
MozReview-Commit-ID: GrqpxUECOtt --HG-- rename : third_party/rust/bitflags/.cargo-checksum.json => third_party/rust/bitflags-0.7.0/.cargo-checksum.json rename : third_party/rust/bitflags/.travis.yml => third_party/rust/bitflags-0.7.0/.travis.yml rename : third_party/rust/bitflags/Cargo.toml => third_party/rust/bitflags-0.7.0/Cargo.toml rename : third_party/rust/dtoa/LICENSE-APACHE => third_party/rust/bitflags-0.7.0/LICENSE-APACHE rename : third_party/rust/serde_json/LICENSE-MIT => third_party/rust/bitflags-0.7.0/LICENSE-MIT rename : third_party/rust/bitflags/README.md => third_party/rust/bitflags-0.7.0/README.md rename : third_party/rust/bitflags/src/lib.rs => third_party/rust/bitflags-0.7.0/src/lib.rs rename : third_party/rust/itoa/LICENSE-APACHE => third_party/rust/syntex/LICENSE-APACHE rename : third_party/rust/serde_json/LICENSE-MIT => third_party/rust/syntex/LICENSE-MIT rename : third_party/rust/serde_json/LICENSE-APACHE => third_party/rust/syntex_errors/LICENSE-APACHE rename : third_party/rust/serde_json/LICENSE-MIT => third_party/rust/syntex_errors/LICENSE-MIT rename : third_party/rust/dtoa/LICENSE-APACHE => third_party/rust/syntex_pos/LICENSE-APACHE rename : third_party/rust/serde_json/LICENSE-MIT => third_party/rust/syntex_pos/LICENSE-MIT rename : third_party/rust/dtoa/LICENSE-APACHE => third_party/rust/syntex_syntax/LICENSE-APACHE rename : third_party/rust/serde_json/LICENSE-MIT => third_party/rust/syntex_syntax/LICENSE-MIT
This commit is contained in:
Родитель
b6d4239e55
Коммит
4fa90b8c5b
|
@ -1 +1 @@
|
|||
{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","Cargo.toml":"a5b1192b97986381fc06f9e4c7b857867296efe0c585b3a7daff04c991b15e11","src/arm.rs":"83b6ba22ded921ae45e02888e879b2ae73d4659db53e6552675433c3c2e0ed21","src/attr.rs":"7c6d6ff66cfbfa23e5857192db1c7e97c3b2826f4434ea7bd5d4b1ded1fe8b5e","src/block.rs":"71e2268ba151b7ee60a2fe0b0b3a7cf3e2ce3bff4fb0ee260db70ad9b1cd8826","src/constant.rs":"471b0ffc52684733a598a43e08b1719bf6852c26eca74e7f5105f0f964543980","src/ctx.rs":"738213a64a96cfe3beba6d08d82d89d48dc384b37fe726621b324bac5c017859","src/expr.rs":"6e74fc51fe53dada39f4be3371562a015869f29cff37b186fc574aae703251ae","src/fn_decl.rs":"85c30d78942bb7cda0c6bddcf55f1a35b3581a99fb15e33f3abf2763b84f8073","src/generics.rs":"3d8198e7d1b8de295ed8ee5203e6676cbd588a2975ab09709abe51991fc16e21","src/ident.rs":"31ebf657a9c267e24e66ed5e83cc76056e8d2564a8f60883871490e414154223","src/invoke.rs":"03f52dd0b135e8ffcc52c3802cdf8d516ef4a53e393ce4bdd82ced19fd106b88","src/item.rs":"43dec8003165eefaddb7effc7c8664088661c992e96b550a0624ec04e380da9e","src/lib.rs":"64faae6667ed9702bd06fd942dc27e53b7dd484aabe15396ef3c212c0b255316","src/lifetime.rs":"1801727768d88328b816a6aafe92add956d2399a82e794ca2eeac47d5f5bd681","src/lit.rs":"5420333f97ab32d9f373336851c1791802ef73fa5f1bc5139288f503c28a1ba6","src/mac.rs":"ac9569bf0f87a043dcb31063a64cff405b7f6996efaa8d9059cbc4b18781e356","src/method.rs":"bce543c148022170decd0cff9af3b37781323bcdf0dc35e23beec5f200dbc549","src/pat.rs":"0c3c0cb22054d09a2b7df277e4c05023c079d655d54b66a6bf732d56d58971e0","src/path.rs":"6f3f4e4c6f26f01674ca91635516448318f69b94061ce5694eaac15428336b51","src/qpath.rs":"b01bfe2b391754d00f32b7691ae7d65d0d91d78d69c4dfa9250e34d27b5315cf","src/self_.rs":"565780ba85ba851675331cd60dbe8a43f5eb87c318f6cc3b11bb7ba77a0d53fa","src/stmt.rs":"99e577b1417ff66c3057454ca27266a19329c6896b0f36259dcbdba0ff0005fb","src/struct_field.rs":"189fa910e236fea815d85c6b4535a76e6e7151a9d113a806bb60c6a192c7042b","src/symbol.rs":"ecab71523e9a819e063ce4231520bb7b46ba2ac8f2e2212f4f4e189d2988792e","src/ty.rs":"8d698e030192cb85207a3a4b7505af31b457360946e502673ade99dbfb30c32e","src/ty_param.rs":"a89a656a01db3d710dfbf3248b75683734eaf24c329ea241b3e54f39c8fc278f","src/variant.rs":"7fed49d694e029c81b4b70095e00704f1c67ef6357d122157d305f85dd95a512","src/variant_data.rs":"346198e982a2549ed4942ac7c6581f222f6284392afd9c0898acbfa53f58ffd3","src/where_predicate.rs":"e1645a51d5c396055629bdd351a38204f5cf81b9e2c142798ed098df99712298"},"package":"2c9b49e42a449c0b79d8acb91db37621de0978064dca7d3288ddcf030123e5b3"}
|
||||
{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","Cargo.toml":"687fdaee594caaf4e71f43436f1ad56ede33916858eda1dbd1996ead64e1434e","src/arm.rs":"83b6ba22ded921ae45e02888e879b2ae73d4659db53e6552675433c3c2e0ed21","src/attr.rs":"7c6d6ff66cfbfa23e5857192db1c7e97c3b2826f4434ea7bd5d4b1ded1fe8b5e","src/block.rs":"71e2268ba151b7ee60a2fe0b0b3a7cf3e2ce3bff4fb0ee260db70ad9b1cd8826","src/constant.rs":"471b0ffc52684733a598a43e08b1719bf6852c26eca74e7f5105f0f964543980","src/ctx.rs":"738213a64a96cfe3beba6d08d82d89d48dc384b37fe726621b324bac5c017859","src/expr.rs":"e3c1237d1631f32ca2459f9579cbe4ec5877952227527df4feb5694f303f6d95","src/fn_decl.rs":"85c30d78942bb7cda0c6bddcf55f1a35b3581a99fb15e33f3abf2763b84f8073","src/generics.rs":"0ee307fadb0922599d9f8b0be5b9eb6966a601b2792167fe881911efc5debcb1","src/ident.rs":"31ebf657a9c267e24e66ed5e83cc76056e8d2564a8f60883871490e414154223","src/invoke.rs":"03f52dd0b135e8ffcc52c3802cdf8d516ef4a53e393ce4bdd82ced19fd106b88","src/item.rs":"238d4e8ecef7c1d2a4104e6ff12a24bdf0a238c22e4ea6749dad12bd21febf33","src/lib.rs":"64faae6667ed9702bd06fd942dc27e53b7dd484aabe15396ef3c212c0b255316","src/lifetime.rs":"1801727768d88328b816a6aafe92add956d2399a82e794ca2eeac47d5f5bd681","src/lit.rs":"5420333f97ab32d9f373336851c1791802ef73fa5f1bc5139288f503c28a1ba6","src/mac.rs":"ac9569bf0f87a043dcb31063a64cff405b7f6996efaa8d9059cbc4b18781e356","src/method.rs":"bce543c148022170decd0cff9af3b37781323bcdf0dc35e23beec5f200dbc549","src/pat.rs":"39cc530a1b246e67c1e004fee1dcba9befe4264404d9a38ced3cb348a88b4c55","src/path.rs":"d5370cf1b134e564a636ce435213b3027b6e24ae42eb94c9806ec13e2b9a6045","src/qpath.rs":"b01bfe2b391754d00f32b7691ae7d65d0d91d78d69c4dfa9250e34d27b5315cf","src/self_.rs":"565780ba85ba851675331cd60dbe8a43f5eb87c318f6cc3b11bb7ba77a0d53fa","src/stmt.rs":"99e577b1417ff66c3057454ca27266a19329c6896b0f36259dcbdba0ff0005fb","src/struct_field.rs":"189fa910e236fea815d85c6b4535a76e6e7151a9d113a806bb60c6a192c7042b","src/symbol.rs":"ecab71523e9a819e063ce4231520bb7b46ba2ac8f2e2212f4f4e189d2988792e","src/ty.rs":"d79a6d58e008d520761e3a6c1a5dc7732fa62694680a23a2c07dc9ea44781f2e","src/ty_param.rs":"082adf61d2959ffe6880e85b6c0356a59529a52c1caee23f0403d33bf7b600c0","src/variant.rs":"7fed49d694e029c81b4b70095e00704f1c67ef6357d122157d305f85dd95a512","src/variant_data.rs":"346198e982a2549ed4942ac7c6581f222f6284392afd9c0898acbfa53f58ffd3","src/where_predicate.rs":"41bc54f94e9fdc89b1a86cb293fb2626b3fd3905666a7baa7b78d41baa18abfa"},"package":"4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0"}
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "aster"
|
||||
version = "0.38.0"
|
||||
version = "0.41.0"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "A libsyntax ast builder"
|
||||
|
@ -12,9 +12,9 @@ with-syntex = ["syntex_syntax"]
|
|||
unstable-testing = ["clippy", "compiletest_rs"]
|
||||
|
||||
[dependencies]
|
||||
syntex_syntax = { version = "^0.54.0", optional = true }
|
||||
syntex_syntax = { version = "0.58", optional = true }
|
||||
clippy = { version = "0.*", optional = true }
|
||||
compiletest_rs = { version = "^0.2.0", optional = true }
|
||||
compiletest_rs = { version = "0.2", optional = true }
|
||||
|
||||
[[test]]
|
||||
name = "test"
|
||||
|
|
|
@ -1110,6 +1110,7 @@ impl<I, F> Invoke<P<ast::Expr>> for ExprStructFieldBuilder<I, F>
|
|||
expr: expr,
|
||||
span: self.builder.span,
|
||||
is_shorthand: false,
|
||||
attrs: Vec::new().into(),
|
||||
};
|
||||
self.builder.fields.push(field);
|
||||
self.builder
|
||||
|
@ -1904,7 +1905,7 @@ impl<F: Invoke<P<ast::Expr>>> ExprSliceBuilder<F>
|
|||
}
|
||||
|
||||
pub fn build(self) -> F::Result {
|
||||
self.builder.build_expr_kind(ast::ExprKind::Vec(self.exprs))
|
||||
self.builder.build_expr_kind(ast::ExprKind::Array(self.exprs))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ use std::iter::IntoIterator;
|
|||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{DUMMY_SP, Span};
|
||||
use syntax::ptr::P;
|
||||
|
||||
use ident::ToIdent;
|
||||
use invoke::{Invoke, Identity};
|
||||
|
@ -50,7 +49,7 @@ impl<F> GenericsBuilder<F>
|
|||
callback: callback,
|
||||
span: DUMMY_SP,
|
||||
lifetimes: generics.lifetimes,
|
||||
ty_params: generics.ty_params.into_vec(),
|
||||
ty_params: generics.ty_params,
|
||||
predicates: generics.where_clause.predicates,
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +199,7 @@ impl<F> GenericsBuilder<F>
|
|||
|
||||
pub fn strip_ty_params(mut self) -> Self {
|
||||
for ty_param in &mut self.ty_params {
|
||||
ty_param.bounds = P::new();
|
||||
ty_param.bounds = vec![];
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -213,7 +212,7 @@ impl<F> GenericsBuilder<F>
|
|||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(ast::Generics {
|
||||
lifetimes: self.lifetimes,
|
||||
ty_params: P::from_vec(self.ty_params),
|
||||
ty_params: self.ty_params,
|
||||
where_clause: ast::WhereClause {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
predicates: self.predicates,
|
||||
|
|
|
@ -909,7 +909,7 @@ impl<F> ItemTraitBuilder<F>
|
|||
self.builder.build_item_kind(self.id, ast::ItemKind::Trait(
|
||||
self.unsafety,
|
||||
self.generics,
|
||||
P::from_vec(self.bounds),
|
||||
self.bounds,
|
||||
self.items,
|
||||
))
|
||||
}
|
||||
|
@ -1123,7 +1123,7 @@ impl<F> ItemTraitTypeBuilder<F>
|
|||
|
||||
pub fn build_option_ty(self, ty: Option<P<ast::Ty>>) -> F::Result {
|
||||
let bounds = P::from_vec(self.bounds);
|
||||
let node = ast::TraitItemKind::Type(bounds, ty);
|
||||
let node = ast::TraitItemKind::Type(bounds.into_vec(), ty);
|
||||
self.builder.build_item(node)
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ impl<F> PatBuilder<F>
|
|||
}
|
||||
|
||||
pub fn build_range(self, lhs: P<ast::Expr>, rhs: P<ast::Expr>) -> F::Result {
|
||||
self.build_pat_kind(ast::PatKind::Range(lhs, rhs))
|
||||
self.build_pat_kind(ast::PatKind::Range(lhs, rhs, ast::RangeEnd::Included))
|
||||
}
|
||||
|
||||
pub fn range(self) -> ExprBuilder<PatRangeBuilder<F>> {
|
||||
|
@ -432,6 +432,7 @@ impl<F> PatStructPathBuilder<F>
|
|||
ident: id,
|
||||
pat: pat,
|
||||
is_shorthand: true,
|
||||
attrs: Vec::new().into(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -446,6 +447,7 @@ impl<F> PatStructPathBuilder<F>
|
|||
ident: id,
|
||||
pat: pat,
|
||||
is_shorthand: true,
|
||||
attrs: Vec::new().into(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -475,6 +477,7 @@ impl<F> Invoke<P<ast::Pat>> for PatStructFieldBuilder<F>
|
|||
ident: self.id,
|
||||
pat: pat,
|
||||
is_shorthand: false,
|
||||
attrs: Vec::new().into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -314,8 +314,8 @@ impl<F> PathSegmentBuilder<F>
|
|||
} else {
|
||||
let data = ast::AngleBracketedParameterData {
|
||||
lifetimes: self.lifetimes,
|
||||
types: P::from_vec(self.tys),
|
||||
bindings: P::from_vec(self.bindings),
|
||||
types: self.tys,
|
||||
bindings: self.bindings,
|
||||
};
|
||||
|
||||
Some(P(ast::PathParameters::AngleBracketed(data)))
|
||||
|
|
|
@ -199,13 +199,6 @@ impl<F> TyBuilder<F>
|
|||
TyBuilder::with_callback(TyIteratorBuilder(self)).span(span)
|
||||
}
|
||||
|
||||
pub fn object_sum(self) -> TyBuilder<TyObjectSumBuilder<F>> {
|
||||
let span = self.span;
|
||||
TyBuilder::with_callback(TyObjectSumBuilder {
|
||||
builder: self,
|
||||
}).span(span)
|
||||
}
|
||||
|
||||
pub fn impl_trait(self) -> TyImplTraitTyBuilder<F> {
|
||||
TyImplTraitTyBuilder { builder: self, bounds: Vec::new() }
|
||||
}
|
||||
|
@ -454,91 +447,6 @@ impl<F> Invoke<P<ast::Ty>> for TyIteratorBuilder<F>
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub struct TyObjectSumBuilder<F> {
|
||||
builder: TyBuilder<F>,
|
||||
}
|
||||
|
||||
impl<F> Invoke<P<ast::Ty>> for TyObjectSumBuilder<F>
|
||||
where F: Invoke<P<ast::Ty>>,
|
||||
{
|
||||
type Result = TyObjectSumTyBuilder<F>;
|
||||
|
||||
fn invoke(self, ty: P<ast::Ty>) -> Self::Result {
|
||||
TyObjectSumTyBuilder {
|
||||
builder: self.builder,
|
||||
ty: ty,
|
||||
bounds: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TyObjectSumTyBuilder<F> {
|
||||
builder: TyBuilder<F>,
|
||||
ty: P<ast::Ty>,
|
||||
bounds: Vec<ast::TyParamBound>,
|
||||
}
|
||||
|
||||
impl<F> TyObjectSumTyBuilder<F>
|
||||
where F: Invoke<P<ast::Ty>>,
|
||||
{
|
||||
pub fn with_bounds<I>(mut self, iter: I) -> Self
|
||||
where I: Iterator<Item=ast::TyParamBound>,
|
||||
{
|
||||
self.bounds.extend(iter);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_bound(mut self, bound: ast::TyParamBound) -> Self {
|
||||
self.bounds.push(bound);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn bound(self) -> TyParamBoundBuilder<Self> {
|
||||
TyParamBoundBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
pub fn with_generics(self, generics: ast::Generics) -> Self {
|
||||
self.with_lifetimes(
|
||||
generics.lifetimes.into_iter()
|
||||
.map(|def| def.lifetime)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn with_lifetimes<I, L>(mut self, lifetimes: I) -> Self
|
||||
where I: Iterator<Item=L>,
|
||||
L: IntoLifetime,
|
||||
{
|
||||
for lifetime in lifetimes {
|
||||
self = self.lifetime(lifetime);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn lifetime<L>(self, lifetime: L) -> Self
|
||||
where L: IntoLifetime,
|
||||
{
|
||||
self.bound().lifetime(lifetime)
|
||||
}
|
||||
|
||||
pub fn build(self) -> F::Result {
|
||||
let bounds = P::from_vec(self.bounds);
|
||||
self.builder.build_ty_kind(ast::TyKind::ObjectSum(self.ty, bounds))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Invoke<ast::TyParamBound> for TyObjectSumTyBuilder<F>
|
||||
where F: Invoke<P<ast::Ty>>,
|
||||
{
|
||||
type Result = Self;
|
||||
|
||||
fn invoke(self, bound: ast::TyParamBound) -> Self {
|
||||
self.with_bound(bound)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub struct TyImplTraitTyBuilder<F> {
|
||||
builder: TyBuilder<F>,
|
||||
bounds: Vec<ast::TyParamBound>,
|
||||
|
@ -588,8 +496,7 @@ impl<F> TyImplTraitTyBuilder<F>
|
|||
}
|
||||
|
||||
pub fn build(self) -> F::Result {
|
||||
let bounds = P::from_vec(self.bounds);
|
||||
self.builder.build_ty_kind(ast::TyKind::ImplTrait(bounds))
|
||||
self.builder.build_ty_kind(ast::TyKind::ImplTrait(self.bounds))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ impl<F> TyParamBuilder<F>
|
|||
callback: callback,
|
||||
span: ty_param.span,
|
||||
id: ty_param.ident,
|
||||
bounds: ty_param.bounds.into_vec(),
|
||||
bounds: ty_param.bounds,
|
||||
default: ty_param.default,
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ impl<F> TyParamBuilder<F>
|
|||
attrs: ast::ThinVec::new(),
|
||||
ident: self.id,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
bounds: P::from_vec(self.bounds),
|
||||
bounds: self.bounds,
|
||||
default: self.default,
|
||||
span: self.span,
|
||||
})
|
||||
|
|
|
@ -53,13 +53,13 @@ impl<F> WherePredicateBuilder<F>
|
|||
}
|
||||
}
|
||||
|
||||
pub fn eq<P>(self, path: P) -> WhereEqPredicateBuilder<F>
|
||||
pub fn eq<P>(self, p: P) -> WhereEqPredicateBuilder<F>
|
||||
where P: IntoPath,
|
||||
{
|
||||
WhereEqPredicateBuilder {
|
||||
callback: self.callback,
|
||||
span: self.span,
|
||||
path: path.into_path(),
|
||||
lhs: TyBuilder::new().build_path(p.into_path()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ impl<F> WhereBoundPredicateTyBoundsBuilder<F>
|
|||
span: self.span,
|
||||
bound_lifetimes: self.bound_lifetimes,
|
||||
bounded_ty: self.ty,
|
||||
bounds: P::from_vec(self.bounds),
|
||||
bounds: self.bounds,
|
||||
};
|
||||
|
||||
self.callback.invoke(ast::WherePredicate::BoundPredicate(predicate))
|
||||
|
@ -302,7 +302,7 @@ impl<F> WhereRegionPredicateBuilder<F>
|
|||
pub struct WhereEqPredicateBuilder<F> {
|
||||
callback: F,
|
||||
span: Span,
|
||||
path: ast::Path,
|
||||
lhs: P<ast::Ty>,
|
||||
}
|
||||
|
||||
impl<F> WhereEqPredicateBuilder<F>
|
||||
|
@ -314,13 +314,13 @@ impl<F> WhereEqPredicateBuilder<F>
|
|||
}
|
||||
|
||||
pub fn build_ty(self, ty: P<ast::Ty>) -> F::Result {
|
||||
let WhereEqPredicateBuilder { callback, span, path } = self;
|
||||
let WhereEqPredicateBuilder { callback, span, lhs } = self;
|
||||
|
||||
let predicate = ast::WhereEqPredicate {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: span,
|
||||
path: path,
|
||||
ty: ty,
|
||||
lhs_ty: lhs,
|
||||
rhs_ty: ty,
|
||||
};
|
||||
|
||||
callback.invoke(ast::WherePredicate::EqPredicate(predicate))
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,59 @@
|
|||
### Input C/C++ Header
|
||||
|
||||
```C++
|
||||
// Insert your (minimal) C/C++ header here.
|
||||
```
|
||||
|
||||
### Bindgen Invokation
|
||||
|
||||
<!-- Place either the `bindgen::Builder` or the command line flags used here. -->
|
||||
|
||||
```Rust
|
||||
bindgen::Builder::default()
|
||||
.header("input.h")
|
||||
.generate()
|
||||
.unwrap()
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
$ bindgen input.h --whatever --flags
|
||||
```
|
||||
|
||||
### Actual Results
|
||||
|
||||
```
|
||||
Insert panic message and backtrace (set the `RUST_BACKTRACE=1` env var) here.
|
||||
```
|
||||
|
||||
and/or
|
||||
|
||||
```rust
|
||||
// Insert the (incorrect/buggy) generated bindings here
|
||||
```
|
||||
|
||||
and/or
|
||||
|
||||
```
|
||||
Insert compilation errors generated when compiling the bindings with rustc here
|
||||
```
|
||||
|
||||
### Expected Results
|
||||
|
||||
<!--
|
||||
Replace this with a description of what you expected instead of the actual
|
||||
results. The more precise, the better! For example, if a struct in the generated
|
||||
bindings is missing a field that exists in the C/C++ struct, note that here.
|
||||
-->
|
||||
|
||||
### `RUST_LOG=bindgen` Output
|
||||
|
||||
<details>
|
||||
|
||||
```
|
||||
Insert debug logging when running bindgen with the `RUST_LOG=bindgen` environment
|
||||
variable set.
|
||||
```
|
||||
|
||||
</details>
|
|
@ -9,14 +9,24 @@ addons:
|
|||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
rust:
|
||||
- stable
|
||||
|
||||
env:
|
||||
- CARGO_TARGET_DIR=/tmp/bindgen LLVM_VERSION=3.8 BINDGEN_FEATURES=testing_only_llvm_stable
|
||||
- CARGO_TARGET_DIR=/tmp/bindgen LLVM_VERSION=3.9 BINDGEN_FEATURES=
|
||||
global:
|
||||
- CARGO_TARGET_DIR=/tmp/bindgen
|
||||
matrix:
|
||||
- LLVM_VERSION=3.7.1 BINDGEN_FEATURES=testing_only_llvm_stable
|
||||
- LLVM_VERSION=3.8.1 BINDGEN_FEATURES=testing_only_llvm_stable
|
||||
- LLVM_VERSION=3.9.0 BINDGEN_FEATURES=
|
||||
- LLVM_VERSION=4.0.0 BINDGEN_FEATURES=
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: LLVM_VERSION=4.0.0 BINDGEN_FEATURES=
|
||||
- env: LLVM_VERSION=3.7.1 BINDGEN_FEATURES=testing_only_llvm_stable
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
@ -25,9 +35,17 @@ cache:
|
|||
before_install: . ./ci/before_install.sh
|
||||
|
||||
script:
|
||||
- ./ci/assert-rustfmt.sh
|
||||
# - ./ci/assert-rustfmt.sh
|
||||
- BINDGEN_FEATURES="$BINDGEN_FEATURES" ./ci/assert-docs.sh
|
||||
- BINDGEN_FEATURES="$BINDGEN_FEATURES" ./ci/test.sh
|
||||
- ./ci/test-book.sh
|
||||
|
||||
after_success:
|
||||
- test "$TRAVIS_PULL_REQUEST" == "false" &&
|
||||
test "$TRAVIS_BRANCH" == "master" &&
|
||||
test "$BINDGEN_FEATURES" == "" &&
|
||||
test "$LLVM_VERSION" == "3.9.0" &&
|
||||
./ci/deploy-book.sh
|
||||
|
||||
notifications:
|
||||
webhooks: http://build.servo.org:54856/travis
|
||||
|
|
|
@ -15,8 +15,8 @@ out to us in a GitHub issue, or stop by
|
|||
- [Overview](#overview)
|
||||
- [Running All Tests](#running-all-tests)
|
||||
- [Authoring New Tests](#authoring-new-tests)
|
||||
- [Generating Graphviz Dot File](#generating-graphviz-dot-file)
|
||||
- [Automatic code formatting](#automatic-code-formatting)
|
||||
- [Generating Graphviz Dot Files](#generating-graphviz-dot-files)
|
||||
- [Debug Logging](#debug-logging)
|
||||
- [Using `creduce` to Minimize Test Cases](#using-creduce-to-minimize-test-cases)
|
||||
- [Isolating Your Test Case](#isolating-your-test-case)
|
||||
|
@ -65,12 +65,12 @@ $ export LD_LIBRARY_PATH=path/to/clang-3.9/lib # for Linux
|
|||
$ export DYLD_LIBRARY_PATH=path/to/clang-3.9/lib # for macOS
|
||||
```
|
||||
|
||||
Additionally, you may want to build and test with the `docs_` feature to ensure
|
||||
that you aren't forgetting to document types and functions. CI will catch it if
|
||||
you forget, but the turn around will be a lot slower ;)
|
||||
Additionally, you may want to build and test with the `testing_only_docs`
|
||||
feature to ensure that you aren't forgetting to document types and functions. CI
|
||||
will catch it if you forget, but the turn around will be a lot slower ;)
|
||||
|
||||
```
|
||||
$ cargo build --features docs_
|
||||
$ cargo build --features testing_only_docs
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
@ -94,6 +94,17 @@ Run `cargo test` to compare generated Rust bindings to the expectations.
|
|||
$ cargo test [--all-features]
|
||||
```
|
||||
|
||||
### Running a Single Test
|
||||
|
||||
To generate bindings for a single test header, compile the bindings, and run the
|
||||
layout assertion tests for those bindings, use the `tests/test-one.sh`
|
||||
script. It supports fuzzy searching for test headers. For example, to test
|
||||
`tests/headers/what_is_going_on.hpp`, execute this command:
|
||||
|
||||
```
|
||||
$ ./tests/test-one.sh going
|
||||
```
|
||||
|
||||
### Authoring New Tests
|
||||
|
||||
To add a new test header to the suite, simply put it in the `tests/headers`
|
||||
|
@ -113,27 +124,6 @@ Then verify the new Rust bindings compile and pass some basic tests:
|
|||
$ cargo test -p tests_expectations
|
||||
```
|
||||
|
||||
## Generating Graphviz Dot Files
|
||||
|
||||
We have a special thing which will help you debug your codegen context if something
|
||||
will go wrong. It will generate a [`graphviz`](http://graphviz.org/pdf/dotguide.pdf)
|
||||
dot file and then you can create a PNG from it with `graphviz` tool in your OS.
|
||||
|
||||
Here is an example how it could be done:
|
||||
|
||||
```
|
||||
$ cargo run -- example.hpp --emit-ir-graphviz output.dot
|
||||
```
|
||||
|
||||
It will generate your graphviz dot file and then you will need tog
|
||||
create a PNG from it with `graphviz`.
|
||||
|
||||
Something like this:
|
||||
|
||||
```
|
||||
$ dot -Tpng output.dot -o output.png
|
||||
```
|
||||
|
||||
## Automatic code formatting
|
||||
|
||||
We use [`rustfmt`](https://github.com/rust-lang-nursery/rustfmt) to enforce a
|
||||
|
@ -157,6 +147,37 @@ $ cargo fmt
|
|||
|
||||
The code style is described in the `rustfmt.toml` file in top level of the repo.
|
||||
|
||||
## Generating Graphviz Dot Files
|
||||
|
||||
We can generate [Graphviz](http://graphviz.org/pdf/dotguide.pdf) dot files from
|
||||
our internal representation of a C/C++ input header, and then you can create a
|
||||
PNG or PDF from it with Graphviz's `dot` program. This is very useful when
|
||||
debugging bindgen!
|
||||
|
||||
First, make sure you have Graphviz and `dot` installed:
|
||||
|
||||
```
|
||||
$ brew install graphviz # OS X
|
||||
$ sudo dnf install graphviz # Fedora
|
||||
$ # Etc...
|
||||
```
|
||||
|
||||
Then, use the `--emit-ir-graphviz` flag to generate a `dot` file from our IR:
|
||||
|
||||
```
|
||||
$ cargo run -- example.hpp --emit-ir-graphviz output.dot
|
||||
```
|
||||
|
||||
Finally, convert the `dot` file to an image:
|
||||
|
||||
```
|
||||
$ dot -Tpng output.dot -o output.png
|
||||
```
|
||||
|
||||
The final result will look something like this:
|
||||
|
||||
[![An example graphviz rendering of our IR](./example-graphviz-ir.png)](./example-graphviz-ir.png)
|
||||
|
||||
## Debug Logging
|
||||
|
||||
To help debug what `bindgen` is doing, you can define the environment variable
|
||||
|
|
|
@ -13,10 +13,14 @@ name = "bindgen"
|
|||
readme = "README.md"
|
||||
repository = "https://github.com/servo/rust-bindgen"
|
||||
documentation = "https://docs.rs/bindgen"
|
||||
version = "0.22.0"
|
||||
version = "0.24.0"
|
||||
build = "build.rs"
|
||||
|
||||
exclude = ["tests/headers", "tests/expectations", "bindgen-integration", "ci"]
|
||||
exclude = [
|
||||
"bindgen-integration",
|
||||
"ci",
|
||||
"tests/**",
|
||||
]
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "servo/rust-bindgen" }
|
||||
|
@ -27,6 +31,7 @@ path = "src/lib.rs"
|
|||
[[bin]]
|
||||
name = "bindgen"
|
||||
path = "src/main.rs"
|
||||
doc = false
|
||||
|
||||
[dev-dependencies]
|
||||
diff = "0.1"
|
||||
|
@ -34,22 +39,21 @@ clap = "2"
|
|||
shlex = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
quasi_codegen = "0.29"
|
||||
quasi_codegen = "0.32"
|
||||
|
||||
[dependencies]
|
||||
cexpr = "0.2"
|
||||
cfg-if = "0.1.0"
|
||||
clang-sys = { version = "0.14", features = ["runtime", "clang_3_9"] }
|
||||
clang-sys = { version = "0.16.0", features = ["runtime", "clang_3_9"] }
|
||||
lazy_static = "0.2.1"
|
||||
rustc-serialize = "0.3.19"
|
||||
syntex_syntax = "0.54"
|
||||
syntex_syntax = "0.58"
|
||||
regex = "0.2"
|
||||
# This kinda sucks: https://github.com/rust-lang/cargo/issues/1982
|
||||
clap = "2"
|
||||
|
||||
[dependencies.aster]
|
||||
features = ["with-syntex"]
|
||||
version = "0.38"
|
||||
version = "0.41"
|
||||
|
||||
[dependencies.env_logger]
|
||||
optional = true
|
||||
|
@ -61,13 +65,15 @@ version = "0.3"
|
|||
|
||||
[dependencies.quasi]
|
||||
features = ["with-syntex"]
|
||||
version = "0.29"
|
||||
version = "0.32"
|
||||
|
||||
[features]
|
||||
assert_no_dangling_items = []
|
||||
default = ["logging"]
|
||||
testing_only_llvm_stable = []
|
||||
logging = ["env_logger", "log"]
|
||||
static = []
|
||||
# This feature only exists for CI -- don't use it!
|
||||
docs_ = []
|
||||
|
||||
# These features only exist for CI testing -- don't use them if you're not hacking
|
||||
# on bindgen!
|
||||
testing_only_docs = []
|
||||
testing_only_extra_assertions = []
|
||||
testing_only_llvm_stable = []
|
||||
|
|
|
@ -1,227 +1,45 @@
|
|||
# `bindgen`
|
||||
|
||||
Automatically generates Rust FFI bindings to C and C++ libraries.
|
||||
**`bindgen` automatically generates Rust FFI bindings to C and C++ libraries.**
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
For example, given the C header `cool.h`:
|
||||
|
||||
```c
|
||||
typedef struct CoolStruct {
|
||||
int x;
|
||||
int y;
|
||||
} CoolStruct;
|
||||
|
||||
- [Usage](#usage)
|
||||
- [Requirements](#requirements)
|
||||
- [Installing Clang 3.9](#installing-clang-39)
|
||||
- [Windows](#windows)
|
||||
- [OSX](#osx)
|
||||
- [Debian-based Linuxes](#debian-based-linuxes)
|
||||
- [Arch](#arch)
|
||||
- [From source](#from-source)
|
||||
- [Library usage with `build.rs`](#library-usage-with-buildrs)
|
||||
- [`build.rs` Tutorial](#buildrs-tutorial)
|
||||
- [Simple Example: `./bindgen-integration`](#simple-example-bindgen-integration)
|
||||
- [Real World Example: Stylo](#real-world-example-stylo)
|
||||
- [Command Line Usage](#command-line-usage)
|
||||
- [C++](#c)
|
||||
- [Annotations](#annotations)
|
||||
- [`opaque`](#opaque)
|
||||
- [`hide`](#hide)
|
||||
- [`replaces`](#replaces)
|
||||
- [`nocopy`](#nocopy)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
## Usage
|
||||
|
||||
### Requirements
|
||||
|
||||
It is recommended to use Clang 3.9 or greater, however `bindgen` can run with
|
||||
older Clangs with some features disabled.
|
||||
|
||||
#### Installing Clang 3.9
|
||||
|
||||
##### Windows
|
||||
|
||||
Download and install the official pre-built binary from
|
||||
[LLVM download page](http://releases.llvm.org/download.html).
|
||||
|
||||
##### OSX
|
||||
|
||||
If you use Homebrew:
|
||||
|
||||
```
|
||||
$ brew install llvm
|
||||
void cool_function(int i, char c, CoolStruct* cs);
|
||||
```
|
||||
|
||||
If you use MacPorts:
|
||||
|
||||
```
|
||||
$ port install clang-3.9
|
||||
```
|
||||
|
||||
##### Debian-based Linuxes
|
||||
|
||||
```
|
||||
# apt-get install llvm-3.9-dev libclang-3.9-dev
|
||||
```
|
||||
|
||||
Ubuntu 16.10 provides the necessary packages directly. If you are using older
|
||||
version of Ubuntu or other Debian-based distros, you may need to add the LLVM
|
||||
repos to get version 3.9. See http://apt.llvm.org/.
|
||||
|
||||
##### Arch
|
||||
|
||||
```
|
||||
# pacman -S clang
|
||||
```
|
||||
|
||||
##### From source
|
||||
|
||||
If your package manager doesn't yet offer Clang 3.9, you'll need to build from
|
||||
source. For that, follow the instructions
|
||||
[here](http://clang.llvm.org/get_started.html).
|
||||
|
||||
Those instructions list optional steps. For bindgen:
|
||||
|
||||
* Checkout and build clang
|
||||
* Checkout and build the extra-clang-tools
|
||||
* Checkout and build the compiler-rt
|
||||
* You do not need to checkout or build libcxx
|
||||
|
||||
### Library usage with `build.rs`
|
||||
|
||||
💡 This is the recommended way to use `bindgen`. 💡
|
||||
|
||||
#### `build.rs` Tutorial
|
||||
|
||||
[Here is a step-by-step tutorial for generating FFI bindings to the `bzip2` C library.][tutorial]
|
||||
|
||||
[tutorial]: http://fitzgeraldnick.com/2016/12/14/using-libbindgen-in-build-rs.html
|
||||
|
||||
#### Simple Example: `./bindgen-integration`
|
||||
|
||||
The [`./bindgen-integration`][integration] directory has an example crate that
|
||||
generates FFI bindings in `build.rs` and can be used a template for new
|
||||
projects.
|
||||
|
||||
[integration]: ./bindgen-integration
|
||||
|
||||
#### Real World Example: Stylo
|
||||
|
||||
A real world example is [the Stylo build script][stylo-script] used for
|
||||
integrating Servo's layout system into Gecko.
|
||||
|
||||
[stylo-script]: https://github.com/servo/servo/blob/master/components/style/build_gecko.rs
|
||||
|
||||
In `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[package]
|
||||
# ...
|
||||
build = "build.rs"
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = "0.20"
|
||||
```
|
||||
|
||||
In `build.rs`:
|
||||
`bindgen` produces Rust FFI code allowing you to call into the `cool` library's
|
||||
functions and use its types:
|
||||
|
||||
```rust
|
||||
extern crate bindgen;
|
||||
/* automatically generated by rust-bindgen */
|
||||
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
#[repr(C)]
|
||||
pub struct CoolStruct {
|
||||
pub x: ::std::os::raw::c_int,
|
||||
pub y: ::std::os::raw::c_int,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
let _ = bindgen::builder()
|
||||
.header("example.h")
|
||||
.use_core()
|
||||
.generate().unwrap()
|
||||
.write_to_file(Path::new(&out_dir).join("example.rs"));
|
||||
extern "C" {
|
||||
pub fn cool_function(i: ::std::os::raw::c_int,
|
||||
c: ::std::os::raw::c_char,
|
||||
cs: *mut CoolStruct);
|
||||
}
|
||||
```
|
||||
|
||||
In `src/main.rs`:
|
||||
## Users Guide
|
||||
|
||||
```rust
|
||||
include!(concat!(env!("OUT_DIR"), "/example.rs"));
|
||||
```
|
||||
[📚 Read the `bindgen` users guide here! 📚](https://servo.github.io/rust-bindgen)
|
||||
|
||||
### Command Line Usage
|
||||
## API Reference
|
||||
|
||||
```
|
||||
$ cargo install bindgen
|
||||
```
|
||||
[API reference documentation is on docs.rs](https://docs.rs/bindgen)
|
||||
|
||||
There are a few options documented when running `bindgen --help`. Bindgen is installed to `~/.cargo/bin`. You have to add that directory to your path to use `bindgen`.
|
||||
## Contributing
|
||||
|
||||
### C++
|
||||
|
||||
`bindgen` can handle most C++ features, but not all of them (C++ is hard!)
|
||||
|
||||
Notable C++ features that are unsupported or only partially supported:
|
||||
|
||||
* Partial template specialization
|
||||
* Traits templates
|
||||
* SFINAE
|
||||
* Instantiating new template specializations
|
||||
|
||||
When passing in header files, the file will automatically be treated as C++ if
|
||||
it ends in ``.hpp``. If it doesn't, ``-x c++`` can be used to force C++ mode.
|
||||
|
||||
You must use whitelisting when working with C++ to avoid pulling in all of the
|
||||
`std::*` types, some of which `bindgen` cannot handle. Additionally, you may
|
||||
want to blacklist other types that `bindgen` stumbles on, or make `bindgen`
|
||||
treat certain types as opaque.
|
||||
|
||||
### Annotations
|
||||
|
||||
The translation of classes, structs, enums, and typedefs can be adjusted using
|
||||
annotations. Annotations are specifically formatted html tags inside doxygen
|
||||
style comments.
|
||||
|
||||
#### `opaque`
|
||||
|
||||
The `opaque` annotation instructs bindgen to ignore all fields defined in
|
||||
a struct/class.
|
||||
|
||||
```cpp
|
||||
/// <div rustbindgen opaque></div>
|
||||
```
|
||||
|
||||
#### `hide`
|
||||
|
||||
The `hide` annotation instructs bindgen to ignore the struct/class/field/enum
|
||||
completely.
|
||||
|
||||
```cpp
|
||||
/// <div rustbindgen hide></div>
|
||||
```
|
||||
|
||||
#### `replaces`
|
||||
|
||||
The `replaces` annotation can be used to use a type as a replacement for other
|
||||
(presumably more complex) type. This is used in Stylo to generate bindings for
|
||||
structures that for multiple reasons are too complex for bindgen to understand.
|
||||
|
||||
For example, in a C++ header:
|
||||
|
||||
```cpp
|
||||
/**
|
||||
* <div rustbindgen replaces="nsTArray"></div>
|
||||
*/
|
||||
template<typename T>
|
||||
class nsTArray_Simple {
|
||||
T* mBuffer;
|
||||
public:
|
||||
// The existence of a destructor here prevents bindgen from deriving the Clone
|
||||
// trait via a simple memory copy.
|
||||
~nsTArray_Simple() {};
|
||||
};
|
||||
```
|
||||
|
||||
That way, after code generation, the bindings for the `nsTArray` type are
|
||||
the ones that would be generated for `nsTArray_Simple`.
|
||||
|
||||
#### `nocopy`
|
||||
|
||||
The `nocopy` annotation is used to prevent bindgen to autoderive the `Copy`
|
||||
and `Clone` traits for a type.
|
||||
[See `CONTRIBUTING.md` for hacking on `bindgen`!](./CONTRIBUTING.md)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
book
|
|
@ -0,0 +1,3 @@
|
|||
title = "The `bindgen` User Guide"
|
||||
author = "The Servo project developers"
|
||||
description = "`bindgen` automatically generates Rust FFI bindings to C and C++ libraries."
|
|
@ -0,0 +1,20 @@
|
|||
# Summary
|
||||
|
||||
- [Introduction](./introduction.md)
|
||||
- [Requirements](./requirements.md)
|
||||
- [Library Usage with `build.rs`](./library-usage.md)
|
||||
- [Tutorial](./tutorial-0.md)
|
||||
- [Add `bindgen` as a Build Dependency](./tutorial-1.md)
|
||||
- [Create a `wrapper.h` Header](./tutorial-2.md)
|
||||
- [Create a `build.rs` File](./tutorial-3.md)
|
||||
- [Include the Generated Bindings in `src/lib.rs`](./tutorial-4.md)
|
||||
- [Write a Sanity Test](./tutorial-5.md)
|
||||
- [Publish Your Crate!](./tutorial-6.md)
|
||||
- [Command Line Usage](./command-line-usage.md)
|
||||
- [Customizing the Generated Bindings](./customizing-generated-bindings.md)
|
||||
- [Whitelisting](./whitelisting.md)
|
||||
- [Blacklisting](./blacklisting.md)
|
||||
- [Treating a Type as an Opaque Blob of Bytes](./opaque.md)
|
||||
- [Replacing One Type with Another](./replacing-types.md)
|
||||
- [Preventing the Derivation of `Copy` and `Clone`](./nocopy.md)
|
||||
- [Generating Bindings to C++](./cpp.md)
|
|
@ -0,0 +1,26 @@
|
|||
# Blacklisting
|
||||
|
||||
If you need to provide your own custom translation of some type (for example,
|
||||
because you need to wrap one of its fields in an `UnsafeCell`), you can
|
||||
explicitly blacklist generation of its definition. Uses of the blacklisted type
|
||||
will still appear in other types' definitions. (If you don't want the type to
|
||||
appear in the bindings at
|
||||
all, [make it opaque](./opaque.html) instead of
|
||||
blacklisting it.)
|
||||
|
||||
### Library
|
||||
|
||||
* [`bindgen::Builder::hide_type`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.hide_type)
|
||||
|
||||
### Command Line
|
||||
|
||||
* `--blacklist-type <type>`
|
||||
|
||||
### Annotations
|
||||
|
||||
```cpp
|
||||
/// <div rustbindgen hide></div>
|
||||
class Foo {
|
||||
// ...
|
||||
};
|
||||
```
|
|
@ -0,0 +1 @@
|
|||
# Chapter 1
|
|
@ -0,0 +1,27 @@
|
|||
# Command Line Usage
|
||||
|
||||
Install the `bindgen` executable with `cargo`:
|
||||
|
||||
```bash
|
||||
$ cargo install bindgen
|
||||
```
|
||||
|
||||
The `bindgen` executable is installed to `~/.cargo/bin`. You have to add that
|
||||
directory to your `$PATH` to use `bindgen`.
|
||||
|
||||
`bindgen` takes the path to an input C or C++ header file, and optionally an
|
||||
output file path for the generated bindings. If the output file path is not
|
||||
supplied, the bindings are printed to `stdout`.
|
||||
|
||||
If we wanted to generated Rust FFI bindings from a C header named `input.h` and
|
||||
put them in the `bindings.rs` file, we would invoke `bindgen` like this:
|
||||
|
||||
```bash
|
||||
$ bindgen input.h -o bindings.rs
|
||||
```
|
||||
|
||||
For more details, pass the `--help` flag:
|
||||
|
||||
```bash
|
||||
$ bindgen --help
|
||||
```
|
|
@ -0,0 +1,27 @@
|
|||
# Generating Bindings to C++
|
||||
|
||||
`bindgen` can handle a surprising number of C++ features, but not all of
|
||||
them. When `bindgen` can't translate some C++ construct into Rust, it usually
|
||||
comes down to one of two things:
|
||||
|
||||
1. Rust has no equivalent language feature
|
||||
2. C++ is *hard!*
|
||||
|
||||
Notable C++ features that are unsupported or only partially supported, and for
|
||||
which `bindgen` *should* generate opaque blobs whenever it finds an occurrence
|
||||
of them in a type it is generating bindings for:
|
||||
|
||||
* Template specialization
|
||||
* Partial template specialization
|
||||
* Traits templates
|
||||
* SFINAE
|
||||
|
||||
When passing in header files, the file will automatically be treated as C++ if
|
||||
it ends in `.hpp`. If it doesn't, adding `-x=c++` clang args can be used to
|
||||
force C++ mode. You probably also want to use `-std=c++14` or similar clang args
|
||||
as well.
|
||||
|
||||
You pretty much **must** use [whitelisting](./whitelisting.html) when working
|
||||
with C++ to avoid pulling in all of the `std::*` types, many of which `bindgen`
|
||||
cannot handle. Additionally, you may want to mark other types
|
||||
as [opaque](./opaque.html) that `bindgen` stumbles on.
|
|
@ -0,0 +1,28 @@
|
|||
# Customizing the Generated Bindings
|
||||
|
||||
The translation of classes, structs, enums, and typedefs can be adjusted in a
|
||||
few ways:
|
||||
|
||||
1. By using the `bindgen::Builder`'s configuration methods, when using `bindgen`
|
||||
as a library.
|
||||
|
||||
2. By passing extra flags and options to the `bindgen` executable.
|
||||
|
||||
3. By adding an annotation comment to the C/C++ source code. Annotations are
|
||||
specially formatted HTML tags inside doxygen style comments:
|
||||
|
||||
* For single line comments:
|
||||
```c
|
||||
/// <div rustbindgen></div>
|
||||
```
|
||||
|
||||
* For multi-line comments:
|
||||
```c
|
||||
/**
|
||||
* <div rustbindgen></div>
|
||||
*/
|
||||
```
|
||||
|
||||
We'll leave the nitty-gritty details to
|
||||
the [docs.rs API reference](https://docs.rs/bindgen) and `bindgen --help`, but
|
||||
provide higher level concept documentation here.
|
|
@ -0,0 +1,34 @@
|
|||
# Introduction
|
||||
|
||||
**[`bindgen`](https://github.com/servo/rust-bindgen) automatically generates Rust
|
||||
FFI bindings to C and C++ libraries.**
|
||||
|
||||
For example, given the C header `cool.h`:
|
||||
|
||||
```c
|
||||
typedef struct CoolStruct {
|
||||
int x;
|
||||
int y;
|
||||
} CoolStruct;
|
||||
|
||||
void cool_function(int i, char c, CoolStruct* cs);
|
||||
```
|
||||
|
||||
`bindgen` produces Rust FFI code allowing you to call into the `cool` library's
|
||||
functions and use its types:
|
||||
|
||||
```rust
|
||||
/* automatically generated by rust-bindgen */
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CoolStruct {
|
||||
pub x: ::std::os::raw::c_int,
|
||||
pub y: ::std::os::raw::c_int,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn cool_function(i: ::std::os::raw::c_int,
|
||||
c: ::std::os::raw::c_char,
|
||||
cs: *mut CoolStruct);
|
||||
}
|
||||
```
|
|
@ -0,0 +1,22 @@
|
|||
# Library Usage with `build.rs`
|
||||
|
||||
💡 This is the recommended way to use `bindgen`. 💡
|
||||
|
||||
Often times C and C++ headers will have platform- and architecture-specific
|
||||
`#ifdef`s that affect the shape of the Rust FFI bindings we need to create to
|
||||
interface Rust code with the outside world. By using `bindgen` as a library
|
||||
inside your `build.rs`, you can generate bindings for the current target
|
||||
on-the-fly. Otherwise, you would need to generate and maintain
|
||||
`x86_64-unknown-linux-gnu-bindings.rs`, `x86_64-apple-darwin-bindings.rs`,
|
||||
etc... separate bindings files for each of your supported targets, which can be
|
||||
a huge pain. The downside is that everyone building your crate also needs
|
||||
`libclang` available to run `bindgen`.
|
||||
|
||||
## Library API Documentation
|
||||
|
||||
[📚 There is complete API reference documentation on docs.rs 📚](https://docs.rs/bindgen)
|
||||
|
||||
## Tutorial
|
||||
|
||||
The next section contains a detailed, step-by-step tutorial for using `bindgen`
|
||||
as a library inside `build.rs`.
|
|
@ -0,0 +1,20 @@
|
|||
# Preventing the Derivation of `Copy` and `Clone`
|
||||
|
||||
`bindgen` will attempt to derive the `Copy` and `Clone` traits on a best-effort
|
||||
basis. Sometimes, it might not understand that although adding `#[derive(Copy,
|
||||
Clone)]` to a translated type definition will compile, it still shouldn't do
|
||||
that for reasons it can't know. In these cases, the `nocopy` annotation can be
|
||||
used to prevent bindgen to autoderive the `Copy` and `Clone` traits for a type.
|
||||
|
||||
```c
|
||||
/**
|
||||
* Although bindgen can't know, this struct is not safe to move because pthread
|
||||
* mutexes can't move in memory!
|
||||
*
|
||||
* <div rustbindgen nocopy></div>
|
||||
*/
|
||||
struct MyMutexWrapper {
|
||||
pthread_mutex_t raw;
|
||||
// ...
|
||||
};
|
||||
```
|
|
@ -0,0 +1,26 @@
|
|||
# Treating a Type as an Opaque Blob of Bytes
|
||||
|
||||
Sometimes a type definition is simply not translatable to Rust, for example it
|
||||
uses
|
||||
[C++'s SFINAE](https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error) for
|
||||
which Rust has no equivalent. In these cases, it is best to treat all
|
||||
occurrences of the type as an opaque blob of bytes with a size and
|
||||
alignment. `bindgen` will attempt to detect such cases and do this
|
||||
automatically, but other times it needs some explicit help from you.
|
||||
|
||||
### Library
|
||||
|
||||
* [`bindgen::Builder::opaque_type`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.opaque_type)
|
||||
|
||||
### Command Line
|
||||
|
||||
* `--opaque-type <type>`
|
||||
|
||||
### Annotation
|
||||
|
||||
```cpp
|
||||
/// <div rustbindgen opaque></div>
|
||||
class Foo {
|
||||
// ...
|
||||
};
|
||||
```
|
|
@ -0,0 +1,27 @@
|
|||
# Replacing One Type with Another
|
||||
|
||||
The `replaces` annotation can be used to use a type as a replacement for other
|
||||
(presumably more complex) type. This is used in Stylo to generate bindings for
|
||||
structures that for multiple reasons are too complex for bindgen to understand.
|
||||
|
||||
For example, in a C++ header:
|
||||
|
||||
```cpp
|
||||
/**
|
||||
* <div rustbindgen replaces="nsTArray"></div>
|
||||
*/
|
||||
template<typename T>
|
||||
class nsTArray_Simple {
|
||||
T* mBuffer;
|
||||
public:
|
||||
// The existence of a destructor here prevents bindgen from deriving the Clone
|
||||
// trait via a simple memory copy.
|
||||
~nsTArray_Simple() {};
|
||||
};
|
||||
```
|
||||
|
||||
That way, after code generation, the bindings for the `nsTArray` type are
|
||||
the ones that would be generated for `nsTArray_Simple`.
|
||||
|
||||
Replacing is only available as an annotation. To replace a C or C++ definition
|
||||
with a Rust definition, use [blacklisting](./blacklisting.html).
|
|
@ -0,0 +1,67 @@
|
|||
# Requirements
|
||||
|
||||
This page lists the requirements for running `bindgen` and how to get them.
|
||||
|
||||
## Clang
|
||||
|
||||
`bindgen` leverages `libclang` to preprocess, parse, and type check C and C++
|
||||
header files.
|
||||
|
||||
It is recommended to use Clang 3.9 or greater, however `bindgen` can run with
|
||||
older Clangs with some features disabled.
|
||||
|
||||
* **If you are generating bindings to C,** 3.7 and 3.8 will probably work OK for
|
||||
you.
|
||||
|
||||
* **If you are generating bindings to C++,** you almost definitely want 3.9 or
|
||||
greater.
|
||||
|
||||
### Installing Clang 3.9
|
||||
|
||||
#### Windows
|
||||
|
||||
Download and install the official pre-built binary from
|
||||
[LLVM download page](http://releases.llvm.org/download.html).
|
||||
|
||||
#### macOS
|
||||
|
||||
If you use Homebrew:
|
||||
|
||||
```bash
|
||||
$ brew install llvm@3.9
|
||||
```
|
||||
|
||||
If you use MacPorts:
|
||||
|
||||
```bash
|
||||
$ port install clang-3.9
|
||||
```
|
||||
|
||||
#### Debian-based Linuxes
|
||||
|
||||
```bash
|
||||
# apt-get install llvm-3.9-dev libclang-3.9-dev clang-3.9
|
||||
```
|
||||
|
||||
Ubuntu 16.10 provides the necessary packages directly. If you are using older
|
||||
version of Ubuntu or other Debian-based distros, you may need to add the LLVM
|
||||
repos to get version 3.9. See http://apt.llvm.org/.
|
||||
|
||||
#### Arch
|
||||
|
||||
```bash
|
||||
# pacman -S clang
|
||||
```
|
||||
|
||||
#### From source
|
||||
|
||||
If your package manager doesn't yet offer Clang 3.9, you'll need to build from
|
||||
source. For that, follow the
|
||||
instructions [here](http://clang.llvm.org/get_started.html).
|
||||
|
||||
Those instructions list optional steps. For `bindgen`:
|
||||
|
||||
* Checkout and build clang
|
||||
* Checkout and build the extra-clang-tools
|
||||
* You do not need to checkout or build compiler-rt
|
||||
* You do not need to checkout or build libcxx
|
|
@ -0,0 +1,12 @@
|
|||
# Tutorial
|
||||
|
||||
The following tutorial is adapted from [this blog post][tutorial].
|
||||
|
||||
What follows is a whirlwind introductory tutorial to using `bindgen` from inside
|
||||
`build.rs`. We'll generate bindings to `bzip2` (which is available on most
|
||||
systems) on-the-fly.
|
||||
|
||||
[**TL;DR?** The full tutorial code is available here.][example]
|
||||
|
||||
[tutorial]: http://fitzgeraldnick.com/2016/12/14/using-libbindgen-in-build-rs.html
|
||||
[example]: https://github.com/fitzgen/libbindgen-tutorial-bzip2-sys
|
|
@ -0,0 +1,9 @@
|
|||
# Add `bindgen` as a Build Dependency
|
||||
|
||||
Declare a build-time dependency on `bindgen` by adding it to the
|
||||
`[build-dependencies]` section of our crate's `Cargo.toml` metadata file:
|
||||
|
||||
```toml
|
||||
[build-dependencies]
|
||||
bindgen = "0.23"
|
||||
```
|
|
@ -0,0 +1,20 @@
|
|||
# Create a `wrapper.h` Header
|
||||
|
||||
The `wrapper.h` file will include all the various headers containing
|
||||
declarations of structs and functions we would like bindings for. In the
|
||||
particular case of `bzip2`, this is pretty easy since the entire public API is
|
||||
contained in a single header. For a project like [SpiderMonkey][spidermonkey],
|
||||
where the public API is split across multiple header files and grouped by
|
||||
functionality, we'd want to include all those headers we want to bind to in this
|
||||
single `wrapper.h` entry point for `bindgen`.
|
||||
|
||||
Here is our `wrapper.h`:
|
||||
|
||||
```c
|
||||
#include <bzlib.h>
|
||||
```
|
||||
|
||||
This is also where we would add any [replacement types](./replacing-types.html),
|
||||
if we were using some.
|
||||
|
||||
[spidermonkey]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/How_to_embed_the_JavaScript_engine
|
|
@ -0,0 +1,58 @@
|
|||
# Create a `build.rs` File
|
||||
|
||||
First, we have to tell `cargo` that we have a `build.rs` script by adding
|
||||
another line to the `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[package]
|
||||
build = "build.rs"
|
||||
```
|
||||
|
||||
Second, we create the `build.rs` file in our crate's root. This file is compiled
|
||||
and executed before the rest of the crate is built, and can be used to generate
|
||||
code at compile time. And of course in our case, we will be generating Rust FFI
|
||||
bindings to `bzip2` at compile time. The resulting bindings will be written to
|
||||
`$OUT_DIR/bindings.rs` where `$OUT_DIR` is chosen by `cargo` and is something
|
||||
like `./target/debug/build/libbindgen-tutorial-bzip2-sys-afc7747d7eafd720/out/`.
|
||||
|
||||
```rust,ignore
|
||||
extern crate bindgen;
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
// Tell cargo to tell rustc to link the system bzip2
|
||||
// shared library.
|
||||
println!("cargo:rustc-link-lib=bz2");
|
||||
|
||||
// The bindgen::Builder is the main entry point
|
||||
// to bindgen, and lets you build up options for
|
||||
// the resulting bindings.
|
||||
let bindings = bindgen::Builder::default()
|
||||
// Do not generate unstable Rust code that
|
||||
// requires a nightly rustc and enabling
|
||||
// unstable features.
|
||||
.no_unstable_rust()
|
||||
// The input header we would like to generate
|
||||
// bindings for.
|
||||
.header("wrapper.h")
|
||||
// Finish the builder and generate the bindings.
|
||||
.generate()
|
||||
// Unwrap the Result and panic on failure.
|
||||
.expect("Unable to generate bindings");
|
||||
|
||||
// Write the bindings to the $OUT_DIR/bindings.rs file.
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
bindings
|
||||
.write_to_file(out_path.join("bindings.rs"))
|
||||
.expect("Couldn't write bindings!");
|
||||
}
|
||||
```
|
||||
|
||||
Now, when we run `cargo build`, our bindings to `bzip2` are generated on the
|
||||
fly!
|
||||
|
||||
[There's more info about `build.rs` files in the crates.io documentation.][build-rs]
|
||||
|
||||
[build-rs]: http://doc.crates.io/build-script.html
|
|
@ -0,0 +1,57 @@
|
|||
# Include the Generated Bindings in `src/lib.rs`
|
||||
|
||||
We can use the `include!` macro to dump our generated bindings right into our
|
||||
crate's main entry point, `src/lib.rs`:
|
||||
|
||||
```rust,ignore
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
```
|
||||
|
||||
Because `bzip2`'s symbols do not follow Rust's style conventions, we suppress a
|
||||
bunch of warnings with a few `#![allow(...)]` pragmas.
|
||||
|
||||
We can run `cargo build` again to check that the bindings themselves compile:
|
||||
|
||||
```bash
|
||||
$ cargo build
|
||||
Compiling libbindgen-tutorial-bzip2-sys v0.1.0
|
||||
Finished debug [unoptimized + debuginfo] target(s) in 62.8 secs
|
||||
```
|
||||
|
||||
And we can run `cargo test` to verify that the layout, size, and alignment of
|
||||
our generated Rust FFI structs match what `bindgen` thinks they should be:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling libbindgen-tutorial-bzip2-sys v0.1.0
|
||||
Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
|
||||
Running target/debug/deps/bzip2_sys-10413fc2af207810
|
||||
|
||||
running 14 tests
|
||||
test bindgen_test_layout___darwin_pthread_handler_rec ... ok
|
||||
test bindgen_test_layout___sFILE ... ok
|
||||
test bindgen_test_layout___sbuf ... ok
|
||||
test bindgen_test_layout__bindgen_ty_1 ... ok
|
||||
test bindgen_test_layout__bindgen_ty_2 ... ok
|
||||
test bindgen_test_layout__opaque_pthread_attr_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_cond_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_mutex_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_condattr_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_mutexattr_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_once_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_rwlock_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_rwlockattr_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_t ... ok
|
||||
|
||||
test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
Doc-tests libbindgen-tutorial-bzip2-sys
|
||||
|
||||
running 0 tests
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
|
@ -0,0 +1,169 @@
|
|||
# Write a Sanity Test
|
||||
|
||||
Finally, to tie everything together, let's write a sanity test that round trips
|
||||
some text through compression and decompression, and then asserts that it came
|
||||
back out the same as it went in. This is a little wordy using the raw FFI
|
||||
bindings, but hopefully we wouldn't usually ask people to do this, we'd provide
|
||||
a nice Rust-y API on top of the raw FFI bindings for them. However, since this
|
||||
is for testing the bindings directly, our sanity test will use the bindings
|
||||
directly.
|
||||
|
||||
The test data I'm round tripping are some Futurama quotes I got off the internet
|
||||
and put in the `futurama-quotes.txt` file, which is read into a `&'static str`
|
||||
at compile time via the `include_str!("../futurama-quotes.txt")` macro
|
||||
invocation.
|
||||
|
||||
Without further ado, here is the test, which should be appended to the bottom of
|
||||
our `src/lib.rs` file:
|
||||
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::mem;
|
||||
|
||||
#[test]
|
||||
fn round_trip_compression_decompression() {
|
||||
unsafe {
|
||||
let input = include_str!("../futurama-quotes.txt").as_bytes();
|
||||
let mut compressed_output: Vec<u8> = vec![0; input.len()];
|
||||
let mut decompressed_output: Vec<u8> = vec![0; input.len()];
|
||||
|
||||
// Construct a compression stream.
|
||||
let mut stream: bz_stream = mem::zeroed();
|
||||
let result = BZ2_bzCompressInit(&mut stream as *mut _,
|
||||
1, // 1 x 100000 block size
|
||||
4, // verbosity (4 = most verbose)
|
||||
0); // default work factor
|
||||
match result {
|
||||
r if r == (BZ_CONFIG_ERROR as _) => panic!("BZ_CONFIG_ERROR"),
|
||||
r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
|
||||
r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),
|
||||
r if r == (BZ_OK as _) => {},
|
||||
r => panic!("Unknown return value = {}", r),
|
||||
}
|
||||
|
||||
// Compress `input` into `compressed_output`.
|
||||
stream.next_in = input.as_ptr() as *mut _;
|
||||
stream.avail_in = input.len() as _;
|
||||
stream.next_out = compressed_output.as_mut_ptr() as *mut _;
|
||||
stream.avail_out = compressed_output.len() as _;
|
||||
let result = BZ2_bzCompress(&mut stream as *mut _, BZ_FINISH as _);
|
||||
match result {
|
||||
r if r == (BZ_RUN_OK as _) => panic!("BZ_RUN_OK"),
|
||||
r if r == (BZ_FLUSH_OK as _) => panic!("BZ_FLUSH_OK"),
|
||||
r if r == (BZ_FINISH_OK as _) => panic!("BZ_FINISH_OK"),
|
||||
r if r == (BZ_SEQUENCE_ERROR as _) => panic!("BZ_SEQUENCE_ERROR"),
|
||||
r if r == (BZ_STREAM_END as _) => {},
|
||||
r => panic!("Unknown return value = {}", r),
|
||||
}
|
||||
|
||||
// Finish the compression stream.
|
||||
let result = BZ2_bzCompressEnd(&mut stream as *mut _);
|
||||
match result {
|
||||
r if r == (BZ_PARAM_ERROR as _) => panic!(BZ_PARAM_ERROR),
|
||||
r if r == (BZ_OK as _) => {},
|
||||
r => panic!("Unknown return value = {}", r),
|
||||
}
|
||||
|
||||
// Construct a decompression stream.
|
||||
let mut stream: bz_stream = mem::zeroed();
|
||||
let result = BZ2_bzDecompressInit(&mut stream as *mut _,
|
||||
4, // verbosity (4 = most verbose)
|
||||
0); // default small factor
|
||||
match result {
|
||||
r if r == (BZ_CONFIG_ERROR as _) => panic!("BZ_CONFIG_ERROR"),
|
||||
r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
|
||||
r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),
|
||||
r if r == (BZ_OK as _) => {},
|
||||
r => panic!("Unknown return value = {}", r),
|
||||
}
|
||||
|
||||
// Decompress `compressed_output` into `decompressed_output`.
|
||||
stream.next_in = compressed_output.as_ptr() as *mut _;
|
||||
stream.avail_in = compressed_output.len() as _;
|
||||
stream.next_out = decompressed_output.as_mut_ptr() as *mut _;
|
||||
stream.avail_out = decompressed_output.len() as _;
|
||||
let result = BZ2_bzDecompress(&mut stream as *mut _);
|
||||
match result {
|
||||
r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
|
||||
r if r == (BZ_DATA_ERROR as _) => panic!("BZ_DATA_ERROR"),
|
||||
r if r == (BZ_DATA_ERROR_MAGIC as _) => panic!("BZ_DATA_ERROR"),
|
||||
r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),
|
||||
r if r == (BZ_OK as _) => panic!("BZ_OK"),
|
||||
r if r == (BZ_STREAM_END as _) => {},
|
||||
r => panic!("Unknown return value = {}", r),
|
||||
}
|
||||
|
||||
// Close the decompression stream.
|
||||
let result = BZ2_bzDecompressEnd(&mut stream as *mut _);
|
||||
match result {
|
||||
r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
|
||||
r if r == (BZ_OK as _) => {},
|
||||
r => panic!("Unknown return value = {}", r),
|
||||
}
|
||||
|
||||
assert_eq!(input, &decompressed_output[..]);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now let's run `cargo test` again and verify that everying is linking and binding
|
||||
properly!
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling libbindgen-tutorial-bzip2-sys v0.1.0
|
||||
Finished debug [unoptimized + debuginfo] target(s) in 0.54 secs
|
||||
Running target/debug/deps/libbindgen_tutorial_bzip2_sys-1c5626bbc4401c3a
|
||||
|
||||
running 15 tests
|
||||
test bindgen_test_layout___darwin_pthread_handler_rec ... ok
|
||||
test bindgen_test_layout___sFILE ... ok
|
||||
test bindgen_test_layout___sbuf ... ok
|
||||
test bindgen_test_layout__bindgen_ty_1 ... ok
|
||||
test bindgen_test_layout__bindgen_ty_2 ... ok
|
||||
test bindgen_test_layout__opaque_pthread_attr_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_cond_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_condattr_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_mutex_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_mutexattr_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_once_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_rwlock_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_rwlockattr_t ... ok
|
||||
test bindgen_test_layout__opaque_pthread_t ... ok
|
||||
block 1: crc = 0x47bfca17, combined CRC = 0x47bfca17, size = 2857
|
||||
bucket sorting ...
|
||||
depth 1 has 2849 unresolved strings
|
||||
depth 2 has 2702 unresolved strings
|
||||
depth 4 has 1508 unresolved strings
|
||||
depth 8 has 538 unresolved strings
|
||||
depth 16 has 148 unresolved strings
|
||||
depth 32 has 0 unresolved strings
|
||||
reconstructing block ...
|
||||
2857 in block, 2221 after MTF & 1-2 coding, 61+2 syms in use
|
||||
initial group 5, [0 .. 1], has 570 syms (25.7%)
|
||||
initial group 4, [2 .. 2], has 256 syms (11.5%)
|
||||
initial group 3, [3 .. 6], has 554 syms (24.9%)
|
||||
initial group 2, [7 .. 12], has 372 syms (16.7%)
|
||||
initial group 1, [13 .. 62], has 469 syms (21.1%)
|
||||
pass 1: size is 2743, grp uses are 13 6 15 0 11
|
||||
pass 2: size is 1216, grp uses are 13 7 15 0 10
|
||||
pass 3: size is 1214, grp uses are 13 8 14 0 10
|
||||
pass 4: size is 1213, grp uses are 13 9 13 0 10
|
||||
bytes: mapping 19, selectors 17, code lengths 79, codes 1213
|
||||
final combined CRC = 0x47bfca17
|
||||
|
||||
[1: huff+mtf rt+rld {0x47bfca17, 0x47bfca17}]
|
||||
combined CRCs: stored = 0x47bfca17, computed = 0x47bfca17
|
||||
test tests::round_trip_compression_decompression ... ok
|
||||
|
||||
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
Doc-tests libbindgen-tutorial-bzip2-sys
|
||||
|
||||
running 0 tests
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
# Publish Your Crate!
|
||||
|
||||
That's it! Now we can publish our crate on crates.io and we can write a nice,
|
||||
Rust-y API wrapping the raw FFI bindings in a safe interface. However, there is
|
||||
already a [`bzip2-sys`][bz-sys] crate providing raw FFI bindings, and there is
|
||||
already a [`bzip2`][bz] crate providing a nice, safe, Rust-y API on top of the
|
||||
bindings, so we have nothing left to do here!
|
||||
|
||||
Check out the [full code on Github!][example]
|
||||
|
||||
[bz-sys]: https://crates.io/crates/bzip2-sys
|
||||
[bz]: https://crates.io/crates/bzip2
|
||||
[example]: https://github.com/fitzgen/libbindgen-tutorial-bzip2-sys
|
|
@ -0,0 +1,31 @@
|
|||
# Whitelisting
|
||||
|
||||
Whitelisting allows us to be precise about which type, function, and global
|
||||
variable definitions `bindgen` generates bindings for. By default, if we don't
|
||||
specify any whitelisting rules, everything is considered whitelisted. This may
|
||||
not be desirable because of either
|
||||
|
||||
* the generated bindings contain a lot of extra defintions we don't plan on using, or
|
||||
* the header file contains C++ features for which Rust does not have a
|
||||
corresponding form (such as partial template specialization), and we would
|
||||
like to avoid these definitions
|
||||
|
||||
If we specify whitelisting rules, then `bindgen` will only generate bindings to
|
||||
types, functions, and global variables that match the whitelisting rules, or are
|
||||
transitively used by a definition that matches them.
|
||||
|
||||
### Library
|
||||
|
||||
* [`bindgen::Builder::whitelisted_type`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.whitelisted_type)
|
||||
* [`bindgen::Builder::whitelisted_function`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.whitelisted_function)
|
||||
* [`bindgen::Builder::whitelisted_var`](https://docs.rs/bindgen/0.23.1/bindgen/struct.Builder.html#method.whitelisted_function)
|
||||
|
||||
### Command Line
|
||||
|
||||
* `--whitelist-type <type>`
|
||||
* `--whitelist-function <function>`
|
||||
* `--whitelist-var <var>`
|
||||
|
||||
### Annotations
|
||||
|
||||
None.
|
|
@ -10,6 +10,7 @@ mod codegen {
|
|||
|
||||
quasi_codegen::expand(&src, &dst).unwrap();
|
||||
println!("cargo:rerun-if-changed=src/codegen/mod.rs");
|
||||
println!("cargo:rerun-if-changed=src/codegen/error.rs");
|
||||
println!("cargo:rerun-if-changed=src/codegen/helpers.rs");
|
||||
println!("cargo:rerun-if-changed=src/codegen/struct_layout.rs");
|
||||
}
|
||||
|
@ -27,13 +28,19 @@ mod testgen {
|
|||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).unwrap();
|
||||
|
||||
println!("cargo:rerun-if-changed=tests/headers");
|
||||
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
let headers_dir = manifest_dir.join("tests").join("headers");
|
||||
|
||||
let entries = fs::read_dir(headers_dir)
|
||||
.expect("Couldn't read headers dir")
|
||||
.map(|result| result.expect("Couldn't read header file"));
|
||||
let headers = match fs::read_dir(headers_dir) {
|
||||
Ok(dir) => dir,
|
||||
// We may not have headers directory after packaging.
|
||||
Err(..) => return,
|
||||
};
|
||||
|
||||
let entries =
|
||||
headers.map(|result| result.expect("Couldn't read header file"));
|
||||
|
||||
println!("cargo:rerun-if-changed=tests/headers");
|
||||
|
||||
for entry in entries {
|
||||
match entry.path().extension().and_then(OsStr::to_str) {
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
set -xeu
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
cargo build --features "$BINDGEN_FEATURES docs_"
|
||||
cargo build --features "$BINDGEN_FEATURES testing_only_docs"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
set -e
|
||||
set -ex
|
||||
pushd ~
|
||||
|
||||
# Workaround for Travis CI macOS bug (https://github.com/travis-ci/travis-ci/issues/6307)
|
||||
|
@ -6,16 +6,8 @@ if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
|
|||
rvm get head || true
|
||||
fi
|
||||
|
||||
function llvm_version_triple() {
|
||||
if [ "$1" == "3.8" ]; then
|
||||
echo "3.8.0"
|
||||
elif [ "$1" == "3.9" ]; then
|
||||
echo "3.9.0"
|
||||
fi
|
||||
}
|
||||
|
||||
function llvm_download() {
|
||||
export LLVM_VERSION_TRIPLE=`llvm_version_triple ${LLVM_VERSION}`
|
||||
export LLVM_VERSION_TRIPLE="${LLVM_VERSION}"
|
||||
export LLVM=clang+llvm-${LLVM_VERSION_TRIPLE}-x86_64-$1
|
||||
|
||||
wget http://llvm.org/releases/${LLVM_VERSION_TRIPLE}/${LLVM}.tar.xz
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -xeu
|
||||
cd "$(dirname "$0")/../book"
|
||||
|
||||
# Ensure mdbook is installed.
|
||||
cargo install mdbook || true
|
||||
export PATH="$PATH:~/.cargo/bin"
|
||||
|
||||
# Get the git revision we are on.
|
||||
rev=$(git rev-parse --short HEAD)
|
||||
|
||||
# Build the users guide book and go into the built book's directory.
|
||||
rm -rf ./book
|
||||
mdbook build
|
||||
cd ./book
|
||||
|
||||
# Make the built book directory a new git repo, fetch upstream, make a new
|
||||
# commit on gh-pages, and push it upstream.
|
||||
|
||||
git init
|
||||
git config user.name "Travis CI"
|
||||
git config user.email "builds@travis-ci.org"
|
||||
|
||||
git remote add upstream "https://$GH_TOKEN@github.com/servo/rust-bindgen.git"
|
||||
git fetch upstream
|
||||
git reset upstream/gh-pages
|
||||
|
||||
touch .
|
||||
|
||||
git add -A .
|
||||
git commit -m "Rebuild users guide at ${rev}"
|
||||
git push upstream HEAD:gh-pages
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -xeu
|
||||
cd "$(dirname "$0")/../book"
|
||||
|
||||
cargo install mdbook || true
|
||||
export PATH="$PATH:~/.cargo/bin"
|
||||
|
||||
mdbook build
|
||||
mdbook test
|
|
@ -6,10 +6,13 @@ cd "$(dirname "$0")/.."
|
|||
# Regenerate the test headers' bindings in debug and release modes, and assert
|
||||
# that we always get the expected generated bindings.
|
||||
|
||||
cargo test --features "$BINDGEN_FEATURES assert_no_dangling_items"
|
||||
cargo test --features "$BINDGEN_FEATURES"
|
||||
./ci/assert-no-diff.sh
|
||||
|
||||
cargo test --release --features "$BINDGEN_FEATURES assert_no_dangling_items"
|
||||
cargo test --features "$BINDGEN_FEATURES testing_only_extra_assertions"
|
||||
./ci/assert-no-diff.sh
|
||||
|
||||
cargo test --release --features "$BINDGEN_FEATURES testing_only_extra_assertions"
|
||||
./ci/assert-no-diff.sh
|
||||
|
||||
# Now test the expectations' size and alignment tests.
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.3 MiB |
|
@ -7,7 +7,11 @@ use std::panic::UnwindSafe;
|
|||
|
||||
/// A trait to allow configuring different kinds of types in different
|
||||
/// situations.
|
||||
pub trait TypeChooser: fmt::Debug + UnwindSafe {
|
||||
pub trait ParseCallbacks: fmt::Debug + UnwindSafe {
|
||||
|
||||
/// This function will be run on every macro that is identified
|
||||
fn parsed_macro(&self, _name: &str) {}
|
||||
|
||||
/// The integer kind an integer macro should have, given a name and the
|
||||
/// value of that macro, or `None` if you want the default to be chosen.
|
||||
fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> {
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
use cexpr;
|
||||
use clang_sys::*;
|
||||
use regex;
|
||||
use std::{mem, ptr, slice};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fmt;
|
||||
|
@ -76,6 +77,36 @@ impl Cursor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the C++ manglings for this cursor, or an error if the function is
|
||||
/// not loaded or the manglings are not available.
|
||||
pub fn cxx_manglings(&self) -> Result<Vec<String>, ()> {
|
||||
use clang_sys::*;
|
||||
if !clang_Cursor_getCXXManglings::is_loaded() {
|
||||
return Err(());
|
||||
}
|
||||
unsafe {
|
||||
let manglings = clang_Cursor_getCXXManglings(self.x);
|
||||
if manglings.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
let count = (*manglings).Count as usize;
|
||||
|
||||
let mut result = Vec::with_capacity(count);
|
||||
for i in 0..count {
|
||||
let string_ptr = (*manglings).Strings.offset(i as isize);
|
||||
result.push(cxstring_to_string_leaky(*string_ptr));
|
||||
}
|
||||
clang_disposeStringSet(manglings);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the cursor refers to a built-in definition.
|
||||
pub fn is_builtin(&self) -> bool {
|
||||
let (file, _, _, _) = self.location().location();
|
||||
file.name().is_none()
|
||||
}
|
||||
|
||||
/// Get the `Cursor` for this cursor's referent's lexical parent.
|
||||
///
|
||||
/// The lexical parent is the parent of the definition. The semantic parent
|
||||
|
@ -126,11 +157,11 @@ impl Cursor {
|
|||
}
|
||||
|
||||
/// Return the number of template arguments used by this cursor's referent,
|
||||
/// if the referent is either a template specialization or declaration.
|
||||
/// Returns `None` otherwise.
|
||||
/// if the referent is either a template instantiation. Returns `None`
|
||||
/// otherwise.
|
||||
///
|
||||
/// NOTE: This may not return `Some` for some non-fully specialized
|
||||
/// templates, see #193 and #194.
|
||||
/// NOTE: This may not return `Some` for partial template specializations,
|
||||
/// see #193 and #194.
|
||||
pub fn num_template_args(&self) -> Option<u32> {
|
||||
// XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while
|
||||
// `clang_Cursor_getNumTemplateArguments` is totally unreliable.
|
||||
|
@ -208,7 +239,7 @@ impl Cursor {
|
|||
|
||||
/// Get the kind of referent this cursor is pointing to.
|
||||
pub fn kind(&self) -> CXCursorKind {
|
||||
unsafe { clang_getCursorKind(self.x) }
|
||||
self.x.kind
|
||||
}
|
||||
|
||||
/// Returns true is the cursor is a definition
|
||||
|
@ -302,7 +333,11 @@ impl Cursor {
|
|||
x: clang_getCursorDefinition(self.x),
|
||||
};
|
||||
|
||||
if ret.is_valid() { Some(ret) } else { None }
|
||||
if ret.is_valid() && ret.kind() != CXCursor_NoDeclFound {
|
||||
Some(ret)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,8 +366,9 @@ impl Cursor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Given that this cursor points to a template specialization, get a cursor
|
||||
/// pointing to the template definition that is being specialized.
|
||||
/// Given that this cursor points to either a template specialization or a
|
||||
/// template instantiation, get a cursor pointing to the template definition
|
||||
/// that is being specialized.
|
||||
pub fn specialized(&self) -> Option<Cursor> {
|
||||
unsafe {
|
||||
let ret = Cursor {
|
||||
|
@ -588,6 +624,17 @@ impl Cursor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks whether the name looks like an identifier, i.e. is alphanumeric
|
||||
/// (including '_') and does not start with a digit.
|
||||
pub fn is_valid_identifier(name: &str) -> bool {
|
||||
let mut chars = name.chars();
|
||||
let first_valid = chars.next()
|
||||
.map(|c| c.is_alphabetic() || c == '_')
|
||||
.unwrap_or(false);
|
||||
|
||||
first_valid && chars.all(|c| c.is_alphanumeric() || c == '_')
|
||||
}
|
||||
|
||||
extern "C" fn visit_children<Visitor>(cur: CXCursor,
|
||||
_parent: CXCursor,
|
||||
data: CXClientData)
|
||||
|
@ -633,9 +680,10 @@ impl Eq for Type {}
|
|||
impl fmt::Debug for Type {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt,
|
||||
"Type({}, kind: {}, decl: {:?}, canon: {:?})",
|
||||
"Type({}, kind: {}, cconv: {}, decl: {:?}, canon: {:?})",
|
||||
self.spelling(),
|
||||
type_to_str(self.kind()),
|
||||
self.call_conv(),
|
||||
self.declaration(),
|
||||
self.declaration().canonical())
|
||||
}
|
||||
|
@ -716,7 +764,16 @@ impl Type {
|
|||
|
||||
/// Get a raw display name for this type.
|
||||
pub fn spelling(&self) -> String {
|
||||
unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) }
|
||||
let s = unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) };
|
||||
// Clang 5.0 introduced changes in the spelling API so it returned the
|
||||
// full qualified name. Let's undo that here.
|
||||
if s.split("::").all(|s| is_valid_identifier(s)) {
|
||||
if let Some(s) = s.split("::").last() {
|
||||
return s.to_owned();
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
/// Is this type const qualified?
|
||||
|
@ -875,7 +932,11 @@ impl Type {
|
|||
pub fn named(&self) -> Type {
|
||||
unsafe {
|
||||
Type {
|
||||
x: clang_Type_getNamedType(self.x),
|
||||
x: if clang_Type_getNamedType::is_loaded() {
|
||||
clang_Type_getNamedType(self.x)
|
||||
} else {
|
||||
self.x
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -890,8 +951,8 @@ impl Type {
|
|||
self.is_valid() && self.kind() != CXType_Unexposed
|
||||
}
|
||||
|
||||
/// Is this type a fully specialized template?
|
||||
pub fn is_fully_specialized_template(&self) -> bool {
|
||||
/// Is this type a fully instantiated template?
|
||||
pub fn is_fully_instantiated_template(&self) -> bool {
|
||||
// Yep, the spelling of this containing type-parameter is extremely
|
||||
// nasty... But can happen in <type_traits>. Unfortunately I couldn't
|
||||
// reduce it enough :(
|
||||
|
@ -903,6 +964,30 @@ impl Type {
|
|||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this type an associated template type? Eg `T::Associated` in
|
||||
/// this example:
|
||||
///
|
||||
/// ```c++
|
||||
/// template <typename T>
|
||||
/// class Foo {
|
||||
/// typename T::Associated member;
|
||||
/// };
|
||||
/// ```
|
||||
pub fn is_associated_type(&self) -> bool {
|
||||
// This is terrible :(
|
||||
fn hacky_parse_associated_type<S: AsRef<str>>(spelling: S) -> bool {
|
||||
lazy_static! {
|
||||
static ref ASSOC_TYPE_RE: regex::Regex =
|
||||
regex::Regex::new(r"typename type\-parameter\-\d+\-\d+::.+").unwrap();
|
||||
}
|
||||
ASSOC_TYPE_RE.is_match(spelling.as_ref())
|
||||
}
|
||||
|
||||
self.kind() == CXType_Unexposed &&
|
||||
(hacky_parse_associated_type(self.spelling()) ||
|
||||
hacky_parse_associated_type(self.canonical_type().spelling()))
|
||||
}
|
||||
}
|
||||
|
||||
/// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its
|
||||
|
@ -1107,16 +1192,18 @@ impl File {
|
|||
}
|
||||
}
|
||||
|
||||
fn cxstring_into_string(s: CXString) -> String {
|
||||
fn cxstring_to_string_leaky(s: CXString) -> String {
|
||||
if s.data.is_null() {
|
||||
return "".to_owned();
|
||||
}
|
||||
unsafe {
|
||||
let c_str = CStr::from_ptr(clang_getCString(s) as *const _);
|
||||
let ret = c_str.to_string_lossy().into_owned();
|
||||
clang_disposeString(s);
|
||||
ret
|
||||
let c_str = unsafe { CStr::from_ptr(clang_getCString(s) as *const _) };
|
||||
c_str.to_string_lossy().into_owned()
|
||||
}
|
||||
|
||||
fn cxstring_into_string(s: CXString) -> String {
|
||||
let ret = cxstring_to_string_leaky(s);
|
||||
unsafe { clang_disposeString(s) };
|
||||
ret
|
||||
}
|
||||
|
||||
/// An `Index` is an environment for a set of translation units that will
|
||||
|
@ -1368,7 +1455,9 @@ impl Drop for Diagnostic {
|
|||
/// A file which has not been saved to disk.
|
||||
pub struct UnsavedFile {
|
||||
x: CXUnsavedFile,
|
||||
name: CString,
|
||||
/// The name of the unsaved file. Kept here to avoid leaving dangling pointers in
|
||||
/// `CXUnsavedFile`.
|
||||
pub name: CString,
|
||||
contents: CString,
|
||||
}
|
||||
|
||||
|
@ -1390,6 +1479,15 @@ impl UnsavedFile {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for UnsavedFile {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt,
|
||||
"UnsavedFile(name: {:?}, contents: {:?})",
|
||||
self.name,
|
||||
self.contents)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a cursor kind into a static string.
|
||||
pub fn kind_to_str(x: CXCursorKind) -> String {
|
||||
unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) }
|
||||
|
@ -1498,6 +1596,13 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
|
|||
&specialized);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(parent) = c.fallible_semantic_parent() {
|
||||
println!("");
|
||||
print_cursor(depth,
|
||||
String::from(prefix) + "semantic-parent.",
|
||||
&parent);
|
||||
}
|
||||
}
|
||||
|
||||
fn print_type<S: AsRef<str>>(depth: isize, prefix: S, ty: &Type) {
|
||||
|
@ -1509,6 +1614,8 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
|
|||
return;
|
||||
}
|
||||
|
||||
print_indent(depth, format!(" {}cconv = {}", prefix, ty.call_conv()));
|
||||
|
||||
print_indent(depth,
|
||||
format!(" {}spelling = \"{}\"", prefix, ty.spelling()));
|
||||
let num_template_args =
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
use std::error;
|
||||
use std::fmt;
|
||||
|
||||
/// Errors that can occur during code generation.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
/// Tried to generate an opaque blob for a type that did not have a layout.
|
||||
NoLayoutForOpaqueBlob,
|
||||
|
||||
/// Tried to instantiate an opaque template definition, or a template
|
||||
/// definition that is too difficult for us to understand (like a partial
|
||||
/// template specialization).
|
||||
InstantiationOfOpaqueType,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", error::Error::description(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
None
|
||||
}
|
||||
|
||||
fn description(&self) -> &'static str {
|
||||
match *self {
|
||||
Error::NoLayoutForOpaqueBlob => {
|
||||
"Tried to generate an opaque blob, but had no layout"
|
||||
}
|
||||
Error::InstantiationOfOpaqueType => {
|
||||
"Instantiation of opaque template type or partial template \
|
||||
specialization"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A `Result` of `T` or an error of `bindgen::codegen::error::Error`.
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
|
@ -10,6 +10,10 @@ pub mod attributes {
|
|||
use aster;
|
||||
use syntax::ast;
|
||||
|
||||
pub fn allow(which_ones: &[&str]) -> ast::Attribute {
|
||||
aster::AstBuilder::new().attr().list("allow").words(which_ones).build()
|
||||
}
|
||||
|
||||
pub fn repr(which: &str) -> ast::Attribute {
|
||||
aster::AstBuilder::new().attr().list("repr").words(&[which]).build()
|
||||
}
|
||||
|
@ -142,7 +146,7 @@ pub mod ast_ty {
|
|||
}
|
||||
vec.push(int_expr(0));
|
||||
|
||||
let kind = ast::ExprKind::Vec(vec);
|
||||
let kind = ast::ExprKind::Array(vec);
|
||||
|
||||
aster::AstBuilder::new().expr().build_expr_kind(kind)
|
||||
}
|
||||
|
@ -154,8 +158,12 @@ pub mod ast_ty {
|
|||
.build_lit(aster::AstBuilder::new().lit().byte_str(string))
|
||||
}
|
||||
|
||||
pub fn float_expr(f: f64) -> P<ast::Expr> {
|
||||
pub fn float_expr(ctx: &BindgenContext,
|
||||
f: f64)
|
||||
-> Result<P<ast::Expr>, ()> {
|
||||
use aster::symbol::ToSymbol;
|
||||
|
||||
if f.is_finite() {
|
||||
let mut string = f.to_string();
|
||||
|
||||
// So it gets properly recognised as a floating point constant.
|
||||
|
@ -164,7 +172,24 @@ pub mod ast_ty {
|
|||
}
|
||||
|
||||
let kind = ast::LitKind::FloatUnsuffixed(string.as_str().to_symbol());
|
||||
aster::AstBuilder::new().expr().lit().build_lit(kind)
|
||||
return Ok(aster::AstBuilder::new().expr().lit().build_lit(kind))
|
||||
}
|
||||
|
||||
let prefix = ctx.trait_prefix();
|
||||
if f.is_nan() {
|
||||
return Ok(quote_expr!(ctx.ext_cx(), ::$prefix::f64::NAN));
|
||||
}
|
||||
|
||||
if f.is_infinite() {
|
||||
return Ok(if f.is_sign_positive() {
|
||||
quote_expr!(ctx.ext_cx(), ::$prefix::f64::INFINITY)
|
||||
} else {
|
||||
quote_expr!(ctx.ext_cx(), ::$prefix::f64::NEG_INFINITY)
|
||||
});
|
||||
}
|
||||
|
||||
warn!("Unknown non-finite float number: {:?}", f);
|
||||
return Err(());
|
||||
}
|
||||
|
||||
pub fn arguments_from_signature(signature: &FunctionSig,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -167,17 +167,20 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
|||
None => return None,
|
||||
};
|
||||
|
||||
if let TypeKind::Array(inner, len) = *field_ty.canonical_type(self.ctx).kind() {
|
||||
if let TypeKind::Array(inner, len) =
|
||||
*field_ty.canonical_type(self.ctx).kind() {
|
||||
// FIXME(emilio): As an _ultra_ hack, we correct the layout returned
|
||||
// by arrays of structs that have a bigger alignment than what we
|
||||
// can support.
|
||||
//
|
||||
// This means that the structs in the array are super-unsafe to
|
||||
// access, since they won't be properly aligned, but *shrug*.
|
||||
if let Some(layout) = self.ctx.resolve_type(inner).layout(self.ctx) {
|
||||
if let Some(layout) = self.ctx
|
||||
.resolve_type(inner)
|
||||
.layout(self.ctx) {
|
||||
if layout.align > mem::size_of::<*mut ()>() {
|
||||
field_layout.size =
|
||||
align_to(layout.size, layout.align) * len;
|
||||
field_layout.size = align_to(layout.size, layout.align) *
|
||||
len;
|
||||
field_layout.align = mem::size_of::<*mut ()>();
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +200,8 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
|||
};
|
||||
|
||||
// Otherwise the padding is useless.
|
||||
let need_padding = padding_bytes >= field_layout.align;
|
||||
let need_padding = padding_bytes >= field_layout.align ||
|
||||
field_layout.align > mem::size_of::<*mut ()>();
|
||||
|
||||
self.latest_offset += padding_bytes;
|
||||
|
||||
|
@ -213,7 +217,9 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
|||
field_layout);
|
||||
|
||||
if need_padding && padding_bytes != 0 {
|
||||
Some(Layout::new(padding_bytes, field_layout.align))
|
||||
Some(Layout::new(padding_bytes,
|
||||
cmp::min(field_layout.align,
|
||||
mem::size_of::<*mut ()>())))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -221,7 +227,8 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
|||
|
||||
self.latest_offset += field_layout.size;
|
||||
self.latest_field_layout = Some(field_layout);
|
||||
self.max_field_align = cmp::max(self.max_field_align, field_layout.align);
|
||||
self.max_field_align = cmp::max(self.max_field_align,
|
||||
field_layout.align);
|
||||
self.last_field_was_bitfield = false;
|
||||
|
||||
debug!("Offset: {}: {} -> {}",
|
||||
|
@ -232,11 +239,15 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
|||
padding_layout.map(|layout| self.padding_field(layout))
|
||||
}
|
||||
|
||||
pub fn pad_struct(&mut self, name: &str, layout: Layout) -> Option<ast::StructField> {
|
||||
pub fn pad_struct(&mut self,
|
||||
name: &str,
|
||||
layout: Layout)
|
||||
-> Option<ast::StructField> {
|
||||
if layout.size < self.latest_offset {
|
||||
error!("Calculated wrong layout for {}, too more {} bytes",
|
||||
name, self.latest_offset - layout.size);
|
||||
return None
|
||||
name,
|
||||
self.latest_offset - layout.size);
|
||||
return None;
|
||||
}
|
||||
|
||||
let padding_bytes = layout.size - self.latest_offset;
|
||||
|
@ -262,6 +273,8 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
|||
Layout::new(padding_bytes, layout.align)
|
||||
};
|
||||
|
||||
debug!("pad bytes to struct {}, {:?}", name, layout);
|
||||
|
||||
Some(self.padding_field(layout))
|
||||
} else {
|
||||
None
|
||||
|
@ -314,8 +327,10 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
|||
|
||||
// If it was, we may or may not need to align, depending on what the
|
||||
// current field alignment and the bitfield size and alignment are.
|
||||
debug!("align_to_bitfield? {}: {:?} {:?}", self.last_field_was_bitfield,
|
||||
layout, new_field_layout);
|
||||
debug!("align_to_bitfield? {}: {:?} {:?}",
|
||||
self.last_field_was_bitfield,
|
||||
layout,
|
||||
new_field_layout);
|
||||
|
||||
if self.last_field_was_bitfield &&
|
||||
new_field_layout.align <= layout.size % layout.align &&
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
//! Macros for defining extra assertions that should only be checked in testing
|
||||
//! and/or CI when the `testing_only_extra_assertions` feature is enabled.
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! extra_assert {
|
||||
( $cond:expr ) => {
|
||||
if cfg!(feature = "testing_only_extra_assertions") {
|
||||
assert!($cond);
|
||||
}
|
||||
};
|
||||
( $cond:expr , $( $arg:tt )+ ) => {
|
||||
if cfg!(feature = "testing_only_extra_assertions") {
|
||||
assert!($cond, $( $arg )* )
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! extra_assert_eq {
|
||||
( $lhs:expr , $rhs:expr ) => {
|
||||
if cfg!(feature = "testing_only_extra_assertions") {
|
||||
assert_eq!($lhs, $rhs);
|
||||
}
|
||||
};
|
||||
( $lhs:expr , $rhs:expr , $( $arg:tt )+ ) => {
|
||||
if cfg!(feature = "testing_only_extra_assertions") {
|
||||
assert!($lhs, $rhs, $( $arg )* );
|
||||
}
|
||||
};
|
||||
}
|
|
@ -6,7 +6,7 @@ use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
|
|||
use super::item::Item;
|
||||
use super::layout::Layout;
|
||||
use super::traversal::{EdgeKind, Trace, Tracer};
|
||||
use super::ty::{TemplateDeclaration, Type};
|
||||
use super::template::TemplateParameters;
|
||||
use clang;
|
||||
use parse::{ClangItemParser, ParseError};
|
||||
use std::cell::Cell;
|
||||
|
@ -26,6 +26,10 @@ pub enum MethodKind {
|
|||
/// A constructor. We represent it as method for convenience, to avoid code
|
||||
/// duplication.
|
||||
Constructor,
|
||||
/// A destructor.
|
||||
Destructor,
|
||||
/// A virtual destructor.
|
||||
VirtualDestructor,
|
||||
/// A static method.
|
||||
Static,
|
||||
/// A normal method.
|
||||
|
@ -61,6 +65,12 @@ impl Method {
|
|||
self.kind
|
||||
}
|
||||
|
||||
/// Is this a destructor method?
|
||||
pub fn is_destructor(&self) -> bool {
|
||||
self.kind == MethodKind::Destructor ||
|
||||
self.kind == MethodKind::VirtualDestructor
|
||||
}
|
||||
|
||||
/// Is this a constructor?
|
||||
pub fn is_constructor(&self) -> bool {
|
||||
self.kind == MethodKind::Constructor
|
||||
|
@ -68,7 +78,8 @@ impl Method {
|
|||
|
||||
/// Is this a virtual method?
|
||||
pub fn is_virtual(&self) -> bool {
|
||||
self.kind == MethodKind::Virtual
|
||||
self.kind == MethodKind::Virtual ||
|
||||
self.kind == MethodKind::VirtualDestructor
|
||||
}
|
||||
|
||||
/// Is this a static method?
|
||||
|
@ -238,10 +249,11 @@ pub struct CompInfo {
|
|||
/// The members of this struct or union.
|
||||
fields: Vec<Field>,
|
||||
|
||||
/// The template parameters of this class. These are non-concrete, and
|
||||
/// should always be a Type(TypeKind::Named(name)), but still they need to
|
||||
/// be registered with an unique type id in the context.
|
||||
template_args: Vec<ItemId>,
|
||||
/// The abstract template parameters of this class. These are NOT concrete
|
||||
/// template arguments, and should always be a
|
||||
/// Type(TypeKind::Named(name)). For concrete template arguments, see the
|
||||
/// TypeKind::TemplateInstantiation.
|
||||
template_params: Vec<ItemId>,
|
||||
|
||||
/// The method declarations inside this class, if in C++ mode.
|
||||
methods: Vec<Method>,
|
||||
|
@ -249,12 +261,13 @@ pub struct CompInfo {
|
|||
/// The different constructors this struct or class contains.
|
||||
constructors: Vec<ItemId>,
|
||||
|
||||
/// The destructor of this type. The bool represents whether this destructor
|
||||
/// is virtual.
|
||||
destructor: Option<(bool, ItemId)>,
|
||||
|
||||
/// Vector of classes this one inherits from.
|
||||
base_members: Vec<Base>,
|
||||
|
||||
/// The parent reference template if any.
|
||||
ref_template: Option<ItemId>,
|
||||
|
||||
/// The inner types that were declared inside this class, in something like:
|
||||
///
|
||||
/// class Foo {
|
||||
|
@ -320,11 +333,11 @@ impl CompInfo {
|
|||
CompInfo {
|
||||
kind: kind,
|
||||
fields: vec![],
|
||||
template_args: vec![],
|
||||
template_params: vec![],
|
||||
methods: vec![],
|
||||
constructors: vec![],
|
||||
destructor: None,
|
||||
base_members: vec![],
|
||||
ref_template: None,
|
||||
inner_types: vec![],
|
||||
inner_vars: vec![],
|
||||
has_vtable: false,
|
||||
|
@ -345,9 +358,7 @@ impl CompInfo {
|
|||
!self.has_vtable(ctx) && self.fields.is_empty() &&
|
||||
self.base_members.iter().all(|base| {
|
||||
ctx.resolve_type(base.ty).canonical_type(ctx).is_unsized(ctx)
|
||||
}) &&
|
||||
self.ref_template
|
||||
.map_or(true, |template| ctx.resolve_type(template).is_unsized(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
/// Does this compound type have a destructor?
|
||||
|
@ -364,16 +375,6 @@ impl CompInfo {
|
|||
match self.kind {
|
||||
CompKind::Union => false,
|
||||
CompKind::Struct => {
|
||||
// NB: We can't rely on a type with type parameters
|
||||
// not having destructor.
|
||||
//
|
||||
// This is unfortunate, but...
|
||||
self.ref_template.as_ref().map_or(false, |t| {
|
||||
ctx.resolve_type(*t).has_destructor(ctx)
|
||||
}) ||
|
||||
self.template_args.iter().any(|t| {
|
||||
ctx.resolve_type(*t).has_destructor(ctx)
|
||||
}) ||
|
||||
self.base_members.iter().any(|base| {
|
||||
ctx.resolve_type(base.ty).has_destructor(ctx)
|
||||
}) ||
|
||||
|
@ -389,16 +390,6 @@ impl CompInfo {
|
|||
has_destructor
|
||||
}
|
||||
|
||||
/// Is this type a template specialization?
|
||||
pub fn is_template_specialization(&self) -> bool {
|
||||
self.ref_template.is_some()
|
||||
}
|
||||
|
||||
/// Get the template declaration this specialization is specializing.
|
||||
pub fn specialized_template(&self) -> Option<ItemId> {
|
||||
self.ref_template
|
||||
}
|
||||
|
||||
/// Compute the layout of this type.
|
||||
///
|
||||
/// This is called as a fallback under some circumstances where LLVM doesn't
|
||||
|
@ -411,7 +402,7 @@ impl CompInfo {
|
|||
use std::cmp;
|
||||
// We can't do better than clang here, sorry.
|
||||
if self.kind == CompKind::Struct {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut max_size = 0;
|
||||
|
@ -434,12 +425,6 @@ impl CompInfo {
|
|||
&self.fields
|
||||
}
|
||||
|
||||
/// Get this type's set of free template arguments. Empty if this is not a
|
||||
/// template.
|
||||
pub fn template_args(&self) -> &[ItemId] {
|
||||
&self.template_args
|
||||
}
|
||||
|
||||
/// Does this type have any template parameters that aren't types
|
||||
/// (e.g. int)?
|
||||
pub fn has_non_type_template_params(&self) -> bool {
|
||||
|
@ -452,9 +437,6 @@ impl CompInfo {
|
|||
self.base_members().iter().any(|base| {
|
||||
ctx.resolve_type(base.ty)
|
||||
.has_vtable(ctx)
|
||||
}) ||
|
||||
self.ref_template.map_or(false, |template| {
|
||||
ctx.resolve_type(template).has_vtable(ctx)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -468,6 +450,11 @@ impl CompInfo {
|
|||
&self.constructors
|
||||
}
|
||||
|
||||
/// Get this type's destructor.
|
||||
pub fn destructor(&self) -> Option<(bool, ItemId)> {
|
||||
self.destructor
|
||||
}
|
||||
|
||||
/// What kind of compound type is this?
|
||||
pub fn kind(&self) -> CompKind {
|
||||
self.kind
|
||||
|
@ -485,10 +472,9 @@ impl CompInfo {
|
|||
ctx: &mut BindgenContext)
|
||||
-> Result<Self, ParseError> {
|
||||
use clang_sys::*;
|
||||
// Sigh... For class templates we want the location, for
|
||||
// specialisations, we want the declaration... So just try both.
|
||||
//
|
||||
// TODO: Yeah, this code reads really bad.
|
||||
assert!(ty.template_args().is_none(),
|
||||
"We handle template instantiations elsewhere");
|
||||
|
||||
let mut cursor = ty.declaration();
|
||||
let mut kind = Self::kind_from_cursor(&cursor);
|
||||
if kind.is_err() {
|
||||
|
@ -510,46 +496,25 @@ impl CompInfo {
|
|||
CXCursor_ClassDecl => !cur.is_definition(),
|
||||
_ => false,
|
||||
});
|
||||
ci.template_args = match ty.template_args() {
|
||||
// In forward declarations and not specializations, etc, they are in
|
||||
// the ast, we'll meet them in CXCursor_TemplateTypeParameter
|
||||
None => vec![],
|
||||
Some(arg_types) => {
|
||||
let num_arg_types = arg_types.len();
|
||||
let mut specialization = true;
|
||||
|
||||
let args = arg_types.filter(|t| t.kind() != CXType_Invalid)
|
||||
.filter_map(|t| if t.spelling()
|
||||
.starts_with("type-parameter") {
|
||||
specialization = false;
|
||||
None
|
||||
} else {
|
||||
Some(Item::from_ty_or_ref(t, None, None, ctx))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if specialization && args.len() != num_arg_types {
|
||||
ci.has_non_type_template_params = true;
|
||||
warn!("warning: Template parameter is not a type");
|
||||
}
|
||||
|
||||
if specialization { args } else { vec![] }
|
||||
}
|
||||
};
|
||||
|
||||
ci.ref_template = cursor.specialized()
|
||||
.and_then(|c| Item::parse(c, None, ctx).ok());
|
||||
|
||||
let mut maybe_anonymous_struct_field = None;
|
||||
cursor.visit(|cur| {
|
||||
if cur.kind() != CXCursor_FieldDecl {
|
||||
if let Some((ty, _, offset)) =
|
||||
if let Some((ty, clang_ty, offset)) =
|
||||
maybe_anonymous_struct_field.take() {
|
||||
if cur.kind() == CXCursor_TypedefDecl &&
|
||||
cur.typedef_type().unwrap().canonical_type() == clang_ty {
|
||||
// Typedefs of anonymous structs appear later in the ast
|
||||
// than the struct itself, that would otherwise be an
|
||||
// anonymous field. Detect that case here, and do
|
||||
// nothing.
|
||||
} else {
|
||||
let field =
|
||||
Field::new(None, ty, None, None, None, false, offset);
|
||||
ci.fields.push(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match cur.kind() {
|
||||
CXCursor_FieldDecl => {
|
||||
|
@ -576,7 +541,7 @@ impl CompInfo {
|
|||
|
||||
let bit_width = cur.bit_width();
|
||||
let field_type = Item::from_ty_or_ref(cur.cur_type(),
|
||||
Some(cur),
|
||||
cur,
|
||||
Some(potential_id),
|
||||
ctx);
|
||||
|
||||
|
@ -616,17 +581,27 @@ impl CompInfo {
|
|||
}
|
||||
CXCursor_EnumDecl |
|
||||
CXCursor_TypeAliasDecl |
|
||||
CXCursor_TypeAliasTemplateDecl |
|
||||
CXCursor_TypedefDecl |
|
||||
CXCursor_StructDecl |
|
||||
CXCursor_UnionDecl |
|
||||
CXCursor_ClassTemplate |
|
||||
CXCursor_ClassDecl => {
|
||||
// We can find non-semantic children here, clang uses a
|
||||
// StructDecl to note incomplete structs that hasn't been
|
||||
// forward-declared before, see:
|
||||
// StructDecl to note incomplete structs that haven't been
|
||||
// forward-declared before, see [1].
|
||||
//
|
||||
// https://github.com/servo/rust-bindgen/issues/482
|
||||
if cur.semantic_parent() != cursor {
|
||||
// Also, clang seems to scope struct definitions inside
|
||||
// unions, and other named struct definitions inside other
|
||||
// structs to the whole translation unit.
|
||||
//
|
||||
// Let's just assume that if the cursor we've found is a
|
||||
// definition, it's a valid inner type.
|
||||
//
|
||||
// [1]: https://github.com/servo/rust-bindgen/issues/482
|
||||
let is_inner_struct = cur.semantic_parent() == cursor ||
|
||||
cur.is_definition();
|
||||
if !is_inner_struct {
|
||||
return CXChildVisit_Continue;
|
||||
}
|
||||
|
||||
|
@ -649,17 +624,10 @@ impl CompInfo {
|
|||
ci.packed = true;
|
||||
}
|
||||
CXCursor_TemplateTypeParameter => {
|
||||
// Yes! You can arrive here with an empty template parameter
|
||||
// name! Awesome, isn't it?
|
||||
//
|
||||
// see tests/headers/empty_template_param_name.hpp
|
||||
if cur.spelling().is_empty() {
|
||||
return CXChildVisit_Continue;
|
||||
}
|
||||
|
||||
let param =
|
||||
Item::named_type(cur.spelling(), potential_id, ctx);
|
||||
ci.template_args.push(param);
|
||||
let param = Item::named_type(None, cur, ctx)
|
||||
.expect("Item::named_type should't fail when pointing \
|
||||
at a TemplateTypeParameter");
|
||||
ci.template_params.push(param);
|
||||
}
|
||||
CXCursor_CXXBaseSpecifier => {
|
||||
let is_virtual_base = cur.is_virtual_base();
|
||||
|
@ -671,10 +639,8 @@ impl CompInfo {
|
|||
BaseKind::Normal
|
||||
};
|
||||
|
||||
let type_id = Item::from_ty_or_ref(cur.cur_type(),
|
||||
Some(cur),
|
||||
None,
|
||||
ctx);
|
||||
let type_id =
|
||||
Item::from_ty_or_ref(cur.cur_type(), cur, None, ctx);
|
||||
ci.base_members.push(Base {
|
||||
ty: type_id,
|
||||
kind: kind,
|
||||
|
@ -700,7 +666,7 @@ impl CompInfo {
|
|||
// Methods of template functions not only use to be inlined,
|
||||
// but also instantiated, and we wouldn't be able to call
|
||||
// them, so just bail out.
|
||||
if !ci.template_args.is_empty() {
|
||||
if !ci.template_params.is_empty() {
|
||||
return CXChildVisit_Continue;
|
||||
}
|
||||
|
||||
|
@ -718,8 +684,9 @@ impl CompInfo {
|
|||
CXCursor_Constructor => {
|
||||
ci.constructors.push(signature);
|
||||
}
|
||||
// TODO(emilio): Bind the destructor?
|
||||
CXCursor_Destructor => {}
|
||||
CXCursor_Destructor => {
|
||||
ci.destructor = Some((is_virtual, signature));
|
||||
}
|
||||
CXCursor_CXXMethod => {
|
||||
let is_const = cur.method_is_const();
|
||||
let method_kind = if is_static {
|
||||
|
@ -767,7 +734,7 @@ impl CompInfo {
|
|||
_ => {
|
||||
warn!("unhandled comp member `{}` (kind {:?}) in `{}` ({})",
|
||||
cur.spelling(),
|
||||
cur.kind(),
|
||||
clang::kind_to_str(cur.kind()),
|
||||
cursor.spelling(),
|
||||
cur.location());
|
||||
}
|
||||
|
@ -776,7 +743,8 @@ impl CompInfo {
|
|||
});
|
||||
|
||||
if let Some((ty, _, offset)) = maybe_anonymous_struct_field {
|
||||
let field = Field::new(None, ty, None, None, None, false, offset);
|
||||
let field =
|
||||
Field::new(None, ty, None, None, None, false, offset);
|
||||
ci.fields.push(field);
|
||||
}
|
||||
|
||||
|
@ -805,25 +773,6 @@ impl CompInfo {
|
|||
})
|
||||
}
|
||||
|
||||
/// Do any of the types that participate in this type's "signature" use the
|
||||
/// named type `ty`?
|
||||
///
|
||||
/// See also documentation for `ir::Item::signature_contains_named_type`.
|
||||
pub fn signature_contains_named_type(&self,
|
||||
ctx: &BindgenContext,
|
||||
ty: &Type)
|
||||
-> bool {
|
||||
// We don't generate these, so rather don't make the codegen step to
|
||||
// think we got it covered.
|
||||
if self.has_non_type_template_params() {
|
||||
return false;
|
||||
}
|
||||
self.template_args.iter().any(|arg| {
|
||||
ctx.resolve_type(*arg)
|
||||
.signature_contains_named_type(ctx, ty)
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the set of types that were declared within this compound type
|
||||
/// (e.g. nested class definitions).
|
||||
pub fn inner_types(&self) -> &[ItemId] {
|
||||
|
@ -870,12 +819,14 @@ impl CompInfo {
|
|||
}
|
||||
}
|
||||
|
||||
impl TemplateDeclaration for CompInfo {
|
||||
fn template_params(&self, _ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
||||
if self.template_args.is_empty() {
|
||||
impl TemplateParameters for CompInfo {
|
||||
fn self_template_params(&self,
|
||||
_ctx: &BindgenContext)
|
||||
-> Option<Vec<ItemId>> {
|
||||
if self.template_params.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.template_args.clone())
|
||||
Some(self.template_params.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -914,13 +865,9 @@ impl CanDeriveDebug for CompInfo {
|
|||
self.base_members
|
||||
.iter()
|
||||
.all(|base| base.ty.can_derive_debug(ctx, ())) &&
|
||||
self.template_args
|
||||
.iter()
|
||||
.all(|id| id.can_derive_debug(ctx, ())) &&
|
||||
self.fields
|
||||
.iter()
|
||||
.all(|f| f.can_derive_debug(ctx, ())) &&
|
||||
self.ref_template.map_or(true, |id| id.can_derive_debug(ctx, ()))
|
||||
.all(|f| f.can_derive_debug(ctx, ()))
|
||||
};
|
||||
|
||||
self.detect_derive_debug_cycle.set(false);
|
||||
|
@ -950,7 +897,7 @@ impl CanDeriveDefault for CompInfo {
|
|||
|
||||
return layout.unwrap_or_else(Layout::zero)
|
||||
.opaque()
|
||||
.can_derive_debug(ctx, ());
|
||||
.can_derive_default(ctx, ());
|
||||
}
|
||||
|
||||
self.detect_derive_default_cycle.set(true);
|
||||
|
@ -960,14 +907,9 @@ impl CanDeriveDefault for CompInfo {
|
|||
self.base_members
|
||||
.iter()
|
||||
.all(|base| base.ty.can_derive_default(ctx, ())) &&
|
||||
self.template_args
|
||||
.iter()
|
||||
.all(|id| id.can_derive_default(ctx, ())) &&
|
||||
self.fields
|
||||
.iter()
|
||||
.all(|f| f.can_derive_default(ctx, ())) &&
|
||||
self.ref_template
|
||||
.map_or(true, |id| id.can_derive_default(ctx, ()));
|
||||
.all(|f| f.can_derive_default(ctx, ()));
|
||||
|
||||
self.detect_derive_default_cycle.set(false);
|
||||
|
||||
|
@ -1002,17 +944,12 @@ impl<'a> CanDeriveCopy<'a> for CompInfo {
|
|||
}
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/36640
|
||||
if !self.template_args.is_empty() || self.ref_template.is_some() ||
|
||||
!item.applicable_template_args(ctx).is_empty() {
|
||||
if !self.template_params.is_empty() ||
|
||||
item.used_template_params(ctx).is_some() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// With template args, use a safe subset of the types,
|
||||
// since copyability depends on the types itself.
|
||||
self.ref_template
|
||||
.as_ref()
|
||||
.map_or(true, |t| t.can_derive_copy(ctx, ())) &&
|
||||
self.base_members
|
||||
.iter()
|
||||
.all(|base| base.ty.can_derive_copy(ctx, ())) &&
|
||||
|
@ -1033,49 +970,40 @@ impl Trace for CompInfo {
|
|||
fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
|
||||
where T: Tracer,
|
||||
{
|
||||
// TODO: We should properly distinguish template instantiations from
|
||||
// template declarations at the type level. Why are some template
|
||||
// instantiations represented here instead of as
|
||||
// TypeKind::TemplateInstantiation?
|
||||
if let Some(template) = self.specialized_template() {
|
||||
// This is an instantiation of a template declaration with concrete
|
||||
// template type arguments.
|
||||
tracer.visit(template);
|
||||
let args = item.applicable_template_args(context);
|
||||
for a in args {
|
||||
tracer.visit(a);
|
||||
}
|
||||
} else {
|
||||
let params = item.applicable_template_args(context);
|
||||
// This is a template declaration with abstract template type
|
||||
// parameters.
|
||||
let params = item.all_template_params(context).unwrap_or(vec![]);
|
||||
for p in params {
|
||||
tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition);
|
||||
}
|
||||
|
||||
for &ty in self.inner_types() {
|
||||
tracer.visit_kind(ty, EdgeKind::InnerType);
|
||||
}
|
||||
|
||||
// We unconditionally trace `CompInfo`'s template parameters and inner
|
||||
// types for the the usage analysis. However, we don't want to continue
|
||||
// tracing anything else, if this type is marked opaque.
|
||||
if item.is_opaque(context) {
|
||||
return;
|
||||
}
|
||||
|
||||
for base in self.base_members() {
|
||||
tracer.visit(base.ty);
|
||||
tracer.visit_kind(base.ty, EdgeKind::BaseMember);
|
||||
}
|
||||
|
||||
for field in self.fields() {
|
||||
tracer.visit(field.ty());
|
||||
}
|
||||
|
||||
for &ty in self.inner_types() {
|
||||
tracer.visit(ty);
|
||||
tracer.visit_kind(field.ty(), EdgeKind::Field);
|
||||
}
|
||||
|
||||
for &var in self.inner_vars() {
|
||||
tracer.visit(var);
|
||||
tracer.visit_kind(var, EdgeKind::InnerVar);
|
||||
}
|
||||
|
||||
for method in self.methods() {
|
||||
tracer.visit(method.signature);
|
||||
tracer.visit_kind(method.signature, EdgeKind::Method);
|
||||
}
|
||||
|
||||
for &ctor in self.constructors() {
|
||||
tracer.visit(ctor);
|
||||
tracer.visit_kind(ctor, EdgeKind::Constructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,13 @@ use super::int::IntKind;
|
|||
use super::item::{Item, ItemCanonicalPath, ItemSet};
|
||||
use super::item_kind::ItemKind;
|
||||
use super::module::{Module, ModuleKind};
|
||||
use super::traversal::{self, Edge, ItemTraversal, Trace};
|
||||
use super::ty::{FloatKind, TemplateDeclaration, Type, TypeKind};
|
||||
use super::named::{UsedTemplateParameters, analyze};
|
||||
use super::template::{TemplateInstantiation, TemplateParameters};
|
||||
use super::traversal::{self, Edge, ItemTraversal};
|
||||
use super::ty::{FloatKind, Type, TypeKind};
|
||||
use BindgenOptions;
|
||||
use cexpr;
|
||||
use chooser::TypeChooser;
|
||||
use callbacks::ParseCallbacks;
|
||||
use clang::{self, Cursor};
|
||||
use clang_sys;
|
||||
use parse::ClangItemParser;
|
||||
|
@ -18,8 +20,6 @@ use std::cell::Cell;
|
|||
use std::collections::{HashMap, hash_map};
|
||||
use std::collections::btree_map::{self, BTreeMap};
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Write};
|
||||
use std::iter::IntoIterator;
|
||||
use syntax::ast::Ident;
|
||||
use syntax::codemap::{DUMMY_SP, Span};
|
||||
|
@ -104,6 +104,10 @@ pub struct BindgenContext<'ctx> {
|
|||
/// item ids during parsing.
|
||||
types: HashMap<TypeKey, ItemId>,
|
||||
|
||||
/// Maps from a cursor to the item id of the named template type parameter
|
||||
/// for that cursor.
|
||||
named_types: HashMap<clang::Cursor, ItemId>,
|
||||
|
||||
/// A cursor to module map. Similar reason than above.
|
||||
modules: HashMap<Cursor, ItemId>,
|
||||
|
||||
|
@ -151,15 +155,61 @@ pub struct BindgenContext<'ctx> {
|
|||
|
||||
/// Whether a bindgen complex was generated
|
||||
generated_bindegen_complex: Cell<bool>,
|
||||
|
||||
/// Map from an item's id to the set of template parameter items that it
|
||||
/// uses. See `ir::named` for more details. Always `Some` during the codegen
|
||||
/// phase.
|
||||
used_template_parameters: Option<HashMap<ItemId, ItemSet>>,
|
||||
}
|
||||
|
||||
/// A traversal of whitelisted items.
|
||||
pub type WhitelistedItems<'ctx, 'gen> = ItemTraversal<'ctx,
|
||||
pub struct WhitelistedItems<'ctx, 'gen>
|
||||
where 'gen: 'ctx
|
||||
{
|
||||
ctx: &'ctx BindgenContext<'gen>,
|
||||
traversal: ItemTraversal<'ctx,
|
||||
'gen,
|
||||
ItemSet,
|
||||
Vec<ItemId>,
|
||||
fn(Edge) -> bool>;
|
||||
fn(Edge) -> bool>,
|
||||
}
|
||||
|
||||
impl<'ctx, 'gen> Iterator for WhitelistedItems<'ctx, 'gen>
|
||||
where 'gen: 'ctx
|
||||
{
|
||||
type Item = ItemId;
|
||||
|
||||
fn next(&mut self) -> Option<ItemId> {
|
||||
loop {
|
||||
match self.traversal.next() {
|
||||
None => return None,
|
||||
Some(id) if self.ctx.resolve_item(id).is_hidden(self.ctx) => continue,
|
||||
Some(id) => return Some(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, 'gen> WhitelistedItems<'ctx, 'gen>
|
||||
where 'gen: 'ctx
|
||||
{
|
||||
/// Construct a new whitelisted items traversal.
|
||||
pub fn new<R>(ctx: &'ctx BindgenContext<'gen>,
|
||||
roots: R)
|
||||
-> WhitelistedItems<'ctx, 'gen>
|
||||
where R: IntoIterator<Item = ItemId>,
|
||||
{
|
||||
let predicate = if ctx.options().whitelist_recursively {
|
||||
traversal::all_edges
|
||||
} else {
|
||||
traversal::no_edges
|
||||
};
|
||||
WhitelistedItems {
|
||||
ctx: ctx,
|
||||
traversal: ItemTraversal::new(ctx, roots, predicate)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'ctx> BindgenContext<'ctx> {
|
||||
/// Construct the context for the given `options`.
|
||||
pub fn new(options: BindgenOptions) -> Self {
|
||||
|
@ -173,14 +223,15 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
clang::TranslationUnit::parse(&index,
|
||||
"",
|
||||
&options.clang_args,
|
||||
&[],
|
||||
&options.input_unsaved_files,
|
||||
parse_options)
|
||||
.expect("TranslationUnit::parse");
|
||||
.expect("TranslationUnit::parse failed");
|
||||
|
||||
let root_module = Self::build_root_module(ItemId(0));
|
||||
let mut me = BindgenContext {
|
||||
items: Default::default(),
|
||||
types: Default::default(),
|
||||
named_types: Default::default(),
|
||||
modules: Default::default(),
|
||||
next_item_id: ItemId(1),
|
||||
root_module: root_module.id(),
|
||||
|
@ -195,6 +246,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
translation_unit: translation_unit,
|
||||
options: options,
|
||||
generated_bindegen_complex: Cell::new(false),
|
||||
used_template_parameters: None,
|
||||
};
|
||||
|
||||
me.add_item(root_module, None, None);
|
||||
|
@ -222,9 +274,9 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
.expect("should have been parsing a type, if we finished parsing a type")
|
||||
}
|
||||
|
||||
/// Get the user-provided type chooser by reference, if any.
|
||||
pub fn type_chooser(&self) -> Option<&TypeChooser> {
|
||||
self.options().type_chooser.as_ref().map(|t| &**t)
|
||||
/// Get the user-provided callbacks by reference, if any.
|
||||
pub fn parse_callbacks(&self) -> Option<&ParseCallbacks> {
|
||||
self.options().parse_callbacks.as_ref().map(|t| &**t)
|
||||
}
|
||||
|
||||
/// Define a new item.
|
||||
|
@ -240,7 +292,8 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
declaration,
|
||||
location);
|
||||
debug_assert!(declaration.is_some() || !item.kind().is_type() ||
|
||||
item.kind().expect_type().is_builtin_or_named(),
|
||||
item.kind().expect_type().is_builtin_or_named() ||
|
||||
item.kind().expect_type().is_opaque(),
|
||||
"Adding a type without declaration?");
|
||||
|
||||
let id = item.id();
|
||||
|
@ -258,7 +311,8 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
}
|
||||
|
||||
let old_item = self.items.insert(id, item);
|
||||
assert!(old_item.is_none(), "Inserted type twice?");
|
||||
assert!(old_item.is_none(),
|
||||
"should not have already associated an item with the given id");
|
||||
|
||||
// Unnamed items can have an USR, but they can't be referenced from
|
||||
// other sites explicitly and the USR can match if the unnamed items are
|
||||
|
@ -301,6 +355,35 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Add a new named template type parameter to this context's item set.
|
||||
pub fn add_named_type(&mut self, item: Item, definition: clang::Cursor) {
|
||||
debug!("BindgenContext::add_named_type: item = {:?}; definition = {:?}",
|
||||
item,
|
||||
definition);
|
||||
|
||||
assert!(item.expect_type().is_named(),
|
||||
"Should directly be a named type, not a resolved reference or anything");
|
||||
assert_eq!(definition.kind(),
|
||||
clang_sys::CXCursor_TemplateTypeParameter);
|
||||
|
||||
let id = item.id();
|
||||
let old_item = self.items.insert(id, item);
|
||||
assert!(old_item.is_none(),
|
||||
"should not have already associated an item with the given id");
|
||||
|
||||
let old_named_ty = self.named_types.insert(definition, id);
|
||||
assert!(old_named_ty.is_none(),
|
||||
"should not have already associated a named type with this id");
|
||||
}
|
||||
|
||||
/// Get the named type defined at the given cursor location, if we've
|
||||
/// already added one.
|
||||
pub fn get_named_type(&self, definition: &clang::Cursor) -> Option<ItemId> {
|
||||
assert_eq!(definition.kind(),
|
||||
clang_sys::CXCursor_TemplateTypeParameter);
|
||||
self.named_types.get(definition).cloned()
|
||||
}
|
||||
|
||||
// TODO: Move all this syntax crap to other part of the code.
|
||||
|
||||
/// Given that we are in the codegen phase, get the syntex context.
|
||||
|
@ -354,7 +437,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
/// Gather all the unresolved type references.
|
||||
fn collect_typerefs
|
||||
(&mut self)
|
||||
-> Vec<(ItemId, clang::Type, Option<clang::Cursor>, Option<ItemId>)> {
|
||||
-> Vec<(ItemId, clang::Type, clang::Cursor, Option<ItemId>)> {
|
||||
debug_assert!(!self.collected_typerefs);
|
||||
self.collected_typerefs = true;
|
||||
let mut typerefs = vec![];
|
||||
|
@ -382,7 +465,11 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
for (id, ty, loc, parent_id) in typerefs {
|
||||
let _resolved = {
|
||||
let resolved = Item::from_ty(&ty, loc, parent_id, self)
|
||||
.expect("What happened?");
|
||||
.unwrap_or_else(|_| {
|
||||
warn!("Could not resolve type reference, falling back \
|
||||
to opaque blob");
|
||||
Item::new_opaque_type(self.next_item_id(), &ty, self)
|
||||
});
|
||||
let mut item = self.items.get_mut(&id).unwrap();
|
||||
|
||||
*item.kind_mut().as_type_mut().unwrap().kind_mut() =
|
||||
|
@ -425,7 +512,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
};
|
||||
|
||||
match *ty.kind() {
|
||||
TypeKind::Comp(ref ci) if !ci.is_template_specialization() => {}
|
||||
TypeKind::Comp(..) |
|
||||
TypeKind::TemplateAlias(..) |
|
||||
TypeKind::Alias(..) => {}
|
||||
_ => continue,
|
||||
|
@ -531,14 +618,18 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
self.process_replacements();
|
||||
}
|
||||
|
||||
self.find_used_template_parameters();
|
||||
|
||||
let ret = cb(self);
|
||||
self.gen_ctx = None;
|
||||
ret
|
||||
}
|
||||
|
||||
/// This function trying to find any dangling references inside of `items`
|
||||
/// When the `testing_only_extra_assertions` feature is enabled, this
|
||||
/// function walks the IR graph and asserts that we do not have any edges
|
||||
/// referencing an ItemId for which we do not have an associated IR item.
|
||||
fn assert_no_dangling_references(&self) {
|
||||
if cfg!(feature = "assert_no_dangling_items") {
|
||||
if cfg!(feature = "testing_only_extra_assertions") {
|
||||
for _ in self.assert_no_dangling_item_traversal() {
|
||||
// The iterator's next method does the asserting for us.
|
||||
}
|
||||
|
@ -557,6 +648,62 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
traversal::all_edges)
|
||||
}
|
||||
|
||||
fn find_used_template_parameters(&mut self) {
|
||||
if self.options.whitelist_recursively {
|
||||
let used_params = analyze::<UsedTemplateParameters>(self);
|
||||
self.used_template_parameters = Some(used_params);
|
||||
} else {
|
||||
// If you aren't recursively whitelisting, then we can't really make
|
||||
// any sense of template parameter usage, and you're on your own.
|
||||
let mut used_params = HashMap::new();
|
||||
for id in self.whitelisted_items() {
|
||||
used_params.entry(id)
|
||||
.or_insert(id.self_template_params(self)
|
||||
.map_or(Default::default(),
|
||||
|params| params.into_iter().collect()));
|
||||
}
|
||||
self.used_template_parameters = Some(used_params);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if `item` uses the given `template_param`, `false`
|
||||
/// otherwise.
|
||||
///
|
||||
/// This method may only be called during the codegen phase, because the
|
||||
/// template usage information is only computed as we enter the codegen
|
||||
/// phase.
|
||||
///
|
||||
/// If the item is blacklisted, then we say that it always uses the template
|
||||
/// parameter. This is a little subtle. The template parameter usage
|
||||
/// analysis only considers whitelisted items, and if any blacklisted item
|
||||
/// shows up in the generated bindings, it is the user's responsibility to
|
||||
/// manually provide a definition for them. To give them the most
|
||||
/// flexibility when doing that, we assume that they use every template
|
||||
/// parameter and always pass template arguments through in instantiations.
|
||||
pub fn uses_template_parameter(&self,
|
||||
item: ItemId,
|
||||
template_param: ItemId)
|
||||
-> bool {
|
||||
assert!(self.in_codegen_phase(),
|
||||
"We only compute template parameter usage as we enter codegen");
|
||||
|
||||
if self.resolve_item(item).is_hidden(self) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let template_param = template_param.into_resolver()
|
||||
.through_type_refs()
|
||||
.through_type_aliases()
|
||||
.resolve(self)
|
||||
.id();
|
||||
|
||||
self.used_template_parameters
|
||||
.as_ref()
|
||||
.expect("should have found template parameter usage if we're in codegen")
|
||||
.get(&item)
|
||||
.map_or(false, |items_used_params| items_used_params.contains(&template_param))
|
||||
}
|
||||
|
||||
// This deserves a comment. Builtin types don't get a valid declaration, so
|
||||
// we can't add it to the cursor->type map.
|
||||
//
|
||||
|
@ -636,7 +783,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
.and_then(|canon_decl| {
|
||||
self.get_resolved_type(&canon_decl)
|
||||
.and_then(|template_decl_id| {
|
||||
template_decl_id.num_template_params(self)
|
||||
template_decl_id.num_self_template_params(self)
|
||||
.map(|num_params| {
|
||||
(*canon_decl.cursor(),
|
||||
template_decl_id,
|
||||
|
@ -660,7 +807,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
.cloned()
|
||||
})
|
||||
.and_then(|template_decl| {
|
||||
template_decl.num_template_params(self)
|
||||
template_decl.num_self_template_params(self)
|
||||
.map(|num_template_params| {
|
||||
(*template_decl.decl(),
|
||||
template_decl.id(),
|
||||
|
@ -708,7 +855,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
use clang_sys;
|
||||
|
||||
let num_expected_args = match self.resolve_type(template)
|
||||
.num_template_params(self) {
|
||||
.num_self_template_params(self) {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
warn!("Tried to instantiate a template for which we could not \
|
||||
|
@ -755,7 +902,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
// template declaration as the parent. It is already parsed and
|
||||
// has a known-resolvable `ItemId`.
|
||||
let ty = Item::from_ty_or_ref(child.cur_type(),
|
||||
Some(*child),
|
||||
*child,
|
||||
Some(template),
|
||||
self);
|
||||
args.push(ty);
|
||||
|
@ -772,7 +919,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
// Do a happy little parse. See comment in the TypeRef
|
||||
// match arm about parent IDs.
|
||||
let ty = Item::from_ty_or_ref(child.cur_type(),
|
||||
Some(*child),
|
||||
*child,
|
||||
Some(template),
|
||||
self);
|
||||
args.push(ty);
|
||||
|
@ -794,9 +941,9 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
sub_args.reverse();
|
||||
|
||||
let sub_name = Some(template_decl_cursor.spelling());
|
||||
let sub_inst = TemplateInstantiation::new(template_decl_id, sub_args);
|
||||
let sub_kind =
|
||||
TypeKind::TemplateInstantiation(template_decl_id,
|
||||
sub_args);
|
||||
TypeKind::TemplateInstantiation(sub_inst);
|
||||
let sub_ty = Type::new(sub_name,
|
||||
template_decl_cursor.cur_type()
|
||||
.fallible_layout()
|
||||
|
@ -846,7 +993,8 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
}
|
||||
|
||||
args.reverse();
|
||||
let type_kind = TypeKind::TemplateInstantiation(template, args);
|
||||
let type_kind = TypeKind::TemplateInstantiation(
|
||||
TemplateInstantiation::new(template, args));
|
||||
let name = ty.spelling();
|
||||
let name = if name.is_empty() { None } else { Some(name) };
|
||||
let ty = Type::new(name,
|
||||
|
@ -865,7 +1013,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
|
||||
/// If we have already resolved the type for the given type declaration,
|
||||
/// return its `ItemId`. Otherwise, return `None`.
|
||||
fn get_resolved_type(&self,
|
||||
pub fn get_resolved_type(&self,
|
||||
decl: &clang::CanonicalTypeDeclaration)
|
||||
-> Option<ItemId> {
|
||||
self.types
|
||||
|
@ -906,16 +1054,15 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
// of it, or
|
||||
// * we have already parsed and resolved this type, and
|
||||
// there's nothing left to do.
|
||||
//
|
||||
// Note that we only do the former if the `parent_id` exists,
|
||||
// and we have a location for building the new arguments. The
|
||||
// template argument names don't matter in the global context.
|
||||
if decl.cursor().is_template_like() &&
|
||||
*ty != decl.cursor().cur_type() &&
|
||||
location.is_some() &&
|
||||
parent_id.is_some() {
|
||||
location.is_some() {
|
||||
let location = location.unwrap();
|
||||
let parent_id = parent_id.unwrap();
|
||||
|
||||
// It is always safe to hang instantiations off of the root
|
||||
// module. They use their template definition for naming,
|
||||
// and don't need the parent for anything else.
|
||||
let parent_id = self.root_module();
|
||||
|
||||
// For specialized type aliases, there's no way to get the
|
||||
// template parameters as of this writing (for a struct
|
||||
|
@ -949,12 +1096,15 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
self.build_builtin_ty(ty)
|
||||
}
|
||||
|
||||
// This is unfortunately a lot of bloat, but is needed to properly track
|
||||
// constness et. al.
|
||||
//
|
||||
// We should probably make the constness tracking separate, so it doesn't
|
||||
// bloat that much, but hey, we already bloat the heck out of builtin types.
|
||||
fn build_ty_wrapper(&mut self,
|
||||
/// Make a new item that is a resolved type reference to the `wrapped_id`.
|
||||
///
|
||||
/// This is unfortunately a lot of bloat, but is needed to properly track
|
||||
/// constness et. al.
|
||||
///
|
||||
/// We should probably make the constness tracking separate, so it doesn't
|
||||
/// bloat that much, but hey, we already bloat the heck out of builtin
|
||||
/// types.
|
||||
pub fn build_ty_wrapper(&mut self,
|
||||
with_id: ItemId,
|
||||
wrapped_id: ItemId,
|
||||
parent_id: Option<ItemId>,
|
||||
|
@ -989,8 +1139,10 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
CXType_Bool => TypeKind::Int(IntKind::Bool),
|
||||
CXType_Int => TypeKind::Int(IntKind::Int),
|
||||
CXType_UInt => TypeKind::Int(IntKind::UInt),
|
||||
CXType_SChar | CXType_Char_S => TypeKind::Int(IntKind::Char),
|
||||
CXType_UChar | CXType_Char_U => TypeKind::Int(IntKind::UChar),
|
||||
CXType_Char_S => TypeKind::Int(IntKind::Char { is_signed: true }),
|
||||
CXType_Char_U => TypeKind::Int(IntKind::Char { is_signed: false }),
|
||||
CXType_SChar => TypeKind::Int(IntKind::SChar),
|
||||
CXType_UChar => TypeKind::Int(IntKind::UChar),
|
||||
CXType_Short => TypeKind::Int(IntKind::Short),
|
||||
CXType_UShort => TypeKind::Int(IntKind::UShort),
|
||||
CXType_WChar | CXType_Char16 => TypeKind::Int(IntKind::U16),
|
||||
|
@ -1111,35 +1263,8 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
&self.options
|
||||
}
|
||||
|
||||
/// Output graphviz dot file.
|
||||
pub fn emit_ir_graphviz(&self, path: String) -> io::Result<()> {
|
||||
let file = try!(File::create(path));
|
||||
let mut dot_file = io::BufWriter::new(file);
|
||||
writeln!(&mut dot_file, "digraph {{")?;
|
||||
|
||||
let mut err: Option<io::Result<_>> = None;
|
||||
|
||||
for (id, item) in self.items() {
|
||||
writeln!(&mut dot_file, "{} {};", id.0, item.dot_attributes(self))?;
|
||||
|
||||
item.trace(self, &mut |sub_id: ItemId, _edge_kind| {
|
||||
match writeln!(&mut dot_file, "{} -> {};", id.0, sub_id.as_usize()) {
|
||||
Ok(_) => {},
|
||||
Err(e) => err = Some(Err(e)),
|
||||
}
|
||||
}, &());
|
||||
|
||||
if err.is_some() {
|
||||
return err.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(&mut dot_file, "}}")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Tokenizes a namespace cursor in order to get the name and kind of the
|
||||
/// namespace,
|
||||
/// namespace.
|
||||
fn tokenize_namespace(&self,
|
||||
cursor: &clang::Cursor)
|
||||
-> (Option<String>, ModuleKind) {
|
||||
|
@ -1155,6 +1280,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
let mut kind = ModuleKind::Normal;
|
||||
let mut found_namespace_keyword = false;
|
||||
let mut module_name = None;
|
||||
|
||||
while let Some(token) = iter.next() {
|
||||
match &*token.spelling {
|
||||
"inline" => {
|
||||
|
@ -1162,7 +1288,17 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
assert!(kind != ModuleKind::Inline);
|
||||
kind = ModuleKind::Inline;
|
||||
}
|
||||
"namespace" => {
|
||||
// The double colon allows us to handle nested namespaces like
|
||||
// namespace foo::bar { }
|
||||
//
|
||||
// libclang still gives us two namespace cursors, which is cool,
|
||||
// but the tokenization of the second begins with the double
|
||||
// colon. That's ok, so we only need to handle the weird
|
||||
// tokenization here.
|
||||
//
|
||||
// Fortunately enough, inline nested namespace specifiers aren't
|
||||
// a thing, and are invalid C++ :)
|
||||
"namespace" | "::" => {
|
||||
found_namespace_keyword = true;
|
||||
}
|
||||
"{" => {
|
||||
|
@ -1299,14 +1435,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
// unions).
|
||||
let mut roots: Vec<_> = roots.collect();
|
||||
roots.reverse();
|
||||
|
||||
let predicate = if self.options().whitelist_recursively {
|
||||
traversal::all_edges
|
||||
} else {
|
||||
traversal::no_edges
|
||||
};
|
||||
|
||||
WhitelistedItems::new(self, roots, predicate)
|
||||
WhitelistedItems::new(self, roots)
|
||||
}
|
||||
|
||||
/// Convenient method for getting the prefix to use for most traits in
|
||||
|
@ -1330,6 +1459,73 @@ impl<'ctx> BindgenContext<'ctx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A builder struct for configuring item resolution options.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ItemResolver {
|
||||
id: ItemId,
|
||||
through_type_refs: bool,
|
||||
through_type_aliases: bool,
|
||||
}
|
||||
|
||||
impl ItemId {
|
||||
/// Create an `ItemResolver` from this item id.
|
||||
pub fn into_resolver(self) -> ItemResolver {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ItemId> for ItemResolver {
|
||||
fn from(id: ItemId) -> ItemResolver {
|
||||
ItemResolver::new(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemResolver {
|
||||
/// Construct a new `ItemResolver` from the given id.
|
||||
pub fn new(id: ItemId) -> ItemResolver {
|
||||
ItemResolver {
|
||||
id: id,
|
||||
through_type_refs: false,
|
||||
through_type_aliases: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Keep resolving through `Type::TypeRef` items.
|
||||
pub fn through_type_refs(mut self) -> ItemResolver {
|
||||
self.through_type_refs = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Keep resolving through `Type::Alias` items.
|
||||
pub fn through_type_aliases(mut self) -> ItemResolver {
|
||||
self.through_type_aliases = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Finish configuring and perform the actual item resolution.
|
||||
pub fn resolve<'a, 'b>(self, ctx: &'a BindgenContext<'b>) -> &'a Item {
|
||||
assert!(ctx.collected_typerefs());
|
||||
|
||||
let mut id = self.id;
|
||||
loop {
|
||||
let item = ctx.resolve_item(id);
|
||||
let ty_kind = item.as_type().map(|t| t.kind());
|
||||
match ty_kind {
|
||||
Some(&TypeKind::ResolvedTypeRef(next_id)) if self.through_type_refs => {
|
||||
id = next_id;
|
||||
}
|
||||
// We intentionally ignore template aliases here, as they are
|
||||
// more complicated, and don't represent a simple renaming of
|
||||
// some type.
|
||||
Some(&TypeKind::Alias(next_id)) if self.through_type_aliases => {
|
||||
id = next_id;
|
||||
}
|
||||
_ => return item,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A type that we are in the middle of parsing.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct PartialType {
|
||||
|
@ -1359,14 +1555,16 @@ impl PartialType {
|
|||
}
|
||||
}
|
||||
|
||||
impl TemplateDeclaration for PartialType {
|
||||
fn template_params(&self, _ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
||||
impl TemplateParameters for PartialType {
|
||||
fn self_template_params(&self,
|
||||
_ctx: &BindgenContext)
|
||||
-> Option<Vec<ItemId>> {
|
||||
// Maybe at some point we will eagerly parse named types, but for now we
|
||||
// don't and this information is unavailable.
|
||||
None
|
||||
}
|
||||
|
||||
fn num_template_params(&self, _ctx: &BindgenContext) -> Option<usize> {
|
||||
fn num_self_template_params(&self, _ctx: &BindgenContext) -> Option<usize> {
|
||||
// Wouldn't it be nice if libclang would reliably give us this
|
||||
// information‽
|
||||
match self.decl().kind() {
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
//! Generating Graphviz `dot` files from our IR.
|
||||
|
||||
use super::context::{BindgenContext, ItemId};
|
||||
use super::traversal::Trace;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
|
||||
/// A trait for anything that can write attributes as `<table>` rows to a dot
|
||||
/// file.
|
||||
pub trait DotAttributes {
|
||||
/// Write this thing's attributes to the given output. Each attribute must
|
||||
/// be its own `<tr>...</tr>`.
|
||||
fn dot_attributes<W>(&self,
|
||||
ctx: &BindgenContext,
|
||||
out: &mut W)
|
||||
-> io::Result<()>
|
||||
where W: io::Write;
|
||||
}
|
||||
|
||||
/// Write a graphviz dot file containing our IR.
|
||||
pub fn write_dot_file<P>(ctx: &BindgenContext, path: P) -> io::Result<()>
|
||||
where P: AsRef<Path>,
|
||||
{
|
||||
let file = try!(File::create(path));
|
||||
let mut dot_file = io::BufWriter::new(file);
|
||||
try!(writeln!(&mut dot_file, "digraph {{"));
|
||||
|
||||
let mut err: Option<io::Result<_>> = None;
|
||||
|
||||
for (id, item) in ctx.items() {
|
||||
try!(writeln!(&mut dot_file,
|
||||
r#"{} [fontname="courier", label=< <table border="0">"#,
|
||||
id.as_usize()));
|
||||
try!(item.dot_attributes(ctx, &mut dot_file));
|
||||
try!(writeln!(&mut dot_file, r#"</table> >];"#));
|
||||
|
||||
item.trace(ctx,
|
||||
&mut |sub_id: ItemId, edge_kind| {
|
||||
if err.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
match writeln!(&mut dot_file,
|
||||
"{} -> {} [label={:?}];",
|
||||
id.as_usize(),
|
||||
sub_id.as_usize(),
|
||||
edge_kind) {
|
||||
Ok(_) => {}
|
||||
Err(e) => err = Some(Err(e)),
|
||||
}
|
||||
},
|
||||
&());
|
||||
|
||||
if let Some(err) = err {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
try!(writeln!(&mut dot_file, "}}"));
|
||||
Ok(())
|
||||
}
|
|
@ -54,13 +54,15 @@ impl Enum {
|
|||
ctx: &mut BindgenContext)
|
||||
-> Result<Self, ParseError> {
|
||||
use clang_sys::*;
|
||||
debug!("Enum::from_ty {:?}", ty);
|
||||
|
||||
if ty.kind() != CXType_Enum {
|
||||
return Err(ParseError::Continue);
|
||||
}
|
||||
|
||||
let declaration = ty.declaration().canonical();
|
||||
let repr = declaration.enum_type()
|
||||
.and_then(|et| Item::from_ty(&et, None, None, ctx).ok());
|
||||
.and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok());
|
||||
let mut variants = vec![];
|
||||
|
||||
// Assume signedness since the default type by the C standard is an int.
|
||||
|
@ -82,7 +84,8 @@ impl Enum {
|
|||
};
|
||||
let type_name = type_name.as_ref().map(String::as_str);
|
||||
|
||||
declaration.visit(|cursor| {
|
||||
let definition = declaration.definition().unwrap_or(declaration);
|
||||
definition.visit(|cursor| {
|
||||
if cursor.kind() == CXCursor_EnumConstantDecl {
|
||||
let value = if is_signed {
|
||||
cursor.enum_val_signed().map(EnumVariantValue::Signed)
|
||||
|
@ -91,7 +94,7 @@ impl Enum {
|
|||
};
|
||||
if let Some(val) = value {
|
||||
let name = cursor.spelling();
|
||||
let custom_behavior = ctx.type_chooser()
|
||||
let custom_behavior = ctx.parse_callbacks()
|
||||
.and_then(|t| {
|
||||
t.enum_variant_behavior(type_name, &name, val)
|
||||
})
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
//! Intermediate representation for C/C++ functions and methods.
|
||||
|
||||
use super::context::{BindgenContext, ItemId};
|
||||
use super::dot::DotAttributes;
|
||||
use super::item::Item;
|
||||
use super::traversal::{Trace, Tracer};
|
||||
use super::traversal::{EdgeKind, Trace, Tracer};
|
||||
use super::ty::TypeKind;
|
||||
use clang;
|
||||
use clang_sys::CXCallingConv;
|
||||
use ir::derive::CanDeriveDebug;
|
||||
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
|
||||
use std::io;
|
||||
use syntax::abi;
|
||||
|
||||
/// A function declaration, with a signature, arguments, and argument names.
|
||||
|
@ -59,6 +62,23 @@ impl Function {
|
|||
}
|
||||
}
|
||||
|
||||
impl DotAttributes for Function {
|
||||
fn dot_attributes<W>(&self,
|
||||
_ctx: &BindgenContext,
|
||||
out: &mut W)
|
||||
-> io::Result<()>
|
||||
where W: io::Write,
|
||||
{
|
||||
if let Some(ref mangled) = self.mangled_name {
|
||||
try!(writeln!(out,
|
||||
"<tr><td>mangled name</td><td>{}</td></tr>",
|
||||
mangled));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A function signature.
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionSig {
|
||||
|
@ -91,7 +111,14 @@ fn get_abi(cc: CXCallingConv) -> Option<abi::Abi> {
|
|||
}
|
||||
|
||||
/// Get the mangled name for the cursor's referent.
|
||||
pub fn cursor_mangling(cursor: &clang::Cursor) -> Option<String> {
|
||||
pub fn cursor_mangling(ctx: &BindgenContext,
|
||||
cursor: &clang::Cursor)
|
||||
-> Option<String> {
|
||||
use clang_sys;
|
||||
if !ctx.options().enable_mangling {
|
||||
return None;
|
||||
}
|
||||
|
||||
// We early return here because libclang may crash in some case
|
||||
// if we pass in a variable inside a partial specialized template.
|
||||
// See servo/rust-bindgen#67, and servo/rust-bindgen#462.
|
||||
|
@ -99,16 +126,52 @@ pub fn cursor_mangling(cursor: &clang::Cursor) -> Option<String> {
|
|||
return None;
|
||||
}
|
||||
|
||||
if let Ok(mut manglings) = cursor.cxx_manglings() {
|
||||
if let Some(m) = manglings.pop() {
|
||||
return Some(m);
|
||||
}
|
||||
}
|
||||
|
||||
let mut mangling = cursor.mangling();
|
||||
if mangling.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Try to undo backend linkage munging (prepended _, generally)
|
||||
//
|
||||
// TODO(emilio): This is wrong when the target system is not the host
|
||||
// system. See https://github.com/servo/rust-bindgen/issues/593
|
||||
if cfg!(target_os = "macos") {
|
||||
mangling.remove(0);
|
||||
}
|
||||
|
||||
if cursor.kind() == clang_sys::CXCursor_Destructor {
|
||||
// With old (3.8-) libclang versions, and the Itanium ABI, clang returns
|
||||
// the "destructor group 0" symbol, which means that it'll try to free
|
||||
// memory, which definitely isn't what we want.
|
||||
//
|
||||
// Explicitly force the destructor group 1 symbol.
|
||||
//
|
||||
// See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special
|
||||
// for the reference, and http://stackoverflow.com/a/6614369/1091587 for
|
||||
// a more friendly explanation.
|
||||
//
|
||||
// We don't need to do this for constructors since clang seems to always
|
||||
// have returned the C1 constructor.
|
||||
//
|
||||
// FIXME(emilio): Can a legit symbol in other ABIs end with this string?
|
||||
// I don't think so, but if it can this would become a linker error
|
||||
// anyway, not an invalid free at runtime.
|
||||
//
|
||||
// TODO(emilio, #611): Use cpp_demangle if this becomes nastier with
|
||||
// time.
|
||||
if mangling.ends_with("D0Ev") {
|
||||
let new_len = mangling.len() - 4;
|
||||
mangling.truncate(new_len);
|
||||
mangling.push_str("D1Ev");
|
||||
}
|
||||
}
|
||||
|
||||
Some(mangling)
|
||||
}
|
||||
|
||||
|
@ -156,7 +219,8 @@ impl FunctionSig {
|
|||
CXCursor_FunctionDecl |
|
||||
CXCursor_Constructor |
|
||||
CXCursor_CXXMethod |
|
||||
CXCursor_ObjCInstanceMethodDecl => {
|
||||
CXCursor_ObjCInstanceMethodDecl |
|
||||
CXCursor_ObjCClassMethodDecl => {
|
||||
// For CXCursor_FunctionDecl, cursor.args() is the reliable way
|
||||
// to get parameter names and types.
|
||||
cursor.args()
|
||||
|
@ -167,8 +231,7 @@ impl FunctionSig {
|
|||
let name = arg.spelling();
|
||||
let name =
|
||||
if name.is_empty() { None } else { Some(name) };
|
||||
let ty =
|
||||
Item::from_ty_or_ref(arg_ty, Some(*arg), None, ctx);
|
||||
let ty = Item::from_ty_or_ref(arg_ty, *arg, None, ctx);
|
||||
(name, ty)
|
||||
})
|
||||
.collect()
|
||||
|
@ -179,10 +242,8 @@ impl FunctionSig {
|
|||
let mut args = vec![];
|
||||
cursor.visit(|c| {
|
||||
if c.kind() == CXCursor_ParmDecl {
|
||||
let ty = Item::from_ty_or_ref(c.cur_type(),
|
||||
Some(c),
|
||||
None,
|
||||
ctx);
|
||||
let ty =
|
||||
Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
|
||||
let name = c.spelling();
|
||||
let name =
|
||||
if name.is_empty() { None } else { Some(name) };
|
||||
|
@ -196,13 +257,14 @@ impl FunctionSig {
|
|||
|
||||
let is_method = cursor.kind() == CXCursor_CXXMethod;
|
||||
let is_constructor = cursor.kind() == CXCursor_Constructor;
|
||||
if (is_constructor || is_method) &&
|
||||
let is_destructor = cursor.kind() == CXCursor_Destructor;
|
||||
if (is_constructor || is_destructor || is_method) &&
|
||||
cursor.lexical_parent() != cursor.semantic_parent() {
|
||||
// Only parse constructors once.
|
||||
return Err(ParseError::Continue);
|
||||
}
|
||||
|
||||
if is_method || is_constructor {
|
||||
if is_method || is_constructor || is_destructor {
|
||||
let is_const = is_method && cursor.method_is_const();
|
||||
let is_virtual = is_method && cursor.method_is_virtual();
|
||||
let is_static = is_method && cursor.method_is_static();
|
||||
|
@ -220,17 +282,20 @@ impl FunctionSig {
|
|||
}
|
||||
}
|
||||
|
||||
let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl {
|
||||
try!(cursor.ret_type().ok_or(ParseError::Continue))
|
||||
let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
|
||||
cursor.kind() == CXCursor_ObjCClassMethodDecl {
|
||||
try!(ty.ret_type()
|
||||
.or_else(|| cursor.ret_type())
|
||||
.ok_or(ParseError::Continue))
|
||||
} else {
|
||||
try!(ty.ret_type().ok_or(ParseError::Continue))
|
||||
};
|
||||
let ret = Item::from_ty_or_ref(ty_ret_type, None, None, ctx);
|
||||
let ret = Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx);
|
||||
let abi = get_abi(ty.call_conv());
|
||||
|
||||
if abi.is_none() {
|
||||
assert_eq!(cursor.kind(),
|
||||
CXCursor_ObjCInstanceMethodDecl,
|
||||
assert!(cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
|
||||
cursor.kind() == CXCursor_ObjCClassMethodDecl,
|
||||
"Invalid ABI for function signature")
|
||||
}
|
||||
|
||||
|
@ -267,9 +332,9 @@ impl ClangSubItemParser for Function {
|
|||
-> Result<ParseResult<Self>, ParseError> {
|
||||
use clang_sys::*;
|
||||
match cursor.kind() {
|
||||
// FIXME(emilio): Generate destructors properly.
|
||||
CXCursor_FunctionDecl |
|
||||
CXCursor_Constructor |
|
||||
CXCursor_Destructor |
|
||||
CXCursor_CXXMethod => {}
|
||||
_ => return Err(ParseError::Continue),
|
||||
};
|
||||
|
@ -285,7 +350,8 @@ impl ClangSubItemParser for Function {
|
|||
return Err(ParseError::Continue);
|
||||
}
|
||||
|
||||
if cursor.is_inlined_function() {
|
||||
if !context.options().generate_inline_functions &&
|
||||
cursor.is_inlined_function() {
|
||||
return Err(ParseError::Continue);
|
||||
}
|
||||
|
||||
|
@ -296,15 +362,27 @@ impl ClangSubItemParser for Function {
|
|||
}
|
||||
|
||||
// Grab the signature using Item::from_ty.
|
||||
let sig = try!(Item::from_ty(&cursor.cur_type(),
|
||||
Some(cursor),
|
||||
None,
|
||||
context));
|
||||
let sig =
|
||||
try!(Item::from_ty(&cursor.cur_type(), cursor, None, context));
|
||||
|
||||
let name = cursor.spelling();
|
||||
let mut name = cursor.spelling();
|
||||
assert!(!name.is_empty(), "Empty function name?");
|
||||
|
||||
let mut mangled_name = cursor_mangling(&cursor);
|
||||
if cursor.kind() == CXCursor_Destructor {
|
||||
// Remove the leading `~`. The alternative to this is special-casing
|
||||
// code-generation for destructor functions, which seems less than
|
||||
// ideal.
|
||||
if name.starts_with('~') {
|
||||
name.remove(0);
|
||||
}
|
||||
|
||||
// Add a suffix to avoid colliding with constructors. This would be
|
||||
// technically fine (since we handle duplicated functions/methods),
|
||||
// but seems easy enough to handle it here.
|
||||
name.push_str("_destructor");
|
||||
}
|
||||
|
||||
let mut mangled_name = cursor_mangling(context, &cursor);
|
||||
if mangled_name.as_ref() == Some(&name) {
|
||||
mangled_name = None;
|
||||
}
|
||||
|
@ -322,10 +400,34 @@ impl Trace for FunctionSig {
|
|||
fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
|
||||
where T: Tracer,
|
||||
{
|
||||
tracer.visit(self.return_type());
|
||||
tracer.visit_kind(self.return_type(), EdgeKind::FunctionReturn);
|
||||
|
||||
for &(_, ty) in self.argument_types() {
|
||||
tracer.visit(ty);
|
||||
tracer.visit_kind(ty, EdgeKind::FunctionParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function pointers follow special rules, see:
|
||||
//
|
||||
// https://github.com/servo/rust-bindgen/issues/547,
|
||||
// https://github.com/rust-lang/rust/issues/38848,
|
||||
// and https://github.com/rust-lang/rust/issues/40158
|
||||
//
|
||||
// Note that copy is always derived, so we don't need to implement it.
|
||||
impl CanDeriveDebug for FunctionSig {
|
||||
type Extra = ();
|
||||
|
||||
fn can_derive_debug(&self, _ctx: &BindgenContext, _: ()) -> bool {
|
||||
const RUST_DERIVE_FUNPTR_LIMIT: usize = 12;
|
||||
if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT {
|
||||
return false;
|
||||
}
|
||||
|
||||
match self.abi {
|
||||
Some(abi::Abi::C) |
|
||||
None => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,18 @@ pub enum IntKind {
|
|||
/// A `bool`.
|
||||
Bool,
|
||||
|
||||
/// A `char`.
|
||||
Char,
|
||||
/// A `signed char`.
|
||||
SChar,
|
||||
|
||||
/// An `unsigned char`.
|
||||
UChar,
|
||||
|
||||
/// A platform-dependent `char` type, with the signedness support.
|
||||
Char {
|
||||
/// Whether the char is signed for the target platform.
|
||||
is_signed: bool,
|
||||
},
|
||||
|
||||
/// A `short`.
|
||||
Short,
|
||||
|
||||
|
@ -84,9 +90,11 @@ impl IntKind {
|
|||
Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 |
|
||||
U32 | U64 | U128 => false,
|
||||
|
||||
Char | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 |
|
||||
SChar | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 |
|
||||
I128 => true,
|
||||
|
||||
Char { is_signed } => is_signed,
|
||||
|
||||
Custom { is_signed, .. } => is_signed,
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +105,7 @@ impl IntKind {
|
|||
pub fn known_size(&self) -> Option<usize> {
|
||||
use self::IntKind::*;
|
||||
Some(match *self {
|
||||
Bool | UChar | Char | U8 | I8 => 1,
|
||||
Bool | UChar | SChar | U8 | I8 | Char { .. } => 1,
|
||||
U16 | I16 => 2,
|
||||
U32 | I32 => 4,
|
||||
U64 | I64 => 8,
|
||||
|
|
|
@ -3,18 +3,23 @@
|
|||
use super::annotations::Annotations;
|
||||
use super::context::{BindgenContext, ItemId, PartialType};
|
||||
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
|
||||
use super::dot::DotAttributes;
|
||||
use super::function::Function;
|
||||
use super::item_kind::ItemKind;
|
||||
use super::layout::Opaque;
|
||||
use super::module::Module;
|
||||
use super::traversal::{Trace, Tracer};
|
||||
use super::ty::{TemplateDeclaration, Type, TypeKind};
|
||||
use super::template::{AsNamed, TemplateParameters};
|
||||
use super::traversal::{EdgeKind, Trace, Tracer};
|
||||
use super::ty::{Type, TypeKind};
|
||||
use clang;
|
||||
use clang_sys;
|
||||
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::Write;
|
||||
use std::io;
|
||||
use std::iter;
|
||||
use regex;
|
||||
|
||||
/// A trait to get the canonical name from an item.
|
||||
///
|
||||
|
@ -65,7 +70,7 @@ pub trait ItemAncestors {
|
|||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(debug_assertions)] {
|
||||
if #[cfg(testing_only_extra_assertions)] {
|
||||
type DebugOnlyItemSet = ItemSet;
|
||||
} else {
|
||||
struct DebugOnlyItemSet;
|
||||
|
@ -118,7 +123,7 @@ impl<'a, 'b> Iterator for ItemAncestorsIter<'a, 'b>
|
|||
} else {
|
||||
self.item = item.parent_id();
|
||||
|
||||
debug_assert!(!self.seen.contains(&item.id()));
|
||||
extra_assert!(!self.seen.contains(&item.id()));
|
||||
self.seen.insert(item.id());
|
||||
|
||||
Some(item.id())
|
||||
|
@ -126,6 +131,35 @@ impl<'a, 'b> Iterator for ItemAncestorsIter<'a, 'b>
|
|||
}
|
||||
}
|
||||
|
||||
impl AsNamed for ItemId {
|
||||
type Extra = ();
|
||||
|
||||
fn as_named(&self, ctx: &BindgenContext, _: &()) -> Option<ItemId> {
|
||||
ctx.resolve_item(*self).as_named(ctx, &())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsNamed for Item {
|
||||
type Extra = ();
|
||||
|
||||
fn as_named(&self, ctx: &BindgenContext, _: &()) -> Option<ItemId> {
|
||||
self.kind.as_named(ctx, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsNamed for ItemKind {
|
||||
type Extra = Item;
|
||||
|
||||
fn as_named(&self, ctx: &BindgenContext, item: &Item) -> Option<ItemId> {
|
||||
match *self {
|
||||
ItemKind::Type(ref ty) => ty.as_named(ctx, item),
|
||||
ItemKind::Module(..) |
|
||||
ItemKind::Function(..) |
|
||||
ItemKind::Var(..) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pure convenience
|
||||
impl ItemCanonicalName for ItemId {
|
||||
fn canonical_name(&self, ctx: &BindgenContext) -> String {
|
||||
|
@ -183,9 +217,12 @@ impl Trace for Item {
|
|||
fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, _extra: &())
|
||||
where T: Tracer,
|
||||
{
|
||||
if self.is_hidden(ctx) {
|
||||
return;
|
||||
}
|
||||
// Even if this item is blacklisted/hidden, we want to trace it. It is
|
||||
// traversal iterators' consumers' responsibility to filter items as
|
||||
// needed. Generally, this filtering happens in the implementation of
|
||||
// `Iterator` for `WhitelistedItems`. Fully tracing blacklisted items is
|
||||
// necessary for things like the template parameter usage analysis to
|
||||
// function correctly.
|
||||
|
||||
match *self.kind() {
|
||||
ItemKind::Type(ref ty) => {
|
||||
|
@ -203,7 +240,7 @@ impl Trace for Item {
|
|||
tracer.visit(fun.signature());
|
||||
}
|
||||
ItemKind::Var(ref var) => {
|
||||
tracer.visit(var.ty());
|
||||
tracer.visit_kind(var.ty(), EdgeKind::VarType);
|
||||
}
|
||||
ItemKind::Module(_) => {
|
||||
// Module -> children edges are "weak", and we do not want to
|
||||
|
@ -222,7 +259,13 @@ impl CanDeriveDebug for Item {
|
|||
type Extra = ();
|
||||
|
||||
fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
|
||||
ctx.options().derive_debug &&
|
||||
if self.detect_derive_debug_cycle.get() {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.detect_derive_debug_cycle.set(true);
|
||||
|
||||
let result = ctx.options().derive_debug &&
|
||||
match self.kind {
|
||||
ItemKind::Type(ref ty) => {
|
||||
if self.is_opaque(ctx) {
|
||||
|
@ -233,7 +276,11 @@ impl CanDeriveDebug for Item {
|
|||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
|
||||
self.detect_derive_debug_cycle.set(false);
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,7 +308,13 @@ impl<'a> CanDeriveCopy<'a> for Item {
|
|||
type Extra = ();
|
||||
|
||||
fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
|
||||
match self.kind {
|
||||
if self.detect_derive_copy_cycle.get() {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.detect_derive_copy_cycle.set(true);
|
||||
|
||||
let result = match self.kind {
|
||||
ItemKind::Type(ref ty) => {
|
||||
if self.is_opaque(ctx) {
|
||||
ty.layout(ctx)
|
||||
|
@ -271,7 +324,11 @@ impl<'a> CanDeriveCopy<'a> for Item {
|
|||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
|
||||
self.detect_derive_copy_cycle.set(false);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
|
||||
|
@ -344,6 +401,16 @@ pub struct Item {
|
|||
parent_id: ItemId,
|
||||
/// The item kind.
|
||||
kind: ItemKind,
|
||||
/// Detect cycles when determining if we can derive debug/copy or not, and
|
||||
/// avoid infinite recursion.
|
||||
detect_derive_debug_cycle: Cell<bool>,
|
||||
detect_derive_copy_cycle: Cell<bool>,
|
||||
}
|
||||
|
||||
impl AsRef<ItemId> for Item {
|
||||
fn as_ref(&self) -> &ItemId {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Item {
|
||||
|
@ -364,28 +431,28 @@ impl Item {
|
|||
comment: comment,
|
||||
annotations: annotations.unwrap_or_default(),
|
||||
kind: kind,
|
||||
detect_derive_debug_cycle: Cell::new(false),
|
||||
detect_derive_copy_cycle: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a new opaque item type.
|
||||
pub fn new_opaque_type(with_id: ItemId,
|
||||
ty: &clang::Type,
|
||||
ctx: &mut BindgenContext)
|
||||
-> ItemId {
|
||||
let ty = Opaque::from_clang_ty(ty);
|
||||
let kind = ItemKind::Type(ty);
|
||||
let parent = ctx.root_module();
|
||||
ctx.add_item(Item::new(with_id, None, None, parent, kind), None, None);
|
||||
with_id
|
||||
}
|
||||
|
||||
/// Get this `Item`'s identifier.
|
||||
pub fn id(&self) -> ItemId {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Get this `Item`'s dot attributes.
|
||||
pub fn dot_attributes(&self, ctx: &BindgenContext) -> String {
|
||||
format!("[fontname=\"courier\", label=< \
|
||||
<table border=\"0\"> \
|
||||
<tr><td>ItemId({})</td></tr> \
|
||||
<tr><td>name</td><td>{}</td></tr> \
|
||||
<tr><td>kind</td><td>{}</td></tr> \
|
||||
</table> \
|
||||
>]",
|
||||
self.id.as_usize(),
|
||||
self.name(ctx).get(),
|
||||
self.kind.kind_name())
|
||||
}
|
||||
|
||||
/// Get this `Item`'s parent's identifier.
|
||||
///
|
||||
/// For the root module, the parent's ID is its own ID.
|
||||
|
@ -486,184 +553,12 @@ impl Item {
|
|||
self.kind().as_type()
|
||||
}
|
||||
|
||||
/// Is this item a named template type parameter?
|
||||
pub fn is_named(&self) -> bool {
|
||||
self.as_type()
|
||||
.map(|ty| ty.is_named())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Get a reference to this item's underlying `Function`. Panic if this is
|
||||
/// some other kind of item.
|
||||
pub fn expect_function(&self) -> &Function {
|
||||
self.kind().expect_function()
|
||||
}
|
||||
|
||||
/// Checks whether an item contains in its "type signature" some named type.
|
||||
///
|
||||
/// This function is used to avoid unused template parameter errors in Rust
|
||||
/// when generating typedef declarations, and also to know whether we need
|
||||
/// to generate a `PhantomData` member for a template parameter.
|
||||
///
|
||||
/// For example, in code like the following:
|
||||
///
|
||||
/// ```c++
|
||||
/// template<typename T, typename U>
|
||||
/// struct Foo {
|
||||
/// T bar;
|
||||
///
|
||||
/// struct Baz {
|
||||
/// U bas;
|
||||
/// };
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// Both `Foo` and `Baz` contain both `T` and `U` template parameters in
|
||||
/// their signature:
|
||||
///
|
||||
/// * `Foo<T, U>`
|
||||
/// * `Bar<T, U>`
|
||||
///
|
||||
/// But the Rust structure for `Foo` would look like:
|
||||
///
|
||||
/// ```rust
|
||||
/// struct Foo<T, U> {
|
||||
/// bar: T,
|
||||
/// _phantom0: ::std::marker::PhantomData<U>,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// because none of its member fields contained the `U` type in the
|
||||
/// signature. Similarly, `Bar` would contain a `PhantomData<T>` type, for
|
||||
/// the same reason.
|
||||
///
|
||||
/// Note that this is somewhat similar to `applicable_template_args`, but
|
||||
/// this also takes into account other kind of types, like arrays,
|
||||
/// (`[T; 40]`), pointers: `*mut T`, etc...
|
||||
///
|
||||
/// Normally we could do this check just in the `Type` kind, but we also
|
||||
/// need to check the `applicable_template_args` more generally, since we
|
||||
/// could need a type transitively from our parent, see the test added in
|
||||
/// commit 2a3f93074dd2898669dbbce6e97e5cc4405d7cb1.
|
||||
///
|
||||
/// It's kind of unfortunate (in the sense that it's a sort of complex
|
||||
/// process), but I think it should get all the cases.
|
||||
fn signature_contains_named_type(&self,
|
||||
ctx: &BindgenContext,
|
||||
ty: &Type)
|
||||
-> bool {
|
||||
debug_assert!(ty.is_named());
|
||||
self.expect_type().signature_contains_named_type(ctx, ty) ||
|
||||
self.applicable_template_args(ctx).iter().any(|template| {
|
||||
ctx.resolve_type(*template).signature_contains_named_type(ctx, ty)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the template arguments that apply to a struct. This is a concept
|
||||
/// needed because of type declarations inside templates, for example:
|
||||
///
|
||||
/// ```c++
|
||||
/// template<typename T>
|
||||
/// class Foo {
|
||||
/// typedef T element_type;
|
||||
/// typedef int Bar;
|
||||
///
|
||||
/// template<typename U>
|
||||
/// class Baz {
|
||||
/// };
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// In this case, the applicable template arguments for the different types
|
||||
/// would be:
|
||||
///
|
||||
/// * `Foo`: [`T`]
|
||||
/// * `Foo::element_type`: [`T`]
|
||||
/// * `Foo::Bar`: [`T`]
|
||||
/// * `Foo::Baz`: [`T`, `U`]
|
||||
///
|
||||
/// You might notice that we can't generate something like:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// type Foo_Bar<T> = ::std::os::raw::c_int;
|
||||
/// ```
|
||||
///
|
||||
/// since that would be invalid Rust. Still, conceptually, `Bar` *could* use
|
||||
/// the template parameter type `T`, and that's exactly what this method
|
||||
/// represents. The unused template parameters get stripped in the
|
||||
/// `signature_contains_named_type` check.
|
||||
pub fn applicable_template_args(&self,
|
||||
ctx: &BindgenContext)
|
||||
-> Vec<ItemId> {
|
||||
let ty = match *self.kind() {
|
||||
ItemKind::Type(ref ty) => ty,
|
||||
_ => return vec![],
|
||||
};
|
||||
|
||||
fn parent_contains(ctx: &BindgenContext,
|
||||
parent_template_args: &[ItemId],
|
||||
item: ItemId)
|
||||
-> bool {
|
||||
let item_ty = ctx.resolve_type(item);
|
||||
parent_template_args.iter().any(|parent_item| {
|
||||
let parent_ty = ctx.resolve_type(*parent_item);
|
||||
match (parent_ty.kind(), item_ty.kind()) {
|
||||
(&TypeKind::Named, &TypeKind::Named) => {
|
||||
parent_ty.name() == item_ty.name()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
match *ty.kind() {
|
||||
TypeKind::Named => vec![self.id()],
|
||||
TypeKind::Array(inner, _) |
|
||||
TypeKind::Pointer(inner) |
|
||||
TypeKind::Reference(inner) |
|
||||
TypeKind::ResolvedTypeRef(inner) => {
|
||||
ctx.resolve_item(inner).applicable_template_args(ctx)
|
||||
}
|
||||
TypeKind::Alias(inner) => {
|
||||
let parent_args = ctx.resolve_item(self.parent_id())
|
||||
.applicable_template_args(ctx);
|
||||
let inner = ctx.resolve_item(inner);
|
||||
|
||||
// Avoid unused type parameters, sigh.
|
||||
parent_args.iter()
|
||||
.cloned()
|
||||
.filter(|arg| {
|
||||
let arg = ctx.resolve_type(*arg);
|
||||
arg.is_named() &&
|
||||
inner.signature_contains_named_type(ctx, arg)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
// XXX Is this completely correct? Partial template specialization
|
||||
// is hard anyways, sigh...
|
||||
TypeKind::TemplateAlias(_, ref args) |
|
||||
TypeKind::TemplateInstantiation(_, ref args) => args.clone(),
|
||||
// In a template specialization we've got all we want.
|
||||
TypeKind::Comp(ref ci) if ci.is_template_specialization() => {
|
||||
ci.template_args().iter().cloned().collect()
|
||||
}
|
||||
TypeKind::Comp(ref ci) => {
|
||||
let mut parent_template_args =
|
||||
ctx.resolve_item(self.parent_id())
|
||||
.applicable_template_args(ctx);
|
||||
|
||||
for ty in ci.template_args() {
|
||||
if !parent_contains(ctx, &parent_template_args, *ty) {
|
||||
parent_template_args.push(*ty);
|
||||
}
|
||||
}
|
||||
|
||||
parent_template_args
|
||||
}
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this item a module?
|
||||
pub fn is_module(&self) -> bool {
|
||||
match self.kind {
|
||||
|
@ -692,6 +587,7 @@ impl Item {
|
|||
debug_assert!(ctx.in_codegen_phase(),
|
||||
"You're not supposed to call this yet");
|
||||
self.annotations.opaque() ||
|
||||
self.as_type().map_or(false, |ty| ty.is_opaque()) ||
|
||||
ctx.opaque_by_name(&self.canonical_path(ctx))
|
||||
}
|
||||
|
||||
|
@ -721,7 +617,7 @@ impl Item {
|
|||
let mut item = self;
|
||||
|
||||
loop {
|
||||
debug_assert!(!targets_seen.contains(&item.id()));
|
||||
extra_assert!(!targets_seen.contains(&item.id()));
|
||||
targets_seen.insert(item.id());
|
||||
|
||||
if self.annotations().use_instead_of().is_some() {
|
||||
|
@ -731,19 +627,12 @@ impl Item {
|
|||
match *item.kind() {
|
||||
ItemKind::Type(ref ty) => {
|
||||
match *ty.kind() {
|
||||
// If we're a template specialization, our name is our
|
||||
// parent's name.
|
||||
TypeKind::Comp(ref ci)
|
||||
if ci.is_template_specialization() => {
|
||||
let specialized =
|
||||
ci.specialized_template().unwrap();
|
||||
item = ctx.resolve_item(specialized);
|
||||
}
|
||||
// Same as above.
|
||||
TypeKind::ResolvedTypeRef(inner) |
|
||||
TypeKind::TemplateInstantiation(inner, _) => {
|
||||
TypeKind::ResolvedTypeRef(inner) => {
|
||||
item = ctx.resolve_item(inner);
|
||||
}
|
||||
TypeKind::TemplateInstantiation(ref inst) => {
|
||||
item = ctx.resolve_item(inst.template_definition());
|
||||
}
|
||||
_ => return item.id(),
|
||||
}
|
||||
}
|
||||
|
@ -857,7 +746,7 @@ impl Item {
|
|||
|
||||
// Named template type arguments are never namespaced, and never
|
||||
// mangled.
|
||||
if target.as_type().map_or(false, |ty| ty.is_named()) {
|
||||
if target.is_named(ctx, &()) {
|
||||
return base_name;
|
||||
}
|
||||
|
||||
|
@ -928,23 +817,45 @@ impl Item {
|
|||
/// A set of items.
|
||||
pub type ItemSet = BTreeSet<ItemId>;
|
||||
|
||||
impl TemplateDeclaration for ItemId {
|
||||
fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
||||
impl DotAttributes for Item {
|
||||
fn dot_attributes<W>(&self,
|
||||
ctx: &BindgenContext,
|
||||
out: &mut W)
|
||||
-> io::Result<()>
|
||||
where W: io::Write,
|
||||
{
|
||||
try!(writeln!(out,
|
||||
"<tr><td>{:?}</td></tr>
|
||||
<tr><td>name</td><td>{}</td></tr>",
|
||||
self.id,
|
||||
self.name(ctx).get()));
|
||||
self.kind.dot_attributes(ctx, out)
|
||||
}
|
||||
}
|
||||
|
||||
impl TemplateParameters for ItemId {
|
||||
fn self_template_params(&self,
|
||||
ctx: &BindgenContext)
|
||||
-> Option<Vec<ItemId>> {
|
||||
ctx.resolve_item_fallible(*self)
|
||||
.and_then(|item| item.template_params(ctx))
|
||||
.and_then(|item| item.self_template_params(ctx))
|
||||
}
|
||||
}
|
||||
|
||||
impl TemplateDeclaration for Item {
|
||||
fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
||||
self.kind.template_params(ctx)
|
||||
impl TemplateParameters for Item {
|
||||
fn self_template_params(&self,
|
||||
ctx: &BindgenContext)
|
||||
-> Option<Vec<ItemId>> {
|
||||
self.kind.self_template_params(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl TemplateDeclaration for ItemKind {
|
||||
fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
||||
impl TemplateParameters for ItemKind {
|
||||
fn self_template_params(&self,
|
||||
ctx: &BindgenContext)
|
||||
-> Option<Vec<ItemId>> {
|
||||
match *self {
|
||||
ItemKind::Type(ref ty) => ty.template_params(ctx),
|
||||
ItemKind::Type(ref ty) => ty.self_template_params(ctx),
|
||||
// If we start emitting bindings to explicitly instantiated
|
||||
// functions, then we'll need to check ItemKind::Function for
|
||||
// template params.
|
||||
|
@ -968,7 +879,7 @@ fn visit_child(cur: clang::Cursor,
|
|||
return CXChildVisit_Break;
|
||||
}
|
||||
|
||||
*result = Item::from_ty_with_id(id, ty, Some(cur), parent_id, ctx);
|
||||
*result = Item::from_ty_with_id(id, ty, cur, parent_id, ctx);
|
||||
|
||||
match *result {
|
||||
Ok(..) => CXChildVisit_Break,
|
||||
|
@ -1061,8 +972,8 @@ impl ClangItemParser for Item {
|
|||
// twice, handle them separately.
|
||||
{
|
||||
let applicable_cursor = cursor.definition().unwrap_or(cursor);
|
||||
match Self::from_ty(&applicable_cursor.cur_type(),
|
||||
Some(applicable_cursor),
|
||||
match Item::from_ty(&applicable_cursor.cur_type(),
|
||||
applicable_cursor,
|
||||
parent_id,
|
||||
ctx) {
|
||||
Ok(ty) => return Ok(ty),
|
||||
|
@ -1104,7 +1015,7 @@ impl ClangItemParser for Item {
|
|||
}
|
||||
|
||||
fn from_ty_or_ref(ty: clang::Type,
|
||||
location: Option<clang::Cursor>,
|
||||
location: clang::Cursor,
|
||||
parent_id: Option<ItemId>,
|
||||
ctx: &mut BindgenContext)
|
||||
-> ItemId {
|
||||
|
@ -1124,7 +1035,7 @@ impl ClangItemParser for Item {
|
|||
/// `BindgenContext::resolve_typerefs`.
|
||||
fn from_ty_or_ref_with_id(potential_id: ItemId,
|
||||
ty: clang::Type,
|
||||
location: Option<clang::Cursor>,
|
||||
location: clang::Cursor,
|
||||
parent_id: Option<ItemId>,
|
||||
ctx: &mut BindgenContext)
|
||||
-> ItemId {
|
||||
|
@ -1136,16 +1047,20 @@ impl ClangItemParser for Item {
|
|||
|
||||
if ctx.collected_typerefs() {
|
||||
debug!("refs already collected, resolving directly");
|
||||
return Self::from_ty_with_id(potential_id,
|
||||
return Item::from_ty_with_id(potential_id,
|
||||
&ty,
|
||||
location,
|
||||
parent_id,
|
||||
ctx)
|
||||
.expect("Unable to resolve type");
|
||||
.unwrap_or_else(|_| {
|
||||
Item::new_opaque_type(potential_id, &ty, ctx)
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(ty) =
|
||||
ctx.builtin_or_resolved_ty(potential_id, parent_id, &ty, location) {
|
||||
if let Some(ty) = ctx.builtin_or_resolved_ty(potential_id,
|
||||
parent_id,
|
||||
&ty,
|
||||
Some(location)) {
|
||||
debug!("{:?} already resolved: {:?}", ty, location);
|
||||
return ty;
|
||||
}
|
||||
|
@ -1168,14 +1083,13 @@ impl ClangItemParser for Item {
|
|||
potential_id
|
||||
}
|
||||
|
||||
|
||||
fn from_ty(ty: &clang::Type,
|
||||
location: Option<clang::Cursor>,
|
||||
location: clang::Cursor,
|
||||
parent_id: Option<ItemId>,
|
||||
ctx: &mut BindgenContext)
|
||||
-> Result<ItemId, ParseError> {
|
||||
let id = ctx.next_item_id();
|
||||
Self::from_ty_with_id(id, ty, location, parent_id, ctx)
|
||||
Item::from_ty_with_id(id, ty, location, parent_id, ctx)
|
||||
}
|
||||
|
||||
/// This is one of the trickiest methods you'll find (probably along with
|
||||
|
@ -1188,21 +1102,41 @@ impl ClangItemParser for Item {
|
|||
/// context.
|
||||
fn from_ty_with_id(id: ItemId,
|
||||
ty: &clang::Type,
|
||||
location: Option<clang::Cursor>,
|
||||
location: clang::Cursor,
|
||||
parent_id: Option<ItemId>,
|
||||
ctx: &mut BindgenContext)
|
||||
-> Result<ItemId, ParseError> {
|
||||
use clang_sys::*;
|
||||
|
||||
debug!("Item::from_ty_with_id: {:?}\n\
|
||||
\tty = {:?},\n\
|
||||
\tlocation = {:?}",
|
||||
id,
|
||||
ty,
|
||||
location);
|
||||
|
||||
if ty.kind() == clang_sys::CXType_Unexposed ||
|
||||
location.cur_type().kind() == clang_sys::CXType_Unexposed {
|
||||
|
||||
if ty.is_associated_type() ||
|
||||
location.cur_type().is_associated_type() {
|
||||
return Ok(Item::new_opaque_type(id, ty, ctx));
|
||||
}
|
||||
|
||||
if let Some(id) = Item::named_type(Some(id), location, ctx) {
|
||||
return Ok(id);
|
||||
}
|
||||
}
|
||||
|
||||
let decl = {
|
||||
let decl = ty.declaration();
|
||||
decl.definition().unwrap_or(decl)
|
||||
};
|
||||
|
||||
let comment = decl.raw_comment()
|
||||
.or_else(|| location.as_ref().and_then(|l| l.raw_comment()));
|
||||
.or_else(|| location.raw_comment());
|
||||
let annotations = Annotations::new(&decl)
|
||||
.or_else(|| location.as_ref().and_then(|l| Annotations::new(l)));
|
||||
.or_else(|| Annotations::new(&location));
|
||||
|
||||
if let Some(ref annotations) = annotations {
|
||||
if let Some(ref replaced) = annotations.use_instead_of() {
|
||||
|
@ -1211,7 +1145,7 @@ impl ClangItemParser for Item {
|
|||
}
|
||||
|
||||
if let Some(ty) =
|
||||
ctx.builtin_or_resolved_ty(id, parent_id, ty, location) {
|
||||
ctx.builtin_or_resolved_ty(id, parent_id, ty, Some(location)) {
|
||||
return Ok(ty);
|
||||
}
|
||||
|
||||
|
@ -1219,11 +1153,10 @@ impl ClangItemParser for Item {
|
|||
let mut valid_decl = decl.kind() != CXCursor_NoDeclFound;
|
||||
let declaration_to_look_for = if valid_decl {
|
||||
decl.canonical()
|
||||
} else if location.is_some() &&
|
||||
location.unwrap().kind() ==
|
||||
} else if location.kind() ==
|
||||
CXCursor_ClassTemplate {
|
||||
valid_decl = true;
|
||||
location.unwrap()
|
||||
location
|
||||
} else {
|
||||
decl
|
||||
};
|
||||
|
@ -1254,14 +1187,14 @@ impl ClangItemParser for Item {
|
|||
relevant_parent_id,
|
||||
ItemKind::Type(item)),
|
||||
declaration,
|
||||
location);
|
||||
Some(location));
|
||||
Ok(id)
|
||||
}
|
||||
Err(ParseError::Continue) => Err(ParseError::Continue),
|
||||
Err(ParseError::Recurse) => {
|
||||
debug!("Item::from_ty recursing in the ast");
|
||||
let mut result = Err(ParseError::Recurse);
|
||||
if let Some(ref location) = location {
|
||||
|
||||
// Need to pop here, otherwise we'll get stuck.
|
||||
//
|
||||
// TODO: Find a nicer interface, really. Also, the
|
||||
|
@ -1277,28 +1210,24 @@ impl ClangItemParser for Item {
|
|||
});
|
||||
|
||||
if valid_decl {
|
||||
let partial_ty =
|
||||
PartialType::new(declaration_to_look_for, id);
|
||||
let partial_ty = PartialType::new(declaration_to_look_for,
|
||||
id);
|
||||
ctx.begin_parsing(partial_ty);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have recursed into the AST all we know, and we still
|
||||
// haven't found what we've got, let's just make a named type.
|
||||
// haven't found what we've got, let's just try and make a named
|
||||
// type.
|
||||
//
|
||||
// This is what happens with some template members, for example.
|
||||
//
|
||||
// FIXME: Maybe we should restrict this to things with parent?
|
||||
// It's harmless, but if we restrict that, then
|
||||
// tests/headers/nsStyleAutoArray.hpp crashes.
|
||||
if let Err(ParseError::Recurse) = result {
|
||||
warn!("Unknown type, assuming named template type: \
|
||||
id = {:?}; spelling = {}",
|
||||
id,
|
||||
ty.spelling());
|
||||
Ok(Self::named_type_with_id(id,
|
||||
ty.spelling(),
|
||||
relevant_parent_id,
|
||||
ctx))
|
||||
Item::named_type(Some(id), location, ctx)
|
||||
.map(Ok)
|
||||
.unwrap_or(Err(ParseError::Recurse))
|
||||
} else {
|
||||
result
|
||||
}
|
||||
|
@ -1316,40 +1245,161 @@ impl ClangItemParser for Item {
|
|||
/// A named type is a template parameter, e.g., the "T" in Foo<T>. They're
|
||||
/// always local so it's the only exception when there's no declaration for
|
||||
/// a type.
|
||||
///
|
||||
/// It must have an id, and must not be the current module id. Ideally we
|
||||
/// could assert the parent id is a Comp(..) type, but that info isn't
|
||||
/// available yet.
|
||||
fn named_type_with_id<S>(id: ItemId,
|
||||
name: S,
|
||||
parent_id: ItemId,
|
||||
fn named_type(with_id: Option<ItemId>,
|
||||
location: clang::Cursor,
|
||||
ctx: &mut BindgenContext)
|
||||
-> ItemId
|
||||
where S: Into<String>,
|
||||
{
|
||||
// see tests/headers/const_tparam.hpp
|
||||
// and tests/headers/variadic_tname.hpp
|
||||
let name = name.into().replace("const ", "").replace(".", "");
|
||||
-> Option<ItemId> {
|
||||
let ty = location.cur_type();
|
||||
|
||||
ctx.add_item(Item::new(id,
|
||||
None,
|
||||
None,
|
||||
parent_id,
|
||||
ItemKind::Type(Type::named(name))),
|
||||
None,
|
||||
None);
|
||||
debug!("Item::named_type:\n\
|
||||
\twith_id = {:?},\n\
|
||||
\tty = {} {:?},\n\
|
||||
\tlocation: {:?}",
|
||||
with_id,
|
||||
ty.spelling(),
|
||||
ty,
|
||||
location);
|
||||
|
||||
id
|
||||
if ty.kind() != clang_sys::CXType_Unexposed {
|
||||
// If the given cursor's type's kind is not Unexposed, then we
|
||||
// aren't looking at a template parameter. This check may need to be
|
||||
// updated in the future if they start properly exposing template
|
||||
// type parameters.
|
||||
return None;
|
||||
}
|
||||
|
||||
fn named_type<S>(name: S,
|
||||
parent_id: ItemId,
|
||||
ctx: &mut BindgenContext)
|
||||
-> ItemId
|
||||
where S: Into<String>,
|
||||
{
|
||||
let id = ctx.next_item_id();
|
||||
Self::named_type_with_id(id, name, parent_id, ctx)
|
||||
let ty_spelling = ty.spelling();
|
||||
|
||||
// Clang does not expose any information about template type parameters
|
||||
// via their clang::Type, nor does it give us their canonical cursors
|
||||
// the straightforward way. However, there are three situations from
|
||||
// which we can find the definition of the template type parameter, if
|
||||
// the cursor is indeed looking at some kind of a template type
|
||||
// parameter or use of one:
|
||||
//
|
||||
// 1. The cursor is pointing at the template type parameter's
|
||||
// definition. This is the trivial case.
|
||||
//
|
||||
// (kind = TemplateTypeParameter, ...)
|
||||
//
|
||||
// 2. The cursor is pointing at a TypeRef whose referenced() cursor is
|
||||
// situation (1).
|
||||
//
|
||||
// (kind = TypeRef,
|
||||
// referenced = (kind = TemplateTypeParameter, ...),
|
||||
// ...)
|
||||
//
|
||||
// 3. The cursor is pointing at some use of a template type parameter
|
||||
// (for example, in a FieldDecl), and this cursor has a child cursor
|
||||
// whose spelling is the same as the parent's type's spelling, and whose
|
||||
// kind is a TypeRef of the situation (2) variety.
|
||||
//
|
||||
// (kind = FieldDecl,
|
||||
// type = (kind = Unexposed,
|
||||
// spelling = "T",
|
||||
// ...),
|
||||
// children =
|
||||
// (kind = TypeRef,
|
||||
// spelling = "T",
|
||||
// referenced = (kind = TemplateTypeParameter,
|
||||
// spelling = "T",
|
||||
// ...),
|
||||
// ...)
|
||||
// ...)
|
||||
//
|
||||
// TODO: The alternative to this hacky pattern matching would be to
|
||||
// maintain proper scopes of template parameters while parsing and use
|
||||
// de Brujin indices to access template parameters, which clang exposes
|
||||
// in the cursor's type's canonical type's spelling:
|
||||
// "type-parameter-x-y". That is probably a better approach long-term,
|
||||
// but maintaining these scopes properly would require more changes to
|
||||
// the whole libclang -> IR parsing code.
|
||||
|
||||
fn is_template_with_spelling(refd: &clang::Cursor,
|
||||
spelling: &str)
|
||||
-> bool {
|
||||
lazy_static! {
|
||||
static ref ANON_TYPE_PARAM_RE: regex::Regex =
|
||||
regex::Regex::new(r"^type\-parameter\-\d+\-\d+$").unwrap();
|
||||
}
|
||||
|
||||
if refd.kind() != clang_sys::CXCursor_TemplateTypeParameter {
|
||||
return false;
|
||||
}
|
||||
|
||||
let refd_spelling = refd.spelling();
|
||||
refd_spelling == spelling ||
|
||||
// Allow for anonymous template parameters.
|
||||
(refd_spelling.is_empty() && ANON_TYPE_PARAM_RE.is_match(spelling.as_ref()))
|
||||
}
|
||||
|
||||
let definition = if is_template_with_spelling(&location,
|
||||
&ty_spelling) {
|
||||
// Situation (1)
|
||||
location
|
||||
} else if location.kind() ==
|
||||
clang_sys::CXCursor_TypeRef {
|
||||
// Situation (2)
|
||||
match location.referenced() {
|
||||
Some(refd) if is_template_with_spelling(&refd,
|
||||
&ty_spelling) => refd,
|
||||
_ => return None,
|
||||
}
|
||||
} else {
|
||||
// Situation (3)
|
||||
let mut definition = None;
|
||||
|
||||
location.visit(|child| {
|
||||
let child_ty = child.cur_type();
|
||||
if child_ty.kind() == clang_sys::CXCursor_TypeRef &&
|
||||
child_ty.spelling() == ty_spelling {
|
||||
match child.referenced() {
|
||||
Some(refd) if is_template_with_spelling(&refd, &ty_spelling) => {
|
||||
definition = Some(refd);
|
||||
return clang_sys::CXChildVisit_Break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
clang_sys::CXChildVisit_Continue
|
||||
});
|
||||
|
||||
if let Some(def) = definition {
|
||||
def
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
assert!(is_template_with_spelling(&definition, &ty_spelling));
|
||||
|
||||
// Named types are always parented to the root module. They are never
|
||||
// referenced with namespace prefixes, and they can't inherit anything
|
||||
// from their parent either, so it is simplest to just hang them off
|
||||
// something we know will always exist.
|
||||
let parent = ctx.root_module();
|
||||
|
||||
if let Some(id) = ctx.get_named_type(&definition) {
|
||||
if let Some(with_id) = with_id {
|
||||
return Some(ctx.build_ty_wrapper(with_id, id, Some(parent), &ty));
|
||||
} else {
|
||||
return Some(id);
|
||||
}
|
||||
}
|
||||
|
||||
// See tests/headers/const_tparam.hpp and
|
||||
// tests/headers/variadic_tname.hpp.
|
||||
let name = ty_spelling.replace("const ", "")
|
||||
.replace(".", "");
|
||||
|
||||
let id = with_id.unwrap_or_else(|| ctx.next_item_id());
|
||||
let item = Item::new(id,
|
||||
None,
|
||||
None,
|
||||
parent,
|
||||
ItemKind::Type(Type::named(name)));
|
||||
ctx.add_named_type(item, definition);
|
||||
Some(id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
//! Different variants of an `Item` in our intermediate representation.
|
||||
|
||||
use super::context::BindgenContext;
|
||||
use super::dot::DotAttributes;
|
||||
use super::function::Function;
|
||||
use super::module::Module;
|
||||
use super::ty::Type;
|
||||
use super::var::Var;
|
||||
use std::io;
|
||||
|
||||
/// A item we parse and translate.
|
||||
#[derive(Debug)]
|
||||
|
@ -38,7 +41,7 @@ impl ItemKind {
|
|||
ItemKind::Module(..) => "Module",
|
||||
ItemKind::Type(..) => "Type",
|
||||
ItemKind::Function(..) => "Function",
|
||||
ItemKind::Var(..) => "Var"
|
||||
ItemKind::Var(..) => "Var",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,3 +125,23 @@ impl ItemKind {
|
|||
self.as_var().expect("Not a var")
|
||||
}
|
||||
}
|
||||
|
||||
impl DotAttributes for ItemKind {
|
||||
fn dot_attributes<W>(&self,
|
||||
ctx: &BindgenContext,
|
||||
out: &mut W)
|
||||
-> io::Result<()>
|
||||
where W: io::Write,
|
||||
{
|
||||
try!(writeln!(out,
|
||||
"<tr><td>kind</td><td>{}</td></tr>",
|
||||
self.kind_name()));
|
||||
|
||||
match *self {
|
||||
ItemKind::Module(ref module) => module.dot_attributes(ctx, out),
|
||||
ItemKind::Type(ref ty) => ty.dot_attributes(ctx, out),
|
||||
ItemKind::Function(ref func) => func.dot_attributes(ctx, out),
|
||||
ItemKind::Var(ref var) => var.dot_attributes(ctx, out),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
use super::context::BindgenContext;
|
||||
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
|
||||
use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
|
||||
use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind};
|
||||
use clang;
|
||||
use std::{cmp, mem};
|
||||
|
||||
/// A type that represents the struct layout of a type.
|
||||
|
@ -20,7 +21,8 @@ pub struct Layout {
|
|||
fn test_layout_for_size() {
|
||||
let ptr_size = mem::size_of::<*mut ()>();
|
||||
assert_eq!(Layout::for_size(ptr_size), Layout::new(ptr_size, ptr_size));
|
||||
assert_eq!(Layout::for_size(3 * ptr_size), Layout::new(3 * ptr_size, ptr_size));
|
||||
assert_eq!(Layout::for_size(3 * ptr_size),
|
||||
Layout::new(3 * ptr_size, ptr_size));
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
|
@ -38,7 +40,8 @@ impl Layout {
|
|||
/// alignment possible.
|
||||
pub fn for_size(size: usize) -> Self {
|
||||
let mut next_align = 2;
|
||||
while size % next_align == 0 && next_align <= 2 * mem::size_of::<*mut ()>() {
|
||||
while size % next_align == 0 &&
|
||||
next_align <= mem::size_of::<*mut ()>() {
|
||||
next_align *= 2;
|
||||
}
|
||||
Layout {
|
||||
|
@ -65,9 +68,17 @@ impl Layout {
|
|||
}
|
||||
|
||||
/// When we are treating a type as opaque, it is just a blob with a `Layout`.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Opaque(pub Layout);
|
||||
|
||||
impl Opaque {
|
||||
/// Construct a new opaque type from the given clang type.
|
||||
pub fn from_clang_ty(ty: &clang::Type) -> Type {
|
||||
let layout = Layout::new(ty.size(), ty.align());
|
||||
let ty_kind = TypeKind::Opaque;
|
||||
Type::new(None, Some(layout), ty_kind, false)
|
||||
}
|
||||
|
||||
/// Return the known rust type we should use to create a correctly-aligned
|
||||
/// field with this layout.
|
||||
pub fn known_rust_type_for_array(&self) -> Option<&'static str> {
|
||||
|
|
|
@ -7,6 +7,7 @@ pub mod annotations;
|
|||
pub mod comp;
|
||||
pub mod context;
|
||||
pub mod derive;
|
||||
pub mod dot;
|
||||
pub mod enum_ty;
|
||||
pub mod function;
|
||||
pub mod int;
|
||||
|
@ -15,6 +16,7 @@ pub mod item_kind;
|
|||
pub mod layout;
|
||||
pub mod module;
|
||||
pub mod named;
|
||||
pub mod template;
|
||||
pub mod traversal;
|
||||
pub mod ty;
|
||||
pub mod var;
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
//! Intermediate representation for modules (AKA C++ namespaces).
|
||||
|
||||
use super::context::{BindgenContext, ItemId};
|
||||
use super::dot::DotAttributes;
|
||||
use clang;
|
||||
use parse::{ClangSubItemParser, ParseError, ParseResult};
|
||||
use parse_one;
|
||||
use std::io;
|
||||
|
||||
/// Whether this module is inline or not.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
|
@ -56,6 +58,17 @@ impl Module {
|
|||
}
|
||||
}
|
||||
|
||||
impl DotAttributes for Module {
|
||||
fn dot_attributes<W>(&self,
|
||||
_ctx: &BindgenContext,
|
||||
out: &mut W)
|
||||
-> io::Result<()>
|
||||
where W: io::Write,
|
||||
{
|
||||
writeln!(out, "<tr><td>ModuleKind</td><td>{:?}</td></tr>", self.kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl ClangSubItemParser for Module {
|
||||
fn parse(cursor: clang::Cursor,
|
||||
ctx: &mut BindgenContext)
|
||||
|
|
|
@ -76,23 +76,63 @@
|
|||
//! fixed-point.
|
||||
//!
|
||||
//! We use the "monotone framework" for this fix-point analysis where our
|
||||
//! lattice is the powerset of the template parameters that appear in the input
|
||||
//! C++ header, our join function is set union, and we use the
|
||||
//! `ir::traversal::Trace` trait to implement the work-list optimization so we
|
||||
//! don't have to revisit every node in the graph when for every iteration
|
||||
//! towards the fix-point.
|
||||
//! lattice is the mapping from each IR item to the powerset of the template
|
||||
//! parameters that appear in the input C++ header, our join function is set
|
||||
//! union, and we use the `ir::traversal::Trace` trait to implement the
|
||||
//! work-list optimization so we don't have to revisit every node in the graph
|
||||
//! when for every iteration towards the fix-point.
|
||||
//!
|
||||
//! A lattice is a set with a partial ordering between elements, where there is
|
||||
//! a single least upper bound and a single greatest least bound for every
|
||||
//! subset. We are dealing with finite lattices, which means that it has a
|
||||
//! finite number of elements, and it follows that there exists a single top and
|
||||
//! a single bottom member of the lattice. For example, the power set of a
|
||||
//! finite set forms a finite lattice where partial ordering is defined by set
|
||||
//! inclusion, that is `a <= b` if `a` is a subset of `b`. Here is the finite
|
||||
//! lattice constructed from the set {0,1,2}:
|
||||
//!
|
||||
//! ```text
|
||||
//! .----- Top = {0,1,2} -----.
|
||||
//! / | \
|
||||
//! / | \
|
||||
//! / | \
|
||||
//! {0,1} -------. {0,2} .--------- {1,2}
|
||||
//! | \ / \ / |
|
||||
//! | / \ |
|
||||
//! | / \ / \ |
|
||||
//! {0} --------' {1} `---------- {2}
|
||||
//! \ | /
|
||||
//! \ | /
|
||||
//! \ | /
|
||||
//! `------ Bottom = {} ------'
|
||||
//! ```
|
||||
//!
|
||||
//! A monotone function `f` is a function where if `x <= y`, then it holds that
|
||||
//! `f(x) <= f(y)`. It should be clear that running a monotone function to a
|
||||
//! fix-point on a finite lattice will always terminate: `f` can only "move"
|
||||
//! along the lattice in a single direction, and therefore can only either find
|
||||
//! a fix-point in the middle of the lattice or continue to the top or bottom
|
||||
//! depending if it is ascending or descending the lattice respectively.
|
||||
//!
|
||||
//! For our analysis, we are collecting the set of template parameters used by
|
||||
//! any given IR node. The set of template parameters appearing in the program
|
||||
//! is finite. Our lattice is their powerset. We start at the bottom element,
|
||||
//! the empty set. Our analysis only adds members to the set of used template
|
||||
//! parameters, never removes them, so it is monotone, and therefore iteration
|
||||
//! to a fix-point will terminate.
|
||||
//!
|
||||
//! For a deeper introduction to the general form of this kind of analysis, see
|
||||
//! [Static Program Analysis by Anders Møller and Michael I. Schwartzbach][spa].
|
||||
//!
|
||||
//! [spa]: https://cs.au.dk/~amoeller/spa/spa.pdf
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use super::context::{BindgenContext, ItemId};
|
||||
use super::item::ItemSet;
|
||||
use super::item::{Item, ItemSet};
|
||||
use super::template::{TemplateInstantiation, TemplateParameters};
|
||||
use super::traversal::{EdgeKind, Trace};
|
||||
use super::ty::{TemplateDeclaration, TypeKind};
|
||||
use super::ty::TypeKind;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt;
|
||||
|
||||
/// An analysis in the monotone framework.
|
||||
///
|
||||
|
@ -124,7 +164,7 @@ pub trait MonotoneFramework: Sized + fmt::Debug {
|
|||
/// The final output of this analysis. Once we have reached a fix-point, we
|
||||
/// convert `self` into this type, and return it as the final result of the
|
||||
/// analysis.
|
||||
type Output: From<Self>;
|
||||
type Output: From<Self> + fmt::Debug;
|
||||
|
||||
/// Construct a new instance of this analysis.
|
||||
fn new(extra: Self::Extra) -> Self;
|
||||
|
@ -152,12 +192,8 @@ pub trait MonotoneFramework: Sized + fmt::Debug {
|
|||
}
|
||||
|
||||
/// Run an analysis in the monotone framework.
|
||||
// TODO: This allow(...) is just temporary until we replace
|
||||
// `Item::signature_contains_named_type` with
|
||||
// `analyze::<UsedTemplateParameters>`.
|
||||
#[allow(dead_code)]
|
||||
pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output
|
||||
where Analysis: MonotoneFramework
|
||||
where Analysis: MonotoneFramework,
|
||||
{
|
||||
let mut analysis = Analysis::new(extra);
|
||||
let mut worklist = analysis.initial_worklist();
|
||||
|
@ -173,129 +209,453 @@ pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output
|
|||
analysis.into()
|
||||
}
|
||||
|
||||
/// An analysis that finds the set of template parameters that actually end up
|
||||
/// used in our generated bindings.
|
||||
/// An analysis that finds for each IR item its set of template parameters that
|
||||
/// it uses.
|
||||
///
|
||||
/// We use the monotone constraint function `template_param_usage`, defined as
|
||||
/// follows:
|
||||
///
|
||||
/// * If `T` is a named template type parameter, it trivially uses itself:
|
||||
///
|
||||
/// ```ignore
|
||||
/// template_param_usage(T) = { T }
|
||||
/// ```
|
||||
///
|
||||
/// * If `inst` is a template instantiation, `inst.args` are the template
|
||||
/// instantiation's template arguments, `inst.def` is the template definition
|
||||
/// being instantiated, and `inst.def.params` is the template definition's
|
||||
/// template parameters, then the instantiation's usage is the union of each
|
||||
/// of its arguments' usages *if* the corresponding template parameter is in
|
||||
/// turn used by the template definition:
|
||||
///
|
||||
/// ```ignore
|
||||
/// template_param_usage(inst) = union(
|
||||
/// template_param_usage(inst.args[i])
|
||||
/// for i in 0..length(inst.args.length)
|
||||
/// if inst.def.params[i] in template_param_usage(inst.def)
|
||||
/// )
|
||||
/// ```
|
||||
///
|
||||
/// * Finally, for all other IR item kinds, we use our lattice's `join`
|
||||
/// operation: set union with each successor of the given item's template
|
||||
/// parameter usage:
|
||||
///
|
||||
/// ```ignore
|
||||
/// template_param_usage(v) =
|
||||
/// union(template_param_usage(w) for w in successors(v))
|
||||
/// ```
|
||||
///
|
||||
/// Note that we ignore certain edges in the graph, such as edges from a
|
||||
/// template declaration to its template parameters' definitions for this
|
||||
/// analysis. If we didn't, then we would mistakenly determine that ever
|
||||
/// template parameter is always used.
|
||||
///
|
||||
/// The final wrinkle is handling of blacklisted types. Normally, we say that
|
||||
/// the set of whitelisted items is the transitive closure of items explicitly
|
||||
/// called out for whitelisting, *without* any items explicitly called out as
|
||||
/// blacklisted. However, for the purposes of this analysis's correctness, we
|
||||
/// simplify and consider run the analysis on the full transitive closure of
|
||||
/// whitelisted items. We do, however, treat instantiations of blacklisted items
|
||||
/// specially; see `constrain_instantiation_of_blacklisted_template` and its
|
||||
/// documentation for details.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UsedTemplateParameters<'a> {
|
||||
ctx: &'a BindgenContext<'a>,
|
||||
used: ItemSet,
|
||||
pub struct UsedTemplateParameters<'ctx, 'gen>
|
||||
where 'gen: 'ctx,
|
||||
{
|
||||
ctx: &'ctx BindgenContext<'gen>,
|
||||
|
||||
// The Option is only there for temporary moves out of the hash map. See the
|
||||
// comments in `UsedTemplateParameters::constrain` below.
|
||||
used: HashMap<ItemId, Option<ItemSet>>,
|
||||
|
||||
dependencies: HashMap<ItemId, Vec<ItemId>>,
|
||||
|
||||
// The set of whitelisted items, without any blacklisted items reachable
|
||||
// from the whitelisted items which would otherwise be considered
|
||||
// whitelisted as well.
|
||||
whitelisted_items: HashSet<ItemId>,
|
||||
}
|
||||
|
||||
impl<'a> MonotoneFramework for UsedTemplateParameters<'a> {
|
||||
impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> {
|
||||
fn consider_edge(kind: EdgeKind) -> bool {
|
||||
match kind {
|
||||
// For each of these kinds of edges, if the referent uses a template
|
||||
// parameter, then it should be considered that the origin of the
|
||||
// edge also uses the template parameter.
|
||||
EdgeKind::TemplateArgument |
|
||||
EdgeKind::BaseMember |
|
||||
EdgeKind::Field |
|
||||
EdgeKind::Constructor |
|
||||
EdgeKind::VarType |
|
||||
EdgeKind::FunctionReturn |
|
||||
EdgeKind::FunctionParameter |
|
||||
EdgeKind::TypeReference => true,
|
||||
|
||||
// An inner var or type using a template parameter is orthogonal
|
||||
// from whether we use it. See template-param-usage-{6,11}.hpp.
|
||||
EdgeKind::InnerVar | EdgeKind::InnerType => false,
|
||||
|
||||
// We can't emit machine code for new monomorphizations of class
|
||||
// templates' methods (and don't detect explicit instantiations) so
|
||||
// we must ignore template parameters that are only used by
|
||||
// methods. This doesn't apply to a function type's return or
|
||||
// parameter types, however, because of type aliases of function
|
||||
// pointers that use template parameters, eg
|
||||
// tests/headers/struct_with_typedef_template_arg.hpp
|
||||
EdgeKind::Method => false,
|
||||
|
||||
// If we considered these edges, we would end up mistakenly claiming
|
||||
// that every template parameter always used.
|
||||
EdgeKind::TemplateDeclaration |
|
||||
EdgeKind::TemplateParameterDefinition => false,
|
||||
|
||||
// Since we have to be careful about which edges we consider for
|
||||
// this analysis to be correct, we ignore generic edges. We also
|
||||
// avoid a `_` wild card to force authors of new edge kinds to
|
||||
// determine whether they need to be considered by this analysis.
|
||||
EdgeKind::Generic => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn take_this_id_usage_set(&mut self, this_id: ItemId) -> ItemSet {
|
||||
self.used
|
||||
.get_mut(&this_id)
|
||||
.expect("Should have a set of used template params for every item \
|
||||
id")
|
||||
.take()
|
||||
.expect("Should maintain the invariant that all used template param \
|
||||
sets are `Some` upon entry of `constrain`")
|
||||
}
|
||||
|
||||
/// We say that blacklisted items use all of their template parameters. The
|
||||
/// blacklisted type is most likely implemented explicitly by the user,
|
||||
/// since it won't be in the generated bindings, and we don't know exactly
|
||||
/// what they'll to with template parameters, but we can push the issue down
|
||||
/// the line to them.
|
||||
fn constrain_instantiation_of_blacklisted_template(&self,
|
||||
this_id: ItemId,
|
||||
used_by_this_id: &mut ItemSet,
|
||||
instantiation: &TemplateInstantiation) {
|
||||
trace!(" instantiation of blacklisted template, uses all template \
|
||||
arguments");
|
||||
|
||||
let args = instantiation.template_arguments()
|
||||
.into_iter()
|
||||
.map(|a| {
|
||||
a.into_resolver()
|
||||
.through_type_refs()
|
||||
.through_type_aliases()
|
||||
.resolve(self.ctx)
|
||||
.id()
|
||||
})
|
||||
.filter(|a| *a != this_id)
|
||||
.flat_map(|a| {
|
||||
self.used.get(&a)
|
||||
.expect("Should have a used entry for the template arg")
|
||||
.as_ref()
|
||||
.expect("Because a != this_id, and all used template \
|
||||
param sets other than this_id's are `Some`, \
|
||||
a's used template param set should be `Some`")
|
||||
.iter()
|
||||
.cloned()
|
||||
});
|
||||
|
||||
used_by_this_id.extend(args);
|
||||
}
|
||||
|
||||
/// A template instantiation's concrete template argument is only used if
|
||||
/// the template definition uses the corresponding template parameter.
|
||||
fn constrain_instantiation(&self,
|
||||
this_id: ItemId,
|
||||
used_by_this_id: &mut ItemSet,
|
||||
instantiation: &TemplateInstantiation) {
|
||||
trace!(" template instantiation");
|
||||
|
||||
let decl = self.ctx.resolve_type(instantiation.template_definition());
|
||||
let args = instantiation.template_arguments();
|
||||
|
||||
let params = decl.self_template_params(self.ctx)
|
||||
.unwrap_or(vec![]);
|
||||
|
||||
debug_assert!(this_id != instantiation.template_definition());
|
||||
let used_by_def = self.used
|
||||
.get(&instantiation.template_definition())
|
||||
.expect("Should have a used entry for instantiation's template definition")
|
||||
.as_ref()
|
||||
.expect("And it should be Some because only this_id's set is None, and an \
|
||||
instantiation's template definition should never be the \
|
||||
instantiation itself");
|
||||
|
||||
for (arg, param) in args.iter().zip(params.iter()) {
|
||||
trace!(" instantiation's argument {:?} is used if definition's \
|
||||
parameter {:?} is used",
|
||||
arg,
|
||||
param);
|
||||
|
||||
if used_by_def.contains(param) {
|
||||
trace!(" param is used by template definition");
|
||||
|
||||
let arg = arg.into_resolver()
|
||||
.through_type_refs()
|
||||
.through_type_aliases()
|
||||
.resolve(self.ctx)
|
||||
.id();
|
||||
|
||||
if arg == this_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
let used_by_arg = self.used
|
||||
.get(&arg)
|
||||
.expect("Should have a used entry for the template arg")
|
||||
.as_ref()
|
||||
.expect("Because arg != this_id, and all used template \
|
||||
param sets other than this_id's are `Some`, \
|
||||
arg's used template param set should be \
|
||||
`Some`")
|
||||
.iter()
|
||||
.cloned();
|
||||
used_by_this_id.extend(used_by_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The join operation on our lattice: the set union of all of this id's
|
||||
/// successors.
|
||||
fn constrain_join(&self, used_by_this_id: &mut ItemSet, item: &Item) {
|
||||
trace!(" other item: join with successors' usage");
|
||||
|
||||
item.trace(self.ctx, &mut |sub_id, edge_kind| {
|
||||
// Ignore ourselves, since union with ourself is a
|
||||
// no-op. Ignore edges that aren't relevant to the
|
||||
// analysis.
|
||||
if sub_id == item.id() || !Self::consider_edge(edge_kind) {
|
||||
return;
|
||||
}
|
||||
|
||||
let used_by_sub_id = self.used
|
||||
.get(&sub_id)
|
||||
.expect("Should have a used set for the sub_id successor")
|
||||
.as_ref()
|
||||
.expect("Because sub_id != id, and all used template \
|
||||
param sets other than id's are `Some`, \
|
||||
sub_id's used template param set should be \
|
||||
`Some`")
|
||||
.iter()
|
||||
.cloned();
|
||||
|
||||
trace!(" union with {:?}'s usage: {:?}",
|
||||
sub_id,
|
||||
used_by_sub_id.clone().collect::<Vec<_>>());
|
||||
|
||||
used_by_this_id.extend(used_by_sub_id);
|
||||
}, &());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
|
||||
type Node = ItemId;
|
||||
type Extra = &'a BindgenContext<'a>;
|
||||
type Output = ItemSet;
|
||||
type Extra = &'ctx BindgenContext<'gen>;
|
||||
type Output = HashMap<ItemId, ItemSet>;
|
||||
|
||||
fn new(ctx: &'a BindgenContext<'a>) -> UsedTemplateParameters<'a> {
|
||||
fn new(ctx: &'ctx BindgenContext<'gen>)
|
||||
-> UsedTemplateParameters<'ctx, 'gen> {
|
||||
let mut used = HashMap::new();
|
||||
let mut dependencies = HashMap::new();
|
||||
let whitelisted_items: HashSet<_> = ctx.whitelisted_items().collect();
|
||||
|
||||
let whitelisted_and_blacklisted_items: ItemSet = whitelisted_items.iter()
|
||||
.cloned()
|
||||
.flat_map(|i| {
|
||||
let mut reachable = vec![i];
|
||||
i.trace(ctx, &mut |s, _| {
|
||||
reachable.push(s);
|
||||
}, &());
|
||||
reachable
|
||||
})
|
||||
.collect();
|
||||
|
||||
for item in whitelisted_and_blacklisted_items {
|
||||
dependencies.entry(item).or_insert(vec![]);
|
||||
used.entry(item).or_insert(Some(ItemSet::new()));
|
||||
|
||||
for item in ctx.whitelisted_items() {
|
||||
{
|
||||
// We reverse our natural IR graph edges to find dependencies
|
||||
// between nodes.
|
||||
let mut add_reverse_edge = |sub_item, _| {
|
||||
dependencies.entry(sub_item).or_insert(vec![]).push(item);
|
||||
};
|
||||
item.trace(ctx, &mut add_reverse_edge, &());
|
||||
item.trace(ctx, &mut |sub_item: ItemId, _| {
|
||||
used.entry(sub_item).or_insert(Some(ItemSet::new()));
|
||||
dependencies.entry(sub_item)
|
||||
.or_insert(vec![])
|
||||
.push(item);
|
||||
}, &());
|
||||
}
|
||||
|
||||
// Additionally, whether a template instantiation's template
|
||||
// arguments are used depends on whether the template declaration's
|
||||
// generic template parameters are used.
|
||||
ctx.resolve_item_fallible(item)
|
||||
.and_then(|item| item.as_type())
|
||||
ctx.resolve_item(item)
|
||||
.as_type()
|
||||
.map(|ty| match ty.kind() {
|
||||
&TypeKind::TemplateInstantiation(decl, ref args) => {
|
||||
let decl = ctx.resolve_type(decl);
|
||||
let params = decl.template_params(ctx)
|
||||
.expect("a template instantiation's referenced \
|
||||
template declaration should have template \
|
||||
parameters");
|
||||
&TypeKind::TemplateInstantiation(ref inst) => {
|
||||
let decl = ctx.resolve_type(inst.template_definition());
|
||||
let args = inst.template_arguments();
|
||||
|
||||
// Although template definitions should always have
|
||||
// template parameters, there is a single exception:
|
||||
// opaque templates. Hence the unwrap_or.
|
||||
let params = decl.self_template_params(ctx)
|
||||
.unwrap_or(vec![]);
|
||||
|
||||
for (arg, param) in args.iter().zip(params.iter()) {
|
||||
dependencies.entry(*arg).or_insert(vec![]).push(*param);
|
||||
let arg = arg.into_resolver()
|
||||
.through_type_aliases()
|
||||
.through_type_refs()
|
||||
.resolve(ctx)
|
||||
.id();
|
||||
|
||||
let param = param.into_resolver()
|
||||
.through_type_aliases()
|
||||
.through_type_refs()
|
||||
.resolve(ctx)
|
||||
.id();
|
||||
|
||||
used.entry(arg).or_insert(Some(ItemSet::new()));
|
||||
used.entry(param).or_insert(Some(ItemSet::new()));
|
||||
|
||||
dependencies.entry(arg)
|
||||
.or_insert(vec![])
|
||||
.push(param);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
|
||||
if cfg!(feature = "testing_only_extra_assertions") {
|
||||
// Invariant: The `used` map has an entry for every whitelisted
|
||||
// item, as well as all explicitly blacklisted items that are
|
||||
// reachable from whitelisted items.
|
||||
//
|
||||
// Invariant: the `dependencies` map has an entry for every
|
||||
// whitelisted item.
|
||||
//
|
||||
// (This is so that every item we call `constrain` on is guaranteed
|
||||
// to have a set of template parameters, and we can allow
|
||||
// blacklisted templates to use all of their parameters).
|
||||
for item in whitelisted_items.iter() {
|
||||
extra_assert!(used.contains_key(item));
|
||||
extra_assert!(dependencies.contains_key(item));
|
||||
item.trace(ctx, &mut |sub_item, _| {
|
||||
extra_assert!(used.contains_key(&sub_item));
|
||||
extra_assert!(dependencies.contains_key(&sub_item));
|
||||
}, &())
|
||||
}
|
||||
}
|
||||
|
||||
UsedTemplateParameters {
|
||||
ctx: ctx,
|
||||
used: ItemSet::new(),
|
||||
used: used,
|
||||
dependencies: dependencies,
|
||||
whitelisted_items: whitelisted_items,
|
||||
}
|
||||
}
|
||||
|
||||
fn initial_worklist(&self) -> Vec<Self::Node> {
|
||||
self.ctx.whitelisted_items().collect()
|
||||
}
|
||||
|
||||
fn constrain(&mut self, item: ItemId) -> bool {
|
||||
let original_size = self.used.len();
|
||||
|
||||
item.trace(self.ctx, &mut |item, edge_kind| {
|
||||
if edge_kind == EdgeKind::TemplateParameterDefinition {
|
||||
// The definition of a template parameter is not considered a
|
||||
// use of said template parameter. Ignore this edge.
|
||||
return;
|
||||
}
|
||||
|
||||
let ty_kind = self.ctx.resolve_item(item)
|
||||
.as_type()
|
||||
.map(|ty| ty.kind());
|
||||
|
||||
match ty_kind {
|
||||
Some(&TypeKind::Named) => {
|
||||
// This is a "trivial" use of the template type parameter.
|
||||
self.used.insert(item);
|
||||
},
|
||||
Some(&TypeKind::TemplateInstantiation(decl, ref args)) => {
|
||||
// A template instantiation's concrete template argument is
|
||||
// only used if the template declaration uses the
|
||||
// corresponding template parameter.
|
||||
let decl = self.ctx.resolve_type(decl);
|
||||
let params = decl.template_params(self.ctx)
|
||||
.expect("a template instantiation's referenced \
|
||||
template declaration should have template \
|
||||
parameters");
|
||||
for (arg, param) in args.iter().zip(params.iter()) {
|
||||
if self.used.contains(param) {
|
||||
if self.ctx.resolve_item(*arg).is_named() {
|
||||
self.used.insert(*arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => return,
|
||||
}
|
||||
fn initial_worklist(&self) -> Vec<ItemId> {
|
||||
// The transitive closure of all whitelisted items, including explicitly
|
||||
// blacklisted items.
|
||||
self.ctx
|
||||
.whitelisted_items()
|
||||
.flat_map(|i| {
|
||||
let mut reachable = vec![i];
|
||||
i.trace(self.ctx, &mut |s, _| {
|
||||
reachable.push(s);
|
||||
}, &());
|
||||
reachable
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
let new_size = self.used.len();
|
||||
new_size != original_size
|
||||
fn constrain(&mut self, id: ItemId) -> bool {
|
||||
// Invariant: all hash map entries' values are `Some` upon entering and
|
||||
// exiting this method.
|
||||
extra_assert!(self.used.values().all(|v| v.is_some()));
|
||||
|
||||
// Take the set for this id out of the hash map while we mutate it based
|
||||
// on other hash map entries. We *must* put it back into the hash map at
|
||||
// the end of this method. This allows us to side-step HashMap's lack of
|
||||
// an analog to slice::split_at_mut.
|
||||
let mut used_by_this_id = self.take_this_id_usage_set(id);
|
||||
|
||||
trace!("constrain {:?}", id);
|
||||
trace!(" initially, used set is {:?}", used_by_this_id);
|
||||
|
||||
let original_len = used_by_this_id.len();
|
||||
|
||||
let item = self.ctx.resolve_item(id);
|
||||
let ty_kind = item.as_type().map(|ty| ty.kind());
|
||||
match ty_kind {
|
||||
// Named template type parameters trivially use themselves.
|
||||
Some(&TypeKind::Named) => {
|
||||
trace!(" named type, trivially uses itself");
|
||||
used_by_this_id.insert(id);
|
||||
}
|
||||
// Template instantiations only use their template arguments if the
|
||||
// template definition uses the corresponding template parameter.
|
||||
Some(&TypeKind::TemplateInstantiation(ref inst)) => {
|
||||
if self.whitelisted_items.contains(&inst.template_definition()) {
|
||||
self.constrain_instantiation(id, &mut used_by_this_id, inst);
|
||||
} else {
|
||||
self.constrain_instantiation_of_blacklisted_template(id,
|
||||
&mut used_by_this_id,
|
||||
inst);
|
||||
}
|
||||
}
|
||||
// Otherwise, add the union of each of its referent item's template
|
||||
// parameter usage.
|
||||
_ => self.constrain_join(&mut used_by_this_id, item),
|
||||
}
|
||||
|
||||
trace!(" finally, used set is {:?}", used_by_this_id);
|
||||
|
||||
let new_len = used_by_this_id.len();
|
||||
assert!(new_len >= original_len,
|
||||
"This is the property that ensures this function is monotone -- \
|
||||
if it doesn't hold, the analysis might never terminate!");
|
||||
|
||||
// Put the set back in the hash map and restore our invariant.
|
||||
debug_assert!(self.used[&id].is_none());
|
||||
self.used.insert(id, Some(used_by_this_id));
|
||||
extra_assert!(self.used.values().all(|v| v.is_some()));
|
||||
|
||||
new_len != original_len
|
||||
}
|
||||
|
||||
fn each_depending_on<F>(&self, item: ItemId, mut f: F)
|
||||
where F: FnMut(Self::Node)
|
||||
where F: FnMut(ItemId),
|
||||
{
|
||||
if let Some(edges) = self.dependencies.get(&item) {
|
||||
for item in edges {
|
||||
trace!("enqueue {:?} into worklist", item);
|
||||
f(*item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<UsedTemplateParameters<'a>> for ItemSet {
|
||||
fn from(used_templ_params: UsedTemplateParameters) -> ItemSet {
|
||||
impl<'ctx, 'gen> From<UsedTemplateParameters<'ctx, 'gen>>
|
||||
for HashMap<ItemId, ItemSet> {
|
||||
fn from(used_templ_params: UsedTemplateParameters<'ctx, 'gen>) -> Self {
|
||||
used_templ_params.used
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, v.unwrap()))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use super::*;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
// Here we find the set of nodes that are reachable from any given
|
||||
// node. This is a lattice mapping nodes to subsets of all nodes. Our join
|
||||
|
@ -409,7 +769,8 @@ mod tests {
|
|||
// Yes, what follows is a **terribly** inefficient set union
|
||||
// implementation. Don't copy this code outside of this test!
|
||||
|
||||
let original_size = self.reachable.entry(node).or_insert(HashSet::new()).len();
|
||||
let original_size =
|
||||
self.reachable.entry(node).or_insert(HashSet::new()).len();
|
||||
|
||||
for sub_node in self.graph.0[&node].iter() {
|
||||
self.reachable.get_mut(&node).unwrap().insert(*sub_node);
|
||||
|
@ -429,7 +790,7 @@ mod tests {
|
|||
}
|
||||
|
||||
fn each_depending_on<F>(&self, node: Node, mut f: F)
|
||||
where F: FnMut(Node)
|
||||
where F: FnMut(Node),
|
||||
{
|
||||
for dep in self.reversed.0[&node].iter() {
|
||||
f(*dep);
|
||||
|
@ -450,7 +811,7 @@ mod tests {
|
|||
println!("reachable = {:#?}", reachable);
|
||||
|
||||
fn nodes<A>(nodes: A) -> HashSet<Node>
|
||||
where A: AsRef<[usize]>
|
||||
where A: AsRef<[usize]>,
|
||||
{
|
||||
nodes.as_ref().iter().cloned().map(Node).collect()
|
||||
}
|
||||
|
|
|
@ -1,27 +1,42 @@
|
|||
//! Objective C types
|
||||
|
||||
use super::context::BindgenContext;
|
||||
use super::context::{BindgenContext, ItemId};
|
||||
use super::function::FunctionSig;
|
||||
use super::traversal::{Trace, Tracer};
|
||||
use super::ty::TypeKind;
|
||||
use clang;
|
||||
use clang_sys::CXChildVisit_Continue;
|
||||
use clang_sys::CXCursor_ObjCCategoryDecl;
|
||||
use clang_sys::CXCursor_ObjCClassMethodDecl;
|
||||
use clang_sys::CXCursor_ObjCClassRef;
|
||||
use clang_sys::CXCursor_ObjCInstanceMethodDecl;
|
||||
use clang_sys::CXCursor_ObjCProtocolDecl;
|
||||
use clang_sys::CXCursor_ObjCProtocolRef;
|
||||
|
||||
/// Objective C interface as used in TypeKind
|
||||
///
|
||||
/// Also protocols are parsed as this type
|
||||
/// Also protocols and categories are parsed as this type
|
||||
#[derive(Debug)]
|
||||
pub struct ObjCInterface {
|
||||
/// The name
|
||||
/// like, NSObject
|
||||
name: String,
|
||||
|
||||
category: Option<String>,
|
||||
|
||||
is_protocol: bool,
|
||||
|
||||
conforms_to: Vec<ItemId>,
|
||||
|
||||
/// List of the methods defined in this interfae
|
||||
methods: Vec<ObjCInstanceMethod>,
|
||||
methods: Vec<ObjCMethod>,
|
||||
|
||||
class_methods: Vec<ObjCMethod>,
|
||||
}
|
||||
|
||||
/// The objective c methods
|
||||
#[derive(Debug)]
|
||||
pub struct ObjCInstanceMethod {
|
||||
pub struct ObjCMethod {
|
||||
/// The original method selector name
|
||||
/// like, dataWithBytes:length:
|
||||
name: String,
|
||||
|
@ -31,13 +46,20 @@ pub struct ObjCInstanceMethod {
|
|||
rust_name: String,
|
||||
|
||||
signature: FunctionSig,
|
||||
|
||||
/// Is class method?
|
||||
is_class_method: bool,
|
||||
}
|
||||
|
||||
impl ObjCInterface {
|
||||
fn new(name: &str) -> ObjCInterface {
|
||||
ObjCInterface {
|
||||
name: name.to_owned(),
|
||||
category: None,
|
||||
is_protocol: false,
|
||||
conforms_to: Vec::new(),
|
||||
methods: Vec::new(),
|
||||
class_methods: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,11 +69,31 @@ impl ObjCInterface {
|
|||
self.name.as_ref()
|
||||
}
|
||||
|
||||
/// List of the methods defined in this interfae
|
||||
pub fn methods(&self) -> &Vec<ObjCInstanceMethod> {
|
||||
/// Formats the name for rust
|
||||
/// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods
|
||||
/// and protocols are like protocol_NSObject
|
||||
pub fn rust_name(&self) -> String {
|
||||
if let Some(ref cat) = self.category {
|
||||
format!("{}_{}", self.name(), cat)
|
||||
} else {
|
||||
if self.is_protocol {
|
||||
format!("protocol_{}", self.name())
|
||||
} else {
|
||||
self.name().to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// List of the methods defined in this interface
|
||||
pub fn methods(&self) -> &Vec<ObjCMethod> {
|
||||
&self.methods
|
||||
}
|
||||
|
||||
/// List of the class methods defined in this interface
|
||||
pub fn class_methods(&self) -> &Vec<ObjCMethod> {
|
||||
&self.class_methods
|
||||
}
|
||||
|
||||
/// Parses the Objective C interface from the cursor
|
||||
pub fn from_ty(cursor: &clang::Cursor,
|
||||
ctx: &mut BindgenContext)
|
||||
|
@ -59,16 +101,57 @@ impl ObjCInterface {
|
|||
let name = cursor.spelling();
|
||||
let mut interface = Self::new(&name);
|
||||
|
||||
cursor.visit(|cursor| {
|
||||
match cursor.kind() {
|
||||
CXCursor_ObjCInstanceMethodDecl => {
|
||||
let name = cursor.spelling();
|
||||
let signature =
|
||||
FunctionSig::from_ty(&cursor.cur_type(), &cursor, ctx)
|
||||
.expect("Invalid function sig");
|
||||
let method = ObjCInstanceMethod::new(&name, signature);
|
||||
if cursor.kind() == CXCursor_ObjCProtocolDecl {
|
||||
interface.is_protocol = true;
|
||||
}
|
||||
|
||||
interface.methods.push(method);
|
||||
cursor.visit(|c| {
|
||||
match c.kind() {
|
||||
CXCursor_ObjCClassRef => {
|
||||
if cursor.kind() == CXCursor_ObjCCategoryDecl {
|
||||
// We are actually a category extension, and we found the reference
|
||||
// to the original interface, so name this interface approriately
|
||||
interface.name = c.spelling();
|
||||
interface.category = Some(cursor.spelling());
|
||||
}
|
||||
}
|
||||
CXCursor_ObjCProtocolRef => {
|
||||
// Gather protocols this interface conforms to
|
||||
let needle = format!("protocol_{}", c.spelling());
|
||||
let items_map = ctx.items();
|
||||
debug!("Interface {} conforms to {}, find the item", interface.name, needle);
|
||||
|
||||
for (id, item) in items_map
|
||||
{
|
||||
if let Some(ty) = item.as_type() {
|
||||
match *ty.kind() {
|
||||
TypeKind::ObjCInterface(ref protocol) => {
|
||||
if protocol.is_protocol
|
||||
{
|
||||
debug!("Checking protocol {}, ty.name {:?}", protocol.name, ty.name());
|
||||
if Some(needle.as_ref()) == ty.name()
|
||||
{
|
||||
debug!("Found conforming protocol {:?}", item);
|
||||
interface.conforms_to.push(*id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
CXCursor_ObjCInstanceMethodDecl |
|
||||
CXCursor_ObjCClassMethodDecl => {
|
||||
let name = c.spelling();
|
||||
let signature =
|
||||
FunctionSig::from_ty(&c.cur_type(), &c, ctx)
|
||||
.expect("Invalid function sig");
|
||||
let is_class_method = c.kind() == CXCursor_ObjCClassMethodDecl;
|
||||
let method = ObjCMethod::new(&name, signature, is_class_method);
|
||||
interface.add_method(method);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -76,18 +159,30 @@ impl ObjCInterface {
|
|||
});
|
||||
Some(interface)
|
||||
}
|
||||
|
||||
fn add_method(&mut self, method: ObjCMethod) {
|
||||
if method.is_class_method {
|
||||
self.class_methods.push(method);
|
||||
} else {
|
||||
self.methods.push(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjCInstanceMethod {
|
||||
fn new(name: &str, signature: FunctionSig) -> ObjCInstanceMethod {
|
||||
impl ObjCMethod {
|
||||
fn new(name: &str,
|
||||
signature: FunctionSig,
|
||||
is_class_method: bool)
|
||||
-> ObjCMethod {
|
||||
let split_name: Vec<&str> = name.split(':').collect();
|
||||
|
||||
let rust_name = split_name.join("_");
|
||||
|
||||
ObjCInstanceMethod {
|
||||
ObjCMethod {
|
||||
name: name.to_owned(),
|
||||
rust_name: rust_name.to_owned(),
|
||||
signature: signature,
|
||||
is_class_method: is_class_method,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,6 +203,11 @@ impl ObjCInstanceMethod {
|
|||
&self.signature
|
||||
}
|
||||
|
||||
/// Is this a class method?
|
||||
pub fn is_class_method(&self) -> bool {
|
||||
self.is_class_method
|
||||
}
|
||||
|
||||
/// Formats the method call
|
||||
pub fn format_method_call(&self, args: &[String]) -> String {
|
||||
let split_name: Vec<&str> =
|
||||
|
@ -132,3 +232,23 @@ impl ObjCInstanceMethod {
|
|||
.join("")
|
||||
}
|
||||
}
|
||||
|
||||
impl Trace for ObjCInterface {
|
||||
type Extra = ();
|
||||
|
||||
fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, _: &())
|
||||
where T: Tracer,
|
||||
{
|
||||
for method in &self.methods {
|
||||
method.signature.trace(context, tracer, &());
|
||||
}
|
||||
|
||||
for class_method in &self.class_methods {
|
||||
class_method.signature.trace(context, tracer, &());
|
||||
}
|
||||
|
||||
for protocol in &self.conforms_to {
|
||||
tracer.visit(*protocol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,343 @@
|
|||
//! Template declaration and instantiation related things.
|
||||
//!
|
||||
//! The nomenclature surrounding templates is often confusing, so here are a few
|
||||
//! brief definitions:
|
||||
//!
|
||||
//! * "Template definition": a class/struct/alias/function definition that takes
|
||||
//! generic template parameters. For example:
|
||||
//!
|
||||
//! ```c++
|
||||
//! template<typename T>
|
||||
//! class List<T> {
|
||||
//! // ...
|
||||
//! };
|
||||
//! ```
|
||||
//!
|
||||
//! * "Template instantiation": an instantiation is a use of a template with
|
||||
//! concrete template arguments. For example, `List<int>`.
|
||||
//!
|
||||
//! * "Template specialization": an alternative template definition providing a
|
||||
//! custom definition for instantiations with the matching template
|
||||
//! arguments. This C++ feature is unsupported by bindgen. For example:
|
||||
//!
|
||||
//! ```c++
|
||||
//! template<>
|
||||
//! class List<int> {
|
||||
//! // Special layout for int lists...
|
||||
//! };
|
||||
//! ```
|
||||
|
||||
use super::context::{BindgenContext, ItemId};
|
||||
use super::derive::{CanDeriveCopy, CanDeriveDebug};
|
||||
use super::item::{Item, ItemAncestors};
|
||||
use super::layout::Layout;
|
||||
use super::traversal::{EdgeKind, Trace, Tracer};
|
||||
use clang;
|
||||
use parse::ClangItemParser;
|
||||
|
||||
/// Template declaration (and such declaration's template parameters) related
|
||||
/// methods.
|
||||
///
|
||||
/// This trait's methods distinguish between `None` and `Some([])` for
|
||||
/// declarations that are not templates and template declarations with zero
|
||||
/// parameters, in general.
|
||||
///
|
||||
/// Consider this example:
|
||||
///
|
||||
/// ```c++
|
||||
/// template <typename T, typename U>
|
||||
/// class Foo {
|
||||
/// T use_of_t;
|
||||
/// U use_of_u;
|
||||
///
|
||||
/// template <typename V>
|
||||
/// using Bar = V*;
|
||||
///
|
||||
/// class Inner {
|
||||
/// T x;
|
||||
/// U y;
|
||||
/// Bar<int> z;
|
||||
/// };
|
||||
///
|
||||
/// template <typename W>
|
||||
/// class Lol {
|
||||
/// // No use of W, but here's a use of T.
|
||||
/// T t;
|
||||
/// };
|
||||
///
|
||||
/// template <typename X>
|
||||
/// class Wtf {
|
||||
/// // X is not used because W is not used.
|
||||
/// Lol<X> lololol;
|
||||
/// };
|
||||
/// };
|
||||
///
|
||||
/// class Qux {
|
||||
/// int y;
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// The following table depicts the results of each trait method when invoked on
|
||||
/// each of the declarations above:
|
||||
///
|
||||
/// +------+----------------------+--------------------------+------------------------+----
|
||||
/// |Decl. | self_template_params | num_self_template_params | all_template_parameters| ...
|
||||
/// +------+----------------------+--------------------------+------------------------+----
|
||||
/// |Foo | Some([T, U]) | Some(2) | Some([T, U]) | ...
|
||||
/// |Bar | Some([V]) | Some(1) | Some([T, U, V]) | ...
|
||||
/// |Inner | None | None | Some([T, U]) | ...
|
||||
/// |Lol | Some([W]) | Some(1) | Some([T, U, W]) | ...
|
||||
/// |Wtf | Some([X]) | Some(1) | Some([T, U, X]) | ...
|
||||
/// |Qux | None | None | None | ...
|
||||
/// +------+----------------------+--------------------------+------------------------+----
|
||||
///
|
||||
/// ----+------+-----+----------------------+
|
||||
/// ... |Decl. | ... | used_template_params |
|
||||
/// ----+------+-----+----------------------+
|
||||
/// ... |Foo | ... | Some([T, U]) |
|
||||
/// ... |Bar | ... | Some([V]) |
|
||||
/// ... |Inner | ... | None |
|
||||
/// ... |Lol | ... | Some([T]) |
|
||||
/// ... |Wtf | ... | Some([T]) |
|
||||
/// ... |Qux | ... | None |
|
||||
/// ----+------+-----+----------------------+
|
||||
pub trait TemplateParameters {
|
||||
/// Get the set of `ItemId`s that make up this template declaration's free
|
||||
/// template parameters.
|
||||
///
|
||||
/// Note that these might *not* all be named types: C++ allows
|
||||
/// constant-value template parameters as well as template-template
|
||||
/// parameters. Of course, Rust does not allow generic parameters to be
|
||||
/// anything but types, so we must treat them as opaque, and avoid
|
||||
/// instantiating them.
|
||||
fn self_template_params(&self,
|
||||
ctx: &BindgenContext)
|
||||
-> Option<Vec<ItemId>>;
|
||||
|
||||
/// Get the number of free template parameters this template declaration
|
||||
/// has.
|
||||
///
|
||||
/// Implementations *may* return `Some` from this method when
|
||||
/// `template_params` returns `None`. This is useful when we only have
|
||||
/// partial information about the template declaration, such as when we are
|
||||
/// in the middle of parsing it.
|
||||
fn num_self_template_params(&self, ctx: &BindgenContext) -> Option<usize> {
|
||||
self.self_template_params(ctx).map(|params| params.len())
|
||||
}
|
||||
|
||||
/// Get the complete set of template parameters that can affect this
|
||||
/// declaration.
|
||||
///
|
||||
/// Note that this item doesn't need to be a template declaration itself for
|
||||
/// `Some` to be returned here (in contrast to `self_template_params`). If
|
||||
/// this item is a member of a template declaration, then the parent's
|
||||
/// template parameters are included here.
|
||||
///
|
||||
/// In the example above, `Inner` depends on both of the `T` and `U` type
|
||||
/// parameters, even though it is not itself a template declaration and
|
||||
/// therefore has no type parameters itself. Perhaps it helps to think about
|
||||
/// how we would fully reference such a member type in C++:
|
||||
/// `Foo<int,char>::Inner`. `Foo` *must* be instantiated with template
|
||||
/// arguments before we can gain access to the `Inner` member type.
|
||||
fn all_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
|
||||
where Self: ItemAncestors,
|
||||
{
|
||||
let each_self_params: Vec<Vec<_>> = self.ancestors(ctx)
|
||||
.filter_map(|id| id.self_template_params(ctx))
|
||||
.collect();
|
||||
if each_self_params.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(each_self_params.into_iter()
|
||||
.rev()
|
||||
.flat_map(|params| params)
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
/// Get only the set of template parameters that this item uses. This is a
|
||||
/// subset of `all_template_params` and does not necessarily contain any of
|
||||
/// `self_template_params`.
|
||||
fn used_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
|
||||
where Self: AsRef<ItemId>,
|
||||
{
|
||||
assert!(ctx.in_codegen_phase(),
|
||||
"template parameter usage is not computed until codegen");
|
||||
|
||||
let id = *self.as_ref();
|
||||
ctx.resolve_item(id)
|
||||
.all_template_params(ctx)
|
||||
.map(|all_params| {
|
||||
all_params.into_iter()
|
||||
.filter(|p| ctx.uses_template_parameter(id, *p))
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for things which may or may not be a named template type parameter.
|
||||
pub trait AsNamed {
|
||||
/// Any extra information the implementor might need to make this decision.
|
||||
type Extra;
|
||||
|
||||
/// Convert this thing to the item id of a named template type parameter.
|
||||
fn as_named(&self,
|
||||
ctx: &BindgenContext,
|
||||
extra: &Self::Extra)
|
||||
-> Option<ItemId>;
|
||||
|
||||
/// Is this a named template type parameter?
|
||||
fn is_named(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool {
|
||||
self.as_named(ctx, extra).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
/// A concrete instantiation of a generic template.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TemplateInstantiation {
|
||||
/// The template definition which this is instantiating.
|
||||
definition: ItemId,
|
||||
/// The concrete template arguments, which will be substituted in the
|
||||
/// definition for the generic template parameters.
|
||||
args: Vec<ItemId>,
|
||||
}
|
||||
|
||||
impl TemplateInstantiation {
|
||||
/// Construct a new template instantiation from the given parts.
|
||||
pub fn new<I>(template_definition: ItemId,
|
||||
template_args: I)
|
||||
-> TemplateInstantiation
|
||||
where I: IntoIterator<Item = ItemId>,
|
||||
{
|
||||
TemplateInstantiation {
|
||||
definition: template_definition,
|
||||
args: template_args.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the template definition for this instantiation.
|
||||
pub fn template_definition(&self) -> ItemId {
|
||||
self.definition
|
||||
}
|
||||
|
||||
/// Get the concrete template arguments used in this instantiation.
|
||||
pub fn template_arguments(&self) -> &[ItemId] {
|
||||
&self.args[..]
|
||||
}
|
||||
|
||||
/// Parse a `TemplateInstantiation` from a clang `Type`.
|
||||
pub fn from_ty(ty: &clang::Type,
|
||||
ctx: &mut BindgenContext)
|
||||
-> Option<TemplateInstantiation> {
|
||||
use clang_sys::*;
|
||||
|
||||
let template_args = ty.template_args()
|
||||
.map_or(vec![], |args| {
|
||||
args.filter(|t| t.kind() != CXType_Invalid)
|
||||
.map(|t| {
|
||||
Item::from_ty_or_ref(t, t.declaration(), None, ctx)
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
let definition = ty.declaration()
|
||||
.specialized()
|
||||
.or_else(|| {
|
||||
let mut template_ref = None;
|
||||
ty.declaration().visit(|child| {
|
||||
if child.kind() == CXCursor_TemplateRef {
|
||||
template_ref = Some(child);
|
||||
return CXVisit_Break;
|
||||
}
|
||||
|
||||
// Instantiations of template aliases might have the
|
||||
// TemplateRef to the template alias definition arbitrarily
|
||||
// deep, so we need to recurse here and not only visit
|
||||
// direct children.
|
||||
CXChildVisit_Recurse
|
||||
});
|
||||
|
||||
template_ref.and_then(|cur| cur.referenced())
|
||||
});
|
||||
|
||||
let definition = match definition {
|
||||
Some(def) => def,
|
||||
None => {
|
||||
if !ty.declaration().is_builtin() {
|
||||
warn!("Could not find template definition for template \
|
||||
instantiation");
|
||||
}
|
||||
return None
|
||||
}
|
||||
};
|
||||
|
||||
let template_definition =
|
||||
Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx);
|
||||
|
||||
Some(TemplateInstantiation::new(template_definition, template_args))
|
||||
}
|
||||
|
||||
/// Does this instantiation have a vtable?
|
||||
pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
|
||||
ctx.resolve_type(self.definition).has_vtable(ctx) ||
|
||||
self.args.iter().any(|arg| ctx.resolve_type(*arg).has_vtable(ctx))
|
||||
}
|
||||
|
||||
/// Does this instantiation have a destructor?
|
||||
pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
|
||||
ctx.resolve_type(self.definition).has_destructor(ctx) ||
|
||||
self.args.iter().any(|arg| ctx.resolve_type(*arg).has_destructor(ctx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CanDeriveCopy<'a> for TemplateInstantiation {
|
||||
type Extra = ();
|
||||
|
||||
fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
|
||||
self.definition.can_derive_copy(ctx, ()) &&
|
||||
self.args.iter().all(|arg| arg.can_derive_copy(ctx, ()))
|
||||
}
|
||||
|
||||
fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
|
||||
self.definition.can_derive_copy_in_array(ctx, ()) &&
|
||||
self.args.iter().all(|arg| arg.can_derive_copy_in_array(ctx, ()))
|
||||
}
|
||||
}
|
||||
|
||||
impl CanDeriveDebug for TemplateInstantiation {
|
||||
type Extra = Option<Layout>;
|
||||
|
||||
fn can_derive_debug(&self,
|
||||
ctx: &BindgenContext,
|
||||
layout: Option<Layout>)
|
||||
-> bool {
|
||||
self.args.iter().all(|arg| arg.can_derive_debug(ctx, ())) &&
|
||||
ctx.resolve_type(self.definition)
|
||||
.as_comp()
|
||||
.and_then(|c| {
|
||||
// For non-type template parameters, we generate an opaque
|
||||
// blob, and in this case the instantiation has a better
|
||||
// idea of the layout than the definition does.
|
||||
if c.has_non_type_template_params() {
|
||||
let opaque = layout.unwrap_or(Layout::zero()).opaque();
|
||||
Some(opaque.can_derive_debug(ctx, ()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| self.definition.can_derive_debug(ctx, ()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Trace for TemplateInstantiation {
|
||||
type Extra = ();
|
||||
|
||||
fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
|
||||
where T: Tracer,
|
||||
{
|
||||
tracer.visit_kind(self.definition, EdgeKind::TemplateDeclaration);
|
||||
for &item in self.template_arguments() {
|
||||
tracer.visit_kind(item, EdgeKind::TemplateArgument);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,16 +25,6 @@ impl Edge {
|
|||
kind: kind,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the item that this edge is pointing to.
|
||||
pub fn to(&self) -> ItemId {
|
||||
self.to
|
||||
}
|
||||
|
||||
/// Get the kind of edge that this is.
|
||||
pub fn kind(&self) -> EdgeKind {
|
||||
self.kind
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ItemId> for Edge {
|
||||
|
@ -44,22 +34,137 @@ impl Into<ItemId> for Edge {
|
|||
}
|
||||
|
||||
/// The kind of edge reference. This is useful when we wish to only consider
|
||||
/// certain kinds of edges for a particular traversal.
|
||||
/// certain kinds of edges for a particular traversal or analysis.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum EdgeKind {
|
||||
/// A generic, catch-all edge.
|
||||
Generic,
|
||||
|
||||
/// An edge from a template declaration, to the definition of a named type
|
||||
/// parameter. For example, the edge Foo -> T in the following snippet:
|
||||
/// parameter. For example, the edge from `Foo<T>` to `T` in the following
|
||||
/// snippet:
|
||||
///
|
||||
/// ```C++
|
||||
/// template<typename T>
|
||||
/// class Foo { };
|
||||
/// ```
|
||||
TemplateParameterDefinition,
|
||||
|
||||
/// An edge from a template instantiation to the template declaration that
|
||||
/// is being instantiated. For example, the edge from `Foo<int>` to
|
||||
/// to `Foo<T>`:
|
||||
///
|
||||
/// ```C++
|
||||
/// template<typename T>
|
||||
/// class Foo { };
|
||||
///
|
||||
/// using Bar = Foo<int>;
|
||||
/// ```
|
||||
TemplateDeclaration,
|
||||
|
||||
/// An edge from a template instantiation to its template argument. For
|
||||
/// example, `Foo<Bar>` to `Bar`:
|
||||
///
|
||||
/// ```C++
|
||||
/// template<typename T>
|
||||
/// class Foo { };
|
||||
///
|
||||
/// class Bar { };
|
||||
///
|
||||
/// using FooBar = Foo<Bar>;
|
||||
/// ```
|
||||
TemplateArgument,
|
||||
|
||||
/// An edge from a compound type to one of its base member types. For
|
||||
/// example, the edge from `Bar` to `Foo`:
|
||||
///
|
||||
/// ```C++
|
||||
/// class Foo { };
|
||||
///
|
||||
/// class Bar : public Foo { };
|
||||
/// ```
|
||||
BaseMember,
|
||||
|
||||
/// An edge from a compound type to the types of one of its fields. For
|
||||
/// example, the edge from `Foo` to `int`:
|
||||
///
|
||||
/// ```C++
|
||||
/// class Foo {
|
||||
/// int x;
|
||||
/// };
|
||||
/// ```
|
||||
TemplateParameterDefinition,
|
||||
Field,
|
||||
|
||||
/// An edge from an class or struct type to an inner type member. For
|
||||
/// example, the edge from `Foo` to `Foo::Bar` here:
|
||||
///
|
||||
/// ```C++
|
||||
/// class Foo {
|
||||
/// struct Bar { };
|
||||
/// };
|
||||
/// ```
|
||||
InnerType,
|
||||
|
||||
/// An edge from an class or struct type to an inner static variable. For
|
||||
/// example, the edge from `Foo` to `Foo::BAR` here:
|
||||
///
|
||||
/// ```C++
|
||||
/// class Foo {
|
||||
/// static const char* BAR;
|
||||
/// };
|
||||
/// ```
|
||||
InnerVar,
|
||||
|
||||
/// An edge from a class or struct type to one of its method functions. For
|
||||
/// example, the edge from `Foo` to `Foo::bar`:
|
||||
///
|
||||
/// ```C++
|
||||
/// class Foo {
|
||||
/// bool bar(int x, int y);
|
||||
/// };
|
||||
/// ```
|
||||
Method,
|
||||
|
||||
/// An edge from a class or struct type to one of its constructor
|
||||
/// functions. For example, the edge from `Foo` to `Foo::Foo(int x, int y)`:
|
||||
///
|
||||
/// ```C++
|
||||
/// class Foo {
|
||||
/// int my_x;
|
||||
/// int my_y;
|
||||
///
|
||||
/// public:
|
||||
/// Foo(int x, int y);
|
||||
/// };
|
||||
/// ```
|
||||
Constructor,
|
||||
|
||||
/// An edge from a function declaration to its return type. For example, the
|
||||
/// edge from `foo` to `int`:
|
||||
///
|
||||
/// ```C++
|
||||
/// int foo(char* string);
|
||||
/// ```
|
||||
FunctionReturn,
|
||||
|
||||
/// An edge from a function declaration to one of its parameter types. For
|
||||
/// example, the edge from `foo` to `char*`:
|
||||
///
|
||||
/// ```C++
|
||||
/// int foo(char* string);
|
||||
/// ```
|
||||
FunctionParameter,
|
||||
|
||||
/// An edge from a static variable to its type. For example, the edge from
|
||||
/// `FOO` to `const char*`:
|
||||
///
|
||||
/// ```C++
|
||||
/// static const char* FOO;
|
||||
/// ```
|
||||
VarType,
|
||||
|
||||
/// An edge from a non-templated alias or typedef to the referenced type.
|
||||
TypeReference,
|
||||
}
|
||||
|
||||
/// A predicate to allow visiting only sub-sets of the whole IR graph by
|
||||
|
@ -203,7 +308,7 @@ pub trait Tracer {
|
|||
}
|
||||
|
||||
impl<F> Tracer for F
|
||||
where F: FnMut(ItemId, EdgeKind)
|
||||
where F: FnMut(ItemId, EdgeKind),
|
||||
{
|
||||
fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) {
|
||||
(*self)(item, kind)
|
||||
|
@ -211,7 +316,8 @@ impl<F> Tracer for F
|
|||
}
|
||||
|
||||
/// Trace all of the outgoing edges to other items. Implementations should call
|
||||
/// `tracer.visit(edge)` for each of their outgoing edges.
|
||||
/// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)`
|
||||
/// for each of their outgoing edges.
|
||||
pub trait Trace {
|
||||
/// If a particular type needs extra information beyond what it has in
|
||||
/// `self` and `context` to find its referenced items, its implementation
|
||||
|
|
|
@ -3,40 +3,21 @@
|
|||
use super::comp::CompInfo;
|
||||
use super::context::{BindgenContext, ItemId};
|
||||
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
|
||||
use super::dot::DotAttributes;
|
||||
use super::enum_ty::Enum;
|
||||
use super::function::FunctionSig;
|
||||
use super::int::IntKind;
|
||||
use super::item::Item;
|
||||
use super::layout::Layout;
|
||||
use super::layout::{Layout, Opaque};
|
||||
use super::objc::ObjCInterface;
|
||||
use super::traversal::{Trace, Tracer};
|
||||
use super::template::{AsNamed, TemplateInstantiation, TemplateParameters};
|
||||
use super::traversal::{EdgeKind, Trace, Tracer};
|
||||
use clang::{self, Cursor};
|
||||
use parse::{ClangItemParser, ParseError, ParseResult};
|
||||
use std::cell::Cell;
|
||||
use std::io;
|
||||
use std::mem;
|
||||
|
||||
/// Template declaration related methods.
|
||||
pub trait TemplateDeclaration {
|
||||
/// Get the set of `ItemId`s that make up this template declaration's free
|
||||
/// template parameters.
|
||||
///
|
||||
/// Note that these might *not* all be named types: C++ allows
|
||||
/// constant-value template parameters. Of course, Rust does not allow
|
||||
/// generic parameters to be anything but types, so we must treat them as
|
||||
/// opaque, and avoid instantiating them.
|
||||
fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>;
|
||||
|
||||
/// Get the number of free template parameters this template declaration
|
||||
/// has.
|
||||
///
|
||||
/// Implementations *may* return `Some` from this method when
|
||||
/// `template_params` returns `None`. This is useful when we only have
|
||||
/// partial information about the template declaration, such as when we are
|
||||
/// in the middle of parsing it.
|
||||
fn num_template_params(&self, ctx: &BindgenContext) -> Option<usize> {
|
||||
self.template_params(ctx).map(|params| params.len())
|
||||
}
|
||||
}
|
||||
|
||||
/// The base representation of a type in bindgen.
|
||||
///
|
||||
/// A type has an optional name, which if present cannot be empty, a `layout`
|
||||
|
@ -52,6 +33,9 @@ pub struct Type {
|
|||
kind: TypeKind,
|
||||
/// Whether this type is const-qualified.
|
||||
is_const: bool,
|
||||
/// Don't go into an infinite loop when detecting if we have a vtable or
|
||||
/// not.
|
||||
detect_has_vtable_cycle: Cell<bool>,
|
||||
}
|
||||
|
||||
/// The maximum number of items in an array for which Rust implements common
|
||||
|
@ -82,6 +66,7 @@ impl Type {
|
|||
layout: layout,
|
||||
kind: kind,
|
||||
is_const: is_const,
|
||||
detect_has_vtable_cycle: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +93,15 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
/// Is this a named type?
|
||||
/// Is this type of kind `TypeKind::Opaque`?
|
||||
pub fn is_opaque(&self) -> bool {
|
||||
match self.kind {
|
||||
TypeKind::Opaque => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this type of kind `TypeKind::Named`?
|
||||
pub fn is_named(&self) -> bool {
|
||||
match self.kind {
|
||||
TypeKind::Named => true,
|
||||
|
@ -159,8 +152,12 @@ impl Type {
|
|||
|
||||
/// Creates a new named type, with name `name`.
|
||||
pub fn named(name: String) -> Self {
|
||||
assert!(!name.is_empty());
|
||||
Self::new(Some(name), None, TypeKind::Named, false)
|
||||
let name = if name.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(name)
|
||||
};
|
||||
Self::new(name, None, TypeKind::Named, false)
|
||||
}
|
||||
|
||||
/// Is this a floating point type?
|
||||
|
@ -238,71 +235,43 @@ impl Type {
|
|||
|
||||
/// Whether this type has a vtable.
|
||||
pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
|
||||
if self.detect_has_vtable_cycle.get() {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.detect_has_vtable_cycle.set(true);
|
||||
|
||||
// FIXME: Can we do something about template parameters? Huh...
|
||||
match self.kind {
|
||||
TypeKind::TemplateInstantiation(t, _) |
|
||||
let result = match self.kind {
|
||||
TypeKind::TemplateAlias(t, _) |
|
||||
TypeKind::Alias(t) |
|
||||
TypeKind::ResolvedTypeRef(t) => ctx.resolve_type(t).has_vtable(ctx),
|
||||
TypeKind::Comp(ref info) => info.has_vtable(ctx),
|
||||
TypeKind::TemplateInstantiation(ref inst) => inst.has_vtable(ctx),
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
|
||||
self.detect_has_vtable_cycle.set(false);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns whether this type has a destructor.
|
||||
pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
|
||||
match self.kind {
|
||||
TypeKind::TemplateInstantiation(t, _) |
|
||||
TypeKind::TemplateAlias(t, _) |
|
||||
TypeKind::Alias(t) |
|
||||
TypeKind::ResolvedTypeRef(t) => {
|
||||
ctx.resolve_type(t).has_destructor(ctx)
|
||||
}
|
||||
TypeKind::TemplateInstantiation(ref inst) => {
|
||||
inst.has_destructor(ctx)
|
||||
}
|
||||
TypeKind::Comp(ref info) => info.has_destructor(ctx),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// See the comment in `Item::signature_contains_named_type`.
|
||||
pub fn signature_contains_named_type(&self,
|
||||
ctx: &BindgenContext,
|
||||
ty: &Type)
|
||||
-> bool {
|
||||
let name = match *ty.kind() {
|
||||
TypeKind::Named => ty.name(),
|
||||
ref other @ _ => unreachable!("Not a named type: {:?}", other),
|
||||
};
|
||||
|
||||
match self.kind {
|
||||
TypeKind::Named => self.name() == name,
|
||||
TypeKind::ResolvedTypeRef(t) |
|
||||
TypeKind::Array(t, _) |
|
||||
TypeKind::Pointer(t) |
|
||||
TypeKind::Alias(t) => {
|
||||
ctx.resolve_type(t)
|
||||
.signature_contains_named_type(ctx, ty)
|
||||
}
|
||||
TypeKind::Function(ref sig) => {
|
||||
sig.argument_types().iter().any(|&(_, arg)| {
|
||||
ctx.resolve_type(arg)
|
||||
.signature_contains_named_type(ctx, ty)
|
||||
}) ||
|
||||
ctx.resolve_type(sig.return_type())
|
||||
.signature_contains_named_type(ctx, ty)
|
||||
}
|
||||
TypeKind::TemplateAlias(_, ref template_args) |
|
||||
TypeKind::TemplateInstantiation(_, ref template_args) => {
|
||||
template_args.iter().any(|arg| {
|
||||
ctx.resolve_type(*arg)
|
||||
.signature_contains_named_type(ctx, ty)
|
||||
})
|
||||
}
|
||||
TypeKind::Comp(ref ci) => ci.signature_contains_named_type(ctx, ty),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this named type is an invalid C++ identifier. This is done to
|
||||
/// avoid generating invalid code with some cases we can't handle, see:
|
||||
///
|
||||
|
@ -320,10 +289,7 @@ impl Type {
|
|||
/// Checks whether the name looks like an identifier,
|
||||
/// i.e. is alphanumeric (including '_') and does not start with a digit.
|
||||
pub fn is_valid_identifier(name: &str) -> bool {
|
||||
let mut chars = name.chars();
|
||||
let first_valid = chars.next().map(|c| c.is_alphabetic() || c == '_').unwrap_or(false);
|
||||
|
||||
first_valid && chars.all(|c| c.is_alphanumeric() || c == '_')
|
||||
clang::is_valid_identifier(name)
|
||||
}
|
||||
|
||||
/// See safe_canonical_type.
|
||||
|
@ -337,7 +303,7 @@ impl Type {
|
|||
/// Returns the canonical type of this type, that is, the "inner type".
|
||||
///
|
||||
/// For example, for a `typedef`, the canonical type would be the
|
||||
/// `typedef`ed type, for a template specialization, would be the template
|
||||
/// `typedef`ed type, for a template instantiation, would be the template
|
||||
/// its specializing, and so on. Return None if the type is unresolved.
|
||||
pub fn safe_canonical_type<'tr>(&'tr self,
|
||||
ctx: &'tr BindgenContext)
|
||||
|
@ -346,6 +312,7 @@ impl Type {
|
|||
TypeKind::Named |
|
||||
TypeKind::Array(..) |
|
||||
TypeKind::Comp(..) |
|
||||
TypeKind::Opaque |
|
||||
TypeKind::Int(..) |
|
||||
TypeKind::Float(..) |
|
||||
TypeKind::Complex(..) |
|
||||
|
@ -356,14 +323,19 @@ impl Type {
|
|||
TypeKind::NullPtr |
|
||||
TypeKind::BlockPointer |
|
||||
TypeKind::Pointer(..) |
|
||||
TypeKind::ObjCId |
|
||||
TypeKind::ObjCSel |
|
||||
TypeKind::ObjCInterface(..) => Some(self),
|
||||
|
||||
TypeKind::ResolvedTypeRef(inner) |
|
||||
TypeKind::Alias(inner) |
|
||||
TypeKind::TemplateAlias(inner, _) |
|
||||
TypeKind::TemplateInstantiation(inner, _) => {
|
||||
TypeKind::TemplateAlias(inner, _) => {
|
||||
ctx.resolve_type(inner).safe_canonical_type(ctx)
|
||||
}
|
||||
TypeKind::TemplateInstantiation(ref inst) => {
|
||||
ctx.resolve_type(inst.template_definition())
|
||||
.safe_canonical_type(ctx)
|
||||
}
|
||||
|
||||
TypeKind::UnresolvedTypeRef(..) => None,
|
||||
}
|
||||
|
@ -373,6 +345,7 @@ impl Type {
|
|||
/// item, so we can arrive to the proper item that needs to be generated.
|
||||
pub fn should_be_traced_unconditionally(&self) -> bool {
|
||||
match self.kind {
|
||||
TypeKind::Comp(..) |
|
||||
TypeKind::Function(..) |
|
||||
TypeKind::Pointer(..) |
|
||||
TypeKind::Array(..) |
|
||||
|
@ -384,6 +357,88 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsNamed for Type {
|
||||
type Extra = Item;
|
||||
|
||||
fn as_named(&self, ctx: &BindgenContext, item: &Item) -> Option<ItemId> {
|
||||
self.kind.as_named(ctx, item)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsNamed for TypeKind {
|
||||
type Extra = Item;
|
||||
|
||||
fn as_named(&self, ctx: &BindgenContext, item: &Item) -> Option<ItemId> {
|
||||
match *self {
|
||||
TypeKind::Named => Some(item.id()),
|
||||
TypeKind::ResolvedTypeRef(id) => id.as_named(ctx, &()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DotAttributes for Type {
|
||||
fn dot_attributes<W>(&self,
|
||||
ctx: &BindgenContext,
|
||||
out: &mut W)
|
||||
-> io::Result<()>
|
||||
where W: io::Write,
|
||||
{
|
||||
if let Some(ref layout) = self.layout {
|
||||
try!(writeln!(out,
|
||||
"<tr><td>size</td><td>{}</td></tr>
|
||||
<tr><td>align</td><td>{}</td></tr>",
|
||||
layout.size,
|
||||
layout.align));
|
||||
if layout.packed {
|
||||
try!(writeln!(out, "<tr><td>packed</td><td>true</td></tr>"));
|
||||
}
|
||||
}
|
||||
|
||||
if self.is_const {
|
||||
try!(writeln!(out, "<tr><td>const</td><td>true</td></tr>"));
|
||||
}
|
||||
|
||||
self.kind.dot_attributes(ctx, out)
|
||||
}
|
||||
}
|
||||
|
||||
impl DotAttributes for TypeKind {
|
||||
fn dot_attributes<W>(&self,
|
||||
_ctx: &BindgenContext,
|
||||
out: &mut W)
|
||||
-> io::Result<()>
|
||||
where W: io::Write,
|
||||
{
|
||||
write!(out,
|
||||
"<tr><td>TypeKind</td><td>{}</td></tr>",
|
||||
match *self {
|
||||
TypeKind::Void => "Void",
|
||||
TypeKind::NullPtr => "NullPtr",
|
||||
TypeKind::Comp(..) => "Comp",
|
||||
TypeKind::Opaque => "Opaque",
|
||||
TypeKind::Int(..) => "Int",
|
||||
TypeKind::Float(..) => "Float",
|
||||
TypeKind::Complex(..) => "Complex",
|
||||
TypeKind::Alias(..) => "Alias",
|
||||
TypeKind::TemplateAlias(..) => "TemplateAlias",
|
||||
TypeKind::Array(..) => "Array",
|
||||
TypeKind::Function(..) => "Function",
|
||||
TypeKind::Enum(..) => "Enum",
|
||||
TypeKind::Pointer(..) => "Pointer",
|
||||
TypeKind::BlockPointer => "BlockPointer",
|
||||
TypeKind::Reference(..) => "Reference",
|
||||
TypeKind::TemplateInstantiation(..) => "TemplateInstantiation",
|
||||
TypeKind::ResolvedTypeRef(..) => "ResolvedTypeRef",
|
||||
TypeKind::Named => "Named",
|
||||
TypeKind::ObjCId => "ObjCId",
|
||||
TypeKind::ObjCSel => "ObjCSel",
|
||||
TypeKind::ObjCInterface(..) => "ObjCInterface",
|
||||
TypeKind::UnresolvedTypeRef(..) => unreachable!("there shouldn't be any more of these anymore"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_invalid_named_type_valid() {
|
||||
let ty = Type::new(Some("foo".into()), None, TypeKind::Named, false);
|
||||
|
@ -429,21 +484,26 @@ fn is_invalid_named_type_empty_name() {
|
|||
}
|
||||
|
||||
|
||||
impl TemplateDeclaration for Type {
|
||||
fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
||||
self.kind.template_params(ctx)
|
||||
impl TemplateParameters for Type {
|
||||
fn self_template_params(&self,
|
||||
ctx: &BindgenContext)
|
||||
-> Option<Vec<ItemId>> {
|
||||
self.kind.self_template_params(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl TemplateDeclaration for TypeKind {
|
||||
fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
||||
impl TemplateParameters for TypeKind {
|
||||
fn self_template_params(&self,
|
||||
ctx: &BindgenContext)
|
||||
-> Option<Vec<ItemId>> {
|
||||
match *self {
|
||||
TypeKind::ResolvedTypeRef(id) => {
|
||||
ctx.resolve_type(id).template_params(ctx)
|
||||
ctx.resolve_type(id).self_template_params(ctx)
|
||||
}
|
||||
TypeKind::Comp(ref comp) => comp.template_params(ctx),
|
||||
TypeKind::Comp(ref comp) => comp.self_template_params(ctx),
|
||||
TypeKind::TemplateAlias(_, ref args) => Some(args.clone()),
|
||||
|
||||
TypeKind::Opaque |
|
||||
TypeKind::TemplateInstantiation(..) |
|
||||
TypeKind::Void |
|
||||
TypeKind::NullPtr |
|
||||
|
@ -459,6 +519,8 @@ impl TemplateDeclaration for TypeKind {
|
|||
TypeKind::UnresolvedTypeRef(..) |
|
||||
TypeKind::Named |
|
||||
TypeKind::Alias(_) |
|
||||
TypeKind::ObjCId |
|
||||
TypeKind::ObjCSel |
|
||||
TypeKind::ObjCInterface(_) => None,
|
||||
}
|
||||
}
|
||||
|
@ -478,6 +540,17 @@ impl CanDeriveDebug for Type {
|
|||
TypeKind::Comp(ref info) => {
|
||||
info.can_derive_debug(ctx, self.layout(ctx))
|
||||
}
|
||||
TypeKind::Pointer(inner) => {
|
||||
let inner = ctx.resolve_type(inner);
|
||||
if let TypeKind::Function(ref sig) =
|
||||
*inner.canonical_type(ctx).kind() {
|
||||
return sig.can_derive_debug(ctx, ());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
TypeKind::TemplateInstantiation(ref inst) => {
|
||||
inst.can_derive_debug(ctx, self.layout(ctx))
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
@ -498,6 +571,10 @@ impl CanDeriveDefault for Type {
|
|||
TypeKind::Comp(ref info) => {
|
||||
info.can_derive_default(ctx, self.layout(ctx))
|
||||
}
|
||||
TypeKind::Opaque => {
|
||||
self.layout
|
||||
.map_or(true, |l| l.opaque().can_derive_default(ctx, ()))
|
||||
}
|
||||
TypeKind::Void |
|
||||
TypeKind::Named |
|
||||
TypeKind::TemplateInstantiation(..) |
|
||||
|
@ -505,8 +582,11 @@ impl CanDeriveDefault for Type {
|
|||
TypeKind::NullPtr |
|
||||
TypeKind::Pointer(..) |
|
||||
TypeKind::BlockPointer |
|
||||
TypeKind::ObjCId |
|
||||
TypeKind::ObjCSel |
|
||||
TypeKind::ObjCInterface(..) |
|
||||
TypeKind::Enum(..) => false,
|
||||
|
||||
TypeKind::Function(..) |
|
||||
TypeKind::Int(..) |
|
||||
TypeKind::Float(..) |
|
||||
|
@ -527,11 +607,17 @@ impl<'a> CanDeriveCopy<'a> for Type {
|
|||
}
|
||||
TypeKind::ResolvedTypeRef(t) |
|
||||
TypeKind::TemplateAlias(t, _) |
|
||||
TypeKind::TemplateInstantiation(t, _) |
|
||||
TypeKind::Alias(t) => t.can_derive_copy(ctx, ()),
|
||||
TypeKind::TemplateInstantiation(ref inst) => {
|
||||
inst.can_derive_copy(ctx, ())
|
||||
}
|
||||
TypeKind::Comp(ref info) => {
|
||||
info.can_derive_copy(ctx, (item, self.layout(ctx)))
|
||||
}
|
||||
TypeKind::Opaque => {
|
||||
self.layout
|
||||
.map_or(true, |l| l.opaque().can_derive_copy(ctx, ()))
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
@ -587,6 +673,11 @@ pub enum TypeKind {
|
|||
/// A compound type, that is, a class, struct, or union.
|
||||
Comp(CompInfo),
|
||||
|
||||
/// An opaque type that we just don't understand. All usage of this shoulf
|
||||
/// result in an opaque blob of bytes generated from the containing type's
|
||||
/// layout.
|
||||
Opaque,
|
||||
|
||||
/// An integer type, of a given kind. `bool` and `char` are also considered
|
||||
/// integers.
|
||||
Int(IntKind),
|
||||
|
@ -623,9 +714,9 @@ pub enum TypeKind {
|
|||
/// A reference to a type, as in: int& foo().
|
||||
Reference(ItemId),
|
||||
|
||||
/// An instantiation of an abstract template declaration (first tuple
|
||||
/// member) with a set of concrete template arguments (second tuple member).
|
||||
TemplateInstantiation(ItemId, Vec<ItemId>),
|
||||
/// An instantiation of an abstract template definition with a set of
|
||||
/// concrete template arguments.
|
||||
TemplateInstantiation(TemplateInstantiation),
|
||||
|
||||
/// A reference to a yet-to-resolve type. This stores the clang cursor
|
||||
/// itself, and postpones its resolution.
|
||||
|
@ -635,7 +726,7 @@ pub enum TypeKind {
|
|||
///
|
||||
/// see tests/headers/typeref.hpp to see somewhere where this is a problem.
|
||||
UnresolvedTypeRef(clang::Type,
|
||||
Option<clang::Cursor>,
|
||||
clang::Cursor,
|
||||
/* parent_id */
|
||||
Option<ItemId>),
|
||||
|
||||
|
@ -650,6 +741,12 @@ pub enum TypeKind {
|
|||
|
||||
/// Objective C interface. Always referenced through a pointer
|
||||
ObjCInterface(ObjCInterface),
|
||||
|
||||
/// Objective C 'id' type, points to any object
|
||||
ObjCId,
|
||||
|
||||
/// Objective C selector type
|
||||
ObjCSel,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
|
@ -663,15 +760,18 @@ impl Type {
|
|||
match self.kind {
|
||||
TypeKind::Void => true,
|
||||
TypeKind::Comp(ref ci) => ci.is_unsized(ctx),
|
||||
TypeKind::Opaque => self.layout.map_or(true, |l| l.size == 0),
|
||||
TypeKind::Array(inner, size) => {
|
||||
size == 0 || ctx.resolve_type(inner).is_unsized(ctx)
|
||||
}
|
||||
TypeKind::ResolvedTypeRef(inner) |
|
||||
TypeKind::Alias(inner) |
|
||||
TypeKind::TemplateAlias(inner, _) |
|
||||
TypeKind::TemplateInstantiation(inner, _) => {
|
||||
TypeKind::TemplateAlias(inner, _) => {
|
||||
ctx.resolve_type(inner).is_unsized(ctx)
|
||||
}
|
||||
TypeKind::TemplateInstantiation(ref inst) => {
|
||||
ctx.resolve_type(inst.template_definition()).is_unsized(ctx)
|
||||
}
|
||||
TypeKind::Named |
|
||||
TypeKind::Int(..) |
|
||||
TypeKind::Float(..) |
|
||||
|
@ -681,6 +781,8 @@ impl Type {
|
|||
TypeKind::Reference(..) |
|
||||
TypeKind::NullPtr |
|
||||
TypeKind::BlockPointer |
|
||||
TypeKind::ObjCId |
|
||||
TypeKind::ObjCSel |
|
||||
TypeKind::Pointer(..) => false,
|
||||
|
||||
TypeKind::ObjCInterface(..) => true, // dunno?
|
||||
|
@ -698,17 +800,16 @@ impl Type {
|
|||
/// comments in every special case justify why they're there.
|
||||
pub fn from_clang_ty(potential_id: ItemId,
|
||||
ty: &clang::Type,
|
||||
location: Option<Cursor>,
|
||||
location: Cursor,
|
||||
parent_id: Option<ItemId>,
|
||||
ctx: &mut BindgenContext)
|
||||
-> Result<ParseResult<Self>, ParseError> {
|
||||
use clang_sys::*;
|
||||
{
|
||||
let already_resolved =
|
||||
ctx.builtin_or_resolved_ty(potential_id,
|
||||
let already_resolved = ctx.builtin_or_resolved_ty(potential_id,
|
||||
parent_id,
|
||||
ty,
|
||||
location);
|
||||
Some(location));
|
||||
if let Some(ty) = already_resolved {
|
||||
debug!("{:?} already resolved: {:?}", ty, location);
|
||||
return Ok(ParseResult::AlreadyResolved(ty));
|
||||
|
@ -729,15 +830,52 @@ impl Type {
|
|||
|
||||
// Parse objc protocols as if they were interfaces
|
||||
let mut ty_kind = ty.kind();
|
||||
if let Some(loc) = location {
|
||||
if loc.kind() == CXCursor_ObjCProtocolDecl {
|
||||
ty_kind = CXType_ObjCInterface;
|
||||
}
|
||||
match location.kind() {
|
||||
CXCursor_ObjCProtocolDecl |
|
||||
CXCursor_ObjCCategoryDecl => ty_kind = CXType_ObjCInterface,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let kind = match ty_kind {
|
||||
// Objective C template type parameter
|
||||
// FIXME: This is probably wrong, we are attempting to find the
|
||||
// objc template params, which seem to manifest as a typedef.
|
||||
// We are rewriting them as id to suppress multiple conflicting
|
||||
// typedefs at root level
|
||||
if ty_kind == CXType_Typedef {
|
||||
let is_template_type_param = ty.declaration().kind() == CXCursor_TemplateTypeParameter;
|
||||
let is_canonical_objcpointer = canonical_ty.kind() == CXType_ObjCObjectPointer;
|
||||
|
||||
// We have found a template type for objc interface
|
||||
if is_canonical_objcpointer && is_template_type_param {
|
||||
// Objective-C generics are just ids with fancy name.
|
||||
// To keep it simple, just name them ids
|
||||
name = "id".to_owned();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if location.kind() == CXCursor_ClassTemplatePartialSpecialization {
|
||||
// Sorry! (Not sorry)
|
||||
warn!("Found a partial template specialization; bindgen does not \
|
||||
support partial template specialization! Constructing \
|
||||
opaque type instead.");
|
||||
return Ok(ParseResult::New(Opaque::from_clang_ty(&canonical_ty),
|
||||
None));
|
||||
}
|
||||
|
||||
let kind = if location.kind() == CXCursor_TemplateRef ||
|
||||
(ty.template_args().is_some() &&
|
||||
ty_kind != CXType_Typedef) {
|
||||
// This is a template instantiation.
|
||||
match TemplateInstantiation::from_ty(&ty, ctx) {
|
||||
Some(inst) => TypeKind::TemplateInstantiation(inst),
|
||||
None => TypeKind::Opaque,
|
||||
}
|
||||
} else {
|
||||
match ty_kind {
|
||||
CXType_Unexposed if *ty != canonical_ty &&
|
||||
canonical_ty.kind() != CXType_Invalid &&
|
||||
ty.ret_type().is_none() &&
|
||||
// Sometime clang desugars some types more than
|
||||
// what we need, specially with function
|
||||
// pointers.
|
||||
|
@ -764,27 +902,28 @@ impl Type {
|
|||
// tests/headers/func_ptr_in_struct.h), so we do a guess here
|
||||
// trying to see if it has a valid return type.
|
||||
if ty.ret_type().is_some() {
|
||||
let signature = try!(FunctionSig::from_ty(ty,
|
||||
&location.unwrap_or(cursor),
|
||||
ctx));
|
||||
let signature =
|
||||
try!(FunctionSig::from_ty(ty, &location, ctx));
|
||||
TypeKind::Function(signature)
|
||||
// Same here, with template specialisations we can safely
|
||||
// assume this is a Comp(..)
|
||||
} else if ty.is_fully_specialized_template() {
|
||||
} else if ty.is_fully_instantiated_template() {
|
||||
debug!("Template specialization: {:?}, {:?} {:?}",
|
||||
ty,
|
||||
location,
|
||||
canonical_ty);
|
||||
let complex =
|
||||
CompInfo::from_ty(potential_id, ty, location, ctx)
|
||||
let complex = CompInfo::from_ty(potential_id,
|
||||
ty,
|
||||
Some(location),
|
||||
ctx)
|
||||
.expect("C'mon");
|
||||
TypeKind::Comp(complex)
|
||||
} else if let Some(location) = location {
|
||||
} else {
|
||||
match location.kind() {
|
||||
CXCursor_ClassTemplatePartialSpecialization |
|
||||
CXCursor_CXXBaseSpecifier |
|
||||
CXCursor_ClassTemplate => {
|
||||
if location.kind() == CXCursor_CXXBaseSpecifier {
|
||||
if location.kind() ==
|
||||
CXCursor_CXXBaseSpecifier {
|
||||
// In the case we're parsing a base specifier
|
||||
// inside an unexposed or invalid type, it means
|
||||
// that we're parsing one of two things:
|
||||
|
@ -826,18 +965,29 @@ impl Type {
|
|||
// [4]: inherit-namespaced.hpp
|
||||
if location.spelling()
|
||||
.chars()
|
||||
.all(|c| c.is_alphanumeric() || c == '_') {
|
||||
.all(|c| {
|
||||
c.is_alphanumeric() || c == '_'
|
||||
}) {
|
||||
return Err(ParseError::Recurse);
|
||||
}
|
||||
} else {
|
||||
name = location.spelling();
|
||||
}
|
||||
|
||||
let complex = CompInfo::from_ty(potential_id,
|
||||
ty,
|
||||
Some(location),
|
||||
ctx)
|
||||
.expect("C'mon");
|
||||
TypeKind::Comp(complex)
|
||||
ctx);
|
||||
match complex {
|
||||
Ok(complex) => TypeKind::Comp(complex),
|
||||
Err(_) => {
|
||||
warn!("Could not create complex type \
|
||||
from class template or base \
|
||||
specifier, using opaque blob");
|
||||
let opaque = Opaque::from_clang_ty(ty);
|
||||
return Ok(ParseResult::New(opaque, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
CXCursor_TypeAliasTemplateDecl => {
|
||||
debug!("TypeAliasTemplateDecl");
|
||||
|
@ -860,21 +1010,18 @@ impl Type {
|
|||
.expect("Not valid Type?");
|
||||
inner =
|
||||
Item::from_ty(&inner_ty,
|
||||
Some(cur),
|
||||
cur,
|
||||
Some(potential_id),
|
||||
ctx);
|
||||
}
|
||||
CXCursor_TemplateTypeParameter => {
|
||||
// See the comment in src/ir/comp.rs
|
||||
// about the same situation.
|
||||
if cur.spelling().is_empty() {
|
||||
return CXChildVisit_Continue;
|
||||
}
|
||||
|
||||
let param =
|
||||
Item::named_type(cur.spelling(),
|
||||
potential_id,
|
||||
ctx);
|
||||
Item::named_type(None,
|
||||
cur,
|
||||
ctx)
|
||||
.expect("Item::named_type shouldn't \
|
||||
ever fail if we are looking \
|
||||
at a TemplateTypeParameter");
|
||||
args.push(param);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -906,7 +1053,7 @@ impl Type {
|
|||
|
||||
return Self::from_clang_ty(potential_id,
|
||||
&referenced_ty,
|
||||
Some(referenced),
|
||||
referenced,
|
||||
parent_id,
|
||||
ctx);
|
||||
}
|
||||
|
@ -924,7 +1071,7 @@ impl Type {
|
|||
let item =
|
||||
Item::from_ty_or_ref_with_id(potential_id,
|
||||
referenced_ty,
|
||||
Some(declaration),
|
||||
declaration,
|
||||
parent_id,
|
||||
ctx);
|
||||
return Ok(ParseResult::AlreadyResolved(item));
|
||||
|
@ -941,34 +1088,10 @@ impl Type {
|
|||
return Err(ParseError::Recurse);
|
||||
}
|
||||
|
||||
// If the type name is empty we're probably
|
||||
// over-recursing to find a template parameter name
|
||||
// or something like that, so just don't be too
|
||||
// noisy with it since it causes confusion, see for
|
||||
// example the discussion in:
|
||||
//
|
||||
// https://github.com/jamesmunns/teensy3-rs/issues/9
|
||||
if !ty.spelling().is_empty() {
|
||||
warn!("invalid type {:?}", ty);
|
||||
} else {
|
||||
warn!("invalid type {:?}", ty);
|
||||
}
|
||||
return Err(ParseError::Continue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: Don't duplicate this!
|
||||
if ty.kind() == CXType_Unexposed {
|
||||
warn!("Unexposed type {:?}, recursing inside", ty);
|
||||
return Err(ParseError::Recurse);
|
||||
}
|
||||
|
||||
if !ty.spelling().is_empty() {
|
||||
warn!("invalid type {:?}", ty);
|
||||
} else {
|
||||
warn!("invalid type {:?}", ty);
|
||||
}
|
||||
return Err(ParseError::Continue);
|
||||
}
|
||||
}
|
||||
CXType_Auto => {
|
||||
|
@ -993,10 +1116,34 @@ impl Type {
|
|||
CXType_ObjCObjectPointer |
|
||||
CXType_MemberPointer |
|
||||
CXType_Pointer => {
|
||||
let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(),
|
||||
location,
|
||||
None,
|
||||
ctx);
|
||||
// Fun fact: the canonical type of a pointer type may sometimes
|
||||
// contain information we need but isn't present in the concrete
|
||||
// type (yeah, I'm equally wat'd).
|
||||
//
|
||||
// Yet we still have trouble if we unconditionally trust the
|
||||
// canonical type, like too-much desugaring (sigh).
|
||||
//
|
||||
// See tests/headers/call-conv-field.h for an example.
|
||||
//
|
||||
// Since for now the only identifier cause of breakage is the
|
||||
// ABI for function pointers, and different ABI mixed with
|
||||
// problematic stuff like that one is _extremely_ unlikely and
|
||||
// can be bypassed via blacklisting, we do the check explicitly
|
||||
// (as hacky as it is).
|
||||
//
|
||||
// Yet we should probably (somehow) get the best of both worlds,
|
||||
// presumably special-casing function pointers as a whole, yet
|
||||
// someone is going to need to care about typedef'd function
|
||||
// pointers, etc, which isn't trivial given function pointers
|
||||
// are mostly unexposed. I don't have the time for it right now.
|
||||
let mut pointee = ty.pointee_type().unwrap();
|
||||
let canonical_pointee = canonical_ty.pointee_type()
|
||||
.unwrap();
|
||||
if pointee.call_conv() != canonical_pointee.call_conv() {
|
||||
pointee = canonical_pointee;
|
||||
}
|
||||
let inner =
|
||||
Item::from_ty_or_ref(pointee, location, None, ctx);
|
||||
TypeKind::Pointer(inner)
|
||||
}
|
||||
CXType_BlockPointer => TypeKind::BlockPointer,
|
||||
|
@ -1004,7 +1151,8 @@ impl Type {
|
|||
// can even add bindings for that, so huh.
|
||||
CXType_RValueReference |
|
||||
CXType_LValueReference => {
|
||||
let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(),
|
||||
let inner = Item::from_ty_or_ref(ty.pointee_type()
|
||||
.unwrap(),
|
||||
location,
|
||||
None,
|
||||
ctx);
|
||||
|
@ -1030,14 +1178,14 @@ impl Type {
|
|||
}
|
||||
CXType_FunctionNoProto |
|
||||
CXType_FunctionProto => {
|
||||
let signature = try!(FunctionSig::from_ty(ty,
|
||||
&location.unwrap_or(cursor),
|
||||
ctx));
|
||||
let signature =
|
||||
try!(FunctionSig::from_ty(ty, &location, ctx));
|
||||
TypeKind::Function(signature)
|
||||
}
|
||||
CXType_Typedef => {
|
||||
let inner = cursor.typedef_type().expect("Not valid Type?");
|
||||
let inner = Item::from_ty_or_ref(inner, location, None, ctx);
|
||||
let inner =
|
||||
Item::from_ty_or_ref(inner, location, None, ctx);
|
||||
TypeKind::Alias(inner)
|
||||
}
|
||||
CXType_Enum => {
|
||||
|
@ -1053,8 +1201,10 @@ impl Type {
|
|||
TypeKind::Enum(enum_)
|
||||
}
|
||||
CXType_Record => {
|
||||
let complex =
|
||||
CompInfo::from_ty(potential_id, ty, location, ctx)
|
||||
let complex = CompInfo::from_ty(potential_id,
|
||||
ty,
|
||||
Some(location),
|
||||
ctx)
|
||||
.expect("Not a complex type?");
|
||||
|
||||
if name.is_empty() {
|
||||
|
@ -1089,9 +1239,13 @@ impl Type {
|
|||
parent_id,
|
||||
ctx);
|
||||
}
|
||||
CXType_ObjCId => TypeKind::ObjCId,
|
||||
CXType_ObjCSel => TypeKind::ObjCSel,
|
||||
CXType_ObjCClass |
|
||||
CXType_ObjCInterface => {
|
||||
let interface = ObjCInterface::from_ty(&location.unwrap(), ctx)
|
||||
let interface = ObjCInterface::from_ty(&location, ctx)
|
||||
.expect("Not a valid objc interface?");
|
||||
name = interface.rust_name();
|
||||
TypeKind::ObjCInterface(interface)
|
||||
}
|
||||
_ => {
|
||||
|
@ -1101,6 +1255,7 @@ impl Type {
|
|||
location);
|
||||
return Err(ParseError::Continue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let name = if name.is_empty() { None } else { Some(name) };
|
||||
|
@ -1124,16 +1279,18 @@ impl Trace for Type {
|
|||
TypeKind::Array(inner, _) |
|
||||
TypeKind::Alias(inner) |
|
||||
TypeKind::ResolvedTypeRef(inner) => {
|
||||
tracer.visit(inner);
|
||||
tracer.visit_kind(inner, EdgeKind::TypeReference);
|
||||
}
|
||||
|
||||
TypeKind::TemplateAlias(inner, ref template_args) |
|
||||
TypeKind::TemplateInstantiation(inner, ref template_args) => {
|
||||
tracer.visit(inner);
|
||||
for &item in template_args {
|
||||
tracer.visit(item);
|
||||
TypeKind::TemplateAlias(inner, ref template_params) => {
|
||||
tracer.visit_kind(inner, EdgeKind::TypeReference);
|
||||
for &item in template_params {
|
||||
tracer.visit_kind(item,
|
||||
EdgeKind::TemplateParameterDefinition);
|
||||
}
|
||||
}
|
||||
TypeKind::TemplateInstantiation(ref inst) => {
|
||||
inst.trace(context, tracer, &());
|
||||
}
|
||||
TypeKind::Comp(ref ci) => ci.trace(context, tracer, item),
|
||||
TypeKind::Function(ref sig) => sig.trace(context, tracer, &()),
|
||||
TypeKind::Enum(ref en) => {
|
||||
|
@ -1145,11 +1302,12 @@ impl Trace for Type {
|
|||
tracer.visit(id);
|
||||
}
|
||||
|
||||
TypeKind::ObjCInterface(_) => {
|
||||
// TODO:
|
||||
TypeKind::ObjCInterface(ref interface) => {
|
||||
interface.trace(context, tracer, &());
|
||||
}
|
||||
|
||||
// None of these variants have edges to other items and types.
|
||||
TypeKind::Opaque |
|
||||
TypeKind::UnresolvedTypeRef(_, _, None) |
|
||||
TypeKind::Named |
|
||||
TypeKind::Void |
|
||||
|
@ -1157,6 +1315,8 @@ impl Trace for Type {
|
|||
TypeKind::Int(_) |
|
||||
TypeKind::Float(_) |
|
||||
TypeKind::Complex(_) |
|
||||
TypeKind::ObjCId |
|
||||
TypeKind::ObjCSel |
|
||||
TypeKind::BlockPointer => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Intermediate representation of variables.
|
||||
|
||||
use super::context::{BindgenContext, ItemId};
|
||||
use super::dot::DotAttributes;
|
||||
use super::function::cursor_mangling;
|
||||
use super::int::IntKind;
|
||||
use super::item::Item;
|
||||
|
@ -8,6 +9,7 @@ use super::ty::{FloatKind, TypeKind};
|
|||
use cexpr;
|
||||
use clang;
|
||||
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
|
||||
use std::io;
|
||||
use std::num::Wrapping;
|
||||
|
||||
/// The type for a constant variable.
|
||||
|
@ -84,6 +86,27 @@ impl Var {
|
|||
}
|
||||
}
|
||||
|
||||
impl DotAttributes for Var {
|
||||
fn dot_attributes<W>(&self,
|
||||
_ctx: &BindgenContext,
|
||||
out: &mut W)
|
||||
-> io::Result<()>
|
||||
where W: io::Write,
|
||||
{
|
||||
if self.is_const {
|
||||
try!(writeln!(out, "<tr><td>const</td><td>true</td></tr>"));
|
||||
}
|
||||
|
||||
if let Some(ref mangled) = self.mangled_name {
|
||||
try!(writeln!(out,
|
||||
"<tr><td>mangled name</td><td>{}</td></tr>",
|
||||
mangled));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ClangSubItemParser for Var {
|
||||
fn parse(cursor: clang::Cursor,
|
||||
ctx: &mut BindgenContext)
|
||||
|
@ -93,6 +116,11 @@ impl ClangSubItemParser for Var {
|
|||
use cexpr::literal::CChar;
|
||||
match cursor.kind() {
|
||||
CXCursor_MacroDefinition => {
|
||||
|
||||
if let Some(visitor) = ctx.parse_callbacks() {
|
||||
visitor.parsed_macro(&cursor.spelling());
|
||||
}
|
||||
|
||||
let value = parse_macro(ctx, &cursor, ctx.translation_unit());
|
||||
|
||||
let (id, value) = match value {
|
||||
|
@ -123,7 +151,7 @@ impl ClangSubItemParser for Var {
|
|||
let (type_kind, val) = match value {
|
||||
EvalResult::Invalid => return Err(ParseError::Continue),
|
||||
EvalResult::Float(f) => {
|
||||
(TypeKind::Float(FloatKind::Float), VarType::Float(f))
|
||||
(TypeKind::Float(FloatKind::Double), VarType::Float(f))
|
||||
}
|
||||
EvalResult::Char(c) => {
|
||||
let c = match c {
|
||||
|
@ -147,7 +175,7 @@ impl ClangSubItemParser for Var {
|
|||
(TypeKind::Pointer(char_ty), VarType::String(val))
|
||||
}
|
||||
EvalResult::Int(Wrapping(value)) => {
|
||||
let kind = ctx.type_chooser()
|
||||
let kind = ctx.parse_callbacks()
|
||||
.and_then(|c| c.int_macro(&name, value))
|
||||
.unwrap_or_else(|| if value < 0 {
|
||||
if value < i32::min_value() as i64 {
|
||||
|
@ -155,9 +183,7 @@ impl ClangSubItemParser for Var {
|
|||
} else {
|
||||
IntKind::Int
|
||||
}
|
||||
} else if value >
|
||||
u32::max_value() as
|
||||
i64 {
|
||||
} else if value > u32::max_value() as i64 {
|
||||
IntKind::ULongLong
|
||||
} else {
|
||||
IntKind::UInt
|
||||
|
@ -184,7 +210,7 @@ impl ClangSubItemParser for Var {
|
|||
// XXX this is redundant, remove!
|
||||
let is_const = ty.is_const();
|
||||
|
||||
let ty = match Item::from_ty(&ty, Some(cursor), None, ctx) {
|
||||
let ty = match Item::from_ty(&ty, cursor, None, ctx) {
|
||||
Ok(ty) => ty,
|
||||
Err(e) => {
|
||||
assert_eq!(ty.kind(),
|
||||
|
@ -238,7 +264,7 @@ impl ClangSubItemParser for Var {
|
|||
.map(VarType::String)
|
||||
};
|
||||
|
||||
let mangling = cursor_mangling(&cursor);
|
||||
let mangling = cursor_mangling(ctx, &cursor);
|
||||
let var = Var::new(name, mangling, ty, value, is_const);
|
||||
|
||||
Ok(ParseResult::New(var, Some(cursor)))
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! Provide a C/C++ header file, receive Rust FFI code to call into C/C++
|
||||
//! functions and use types defined in the header.
|
||||
//!
|
||||
//! See the [Builder](./struct.Builder.html) struct for usage.
|
||||
//! See the [`Builder`](./struct.Builder.html) struct for usage.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
|
@ -37,16 +37,19 @@ extern crate log;
|
|||
#[macro_use]
|
||||
mod log_stubs;
|
||||
|
||||
#[macro_use]
|
||||
mod extra_assertions;
|
||||
|
||||
// A macro to declare an internal module for which we *must* provide
|
||||
// documentation for. If we are building with the "docs_" feature, then the
|
||||
// module is declared public, and our `#![deny(missing_docs)]` pragma applies to
|
||||
// it. This feature is used in CI, so we won't let anything slip by
|
||||
// documentation for. If we are building with the "testing_only_docs" feature,
|
||||
// then the module is declared public, and our `#![deny(missing_docs)]` pragma
|
||||
// applies to it. This feature is used in CI, so we won't let anything slip by
|
||||
// undocumented. Normal builds, however, will leave the module private, so that
|
||||
// we don't expose internals to library consumers.
|
||||
macro_rules! doc_mod {
|
||||
($m:ident, $doc_mod_name:ident) => {
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "docs_")] {
|
||||
if #[cfg(feature = "testing_only_docs")] {
|
||||
pub mod $doc_mod_name {
|
||||
//! Autogenerated documentation module.
|
||||
pub use super::$m::*;
|
||||
|
@ -63,7 +66,7 @@ mod parse;
|
|||
mod regex_set;
|
||||
mod uses;
|
||||
|
||||
pub mod chooser;
|
||||
pub mod callbacks;
|
||||
|
||||
#[cfg(rustfmt)]
|
||||
mod codegen;
|
||||
|
@ -86,7 +89,7 @@ use regex_set::RegexSet;
|
|||
use std::fs::OpenOptions;
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{DUMMY_SP, Span};
|
||||
|
@ -109,6 +112,8 @@ pub struct CodegenConfig {
|
|||
pub methods: bool,
|
||||
/// Whether to generate constructors.
|
||||
pub constructors: bool,
|
||||
/// Whether to generate destructors.
|
||||
pub destructors: bool,
|
||||
}
|
||||
|
||||
impl CodegenConfig {
|
||||
|
@ -120,6 +125,7 @@ impl CodegenConfig {
|
|||
vars: true,
|
||||
methods: true,
|
||||
constructors: true,
|
||||
destructors: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,6 +137,7 @@ impl CodegenConfig {
|
|||
vars: false,
|
||||
methods: false,
|
||||
constructors: false,
|
||||
destructors: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,13 +175,288 @@ pub fn builder() -> Builder {
|
|||
}
|
||||
|
||||
impl Builder {
|
||||
/// Set the input C/C++ header.
|
||||
/// Generates the command line flags use for creating `Builder`.
|
||||
pub fn command_line_flags(&self) -> Vec<String> {
|
||||
let mut output_vector: Vec<String> = Vec::new();
|
||||
|
||||
if let Some(ref header) = self.options.input_header {
|
||||
//Positional argument 'header'
|
||||
output_vector.push(header.clone().into());
|
||||
}
|
||||
|
||||
self.options
|
||||
.bitfield_enums
|
||||
.get_items()
|
||||
.iter()
|
||||
.map(|item| {
|
||||
output_vector.push("--bitfield-enum".into());
|
||||
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
|
||||
})
|
||||
.count();
|
||||
|
||||
self.options
|
||||
.constified_enums
|
||||
.get_items()
|
||||
.iter()
|
||||
.map(|item| {
|
||||
output_vector.push("--constified-enum".into());
|
||||
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
|
||||
})
|
||||
.count();
|
||||
|
||||
self.options
|
||||
.hidden_types
|
||||
.get_items()
|
||||
.iter()
|
||||
.map(|item| {
|
||||
output_vector.push("--blacklist-type".into());
|
||||
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
|
||||
})
|
||||
.count();
|
||||
|
||||
if !self.options.layout_tests {
|
||||
output_vector.push("--no-layout-tests".into());
|
||||
}
|
||||
|
||||
if !self.options.derive_debug {
|
||||
output_vector.push("--no-derive-debug".into());
|
||||
}
|
||||
|
||||
if !self.options.derive_default {
|
||||
output_vector.push("--no-derive-default".into());
|
||||
} else {
|
||||
output_vector.push("--with-derive-default".into());
|
||||
}
|
||||
|
||||
if !self.options.generate_comments {
|
||||
output_vector.push("--no-doc-comments".into());
|
||||
}
|
||||
|
||||
if !self.options.whitelist_recursively {
|
||||
output_vector.push("--no-recursive-whitelist".into());
|
||||
}
|
||||
|
||||
if self.options.objc_extern_crate {
|
||||
output_vector.push("--objc-extern-crate".into());
|
||||
}
|
||||
|
||||
if self.options.builtins {
|
||||
output_vector.push("--builtins".into());
|
||||
}
|
||||
|
||||
if let Some(ref prefix) = self.options.ctypes_prefix {
|
||||
output_vector.push("--ctypes-prefix".into());
|
||||
output_vector.push(prefix.clone());
|
||||
}
|
||||
|
||||
if let Some(ref dummy) = self.options.dummy_uses {
|
||||
output_vector.push("--dummy-uses".into());
|
||||
output_vector.push(dummy.clone());
|
||||
}
|
||||
|
||||
if self.options.emit_ast {
|
||||
output_vector.push("--emit-clang-ast".into());
|
||||
}
|
||||
|
||||
if self.options.emit_ir {
|
||||
output_vector.push("--emit-ir".into());
|
||||
}
|
||||
if let Some(ref graph) = self.options.emit_ir_graphviz {
|
||||
output_vector.push("--emit-ir-graphviz".into());
|
||||
output_vector.push(graph.clone())
|
||||
}
|
||||
if self.options.enable_cxx_namespaces {
|
||||
output_vector.push("--enable-cxx-namespaces".into());
|
||||
}
|
||||
if self.options.disable_name_namespacing {
|
||||
output_vector.push("--disable-name-namespacing".into());
|
||||
}
|
||||
|
||||
self.options
|
||||
.links
|
||||
.iter()
|
||||
.map(|&(ref item, _)| {
|
||||
output_vector.push("--framework".into());
|
||||
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
|
||||
})
|
||||
.count();
|
||||
|
||||
if !self.options.codegen_config.functions {
|
||||
output_vector.push("--ignore-functions".into());
|
||||
}
|
||||
|
||||
output_vector.push("--generate".into());
|
||||
|
||||
//Temporary placeholder for below 4 options
|
||||
let mut options:Vec<String> = Vec::new();
|
||||
if self.options.codegen_config.functions {
|
||||
options.push("function".into());
|
||||
}
|
||||
if self.options.codegen_config.types {
|
||||
options.push("types".into());
|
||||
}
|
||||
if self.options.codegen_config.vars {
|
||||
options.push("vars".into());
|
||||
}
|
||||
if self.options.codegen_config.methods {
|
||||
options.push("methods".into());
|
||||
}
|
||||
if self.options.codegen_config.constructors {
|
||||
options.push("constructors".into());
|
||||
}
|
||||
if self.options.codegen_config.destructors {
|
||||
options.push("destructors".into());
|
||||
}
|
||||
|
||||
output_vector.push(options.join(","));
|
||||
|
||||
if !self.options.codegen_config.methods {
|
||||
output_vector.push("--ignore-methods".into());
|
||||
}
|
||||
|
||||
self.options
|
||||
.links
|
||||
.iter()
|
||||
.map(|&(ref item, _)| {
|
||||
output_vector.push("--clang-args".into());
|
||||
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
|
||||
})
|
||||
.count();
|
||||
|
||||
if !self.options.convert_floats {
|
||||
output_vector.push("--no-convert-floats".into());
|
||||
}
|
||||
|
||||
if !self.options.prepend_enum_name {
|
||||
output_vector.push("--no-prepend-enum-name".into());
|
||||
}
|
||||
|
||||
if !self.options.unstable_rust {
|
||||
output_vector.push("--no-unstable-rust".into());
|
||||
}
|
||||
|
||||
self.options
|
||||
.opaque_types
|
||||
.get_items()
|
||||
.iter()
|
||||
.map(|item| {
|
||||
output_vector.push("--opaque-type".into());
|
||||
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
|
||||
})
|
||||
.count();
|
||||
|
||||
self.options
|
||||
.raw_lines
|
||||
.iter()
|
||||
.map(|item| {
|
||||
output_vector.push("--raw-line".into());
|
||||
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
|
||||
})
|
||||
.count();
|
||||
|
||||
self.options
|
||||
.links
|
||||
.iter()
|
||||
.map(|&(ref item, _)| {
|
||||
output_vector.push("--static".into());
|
||||
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
|
||||
})
|
||||
.count();
|
||||
|
||||
if self.options.use_core {
|
||||
output_vector.push("--use-core".into());
|
||||
}
|
||||
|
||||
if self.options.conservative_inline_namespaces {
|
||||
output_vector.push("--conservative-inline-namespaces".into());
|
||||
}
|
||||
|
||||
self.options
|
||||
.whitelisted_functions
|
||||
.get_items()
|
||||
.iter()
|
||||
.map(|item| {
|
||||
output_vector.push("--whitelist-function".into());
|
||||
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
|
||||
})
|
||||
.count();
|
||||
|
||||
self.options
|
||||
.whitelisted_types
|
||||
.get_items()
|
||||
.iter()
|
||||
.map(|item| {
|
||||
output_vector.push("--whitelist-type".into());
|
||||
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
|
||||
})
|
||||
.count();
|
||||
|
||||
self.options
|
||||
.whitelisted_vars
|
||||
.get_items()
|
||||
.iter()
|
||||
.map(|item| {
|
||||
output_vector.push("--whitelist-var".into());
|
||||
output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
|
||||
})
|
||||
.count();
|
||||
|
||||
if !self.options.clang_args.is_empty() {
|
||||
output_vector.push("--".into());
|
||||
self.options
|
||||
.clang_args
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|item| {
|
||||
output_vector.push(item);
|
||||
})
|
||||
.count();
|
||||
}
|
||||
|
||||
output_vector
|
||||
}
|
||||
|
||||
/// Add an input C/C++ header to generate bindings for.
|
||||
///
|
||||
/// This can be used to generate bindings to a single header:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let bindings = bindgen::Builder::default()
|
||||
/// .header("input.h")
|
||||
/// .generate()
|
||||
/// .unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// Or you can invoke it multiple times to generate bindings to multiple
|
||||
/// headers:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let bindings = bindgen::Builder::default()
|
||||
/// .header("first.h")
|
||||
/// .header("second.h")
|
||||
/// .header("third.h")
|
||||
/// .generate()
|
||||
/// .unwrap();
|
||||
/// ```
|
||||
pub fn header<T: Into<String>>(mut self, header: T) -> Builder {
|
||||
if let Some(prev_header) = self.options.input_header.take() {
|
||||
self.options.clang_args.push("-include".into());
|
||||
self.options.clang_args.push(prev_header);
|
||||
}
|
||||
|
||||
let header = header.into();
|
||||
self.options.input_header = Some(header);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add `contents` as an input C/C++ header named `name`.
|
||||
///
|
||||
/// The file `name` will be added to the clang arguments.
|
||||
pub fn header_contents(mut self, name: &str, contents: &str) -> Builder {
|
||||
self.options.input_unsaved_files.push(clang::UnsavedFile::new(name, contents));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the output graphviz file.
|
||||
pub fn emit_ir_graphviz<T: Into<String>>(mut self, path: T) -> Builder {
|
||||
let path = path.into();
|
||||
|
@ -199,19 +481,31 @@ impl Builder {
|
|||
///
|
||||
/// This can be used to get bindgen to generate _exactly_ the types you want
|
||||
/// in your bindings, and then import other types manually via other means
|
||||
/// (like `raw_line`).
|
||||
/// (like [`raw_line`](#method.raw_line)).
|
||||
pub fn whitelist_recursively(mut self, doit: bool) -> Self {
|
||||
self.options.whitelist_recursively = doit;
|
||||
self
|
||||
}
|
||||
|
||||
/// Generate '#[macro_use] extern crate objc;' instead of 'use objc;'
|
||||
/// Generate `#[macro_use] extern crate objc;` instead of `use objc;`
|
||||
/// in the prologue of the files generated from objective-c files
|
||||
pub fn objc_extern_crate(mut self, doit: bool) -> Self {
|
||||
self.options.objc_extern_crate = doit;
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether to use the clang-provided name mangling. This is true by default
|
||||
/// and probably needed for C++ features.
|
||||
///
|
||||
/// However, some old libclang versions seem to return incorrect results in
|
||||
/// some cases for non-mangled functions, see [1], so we allow disabling it.
|
||||
///
|
||||
/// [1]: https://github.com/servo/rust-bindgen/issues/528
|
||||
pub fn trust_clang_mangling(mut self, doit: bool) -> Self {
|
||||
self.options.enable_mangling = doit;
|
||||
self
|
||||
}
|
||||
|
||||
/// Generate a C/C++ file that includes the header and has dummy uses of
|
||||
/// every type defined in the header.
|
||||
pub fn dummy_uses<T: Into<String>>(mut self, dummy_uses: T) -> Builder {
|
||||
|
@ -290,6 +584,16 @@ impl Builder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Add arguments to be passed straight through to clang.
|
||||
pub fn clang_args<I>(mut self, iter: I) -> Builder
|
||||
where I: IntoIterator,
|
||||
I::Item: AsRef<str> {
|
||||
for arg in iter {
|
||||
self = self.clang_arg(arg.as_ref())
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Make the generated bindings link the given shared library.
|
||||
pub fn link<T: Into<String>>(mut self, library: T) -> Builder {
|
||||
self.options.links.push((library.into(), LinkType::Default));
|
||||
|
@ -315,12 +619,18 @@ impl Builder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Avoid converting floats to f32/f64 by default.
|
||||
/// Avoid converting floats to `f32`/`f64` by default.
|
||||
pub fn no_convert_floats(mut self) -> Self {
|
||||
self.options.convert_floats = false;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether layout tests should be generated.
|
||||
pub fn layout_tests(mut self, doit: bool) -> Self {
|
||||
self.options.layout_tests = doit;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether `Debug` should be derived by default.
|
||||
pub fn derive_debug(mut self, doit: bool) -> Self {
|
||||
self.options.derive_debug = doit;
|
||||
|
@ -351,20 +661,19 @@ impl Builder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Disable auto-namespacing of names if namespaces are disabled.
|
||||
/// Disable name auto-namespacing.
|
||||
///
|
||||
/// By default, if namespaces are disabled, bindgen tries to mangle the
|
||||
/// names to from `foo::bar::Baz` to look like `foo_bar_Baz`, instead of
|
||||
/// just `Baz`.
|
||||
/// By default, bindgen mangles names like `foo::bar::Baz` to look like
|
||||
/// `foo_bar_Baz` instead of just `Baz`.
|
||||
///
|
||||
/// This option disables that behavior.
|
||||
/// This method disables that behavior.
|
||||
///
|
||||
/// Note that this intentionally doesn't change the names using for
|
||||
/// whitelisting and blacklisting, that should still be mangled with the
|
||||
/// Note that this intentionally does not change the names used for
|
||||
/// whitelisting and blacklisting, which should still be mangled with the
|
||||
/// namespaces.
|
||||
///
|
||||
/// Note, also, that using this option may cause duplicated names to be
|
||||
/// generated.
|
||||
/// Note, also, that this option may cause bindgen to generate duplicate
|
||||
/// names.
|
||||
pub fn disable_name_namespacing(mut self) -> Builder {
|
||||
self.options.disable_name_namespacing = true;
|
||||
self
|
||||
|
@ -403,6 +712,16 @@ impl Builder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Whether inline functions should be generated or not.
|
||||
///
|
||||
/// Note that they will usually not work. However you can use
|
||||
/// `-fkeep-inline-functions` or `-fno-inline-functions` if you are
|
||||
/// responsible of compiling the library to make them callable.
|
||||
pub fn generate_inline_functions(mut self, doit: bool) -> Self {
|
||||
self.options.generate_inline_functions = doit;
|
||||
self
|
||||
}
|
||||
|
||||
/// Ignore functions.
|
||||
pub fn ignore_functions(mut self) -> Builder {
|
||||
self.options.codegen_config.functions = false;
|
||||
|
@ -433,19 +752,26 @@ impl Builder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Allows configuring types in different situations, see the `TypeChooser`
|
||||
/// documentation.
|
||||
pub fn type_chooser(mut self, cb: Box<chooser::TypeChooser>) -> Self {
|
||||
self.options.type_chooser = Some(cb);
|
||||
/// Allows configuring types in different situations, see the
|
||||
/// [`ParseCallbacks`](./callbacks/trait.ParseCallbacks.html) documentation.
|
||||
pub fn parse_callbacks(mut self, cb: Box<callbacks::ParseCallbacks>) -> Self {
|
||||
self.options.parse_callbacks = Some(cb);
|
||||
self
|
||||
}
|
||||
|
||||
/// Choose what to generate using a CodegenConfig.
|
||||
/// Choose what to generate using a
|
||||
/// [`CodegenConfig`](./struct.CodegenConfig.html).
|
||||
pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self {
|
||||
self.options.codegen_config = config;
|
||||
self
|
||||
}
|
||||
|
||||
/// Prepend the enum name to constant or bitfield variants.
|
||||
pub fn prepend_enum_name(mut self, doit: bool) -> Self {
|
||||
self.options.prepend_enum_name = doit;
|
||||
self
|
||||
}
|
||||
|
||||
/// Generate the Rust bindings using the options built up thus far.
|
||||
pub fn generate<'ctx>(self) -> Result<Bindings<'ctx>, ()> {
|
||||
Bindings::generate(self.options, None)
|
||||
|
@ -508,11 +834,14 @@ pub struct BindgenOptions {
|
|||
/// True if we should avoid mangling names with namespaces.
|
||||
pub disable_name_namespacing: bool,
|
||||
|
||||
/// True if we shold derive Debug trait implementations for C/C++ structures
|
||||
/// True if we should generate layout tests for generated structures.
|
||||
pub layout_tests: bool,
|
||||
|
||||
/// True if we should derive Debug trait implementations for C/C++ structures
|
||||
/// and types.
|
||||
pub derive_debug: bool,
|
||||
|
||||
/// True if we shold derive Default trait implementations for C/C++ structures
|
||||
/// True if we should derive Default trait implementations for C/C++ structures
|
||||
/// and types.
|
||||
pub derive_default: bool,
|
||||
|
||||
|
@ -545,13 +874,16 @@ pub struct BindgenOptions {
|
|||
/// The input header file.
|
||||
pub input_header: Option<String>,
|
||||
|
||||
/// Unsaved files for input.
|
||||
pub input_unsaved_files: Vec<clang::UnsavedFile>,
|
||||
|
||||
/// Generate a dummy C/C++ file that includes the header and has dummy uses
|
||||
/// of all types defined therein. See the `uses` module for more.
|
||||
pub dummy_uses: Option<String>,
|
||||
|
||||
/// A user-provided type chooser to allow customizing different kinds of
|
||||
/// A user-provided visitor to allow customizing different kinds of
|
||||
/// situations.
|
||||
pub type_chooser: Option<Box<chooser::TypeChooser>>,
|
||||
pub parse_callbacks: Option<Box<callbacks::ParseCallbacks>>,
|
||||
|
||||
/// Which kind of items should we generate? By default, we'll generate all
|
||||
/// of them.
|
||||
|
@ -566,12 +898,27 @@ pub struct BindgenOptions {
|
|||
/// documentation for more details.
|
||||
pub generate_comments: bool,
|
||||
|
||||
/// Whether to generate inline functions. Defaults to false.
|
||||
pub generate_inline_functions: bool,
|
||||
|
||||
/// Wether to whitelist types recursively. Defaults to true.
|
||||
pub whitelist_recursively: bool,
|
||||
|
||||
/// Intead of emitting 'use objc;' to files generated from objective c files,
|
||||
/// generate '#[macro_use] extern crate objc;'
|
||||
pub objc_extern_crate: bool,
|
||||
|
||||
/// Whether to use the clang-provided name mangling. This is true and
|
||||
/// probably needed for C++ features.
|
||||
///
|
||||
/// However, some old libclang versions seem to return incorrect results in
|
||||
/// some cases for non-mangled functions, see [1], so we allow disabling it.
|
||||
///
|
||||
/// [1]: https://github.com/servo/rust-bindgen/issues/528
|
||||
pub enable_mangling: bool,
|
||||
|
||||
/// Whether to prepend the enum name to bitfield or constant variants.
|
||||
pub prepend_enum_name: bool,
|
||||
}
|
||||
|
||||
/// TODO(emilio): This is sort of a lie (see the error message that results from
|
||||
|
@ -606,6 +953,7 @@ impl Default for BindgenOptions {
|
|||
emit_ast: false,
|
||||
emit_ir: false,
|
||||
emit_ir_graphviz: None,
|
||||
layout_tests: true,
|
||||
derive_debug: true,
|
||||
derive_default: false,
|
||||
enable_cxx_namespaces: false,
|
||||
|
@ -619,13 +967,17 @@ impl Default for BindgenOptions {
|
|||
raw_lines: vec![],
|
||||
clang_args: vec![],
|
||||
input_header: None,
|
||||
input_unsaved_files: vec![],
|
||||
dummy_uses: None,
|
||||
type_chooser: None,
|
||||
parse_callbacks: None,
|
||||
codegen_config: CodegenConfig::all(),
|
||||
conservative_inline_namespaces: false,
|
||||
generate_comments: true,
|
||||
generate_inline_functions: false,
|
||||
whitelist_recursively: true,
|
||||
objc_extern_crate: false,
|
||||
enable_mangling: true,
|
||||
prepend_enum_name: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -653,23 +1005,15 @@ fn ensure_libclang_is_loaded() {
|
|||
// across different threads.
|
||||
|
||||
lazy_static! {
|
||||
static ref LIBCLANG: Mutex<Option<Arc<clang_sys::SharedLibrary>>> = {
|
||||
Mutex::new(None)
|
||||
static ref LIBCLANG: Arc<clang_sys::SharedLibrary> = {
|
||||
clang_sys::load().expect("Unable to find libclang");
|
||||
clang_sys::get_library()
|
||||
.expect("We just loaded libclang and it had better still be \
|
||||
here!")
|
||||
};
|
||||
}
|
||||
|
||||
let mut libclang = LIBCLANG.lock().unwrap();
|
||||
if !clang_sys::is_loaded() {
|
||||
if libclang.is_none() {
|
||||
// TODO(emilio): Return meaningful error (breaking).
|
||||
clang_sys::load().expect("Unable to find libclang");
|
||||
*libclang = Some(clang_sys::get_library()
|
||||
.expect("We just loaded libclang and it had \
|
||||
better still be here!"));
|
||||
} else {
|
||||
clang_sys::set_library(libclang.clone());
|
||||
}
|
||||
}
|
||||
clang_sys::set_library(Some(LIBCLANG.clone()));
|
||||
}
|
||||
|
||||
/// Generated Rust bindings.
|
||||
|
@ -716,6 +1060,10 @@ impl<'ctx> Bindings<'ctx> {
|
|||
options.clang_args.push(h.clone())
|
||||
}
|
||||
|
||||
for f in options.input_unsaved_files.iter() {
|
||||
options.clang_args.push(f.name.to_str().unwrap().to_owned())
|
||||
}
|
||||
|
||||
let mut context = BindgenContext::new(options);
|
||||
try!(parse(&mut context));
|
||||
|
||||
|
@ -802,12 +1150,7 @@ impl<'ctx> Bindings<'ctx> {
|
|||
/// Determines whether the given cursor is in any of the files matched by the
|
||||
/// options.
|
||||
fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
|
||||
let (file, _, _, _) = cursor.location().location();
|
||||
|
||||
match file.name() {
|
||||
None => ctx.options().builtins,
|
||||
Some(..) => true,
|
||||
}
|
||||
ctx.options().builtins || !cursor.is_builtin()
|
||||
}
|
||||
|
||||
/// Parse one `Item` from the Clang cursor.
|
||||
|
@ -847,8 +1190,17 @@ fn parse(context: &mut BindgenContext) -> Result<(), ()> {
|
|||
}
|
||||
|
||||
let cursor = context.translation_unit().cursor();
|
||||
|
||||
if context.options().emit_ast {
|
||||
cursor.visit(|cur| clang::ast_dump(&cur, 0));
|
||||
|
||||
fn dump_if_not_builtin(cur: &clang::Cursor) -> CXChildVisitResult {
|
||||
if !cur.is_builtin() {
|
||||
clang::ast_dump(&cur, 0)
|
||||
} else {
|
||||
CXChildVisit_Continue
|
||||
}
|
||||
}
|
||||
cursor.visit(|cur| dump_if_not_builtin(&cur));
|
||||
}
|
||||
|
||||
let root = context.root_module();
|
||||
|
@ -904,3 +1256,38 @@ pub fn clang_version() -> ClangVersion {
|
|||
full: raw_v.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Test command_line_flag function.
|
||||
#[test]
|
||||
fn commandline_flag_unit_test_function() {
|
||||
//Test 1
|
||||
let bindings = ::builder();
|
||||
let command_line_flags = bindings.command_line_flags();
|
||||
|
||||
let test_cases = vec!["--no-derive-default",
|
||||
"--generate", "function,types,vars,methods,constructors,destructors"]
|
||||
.iter()
|
||||
.map(|&x| x.into())
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
assert!(test_cases.iter().all(|ref x| command_line_flags.contains(x)) );
|
||||
|
||||
//Test 2
|
||||
let bindings = ::builder().header("input_header")
|
||||
.whitelisted_type("Distinct_Type")
|
||||
.whitelisted_function("safe_function");
|
||||
|
||||
let command_line_flags = bindings.command_line_flags();
|
||||
let test_cases = vec!["input_header",
|
||||
"--no-derive-default",
|
||||
"--generate", "function,types,vars,methods,constructors,destructors",
|
||||
"--whitelist-type", "Distinct_Type",
|
||||
"--whitelist-function", "safe_function"]
|
||||
.iter()
|
||||
.map(|&x| x.into())
|
||||
.collect::<Vec<String>>();
|
||||
println!("{:?}", command_line_flags);
|
||||
|
||||
assert!(test_cases.iter().all(|ref x| command_line_flags.contains(x)) );
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
macro_rules! log {
|
||||
(target: $target:expr, $lvl:expr, $($arg)+) => {
|
||||
(target: $target:expr, $lvl:expr, $($arg:tt)+) => {
|
||||
let _ = $target;
|
||||
let _ = log!($lvl, $($arg)+);
|
||||
};
|
||||
($lvl:expr, $($arg:tt)+) => {
|
||||
($lvl:expr, $($arg:tt)+) => {{
|
||||
let _ = $lvl;
|
||||
let _ = format_args!($($arg)+);
|
||||
};
|
||||
}};
|
||||
}
|
||||
macro_rules! error {
|
||||
(target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
|
||||
|
|
|
@ -1,19 +1,25 @@
|
|||
extern crate bindgen;
|
||||
#[cfg(feature="logging")]
|
||||
extern crate env_logger;
|
||||
#[macro_use]
|
||||
#[cfg(feature="logging")]
|
||||
extern crate log;
|
||||
extern crate clang_sys;
|
||||
extern crate clap;
|
||||
extern crate rustc_serialize;
|
||||
|
||||
use bindgen::clang_version;
|
||||
use std::env;
|
||||
use std::panic;
|
||||
|
||||
#[macro_use]
|
||||
#[cfg(not(feature="logging"))]
|
||||
mod log_stubs;
|
||||
|
||||
mod options;
|
||||
use options::builder_from_flags;
|
||||
|
||||
pub fn main() {
|
||||
#[cfg(feature="logging")]
|
||||
log::set_logger(|max_log_level| {
|
||||
use env_logger::Logger;
|
||||
let env_logger = Logger::new();
|
||||
|
|
|
@ -35,11 +35,14 @@ pub fn builder_from_flags<I>
|
|||
.number_of_values(1),
|
||||
Arg::with_name("blacklist-type")
|
||||
.long("blacklist-type")
|
||||
.help("Mark a type as hidden.")
|
||||
.help("Mark <type> as hidden.")
|
||||
.value_name("type")
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.number_of_values(1),
|
||||
Arg::with_name("no-layout-tests")
|
||||
.long("no-layout-tests")
|
||||
.help("Avoid generating layout tests for any type."),
|
||||
Arg::with_name("no-derive-debug")
|
||||
.long("no-derive-debug")
|
||||
.help("Avoid deriving Debug on any type."),
|
||||
|
@ -49,17 +52,20 @@ pub fn builder_from_flags<I>
|
|||
.help("Avoid deriving Default on any type."),
|
||||
Arg::with_name("with-derive-default")
|
||||
.long("with-derive-default")
|
||||
.help("Deriving Default on any type."),
|
||||
.help("Derive Default on any type."),
|
||||
Arg::with_name("no-doc-comments")
|
||||
.long("no-doc-comments")
|
||||
.help("Avoid including doc comments in the output, see: \
|
||||
https://github.com/servo/rust-bindgen/issues/426"),
|
||||
Arg::with_name("no-recursive-whitelist")
|
||||
.long("no-recursive-whitelist")
|
||||
.help("Avoid whitelisting types recursively"),
|
||||
.help("Avoid whitelisting types recursively."),
|
||||
Arg::with_name("objc-extern-crate")
|
||||
.long("objc-extern-crate")
|
||||
.help("Use extern crate instead of use for objc"),
|
||||
.help("Use extern crate instead of use for objc."),
|
||||
Arg::with_name("distrust-clang-mangling")
|
||||
.long("distrust-clang-mangling")
|
||||
.help("Do not trust the libclang-provided mangling"),
|
||||
Arg::with_name("builtins")
|
||||
.long("builtins")
|
||||
.help("Output bindings for builtin definitions, e.g. \
|
||||
|
@ -94,7 +100,9 @@ pub fn builder_from_flags<I>
|
|||
.help("Enable support for C++ namespaces."),
|
||||
Arg::with_name("disable-name-namespacing")
|
||||
.long("disable-name-namespacing")
|
||||
.help("Disable name namespacing if namespaces are disabled."),
|
||||
.help("Disable namespacing via mangling, causing bindgen to \
|
||||
generate names like \"Baz\" instead of \"foo_bar_Baz\" \
|
||||
for an input name \"foo::bar::Baz\"."),
|
||||
Arg::with_name("framework")
|
||||
.long("framework-link")
|
||||
.help("Link to framework.")
|
||||
|
@ -107,9 +115,9 @@ pub fn builder_from_flags<I>
|
|||
is useful when you only care about struct layouts."),
|
||||
Arg::with_name("generate")
|
||||
.long("generate")
|
||||
.help("Generate a given kind of items, split by commas. \
|
||||
Valid values are \"functions\",\"types\", \"vars\" and \
|
||||
\"methods\".")
|
||||
.help("Generate only given items, split by commas. \
|
||||
Valid values are \"functions\",\"types\", \"vars\", \
|
||||
\"methods\", \"constructors\" and \"destructors\".")
|
||||
.takes_value(true),
|
||||
Arg::with_name("ignore-methods")
|
||||
.long("ignore-methods")
|
||||
|
@ -123,14 +131,17 @@ pub fn builder_from_flags<I>
|
|||
.number_of_values(1),
|
||||
Arg::with_name("no-convert-floats")
|
||||
.long("no-convert-floats")
|
||||
.help("Don't automatically convert floats to f32/f64."),
|
||||
.help("Do not automatically convert floats to f32/f64."),
|
||||
Arg::with_name("no-prepend-enum-name")
|
||||
.long("no-prepend-enum-name")
|
||||
.help("Do not prepend the enum name to bitfield or constant variants."),
|
||||
Arg::with_name("no-unstable-rust")
|
||||
.long("no-unstable-rust")
|
||||
.help("Do not generate unstable Rust code.")
|
||||
.multiple(true), // FIXME: Pass legacy test suite
|
||||
Arg::with_name("opaque-type")
|
||||
.long("opaque-type")
|
||||
.help("Mark a type as opaque.")
|
||||
.help("Mark <type> as opaque.")
|
||||
.value_name("type")
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
|
@ -171,6 +182,9 @@ pub fn builder_from_flags<I>
|
|||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.number_of_values(1),
|
||||
Arg::with_name("generate-inline-functions")
|
||||
.long("generate-inline-functions")
|
||||
.help("Generate inline functions."),
|
||||
Arg::with_name("whitelist-type")
|
||||
.long("whitelist-type")
|
||||
.help("Whitelist the type. Other non-whitelisted types will \
|
||||
|
@ -190,7 +204,7 @@ pub fn builder_from_flags<I>
|
|||
.number_of_values(1),
|
||||
Arg::with_name("verbose")
|
||||
.long("verbose")
|
||||
.help("Print verbose error messages"),
|
||||
.help("Print verbose error messages."),
|
||||
]) // .args()
|
||||
.get_matches_from(args);
|
||||
|
||||
|
@ -224,6 +238,10 @@ pub fn builder_from_flags<I>
|
|||
builder = builder.emit_builtins();
|
||||
}
|
||||
|
||||
if matches.is_present("no-layout-tests") {
|
||||
builder = builder.layout_tests(false);
|
||||
}
|
||||
|
||||
if matches.is_present("no-derive-debug") {
|
||||
builder = builder.derive_debug(false);
|
||||
}
|
||||
|
@ -236,6 +254,10 @@ pub fn builder_from_flags<I>
|
|||
builder = builder.derive_default(false);
|
||||
}
|
||||
|
||||
if matches.is_present("no-prepend-enum-name") {
|
||||
builder = builder.prepend_enum_name(false);
|
||||
}
|
||||
|
||||
if let Some(prefix) = matches.value_of("ctypes-prefix") {
|
||||
builder = builder.ctypes_prefix(prefix);
|
||||
}
|
||||
|
@ -258,6 +280,8 @@ pub fn builder_from_flags<I>
|
|||
"types" => config.types = true,
|
||||
"vars" => config.vars = true,
|
||||
"methods" => config.methods = true,
|
||||
"constructors" => config.constructors = true,
|
||||
"destructors" => config.destructors = true,
|
||||
_ => {
|
||||
return Err(Error::new(ErrorKind::Other,
|
||||
"Unknown generate item"));
|
||||
|
@ -317,6 +341,10 @@ pub fn builder_from_flags<I>
|
|||
builder = builder.whitelist_recursively(false);
|
||||
}
|
||||
|
||||
if matches.is_present("objc-extern-crate") {
|
||||
builder = builder.objc_extern_crate(true);
|
||||
}
|
||||
|
||||
if let Some(opaque_types) = matches.values_of("opaque-type") {
|
||||
for ty in opaque_types {
|
||||
builder = builder.opaque_type(ty);
|
||||
|
@ -339,10 +367,18 @@ pub fn builder_from_flags<I>
|
|||
builder = builder.use_core();
|
||||
}
|
||||
|
||||
if matches.is_present("distrust-clang-mangling") {
|
||||
builder = builder.trust_clang_mangling(false);
|
||||
}
|
||||
|
||||
if matches.is_present("conservative-inline-namespaces") {
|
||||
builder = builder.conservative_inline_namespaces();
|
||||
}
|
||||
|
||||
if matches.is_present("generate-inline-functions") {
|
||||
builder = builder.generate_inline_functions(true);
|
||||
}
|
||||
|
||||
if let Some(whitelist) = matches.values_of("whitelist-function") {
|
||||
for regex in whitelist {
|
||||
builder = builder.whitelisted_function(regex);
|
||||
|
|
|
@ -49,7 +49,7 @@ pub trait ClangItemParser: Sized {
|
|||
|
||||
/// Parse this item from the given Clang type.
|
||||
fn from_ty(ty: &clang::Type,
|
||||
location: Option<clang::Cursor>,
|
||||
location: clang::Cursor,
|
||||
parent: Option<ItemId>,
|
||||
ctx: &mut BindgenContext)
|
||||
-> Result<ItemId, ParseError>;
|
||||
|
@ -58,7 +58,7 @@ pub trait ClangItemParser: Sized {
|
|||
/// newly parsed item.
|
||||
fn from_ty_with_id(id: ItemId,
|
||||
ty: &clang::Type,
|
||||
location: Option<clang::Cursor>,
|
||||
location: clang::Cursor,
|
||||
parent: Option<ItemId>,
|
||||
ctx: &mut BindgenContext)
|
||||
-> Result<ItemId, ParseError>;
|
||||
|
@ -66,7 +66,7 @@ pub trait ClangItemParser: Sized {
|
|||
/// Parse this item from the given Clang type, or if we haven't resolved all
|
||||
/// the other items this one depends on, an unresolved reference.
|
||||
fn from_ty_or_ref(ty: clang::Type,
|
||||
location: Option<clang::Cursor>,
|
||||
location: clang::Cursor,
|
||||
parent_id: Option<ItemId>,
|
||||
context: &mut BindgenContext)
|
||||
-> ItemId;
|
||||
|
@ -75,26 +75,16 @@ pub trait ClangItemParser: Sized {
|
|||
/// `ItemId` for the newly parsed item.
|
||||
fn from_ty_or_ref_with_id(potential_id: ItemId,
|
||||
ty: clang::Type,
|
||||
location: Option<clang::Cursor>,
|
||||
location: clang::Cursor,
|
||||
parent_id: Option<ItemId>,
|
||||
context: &mut BindgenContext)
|
||||
-> ItemId;
|
||||
|
||||
/// Create a named template type.
|
||||
fn named_type<S>(name: S,
|
||||
parent: ItemId,
|
||||
context: &mut BindgenContext)
|
||||
-> ItemId
|
||||
where S: Into<String>;
|
||||
|
||||
/// Identical to `named_type`, but use `id` as the resulting item's
|
||||
/// `ItemId`.
|
||||
fn named_type_with_id<S>(id: ItemId,
|
||||
name: S,
|
||||
parent: ItemId,
|
||||
context: &mut BindgenContext)
|
||||
-> ItemId
|
||||
where S: Into<String>;
|
||||
fn named_type(with_id: Option<ItemId>,
|
||||
location: clang::Cursor,
|
||||
ctx: &mut BindgenContext)
|
||||
-> Option<ItemId>;
|
||||
|
||||
/// Create a builtin type.
|
||||
fn builtin_type(kind: TypeKind,
|
||||
|
|
|
@ -36,6 +36,15 @@ impl RegexSet {
|
|||
self.set = None;
|
||||
}
|
||||
|
||||
/// Returns slice of String from its field 'items'
|
||||
pub fn get_items(&self) -> &[String] {
|
||||
&self.items[..]
|
||||
}
|
||||
/// Returns reference of its field 'set'
|
||||
pub fn get_set(&self) -> Option<&RxSet> {
|
||||
self.set.as_ref()
|
||||
}
|
||||
|
||||
/// Construct a RegexSet from the set of entries we've accumulated.
|
||||
///
|
||||
/// Must be called before calling `matches()`, or it will always return
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
use ir::context::BindgenContext;
|
||||
use ir::item::{Item, ItemAncestors, ItemCanonicalName};
|
||||
use ir::template::TemplateParameters;
|
||||
use std::io;
|
||||
|
||||
// Like `canonical_path`, except we always take namespaces into account, ignore
|
||||
|
@ -83,9 +84,9 @@ pub fn generate_dummy_uses<W>(ctx: &mut BindgenContext,
|
|||
// these.
|
||||
!ty.is_builtin_or_named() &&
|
||||
// And finally, we won't be creating any dummy
|
||||
// specializations, so ignore template declarations and
|
||||
// partial specializations.
|
||||
item.applicable_template_args(ctx).is_empty()
|
||||
// instantiations, so ignore template declarations and
|
||||
// instantiations.
|
||||
item.all_template_params(ctx).is_none()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
struct rte_ipv4_tuple {
|
||||
uint32_t src_addr;
|
||||
uint32_t dst_addr;
|
||||
union {
|
||||
struct {
|
||||
uint16_t dport;
|
||||
uint16_t sport;
|
||||
};
|
||||
uint32_t sctp_tag;
|
||||
};
|
||||
};
|
||||
|
||||
struct rte_ipv6_tuple {
|
||||
uint8_t src_addr[16];
|
||||
uint8_t dst_addr[16];
|
||||
union {
|
||||
struct {
|
||||
uint16_t dport;
|
||||
uint16_t sport;
|
||||
};
|
||||
uint32_t sctp_tag;
|
||||
};
|
||||
};
|
||||
|
||||
union rte_thash_tuple {
|
||||
struct rte_ipv4_tuple v4;
|
||||
struct rte_ipv6_tuple v6;
|
||||
} __attribute__((aligned(16)));
|
|
@ -1,7 +0,0 @@
|
|||
// bindgen-flags: -- -std=c++11
|
||||
|
||||
namespace std {
|
||||
template<typename _Alloc> struct allocator_traits {
|
||||
typedef decltype ( _S_size_type_helper ( ( _Alloc * ) 0 ) ) __size_type;
|
||||
};
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
struct SomeAccessors {
|
||||
int mNoAccessor;
|
||||
/** <div rustbindgen accessor></div> */
|
||||
int mBothAccessors;
|
||||
/** <div rustbindgen accessor="unsafe"></div> */
|
||||
int mUnsafeAccessors;
|
||||
/** <div rustbindgen accessor="immutable"></div> */
|
||||
int mImmutableAccessor;
|
||||
};
|
||||
|
||||
/** <div rustbindgen accessor></div> */
|
||||
struct AllAccessors {
|
||||
int mBothAccessors;
|
||||
int mAlsoBothAccessors;
|
||||
};
|
||||
|
||||
/** <div rustbindgen accessor="unsafe"></div> */
|
||||
struct AllUnsafeAccessors {
|
||||
int mBothAccessors;
|
||||
int mAlsoBothAccessors;
|
||||
};
|
||||
|
||||
/** <div rustbindgen accessor></div> */
|
||||
struct ContradictAccessors {
|
||||
int mBothAccessors;
|
||||
/** <div rustbindgen accessor="false"></div> */
|
||||
int mNoAccessors;
|
||||
/** <div rustbindgen accessor="unsafe"></div> */
|
||||
int mUnsafeAccessors;
|
||||
/** <div rustbindgen accessor="immutable"></div> */
|
||||
int mImmutableAccessor;
|
||||
};
|
||||
|
||||
/** <div rustbindgen accessor replaces="Replaced"></div> */
|
||||
struct Replacing {
|
||||
int mAccessor;
|
||||
};
|
||||
|
||||
struct Replaced {
|
||||
int noOp;
|
||||
};
|
||||
|
||||
/** <div rustbindgen accessor></div> */
|
||||
struct Wrapper {
|
||||
Replaced mReplaced;
|
||||
};
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
/**
|
||||
* <div rustbindgen="true" hide="true"></div>
|
||||
*/
|
||||
struct C;
|
||||
|
||||
/**
|
||||
* <div rustbindgen opaque></div>
|
||||
*/
|
||||
struct D {
|
||||
int a;
|
||||
};
|
||||
|
||||
struct NotAnnotated {
|
||||
int f;
|
||||
};
|
|
@ -1,10 +0,0 @@
|
|||
struct Test {
|
||||
int foo;
|
||||
float bar;
|
||||
enum { T_NONE };
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
Foo,
|
||||
Bar,
|
||||
} Baz;
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
template<typename _Tp>
|
||||
class DataType {
|
||||
public:
|
||||
typedef _Tp value_type;
|
||||
typedef value_type work_type;
|
||||
typedef value_type channel_type;
|
||||
typedef value_type vec_type;
|
||||
enum { generic_type = 1,
|
||||
depth = -1,
|
||||
channels = 1,
|
||||
fmt = 0,
|
||||
type = -1,
|
||||
};
|
||||
};
|
||||
|
||||
struct Foo {
|
||||
enum {
|
||||
Bar = 0,
|
||||
Baz = 0,
|
||||
};
|
||||
};
|
|
@ -1,6 +0,0 @@
|
|||
// bindgen-flags: --whitelist-var NODE_.*
|
||||
|
||||
enum {
|
||||
NODE_FLAG_FOO,
|
||||
NODE_FLAG_BAR,
|
||||
};
|
|
@ -1,20 +0,0 @@
|
|||
template<typename T>
|
||||
struct TErrorResult {
|
||||
enum UnionState {
|
||||
HasMessage,
|
||||
HasException,
|
||||
};
|
||||
int mResult;
|
||||
struct Message;
|
||||
struct DOMExceptionInfo;
|
||||
union {
|
||||
Message* mMessage;
|
||||
DOMExceptionInfo* mDOMExceptionInfo;
|
||||
};
|
||||
|
||||
bool mMightHaveUnreported;
|
||||
UnionState mUnionState;
|
||||
};
|
||||
|
||||
struct ErrorResult : public TErrorResult<int> {
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
void foo(const char* type);
|
|
@ -1,19 +0,0 @@
|
|||
// bindgen-flags: -- -std=c++14
|
||||
// bindgen-unstable
|
||||
|
||||
class Foo {
|
||||
static constexpr auto kFoo = 2 == 2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Bar {
|
||||
static const constexpr auto kBar = T(1);
|
||||
};
|
||||
|
||||
template<typename T> auto Test1() {
|
||||
return T(1);
|
||||
}
|
||||
|
||||
auto Test2() {
|
||||
return Test1<unsigned int>();
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
namespace std
|
||||
{
|
||||
template < typename > struct char_traits;
|
||||
}
|
||||
namespace __gnu_cxx
|
||||
{
|
||||
template < typename > struct char_traits;
|
||||
}
|
||||
namespace std
|
||||
{
|
||||
template < class _CharT > struct char_traits:__gnu_cxx::char_traits <
|
||||
_CharT >
|
||||
{
|
||||
};
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// bindgen-flags: -- -std=c++11
|
||||
|
||||
struct false_type {};
|
||||
|
||||
template<typename _From, typename _To, bool>
|
||||
struct __is_base_to_derived_ref;
|
||||
|
||||
template<typename _From, typename _To>
|
||||
struct __is_base_to_derived_ref<_From, _To, true>
|
||||
{
|
||||
typedef _To type;
|
||||
|
||||
static constexpr bool value = type::value;
|
||||
};
|
||||
|
||||
template<typename _From, typename _To>
|
||||
struct __is_base_to_derived_ref<_From, _To, false>
|
||||
: public false_type
|
||||
{ };
|
|
@ -1,27 +0,0 @@
|
|||
// bindgen-flags: --bitfield-enum "Foo|Buz|NS_.*|DUMMY_.*" -- -std=c++11
|
||||
|
||||
enum Foo {
|
||||
Bar = 1 << 1,
|
||||
Baz = 1 << 2,
|
||||
Duplicated = 1 << 2,
|
||||
Negative = -3,
|
||||
};
|
||||
|
||||
enum class Buz : signed char {
|
||||
Bar = 1 << 1,
|
||||
Baz = 1 << 2,
|
||||
Duplicated = 1 << 2,
|
||||
Negative = -3,
|
||||
};
|
||||
|
||||
enum {
|
||||
NS_FOO = 1 << 0,
|
||||
NS_BAR = 1 << 1,
|
||||
};
|
||||
|
||||
class Dummy {
|
||||
enum {
|
||||
DUMMY_FOO = 1 << 0,
|
||||
DUMMY_BAR = 1 << 1,
|
||||
};
|
||||
};
|
|
@ -1,41 +0,0 @@
|
|||
struct A {
|
||||
unsigned char x;
|
||||
unsigned b1 : 1;
|
||||
unsigned b2 : 1;
|
||||
unsigned b3 : 1;
|
||||
unsigned b4 : 1;
|
||||
unsigned b5 : 1;
|
||||
unsigned b6 : 1;
|
||||
unsigned b7 : 1;
|
||||
unsigned b8 : 1;
|
||||
unsigned b9 : 1;
|
||||
unsigned b10 : 1;
|
||||
unsigned char y;
|
||||
};
|
||||
|
||||
struct B {
|
||||
unsigned foo : 31;
|
||||
unsigned char bar : 1;
|
||||
};
|
||||
|
||||
struct C {
|
||||
unsigned char x;
|
||||
unsigned b1 : 1;
|
||||
unsigned b2 : 1;
|
||||
unsigned baz;
|
||||
};
|
||||
|
||||
struct Date1 {
|
||||
unsigned short nWeekDay : 3; // 0..7 (3 bits)
|
||||
unsigned short nMonthDay : 6; // 0..31 (6 bits)
|
||||
unsigned short nMonth : 5; // 0..12 (5 bits)
|
||||
unsigned short nYear : 8; // 0..100 (8 bits)
|
||||
};
|
||||
|
||||
struct Date2 {
|
||||
unsigned short nWeekDay : 3; // 0..7 (3 bits)
|
||||
unsigned short nMonthDay : 6; // 0..31 (6 bits)
|
||||
unsigned short nMonth : 5; // 0..12 (5 bits)
|
||||
unsigned short nYear : 8; // 0..100 (8 bits)
|
||||
unsigned char byte;
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
typedef struct
|
||||
{
|
||||
unsigned int pad3: 24;
|
||||
unsigned int type: 8;
|
||||
} mach_msg_type_descriptor_t;
|
|
@ -1,3 +0,0 @@
|
|||
// bindgen-flags: -- -fblocks
|
||||
|
||||
void atexit_b(void (^)(void));
|
|
@ -1,7 +0,0 @@
|
|||
// bindgen-flags: --disable-name-namespacing
|
||||
|
||||
namespace foo {
|
||||
struct Bar {};
|
||||
}
|
||||
|
||||
void baz(foo::Bar*);
|
|
@ -1,56 +0,0 @@
|
|||
class C {
|
||||
int a;
|
||||
// More than rust limits (32)
|
||||
char big_array[33];
|
||||
};
|
||||
|
||||
class C_with_zero_length_array {
|
||||
int a;
|
||||
// More than rust limits (32)
|
||||
char big_array[33];
|
||||
char zero_length_array[0];
|
||||
};
|
||||
|
||||
class C_with_incomplete_array {
|
||||
int a;
|
||||
// More than rust limits (32)
|
||||
char big_array[33];
|
||||
char incomplete_array[];
|
||||
};
|
||||
|
||||
class C_with_zero_length_array_and_incomplete_array {
|
||||
int a;
|
||||
// More than rust limits (32)
|
||||
char big_array[33];
|
||||
char zero_length_array[0];
|
||||
char incomplete_array[];
|
||||
};
|
||||
|
||||
class WithDtor {
|
||||
int b;
|
||||
|
||||
~WithDtor() {}
|
||||
};
|
||||
|
||||
class IncompleteArrayNonCopiable {
|
||||
void* whatever;
|
||||
C incomplete_array[];
|
||||
};
|
||||
|
||||
union Union {
|
||||
float d;
|
||||
int i;
|
||||
};
|
||||
|
||||
class WithUnion {
|
||||
Union data;
|
||||
};
|
||||
|
||||
class RealAbstractionWithTonsOfMethods {
|
||||
void foo();
|
||||
public:
|
||||
void bar() const;
|
||||
void bar();
|
||||
void bar(int foo);
|
||||
static void sta();
|
||||
};
|
|
@ -1,36 +0,0 @@
|
|||
class A {
|
||||
public:
|
||||
int member_a;
|
||||
class B {
|
||||
int member_b;
|
||||
};
|
||||
|
||||
class C;
|
||||
|
||||
template<typename T>
|
||||
class D {
|
||||
T foo;
|
||||
};
|
||||
};
|
||||
|
||||
class A::C {
|
||||
int baz;
|
||||
};
|
||||
|
||||
A::B var;
|
||||
A::D<int> baz;
|
||||
|
||||
class D {
|
||||
A::B member;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Templated {
|
||||
T member;
|
||||
|
||||
class Templated_inner {
|
||||
public:
|
||||
T* member_ptr;
|
||||
void get() {}
|
||||
};
|
||||
};
|
|
@ -1,16 +0,0 @@
|
|||
// bindgen-flags: -- -std=c++11
|
||||
|
||||
class whatever {
|
||||
};
|
||||
|
||||
class whatever_child: public whatever {
|
||||
};
|
||||
|
||||
class whatever_child_with_member: public whatever {
|
||||
public:
|
||||
int m_member;
|
||||
};
|
||||
|
||||
static_assert(sizeof(whatever) == 1, "Testing!");
|
||||
static_assert(sizeof(whatever_child) == 1, "Testing!");
|
||||
static_assert(sizeof(whatever_child_with_member) == 4, "Testing!");
|
|
@ -1,7 +0,0 @@
|
|||
class MyClass {
|
||||
public:
|
||||
static const int* example;
|
||||
static const int* example_check_no_collision;
|
||||
};
|
||||
|
||||
static const int* example_check_no_collision;
|
|
@ -1,8 +0,0 @@
|
|||
using int32_t = int;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
class A {
|
||||
static const int a = 0;
|
||||
static const int32_t b = 077;
|
||||
static const uint32_t c = 0xff;
|
||||
};
|
|
@ -1,15 +0,0 @@
|
|||
|
||||
/**
|
||||
* <div rustbindgen="true" replaces="whatever"></div>
|
||||
*/
|
||||
struct whatever_replacement {
|
||||
int replacement;
|
||||
};
|
||||
|
||||
struct whatever {
|
||||
int b;
|
||||
};
|
||||
|
||||
struct container {
|
||||
whatever c;
|
||||
};
|
|
@ -1,13 +0,0 @@
|
|||
|
||||
|
||||
template <typename T>
|
||||
class HandleWithDtor {
|
||||
T* ptr;
|
||||
~HandleWithDtor() {}
|
||||
};
|
||||
|
||||
typedef HandleWithDtor<int> HandleValue;
|
||||
|
||||
class WithoutDtor {
|
||||
HandleValue shouldBeWithDtor;
|
||||
};
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче