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:
Emilio Cobos Álvarez 2017-05-08 21:04:51 +02:00
Родитель b6d4239e55
Коммит 4fa90b8c5b
436 изменённых файлов: 12276 добавлений и 20522 удалений

2
third_party/rust/aster/.cargo-checksum.json поставляемый
Просмотреть файл

@ -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"}

6
third_party/rust/aster/Cargo.toml поставляемый
Просмотреть файл

@ -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"

3
third_party/rust/aster/src/expr.rs поставляемый
Просмотреть файл

@ -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))
} }
} }

7
third_party/rust/aster/src/generics.rs поставляемый
Просмотреть файл

@ -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,

4
third_party/rust/aster/src/item.rs поставляемый
Просмотреть файл

@ -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)
} }

5
third_party/rust/aster/src/pat.rs поставляемый
Просмотреть файл

@ -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(),
}) })
} }
} }

4
third_party/rust/aster/src/path.rs поставляемый
Просмотреть файл

@ -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)))

95
third_party/rust/aster/src/ty.rs поставляемый
Просмотреть файл

@ -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))
} }
} }

4
third_party/rust/aster/src/ty_param.rs поставляемый
Просмотреть файл

@ -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,
}) })

14
third_party/rust/aster/src/where_predicate.rs поставляемый
Просмотреть файл

@ -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))

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

59
third_party/rust/bindgen/.github/ISSUE_TEMPLATE.md поставляемый Normal file
Просмотреть файл

@ -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>

26
third_party/rust/bindgen/.travis.yml поставляемый
Просмотреть файл

@ -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

73
third_party/rust/bindgen/CONTRIBUTING.md поставляемый
Просмотреть файл

@ -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

30
third_party/rust/bindgen/Cargo.toml поставляемый
Просмотреть файл

@ -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 = []

234
third_party/rust/bindgen/README.md поставляемый
Просмотреть файл

@ -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.

1
third_party/rust/bindgen/book/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
book

3
third_party/rust/bindgen/book/book.toml поставляемый Normal file
Просмотреть файл

@ -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."

20
third_party/rust/bindgen/book/src/SUMMARY.md поставляемый Normal file
Просмотреть файл

@ -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)

26
third_party/rust/bindgen/book/src/blacklisting.md поставляемый Normal file
Просмотреть файл

@ -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 {
// ...
};
```

1
third_party/rust/bindgen/book/src/chapter_1.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
# Chapter 1

27
third_party/rust/bindgen/book/src/command-line-usage.md поставляемый Normal file
Просмотреть файл

@ -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
```

27
third_party/rust/bindgen/book/src/cpp.md поставляемый Normal file
Просмотреть файл

@ -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.

34
third_party/rust/bindgen/book/src/introduction.md поставляемый Normal file
Просмотреть файл

@ -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);
}
```

22
third_party/rust/bindgen/book/src/library-usage.md поставляемый Normal file
Просмотреть файл

@ -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`.

20
third_party/rust/bindgen/book/src/nocopy.md поставляемый Normal file
Просмотреть файл

@ -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;
// ...
};
```

26
third_party/rust/bindgen/book/src/opaque.md поставляемый Normal file
Просмотреть файл

@ -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 {
// ...
};
```

27
third_party/rust/bindgen/book/src/replacing-types.md поставляемый Normal file
Просмотреть файл

@ -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).

67
third_party/rust/bindgen/book/src/requirements.md поставляемый Normal file
Просмотреть файл

@ -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

12
third_party/rust/bindgen/book/src/tutorial-0.md поставляемый Normal file
Просмотреть файл

@ -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

9
third_party/rust/bindgen/book/src/tutorial-1.md поставляемый Normal file
Просмотреть файл

@ -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"
```

20
third_party/rust/bindgen/book/src/tutorial-2.md поставляемый Normal file
Просмотреть файл

@ -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

58
third_party/rust/bindgen/book/src/tutorial-3.md поставляемый Normal file
Просмотреть файл

@ -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

57
third_party/rust/bindgen/book/src/tutorial-4.md поставляемый Normal file
Просмотреть файл

@ -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
```

169
third_party/rust/bindgen/book/src/tutorial-5.md поставляемый Normal file
Просмотреть файл

@ -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
```

13
third_party/rust/bindgen/book/src/tutorial-6.md поставляемый Normal file
Просмотреть файл

@ -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

31
third_party/rust/bindgen/book/src/whitelisting.md поставляемый Normal file
Просмотреть файл

@ -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.

15
third_party/rust/bindgen/build.rs поставляемый
Просмотреть файл

@ -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) {

2
third_party/rust/bindgen/ci/assert-docs.sh поставляемый
Просмотреть файл

@ -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"

12
third_party/rust/bindgen/ci/before_install.sh поставляемый
Просмотреть файл

@ -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

33
third_party/rust/bindgen/ci/deploy-book.sh поставляемый Executable file
Просмотреть файл

@ -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

10
third_party/rust/bindgen/ci/test-book.sh поставляемый Executable file
Просмотреть файл

@ -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

7
third_party/rust/bindgen/ci/test.sh поставляемый
Просмотреть файл

@ -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.

Двоичные данные
third_party/rust/bindgen/example-graphviz-ir.png поставляемый Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 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> {

149
third_party/rust/bindgen/src/clang.rs поставляемый
Просмотреть файл

@ -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 =

41
third_party/rust/bindgen/src/codegen/error.rs поставляемый Normal file
Просмотреть файл

@ -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,

1348
third_party/rust/bindgen/src/codegen/mod.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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?

30
third_party/rust/bindgen/src/extra_assertions.rs поставляемый Normal file
Просмотреть файл

@ -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 )* );
}
};
}

286
third_party/rust/bindgen/src/ir/comp.rs поставляемый
Просмотреть файл

@ -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);
} }
} }
} }

392
third_party/rust/bindgen/src/ir/context.rs поставляемый
Просмотреть файл

@ -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() {

62
third_party/rust/bindgen/src/ir/dot.rs поставляемый Normal file
Просмотреть файл

@ -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(())
}

9
third_party/rust/bindgen/src/ir/enum_ty.rs поставляемый
Просмотреть файл

@ -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)
}) })

154
third_party/rust/bindgen/src/ir/function.rs поставляемый
Просмотреть файл

@ -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,
} }
} }
} }

16
third_party/rust/bindgen/src/ir/int.rs поставляемый
Просмотреть файл

@ -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,

650
third_party/rust/bindgen/src/ir/item.rs поставляемый
Просмотреть файл

@ -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)
} }
} }

27
third_party/rust/bindgen/src/ir/item_kind.rs поставляемый
Просмотреть файл

@ -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),
}
}
}

17
third_party/rust/bindgen/src/ir/layout.rs поставляемый
Просмотреть файл

@ -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> {

2
third_party/rust/bindgen/src/ir/mod.rs поставляемый
Просмотреть файл

@ -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;

13
third_party/rust/bindgen/src/ir/module.rs поставляемый
Просмотреть файл

@ -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)

547
third_party/rust/bindgen/src/ir/named.rs поставляемый
Просмотреть файл

@ -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);

156
third_party/rust/bindgen/src/ir/objc.rs поставляемый
Просмотреть файл

@ -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);
}
}
}

343
third_party/rust/bindgen/src/ir/template.rs поставляемый Normal file
Просмотреть файл

@ -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);
}
}
}

136
third_party/rust/bindgen/src/ir/traversal.rs поставляемый
Просмотреть файл

@ -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

1070
third_party/rust/bindgen/src/ir/ty.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

40
third_party/rust/bindgen/src/ir/var.rs поставляемый
Просмотреть файл

@ -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)))

489
third_party/rust/bindgen/src/lib.rs поставляемый
Просмотреть файл

@ -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)) );
}

6
third_party/rust/bindgen/src/log_stubs.rs поставляемый
Просмотреть файл

@ -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)*); };

8
third_party/rust/bindgen/src/main.rs поставляемый
Просмотреть файл

@ -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();

58
third_party/rust/bindgen/src/options.rs поставляемый
Просмотреть файл

@ -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);

26
third_party/rust/bindgen/src/parse.rs поставляемый
Просмотреть файл

@ -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,

9
third_party/rust/bindgen/src/regex_set.rs поставляемый
Просмотреть файл

@ -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.
/// ///

7
third_party/rust/bindgen/src/uses.rs поставляемый
Просмотреть файл

@ -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;
};

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше