Skip to content

Commit c48f835

Browse files
author
bors-servo
authored
Auto merge of #281 - fitzgen:namespace-mangle-rust-symbols, r=emilio
Include namespaces in mangled symbols When we aren't using `--enable-cxx-namespaces`, we can end up with conflicting struct symbol names that we need to disambiguate. The solution is to mangle the namespaced C++ symbol "foo::bar::Baz" into the Rust "foo_bar_Baz" symbol. This did change the way anonymous types and modules get named a little, but I think our approach is much more sane now than it was before. Fixes #267. r? @emilio
2 parents 0674f60 + 2a93411 commit c48f835

14 files changed

+255
-203
lines changed

libbindgen/src/ir/item.rs

Lines changed: 130 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
33
use clang;
44
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
5-
use regex::Regex;
65
use std::cell::{Cell, RefCell};
6+
use std::fmt::Write;
77
use super::annotations::Annotations;
88
use super::context::{BindgenContext, ItemId};
99
use super::function::Function;
@@ -490,7 +490,8 @@ impl Item {
490490
}
491491
}
492492

493-
fn is_module(&self) -> bool {
493+
/// Is this item a module?
494+
pub fn is_module(&self) -> bool {
494495
match self.kind {
495496
ItemKind::Module(..) => true,
496497
_ => false,
@@ -525,6 +526,108 @@ impl Item {
525526
self.as_type().map_or(false, |ty| ty.is_type_ref())
526527
}
527528

529+
/// Get the target item id for name generation.
530+
fn name_target(&self, ctx: &BindgenContext, for_name_checking: bool) -> ItemId {
531+
let mut item = self;
532+
loop {
533+
match *item.kind() {
534+
ItemKind::Type(ref ty) => {
535+
match *ty.kind() {
536+
// If we're a template specialization, our name is our
537+
// parent's name.
538+
TypeKind::Comp(ref ci) if ci.is_template_specialization() => {
539+
item = ctx.resolve_item(ci.specialized_template().unwrap());
540+
},
541+
// Same as above.
542+
TypeKind::ResolvedTypeRef(inner) |
543+
TypeKind::TemplateRef(inner, _) => {
544+
item = ctx.resolve_item(inner);
545+
}
546+
// Template aliases use their inner alias type's name if we
547+
// are checking names for whitelisting/replacement/etc.
548+
TypeKind::TemplateAlias(inner, _) if for_name_checking => {
549+
item = ctx.resolve_item(inner);
550+
assert_eq!(item.id(), item.name_target(ctx, for_name_checking));
551+
return item.id();
552+
}
553+
_ => return item.id(),
554+
}
555+
},
556+
_ => return item.id(),
557+
}
558+
}
559+
}
560+
561+
/// Get this function item's name, or `None` if this item is not a function.
562+
fn func_name(&self) -> Option<&str> {
563+
match *self.kind() {
564+
ItemKind::Function(ref func) => Some(func.name()),
565+
_ => None,
566+
}
567+
}
568+
569+
/// Get the overload index for this method. If this is not a method, return
570+
/// `None`.
571+
fn method_overload_index(&self, ctx: &BindgenContext) -> Option<usize> {
572+
self.func_name().and_then(|func_name| {
573+
let parent = ctx.resolve_item(self.parent_id());
574+
if let ItemKind::Type(ref ty) = *parent.kind() {
575+
if let TypeKind::Comp(ref ci) = *ty.kind() {
576+
return ci.methods()
577+
.iter()
578+
.filter(|method| {
579+
let item = ctx.resolve_item(method.signature());
580+
let func = item.expect_function();
581+
func.name() == func_name
582+
})
583+
.enumerate()
584+
.find(|&(_, ref method)| method.signature() == self.id())
585+
.map(|(idx, _)| idx);
586+
}
587+
}
588+
589+
None
590+
})
591+
}
592+
593+
/// Get this item's base name (aka non-namespaced name).
594+
///
595+
/// The `for_name_checking` boolean parameter informs us whether we are
596+
/// asking for the name in order to do a whitelisting/replacement/etc check
597+
/// or if we are instead using it for code generation.
598+
fn base_name(&self, ctx: &BindgenContext, for_name_checking: bool) -> String {
599+
match *self.kind() {
600+
ItemKind::Var(ref var) => var.name().to_owned(),
601+
ItemKind::Module(ref module) => {
602+
module.name()
603+
.map(ToOwned::to_owned)
604+
.unwrap_or_else(|| format!("_bindgen_mod_{}", self.exposed_id(ctx)))
605+
},
606+
ItemKind::Type(ref ty) => {
607+
let name = match *ty.kind() {
608+
TypeKind::ResolvedTypeRef(..) =>
609+
panic!("should have resolved this in name_target()"),
610+
TypeKind::TemplateAlias(..) if !for_name_checking => Some(""),
611+
TypeKind::TemplateAlias(..) => None,
612+
_ => ty.name(),
613+
};
614+
name.map(ToOwned::to_owned)
615+
.unwrap_or_else(|| format!("_bindgen_ty_{}", self.exposed_id(ctx)))
616+
}
617+
ItemKind::Function(ref fun) => {
618+
let mut name = fun.name().to_owned();
619+
620+
if let Some(idx) = self.method_overload_index(ctx) {
621+
if idx > 0 {
622+
write!(&mut name, "{}", idx).unwrap();
623+
}
624+
}
625+
626+
name
627+
},
628+
}
629+
}
630+
528631
/// Get the canonical name without taking into account the replaces
529632
/// annotation.
530633
///
@@ -538,102 +641,38 @@ impl Item {
538641
/// type and the parent chain, since it should be consistent.
539642
pub fn real_canonical_name(&self,
540643
ctx: &BindgenContext,
541-
count_namespaces: bool,
644+
within_namespace: bool,
542645
for_name_checking: bool)
543646
-> String {
544-
let base_name = match *self.kind() {
545-
ItemKind::Type(ref ty) => {
546-
match *ty.kind() {
547-
// If we're a template specialization, our name is our
548-
// parent's.
549-
TypeKind::Comp(ref ci)
550-
if ci.is_template_specialization() => {
551-
return ci.specialized_template().unwrap()
552-
.canonical_name(ctx);
553-
},
554-
// Same as above
555-
TypeKind::ResolvedTypeRef(inner) |
556-
TypeKind::TemplateRef(inner, _) => {
557-
return inner.canonical_name(ctx);
558-
}
559-
// If we're a named type, we don't need to mangle it, and we
560-
// should be able to assert we're not top level.
561-
TypeKind::Named(ref name, _) => {
562-
return name.to_owned();
563-
}
564-
// We call codegen on the inner type, but we do not want
565-
// this alias's name to appear in the canonical name just
566-
// because it is in the inner type's parent chain, so we use
567-
// an empty base name.
568-
//
569-
// Note that this would be incorrect if this type could be
570-
// referenced from, let's say, a member variable, but in
571-
// that case the referenced type is the inner alias, so
572-
// we're good there. If we wouldn't, a more complex solution
573-
// would be needed.
574-
TypeKind::TemplateAlias(inner, _) => {
575-
if for_name_checking {
576-
return ctx.resolve_item(inner)
577-
.real_canonical_name(ctx,
578-
count_namespaces,
579-
false);
580-
}
581-
Some("")
582-
}
583-
// Else use the proper name, or fallback to a name with an
584-
// id.
585-
_ => {
586-
ty.name()
587-
}
588-
}.map(ToOwned::to_owned)
589-
}
590-
ItemKind::Function(ref fun) => {
591-
let mut base = fun.name().to_owned();
592-
593-
// We might need to deduplicate if we're a method.
594-
let parent = ctx.resolve_item(self.parent_id());
595-
if let ItemKind::Type(ref ty) = *parent.kind() {
596-
if let TypeKind::Comp(ref ci) = *ty.kind() {
597-
let mut count = 0;
598-
let mut found = false;
599-
for method in ci.methods() {
600-
if method.signature() == self.id() {
601-
found = true;
602-
break;
603-
}
604-
let fun = ctx.resolve_item(method.signature())
605-
.expect_function();
606-
if fun.name() == base {
607-
count += 1;
608-
}
609-
}
610-
611-
assert!(found, "Method not found?");
612-
if count != 0 {
613-
base.push_str(&count.to_string());
614-
}
615-
}
616-
}
617-
Some(base)
618-
}
619-
ItemKind::Var(ref var) => Some(var.name().to_owned()),
620-
ItemKind::Module(ref module) => {
621-
module.name().map(ToOwned::to_owned)
622-
}
623-
};
647+
let target = ctx.resolve_item(self.name_target(ctx, for_name_checking));
648+
let base_name = target.base_name(ctx, for_name_checking);
624649

625-
let parent = ctx.resolve_item(self.parent_id());
626-
let parent_is_namespace = parent.is_module();
650+
// Named template type arguments are never namespaced, and never
651+
// mangled.
652+
if target.as_type().map_or(false, |ty| ty.is_named()) {
653+
return base_name;
654+
}
627655

628-
if self.is_toplevel(ctx) || (parent_is_namespace && count_namespaces) {
629-
let base_name = self.make_exposed_name(None, base_name, ctx);
656+
if within_namespace {
630657
return ctx.rust_mangle(&base_name).into_owned();
631658
}
632659

633-
// TODO: allow modification of the mangling functions, maybe even per
634-
// item type?
635-
let parent_name = parent.canonical_name(ctx);
636-
self.make_exposed_name(Some(parent_name), base_name, ctx)
660+
// Concatenate this item's ancestors' names together.
661+
let mut names: Vec<_> = target.parent_id()
662+
.ancestors(ctx)
663+
.filter(|id| *id != ctx.root_module())
664+
.map(|id| {
665+
let item = ctx.resolve_item(id);
666+
let target = ctx.resolve_item(item.name_target(ctx, false));
667+
target.base_name(ctx, false)
668+
})
669+
.filter(|name| !name.is_empty())
670+
.collect();
671+
names.reverse();
672+
names.push(base_name);
673+
let name = names.join("_");
674+
675+
ctx.rust_mangle(&name).into_owned()
637676
}
638677

639678
fn exposed_id(&self, ctx: &BindgenContext) -> String {
@@ -654,45 +693,6 @@ impl Item {
654693
format!("id_{}", self.id().as_usize())
655694
}
656695

657-
fn make_exposed_name(&self,
658-
parent_name: Option<String>,
659-
base_name: Option<String>,
660-
ctx: &BindgenContext)
661-
-> String {
662-
lazy_static! {
663-
static ref RE_ENDS_WITH_BINDGEN_TY: Regex =
664-
Regex::new(r"_bindgen_ty(_\d+)+$").unwrap();
665-
666-
static ref RE_ENDS_WITH_BINDGEN_MOD: Regex =
667-
Regex::new(r"_bindgen_mod(_\d+)+$").unwrap();
668-
}
669-
670-
let (re, kind) = match *self.kind() {
671-
ItemKind::Module(..) => (&*RE_ENDS_WITH_BINDGEN_MOD, "mod"),
672-
_ => (&*RE_ENDS_WITH_BINDGEN_TY, "ty"),
673-
};
674-
675-
let parent_name =
676-
parent_name.and_then(|n| if n.is_empty() { None } else { Some(n) });
677-
match (parent_name, base_name) {
678-
(Some(parent), Some(base)) => format!("{}_{}", parent, base),
679-
(Some(parent), None) => {
680-
if re.is_match(parent.as_str()) {
681-
format!("{}_{}", parent, self.exposed_id(ctx))
682-
} else {
683-
format!("{}__bindgen_{}_{}",
684-
parent,
685-
kind,
686-
self.exposed_id(ctx))
687-
}
688-
}
689-
(None, Some(base)) => base,
690-
(None, None) => {
691-
format!("_bindgen_{}_{}", kind, self.exposed_id(ctx))
692-
}
693-
}
694-
}
695-
696696
/// Get a mutable reference to this item's `Module`, or `None` if this is
697697
/// not a `Module` item.
698698
pub fn as_module_mut(&mut self) -> Option<&mut Module> {

libbindgen/tests/expectations/tests/class_with_inner_struct.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -129,38 +129,42 @@ pub struct C {
129129
#[repr(C)]
130130
#[derive(Debug, Copy)]
131131
pub struct C__bindgen_ty_1 {
132-
pub mFunc: __BindgenUnionField<C__bindgen_ty_1_1>,
133-
pub __bindgen_anon_1: __BindgenUnionField<C__bindgen_ty_1_2>,
132+
pub mFunc: __BindgenUnionField<C__bindgen_ty_1__bindgen_ty_1>,
133+
pub __bindgen_anon_1: __BindgenUnionField<C__bindgen_ty_1__bindgen_ty_2>,
134134
pub bindgen_union_field: [u32; 4usize],
135135
}
136136
#[repr(C)]
137137
#[derive(Debug, Copy)]
138-
pub struct C__bindgen_ty_1_1 {
138+
pub struct C__bindgen_ty_1__bindgen_ty_1 {
139139
pub mX1: f32,
140140
pub mY1: f32,
141141
pub mX2: f32,
142142
pub mY2: f32,
143143
}
144144
#[test]
145-
fn bindgen_test_layout_C__bindgen_ty_1_1() {
146-
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1_1>() , 16usize);
147-
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1_1>() , 4usize);
145+
fn bindgen_test_layout_C__bindgen_ty_1__bindgen_ty_1() {
146+
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1__bindgen_ty_1>() ,
147+
16usize);
148+
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1__bindgen_ty_1>() ,
149+
4usize);
148150
}
149-
impl Clone for C__bindgen_ty_1_1 {
151+
impl Clone for C__bindgen_ty_1__bindgen_ty_1 {
150152
fn clone(&self) -> Self { *self }
151153
}
152154
#[repr(C)]
153155
#[derive(Debug, Copy)]
154-
pub struct C__bindgen_ty_1_2 {
156+
pub struct C__bindgen_ty_1__bindgen_ty_2 {
155157
pub mStepSyntax: StepSyntax,
156158
pub mSteps: ::std::os::raw::c_uint,
157159
}
158160
#[test]
159-
fn bindgen_test_layout_C__bindgen_ty_1_2() {
160-
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1_2>() , 8usize);
161-
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1_2>() , 4usize);
161+
fn bindgen_test_layout_C__bindgen_ty_1__bindgen_ty_2() {
162+
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1__bindgen_ty_2>() ,
163+
8usize);
164+
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1__bindgen_ty_2>() ,
165+
4usize);
162166
}
163-
impl Clone for C__bindgen_ty_1_2 {
167+
impl Clone for C__bindgen_ty_1__bindgen_ty_2 {
164168
fn clone(&self) -> Self { *self }
165169
}
166170
#[test]

libbindgen/tests/expectations/tests/elaborated.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
#![allow(non_snake_case)]
55

66

7-
pub type whatever_t = ::std::os::raw::c_int;
7+
pub type whatever_whatever_t = ::std::os::raw::c_int;
88
extern "C" {
99
#[link_name = "_Z9somethingPKi"]
10-
pub fn something(wat: *const whatever_t);
10+
pub fn something(wat: *const whatever_whatever_t);
1111
}

libbindgen/tests/expectations/tests/inherit-namespaced.rs

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

77
#[repr(C)]
88
#[derive(Debug, Copy, Clone)]
9-
pub struct RootedBase<T> {
9+
pub struct js_RootedBase<T> {
1010
pub _address: u8,
1111
pub _phantom_0: ::std::marker::PhantomData<T>,
1212
}

0 commit comments

Comments
 (0)