Skip to content

Commit 959ef7c

Browse files
author
bors-servo
authored
Auto merge of #332 - emilio:constructors, r=fitzgen
Add support for constructors, and integration tests. r? @fitzgen cc @vvuk
2 parents a0ace87 + 1daf989 commit 959ef7c

File tree

15 files changed

+338
-72
lines changed

15 files changed

+338
-72
lines changed

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ script:
3737
- cd ../../../bindgen
3838
- cargo test --features "$BINDGEN_FEATURES"
3939
- cargo test --release --features "$BINDGEN_FEATURES"
40+
- cd ../bindgen-integration
41+
- cargo test --features "$BINDGEN_FEATURES"
42+
- cargo test --release --features "$BINDGEN_FEATURES"
4043

4144
notifications:
4245
webhooks: http://build.servo.org:54856/travis

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[workspace]
22
members = [
33
"bindgen",
4+
"bindgen-integration",
45
"libbindgen",
56
"libbindgen/tests/expectations",
67
]

bindgen-integration/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "bindgen-integration"
3+
description = "A package to test various bindgen features"
4+
version = "0.1.0"
5+
authors = ["Emilio Cobos Álvarez <[email protected]>"]
6+
workspace = ".."
7+
publish = false
8+
build = "build.rs"
9+
10+
[build-dependencies]
11+
libbindgen = { path = "../libbindgen" }
12+
gcc = "0.3"
13+
14+
[features]
15+
llvm_stable = ["libbindgen/llvm_stable"]

bindgen-integration/build.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
extern crate libbindgen;
2+
extern crate gcc;
3+
4+
use std::env;
5+
use std::path::PathBuf;
6+
use libbindgen::Builder;
7+
8+
fn main() {
9+
gcc::Config::new()
10+
.cpp(true)
11+
.file("cpp/Test.cc")
12+
.compile("libtest.a");
13+
14+
let bindings = Builder::default()
15+
.no_unstable_rust()
16+
.header("cpp/Test.h")
17+
.clang_arg("-x")
18+
.clang_arg("c++")
19+
.clang_arg("-std=c++11")
20+
.generate()
21+
.expect("Unable to generate bindings");
22+
23+
24+
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
25+
bindings
26+
.write_to_file(out_path.join("test.rs"))
27+
.expect("Couldn't write bindings!");
28+
}

bindgen-integration/cpp/Test.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "Test.h"
2+
3+
const char* Test::name() {
4+
return "Test";
5+
}
6+
7+
Test::Test(int foo)
8+
: m_int(foo)
9+
, m_double(0.0)
10+
{}
11+
12+
Test::Test(double foo)
13+
: m_int(0)
14+
, m_double(foo)
15+
{}

bindgen-integration/cpp/Test.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#pragma once
2+
3+
class Test {
4+
int m_int;
5+
double m_double;
6+
public:
7+
static const char* name();
8+
Test(int foo);
9+
Test(double foo);
10+
};

bindgen-integration/src/lib.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
mod bindings {
2+
include!(concat!(env!("OUT_DIR"), "/test.rs"));
3+
}
4+
5+
use std::ffi::CStr;
6+
7+
#[test]
8+
fn test_static_method() {
9+
let c_str = unsafe { bindings::Test::name() };
10+
let name = unsafe {
11+
CStr::from_ptr(c_str).to_string_lossy().into_owned()
12+
};
13+
assert_eq!(name, "Test", "Calling a static C++ method works!");
14+
}
15+
16+
#[test]
17+
fn test_constructor() {
18+
let test = unsafe { bindings::Test::new(5) };
19+
assert_eq!(test.m_int, 5);
20+
assert_eq!(test.m_double, 0.0);
21+
}
22+
23+
#[test]
24+
fn test_overload() {
25+
let test = unsafe { bindings::Test::new1(5.0) };
26+
assert_eq!(test.m_int, 0);
27+
assert_eq!(test.m_double, 5.0);
28+
}

libbindgen/src/codegen/helpers.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ impl BlobTyBuilder {
7575
pub mod ast_ty {
7676
use aster;
7777
use ir::context::BindgenContext;
78+
use ir::function::FunctionSig;
7879
use ir::ty::FloatKind;
7980
use syntax::ast;
8081
use syntax::ptr::P;
@@ -164,4 +165,25 @@ pub mod ast_ty {
164165
let kind = ast::LitKind::FloatUnsuffixed(interned_str);
165166
aster::AstBuilder::new().expr().lit().build_lit(kind)
166167
}
168+
169+
pub fn arguments_from_signature(signature: &FunctionSig,
170+
ctx: &BindgenContext)
171+
-> Vec<P<ast::Expr>> {
172+
// TODO: We need to keep in sync the argument names, so we should unify
173+
// this with the other loop that decides them.
174+
let mut unnamed_arguments = 0;
175+
signature.argument_types()
176+
.iter()
177+
.map(|&(ref name, _ty)| {
178+
let arg_name = match *name {
179+
Some(ref name) => ctx.rust_mangle(name).into_owned(),
180+
None => {
181+
unnamed_arguments += 1;
182+
format!("arg{}", unnamed_arguments)
183+
}
184+
};
185+
aster::expr::ExprBuilder::new().id(arg_name)
186+
})
187+
.collect::<Vec<_>>()
188+
}
167189
}

libbindgen/src/codegen/mod.rs

Lines changed: 62 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ mod helpers;
44
use aster;
55

66
use ir::annotations::FieldAccessorKind;
7-
use ir::comp::{CompInfo, CompKind, Field, Method};
7+
use ir::comp::{CompInfo, CompKind, Field, Method, MethodKind};
88
use ir::context::{BindgenContext, ItemId};
99
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
1010
use ir::function::{Function, FunctionSig};
@@ -1181,15 +1181,28 @@ impl CodeGenerator for CompInfo {
11811181
result.push(item);
11821182
}
11831183

1184+
let mut method_names = Default::default();
11841185
if ctx.options().codegen_config.methods {
1185-
let mut method_names = Default::default();
11861186
for method in self.methods() {
1187+
assert!(method.kind() != MethodKind::Constructor);
11871188
method.codegen_method(ctx,
11881189
&mut methods,
11891190
&mut method_names,
11901191
result,
11911192
whitelisted_items,
1192-
item);
1193+
self);
1194+
}
1195+
}
1196+
1197+
if ctx.options().codegen_config.constructors {
1198+
for sig in self.constructors() {
1199+
Method::new(MethodKind::Constructor, *sig, /* const */ false)
1200+
.codegen_method(ctx,
1201+
&mut methods,
1202+
&mut method_names,
1203+
result,
1204+
whitelisted_items,
1205+
self);
11931206
}
11941207
}
11951208
}
@@ -1242,7 +1255,7 @@ trait MethodCodegen {
12421255
method_names: &mut HashMap<String, usize>,
12431256
result: &mut CodegenResult<'a>,
12441257
whitelisted_items: &ItemSet,
1245-
parent: &Item);
1258+
parent: &CompInfo);
12461259
}
12471260

12481261
impl MethodCodegen for Method {
@@ -1252,18 +1265,21 @@ impl MethodCodegen for Method {
12521265
method_names: &mut HashMap<String, usize>,
12531266
result: &mut CodegenResult<'a>,
12541267
whitelisted_items: &ItemSet,
1255-
_parent: &Item) {
1268+
_parent: &CompInfo) {
12561269
if self.is_virtual() {
12571270
return; // FIXME
12581271
}
12591272
// First of all, output the actual function.
1260-
ctx.resolve_item(self.signature())
1261-
.codegen(ctx, result, whitelisted_items, &());
1262-
12631273
let function_item = ctx.resolve_item(self.signature());
1274+
function_item.codegen(ctx, result, whitelisted_items, &());
1275+
12641276
let function = function_item.expect_function();
1265-
let mut name = function.name().to_owned();
12661277
let signature_item = ctx.resolve_item(function.signature());
1278+
let mut name = match self.kind() {
1279+
MethodKind::Constructor => "new".into(),
1280+
_ => function.name().to_owned(),
1281+
};
1282+
12671283
let signature = match *signature_item.expect_type().kind() {
12681284
TypeKind::Function(ref sig) => sig,
12691285
_ => panic!("How in the world?"),
@@ -1283,7 +1299,7 @@ impl MethodCodegen for Method {
12831299
let function_name = function_item.canonical_name(ctx);
12841300
let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item)
12851301
.unwrap();
1286-
if !self.is_static() {
1302+
if !self.is_static() && !self.is_constructor() {
12871303
let mutability = if self.is_const() {
12881304
ast::Mutability::Immutable
12891305
} else {
@@ -1319,32 +1335,39 @@ impl MethodCodegen for Method {
13191335
};
13201336
}
13211337

1338+
// If it's a constructor, we always return `Self`, and we inject the
1339+
// "this" parameter, so there's no need to ask the user for it.
1340+
//
1341+
// Note that constructors in Clang are represented as functions with
1342+
// return-type = void.
1343+
if self.is_constructor() {
1344+
fndecl.inputs.remove(0);
1345+
fndecl.output = ast::FunctionRetTy::Ty(quote_ty!(ctx.ext_cx(), Self));
1346+
}
1347+
13221348
let sig = ast::MethodSig {
13231349
unsafety: ast::Unsafety::Unsafe,
13241350
abi: Abi::Rust,
1325-
decl: P(fndecl.clone()),
1351+
decl: P(fndecl),
13261352
generics: ast::Generics::default(),
13271353
constness: respan(ctx.span(), ast::Constness::NotConst),
13281354
};
13291355

1330-
// TODO: We need to keep in sync the argument names, so we should unify
1331-
// this with the other loop that decides them.
1332-
let mut unnamed_arguments = 0;
1333-
let mut exprs = signature.argument_types()
1334-
.iter()
1335-
.map(|&(ref name, _ty)| {
1336-
let arg_name = match *name {
1337-
Some(ref name) => ctx.rust_mangle(name).into_owned(),
1338-
None => {
1339-
unnamed_arguments += 1;
1340-
format!("arg{}", unnamed_arguments)
1341-
}
1342-
};
1343-
aster::expr::ExprBuilder::new().id(arg_name)
1344-
})
1345-
.collect::<Vec<_>>();
1356+
let mut exprs =
1357+
helpers::ast_ty::arguments_from_signature(&signature, ctx);
1358+
1359+
let mut stmts = vec![];
13461360

1347-
if !self.is_static() {
1361+
// If it's a constructor, we need to insert an extra parameter with a
1362+
// variable called `__bindgen_tmp` we're going to create.
1363+
if self.is_constructor() {
1364+
let tmp_variable_decl =
1365+
quote_stmt!(ctx.ext_cx(),
1366+
let mut __bindgen_tmp = ::std::mem::uninitialized())
1367+
.unwrap();
1368+
stmts.push(tmp_variable_decl);
1369+
exprs[0] = quote_expr!(ctx.ext_cx(), &mut __bindgen_tmp);
1370+
} else if !self.is_static() {
13481371
assert!(!exprs.is_empty());
13491372
exprs[0] = if self.is_const() {
13501373
quote_expr!(ctx.ext_cx(), &*self)
@@ -1359,14 +1382,18 @@ impl MethodCodegen for Method {
13591382
.with_args(exprs)
13601383
.build();
13611384

1385+
stmts.push(ast::Stmt {
1386+
id: ast::DUMMY_NODE_ID,
1387+
node: ast::StmtKind::Expr(call),
1388+
span: ctx.span(),
1389+
});
1390+
1391+
if self.is_constructor() {
1392+
stmts.push(quote_stmt!(ctx.ext_cx(), __bindgen_tmp).unwrap());
1393+
}
1394+
13621395
let block = ast::Block {
1363-
stmts: vec![
1364-
ast::Stmt {
1365-
id: ast::DUMMY_NODE_ID,
1366-
node: ast::StmtKind::Expr(call),
1367-
span: ctx.span(),
1368-
}
1369-
],
1396+
stmts: stmts,
13701397
id: ast::DUMMY_NODE_ID,
13711398
rules: ast::BlockCheckMode::Default,
13721399
span: ctx.span(),

0 commit comments

Comments
 (0)