зеркало из 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]
|
[package]
|
||||||
name = "aster"
|
name = "aster"
|
||||||
version = "0.38.0"
|
version = "0.41.0"
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
description = "A libsyntax ast builder"
|
description = "A libsyntax ast builder"
|
||||||
|
@ -12,9 +12,9 @@ with-syntex = ["syntex_syntax"]
|
||||||
unstable-testing = ["clippy", "compiletest_rs"]
|
unstable-testing = ["clippy", "compiletest_rs"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
syntex_syntax = { version = "^0.54.0", optional = true }
|
syntex_syntax = { version = "0.58", optional = true }
|
||||||
clippy = { version = "0.*", optional = true }
|
clippy = { version = "0.*", optional = true }
|
||||||
compiletest_rs = { version = "^0.2.0", optional = true }
|
compiletest_rs = { version = "0.2", optional = true }
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "test"
|
name = "test"
|
||||||
|
|
|
@ -1110,6 +1110,7 @@ impl<I, F> Invoke<P<ast::Expr>> for ExprStructFieldBuilder<I, F>
|
||||||
expr: expr,
|
expr: expr,
|
||||||
span: self.builder.span,
|
span: self.builder.span,
|
||||||
is_shorthand: false,
|
is_shorthand: false,
|
||||||
|
attrs: Vec::new().into(),
|
||||||
};
|
};
|
||||||
self.builder.fields.push(field);
|
self.builder.fields.push(field);
|
||||||
self.builder
|
self.builder
|
||||||
|
@ -1904,7 +1905,7 @@ impl<F: Invoke<P<ast::Expr>>> ExprSliceBuilder<F>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> F::Result {
|
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::ast;
|
||||||
use syntax::codemap::{DUMMY_SP, Span};
|
use syntax::codemap::{DUMMY_SP, Span};
|
||||||
use syntax::ptr::P;
|
|
||||||
|
|
||||||
use ident::ToIdent;
|
use ident::ToIdent;
|
||||||
use invoke::{Invoke, Identity};
|
use invoke::{Invoke, Identity};
|
||||||
|
@ -50,7 +49,7 @@ impl<F> GenericsBuilder<F>
|
||||||
callback: callback,
|
callback: callback,
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
lifetimes: generics.lifetimes,
|
lifetimes: generics.lifetimes,
|
||||||
ty_params: generics.ty_params.into_vec(),
|
ty_params: generics.ty_params,
|
||||||
predicates: generics.where_clause.predicates,
|
predicates: generics.where_clause.predicates,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,7 +199,7 @@ impl<F> GenericsBuilder<F>
|
||||||
|
|
||||||
pub fn strip_ty_params(mut self) -> Self {
|
pub fn strip_ty_params(mut self) -> Self {
|
||||||
for ty_param in &mut self.ty_params {
|
for ty_param in &mut self.ty_params {
|
||||||
ty_param.bounds = P::new();
|
ty_param.bounds = vec![];
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -213,7 +212,7 @@ impl<F> GenericsBuilder<F>
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(ast::Generics {
|
self.callback.invoke(ast::Generics {
|
||||||
lifetimes: self.lifetimes,
|
lifetimes: self.lifetimes,
|
||||||
ty_params: P::from_vec(self.ty_params),
|
ty_params: self.ty_params,
|
||||||
where_clause: ast::WhereClause {
|
where_clause: ast::WhereClause {
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
predicates: self.predicates,
|
predicates: self.predicates,
|
||||||
|
|
|
@ -909,7 +909,7 @@ impl<F> ItemTraitBuilder<F>
|
||||||
self.builder.build_item_kind(self.id, ast::ItemKind::Trait(
|
self.builder.build_item_kind(self.id, ast::ItemKind::Trait(
|
||||||
self.unsafety,
|
self.unsafety,
|
||||||
self.generics,
|
self.generics,
|
||||||
P::from_vec(self.bounds),
|
self.bounds,
|
||||||
self.items,
|
self.items,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -1123,7 +1123,7 @@ impl<F> ItemTraitTypeBuilder<F>
|
||||||
|
|
||||||
pub fn build_option_ty(self, ty: Option<P<ast::Ty>>) -> F::Result {
|
pub fn build_option_ty(self, ty: Option<P<ast::Ty>>) -> F::Result {
|
||||||
let bounds = P::from_vec(self.bounds);
|
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)
|
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 {
|
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>> {
|
pub fn range(self) -> ExprBuilder<PatRangeBuilder<F>> {
|
||||||
|
@ -432,6 +432,7 @@ impl<F> PatStructPathBuilder<F>
|
||||||
ident: id,
|
ident: id,
|
||||||
pat: pat,
|
pat: pat,
|
||||||
is_shorthand: true,
|
is_shorthand: true,
|
||||||
|
attrs: Vec::new().into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,6 +447,7 @@ impl<F> PatStructPathBuilder<F>
|
||||||
ident: id,
|
ident: id,
|
||||||
pat: pat,
|
pat: pat,
|
||||||
is_shorthand: true,
|
is_shorthand: true,
|
||||||
|
attrs: Vec::new().into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,6 +477,7 @@ impl<F> Invoke<P<ast::Pat>> for PatStructFieldBuilder<F>
|
||||||
ident: self.id,
|
ident: self.id,
|
||||||
pat: pat,
|
pat: pat,
|
||||||
is_shorthand: false,
|
is_shorthand: false,
|
||||||
|
attrs: Vec::new().into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -314,8 +314,8 @@ impl<F> PathSegmentBuilder<F>
|
||||||
} else {
|
} else {
|
||||||
let data = ast::AngleBracketedParameterData {
|
let data = ast::AngleBracketedParameterData {
|
||||||
lifetimes: self.lifetimes,
|
lifetimes: self.lifetimes,
|
||||||
types: P::from_vec(self.tys),
|
types: self.tys,
|
||||||
bindings: P::from_vec(self.bindings),
|
bindings: self.bindings,
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(P(ast::PathParameters::AngleBracketed(data)))
|
Some(P(ast::PathParameters::AngleBracketed(data)))
|
||||||
|
|
|
@ -199,13 +199,6 @@ impl<F> TyBuilder<F>
|
||||||
TyBuilder::with_callback(TyIteratorBuilder(self)).span(span)
|
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> {
|
pub fn impl_trait(self) -> TyImplTraitTyBuilder<F> {
|
||||||
TyImplTraitTyBuilder { builder: self, bounds: Vec::new() }
|
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> {
|
pub struct TyImplTraitTyBuilder<F> {
|
||||||
builder: TyBuilder<F>,
|
builder: TyBuilder<F>,
|
||||||
bounds: Vec<ast::TyParamBound>,
|
bounds: Vec<ast::TyParamBound>,
|
||||||
|
@ -588,8 +496,7 @@ impl<F> TyImplTraitTyBuilder<F>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
let bounds = P::from_vec(self.bounds);
|
self.builder.build_ty_kind(ast::TyKind::ImplTrait(self.bounds))
|
||||||
self.builder.build_ty_kind(ast::TyKind::ImplTrait(bounds))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl<F> TyParamBuilder<F>
|
||||||
callback: callback,
|
callback: callback,
|
||||||
span: ty_param.span,
|
span: ty_param.span,
|
||||||
id: ty_param.ident,
|
id: ty_param.ident,
|
||||||
bounds: ty_param.bounds.into_vec(),
|
bounds: ty_param.bounds,
|
||||||
default: ty_param.default,
|
default: ty_param.default,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ impl<F> TyParamBuilder<F>
|
||||||
attrs: ast::ThinVec::new(),
|
attrs: ast::ThinVec::new(),
|
||||||
ident: self.id,
|
ident: self.id,
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
bounds: P::from_vec(self.bounds),
|
bounds: self.bounds,
|
||||||
default: self.default,
|
default: self.default,
|
||||||
span: self.span,
|
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,
|
where P: IntoPath,
|
||||||
{
|
{
|
||||||
WhereEqPredicateBuilder {
|
WhereEqPredicateBuilder {
|
||||||
callback: self.callback,
|
callback: self.callback,
|
||||||
span: self.span,
|
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,
|
span: self.span,
|
||||||
bound_lifetimes: self.bound_lifetimes,
|
bound_lifetimes: self.bound_lifetimes,
|
||||||
bounded_ty: self.ty,
|
bounded_ty: self.ty,
|
||||||
bounds: P::from_vec(self.bounds),
|
bounds: self.bounds,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.callback.invoke(ast::WherePredicate::BoundPredicate(predicate))
|
self.callback.invoke(ast::WherePredicate::BoundPredicate(predicate))
|
||||||
|
@ -302,7 +302,7 @@ impl<F> WhereRegionPredicateBuilder<F>
|
||||||
pub struct WhereEqPredicateBuilder<F> {
|
pub struct WhereEqPredicateBuilder<F> {
|
||||||
callback: F,
|
callback: F,
|
||||||
span: Span,
|
span: Span,
|
||||||
path: ast::Path,
|
lhs: P<ast::Ty>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> WhereEqPredicateBuilder<F>
|
impl<F> WhereEqPredicateBuilder<F>
|
||||||
|
@ -314,13 +314,13 @@ impl<F> WhereEqPredicateBuilder<F>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_ty(self, ty: P<ast::Ty>) -> F::Result {
|
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 {
|
let predicate = ast::WhereEqPredicate {
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
span: span,
|
span: span,
|
||||||
path: path,
|
lhs_ty: lhs,
|
||||||
ty: ty,
|
rhs_ty: ty,
|
||||||
};
|
};
|
||||||
|
|
||||||
callback.invoke(ast::WherePredicate::EqPredicate(predicate))
|
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:
|
os:
|
||||||
- linux
|
- linux
|
||||||
- osx
|
|
||||||
|
|
||||||
rust:
|
rust:
|
||||||
- stable
|
- stable
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- CARGO_TARGET_DIR=/tmp/bindgen LLVM_VERSION=3.8 BINDGEN_FEATURES=testing_only_llvm_stable
|
global:
|
||||||
- CARGO_TARGET_DIR=/tmp/bindgen LLVM_VERSION=3.9 BINDGEN_FEATURES=
|
- 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:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
|
@ -25,9 +35,17 @@ cache:
|
||||||
before_install: . ./ci/before_install.sh
|
before_install: . ./ci/before_install.sh
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./ci/assert-rustfmt.sh
|
# - ./ci/assert-rustfmt.sh
|
||||||
- BINDGEN_FEATURES="$BINDGEN_FEATURES" ./ci/assert-docs.sh
|
- BINDGEN_FEATURES="$BINDGEN_FEATURES" ./ci/assert-docs.sh
|
||||||
- BINDGEN_FEATURES="$BINDGEN_FEATURES" ./ci/test.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:
|
notifications:
|
||||||
webhooks: http://build.servo.org:54856/travis
|
webhooks: http://build.servo.org:54856/travis
|
||||||
|
|
|
@ -15,8 +15,8 @@ out to us in a GitHub issue, or stop by
|
||||||
- [Overview](#overview)
|
- [Overview](#overview)
|
||||||
- [Running All Tests](#running-all-tests)
|
- [Running All Tests](#running-all-tests)
|
||||||
- [Authoring New Tests](#authoring-new-tests)
|
- [Authoring New Tests](#authoring-new-tests)
|
||||||
- [Generating Graphviz Dot File](#generating-graphviz-dot-file)
|
|
||||||
- [Automatic code formatting](#automatic-code-formatting)
|
- [Automatic code formatting](#automatic-code-formatting)
|
||||||
|
- [Generating Graphviz Dot Files](#generating-graphviz-dot-files)
|
||||||
- [Debug Logging](#debug-logging)
|
- [Debug Logging](#debug-logging)
|
||||||
- [Using `creduce` to Minimize Test Cases](#using-creduce-to-minimize-test-cases)
|
- [Using `creduce` to Minimize Test Cases](#using-creduce-to-minimize-test-cases)
|
||||||
- [Isolating Your Test Case](#isolating-your-test-case)
|
- [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
|
$ 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
|
Additionally, you may want to build and test with the `testing_only_docs`
|
||||||
that you aren't forgetting to document types and functions. CI will catch it if
|
feature to ensure that you aren't forgetting to document types and functions. CI
|
||||||
you forget, but the turn around will be a lot slower ;)
|
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
|
## Testing
|
||||||
|
@ -94,6 +94,17 @@ Run `cargo test` to compare generated Rust bindings to the expectations.
|
||||||
$ cargo test [--all-features]
|
$ 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
|
### Authoring New Tests
|
||||||
|
|
||||||
To add a new test header to the suite, simply put it in the `tests/headers`
|
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
|
$ 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
|
## Automatic code formatting
|
||||||
|
|
||||||
We use [`rustfmt`](https://github.com/rust-lang-nursery/rustfmt) to enforce a
|
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.
|
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
|
## Debug Logging
|
||||||
|
|
||||||
To help debug what `bindgen` is doing, you can define the environment variable
|
To help debug what `bindgen` is doing, you can define the environment variable
|
||||||
|
|
|
@ -13,10 +13,14 @@ name = "bindgen"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/servo/rust-bindgen"
|
repository = "https://github.com/servo/rust-bindgen"
|
||||||
documentation = "https://docs.rs/bindgen"
|
documentation = "https://docs.rs/bindgen"
|
||||||
version = "0.22.0"
|
version = "0.24.0"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
exclude = ["tests/headers", "tests/expectations", "bindgen-integration", "ci"]
|
exclude = [
|
||||||
|
"bindgen-integration",
|
||||||
|
"ci",
|
||||||
|
"tests/**",
|
||||||
|
]
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
travis-ci = { repository = "servo/rust-bindgen" }
|
travis-ci = { repository = "servo/rust-bindgen" }
|
||||||
|
@ -27,6 +31,7 @@ path = "src/lib.rs"
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
doc = false
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
diff = "0.1"
|
diff = "0.1"
|
||||||
|
@ -34,22 +39,21 @@ clap = "2"
|
||||||
shlex = "0.1"
|
shlex = "0.1"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
quasi_codegen = "0.29"
|
quasi_codegen = "0.32"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cexpr = "0.2"
|
cexpr = "0.2"
|
||||||
cfg-if = "0.1.0"
|
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"
|
lazy_static = "0.2.1"
|
||||||
rustc-serialize = "0.3.19"
|
syntex_syntax = "0.58"
|
||||||
syntex_syntax = "0.54"
|
|
||||||
regex = "0.2"
|
regex = "0.2"
|
||||||
# This kinda sucks: https://github.com/rust-lang/cargo/issues/1982
|
# This kinda sucks: https://github.com/rust-lang/cargo/issues/1982
|
||||||
clap = "2"
|
clap = "2"
|
||||||
|
|
||||||
[dependencies.aster]
|
[dependencies.aster]
|
||||||
features = ["with-syntex"]
|
features = ["with-syntex"]
|
||||||
version = "0.38"
|
version = "0.41"
|
||||||
|
|
||||||
[dependencies.env_logger]
|
[dependencies.env_logger]
|
||||||
optional = true
|
optional = true
|
||||||
|
@ -61,13 +65,15 @@ version = "0.3"
|
||||||
|
|
||||||
[dependencies.quasi]
|
[dependencies.quasi]
|
||||||
features = ["with-syntex"]
|
features = ["with-syntex"]
|
||||||
version = "0.29"
|
version = "0.32"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
assert_no_dangling_items = []
|
|
||||||
default = ["logging"]
|
default = ["logging"]
|
||||||
testing_only_llvm_stable = []
|
|
||||||
logging = ["env_logger", "log"]
|
logging = ["env_logger", "log"]
|
||||||
static = []
|
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`
|
# `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 -->
|
For example, given the C header `cool.h`:
|
||||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct CoolStruct {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} CoolStruct;
|
||||||
|
|
||||||
- [Usage](#usage)
|
void cool_function(int i, char c, CoolStruct* cs);
|
||||||
- [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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If you use MacPorts:
|
`bindgen` produces Rust FFI code allowing you to call into the `cool` library's
|
||||||
|
functions and use its types:
|
||||||
```
|
|
||||||
$ 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`:
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern crate bindgen;
|
/* automatically generated by rust-bindgen */
|
||||||
|
|
||||||
use std::env;
|
#[repr(C)]
|
||||||
use std::path::Path;
|
pub struct CoolStruct {
|
||||||
|
pub x: ::std::os::raw::c_int,
|
||||||
|
pub y: ::std::os::raw::c_int,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
extern "C" {
|
||||||
let out_dir = env::var("OUT_DIR").unwrap();
|
pub fn cool_function(i: ::std::os::raw::c_int,
|
||||||
let _ = bindgen::builder()
|
c: ::std::os::raw::c_char,
|
||||||
.header("example.h")
|
cs: *mut CoolStruct);
|
||||||
.use_core()
|
|
||||||
.generate().unwrap()
|
|
||||||
.write_to_file(Path::new(&out_dir).join("example.rs"));
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In `src/main.rs`:
|
## Users Guide
|
||||||
|
|
||||||
```rust
|
[📚 Read the `bindgen` users guide here! 📚](https://servo.github.io/rust-bindgen)
|
||||||
include!(concat!(env!("OUT_DIR"), "/example.rs"));
|
|
||||||
```
|
|
||||||
|
|
||||||
### Command Line Usage
|
## API Reference
|
||||||
|
|
||||||
```
|
[API reference documentation is on docs.rs](https://docs.rs/bindgen)
|
||||||
$ cargo install 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++
|
[See `CONTRIBUTING.md` for hacking on `bindgen`!](./CONTRIBUTING.md)
|
||||||
|
|
||||||
`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.
|
|
||||||
|
|
|
@ -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();
|
quasi_codegen::expand(&src, &dst).unwrap();
|
||||||
println!("cargo:rerun-if-changed=src/codegen/mod.rs");
|
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/helpers.rs");
|
||||||
println!("cargo:rerun-if-changed=src/codegen/struct_layout.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 out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).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 manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||||
let headers_dir = manifest_dir.join("tests").join("headers");
|
let headers_dir = manifest_dir.join("tests").join("headers");
|
||||||
|
|
||||||
let entries = fs::read_dir(headers_dir)
|
let headers = match fs::read_dir(headers_dir) {
|
||||||
.expect("Couldn't read headers dir")
|
Ok(dir) => dir,
|
||||||
.map(|result| result.expect("Couldn't read header file"));
|
// 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 {
|
for entry in entries {
|
||||||
match entry.path().extension().and_then(OsStr::to_str) {
|
match entry.path().extension().and_then(OsStr::to_str) {
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
set -xeu
|
set -xeu
|
||||||
cd "$(dirname "$0")/.."
|
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 ~
|
pushd ~
|
||||||
|
|
||||||
# Workaround for Travis CI macOS bug (https://github.com/travis-ci/travis-ci/issues/6307)
|
# 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
|
rvm get head || true
|
||||||
fi
|
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() {
|
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
|
export LLVM=clang+llvm-${LLVM_VERSION_TRIPLE}-x86_64-$1
|
||||||
|
|
||||||
wget http://llvm.org/releases/${LLVM_VERSION_TRIPLE}/${LLVM}.tar.xz
|
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
|
# Regenerate the test headers' bindings in debug and release modes, and assert
|
||||||
# that we always get the expected generated bindings.
|
# 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
|
./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
|
./ci/assert-no-diff.sh
|
||||||
|
|
||||||
# Now test the expectations' size and alignment tests.
|
# 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
|
/// A trait to allow configuring different kinds of types in different
|
||||||
/// situations.
|
/// 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
|
/// 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.
|
/// value of that macro, or `None` if you want the default to be chosen.
|
||||||
fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> {
|
fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> {
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
use cexpr;
|
use cexpr;
|
||||||
use clang_sys::*;
|
use clang_sys::*;
|
||||||
|
use regex;
|
||||||
use std::{mem, ptr, slice};
|
use std::{mem, ptr, slice};
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::fmt;
|
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.
|
/// Get the `Cursor` for this cursor's referent's lexical parent.
|
||||||
///
|
///
|
||||||
/// The lexical parent is the parent of the definition. The semantic 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,
|
/// Return the number of template arguments used by this cursor's referent,
|
||||||
/// if the referent is either a template specialization or declaration.
|
/// if the referent is either a template instantiation. Returns `None`
|
||||||
/// Returns `None` otherwise.
|
/// otherwise.
|
||||||
///
|
///
|
||||||
/// NOTE: This may not return `Some` for some non-fully specialized
|
/// NOTE: This may not return `Some` for partial template specializations,
|
||||||
/// templates, see #193 and #194.
|
/// see #193 and #194.
|
||||||
pub fn num_template_args(&self) -> Option<u32> {
|
pub fn num_template_args(&self) -> Option<u32> {
|
||||||
// XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while
|
// XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while
|
||||||
// `clang_Cursor_getNumTemplateArguments` is totally unreliable.
|
// `clang_Cursor_getNumTemplateArguments` is totally unreliable.
|
||||||
|
@ -208,7 +239,7 @@ impl Cursor {
|
||||||
|
|
||||||
/// Get the kind of referent this cursor is pointing to.
|
/// Get the kind of referent this cursor is pointing to.
|
||||||
pub fn kind(&self) -> CXCursorKind {
|
pub fn kind(&self) -> CXCursorKind {
|
||||||
unsafe { clang_getCursorKind(self.x) }
|
self.x.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true is the cursor is a definition
|
/// Returns true is the cursor is a definition
|
||||||
|
@ -302,7 +333,11 @@ impl Cursor {
|
||||||
x: clang_getCursorDefinition(self.x),
|
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
|
/// Given that this cursor points to either a template specialization or a
|
||||||
/// pointing to the template definition that is being specialized.
|
/// template instantiation, get a cursor pointing to the template definition
|
||||||
|
/// that is being specialized.
|
||||||
pub fn specialized(&self) -> Option<Cursor> {
|
pub fn specialized(&self) -> Option<Cursor> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ret = Cursor {
|
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,
|
extern "C" fn visit_children<Visitor>(cur: CXCursor,
|
||||||
_parent: CXCursor,
|
_parent: CXCursor,
|
||||||
data: CXClientData)
|
data: CXClientData)
|
||||||
|
@ -633,9 +680,10 @@ impl Eq for Type {}
|
||||||
impl fmt::Debug for Type {
|
impl fmt::Debug for Type {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(fmt,
|
write!(fmt,
|
||||||
"Type({}, kind: {}, decl: {:?}, canon: {:?})",
|
"Type({}, kind: {}, cconv: {}, decl: {:?}, canon: {:?})",
|
||||||
self.spelling(),
|
self.spelling(),
|
||||||
type_to_str(self.kind()),
|
type_to_str(self.kind()),
|
||||||
|
self.call_conv(),
|
||||||
self.declaration(),
|
self.declaration(),
|
||||||
self.declaration().canonical())
|
self.declaration().canonical())
|
||||||
}
|
}
|
||||||
|
@ -716,7 +764,16 @@ impl Type {
|
||||||
|
|
||||||
/// Get a raw display name for this type.
|
/// Get a raw display name for this type.
|
||||||
pub fn spelling(&self) -> String {
|
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?
|
/// Is this type const qualified?
|
||||||
|
@ -875,7 +932,11 @@ impl Type {
|
||||||
pub fn named(&self) -> Type {
|
pub fn named(&self) -> Type {
|
||||||
unsafe {
|
unsafe {
|
||||||
Type {
|
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
|
self.is_valid() && self.kind() != CXType_Unexposed
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this type a fully specialized template?
|
/// Is this type a fully instantiated template?
|
||||||
pub fn is_fully_specialized_template(&self) -> bool {
|
pub fn is_fully_instantiated_template(&self) -> bool {
|
||||||
// Yep, the spelling of this containing type-parameter is extremely
|
// Yep, the spelling of this containing type-parameter is extremely
|
||||||
// nasty... But can happen in <type_traits>. Unfortunately I couldn't
|
// nasty... But can happen in <type_traits>. Unfortunately I couldn't
|
||||||
// reduce it enough :(
|
// reduce it enough :(
|
||||||
|
@ -903,6 +964,30 @@ impl Type {
|
||||||
_ => true,
|
_ => 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
|
/// 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() {
|
if s.data.is_null() {
|
||||||
return "".to_owned();
|
return "".to_owned();
|
||||||
}
|
}
|
||||||
unsafe {
|
let c_str = unsafe { CStr::from_ptr(clang_getCString(s) as *const _) };
|
||||||
let c_str = CStr::from_ptr(clang_getCString(s) as *const _);
|
c_str.to_string_lossy().into_owned()
|
||||||
let ret = c_str.to_string_lossy().into_owned();
|
}
|
||||||
clang_disposeString(s);
|
|
||||||
ret
|
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
|
/// 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.
|
/// A file which has not been saved to disk.
|
||||||
pub struct UnsavedFile {
|
pub struct UnsavedFile {
|
||||||
x: CXUnsavedFile,
|
x: CXUnsavedFile,
|
||||||
name: CString,
|
/// The name of the unsaved file. Kept here to avoid leaving dangling pointers in
|
||||||
|
/// `CXUnsavedFile`.
|
||||||
|
pub name: CString,
|
||||||
contents: 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.
|
/// Convert a cursor kind into a static string.
|
||||||
pub fn kind_to_str(x: CXCursorKind) -> String {
|
pub fn kind_to_str(x: CXCursorKind) -> String {
|
||||||
unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) }
|
unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) }
|
||||||
|
@ -1498,6 +1596,13 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
|
||||||
&specialized);
|
&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) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_indent(depth, format!(" {}cconv = {}", prefix, ty.call_conv()));
|
||||||
|
|
||||||
print_indent(depth,
|
print_indent(depth,
|
||||||
format!(" {}spelling = \"{}\"", prefix, ty.spelling()));
|
format!(" {}spelling = \"{}\"", prefix, ty.spelling()));
|
||||||
let num_template_args =
|
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 aster;
|
||||||
use syntax::ast;
|
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 {
|
pub fn repr(which: &str) -> ast::Attribute {
|
||||||
aster::AstBuilder::new().attr().list("repr").words(&[which]).build()
|
aster::AstBuilder::new().attr().list("repr").words(&[which]).build()
|
||||||
}
|
}
|
||||||
|
@ -142,7 +146,7 @@ pub mod ast_ty {
|
||||||
}
|
}
|
||||||
vec.push(int_expr(0));
|
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)
|
aster::AstBuilder::new().expr().build_expr_kind(kind)
|
||||||
}
|
}
|
||||||
|
@ -154,17 +158,38 @@ pub mod ast_ty {
|
||||||
.build_lit(aster::AstBuilder::new().lit().byte_str(string))
|
.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;
|
use aster::symbol::ToSymbol;
|
||||||
let mut string = f.to_string();
|
|
||||||
|
|
||||||
// So it gets properly recognised as a floating point constant.
|
if f.is_finite() {
|
||||||
if !string.contains('.') {
|
let mut string = f.to_string();
|
||||||
string.push('.');
|
|
||||||
|
// So it gets properly recognised as a floating point constant.
|
||||||
|
if !string.contains('.') {
|
||||||
|
string.push('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
let kind = ast::LitKind::FloatUnsuffixed(string.as_str().to_symbol());
|
||||||
|
return Ok(aster::AstBuilder::new().expr().lit().build_lit(kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
let kind = ast::LitKind::FloatUnsuffixed(string.as_str().to_symbol());
|
let prefix = ctx.trait_prefix();
|
||||||
aster::AstBuilder::new().expr().lit().build_lit(kind)
|
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,
|
pub fn arguments_from_signature(signature: &FunctionSig,
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -167,17 +167,20 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
||||||
None => return None,
|
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
|
// FIXME(emilio): As an _ultra_ hack, we correct the layout returned
|
||||||
// by arrays of structs that have a bigger alignment than what we
|
// by arrays of structs that have a bigger alignment than what we
|
||||||
// can support.
|
// can support.
|
||||||
//
|
//
|
||||||
// This means that the structs in the array are super-unsafe to
|
// This means that the structs in the array are super-unsafe to
|
||||||
// access, since they won't be properly aligned, but *shrug*.
|
// 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 ()>() {
|
if layout.align > mem::size_of::<*mut ()>() {
|
||||||
field_layout.size =
|
field_layout.size = align_to(layout.size, layout.align) *
|
||||||
align_to(layout.size, layout.align) * len;
|
len;
|
||||||
field_layout.align = mem::size_of::<*mut ()>();
|
field_layout.align = mem::size_of::<*mut ()>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,7 +200,8 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Otherwise the padding is useless.
|
// 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;
|
self.latest_offset += padding_bytes;
|
||||||
|
|
||||||
|
@ -206,14 +210,16 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
||||||
self.latest_offset);
|
self.latest_offset);
|
||||||
|
|
||||||
debug!("align field {} to {}/{} with {} padding bytes {:?}",
|
debug!("align field {} to {}/{} with {} padding bytes {:?}",
|
||||||
field_name,
|
field_name,
|
||||||
self.latest_offset,
|
self.latest_offset,
|
||||||
field_offset.unwrap_or(0) / 8,
|
field_offset.unwrap_or(0) / 8,
|
||||||
padding_bytes,
|
padding_bytes,
|
||||||
field_layout);
|
field_layout);
|
||||||
|
|
||||||
if need_padding && padding_bytes != 0 {
|
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 {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -221,7 +227,8 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
||||||
|
|
||||||
self.latest_offset += field_layout.size;
|
self.latest_offset += field_layout.size;
|
||||||
self.latest_field_layout = Some(field_layout);
|
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;
|
self.last_field_was_bitfield = false;
|
||||||
|
|
||||||
debug!("Offset: {}: {} -> {}",
|
debug!("Offset: {}: {} -> {}",
|
||||||
|
@ -232,11 +239,15 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
||||||
padding_layout.map(|layout| self.padding_field(layout))
|
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 {
|
if layout.size < self.latest_offset {
|
||||||
error!("Calculated wrong layout for {}, too more {} bytes",
|
error!("Calculated wrong layout for {}, too more {} bytes",
|
||||||
name, self.latest_offset - layout.size);
|
name,
|
||||||
return None
|
self.latest_offset - layout.size);
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let padding_bytes = layout.size - self.latest_offset;
|
let padding_bytes = layout.size - self.latest_offset;
|
||||||
|
@ -248,20 +259,22 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
||||||
// regardless, because bitfields don't respect alignment as strictly as
|
// regardless, because bitfields don't respect alignment as strictly as
|
||||||
// other fields.
|
// other fields.
|
||||||
if padding_bytes > 0 &&
|
if padding_bytes > 0 &&
|
||||||
(padding_bytes >= layout.align ||
|
(padding_bytes >= layout.align ||
|
||||||
(self.last_field_was_bitfield &&
|
(self.last_field_was_bitfield &&
|
||||||
padding_bytes >= self.latest_field_layout.unwrap().align) ||
|
padding_bytes >= self.latest_field_layout.unwrap().align) ||
|
||||||
layout.align > mem::size_of::<*mut ()>()) {
|
layout.align > mem::size_of::<*mut ()>()) {
|
||||||
let layout = if self.comp.packed() {
|
let layout = if self.comp.packed() {
|
||||||
Layout::new(padding_bytes, 1)
|
Layout::new(padding_bytes, 1)
|
||||||
} else if self.last_field_was_bitfield ||
|
} else if self.last_field_was_bitfield ||
|
||||||
layout.align > mem::size_of::<*mut ()>() {
|
layout.align > mem::size_of::<*mut ()>() {
|
||||||
// We've already given up on alignment here.
|
// We've already given up on alignment here.
|
||||||
Layout::for_size(padding_bytes)
|
Layout::for_size(padding_bytes)
|
||||||
} else {
|
} else {
|
||||||
Layout::new(padding_bytes, layout.align)
|
Layout::new(padding_bytes, layout.align)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("pad bytes to struct {}, {:?}", name, layout);
|
||||||
|
|
||||||
Some(self.padding_field(layout))
|
Some(self.padding_field(layout))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -314,12 +327,14 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
|
||||||
|
|
||||||
// If it was, we may or may not need to align, depending on what the
|
// 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.
|
// current field alignment and the bitfield size and alignment are.
|
||||||
debug!("align_to_bitfield? {}: {:?} {:?}", self.last_field_was_bitfield,
|
debug!("align_to_bitfield? {}: {:?} {:?}",
|
||||||
layout, new_field_layout);
|
self.last_field_was_bitfield,
|
||||||
|
layout,
|
||||||
|
new_field_layout);
|
||||||
|
|
||||||
if self.last_field_was_bitfield &&
|
if self.last_field_was_bitfield &&
|
||||||
new_field_layout.align <= layout.size % layout.align &&
|
new_field_layout.align <= layout.size % layout.align &&
|
||||||
new_field_layout.size <= layout.size % layout.align {
|
new_field_layout.size <= layout.size % layout.align {
|
||||||
// The new field will be coalesced into some of the remaining bits.
|
// The new field will be coalesced into some of the remaining bits.
|
||||||
//
|
//
|
||||||
// FIXME(emilio): I think this may not catch everything?
|
// FIXME(emilio): I think this may not catch everything?
|
||||||
|
|
|
@ -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::item::Item;
|
||||||
use super::layout::Layout;
|
use super::layout::Layout;
|
||||||
use super::traversal::{EdgeKind, Trace, Tracer};
|
use super::traversal::{EdgeKind, Trace, Tracer};
|
||||||
use super::ty::{TemplateDeclaration, Type};
|
use super::template::TemplateParameters;
|
||||||
use clang;
|
use clang;
|
||||||
use parse::{ClangItemParser, ParseError};
|
use parse::{ClangItemParser, ParseError};
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -26,6 +26,10 @@ pub enum MethodKind {
|
||||||
/// A constructor. We represent it as method for convenience, to avoid code
|
/// A constructor. We represent it as method for convenience, to avoid code
|
||||||
/// duplication.
|
/// duplication.
|
||||||
Constructor,
|
Constructor,
|
||||||
|
/// A destructor.
|
||||||
|
Destructor,
|
||||||
|
/// A virtual destructor.
|
||||||
|
VirtualDestructor,
|
||||||
/// A static method.
|
/// A static method.
|
||||||
Static,
|
Static,
|
||||||
/// A normal method.
|
/// A normal method.
|
||||||
|
@ -61,6 +65,12 @@ impl Method {
|
||||||
self.kind
|
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?
|
/// Is this a constructor?
|
||||||
pub fn is_constructor(&self) -> bool {
|
pub fn is_constructor(&self) -> bool {
|
||||||
self.kind == MethodKind::Constructor
|
self.kind == MethodKind::Constructor
|
||||||
|
@ -68,7 +78,8 @@ impl Method {
|
||||||
|
|
||||||
/// Is this a virtual method?
|
/// Is this a virtual method?
|
||||||
pub fn is_virtual(&self) -> bool {
|
pub fn is_virtual(&self) -> bool {
|
||||||
self.kind == MethodKind::Virtual
|
self.kind == MethodKind::Virtual ||
|
||||||
|
self.kind == MethodKind::VirtualDestructor
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this a static method?
|
/// Is this a static method?
|
||||||
|
@ -238,10 +249,11 @@ pub struct CompInfo {
|
||||||
/// The members of this struct or union.
|
/// The members of this struct or union.
|
||||||
fields: Vec<Field>,
|
fields: Vec<Field>,
|
||||||
|
|
||||||
/// The template parameters of this class. These are non-concrete, and
|
/// The abstract template parameters of this class. These are NOT concrete
|
||||||
/// should always be a Type(TypeKind::Named(name)), but still they need to
|
/// template arguments, and should always be a
|
||||||
/// be registered with an unique type id in the context.
|
/// Type(TypeKind::Named(name)). For concrete template arguments, see the
|
||||||
template_args: Vec<ItemId>,
|
/// TypeKind::TemplateInstantiation.
|
||||||
|
template_params: Vec<ItemId>,
|
||||||
|
|
||||||
/// The method declarations inside this class, if in C++ mode.
|
/// The method declarations inside this class, if in C++ mode.
|
||||||
methods: Vec<Method>,
|
methods: Vec<Method>,
|
||||||
|
@ -249,12 +261,13 @@ pub struct CompInfo {
|
||||||
/// The different constructors this struct or class contains.
|
/// The different constructors this struct or class contains.
|
||||||
constructors: Vec<ItemId>,
|
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.
|
/// Vector of classes this one inherits from.
|
||||||
base_members: Vec<Base>,
|
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:
|
/// The inner types that were declared inside this class, in something like:
|
||||||
///
|
///
|
||||||
/// class Foo {
|
/// class Foo {
|
||||||
|
@ -320,11 +333,11 @@ impl CompInfo {
|
||||||
CompInfo {
|
CompInfo {
|
||||||
kind: kind,
|
kind: kind,
|
||||||
fields: vec![],
|
fields: vec![],
|
||||||
template_args: vec![],
|
template_params: vec![],
|
||||||
methods: vec![],
|
methods: vec![],
|
||||||
constructors: vec![],
|
constructors: vec![],
|
||||||
|
destructor: None,
|
||||||
base_members: vec![],
|
base_members: vec![],
|
||||||
ref_template: None,
|
|
||||||
inner_types: vec![],
|
inner_types: vec![],
|
||||||
inner_vars: vec![],
|
inner_vars: vec![],
|
||||||
has_vtable: false,
|
has_vtable: false,
|
||||||
|
@ -345,9 +358,7 @@ impl CompInfo {
|
||||||
!self.has_vtable(ctx) && self.fields.is_empty() &&
|
!self.has_vtable(ctx) && self.fields.is_empty() &&
|
||||||
self.base_members.iter().all(|base| {
|
self.base_members.iter().all(|base| {
|
||||||
ctx.resolve_type(base.ty).canonical_type(ctx).is_unsized(ctx)
|
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?
|
/// Does this compound type have a destructor?
|
||||||
|
@ -364,16 +375,6 @@ impl CompInfo {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
CompKind::Union => false,
|
CompKind::Union => false,
|
||||||
CompKind::Struct => {
|
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| {
|
self.base_members.iter().any(|base| {
|
||||||
ctx.resolve_type(base.ty).has_destructor(ctx)
|
ctx.resolve_type(base.ty).has_destructor(ctx)
|
||||||
}) ||
|
}) ||
|
||||||
|
@ -389,16 +390,6 @@ impl CompInfo {
|
||||||
has_destructor
|
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.
|
/// Compute the layout of this type.
|
||||||
///
|
///
|
||||||
/// This is called as a fallback under some circumstances where LLVM doesn't
|
/// This is called as a fallback under some circumstances where LLVM doesn't
|
||||||
|
@ -411,7 +402,7 @@ impl CompInfo {
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
// We can't do better than clang here, sorry.
|
// We can't do better than clang here, sorry.
|
||||||
if self.kind == CompKind::Struct {
|
if self.kind == CompKind::Struct {
|
||||||
return None
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut max_size = 0;
|
let mut max_size = 0;
|
||||||
|
@ -434,12 +425,6 @@ impl CompInfo {
|
||||||
&self.fields
|
&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
|
/// Does this type have any template parameters that aren't types
|
||||||
/// (e.g. int)?
|
/// (e.g. int)?
|
||||||
pub fn has_non_type_template_params(&self) -> bool {
|
pub fn has_non_type_template_params(&self) -> bool {
|
||||||
|
@ -452,9 +437,6 @@ impl CompInfo {
|
||||||
self.base_members().iter().any(|base| {
|
self.base_members().iter().any(|base| {
|
||||||
ctx.resolve_type(base.ty)
|
ctx.resolve_type(base.ty)
|
||||||
.has_vtable(ctx)
|
.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
|
&self.constructors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get this type's destructor.
|
||||||
|
pub fn destructor(&self) -> Option<(bool, ItemId)> {
|
||||||
|
self.destructor
|
||||||
|
}
|
||||||
|
|
||||||
/// What kind of compound type is this?
|
/// What kind of compound type is this?
|
||||||
pub fn kind(&self) -> CompKind {
|
pub fn kind(&self) -> CompKind {
|
||||||
self.kind
|
self.kind
|
||||||
|
@ -485,10 +472,9 @@ impl CompInfo {
|
||||||
ctx: &mut BindgenContext)
|
ctx: &mut BindgenContext)
|
||||||
-> Result<Self, ParseError> {
|
-> Result<Self, ParseError> {
|
||||||
use clang_sys::*;
|
use clang_sys::*;
|
||||||
// Sigh... For class templates we want the location, for
|
assert!(ty.template_args().is_none(),
|
||||||
// specialisations, we want the declaration... So just try both.
|
"We handle template instantiations elsewhere");
|
||||||
//
|
|
||||||
// TODO: Yeah, this code reads really bad.
|
|
||||||
let mut cursor = ty.declaration();
|
let mut cursor = ty.declaration();
|
||||||
let mut kind = Self::kind_from_cursor(&cursor);
|
let mut kind = Self::kind_from_cursor(&cursor);
|
||||||
if kind.is_err() {
|
if kind.is_err() {
|
||||||
|
@ -510,44 +496,23 @@ impl CompInfo {
|
||||||
CXCursor_ClassDecl => !cur.is_definition(),
|
CXCursor_ClassDecl => !cur.is_definition(),
|
||||||
_ => false,
|
_ => 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;
|
let mut maybe_anonymous_struct_field = None;
|
||||||
cursor.visit(|cur| {
|
cursor.visit(|cur| {
|
||||||
if cur.kind() != CXCursor_FieldDecl {
|
if cur.kind() != CXCursor_FieldDecl {
|
||||||
if let Some((ty, _, offset)) =
|
if let Some((ty, clang_ty, offset)) =
|
||||||
maybe_anonymous_struct_field.take() {
|
maybe_anonymous_struct_field.take() {
|
||||||
let field =
|
if cur.kind() == CXCursor_TypedefDecl &&
|
||||||
Field::new(None, ty, None, None, None, false, offset);
|
cur.typedef_type().unwrap().canonical_type() == clang_ty {
|
||||||
ci.fields.push(field);
|
// 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,7 +541,7 @@ impl CompInfo {
|
||||||
|
|
||||||
let bit_width = cur.bit_width();
|
let bit_width = cur.bit_width();
|
||||||
let field_type = Item::from_ty_or_ref(cur.cur_type(),
|
let field_type = Item::from_ty_or_ref(cur.cur_type(),
|
||||||
Some(cur),
|
cur,
|
||||||
Some(potential_id),
|
Some(potential_id),
|
||||||
ctx);
|
ctx);
|
||||||
|
|
||||||
|
@ -616,17 +581,27 @@ impl CompInfo {
|
||||||
}
|
}
|
||||||
CXCursor_EnumDecl |
|
CXCursor_EnumDecl |
|
||||||
CXCursor_TypeAliasDecl |
|
CXCursor_TypeAliasDecl |
|
||||||
|
CXCursor_TypeAliasTemplateDecl |
|
||||||
CXCursor_TypedefDecl |
|
CXCursor_TypedefDecl |
|
||||||
CXCursor_StructDecl |
|
CXCursor_StructDecl |
|
||||||
CXCursor_UnionDecl |
|
CXCursor_UnionDecl |
|
||||||
CXCursor_ClassTemplate |
|
CXCursor_ClassTemplate |
|
||||||
CXCursor_ClassDecl => {
|
CXCursor_ClassDecl => {
|
||||||
// We can find non-semantic children here, clang uses a
|
// We can find non-semantic children here, clang uses a
|
||||||
// StructDecl to note incomplete structs that hasn't been
|
// StructDecl to note incomplete structs that haven't been
|
||||||
// forward-declared before, see:
|
// forward-declared before, see [1].
|
||||||
//
|
//
|
||||||
// https://github.com/servo/rust-bindgen/issues/482
|
// Also, clang seems to scope struct definitions inside
|
||||||
if cur.semantic_parent() != cursor {
|
// 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;
|
return CXChildVisit_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,17 +624,10 @@ impl CompInfo {
|
||||||
ci.packed = true;
|
ci.packed = true;
|
||||||
}
|
}
|
||||||
CXCursor_TemplateTypeParameter => {
|
CXCursor_TemplateTypeParameter => {
|
||||||
// Yes! You can arrive here with an empty template parameter
|
let param = Item::named_type(None, cur, ctx)
|
||||||
// name! Awesome, isn't it?
|
.expect("Item::named_type should't fail when pointing \
|
||||||
//
|
at a TemplateTypeParameter");
|
||||||
// see tests/headers/empty_template_param_name.hpp
|
ci.template_params.push(param);
|
||||||
if cur.spelling().is_empty() {
|
|
||||||
return CXChildVisit_Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let param =
|
|
||||||
Item::named_type(cur.spelling(), potential_id, ctx);
|
|
||||||
ci.template_args.push(param);
|
|
||||||
}
|
}
|
||||||
CXCursor_CXXBaseSpecifier => {
|
CXCursor_CXXBaseSpecifier => {
|
||||||
let is_virtual_base = cur.is_virtual_base();
|
let is_virtual_base = cur.is_virtual_base();
|
||||||
|
@ -671,10 +639,8 @@ impl CompInfo {
|
||||||
BaseKind::Normal
|
BaseKind::Normal
|
||||||
};
|
};
|
||||||
|
|
||||||
let type_id = Item::from_ty_or_ref(cur.cur_type(),
|
let type_id =
|
||||||
Some(cur),
|
Item::from_ty_or_ref(cur.cur_type(), cur, None, ctx);
|
||||||
None,
|
|
||||||
ctx);
|
|
||||||
ci.base_members.push(Base {
|
ci.base_members.push(Base {
|
||||||
ty: type_id,
|
ty: type_id,
|
||||||
kind: kind,
|
kind: kind,
|
||||||
|
@ -700,7 +666,7 @@ impl CompInfo {
|
||||||
// Methods of template functions not only use to be inlined,
|
// Methods of template functions not only use to be inlined,
|
||||||
// but also instantiated, and we wouldn't be able to call
|
// but also instantiated, and we wouldn't be able to call
|
||||||
// them, so just bail out.
|
// them, so just bail out.
|
||||||
if !ci.template_args.is_empty() {
|
if !ci.template_params.is_empty() {
|
||||||
return CXChildVisit_Continue;
|
return CXChildVisit_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -718,8 +684,9 @@ impl CompInfo {
|
||||||
CXCursor_Constructor => {
|
CXCursor_Constructor => {
|
||||||
ci.constructors.push(signature);
|
ci.constructors.push(signature);
|
||||||
}
|
}
|
||||||
// TODO(emilio): Bind the destructor?
|
CXCursor_Destructor => {
|
||||||
CXCursor_Destructor => {}
|
ci.destructor = Some((is_virtual, signature));
|
||||||
|
}
|
||||||
CXCursor_CXXMethod => {
|
CXCursor_CXXMethod => {
|
||||||
let is_const = cur.method_is_const();
|
let is_const = cur.method_is_const();
|
||||||
let method_kind = if is_static {
|
let method_kind = if is_static {
|
||||||
|
@ -767,7 +734,7 @@ impl CompInfo {
|
||||||
_ => {
|
_ => {
|
||||||
warn!("unhandled comp member `{}` (kind {:?}) in `{}` ({})",
|
warn!("unhandled comp member `{}` (kind {:?}) in `{}` ({})",
|
||||||
cur.spelling(),
|
cur.spelling(),
|
||||||
cur.kind(),
|
clang::kind_to_str(cur.kind()),
|
||||||
cursor.spelling(),
|
cursor.spelling(),
|
||||||
cur.location());
|
cur.location());
|
||||||
}
|
}
|
||||||
|
@ -776,7 +743,8 @@ impl CompInfo {
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some((ty, _, offset)) = maybe_anonymous_struct_field {
|
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);
|
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
|
/// Get the set of types that were declared within this compound type
|
||||||
/// (e.g. nested class definitions).
|
/// (e.g. nested class definitions).
|
||||||
pub fn inner_types(&self) -> &[ItemId] {
|
pub fn inner_types(&self) -> &[ItemId] {
|
||||||
|
@ -870,12 +819,14 @@ impl CompInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TemplateDeclaration for CompInfo {
|
impl TemplateParameters for CompInfo {
|
||||||
fn template_params(&self, _ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
fn self_template_params(&self,
|
||||||
if self.template_args.is_empty() {
|
_ctx: &BindgenContext)
|
||||||
|
-> Option<Vec<ItemId>> {
|
||||||
|
if self.template_params.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self.template_args.clone())
|
Some(self.template_params.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -914,13 +865,9 @@ impl CanDeriveDebug for CompInfo {
|
||||||
self.base_members
|
self.base_members
|
||||||
.iter()
|
.iter()
|
||||||
.all(|base| base.ty.can_derive_debug(ctx, ())) &&
|
.all(|base| base.ty.can_derive_debug(ctx, ())) &&
|
||||||
self.template_args
|
|
||||||
.iter()
|
|
||||||
.all(|id| id.can_derive_debug(ctx, ())) &&
|
|
||||||
self.fields
|
self.fields
|
||||||
.iter()
|
.iter()
|
||||||
.all(|f| f.can_derive_debug(ctx, ())) &&
|
.all(|f| f.can_derive_debug(ctx, ()))
|
||||||
self.ref_template.map_or(true, |id| id.can_derive_debug(ctx, ()))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.detect_derive_debug_cycle.set(false);
|
self.detect_derive_debug_cycle.set(false);
|
||||||
|
@ -950,7 +897,7 @@ impl CanDeriveDefault for CompInfo {
|
||||||
|
|
||||||
return layout.unwrap_or_else(Layout::zero)
|
return layout.unwrap_or_else(Layout::zero)
|
||||||
.opaque()
|
.opaque()
|
||||||
.can_derive_debug(ctx, ());
|
.can_derive_default(ctx, ());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.detect_derive_default_cycle.set(true);
|
self.detect_derive_default_cycle.set(true);
|
||||||
|
@ -960,14 +907,9 @@ impl CanDeriveDefault for CompInfo {
|
||||||
self.base_members
|
self.base_members
|
||||||
.iter()
|
.iter()
|
||||||
.all(|base| base.ty.can_derive_default(ctx, ())) &&
|
.all(|base| base.ty.can_derive_default(ctx, ())) &&
|
||||||
self.template_args
|
|
||||||
.iter()
|
|
||||||
.all(|id| id.can_derive_default(ctx, ())) &&
|
|
||||||
self.fields
|
self.fields
|
||||||
.iter()
|
.iter()
|
||||||
.all(|f| f.can_derive_default(ctx, ())) &&
|
.all(|f| f.can_derive_default(ctx, ()));
|
||||||
self.ref_template
|
|
||||||
.map_or(true, |id| id.can_derive_default(ctx, ()));
|
|
||||||
|
|
||||||
self.detect_derive_default_cycle.set(false);
|
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
|
// https://github.com/rust-lang/rust/issues/36640
|
||||||
if !self.template_args.is_empty() || self.ref_template.is_some() ||
|
if !self.template_params.is_empty() ||
|
||||||
!item.applicable_template_args(ctx).is_empty() {
|
item.used_template_params(ctx).is_some() {
|
||||||
return false;
|
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
|
self.base_members
|
||||||
.iter()
|
.iter()
|
||||||
.all(|base| base.ty.can_derive_copy(ctx, ())) &&
|
.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)
|
fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
|
||||||
where T: Tracer,
|
where T: Tracer,
|
||||||
{
|
{
|
||||||
// TODO: We should properly distinguish template instantiations from
|
let params = item.all_template_params(context).unwrap_or(vec![]);
|
||||||
// template declarations at the type level. Why are some template
|
for p in params {
|
||||||
// instantiations represented here instead of as
|
tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition);
|
||||||
// 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.
|
|
||||||
for p in params {
|
|
||||||
tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for base in self.base_members() {
|
|
||||||
tracer.visit(base.ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
for field in self.fields() {
|
|
||||||
tracer.visit(field.ty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for &ty in self.inner_types() {
|
for &ty in self.inner_types() {
|
||||||
tracer.visit(ty);
|
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_kind(base.ty, EdgeKind::BaseMember);
|
||||||
|
}
|
||||||
|
|
||||||
|
for field in self.fields() {
|
||||||
|
tracer.visit_kind(field.ty(), EdgeKind::Field);
|
||||||
}
|
}
|
||||||
|
|
||||||
for &var in self.inner_vars() {
|
for &var in self.inner_vars() {
|
||||||
tracer.visit(var);
|
tracer.visit_kind(var, EdgeKind::InnerVar);
|
||||||
}
|
}
|
||||||
|
|
||||||
for method in self.methods() {
|
for method in self.methods() {
|
||||||
tracer.visit(method.signature);
|
tracer.visit_kind(method.signature, EdgeKind::Method);
|
||||||
}
|
}
|
||||||
|
|
||||||
for &ctor in self.constructors() {
|
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::{Item, ItemCanonicalPath, ItemSet};
|
||||||
use super::item_kind::ItemKind;
|
use super::item_kind::ItemKind;
|
||||||
use super::module::{Module, ModuleKind};
|
use super::module::{Module, ModuleKind};
|
||||||
use super::traversal::{self, Edge, ItemTraversal, Trace};
|
use super::named::{UsedTemplateParameters, analyze};
|
||||||
use super::ty::{FloatKind, TemplateDeclaration, Type, TypeKind};
|
use super::template::{TemplateInstantiation, TemplateParameters};
|
||||||
|
use super::traversal::{self, Edge, ItemTraversal};
|
||||||
|
use super::ty::{FloatKind, Type, TypeKind};
|
||||||
use BindgenOptions;
|
use BindgenOptions;
|
||||||
use cexpr;
|
use cexpr;
|
||||||
use chooser::TypeChooser;
|
use callbacks::ParseCallbacks;
|
||||||
use clang::{self, Cursor};
|
use clang::{self, Cursor};
|
||||||
use clang_sys;
|
use clang_sys;
|
||||||
use parse::ClangItemParser;
|
use parse::ClangItemParser;
|
||||||
|
@ -18,8 +20,6 @@ use std::cell::Cell;
|
||||||
use std::collections::{HashMap, hash_map};
|
use std::collections::{HashMap, hash_map};
|
||||||
use std::collections::btree_map::{self, BTreeMap};
|
use std::collections::btree_map::{self, BTreeMap};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{self, Write};
|
|
||||||
use std::iter::IntoIterator;
|
use std::iter::IntoIterator;
|
||||||
use syntax::ast::Ident;
|
use syntax::ast::Ident;
|
||||||
use syntax::codemap::{DUMMY_SP, Span};
|
use syntax::codemap::{DUMMY_SP, Span};
|
||||||
|
@ -104,6 +104,10 @@ pub struct BindgenContext<'ctx> {
|
||||||
/// item ids during parsing.
|
/// item ids during parsing.
|
||||||
types: HashMap<TypeKey, ItemId>,
|
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.
|
/// A cursor to module map. Similar reason than above.
|
||||||
modules: HashMap<Cursor, ItemId>,
|
modules: HashMap<Cursor, ItemId>,
|
||||||
|
|
||||||
|
@ -151,15 +155,61 @@ pub struct BindgenContext<'ctx> {
|
||||||
|
|
||||||
/// Whether a bindgen complex was generated
|
/// Whether a bindgen complex was generated
|
||||||
generated_bindegen_complex: Cell<bool>,
|
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.
|
/// A traversal of whitelisted items.
|
||||||
pub type WhitelistedItems<'ctx, 'gen> = ItemTraversal<'ctx,
|
pub struct WhitelistedItems<'ctx, 'gen>
|
||||||
'gen,
|
where 'gen: 'ctx
|
||||||
ItemSet,
|
{
|
||||||
Vec<ItemId>,
|
ctx: &'ctx BindgenContext<'gen>,
|
||||||
fn(Edge) -> bool>;
|
traversal: ItemTraversal<'ctx,
|
||||||
|
'gen,
|
||||||
|
ItemSet,
|
||||||
|
Vec<ItemId>,
|
||||||
|
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> {
|
impl<'ctx> BindgenContext<'ctx> {
|
||||||
/// Construct the context for the given `options`.
|
/// Construct the context for the given `options`.
|
||||||
pub fn new(options: BindgenOptions) -> Self {
|
pub fn new(options: BindgenOptions) -> Self {
|
||||||
|
@ -173,14 +223,15 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
clang::TranslationUnit::parse(&index,
|
clang::TranslationUnit::parse(&index,
|
||||||
"",
|
"",
|
||||||
&options.clang_args,
|
&options.clang_args,
|
||||||
&[],
|
&options.input_unsaved_files,
|
||||||
parse_options)
|
parse_options)
|
||||||
.expect("TranslationUnit::parse");
|
.expect("TranslationUnit::parse failed");
|
||||||
|
|
||||||
let root_module = Self::build_root_module(ItemId(0));
|
let root_module = Self::build_root_module(ItemId(0));
|
||||||
let mut me = BindgenContext {
|
let mut me = BindgenContext {
|
||||||
items: Default::default(),
|
items: Default::default(),
|
||||||
types: Default::default(),
|
types: Default::default(),
|
||||||
|
named_types: Default::default(),
|
||||||
modules: Default::default(),
|
modules: Default::default(),
|
||||||
next_item_id: ItemId(1),
|
next_item_id: ItemId(1),
|
||||||
root_module: root_module.id(),
|
root_module: root_module.id(),
|
||||||
|
@ -195,6 +246,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
translation_unit: translation_unit,
|
translation_unit: translation_unit,
|
||||||
options: options,
|
options: options,
|
||||||
generated_bindegen_complex: Cell::new(false),
|
generated_bindegen_complex: Cell::new(false),
|
||||||
|
used_template_parameters: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
me.add_item(root_module, None, 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")
|
.expect("should have been parsing a type, if we finished parsing a type")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the user-provided type chooser by reference, if any.
|
/// Get the user-provided callbacks by reference, if any.
|
||||||
pub fn type_chooser(&self) -> Option<&TypeChooser> {
|
pub fn parse_callbacks(&self) -> Option<&ParseCallbacks> {
|
||||||
self.options().type_chooser.as_ref().map(|t| &**t)
|
self.options().parse_callbacks.as_ref().map(|t| &**t)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define a new item.
|
/// Define a new item.
|
||||||
|
@ -240,7 +292,8 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
declaration,
|
declaration,
|
||||||
location);
|
location);
|
||||||
debug_assert!(declaration.is_some() || !item.kind().is_type() ||
|
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?");
|
"Adding a type without declaration?");
|
||||||
|
|
||||||
let id = item.id();
|
let id = item.id();
|
||||||
|
@ -258,7 +311,8 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_item = self.items.insert(id, item);
|
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
|
// 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
|
// 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.
|
// TODO: Move all this syntax crap to other part of the code.
|
||||||
|
|
||||||
/// Given that we are in the codegen phase, get the syntex context.
|
/// 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.
|
/// Gather all the unresolved type references.
|
||||||
fn collect_typerefs
|
fn collect_typerefs
|
||||||
(&mut self)
|
(&mut self)
|
||||||
-> Vec<(ItemId, clang::Type, Option<clang::Cursor>, Option<ItemId>)> {
|
-> Vec<(ItemId, clang::Type, clang::Cursor, Option<ItemId>)> {
|
||||||
debug_assert!(!self.collected_typerefs);
|
debug_assert!(!self.collected_typerefs);
|
||||||
self.collected_typerefs = true;
|
self.collected_typerefs = true;
|
||||||
let mut typerefs = vec![];
|
let mut typerefs = vec![];
|
||||||
|
@ -382,7 +465,11 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
for (id, ty, loc, parent_id) in typerefs {
|
for (id, ty, loc, parent_id) in typerefs {
|
||||||
let _resolved = {
|
let _resolved = {
|
||||||
let resolved = Item::from_ty(&ty, loc, parent_id, self)
|
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();
|
let mut item = self.items.get_mut(&id).unwrap();
|
||||||
|
|
||||||
*item.kind_mut().as_type_mut().unwrap().kind_mut() =
|
*item.kind_mut().as_type_mut().unwrap().kind_mut() =
|
||||||
|
@ -425,7 +512,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
TypeKind::Comp(ref ci) if !ci.is_template_specialization() => {}
|
TypeKind::Comp(..) |
|
||||||
TypeKind::TemplateAlias(..) |
|
TypeKind::TemplateAlias(..) |
|
||||||
TypeKind::Alias(..) => {}
|
TypeKind::Alias(..) => {}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
|
@ -531,14 +618,18 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
self.process_replacements();
|
self.process_replacements();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.find_used_template_parameters();
|
||||||
|
|
||||||
let ret = cb(self);
|
let ret = cb(self);
|
||||||
self.gen_ctx = None;
|
self.gen_ctx = None;
|
||||||
ret
|
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) {
|
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() {
|
for _ in self.assert_no_dangling_item_traversal() {
|
||||||
// The iterator's next method does the asserting for us.
|
// The iterator's next method does the asserting for us.
|
||||||
}
|
}
|
||||||
|
@ -557,6 +648,62 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
traversal::all_edges)
|
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
|
// This deserves a comment. Builtin types don't get a valid declaration, so
|
||||||
// we can't add it to the cursor->type map.
|
// we can't add it to the cursor->type map.
|
||||||
//
|
//
|
||||||
|
@ -636,7 +783,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
.and_then(|canon_decl| {
|
.and_then(|canon_decl| {
|
||||||
self.get_resolved_type(&canon_decl)
|
self.get_resolved_type(&canon_decl)
|
||||||
.and_then(|template_decl_id| {
|
.and_then(|template_decl_id| {
|
||||||
template_decl_id.num_template_params(self)
|
template_decl_id.num_self_template_params(self)
|
||||||
.map(|num_params| {
|
.map(|num_params| {
|
||||||
(*canon_decl.cursor(),
|
(*canon_decl.cursor(),
|
||||||
template_decl_id,
|
template_decl_id,
|
||||||
|
@ -660,7 +807,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
.cloned()
|
.cloned()
|
||||||
})
|
})
|
||||||
.and_then(|template_decl| {
|
.and_then(|template_decl| {
|
||||||
template_decl.num_template_params(self)
|
template_decl.num_self_template_params(self)
|
||||||
.map(|num_template_params| {
|
.map(|num_template_params| {
|
||||||
(*template_decl.decl(),
|
(*template_decl.decl(),
|
||||||
template_decl.id(),
|
template_decl.id(),
|
||||||
|
@ -708,7 +855,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
use clang_sys;
|
use clang_sys;
|
||||||
|
|
||||||
let num_expected_args = match self.resolve_type(template)
|
let num_expected_args = match self.resolve_type(template)
|
||||||
.num_template_params(self) {
|
.num_self_template_params(self) {
|
||||||
Some(n) => n,
|
Some(n) => n,
|
||||||
None => {
|
None => {
|
||||||
warn!("Tried to instantiate a template for which we could not \
|
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
|
// template declaration as the parent. It is already parsed and
|
||||||
// has a known-resolvable `ItemId`.
|
// has a known-resolvable `ItemId`.
|
||||||
let ty = Item::from_ty_or_ref(child.cur_type(),
|
let ty = Item::from_ty_or_ref(child.cur_type(),
|
||||||
Some(*child),
|
*child,
|
||||||
Some(template),
|
Some(template),
|
||||||
self);
|
self);
|
||||||
args.push(ty);
|
args.push(ty);
|
||||||
|
@ -772,7 +919,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
// Do a happy little parse. See comment in the TypeRef
|
// Do a happy little parse. See comment in the TypeRef
|
||||||
// match arm about parent IDs.
|
// match arm about parent IDs.
|
||||||
let ty = Item::from_ty_or_ref(child.cur_type(),
|
let ty = Item::from_ty_or_ref(child.cur_type(),
|
||||||
Some(*child),
|
*child,
|
||||||
Some(template),
|
Some(template),
|
||||||
self);
|
self);
|
||||||
args.push(ty);
|
args.push(ty);
|
||||||
|
@ -794,9 +941,9 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
sub_args.reverse();
|
sub_args.reverse();
|
||||||
|
|
||||||
let sub_name = Some(template_decl_cursor.spelling());
|
let sub_name = Some(template_decl_cursor.spelling());
|
||||||
|
let sub_inst = TemplateInstantiation::new(template_decl_id, sub_args);
|
||||||
let sub_kind =
|
let sub_kind =
|
||||||
TypeKind::TemplateInstantiation(template_decl_id,
|
TypeKind::TemplateInstantiation(sub_inst);
|
||||||
sub_args);
|
|
||||||
let sub_ty = Type::new(sub_name,
|
let sub_ty = Type::new(sub_name,
|
||||||
template_decl_cursor.cur_type()
|
template_decl_cursor.cur_type()
|
||||||
.fallible_layout()
|
.fallible_layout()
|
||||||
|
@ -846,7 +993,8 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
args.reverse();
|
args.reverse();
|
||||||
let type_kind = TypeKind::TemplateInstantiation(template, args);
|
let type_kind = TypeKind::TemplateInstantiation(
|
||||||
|
TemplateInstantiation::new(template, args));
|
||||||
let name = ty.spelling();
|
let name = ty.spelling();
|
||||||
let name = if name.is_empty() { None } else { Some(name) };
|
let name = if name.is_empty() { None } else { Some(name) };
|
||||||
let ty = Type::new(name,
|
let ty = Type::new(name,
|
||||||
|
@ -865,9 +1013,9 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
|
|
||||||
/// If we have already resolved the type for the given type declaration,
|
/// If we have already resolved the type for the given type declaration,
|
||||||
/// return its `ItemId`. Otherwise, return `None`.
|
/// return its `ItemId`. Otherwise, return `None`.
|
||||||
fn get_resolved_type(&self,
|
pub fn get_resolved_type(&self,
|
||||||
decl: &clang::CanonicalTypeDeclaration)
|
decl: &clang::CanonicalTypeDeclaration)
|
||||||
-> Option<ItemId> {
|
-> Option<ItemId> {
|
||||||
self.types
|
self.types
|
||||||
.get(&TypeKey::Declaration(*decl.cursor()))
|
.get(&TypeKey::Declaration(*decl.cursor()))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
|
@ -906,16 +1054,15 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
// of it, or
|
// of it, or
|
||||||
// * we have already parsed and resolved this type, and
|
// * we have already parsed and resolved this type, and
|
||||||
// there's nothing left to do.
|
// 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() &&
|
if decl.cursor().is_template_like() &&
|
||||||
*ty != decl.cursor().cur_type() &&
|
*ty != decl.cursor().cur_type() &&
|
||||||
location.is_some() &&
|
location.is_some() {
|
||||||
parent_id.is_some() {
|
|
||||||
let location = location.unwrap();
|
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
|
// For specialized type aliases, there's no way to get the
|
||||||
// template parameters as of this writing (for a struct
|
// template parameters as of this writing (for a struct
|
||||||
|
@ -934,10 +1081,10 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.instantiate_template(with_id,
|
return self.instantiate_template(with_id,
|
||||||
id,
|
id,
|
||||||
parent_id,
|
parent_id,
|
||||||
ty,
|
ty,
|
||||||
location)
|
location)
|
||||||
.or_else(|| Some(id));
|
.or_else(|| Some(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -949,17 +1096,20 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
self.build_builtin_ty(ty)
|
self.build_builtin_ty(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is unfortunately a lot of bloat, but is needed to properly track
|
/// Make a new item that is a resolved type reference to the `wrapped_id`.
|
||||||
// constness et. al.
|
///
|
||||||
//
|
/// This is unfortunately a lot of bloat, but is needed to properly track
|
||||||
// We should probably make the constness tracking separate, so it doesn't
|
/// constness et. al.
|
||||||
// bloat that much, but hey, we already bloat the heck out of builtin types.
|
///
|
||||||
fn build_ty_wrapper(&mut self,
|
/// We should probably make the constness tracking separate, so it doesn't
|
||||||
with_id: ItemId,
|
/// bloat that much, but hey, we already bloat the heck out of builtin
|
||||||
wrapped_id: ItemId,
|
/// types.
|
||||||
parent_id: Option<ItemId>,
|
pub fn build_ty_wrapper(&mut self,
|
||||||
ty: &clang::Type)
|
with_id: ItemId,
|
||||||
-> ItemId {
|
wrapped_id: ItemId,
|
||||||
|
parent_id: Option<ItemId>,
|
||||||
|
ty: &clang::Type)
|
||||||
|
-> ItemId {
|
||||||
let spelling = ty.spelling();
|
let spelling = ty.spelling();
|
||||||
let is_const = ty.is_const();
|
let is_const = ty.is_const();
|
||||||
let layout = ty.fallible_layout().ok();
|
let layout = ty.fallible_layout().ok();
|
||||||
|
@ -989,8 +1139,10 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
CXType_Bool => TypeKind::Int(IntKind::Bool),
|
CXType_Bool => TypeKind::Int(IntKind::Bool),
|
||||||
CXType_Int => TypeKind::Int(IntKind::Int),
|
CXType_Int => TypeKind::Int(IntKind::Int),
|
||||||
CXType_UInt => TypeKind::Int(IntKind::UInt),
|
CXType_UInt => TypeKind::Int(IntKind::UInt),
|
||||||
CXType_SChar | CXType_Char_S => TypeKind::Int(IntKind::Char),
|
CXType_Char_S => TypeKind::Int(IntKind::Char { is_signed: true }),
|
||||||
CXType_UChar | CXType_Char_U => TypeKind::Int(IntKind::UChar),
|
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_Short => TypeKind::Int(IntKind::Short),
|
||||||
CXType_UShort => TypeKind::Int(IntKind::UShort),
|
CXType_UShort => TypeKind::Int(IntKind::UShort),
|
||||||
CXType_WChar | CXType_Char16 => TypeKind::Int(IntKind::U16),
|
CXType_WChar | CXType_Char16 => TypeKind::Int(IntKind::U16),
|
||||||
|
@ -1111,35 +1263,8 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
&self.options
|
&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
|
/// Tokenizes a namespace cursor in order to get the name and kind of the
|
||||||
/// namespace,
|
/// namespace.
|
||||||
fn tokenize_namespace(&self,
|
fn tokenize_namespace(&self,
|
||||||
cursor: &clang::Cursor)
|
cursor: &clang::Cursor)
|
||||||
-> (Option<String>, ModuleKind) {
|
-> (Option<String>, ModuleKind) {
|
||||||
|
@ -1155,6 +1280,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
let mut kind = ModuleKind::Normal;
|
let mut kind = ModuleKind::Normal;
|
||||||
let mut found_namespace_keyword = false;
|
let mut found_namespace_keyword = false;
|
||||||
let mut module_name = None;
|
let mut module_name = None;
|
||||||
|
|
||||||
while let Some(token) = iter.next() {
|
while let Some(token) = iter.next() {
|
||||||
match &*token.spelling {
|
match &*token.spelling {
|
||||||
"inline" => {
|
"inline" => {
|
||||||
|
@ -1162,7 +1288,17 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
assert!(kind != ModuleKind::Inline);
|
assert!(kind != ModuleKind::Inline);
|
||||||
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;
|
found_namespace_keyword = true;
|
||||||
}
|
}
|
||||||
"{" => {
|
"{" => {
|
||||||
|
@ -1299,14 +1435,7 @@ impl<'ctx> BindgenContext<'ctx> {
|
||||||
// unions).
|
// unions).
|
||||||
let mut roots: Vec<_> = roots.collect();
|
let mut roots: Vec<_> = roots.collect();
|
||||||
roots.reverse();
|
roots.reverse();
|
||||||
|
WhitelistedItems::new(self, roots)
|
||||||
let predicate = if self.options().whitelist_recursively {
|
|
||||||
traversal::all_edges
|
|
||||||
} else {
|
|
||||||
traversal::no_edges
|
|
||||||
};
|
|
||||||
|
|
||||||
WhitelistedItems::new(self, roots, predicate)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenient method for getting the prefix to use for most traits in
|
/// 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.
|
/// A type that we are in the middle of parsing.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct PartialType {
|
pub struct PartialType {
|
||||||
|
@ -1359,14 +1555,16 @@ impl PartialType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TemplateDeclaration for PartialType {
|
impl TemplateParameters for PartialType {
|
||||||
fn template_params(&self, _ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
fn self_template_params(&self,
|
||||||
|
_ctx: &BindgenContext)
|
||||||
|
-> Option<Vec<ItemId>> {
|
||||||
// Maybe at some point we will eagerly parse named types, but for now we
|
// Maybe at some point we will eagerly parse named types, but for now we
|
||||||
// don't and this information is unavailable.
|
// don't and this information is unavailable.
|
||||||
None
|
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
|
// Wouldn't it be nice if libclang would reliably give us this
|
||||||
// information‽
|
// information‽
|
||||||
match self.decl().kind() {
|
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)
|
ctx: &mut BindgenContext)
|
||||||
-> Result<Self, ParseError> {
|
-> Result<Self, ParseError> {
|
||||||
use clang_sys::*;
|
use clang_sys::*;
|
||||||
|
debug!("Enum::from_ty {:?}", ty);
|
||||||
|
|
||||||
if ty.kind() != CXType_Enum {
|
if ty.kind() != CXType_Enum {
|
||||||
return Err(ParseError::Continue);
|
return Err(ParseError::Continue);
|
||||||
}
|
}
|
||||||
|
|
||||||
let declaration = ty.declaration().canonical();
|
let declaration = ty.declaration().canonical();
|
||||||
let repr = declaration.enum_type()
|
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![];
|
let mut variants = vec![];
|
||||||
|
|
||||||
// Assume signedness since the default type by the C standard is an int.
|
// 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);
|
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 {
|
if cursor.kind() == CXCursor_EnumConstantDecl {
|
||||||
let value = if is_signed {
|
let value = if is_signed {
|
||||||
cursor.enum_val_signed().map(EnumVariantValue::Signed)
|
cursor.enum_val_signed().map(EnumVariantValue::Signed)
|
||||||
|
@ -91,7 +94,7 @@ impl Enum {
|
||||||
};
|
};
|
||||||
if let Some(val) = value {
|
if let Some(val) = value {
|
||||||
let name = cursor.spelling();
|
let name = cursor.spelling();
|
||||||
let custom_behavior = ctx.type_chooser()
|
let custom_behavior = ctx.parse_callbacks()
|
||||||
.and_then(|t| {
|
.and_then(|t| {
|
||||||
t.enum_variant_behavior(type_name, &name, val)
|
t.enum_variant_behavior(type_name, &name, val)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
//! Intermediate representation for C/C++ functions and methods.
|
//! Intermediate representation for C/C++ functions and methods.
|
||||||
|
|
||||||
use super::context::{BindgenContext, ItemId};
|
use super::context::{BindgenContext, ItemId};
|
||||||
|
use super::dot::DotAttributes;
|
||||||
use super::item::Item;
|
use super::item::Item;
|
||||||
use super::traversal::{Trace, Tracer};
|
use super::traversal::{EdgeKind, Trace, Tracer};
|
||||||
use super::ty::TypeKind;
|
use super::ty::TypeKind;
|
||||||
use clang;
|
use clang;
|
||||||
use clang_sys::CXCallingConv;
|
use clang_sys::CXCallingConv;
|
||||||
|
use ir::derive::CanDeriveDebug;
|
||||||
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
|
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
|
||||||
|
use std::io;
|
||||||
use syntax::abi;
|
use syntax::abi;
|
||||||
|
|
||||||
/// A function declaration, with a signature, arguments, and argument names.
|
/// 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.
|
/// A function signature.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionSig {
|
pub struct FunctionSig {
|
||||||
|
@ -91,7 +111,14 @@ fn get_abi(cc: CXCallingConv) -> Option<abi::Abi> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the mangled name for the cursor's referent.
|
/// 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
|
// We early return here because libclang may crash in some case
|
||||||
// if we pass in a variable inside a partial specialized template.
|
// if we pass in a variable inside a partial specialized template.
|
||||||
// See servo/rust-bindgen#67, and servo/rust-bindgen#462.
|
// 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;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Ok(mut manglings) = cursor.cxx_manglings() {
|
||||||
|
if let Some(m) = manglings.pop() {
|
||||||
|
return Some(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut mangling = cursor.mangling();
|
let mut mangling = cursor.mangling();
|
||||||
if mangling.is_empty() {
|
if mangling.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to undo backend linkage munging (prepended _, generally)
|
// 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") {
|
if cfg!(target_os = "macos") {
|
||||||
mangling.remove(0);
|
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)
|
Some(mangling)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +219,8 @@ impl FunctionSig {
|
||||||
CXCursor_FunctionDecl |
|
CXCursor_FunctionDecl |
|
||||||
CXCursor_Constructor |
|
CXCursor_Constructor |
|
||||||
CXCursor_CXXMethod |
|
CXCursor_CXXMethod |
|
||||||
CXCursor_ObjCInstanceMethodDecl => {
|
CXCursor_ObjCInstanceMethodDecl |
|
||||||
|
CXCursor_ObjCClassMethodDecl => {
|
||||||
// For CXCursor_FunctionDecl, cursor.args() is the reliable way
|
// For CXCursor_FunctionDecl, cursor.args() is the reliable way
|
||||||
// to get parameter names and types.
|
// to get parameter names and types.
|
||||||
cursor.args()
|
cursor.args()
|
||||||
|
@ -167,8 +231,7 @@ impl FunctionSig {
|
||||||
let name = arg.spelling();
|
let name = arg.spelling();
|
||||||
let name =
|
let name =
|
||||||
if name.is_empty() { None } else { Some(name) };
|
if name.is_empty() { None } else { Some(name) };
|
||||||
let ty =
|
let ty = Item::from_ty_or_ref(arg_ty, *arg, None, ctx);
|
||||||
Item::from_ty_or_ref(arg_ty, Some(*arg), None, ctx);
|
|
||||||
(name, ty)
|
(name, ty)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -179,10 +242,8 @@ impl FunctionSig {
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
cursor.visit(|c| {
|
cursor.visit(|c| {
|
||||||
if c.kind() == CXCursor_ParmDecl {
|
if c.kind() == CXCursor_ParmDecl {
|
||||||
let ty = Item::from_ty_or_ref(c.cur_type(),
|
let ty =
|
||||||
Some(c),
|
Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
|
||||||
None,
|
|
||||||
ctx);
|
|
||||||
let name = c.spelling();
|
let name = c.spelling();
|
||||||
let name =
|
let name =
|
||||||
if name.is_empty() { None } else { Some(name) };
|
if name.is_empty() { None } else { Some(name) };
|
||||||
|
@ -196,13 +257,14 @@ impl FunctionSig {
|
||||||
|
|
||||||
let is_method = cursor.kind() == CXCursor_CXXMethod;
|
let is_method = cursor.kind() == CXCursor_CXXMethod;
|
||||||
let is_constructor = cursor.kind() == CXCursor_Constructor;
|
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() {
|
cursor.lexical_parent() != cursor.semantic_parent() {
|
||||||
// Only parse constructors once.
|
// Only parse constructors once.
|
||||||
return Err(ParseError::Continue);
|
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_const = is_method && cursor.method_is_const();
|
||||||
let is_virtual = is_method && cursor.method_is_virtual();
|
let is_virtual = is_method && cursor.method_is_virtual();
|
||||||
let is_static = is_method && cursor.method_is_static();
|
let is_static = is_method && cursor.method_is_static();
|
||||||
|
@ -220,17 +282,20 @@ impl FunctionSig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl {
|
let ty_ret_type = if cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
|
||||||
try!(cursor.ret_type().ok_or(ParseError::Continue))
|
cursor.kind() == CXCursor_ObjCClassMethodDecl {
|
||||||
|
try!(ty.ret_type()
|
||||||
|
.or_else(|| cursor.ret_type())
|
||||||
|
.ok_or(ParseError::Continue))
|
||||||
} else {
|
} else {
|
||||||
try!(ty.ret_type().ok_or(ParseError::Continue))
|
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());
|
let abi = get_abi(ty.call_conv());
|
||||||
|
|
||||||
if abi.is_none() {
|
if abi.is_none() {
|
||||||
assert_eq!(cursor.kind(),
|
assert!(cursor.kind() == CXCursor_ObjCInstanceMethodDecl ||
|
||||||
CXCursor_ObjCInstanceMethodDecl,
|
cursor.kind() == CXCursor_ObjCClassMethodDecl,
|
||||||
"Invalid ABI for function signature")
|
"Invalid ABI for function signature")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,9 +332,9 @@ impl ClangSubItemParser for Function {
|
||||||
-> Result<ParseResult<Self>, ParseError> {
|
-> Result<ParseResult<Self>, ParseError> {
|
||||||
use clang_sys::*;
|
use clang_sys::*;
|
||||||
match cursor.kind() {
|
match cursor.kind() {
|
||||||
// FIXME(emilio): Generate destructors properly.
|
|
||||||
CXCursor_FunctionDecl |
|
CXCursor_FunctionDecl |
|
||||||
CXCursor_Constructor |
|
CXCursor_Constructor |
|
||||||
|
CXCursor_Destructor |
|
||||||
CXCursor_CXXMethod => {}
|
CXCursor_CXXMethod => {}
|
||||||
_ => return Err(ParseError::Continue),
|
_ => return Err(ParseError::Continue),
|
||||||
};
|
};
|
||||||
|
@ -285,7 +350,8 @@ impl ClangSubItemParser for Function {
|
||||||
return Err(ParseError::Continue);
|
return Err(ParseError::Continue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if cursor.is_inlined_function() {
|
if !context.options().generate_inline_functions &&
|
||||||
|
cursor.is_inlined_function() {
|
||||||
return Err(ParseError::Continue);
|
return Err(ParseError::Continue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,15 +362,27 @@ impl ClangSubItemParser for Function {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the signature using Item::from_ty.
|
// Grab the signature using Item::from_ty.
|
||||||
let sig = try!(Item::from_ty(&cursor.cur_type(),
|
let sig =
|
||||||
Some(cursor),
|
try!(Item::from_ty(&cursor.cur_type(), cursor, None, context));
|
||||||
None,
|
|
||||||
context));
|
|
||||||
|
|
||||||
let name = cursor.spelling();
|
let mut name = cursor.spelling();
|
||||||
assert!(!name.is_empty(), "Empty function name?");
|
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) {
|
if mangled_name.as_ref() == Some(&name) {
|
||||||
mangled_name = None;
|
mangled_name = None;
|
||||||
}
|
}
|
||||||
|
@ -322,10 +400,34 @@ impl Trace for FunctionSig {
|
||||||
fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
|
fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
|
||||||
where T: Tracer,
|
where T: Tracer,
|
||||||
{
|
{
|
||||||
tracer.visit(self.return_type());
|
tracer.visit_kind(self.return_type(), EdgeKind::FunctionReturn);
|
||||||
|
|
||||||
for &(_, ty) in self.argument_types() {
|
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`.
|
/// A `bool`.
|
||||||
Bool,
|
Bool,
|
||||||
|
|
||||||
/// A `char`.
|
/// A `signed char`.
|
||||||
Char,
|
SChar,
|
||||||
|
|
||||||
/// An `unsigned char`.
|
/// An `unsigned char`.
|
||||||
UChar,
|
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`.
|
/// A `short`.
|
||||||
Short,
|
Short,
|
||||||
|
|
||||||
|
@ -84,9 +90,11 @@ impl IntKind {
|
||||||
Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 |
|
Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 |
|
||||||
U32 | U64 | U128 => false,
|
U32 | U64 | U128 => false,
|
||||||
|
|
||||||
Char | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 |
|
SChar | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 |
|
||||||
I128 => true,
|
I128 => true,
|
||||||
|
|
||||||
|
Char { is_signed } => is_signed,
|
||||||
|
|
||||||
Custom { is_signed, .. } => is_signed,
|
Custom { is_signed, .. } => is_signed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,7 +105,7 @@ impl IntKind {
|
||||||
pub fn known_size(&self) -> Option<usize> {
|
pub fn known_size(&self) -> Option<usize> {
|
||||||
use self::IntKind::*;
|
use self::IntKind::*;
|
||||||
Some(match *self {
|
Some(match *self {
|
||||||
Bool | UChar | Char | U8 | I8 => 1,
|
Bool | UChar | SChar | U8 | I8 | Char { .. } => 1,
|
||||||
U16 | I16 => 2,
|
U16 | I16 => 2,
|
||||||
U32 | I32 => 4,
|
U32 | I32 => 4,
|
||||||
U64 | I64 => 8,
|
U64 | I64 => 8,
|
||||||
|
|
|
@ -3,18 +3,23 @@
|
||||||
use super::annotations::Annotations;
|
use super::annotations::Annotations;
|
||||||
use super::context::{BindgenContext, ItemId, PartialType};
|
use super::context::{BindgenContext, ItemId, PartialType};
|
||||||
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
|
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
|
||||||
|
use super::dot::DotAttributes;
|
||||||
use super::function::Function;
|
use super::function::Function;
|
||||||
use super::item_kind::ItemKind;
|
use super::item_kind::ItemKind;
|
||||||
|
use super::layout::Opaque;
|
||||||
use super::module::Module;
|
use super::module::Module;
|
||||||
use super::traversal::{Trace, Tracer};
|
use super::template::{AsNamed, TemplateParameters};
|
||||||
use super::ty::{TemplateDeclaration, Type, TypeKind};
|
use super::traversal::{EdgeKind, Trace, Tracer};
|
||||||
|
use super::ty::{Type, TypeKind};
|
||||||
use clang;
|
use clang;
|
||||||
use clang_sys;
|
use clang_sys;
|
||||||
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
|
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
use std::io;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use regex;
|
||||||
|
|
||||||
/// A trait to get the canonical name from an item.
|
/// A trait to get the canonical name from an item.
|
||||||
///
|
///
|
||||||
|
@ -65,7 +70,7 @@ pub trait ItemAncestors {
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(debug_assertions)] {
|
if #[cfg(testing_only_extra_assertions)] {
|
||||||
type DebugOnlyItemSet = ItemSet;
|
type DebugOnlyItemSet = ItemSet;
|
||||||
} else {
|
} else {
|
||||||
struct DebugOnlyItemSet;
|
struct DebugOnlyItemSet;
|
||||||
|
@ -118,7 +123,7 @@ impl<'a, 'b> Iterator for ItemAncestorsIter<'a, 'b>
|
||||||
} else {
|
} else {
|
||||||
self.item = item.parent_id();
|
self.item = item.parent_id();
|
||||||
|
|
||||||
debug_assert!(!self.seen.contains(&item.id()));
|
extra_assert!(!self.seen.contains(&item.id()));
|
||||||
self.seen.insert(item.id());
|
self.seen.insert(item.id());
|
||||||
|
|
||||||
Some(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
|
// Pure convenience
|
||||||
impl ItemCanonicalName for ItemId {
|
impl ItemCanonicalName for ItemId {
|
||||||
fn canonical_name(&self, ctx: &BindgenContext) -> String {
|
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: &())
|
fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, _extra: &())
|
||||||
where T: Tracer,
|
where T: Tracer,
|
||||||
{
|
{
|
||||||
if self.is_hidden(ctx) {
|
// Even if this item is blacklisted/hidden, we want to trace it. It is
|
||||||
return;
|
// 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() {
|
match *self.kind() {
|
||||||
ItemKind::Type(ref ty) => {
|
ItemKind::Type(ref ty) => {
|
||||||
|
@ -203,7 +240,7 @@ impl Trace for Item {
|
||||||
tracer.visit(fun.signature());
|
tracer.visit(fun.signature());
|
||||||
}
|
}
|
||||||
ItemKind::Var(ref var) => {
|
ItemKind::Var(ref var) => {
|
||||||
tracer.visit(var.ty());
|
tracer.visit_kind(var.ty(), EdgeKind::VarType);
|
||||||
}
|
}
|
||||||
ItemKind::Module(_) => {
|
ItemKind::Module(_) => {
|
||||||
// Module -> children edges are "weak", and we do not want to
|
// Module -> children edges are "weak", and we do not want to
|
||||||
|
@ -222,8 +259,14 @@ impl CanDeriveDebug for Item {
|
||||||
type Extra = ();
|
type Extra = ();
|
||||||
|
|
||||||
fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
|
fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
|
||||||
ctx.options().derive_debug &&
|
if self.detect_derive_debug_cycle.get() {
|
||||||
match self.kind {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.detect_derive_debug_cycle.set(true);
|
||||||
|
|
||||||
|
let result = ctx.options().derive_debug &&
|
||||||
|
match self.kind {
|
||||||
ItemKind::Type(ref ty) => {
|
ItemKind::Type(ref ty) => {
|
||||||
if self.is_opaque(ctx) {
|
if self.is_opaque(ctx) {
|
||||||
ty.layout(ctx)
|
ty.layout(ctx)
|
||||||
|
@ -233,7 +276,11 @@ impl CanDeriveDebug for Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
self.detect_derive_debug_cycle.set(false);
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +308,13 @@ impl<'a> CanDeriveCopy<'a> for Item {
|
||||||
type Extra = ();
|
type Extra = ();
|
||||||
|
|
||||||
fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
|
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) => {
|
ItemKind::Type(ref ty) => {
|
||||||
if self.is_opaque(ctx) {
|
if self.is_opaque(ctx) {
|
||||||
ty.layout(ctx)
|
ty.layout(ctx)
|
||||||
|
@ -271,7 +324,11 @@ impl<'a> CanDeriveCopy<'a> for Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
self.detect_derive_copy_cycle.set(false);
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
|
fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
|
||||||
|
@ -344,6 +401,16 @@ pub struct Item {
|
||||||
parent_id: ItemId,
|
parent_id: ItemId,
|
||||||
/// The item kind.
|
/// The item kind.
|
||||||
kind: ItemKind,
|
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 {
|
impl Item {
|
||||||
|
@ -364,28 +431,28 @@ impl Item {
|
||||||
comment: comment,
|
comment: comment,
|
||||||
annotations: annotations.unwrap_or_default(),
|
annotations: annotations.unwrap_or_default(),
|
||||||
kind: kind,
|
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.
|
/// Get this `Item`'s identifier.
|
||||||
pub fn id(&self) -> ItemId {
|
pub fn id(&self) -> ItemId {
|
||||||
self.id
|
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.
|
/// Get this `Item`'s parent's identifier.
|
||||||
///
|
///
|
||||||
/// For the root module, the parent's ID is its own ID.
|
/// For the root module, the parent's ID is its own ID.
|
||||||
|
@ -486,184 +553,12 @@ impl Item {
|
||||||
self.kind().as_type()
|
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
|
/// Get a reference to this item's underlying `Function`. Panic if this is
|
||||||
/// some other kind of item.
|
/// some other kind of item.
|
||||||
pub fn expect_function(&self) -> &Function {
|
pub fn expect_function(&self) -> &Function {
|
||||||
self.kind().expect_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?
|
/// Is this item a module?
|
||||||
pub fn is_module(&self) -> bool {
|
pub fn is_module(&self) -> bool {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
|
@ -692,6 +587,7 @@ impl Item {
|
||||||
debug_assert!(ctx.in_codegen_phase(),
|
debug_assert!(ctx.in_codegen_phase(),
|
||||||
"You're not supposed to call this yet");
|
"You're not supposed to call this yet");
|
||||||
self.annotations.opaque() ||
|
self.annotations.opaque() ||
|
||||||
|
self.as_type().map_or(false, |ty| ty.is_opaque()) ||
|
||||||
ctx.opaque_by_name(&self.canonical_path(ctx))
|
ctx.opaque_by_name(&self.canonical_path(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -721,7 +617,7 @@ impl Item {
|
||||||
let mut item = self;
|
let mut item = self;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
debug_assert!(!targets_seen.contains(&item.id()));
|
extra_assert!(!targets_seen.contains(&item.id()));
|
||||||
targets_seen.insert(item.id());
|
targets_seen.insert(item.id());
|
||||||
|
|
||||||
if self.annotations().use_instead_of().is_some() {
|
if self.annotations().use_instead_of().is_some() {
|
||||||
|
@ -731,19 +627,12 @@ impl Item {
|
||||||
match *item.kind() {
|
match *item.kind() {
|
||||||
ItemKind::Type(ref ty) => {
|
ItemKind::Type(ref ty) => {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
// If we're a template specialization, our name is our
|
TypeKind::ResolvedTypeRef(inner) => {
|
||||||
// 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, _) => {
|
|
||||||
item = ctx.resolve_item(inner);
|
item = ctx.resolve_item(inner);
|
||||||
}
|
}
|
||||||
|
TypeKind::TemplateInstantiation(ref inst) => {
|
||||||
|
item = ctx.resolve_item(inst.template_definition());
|
||||||
|
}
|
||||||
_ => return item.id(),
|
_ => return item.id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -857,7 +746,7 @@ impl Item {
|
||||||
|
|
||||||
// Named template type arguments are never namespaced, and never
|
// Named template type arguments are never namespaced, and never
|
||||||
// mangled.
|
// mangled.
|
||||||
if target.as_type().map_or(false, |ty| ty.is_named()) {
|
if target.is_named(ctx, &()) {
|
||||||
return base_name;
|
return base_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,23 +817,45 @@ impl Item {
|
||||||
/// A set of items.
|
/// A set of items.
|
||||||
pub type ItemSet = BTreeSet<ItemId>;
|
pub type ItemSet = BTreeSet<ItemId>;
|
||||||
|
|
||||||
impl TemplateDeclaration for ItemId {
|
impl DotAttributes for Item {
|
||||||
fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
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)
|
ctx.resolve_item_fallible(*self)
|
||||||
.and_then(|item| item.template_params(ctx))
|
.and_then(|item| item.self_template_params(ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TemplateDeclaration for Item {
|
impl TemplateParameters for Item {
|
||||||
fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
fn self_template_params(&self,
|
||||||
self.kind.template_params(ctx)
|
ctx: &BindgenContext)
|
||||||
|
-> Option<Vec<ItemId>> {
|
||||||
|
self.kind.self_template_params(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TemplateDeclaration for ItemKind {
|
impl TemplateParameters for ItemKind {
|
||||||
fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
|
fn self_template_params(&self,
|
||||||
|
ctx: &BindgenContext)
|
||||||
|
-> Option<Vec<ItemId>> {
|
||||||
match *self {
|
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
|
// If we start emitting bindings to explicitly instantiated
|
||||||
// functions, then we'll need to check ItemKind::Function for
|
// functions, then we'll need to check ItemKind::Function for
|
||||||
// template params.
|
// template params.
|
||||||
|
@ -968,7 +879,7 @@ fn visit_child(cur: clang::Cursor,
|
||||||
return CXChildVisit_Break;
|
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 {
|
match *result {
|
||||||
Ok(..) => CXChildVisit_Break,
|
Ok(..) => CXChildVisit_Break,
|
||||||
|
@ -1061,8 +972,8 @@ impl ClangItemParser for Item {
|
||||||
// twice, handle them separately.
|
// twice, handle them separately.
|
||||||
{
|
{
|
||||||
let applicable_cursor = cursor.definition().unwrap_or(cursor);
|
let applicable_cursor = cursor.definition().unwrap_or(cursor);
|
||||||
match Self::from_ty(&applicable_cursor.cur_type(),
|
match Item::from_ty(&applicable_cursor.cur_type(),
|
||||||
Some(applicable_cursor),
|
applicable_cursor,
|
||||||
parent_id,
|
parent_id,
|
||||||
ctx) {
|
ctx) {
|
||||||
Ok(ty) => return Ok(ty),
|
Ok(ty) => return Ok(ty),
|
||||||
|
@ -1104,7 +1015,7 @@ impl ClangItemParser for Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_ty_or_ref(ty: clang::Type,
|
fn from_ty_or_ref(ty: clang::Type,
|
||||||
location: Option<clang::Cursor>,
|
location: clang::Cursor,
|
||||||
parent_id: Option<ItemId>,
|
parent_id: Option<ItemId>,
|
||||||
ctx: &mut BindgenContext)
|
ctx: &mut BindgenContext)
|
||||||
-> ItemId {
|
-> ItemId {
|
||||||
|
@ -1124,7 +1035,7 @@ impl ClangItemParser for Item {
|
||||||
/// `BindgenContext::resolve_typerefs`.
|
/// `BindgenContext::resolve_typerefs`.
|
||||||
fn from_ty_or_ref_with_id(potential_id: ItemId,
|
fn from_ty_or_ref_with_id(potential_id: ItemId,
|
||||||
ty: clang::Type,
|
ty: clang::Type,
|
||||||
location: Option<clang::Cursor>,
|
location: clang::Cursor,
|
||||||
parent_id: Option<ItemId>,
|
parent_id: Option<ItemId>,
|
||||||
ctx: &mut BindgenContext)
|
ctx: &mut BindgenContext)
|
||||||
-> ItemId {
|
-> ItemId {
|
||||||
|
@ -1136,16 +1047,20 @@ impl ClangItemParser for Item {
|
||||||
|
|
||||||
if ctx.collected_typerefs() {
|
if ctx.collected_typerefs() {
|
||||||
debug!("refs already collected, resolving directly");
|
debug!("refs already collected, resolving directly");
|
||||||
return Self::from_ty_with_id(potential_id,
|
return Item::from_ty_with_id(potential_id,
|
||||||
&ty,
|
&ty,
|
||||||
location,
|
location,
|
||||||
parent_id,
|
parent_id,
|
||||||
ctx)
|
ctx)
|
||||||
.expect("Unable to resolve type");
|
.unwrap_or_else(|_| {
|
||||||
|
Item::new_opaque_type(potential_id, &ty, ctx)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ty) =
|
if let Some(ty) = ctx.builtin_or_resolved_ty(potential_id,
|
||||||
ctx.builtin_or_resolved_ty(potential_id, parent_id, &ty, location) {
|
parent_id,
|
||||||
|
&ty,
|
||||||
|
Some(location)) {
|
||||||
debug!("{:?} already resolved: {:?}", ty, location);
|
debug!("{:?} already resolved: {:?}", ty, location);
|
||||||
return ty;
|
return ty;
|
||||||
}
|
}
|
||||||
|
@ -1168,14 +1083,13 @@ impl ClangItemParser for Item {
|
||||||
potential_id
|
potential_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn from_ty(ty: &clang::Type,
|
fn from_ty(ty: &clang::Type,
|
||||||
location: Option<clang::Cursor>,
|
location: clang::Cursor,
|
||||||
parent_id: Option<ItemId>,
|
parent_id: Option<ItemId>,
|
||||||
ctx: &mut BindgenContext)
|
ctx: &mut BindgenContext)
|
||||||
-> Result<ItemId, ParseError> {
|
-> Result<ItemId, ParseError> {
|
||||||
let id = ctx.next_item_id();
|
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
|
/// This is one of the trickiest methods you'll find (probably along with
|
||||||
|
@ -1188,21 +1102,41 @@ impl ClangItemParser for Item {
|
||||||
/// context.
|
/// context.
|
||||||
fn from_ty_with_id(id: ItemId,
|
fn from_ty_with_id(id: ItemId,
|
||||||
ty: &clang::Type,
|
ty: &clang::Type,
|
||||||
location: Option<clang::Cursor>,
|
location: clang::Cursor,
|
||||||
parent_id: Option<ItemId>,
|
parent_id: Option<ItemId>,
|
||||||
ctx: &mut BindgenContext)
|
ctx: &mut BindgenContext)
|
||||||
-> Result<ItemId, ParseError> {
|
-> Result<ItemId, ParseError> {
|
||||||
use clang_sys::*;
|
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 = {
|
||||||
let decl = ty.declaration();
|
let decl = ty.declaration();
|
||||||
decl.definition().unwrap_or(decl)
|
decl.definition().unwrap_or(decl)
|
||||||
};
|
};
|
||||||
|
|
||||||
let comment = decl.raw_comment()
|
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)
|
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 annotations) = annotations {
|
||||||
if let Some(ref replaced) = annotations.use_instead_of() {
|
if let Some(ref replaced) = annotations.use_instead_of() {
|
||||||
|
@ -1211,7 +1145,7 @@ impl ClangItemParser for Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ty) =
|
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);
|
return Ok(ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,11 +1153,10 @@ impl ClangItemParser for Item {
|
||||||
let mut valid_decl = decl.kind() != CXCursor_NoDeclFound;
|
let mut valid_decl = decl.kind() != CXCursor_NoDeclFound;
|
||||||
let declaration_to_look_for = if valid_decl {
|
let declaration_to_look_for = if valid_decl {
|
||||||
decl.canonical()
|
decl.canonical()
|
||||||
} else if location.is_some() &&
|
} else if location.kind() ==
|
||||||
location.unwrap().kind() ==
|
|
||||||
CXCursor_ClassTemplate {
|
CXCursor_ClassTemplate {
|
||||||
valid_decl = true;
|
valid_decl = true;
|
||||||
location.unwrap()
|
location
|
||||||
} else {
|
} else {
|
||||||
decl
|
decl
|
||||||
};
|
};
|
||||||
|
@ -1254,51 +1187,47 @@ impl ClangItemParser for Item {
|
||||||
relevant_parent_id,
|
relevant_parent_id,
|
||||||
ItemKind::Type(item)),
|
ItemKind::Type(item)),
|
||||||
declaration,
|
declaration,
|
||||||
location);
|
Some(location));
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
Err(ParseError::Continue) => Err(ParseError::Continue),
|
Err(ParseError::Continue) => Err(ParseError::Continue),
|
||||||
Err(ParseError::Recurse) => {
|
Err(ParseError::Recurse) => {
|
||||||
debug!("Item::from_ty recursing in the ast");
|
debug!("Item::from_ty recursing in the ast");
|
||||||
let mut result = Err(ParseError::Recurse);
|
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
|
|
||||||
// declaration_to_look_for suspiciously shares a lot of
|
|
||||||
// logic with ir::context, so we should refactor that.
|
|
||||||
if valid_decl {
|
|
||||||
let finished = ctx.finish_parsing();
|
|
||||||
assert_eq!(*finished.decl(), declaration_to_look_for);
|
|
||||||
}
|
|
||||||
|
|
||||||
location.visit(|cur| {
|
// Need to pop here, otherwise we'll get stuck.
|
||||||
visit_child(cur, id, ty, parent_id, ctx, &mut result)
|
//
|
||||||
});
|
// TODO: Find a nicer interface, really. Also, the
|
||||||
|
// declaration_to_look_for suspiciously shares a lot of
|
||||||
if valid_decl {
|
// logic with ir::context, so we should refactor that.
|
||||||
let partial_ty =
|
if valid_decl {
|
||||||
PartialType::new(declaration_to_look_for, id);
|
let finished = ctx.finish_parsing();
|
||||||
ctx.begin_parsing(partial_ty);
|
assert_eq!(*finished.decl(), declaration_to_look_for);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location.visit(|cur| {
|
||||||
|
visit_child(cur, id, ty, parent_id, ctx, &mut result)
|
||||||
|
});
|
||||||
|
|
||||||
|
if valid_decl {
|
||||||
|
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
|
// 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.
|
// 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 {
|
if let Err(ParseError::Recurse) = result {
|
||||||
warn!("Unknown type, assuming named template type: \
|
warn!("Unknown type, assuming named template type: \
|
||||||
id = {:?}; spelling = {}",
|
id = {:?}; spelling = {}",
|
||||||
id,
|
id,
|
||||||
ty.spelling());
|
ty.spelling());
|
||||||
Ok(Self::named_type_with_id(id,
|
Item::named_type(Some(id), location, ctx)
|
||||||
ty.spelling(),
|
.map(Ok)
|
||||||
relevant_parent_id,
|
.unwrap_or(Err(ParseError::Recurse))
|
||||||
ctx))
|
|
||||||
} else {
|
} else {
|
||||||
result
|
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
|
/// 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
|
/// always local so it's the only exception when there's no declaration for
|
||||||
/// a type.
|
/// a type.
|
||||||
///
|
fn named_type(with_id: Option<ItemId>,
|
||||||
/// It must have an id, and must not be the current module id. Ideally we
|
location: clang::Cursor,
|
||||||
/// could assert the parent id is a Comp(..) type, but that info isn't
|
ctx: &mut BindgenContext)
|
||||||
/// available yet.
|
-> Option<ItemId> {
|
||||||
fn named_type_with_id<S>(id: ItemId,
|
let ty = location.cur_type();
|
||||||
name: S,
|
|
||||||
parent_id: ItemId,
|
|
||||||
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(".", "");
|
|
||||||
|
|
||||||
ctx.add_item(Item::new(id,
|
debug!("Item::named_type:\n\
|
||||||
None,
|
\twith_id = {:?},\n\
|
||||||
None,
|
\tty = {} {:?},\n\
|
||||||
parent_id,
|
\tlocation: {:?}",
|
||||||
ItemKind::Type(Type::named(name))),
|
with_id,
|
||||||
None,
|
ty.spelling(),
|
||||||
None);
|
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,
|
let ty_spelling = ty.spelling();
|
||||||
parent_id: ItemId,
|
|
||||||
ctx: &mut BindgenContext)
|
// Clang does not expose any information about template type parameters
|
||||||
-> ItemId
|
// via their clang::Type, nor does it give us their canonical cursors
|
||||||
where S: Into<String>,
|
// the straightforward way. However, there are three situations from
|
||||||
{
|
// which we can find the definition of the template type parameter, if
|
||||||
let id = ctx.next_item_id();
|
// the cursor is indeed looking at some kind of a template type
|
||||||
Self::named_type_with_id(id, name, parent_id, ctx)
|
// 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.
|
//! Different variants of an `Item` in our intermediate representation.
|
||||||
|
|
||||||
|
use super::context::BindgenContext;
|
||||||
|
use super::dot::DotAttributes;
|
||||||
use super::function::Function;
|
use super::function::Function;
|
||||||
use super::module::Module;
|
use super::module::Module;
|
||||||
use super::ty::Type;
|
use super::ty::Type;
|
||||||
use super::var::Var;
|
use super::var::Var;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
/// A item we parse and translate.
|
/// A item we parse and translate.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -38,8 +41,8 @@ impl ItemKind {
|
||||||
ItemKind::Module(..) => "Module",
|
ItemKind::Module(..) => "Module",
|
||||||
ItemKind::Type(..) => "Type",
|
ItemKind::Type(..) => "Type",
|
||||||
ItemKind::Function(..) => "Function",
|
ItemKind::Function(..) => "Function",
|
||||||
ItemKind::Var(..) => "Var"
|
ItemKind::Var(..) => "Var",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this a module?
|
/// Is this a module?
|
||||||
|
@ -122,3 +125,23 @@ impl ItemKind {
|
||||||
self.as_var().expect("Not a var")
|
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::context::BindgenContext;
|
||||||
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
|
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};
|
use std::{cmp, mem};
|
||||||
|
|
||||||
/// A type that represents the struct layout of a type.
|
/// A type that represents the struct layout of a type.
|
||||||
|
@ -20,7 +21,8 @@ pub struct Layout {
|
||||||
fn test_layout_for_size() {
|
fn test_layout_for_size() {
|
||||||
let ptr_size = mem::size_of::<*mut ()>();
|
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(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 {
|
impl Layout {
|
||||||
|
@ -38,7 +40,8 @@ impl Layout {
|
||||||
/// alignment possible.
|
/// alignment possible.
|
||||||
pub fn for_size(size: usize) -> Self {
|
pub fn for_size(size: usize) -> Self {
|
||||||
let mut next_align = 2;
|
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;
|
next_align *= 2;
|
||||||
}
|
}
|
||||||
Layout {
|
Layout {
|
||||||
|
@ -65,9 +68,17 @@ impl Layout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When we are treating a type as opaque, it is just a blob with a `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);
|
pub struct Opaque(pub Layout);
|
||||||
|
|
||||||
impl Opaque {
|
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
|
/// Return the known rust type we should use to create a correctly-aligned
|
||||||
/// field with this layout.
|
/// field with this layout.
|
||||||
pub fn known_rust_type_for_array(&self) -> Option<&'static str> {
|
pub fn known_rust_type_for_array(&self) -> Option<&'static str> {
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub mod annotations;
|
||||||
pub mod comp;
|
pub mod comp;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod derive;
|
pub mod derive;
|
||||||
|
pub mod dot;
|
||||||
pub mod enum_ty;
|
pub mod enum_ty;
|
||||||
pub mod function;
|
pub mod function;
|
||||||
pub mod int;
|
pub mod int;
|
||||||
|
@ -15,6 +16,7 @@ pub mod item_kind;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod named;
|
pub mod named;
|
||||||
|
pub mod template;
|
||||||
pub mod traversal;
|
pub mod traversal;
|
||||||
pub mod ty;
|
pub mod ty;
|
||||||
pub mod var;
|
pub mod var;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
//! Intermediate representation for modules (AKA C++ namespaces).
|
//! Intermediate representation for modules (AKA C++ namespaces).
|
||||||
|
|
||||||
use super::context::{BindgenContext, ItemId};
|
use super::context::{BindgenContext, ItemId};
|
||||||
|
use super::dot::DotAttributes;
|
||||||
use clang;
|
use clang;
|
||||||
use parse::{ClangSubItemParser, ParseError, ParseResult};
|
use parse::{ClangSubItemParser, ParseError, ParseResult};
|
||||||
use parse_one;
|
use parse_one;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
/// Whether this module is inline or not.
|
/// Whether this module is inline or not.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[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 {
|
impl ClangSubItemParser for Module {
|
||||||
fn parse(cursor: clang::Cursor,
|
fn parse(cursor: clang::Cursor,
|
||||||
ctx: &mut BindgenContext)
|
ctx: &mut BindgenContext)
|
||||||
|
|
|
@ -76,23 +76,63 @@
|
||||||
//! fixed-point.
|
//! fixed-point.
|
||||||
//!
|
//!
|
||||||
//! We use the "monotone framework" for this fix-point analysis where our
|
//! 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
|
//! lattice is the mapping from each IR item to the powerset of the template
|
||||||
//! C++ header, our join function is set union, and we use the
|
//! parameters that appear in the input C++ header, our join function is set
|
||||||
//! `ir::traversal::Trace` trait to implement the work-list optimization so we
|
//! union, and we use the `ir::traversal::Trace` trait to implement the
|
||||||
//! don't have to revisit every node in the graph when for every iteration
|
//! work-list optimization so we don't have to revisit every node in the graph
|
||||||
//! towards the fix-point.
|
//! 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
|
//! 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].
|
//! [Static Program Analysis by Anders Møller and Michael I. Schwartzbach][spa].
|
||||||
//!
|
//!
|
||||||
//! [spa]: https://cs.au.dk/~amoeller/spa/spa.pdf
|
//! [spa]: https://cs.au.dk/~amoeller/spa/spa.pdf
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
|
||||||
use super::context::{BindgenContext, ItemId};
|
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::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.
|
/// 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
|
/// 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
|
/// convert `self` into this type, and return it as the final result of the
|
||||||
/// analysis.
|
/// analysis.
|
||||||
type Output: From<Self>;
|
type Output: From<Self> + fmt::Debug;
|
||||||
|
|
||||||
/// Construct a new instance of this analysis.
|
/// Construct a new instance of this analysis.
|
||||||
fn new(extra: Self::Extra) -> Self;
|
fn new(extra: Self::Extra) -> Self;
|
||||||
|
@ -152,12 +192,8 @@ pub trait MonotoneFramework: Sized + fmt::Debug {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run an analysis in the monotone framework.
|
/// 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
|
pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output
|
||||||
where Analysis: MonotoneFramework
|
where Analysis: MonotoneFramework,
|
||||||
{
|
{
|
||||||
let mut analysis = Analysis::new(extra);
|
let mut analysis = Analysis::new(extra);
|
||||||
let mut worklist = analysis.initial_worklist();
|
let mut worklist = analysis.initial_worklist();
|
||||||
|
@ -173,129 +209,453 @@ pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output
|
||||||
analysis.into()
|
analysis.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An analysis that finds the set of template parameters that actually end up
|
/// An analysis that finds for each IR item its set of template parameters that
|
||||||
/// used in our generated bindings.
|
/// 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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct UsedTemplateParameters<'a> {
|
pub struct UsedTemplateParameters<'ctx, 'gen>
|
||||||
ctx: &'a BindgenContext<'a>,
|
where 'gen: 'ctx,
|
||||||
used: ItemSet,
|
{
|
||||||
|
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>>,
|
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 Node = ItemId;
|
||||||
type Extra = &'a BindgenContext<'a>;
|
type Extra = &'ctx BindgenContext<'gen>;
|
||||||
type Output = ItemSet;
|
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 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
|
// We reverse our natural IR graph edges to find dependencies
|
||||||
// between nodes.
|
// between nodes.
|
||||||
let mut add_reverse_edge = |sub_item, _| {
|
item.trace(ctx, &mut |sub_item: ItemId, _| {
|
||||||
dependencies.entry(sub_item).or_insert(vec![]).push(item);
|
used.entry(sub_item).or_insert(Some(ItemSet::new()));
|
||||||
};
|
dependencies.entry(sub_item)
|
||||||
item.trace(ctx, &mut add_reverse_edge, &());
|
.or_insert(vec![])
|
||||||
|
.push(item);
|
||||||
|
}, &());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additionally, whether a template instantiation's template
|
// Additionally, whether a template instantiation's template
|
||||||
// arguments are used depends on whether the template declaration's
|
// arguments are used depends on whether the template declaration's
|
||||||
// generic template parameters are used.
|
// generic template parameters are used.
|
||||||
ctx.resolve_item_fallible(item)
|
ctx.resolve_item(item)
|
||||||
.and_then(|item| item.as_type())
|
.as_type()
|
||||||
.map(|ty| match ty.kind() {
|
.map(|ty| match ty.kind() {
|
||||||
&TypeKind::TemplateInstantiation(decl, ref args) => {
|
&TypeKind::TemplateInstantiation(ref inst) => {
|
||||||
let decl = ctx.resolve_type(decl);
|
let decl = ctx.resolve_type(inst.template_definition());
|
||||||
let params = decl.template_params(ctx)
|
let args = inst.template_arguments();
|
||||||
.expect("a template instantiation's referenced \
|
|
||||||
template declaration should have template \
|
// Although template definitions should always have
|
||||||
parameters");
|
// 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()) {
|
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 {
|
UsedTemplateParameters {
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
used: ItemSet::new(),
|
used: used,
|
||||||
dependencies: dependencies,
|
dependencies: dependencies,
|
||||||
|
whitelisted_items: whitelisted_items,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initial_worklist(&self) -> Vec<Self::Node> {
|
fn initial_worklist(&self) -> Vec<ItemId> {
|
||||||
self.ctx.whitelisted_items().collect()
|
// 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn constrain(&mut self, item: ItemId) -> bool {
|
fn constrain(&mut self, id: ItemId) -> bool {
|
||||||
let original_size = self.used.len();
|
// Invariant: all hash map entries' values are `Some` upon entering and
|
||||||
|
// exiting this method.
|
||||||
|
extra_assert!(self.used.values().all(|v| v.is_some()));
|
||||||
|
|
||||||
item.trace(self.ctx, &mut |item, edge_kind| {
|
// Take the set for this id out of the hash map while we mutate it based
|
||||||
if edge_kind == EdgeKind::TemplateParameterDefinition {
|
// on other hash map entries. We *must* put it back into the hash map at
|
||||||
// The definition of a template parameter is not considered a
|
// the end of this method. This allows us to side-step HashMap's lack of
|
||||||
// use of said template parameter. Ignore this edge.
|
// an analog to slice::split_at_mut.
|
||||||
return;
|
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
|
||||||
let ty_kind = self.ctx.resolve_item(item)
|
// template definition uses the corresponding template parameter.
|
||||||
.as_type()
|
Some(&TypeKind::TemplateInstantiation(ref inst)) => {
|
||||||
.map(|ty| ty.kind());
|
if self.whitelisted_items.contains(&inst.template_definition()) {
|
||||||
|
self.constrain_instantiation(id, &mut used_by_this_id, inst);
|
||||||
match ty_kind {
|
} else {
|
||||||
Some(&TypeKind::Named) => {
|
self.constrain_instantiation_of_blacklisted_template(id,
|
||||||
// This is a "trivial" use of the template type parameter.
|
&mut used_by_this_id,
|
||||||
self.used.insert(item);
|
inst);
|
||||||
},
|
}
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
}, &());
|
// Otherwise, add the union of each of its referent item's template
|
||||||
|
// parameter usage.
|
||||||
|
_ => self.constrain_join(&mut used_by_this_id, item),
|
||||||
|
}
|
||||||
|
|
||||||
let new_size = self.used.len();
|
trace!(" finally, used set is {:?}", used_by_this_id);
|
||||||
new_size != original_size
|
|
||||||
|
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)
|
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) {
|
if let Some(edges) = self.dependencies.get(&item) {
|
||||||
for item in edges {
|
for item in edges {
|
||||||
|
trace!("enqueue {:?} into worklist", item);
|
||||||
f(*item);
|
f(*item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<UsedTemplateParameters<'a>> for ItemSet {
|
impl<'ctx, 'gen> From<UsedTemplateParameters<'ctx, 'gen>>
|
||||||
fn from(used_templ_params: UsedTemplateParameters) -> ItemSet {
|
for HashMap<ItemId, ItemSet> {
|
||||||
|
fn from(used_templ_params: UsedTemplateParameters<'ctx, 'gen>) -> Self {
|
||||||
used_templ_params.used
|
used_templ_params.used
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (k, v.unwrap()))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
// Here we find the set of nodes that are reachable from any given
|
// 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
|
// node. This is a lattice mapping nodes to subsets of all nodes. Our join
|
||||||
|
@ -361,7 +721,7 @@ mod tests {
|
||||||
g.0.insert(Node(8), vec![]);
|
g.0.insert(Node(8), vec![]);
|
||||||
g
|
g
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reverse(&self) -> Graph {
|
fn reverse(&self) -> Graph {
|
||||||
let mut reversed = Graph::default();
|
let mut reversed = Graph::default();
|
||||||
for (node, edges) in self.0.iter() {
|
for (node, edges) in self.0.iter() {
|
||||||
|
@ -409,8 +769,9 @@ mod tests {
|
||||||
// Yes, what follows is a **terribly** inefficient set union
|
// Yes, what follows is a **terribly** inefficient set union
|
||||||
// implementation. Don't copy this code outside of this test!
|
// 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() {
|
for sub_node in self.graph.0[&node].iter() {
|
||||||
self.reachable.get_mut(&node).unwrap().insert(*sub_node);
|
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)
|
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() {
|
for dep in self.reversed.0[&node].iter() {
|
||||||
f(*dep);
|
f(*dep);
|
||||||
|
@ -450,19 +811,19 @@ mod tests {
|
||||||
println!("reachable = {:#?}", reachable);
|
println!("reachable = {:#?}", reachable);
|
||||||
|
|
||||||
fn nodes<A>(nodes: A) -> HashSet<Node>
|
fn nodes<A>(nodes: A) -> HashSet<Node>
|
||||||
where A: AsRef<[usize]>
|
where A: AsRef<[usize]>,
|
||||||
{
|
{
|
||||||
nodes.as_ref().iter().cloned().map(Node).collect()
|
nodes.as_ref().iter().cloned().map(Node).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut expected = HashMap::new();
|
let mut expected = HashMap::new();
|
||||||
expected.insert(Node(1), nodes([3,4,5,6,7,8]));
|
expected.insert(Node(1), nodes([3, 4, 5, 6, 7, 8]));
|
||||||
expected.insert(Node(2), nodes([2]));
|
expected.insert(Node(2), nodes([2]));
|
||||||
expected.insert(Node(3), nodes([3,4,5,6,7,8]));
|
expected.insert(Node(3), nodes([3, 4, 5, 6, 7, 8]));
|
||||||
expected.insert(Node(4), nodes([3,4,5,6,7,8]));
|
expected.insert(Node(4), nodes([3, 4, 5, 6, 7, 8]));
|
||||||
expected.insert(Node(5), nodes([3,4,5,6,7,8]));
|
expected.insert(Node(5), nodes([3, 4, 5, 6, 7, 8]));
|
||||||
expected.insert(Node(6), nodes([8]));
|
expected.insert(Node(6), nodes([8]));
|
||||||
expected.insert(Node(7), nodes([3,4,5,6,7,8]));
|
expected.insert(Node(7), nodes([3, 4, 5, 6, 7, 8]));
|
||||||
expected.insert(Node(8), nodes([]));
|
expected.insert(Node(8), nodes([]));
|
||||||
println!("expected = {:#?}", expected);
|
println!("expected = {:#?}", expected);
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,42 @@
|
||||||
//! Objective C types
|
//! Objective C types
|
||||||
|
|
||||||
use super::context::BindgenContext;
|
use super::context::{BindgenContext, ItemId};
|
||||||
use super::function::FunctionSig;
|
use super::function::FunctionSig;
|
||||||
|
use super::traversal::{Trace, Tracer};
|
||||||
|
use super::ty::TypeKind;
|
||||||
use clang;
|
use clang;
|
||||||
use clang_sys::CXChildVisit_Continue;
|
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_ObjCInstanceMethodDecl;
|
||||||
|
use clang_sys::CXCursor_ObjCProtocolDecl;
|
||||||
|
use clang_sys::CXCursor_ObjCProtocolRef;
|
||||||
|
|
||||||
/// Objective C interface as used in TypeKind
|
/// 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)]
|
#[derive(Debug)]
|
||||||
pub struct ObjCInterface {
|
pub struct ObjCInterface {
|
||||||
/// The name
|
/// The name
|
||||||
/// like, NSObject
|
/// like, NSObject
|
||||||
name: String,
|
name: String,
|
||||||
|
|
||||||
|
category: Option<String>,
|
||||||
|
|
||||||
|
is_protocol: bool,
|
||||||
|
|
||||||
|
conforms_to: Vec<ItemId>,
|
||||||
|
|
||||||
/// List of the methods defined in this interfae
|
/// List of the methods defined in this interfae
|
||||||
methods: Vec<ObjCInstanceMethod>,
|
methods: Vec<ObjCMethod>,
|
||||||
|
|
||||||
|
class_methods: Vec<ObjCMethod>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The objective c methods
|
/// The objective c methods
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ObjCInstanceMethod {
|
pub struct ObjCMethod {
|
||||||
/// The original method selector name
|
/// The original method selector name
|
||||||
/// like, dataWithBytes:length:
|
/// like, dataWithBytes:length:
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -31,13 +46,20 @@ pub struct ObjCInstanceMethod {
|
||||||
rust_name: String,
|
rust_name: String,
|
||||||
|
|
||||||
signature: FunctionSig,
|
signature: FunctionSig,
|
||||||
|
|
||||||
|
/// Is class method?
|
||||||
|
is_class_method: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjCInterface {
|
impl ObjCInterface {
|
||||||
fn new(name: &str) -> ObjCInterface {
|
fn new(name: &str) -> ObjCInterface {
|
||||||
ObjCInterface {
|
ObjCInterface {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
|
category: None,
|
||||||
|
is_protocol: false,
|
||||||
|
conforms_to: Vec::new(),
|
||||||
methods: Vec::new(),
|
methods: Vec::new(),
|
||||||
|
class_methods: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,11 +69,31 @@ impl ObjCInterface {
|
||||||
self.name.as_ref()
|
self.name.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List of the methods defined in this interfae
|
/// Formats the name for rust
|
||||||
pub fn methods(&self) -> &Vec<ObjCInstanceMethod> {
|
/// 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
|
&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
|
/// Parses the Objective C interface from the cursor
|
||||||
pub fn from_ty(cursor: &clang::Cursor,
|
pub fn from_ty(cursor: &clang::Cursor,
|
||||||
ctx: &mut BindgenContext)
|
ctx: &mut BindgenContext)
|
||||||
|
@ -59,16 +101,57 @@ impl ObjCInterface {
|
||||||
let name = cursor.spelling();
|
let name = cursor.spelling();
|
||||||
let mut interface = Self::new(&name);
|
let mut interface = Self::new(&name);
|
||||||
|
|
||||||
cursor.visit(|cursor| {
|
if cursor.kind() == CXCursor_ObjCProtocolDecl {
|
||||||
match cursor.kind() {
|
interface.is_protocol = true;
|
||||||
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);
|
|
||||||
|
|
||||||
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)
|
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 {
|
impl ObjCMethod {
|
||||||
fn new(name: &str, signature: FunctionSig) -> ObjCInstanceMethod {
|
fn new(name: &str,
|
||||||
|
signature: FunctionSig,
|
||||||
|
is_class_method: bool)
|
||||||
|
-> ObjCMethod {
|
||||||
let split_name: Vec<&str> = name.split(':').collect();
|
let split_name: Vec<&str> = name.split(':').collect();
|
||||||
|
|
||||||
let rust_name = split_name.join("_");
|
let rust_name = split_name.join("_");
|
||||||
|
|
||||||
ObjCInstanceMethod {
|
ObjCMethod {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
rust_name: rust_name.to_owned(),
|
rust_name: rust_name.to_owned(),
|
||||||
signature: signature,
|
signature: signature,
|
||||||
|
is_class_method: is_class_method,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +203,11 @@ impl ObjCInstanceMethod {
|
||||||
&self.signature
|
&self.signature
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is this a class method?
|
||||||
|
pub fn is_class_method(&self) -> bool {
|
||||||
|
self.is_class_method
|
||||||
|
}
|
||||||
|
|
||||||
/// Formats the method call
|
/// Formats the method call
|
||||||
pub fn format_method_call(&self, args: &[String]) -> String {
|
pub fn format_method_call(&self, args: &[String]) -> String {
|
||||||
let split_name: Vec<&str> =
|
let split_name: Vec<&str> =
|
||||||
|
@ -132,3 +232,23 @@ impl ObjCInstanceMethod {
|
||||||
.join("")
|
.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,
|
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 {
|
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
|
/// 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)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum EdgeKind {
|
pub enum EdgeKind {
|
||||||
/// A generic, catch-all edge.
|
/// A generic, catch-all edge.
|
||||||
Generic,
|
Generic,
|
||||||
|
|
||||||
/// An edge from a template declaration, to the definition of a named type
|
/// 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++
|
/// ```C++
|
||||||
/// template<typename T>
|
/// 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 {
|
/// class Foo {
|
||||||
/// int x;
|
/// 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
|
/// 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
|
impl<F> Tracer for F
|
||||||
where F: FnMut(ItemId, EdgeKind)
|
where F: FnMut(ItemId, EdgeKind),
|
||||||
{
|
{
|
||||||
fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) {
|
fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) {
|
||||||
(*self)(item, kind)
|
(*self)(item, kind)
|
||||||
|
@ -211,7 +316,8 @@ impl<F> Tracer for F
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trace all of the outgoing edges to other items. Implementations should call
|
/// 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 {
|
pub trait Trace {
|
||||||
/// If a particular type needs extra information beyond what it has in
|
/// If a particular type needs extra information beyond what it has in
|
||||||
/// `self` and `context` to find its referenced items, its implementation
|
/// `self` and `context` to find its referenced items, its implementation
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,6 +1,7 @@
|
||||||
//! Intermediate representation of variables.
|
//! Intermediate representation of variables.
|
||||||
|
|
||||||
use super::context::{BindgenContext, ItemId};
|
use super::context::{BindgenContext, ItemId};
|
||||||
|
use super::dot::DotAttributes;
|
||||||
use super::function::cursor_mangling;
|
use super::function::cursor_mangling;
|
||||||
use super::int::IntKind;
|
use super::int::IntKind;
|
||||||
use super::item::Item;
|
use super::item::Item;
|
||||||
|
@ -8,6 +9,7 @@ use super::ty::{FloatKind, TypeKind};
|
||||||
use cexpr;
|
use cexpr;
|
||||||
use clang;
|
use clang;
|
||||||
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
|
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
|
||||||
|
use std::io;
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
|
|
||||||
/// The type for a constant variable.
|
/// 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 {
|
impl ClangSubItemParser for Var {
|
||||||
fn parse(cursor: clang::Cursor,
|
fn parse(cursor: clang::Cursor,
|
||||||
ctx: &mut BindgenContext)
|
ctx: &mut BindgenContext)
|
||||||
|
@ -93,6 +116,11 @@ impl ClangSubItemParser for Var {
|
||||||
use cexpr::literal::CChar;
|
use cexpr::literal::CChar;
|
||||||
match cursor.kind() {
|
match cursor.kind() {
|
||||||
CXCursor_MacroDefinition => {
|
CXCursor_MacroDefinition => {
|
||||||
|
|
||||||
|
if let Some(visitor) = ctx.parse_callbacks() {
|
||||||
|
visitor.parsed_macro(&cursor.spelling());
|
||||||
|
}
|
||||||
|
|
||||||
let value = parse_macro(ctx, &cursor, ctx.translation_unit());
|
let value = parse_macro(ctx, &cursor, ctx.translation_unit());
|
||||||
|
|
||||||
let (id, value) = match value {
|
let (id, value) = match value {
|
||||||
|
@ -123,7 +151,7 @@ impl ClangSubItemParser for Var {
|
||||||
let (type_kind, val) = match value {
|
let (type_kind, val) = match value {
|
||||||
EvalResult::Invalid => return Err(ParseError::Continue),
|
EvalResult::Invalid => return Err(ParseError::Continue),
|
||||||
EvalResult::Float(f) => {
|
EvalResult::Float(f) => {
|
||||||
(TypeKind::Float(FloatKind::Float), VarType::Float(f))
|
(TypeKind::Float(FloatKind::Double), VarType::Float(f))
|
||||||
}
|
}
|
||||||
EvalResult::Char(c) => {
|
EvalResult::Char(c) => {
|
||||||
let c = match c {
|
let c = match c {
|
||||||
|
@ -147,7 +175,7 @@ impl ClangSubItemParser for Var {
|
||||||
(TypeKind::Pointer(char_ty), VarType::String(val))
|
(TypeKind::Pointer(char_ty), VarType::String(val))
|
||||||
}
|
}
|
||||||
EvalResult::Int(Wrapping(value)) => {
|
EvalResult::Int(Wrapping(value)) => {
|
||||||
let kind = ctx.type_chooser()
|
let kind = ctx.parse_callbacks()
|
||||||
.and_then(|c| c.int_macro(&name, value))
|
.and_then(|c| c.int_macro(&name, value))
|
||||||
.unwrap_or_else(|| if value < 0 {
|
.unwrap_or_else(|| if value < 0 {
|
||||||
if value < i32::min_value() as i64 {
|
if value < i32::min_value() as i64 {
|
||||||
|
@ -155,9 +183,7 @@ impl ClangSubItemParser for Var {
|
||||||
} else {
|
} else {
|
||||||
IntKind::Int
|
IntKind::Int
|
||||||
}
|
}
|
||||||
} else if value >
|
} else if value > u32::max_value() as i64 {
|
||||||
u32::max_value() as
|
|
||||||
i64 {
|
|
||||||
IntKind::ULongLong
|
IntKind::ULongLong
|
||||||
} else {
|
} else {
|
||||||
IntKind::UInt
|
IntKind::UInt
|
||||||
|
@ -184,7 +210,7 @@ impl ClangSubItemParser for Var {
|
||||||
// XXX this is redundant, remove!
|
// XXX this is redundant, remove!
|
||||||
let is_const = ty.is_const();
|
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,
|
Ok(ty) => ty,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
assert_eq!(ty.kind(),
|
assert_eq!(ty.kind(),
|
||||||
|
@ -238,7 +264,7 @@ impl ClangSubItemParser for Var {
|
||||||
.map(VarType::String)
|
.map(VarType::String)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mangling = cursor_mangling(&cursor);
|
let mangling = cursor_mangling(ctx, &cursor);
|
||||||
let var = Var::new(name, mangling, ty, value, is_const);
|
let var = Var::new(name, mangling, ty, value, is_const);
|
||||||
|
|
||||||
Ok(ParseResult::New(var, Some(cursor)))
|
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++
|
//! Provide a C/C++ header file, receive Rust FFI code to call into C/C++
|
||||||
//! functions and use types defined in the header.
|
//! 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(missing_docs)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
|
@ -37,16 +37,19 @@ extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod log_stubs;
|
mod log_stubs;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod extra_assertions;
|
||||||
|
|
||||||
// A macro to declare an internal module for which we *must* provide
|
// A macro to declare an internal module for which we *must* provide
|
||||||
// documentation for. If we are building with the "docs_" feature, then the
|
// documentation for. If we are building with the "testing_only_docs" feature,
|
||||||
// module is declared public, and our `#![deny(missing_docs)]` pragma applies to
|
// then the module is declared public, and our `#![deny(missing_docs)]` pragma
|
||||||
// it. This feature is used in CI, so we won't let anything slip by
|
// 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
|
// undocumented. Normal builds, however, will leave the module private, so that
|
||||||
// we don't expose internals to library consumers.
|
// we don't expose internals to library consumers.
|
||||||
macro_rules! doc_mod {
|
macro_rules! doc_mod {
|
||||||
($m:ident, $doc_mod_name:ident) => {
|
($m:ident, $doc_mod_name:ident) => {
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "docs_")] {
|
if #[cfg(feature = "testing_only_docs")] {
|
||||||
pub mod $doc_mod_name {
|
pub mod $doc_mod_name {
|
||||||
//! Autogenerated documentation module.
|
//! Autogenerated documentation module.
|
||||||
pub use super::$m::*;
|
pub use super::$m::*;
|
||||||
|
@ -63,7 +66,7 @@ mod parse;
|
||||||
mod regex_set;
|
mod regex_set;
|
||||||
mod uses;
|
mod uses;
|
||||||
|
|
||||||
pub mod chooser;
|
pub mod callbacks;
|
||||||
|
|
||||||
#[cfg(rustfmt)]
|
#[cfg(rustfmt)]
|
||||||
mod codegen;
|
mod codegen;
|
||||||
|
@ -86,7 +89,7 @@ use regex_set::RegexSet;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::{DUMMY_SP, Span};
|
use syntax::codemap::{DUMMY_SP, Span};
|
||||||
|
@ -109,6 +112,8 @@ pub struct CodegenConfig {
|
||||||
pub methods: bool,
|
pub methods: bool,
|
||||||
/// Whether to generate constructors.
|
/// Whether to generate constructors.
|
||||||
pub constructors: bool,
|
pub constructors: bool,
|
||||||
|
/// Whether to generate destructors.
|
||||||
|
pub destructors: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodegenConfig {
|
impl CodegenConfig {
|
||||||
|
@ -120,6 +125,7 @@ impl CodegenConfig {
|
||||||
vars: true,
|
vars: true,
|
||||||
methods: true,
|
methods: true,
|
||||||
constructors: true,
|
constructors: true,
|
||||||
|
destructors: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +137,7 @@ impl CodegenConfig {
|
||||||
vars: false,
|
vars: false,
|
||||||
methods: false,
|
methods: false,
|
||||||
constructors: false,
|
constructors: false,
|
||||||
|
destructors: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,13 +175,288 @@ pub fn builder() -> Builder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
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();
|
let header = header.into();
|
||||||
self.options.input_header = Some(header);
|
self.options.input_header = Some(header);
|
||||||
self
|
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.
|
/// Set the output graphviz file.
|
||||||
pub fn emit_ir_graphviz<T: Into<String>>(mut self, path: T) -> Builder {
|
pub fn emit_ir_graphviz<T: Into<String>>(mut self, path: T) -> Builder {
|
||||||
let path = path.into();
|
let path = path.into();
|
||||||
|
@ -199,19 +481,31 @@ impl Builder {
|
||||||
///
|
///
|
||||||
/// This can be used to get bindgen to generate _exactly_ the types you want
|
/// 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
|
/// 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 {
|
pub fn whitelist_recursively(mut self, doit: bool) -> Self {
|
||||||
self.options.whitelist_recursively = doit;
|
self.options.whitelist_recursively = doit;
|
||||||
self
|
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
|
/// in the prologue of the files generated from objective-c files
|
||||||
pub fn objc_extern_crate(mut self, doit: bool) -> Self {
|
pub fn objc_extern_crate(mut self, doit: bool) -> Self {
|
||||||
self.options.objc_extern_crate = doit;
|
self.options.objc_extern_crate = doit;
|
||||||
self
|
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
|
/// Generate a C/C++ file that includes the header and has dummy uses of
|
||||||
/// every type defined in the header.
|
/// every type defined in the header.
|
||||||
pub fn dummy_uses<T: Into<String>>(mut self, dummy_uses: T) -> Builder {
|
pub fn dummy_uses<T: Into<String>>(mut self, dummy_uses: T) -> Builder {
|
||||||
|
@ -290,6 +584,16 @@ impl Builder {
|
||||||
self
|
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.
|
/// Make the generated bindings link the given shared library.
|
||||||
pub fn link<T: Into<String>>(mut self, library: T) -> Builder {
|
pub fn link<T: Into<String>>(mut self, library: T) -> Builder {
|
||||||
self.options.links.push((library.into(), LinkType::Default));
|
self.options.links.push((library.into(), LinkType::Default));
|
||||||
|
@ -315,12 +619,18 @@ impl Builder {
|
||||||
self
|
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 {
|
pub fn no_convert_floats(mut self) -> Self {
|
||||||
self.options.convert_floats = false;
|
self.options.convert_floats = false;
|
||||||
self
|
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.
|
/// Set whether `Debug` should be derived by default.
|
||||||
pub fn derive_debug(mut self, doit: bool) -> Self {
|
pub fn derive_debug(mut self, doit: bool) -> Self {
|
||||||
self.options.derive_debug = doit;
|
self.options.derive_debug = doit;
|
||||||
|
@ -351,20 +661,19 @@ impl Builder {
|
||||||
self
|
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
|
/// By default, bindgen mangles names like `foo::bar::Baz` to look like
|
||||||
/// names to from `foo::bar::Baz` to look like `foo_bar_Baz`, instead of
|
/// `foo_bar_Baz` instead of just `Baz`.
|
||||||
/// just `Baz`.
|
|
||||||
///
|
///
|
||||||
/// This option disables that behavior.
|
/// This method disables that behavior.
|
||||||
///
|
///
|
||||||
/// Note that this intentionally doesn't change the names using for
|
/// Note that this intentionally does not change the names used for
|
||||||
/// whitelisting and blacklisting, that should still be mangled with the
|
/// whitelisting and blacklisting, which should still be mangled with the
|
||||||
/// namespaces.
|
/// namespaces.
|
||||||
///
|
///
|
||||||
/// Note, also, that using this option may cause duplicated names to be
|
/// Note, also, that this option may cause bindgen to generate duplicate
|
||||||
/// generated.
|
/// names.
|
||||||
pub fn disable_name_namespacing(mut self) -> Builder {
|
pub fn disable_name_namespacing(mut self) -> Builder {
|
||||||
self.options.disable_name_namespacing = true;
|
self.options.disable_name_namespacing = true;
|
||||||
self
|
self
|
||||||
|
@ -403,6 +712,16 @@ impl Builder {
|
||||||
self
|
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.
|
/// Ignore functions.
|
||||||
pub fn ignore_functions(mut self) -> Builder {
|
pub fn ignore_functions(mut self) -> Builder {
|
||||||
self.options.codegen_config.functions = false;
|
self.options.codegen_config.functions = false;
|
||||||
|
@ -433,19 +752,26 @@ impl Builder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows configuring types in different situations, see the `TypeChooser`
|
/// Allows configuring types in different situations, see the
|
||||||
/// documentation.
|
/// [`ParseCallbacks`](./callbacks/trait.ParseCallbacks.html) documentation.
|
||||||
pub fn type_chooser(mut self, cb: Box<chooser::TypeChooser>) -> Self {
|
pub fn parse_callbacks(mut self, cb: Box<callbacks::ParseCallbacks>) -> Self {
|
||||||
self.options.type_chooser = Some(cb);
|
self.options.parse_callbacks = Some(cb);
|
||||||
self
|
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 {
|
pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self {
|
||||||
self.options.codegen_config = config;
|
self.options.codegen_config = config;
|
||||||
self
|
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.
|
/// Generate the Rust bindings using the options built up thus far.
|
||||||
pub fn generate<'ctx>(self) -> Result<Bindings<'ctx>, ()> {
|
pub fn generate<'ctx>(self) -> Result<Bindings<'ctx>, ()> {
|
||||||
Bindings::generate(self.options, None)
|
Bindings::generate(self.options, None)
|
||||||
|
@ -508,11 +834,14 @@ pub struct BindgenOptions {
|
||||||
/// True if we should avoid mangling names with namespaces.
|
/// True if we should avoid mangling names with namespaces.
|
||||||
pub disable_name_namespacing: bool,
|
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.
|
/// and types.
|
||||||
pub derive_debug: bool,
|
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.
|
/// and types.
|
||||||
pub derive_default: bool,
|
pub derive_default: bool,
|
||||||
|
|
||||||
|
@ -545,13 +874,16 @@ pub struct BindgenOptions {
|
||||||
/// The input header file.
|
/// The input header file.
|
||||||
pub input_header: Option<String>,
|
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
|
/// 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.
|
/// of all types defined therein. See the `uses` module for more.
|
||||||
pub dummy_uses: Option<String>,
|
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.
|
/// 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
|
/// Which kind of items should we generate? By default, we'll generate all
|
||||||
/// of them.
|
/// of them.
|
||||||
|
@ -566,12 +898,27 @@ pub struct BindgenOptions {
|
||||||
/// documentation for more details.
|
/// documentation for more details.
|
||||||
pub generate_comments: bool,
|
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.
|
/// Wether to whitelist types recursively. Defaults to true.
|
||||||
pub whitelist_recursively: bool,
|
pub whitelist_recursively: bool,
|
||||||
|
|
||||||
/// Intead of emitting 'use objc;' to files generated from objective c files,
|
/// Intead of emitting 'use objc;' to files generated from objective c files,
|
||||||
/// generate '#[macro_use] extern crate objc;'
|
/// generate '#[macro_use] extern crate objc;'
|
||||||
pub objc_extern_crate: bool,
|
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
|
/// 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_ast: false,
|
||||||
emit_ir: false,
|
emit_ir: false,
|
||||||
emit_ir_graphviz: None,
|
emit_ir_graphviz: None,
|
||||||
|
layout_tests: true,
|
||||||
derive_debug: true,
|
derive_debug: true,
|
||||||
derive_default: false,
|
derive_default: false,
|
||||||
enable_cxx_namespaces: false,
|
enable_cxx_namespaces: false,
|
||||||
|
@ -619,13 +967,17 @@ impl Default for BindgenOptions {
|
||||||
raw_lines: vec![],
|
raw_lines: vec![],
|
||||||
clang_args: vec![],
|
clang_args: vec![],
|
||||||
input_header: None,
|
input_header: None,
|
||||||
|
input_unsaved_files: vec![],
|
||||||
dummy_uses: None,
|
dummy_uses: None,
|
||||||
type_chooser: None,
|
parse_callbacks: None,
|
||||||
codegen_config: CodegenConfig::all(),
|
codegen_config: CodegenConfig::all(),
|
||||||
conservative_inline_namespaces: false,
|
conservative_inline_namespaces: false,
|
||||||
generate_comments: true,
|
generate_comments: true,
|
||||||
|
generate_inline_functions: false,
|
||||||
whitelist_recursively: true,
|
whitelist_recursively: true,
|
||||||
objc_extern_crate: false,
|
objc_extern_crate: false,
|
||||||
|
enable_mangling: true,
|
||||||
|
prepend_enum_name: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -653,23 +1005,15 @@ fn ensure_libclang_is_loaded() {
|
||||||
// across different threads.
|
// across different threads.
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref LIBCLANG: Mutex<Option<Arc<clang_sys::SharedLibrary>>> = {
|
static ref LIBCLANG: Arc<clang_sys::SharedLibrary> = {
|
||||||
Mutex::new(None)
|
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();
|
clang_sys::set_library(Some(LIBCLANG.clone()));
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generated Rust bindings.
|
/// Generated Rust bindings.
|
||||||
|
@ -716,6 +1060,10 @@ impl<'ctx> Bindings<'ctx> {
|
||||||
options.clang_args.push(h.clone())
|
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);
|
let mut context = BindgenContext::new(options);
|
||||||
try!(parse(&mut context));
|
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
|
/// Determines whether the given cursor is in any of the files matched by the
|
||||||
/// options.
|
/// options.
|
||||||
fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
|
fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
|
||||||
let (file, _, _, _) = cursor.location().location();
|
ctx.options().builtins || !cursor.is_builtin()
|
||||||
|
|
||||||
match file.name() {
|
|
||||||
None => ctx.options().builtins,
|
|
||||||
Some(..) => true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse one `Item` from the Clang cursor.
|
/// Parse one `Item` from the Clang cursor.
|
||||||
|
@ -847,8 +1190,17 @@ fn parse(context: &mut BindgenContext) -> Result<(), ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let cursor = context.translation_unit().cursor();
|
let cursor = context.translation_unit().cursor();
|
||||||
|
|
||||||
if context.options().emit_ast {
|
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();
|
let root = context.root_module();
|
||||||
|
@ -904,3 +1256,38 @@ pub fn clang_version() -> ClangVersion {
|
||||||
full: raw_v.clone(),
|
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 {
|
macro_rules! log {
|
||||||
(target: $target:expr, $lvl:expr, $($arg)+) => {
|
(target: $target:expr, $lvl:expr, $($arg:tt)+) => {
|
||||||
let _ = $target;
|
let _ = $target;
|
||||||
let _ = log!($lvl, $($arg)+);
|
let _ = log!($lvl, $($arg)+);
|
||||||
};
|
};
|
||||||
($lvl:expr, $($arg:tt)+) => {
|
($lvl:expr, $($arg:tt)+) => {{
|
||||||
let _ = $lvl;
|
let _ = $lvl;
|
||||||
let _ = format_args!($($arg)+);
|
let _ = format_args!($($arg)+);
|
||||||
};
|
}};
|
||||||
}
|
}
|
||||||
macro_rules! error {
|
macro_rules! error {
|
||||||
(target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
|
(target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
|
||||||
|
|
|
@ -1,19 +1,25 @@
|
||||||
extern crate bindgen;
|
extern crate bindgen;
|
||||||
|
#[cfg(feature="logging")]
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
#[cfg(feature="logging")]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate clang_sys;
|
extern crate clang_sys;
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate rustc_serialize;
|
|
||||||
|
|
||||||
use bindgen::clang_version;
|
use bindgen::clang_version;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::panic;
|
use std::panic;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
#[cfg(not(feature="logging"))]
|
||||||
|
mod log_stubs;
|
||||||
|
|
||||||
mod options;
|
mod options;
|
||||||
use options::builder_from_flags;
|
use options::builder_from_flags;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
#[cfg(feature="logging")]
|
||||||
log::set_logger(|max_log_level| {
|
log::set_logger(|max_log_level| {
|
||||||
use env_logger::Logger;
|
use env_logger::Logger;
|
||||||
let env_logger = Logger::new();
|
let env_logger = Logger::new();
|
||||||
|
|
|
@ -35,11 +35,14 @@ pub fn builder_from_flags<I>
|
||||||
.number_of_values(1),
|
.number_of_values(1),
|
||||||
Arg::with_name("blacklist-type")
|
Arg::with_name("blacklist-type")
|
||||||
.long("blacklist-type")
|
.long("blacklist-type")
|
||||||
.help("Mark a type as hidden.")
|
.help("Mark <type> as hidden.")
|
||||||
.value_name("type")
|
.value_name("type")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.multiple(true)
|
.multiple(true)
|
||||||
.number_of_values(1),
|
.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")
|
Arg::with_name("no-derive-debug")
|
||||||
.long("no-derive-debug")
|
.long("no-derive-debug")
|
||||||
.help("Avoid deriving Debug on any type."),
|
.help("Avoid deriving Debug on any type."),
|
||||||
|
@ -49,17 +52,20 @@ pub fn builder_from_flags<I>
|
||||||
.help("Avoid deriving Default on any type."),
|
.help("Avoid deriving Default on any type."),
|
||||||
Arg::with_name("with-derive-default")
|
Arg::with_name("with-derive-default")
|
||||||
.long("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")
|
Arg::with_name("no-doc-comments")
|
||||||
.long("no-doc-comments")
|
.long("no-doc-comments")
|
||||||
.help("Avoid including doc comments in the output, see: \
|
.help("Avoid including doc comments in the output, see: \
|
||||||
https://github.com/servo/rust-bindgen/issues/426"),
|
https://github.com/servo/rust-bindgen/issues/426"),
|
||||||
Arg::with_name("no-recursive-whitelist")
|
Arg::with_name("no-recursive-whitelist")
|
||||||
.long("no-recursive-whitelist")
|
.long("no-recursive-whitelist")
|
||||||
.help("Avoid whitelisting types recursively"),
|
.help("Avoid whitelisting types recursively."),
|
||||||
Arg::with_name("objc-extern-crate")
|
Arg::with_name("objc-extern-crate")
|
||||||
.long("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")
|
Arg::with_name("builtins")
|
||||||
.long("builtins")
|
.long("builtins")
|
||||||
.help("Output bindings for builtin definitions, e.g. \
|
.help("Output bindings for builtin definitions, e.g. \
|
||||||
|
@ -94,7 +100,9 @@ pub fn builder_from_flags<I>
|
||||||
.help("Enable support for C++ namespaces."),
|
.help("Enable support for C++ namespaces."),
|
||||||
Arg::with_name("disable-name-namespacing")
|
Arg::with_name("disable-name-namespacing")
|
||||||
.long("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")
|
Arg::with_name("framework")
|
||||||
.long("framework-link")
|
.long("framework-link")
|
||||||
.help("Link to framework.")
|
.help("Link to framework.")
|
||||||
|
@ -107,9 +115,9 @@ pub fn builder_from_flags<I>
|
||||||
is useful when you only care about struct layouts."),
|
is useful when you only care about struct layouts."),
|
||||||
Arg::with_name("generate")
|
Arg::with_name("generate")
|
||||||
.long("generate")
|
.long("generate")
|
||||||
.help("Generate a given kind of items, split by commas. \
|
.help("Generate only given items, split by commas. \
|
||||||
Valid values are \"functions\",\"types\", \"vars\" and \
|
Valid values are \"functions\",\"types\", \"vars\", \
|
||||||
\"methods\".")
|
\"methods\", \"constructors\" and \"destructors\".")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
Arg::with_name("ignore-methods")
|
Arg::with_name("ignore-methods")
|
||||||
.long("ignore-methods")
|
.long("ignore-methods")
|
||||||
|
@ -123,14 +131,17 @@ pub fn builder_from_flags<I>
|
||||||
.number_of_values(1),
|
.number_of_values(1),
|
||||||
Arg::with_name("no-convert-floats")
|
Arg::with_name("no-convert-floats")
|
||||||
.long("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")
|
Arg::with_name("no-unstable-rust")
|
||||||
.long("no-unstable-rust")
|
.long("no-unstable-rust")
|
||||||
.help("Do not generate unstable Rust code.")
|
.help("Do not generate unstable Rust code.")
|
||||||
.multiple(true), // FIXME: Pass legacy test suite
|
.multiple(true), // FIXME: Pass legacy test suite
|
||||||
Arg::with_name("opaque-type")
|
Arg::with_name("opaque-type")
|
||||||
.long("opaque-type")
|
.long("opaque-type")
|
||||||
.help("Mark a type as opaque.")
|
.help("Mark <type> as opaque.")
|
||||||
.value_name("type")
|
.value_name("type")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.multiple(true)
|
.multiple(true)
|
||||||
|
@ -171,6 +182,9 @@ pub fn builder_from_flags<I>
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.multiple(true)
|
.multiple(true)
|
||||||
.number_of_values(1),
|
.number_of_values(1),
|
||||||
|
Arg::with_name("generate-inline-functions")
|
||||||
|
.long("generate-inline-functions")
|
||||||
|
.help("Generate inline functions."),
|
||||||
Arg::with_name("whitelist-type")
|
Arg::with_name("whitelist-type")
|
||||||
.long("whitelist-type")
|
.long("whitelist-type")
|
||||||
.help("Whitelist the type. Other non-whitelisted types will \
|
.help("Whitelist the type. Other non-whitelisted types will \
|
||||||
|
@ -190,7 +204,7 @@ pub fn builder_from_flags<I>
|
||||||
.number_of_values(1),
|
.number_of_values(1),
|
||||||
Arg::with_name("verbose")
|
Arg::with_name("verbose")
|
||||||
.long("verbose")
|
.long("verbose")
|
||||||
.help("Print verbose error messages"),
|
.help("Print verbose error messages."),
|
||||||
]) // .args()
|
]) // .args()
|
||||||
.get_matches_from(args);
|
.get_matches_from(args);
|
||||||
|
|
||||||
|
@ -224,6 +238,10 @@ pub fn builder_from_flags<I>
|
||||||
builder = builder.emit_builtins();
|
builder = builder.emit_builtins();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if matches.is_present("no-layout-tests") {
|
||||||
|
builder = builder.layout_tests(false);
|
||||||
|
}
|
||||||
|
|
||||||
if matches.is_present("no-derive-debug") {
|
if matches.is_present("no-derive-debug") {
|
||||||
builder = builder.derive_debug(false);
|
builder = builder.derive_debug(false);
|
||||||
}
|
}
|
||||||
|
@ -236,6 +254,10 @@ pub fn builder_from_flags<I>
|
||||||
builder = builder.derive_default(false);
|
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") {
|
if let Some(prefix) = matches.value_of("ctypes-prefix") {
|
||||||
builder = builder.ctypes_prefix(prefix);
|
builder = builder.ctypes_prefix(prefix);
|
||||||
}
|
}
|
||||||
|
@ -258,6 +280,8 @@ pub fn builder_from_flags<I>
|
||||||
"types" => config.types = true,
|
"types" => config.types = true,
|
||||||
"vars" => config.vars = true,
|
"vars" => config.vars = true,
|
||||||
"methods" => config.methods = true,
|
"methods" => config.methods = true,
|
||||||
|
"constructors" => config.constructors = true,
|
||||||
|
"destructors" => config.destructors = true,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::new(ErrorKind::Other,
|
return Err(Error::new(ErrorKind::Other,
|
||||||
"Unknown generate item"));
|
"Unknown generate item"));
|
||||||
|
@ -317,6 +341,10 @@ pub fn builder_from_flags<I>
|
||||||
builder = builder.whitelist_recursively(false);
|
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") {
|
if let Some(opaque_types) = matches.values_of("opaque-type") {
|
||||||
for ty in opaque_types {
|
for ty in opaque_types {
|
||||||
builder = builder.opaque_type(ty);
|
builder = builder.opaque_type(ty);
|
||||||
|
@ -339,10 +367,18 @@ pub fn builder_from_flags<I>
|
||||||
builder = builder.use_core();
|
builder = builder.use_core();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if matches.is_present("distrust-clang-mangling") {
|
||||||
|
builder = builder.trust_clang_mangling(false);
|
||||||
|
}
|
||||||
|
|
||||||
if matches.is_present("conservative-inline-namespaces") {
|
if matches.is_present("conservative-inline-namespaces") {
|
||||||
builder = builder.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") {
|
if let Some(whitelist) = matches.values_of("whitelist-function") {
|
||||||
for regex in whitelist {
|
for regex in whitelist {
|
||||||
builder = builder.whitelisted_function(regex);
|
builder = builder.whitelisted_function(regex);
|
||||||
|
|
|
@ -49,7 +49,7 @@ pub trait ClangItemParser: Sized {
|
||||||
|
|
||||||
/// Parse this item from the given Clang type.
|
/// Parse this item from the given Clang type.
|
||||||
fn from_ty(ty: &clang::Type,
|
fn from_ty(ty: &clang::Type,
|
||||||
location: Option<clang::Cursor>,
|
location: clang::Cursor,
|
||||||
parent: Option<ItemId>,
|
parent: Option<ItemId>,
|
||||||
ctx: &mut BindgenContext)
|
ctx: &mut BindgenContext)
|
||||||
-> Result<ItemId, ParseError>;
|
-> Result<ItemId, ParseError>;
|
||||||
|
@ -58,7 +58,7 @@ pub trait ClangItemParser: Sized {
|
||||||
/// newly parsed item.
|
/// newly parsed item.
|
||||||
fn from_ty_with_id(id: ItemId,
|
fn from_ty_with_id(id: ItemId,
|
||||||
ty: &clang::Type,
|
ty: &clang::Type,
|
||||||
location: Option<clang::Cursor>,
|
location: clang::Cursor,
|
||||||
parent: Option<ItemId>,
|
parent: Option<ItemId>,
|
||||||
ctx: &mut BindgenContext)
|
ctx: &mut BindgenContext)
|
||||||
-> Result<ItemId, ParseError>;
|
-> 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
|
/// 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.
|
/// the other items this one depends on, an unresolved reference.
|
||||||
fn from_ty_or_ref(ty: clang::Type,
|
fn from_ty_or_ref(ty: clang::Type,
|
||||||
location: Option<clang::Cursor>,
|
location: clang::Cursor,
|
||||||
parent_id: Option<ItemId>,
|
parent_id: Option<ItemId>,
|
||||||
context: &mut BindgenContext)
|
context: &mut BindgenContext)
|
||||||
-> ItemId;
|
-> ItemId;
|
||||||
|
@ -75,26 +75,16 @@ pub trait ClangItemParser: Sized {
|
||||||
/// `ItemId` for the newly parsed item.
|
/// `ItemId` for the newly parsed item.
|
||||||
fn from_ty_or_ref_with_id(potential_id: ItemId,
|
fn from_ty_or_ref_with_id(potential_id: ItemId,
|
||||||
ty: clang::Type,
|
ty: clang::Type,
|
||||||
location: Option<clang::Cursor>,
|
location: clang::Cursor,
|
||||||
parent_id: Option<ItemId>,
|
parent_id: Option<ItemId>,
|
||||||
context: &mut BindgenContext)
|
context: &mut BindgenContext)
|
||||||
-> ItemId;
|
-> ItemId;
|
||||||
|
|
||||||
/// Create a named template type.
|
/// Create a named template type.
|
||||||
fn named_type<S>(name: S,
|
fn named_type(with_id: Option<ItemId>,
|
||||||
parent: ItemId,
|
location: clang::Cursor,
|
||||||
context: &mut BindgenContext)
|
ctx: &mut BindgenContext)
|
||||||
-> ItemId
|
-> Option<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>;
|
|
||||||
|
|
||||||
/// Create a builtin type.
|
/// Create a builtin type.
|
||||||
fn builtin_type(kind: TypeKind,
|
fn builtin_type(kind: TypeKind,
|
||||||
|
|
|
@ -35,6 +35,15 @@ impl RegexSet {
|
||||||
self.items.push(format!("^{}$", string.as_ref()));
|
self.items.push(format!("^{}$", string.as_ref()));
|
||||||
self.set = None;
|
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.
|
/// Construct a RegexSet from the set of entries we've accumulated.
|
||||||
///
|
///
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
use ir::context::BindgenContext;
|
use ir::context::BindgenContext;
|
||||||
use ir::item::{Item, ItemAncestors, ItemCanonicalName};
|
use ir::item::{Item, ItemAncestors, ItemCanonicalName};
|
||||||
|
use ir::template::TemplateParameters;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
// Like `canonical_path`, except we always take namespaces into account, ignore
|
// 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.
|
// these.
|
||||||
!ty.is_builtin_or_named() &&
|
!ty.is_builtin_or_named() &&
|
||||||
// And finally, we won't be creating any dummy
|
// And finally, we won't be creating any dummy
|
||||||
// specializations, so ignore template declarations and
|
// instantiations, so ignore template declarations and
|
||||||
// partial specializations.
|
// instantiations.
|
||||||
item.applicable_template_args(ctx).is_empty()
|
item.all_template_params(ctx).is_none()
|
||||||
} else {
|
} else {
|
||||||
false
|
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;
|
|
||||||
};
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче