Skip to content

Commit e24e134

Browse files
committed
Support in-class constants in C++
1 parent c769d1b commit e24e134

20 files changed

+118
-45
lines changed

src/gen.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,10 +1242,24 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>
12421242
_ => unreachable!()
12431243
}
12441244
}
1245-
if mangledlist.len() > 0 {
1246-
items.push(mk_extern(ctx, &vec![], mangledlist, Abi::C));
1245+
if !mangledlist.is_empty() {
1246+
items.push(mk_extern(ctx, &[], mangledlist, Abi::C));
12471247
items.push(mk_impl(ctx, id_ty, unmangledlist));
12481248
}
1249+
1250+
if !ci.vars.is_empty() {
1251+
let vars = ci.vars.into_iter().map(|v| {
1252+
let vi = v.varinfo();
1253+
let v = vi.borrow_mut();
1254+
let mut var_name = v.name.clone();
1255+
if !v.mangled.is_empty() {
1256+
var_name = format!("{}_consts_{}", name, v.name);
1257+
}
1258+
cvar_to_rs(ctx, var_name, v.mangled.clone(), &v.ty, v.is_const)
1259+
}).collect();
1260+
1261+
items.push(mk_extern(ctx, &[], vars, Abi::C));
1262+
}
12491263
items
12501264
}
12511265

@@ -2301,6 +2315,7 @@ fn gen_union_field_definitions_if_necessary(ctx: &mut GenCtx, mut root_mod: &mut
23012315

23022316
let union_fields_decl = quote_item!(&ctx.ext_cx,
23032317
#[derive(Copy, Debug)]
2318+
#[repr(C)]
23042319
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
23052320
).unwrap();
23062321

src/parser.rs

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct ClangParserCtx<'a> {
3737
builtin_defs: Vec<Cursor>,
3838
module_map: ModuleMap,
3939
current_module_id: ModuleId,
40+
current_translation_unit: TranslationUnit,
4041
logger: &'a (Logger+'a),
4142
err_count: i32,
4243
anonymous_modules_found: usize,
@@ -185,8 +186,15 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
185186
}
186187
CXCursor_VarDecl => {
187188
let mangled = cursor.mangling();
188-
let vi = Rc::new(RefCell::new(VarInfo::new(spelling, mangled, comment, TVoid)));
189-
GVar(vi)
189+
let is_const = ty.is_const();
190+
let ty = conv_ty_resolving_typedefs(ctx, &ty, &cursor, true);
191+
let mut vi = VarInfo::new(spelling, mangled, comment, ty);
192+
vi.is_const = is_const;
193+
cursor.visit(|c, _: &Cursor| {
194+
vi.val = visit_literal(c, &ctx.current_translation_unit);
195+
CXChildVisit_Continue
196+
});
197+
GVar(Rc::new(RefCell::new(vi)))
190198
}
191199
CXCursor_MacroDefinition => {
192200
let vi = Rc::new(RefCell::new(VarInfo::new(spelling, String::new(), comment, TVoid)));
@@ -972,13 +980,26 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
972980
cursor.location()), false);
973981
ci.has_non_type_template_params = true;
974982
}
983+
CXCursor_VarDecl => {
984+
let linkage = cursor.linkage();
985+
if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal {
986+
return CXChildVisit_Continue;
987+
}
988+
989+
let visibility = cursor.visibility();
990+
if visibility != CXVisibility_Default {
991+
return CXChildVisit_Continue;
992+
}
993+
994+
let var = decl_name(ctx, cursor);
995+
ci.vars.push(var);
996+
}
975997
// Intentionally not handled
976998
CXCursor_CXXAccessSpecifier |
977999
CXCursor_CXXFinalAttr |
9781000
CXCursor_Constructor |
9791001
CXCursor_FunctionTemplate |
980-
CXCursor_ConversionFunction |
981-
CXCursor_VarDecl => {}
1002+
CXCursor_ConversionFunction => {}
9821003
_ => {
9831004
// XXX: Some kind of warning would be nice, but this produces far
9841005
// too many.
@@ -1035,8 +1056,7 @@ fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option<i64> {
10351056
}
10361057

10371058
fn visit_top(cursor: &Cursor,
1038-
mut ctx: &mut ClangParserCtx,
1039-
unit: &TranslationUnit) -> Enum_CXVisitorResult {
1059+
mut ctx: &mut ClangParserCtx) -> Enum_CXVisitorResult {
10401060
if !match_pattern(ctx, cursor) {
10411061
return CXChildVisit_Continue;
10421062
}
@@ -1194,17 +1214,8 @@ fn visit_top(cursor: &Cursor,
11941214
if visibility != CXVisibility_Default {
11951215
return CXChildVisit_Continue;
11961216
}
1197-
let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
1198-
let var = decl_name(ctx, cursor);
1199-
let vi = var.varinfo();
1200-
let mut vi = vi.borrow_mut();
1201-
vi.ty = ty.clone();
1202-
vi.is_const = cursor.cur_type().is_const();
1203-
cursor.visit(|c, _: &Cursor| {
1204-
vi.val = visit_literal(c, unit);
1205-
CXChildVisit_Continue
1206-
});
1207-
ctx.current_module_mut().globals.push(var);
1217+
let val = decl_name(ctx, cursor);
1218+
ctx.current_module_mut().globals.push(val);
12081219

12091220
CXChildVisit_Continue
12101221
}
@@ -1255,7 +1266,7 @@ fn visit_top(cursor: &Cursor,
12551266
return CXChildVisit_Recurse;
12561267
}
12571268

1258-
let namespace_name = match unit.tokens(cursor) {
1269+
let namespace_name = match ctx.current_translation_unit.tokens(cursor) {
12591270
None => None,
12601271
Some(tokens) => {
12611272
if tokens.len() <= 1 {
@@ -1292,13 +1303,13 @@ fn visit_top(cursor: &Cursor,
12921303
let previous_id = ctx.current_module_id;
12931304

12941305
ctx.current_module_id = mod_id;
1295-
cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx, &unit));
1306+
cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx));
12961307
ctx.current_module_id = previous_id;
12971308

12981309
return CXChildVisit_Continue;
12991310
}
13001311
CXCursor_MacroDefinition => {
1301-
let val = parse_int_literal_tokens(cursor, unit, 1);
1312+
let val = parse_int_literal_tokens(cursor, &ctx.current_translation_unit, 1);
13021313
if val.is_none() {
13031314
// Not an integer literal.
13041315
return CXChildVisit_Continue;
@@ -1334,32 +1345,33 @@ fn log_err_warn(ctx: &mut ClangParserCtx, msg: &str, is_err: bool) {
13341345
}
13351346

13361347
pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<ModuleMap, ()> {
1348+
let ix = cx::Index::create(false, true);
1349+
if ix.is_null() {
1350+
logger.error("Clang failed to create index");
1351+
return Err(())
1352+
}
1353+
1354+
let unit = TranslationUnit::parse(&ix, "", &options.clang_args, &[], CXTranslationUnit_DetailedPreprocessingRecord);
1355+
if unit.is_null() {
1356+
logger.error("No input files given");
1357+
return Err(())
1358+
}
1359+
13371360
let mut ctx = ClangParserCtx {
13381361
options: options,
13391362
name: HashMap::new(),
13401363
builtin_defs: vec!(),
13411364
module_map: ModuleMap::new(),
13421365
current_module_id: ROOT_MODULE_ID,
1366+
current_translation_unit: unit,
13431367
logger: logger,
13441368
err_count: 0,
13451369
anonymous_modules_found: 0,
13461370
};
13471371

13481372
ctx.module_map.insert(ROOT_MODULE_ID, Module::new("root".to_owned(), None));
13491373

1350-
let ix = cx::Index::create(false, true);
1351-
if ix.is_null() {
1352-
ctx.logger.error("Clang failed to create index");
1353-
return Err(())
1354-
}
1355-
1356-
let unit = TranslationUnit::parse(&ix, "", &ctx.options.clang_args[..], &[], CXTranslationUnit_DetailedPreprocessingRecord);
1357-
if unit.is_null() {
1358-
ctx.logger.error("No input files given");
1359-
return Err(())
1360-
}
1361-
1362-
let diags = unit.diags();
1374+
let diags = ctx.current_translation_unit.diags();
13631375
for d in &diags {
13641376
let msg = d.format(Diagnostic::default_opts());
13651377
let is_err = d.severity() >= CXDiagnostic_Error;
@@ -1370,20 +1382,20 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<ModuleMap,
13701382
return Err(())
13711383
}
13721384

1373-
let cursor = unit.cursor();
1385+
let cursor = ctx.current_translation_unit.cursor();
13741386

13751387
if ctx.options.emit_ast {
13761388
cursor.visit(|cur, _: &Cursor| ast_dump(cur, 0));
13771389
}
13781390

1379-
cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx, &unit));
1391+
cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx));
13801392

13811393
while !ctx.builtin_defs.is_empty() {
13821394
let c = ctx.builtin_defs.remove(0);
1383-
visit_top(&c.definition(), &mut ctx, &unit);
1395+
visit_top(&c.definition(), &mut ctx);
13841396
}
13851397

1386-
unit.dispose();
1398+
ctx.current_translation_unit.dispose();
13871399
ix.dispose();
13881400

13891401
if ctx.err_count > 0 {

src/types.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ impl Module {
5555
}
5656
}
5757

58-
#[derive(Clone)]
58+
#[derive(Clone, PartialEq)]
5959
pub enum Global {
6060
GType(Rc<RefCell<TypeInfo>>),
6161
GComp(Rc<RefCell<CompInfo>>),
@@ -435,6 +435,8 @@ pub struct CompInfo {
435435
pub has_non_type_template_params: bool,
436436
/// If this type was unnamed when parsed
437437
pub was_unnamed: bool,
438+
/// Set of static vars declared inside this class.
439+
pub vars: Vec<Global>,
438440
/// Used to detect if we've run in a can_derive_debug cycle while
439441
/// cycling around the template arguments.
440442
detect_derive_debug_cycle: Cell<bool>,
@@ -467,9 +469,9 @@ impl CompInfo {
467469
filename: filename,
468470
comment: comment,
469471
members: members,
470-
args: vec!(),
471-
methods: vec!(),
472-
vmethods: vec!(),
472+
args: vec![],
473+
methods: vec![],
474+
vmethods: vec![],
473475
ref_template: None,
474476
has_vtable: false,
475477
has_destructor: false,
@@ -479,7 +481,8 @@ impl CompInfo {
479481
opaque: false,
480482
base_members: 0,
481483
layout: layout,
482-
typedefs: vec!(),
484+
typedefs: vec![],
485+
vars: vec![],
483486
has_non_type_template_params: false,
484487
was_unnamed: was_unnamed,
485488
detect_derive_debug_cycle: Cell::new(false),

tests/expectations/class.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/class_static.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![feature(const_fn)]
5+
#![allow(non_snake_case)]
6+
7+
8+
#[repr(C)]
9+
#[derive(Debug, Copy)]
10+
pub struct Struct_MyClass;
11+
impl ::std::clone::Clone for Struct_MyClass {
12+
fn clone(&self) -> Self { *self }
13+
}
14+
extern "C" {
15+
#[link_name = "_ZN7MyClass7exampleE"]
16+
pub static mut Struct_MyClass_consts_example:
17+
*const ::std::os::raw::c_int;
18+
#[link_name = "_ZN7MyClass26example_check_no_collisionE"]
19+
pub static mut Struct_MyClass_consts_example_check_no_collision:
20+
*const ::std::os::raw::c_int;
21+
}

tests/expectations/class_with_inner_struct.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/jsval_layout_opaque.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/struct_with_anon_union.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/struct_with_anon_unnamed_union.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/struct_with_nesting.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/union_fields.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/union_with_anon_struct.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/union_with_anon_struct_bitfield.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/union_with_anon_union.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/union_with_anon_unnamed_struct.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/union_with_anon_unnamed_union.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/union_with_big_member.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/expectations/union_with_nesting.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#[derive(Copy, Debug)]
9+
#[repr(C)]
910
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
1011
impl <T> __BindgenUnionField<T> {
1112
#[inline]

tests/headers/class_static.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class MyClass {
2+
public:
3+
static const int* example;
4+
static const int* example_check_no_collision;
5+
};
6+
7+
static const int* example_check_no_collision;

0 commit comments

Comments
 (0)