Skip to content

Commit ab6c438

Browse files
author
bors-servo
authored
Auto merge of #85 - emilio:template-alias, r=nox
Handle templated aliases. Fixes #83. cc @fitzgen r? @nox
2 parents b162e92 + 2a3f930 commit ab6c438

13 files changed

+241
-18
lines changed

src/clang.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1050,7 +1050,9 @@ pub fn kind_to_str(x: Enum_CXCursorKind) -> &'static str {
10501050
//CXCursor_FirstPreprocessing => "FirstPreprocessing",
10511051
//CXCursor_LastPreprocessing => "LastPreprocessing",
10521052
CXCursor_PackedAttr => "PackedAttr",
1053-
1053+
CXCursor_ModuleImportDecl => "ModuleImportDecl",
1054+
CXCursor_TypeAliasTemplateDecl => "TypeAliasTemplateDecl",
1055+
CXCursor_StaticAssert => "StaticAssert",
10541056
_ => "?",
10551057
}
10561058
}

src/clangll.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,11 @@ pub const CXCursor_InclusionDirective: c_uint = 503;
313313
pub const CXCursor_FirstPreprocessing: c_uint = 500;
314314
pub const CXCursor_LastPreprocessing: c_uint = 503;
315315
pub const CXCursor_ModuleImportDecl: c_uint = 600;
316+
pub const CXCursor_TypeAliasTemplateDecl: c_uint = 601;
317+
pub const CXCursor_StaticAssert: c_uint = 602;
316318
pub const CXCursor_FirstExtraDecl: c_uint = 600;
317-
pub const CXCursor_LastExtraDecl: c_uint = 600;
319+
pub const CXCursor_LastExtraDecl: c_uint = 602;
320+
pub const CXCursor_OverloadCandidate: c_uint = 700;
318321
#[repr(C)]
319322
#[derive(Copy, Clone)]
320323
pub struct CXCursor {

src/codegen/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,12 @@ impl CodeGenerator for Type {
341341
return;
342342
}
343343
TypeKind::Comp(ref ci) => ci.codegen(ctx, result, item),
344+
TypeKind::TemplateAlias(inner, _) => {
345+
// NB: The inner Alias will pick the correct
346+
// applicable_template_args.
347+
let inner_item = ctx.resolve_item(inner);
348+
inner_item.expect_type().codegen(ctx, result, inner_item);
349+
}
344350
TypeKind::Alias(ref spelling, inner) => {
345351
let inner_item = ctx.resolve_item(inner);
346352
let name = item.canonical_name(ctx);
@@ -1361,6 +1367,7 @@ impl ToRustTy for Type {
13611367
let path = item.canonical_path(ctx);
13621368
aster::AstBuilder::new().ty().path().ids(path).build()
13631369
}
1370+
TypeKind::TemplateAlias(inner, ref template_args) |
13641371
TypeKind::TemplateRef(inner, ref template_args) => {
13651372
// PS: Sorry for the duplication here.
13661373
let mut inner_ty = inner.to_rust_ty(ctx).unwrap();
@@ -1618,6 +1625,7 @@ impl TypeCollector for Type {
16181625
TypeKind::Pointer(inner) |
16191626
TypeKind::Reference(inner) |
16201627
TypeKind::Array(inner, _) |
1628+
TypeKind::TemplateAlias(inner, _) |
16211629
TypeKind::Alias(_, inner) |
16221630
TypeKind::Named(_, Some(inner)) |
16231631
TypeKind::ResolvedTypeRef(inner)

src/ir/item.rs

+66-13
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,20 @@ impl Item {
167167
self.kind().expect_function()
168168
}
169169

170+
// This check is needed because even though the type might not contain the
171+
// applicable template args itself, they might apply transitively via, for
172+
// example, the parent.
173+
//
174+
// It's kind of unfortunate (in the sense that it's a sort of complex
175+
// process, but I think it gets all the cases).
176+
fn signature_contains_named_type(&self, ctx: &BindgenContext, ty: &Type) -> bool {
177+
debug_assert!(ty.is_named());
178+
self.expect_type().signature_contains_named_type(ctx, ty) ||
179+
self.applicable_template_args(ctx).iter().any(|template| {
180+
ctx.resolve_type(*template).signature_contains_named_type(ctx, ty)
181+
})
182+
}
183+
170184
pub fn applicable_template_args(&self, ctx: &BindgenContext) -> Vec<ItemId> {
171185
let ty = match *self.kind() {
172186
ItemKind::Type(ref ty) => ty,
@@ -197,7 +211,8 @@ impl Item {
197211
TypeKind::Alias(_, inner) => {
198212
let parent_args = ctx.resolve_item(self.parent_id())
199213
.applicable_template_args(ctx);
200-
let inner = ctx.resolve_type(inner);
214+
let inner = ctx.resolve_item(inner);
215+
201216
// Avoid unused type parameters, sigh.
202217
parent_args.iter().cloned().filter(|arg| {
203218
let arg = ctx.resolve_type(*arg);
@@ -206,6 +221,7 @@ impl Item {
206221
}
207222
// XXX Is this completely correct? Partial template specialization
208223
// is hard anyways, sigh...
224+
TypeKind::TemplateAlias(_, ref args) |
209225
TypeKind::TemplateRef(_, ref args) => {
210226
args.clone()
211227
}
@@ -247,19 +263,22 @@ impl Item {
247263
debug_assert!(ctx.in_codegen_phase(),
248264
"You're not supposed to call this yet");
249265
self.annotations.hide() ||
250-
ctx.hidden_by_name(&self.real_canonical_name(ctx, false), self.id)
266+
ctx.hidden_by_name(&self.real_canonical_name(ctx, false, true), self.id)
251267
}
252268

253269
pub fn is_opaque(&self, ctx: &BindgenContext) -> bool {
254270
debug_assert!(ctx.in_codegen_phase(),
255271
"You're not supposed to call this yet");
256272
self.annotations.opaque() ||
257-
ctx.opaque_by_name(&self.real_canonical_name(ctx, false))
273+
ctx.opaque_by_name(&self.real_canonical_name(ctx, false, true))
258274
}
259275

260276
/// Get the canonical name without taking into account the replaces
261277
/// annotation.
262-
fn real_canonical_name(&self, ctx: &BindgenContext, count_namespaces: bool) -> String {
278+
fn real_canonical_name(&self,
279+
ctx: &BindgenContext,
280+
count_namespaces: bool,
281+
for_name_checking: bool) -> String {
263282
let base_name = match *self.kind() {
264283
ItemKind::Type(ref ty) => {
265284
match *ty.kind() {
@@ -277,11 +296,29 @@ impl Item {
277296
TypeKind::Named(ref name, _) => {
278297
return name.to_owned();
279298
}
280-
_ => {}
281-
}
282-
283-
ty.name().map(ToOwned::to_owned)
284-
.unwrap_or_else(|| format!("_bindgen_ty{}", self.id()))
299+
// We call codegen on the inner type, but we do not want
300+
// this alias's name to appear in the canonical name just
301+
// because it is in the inner type's parent chain, so we use
302+
// an empty base name.
303+
//
304+
// Note that this would be incorrect if this type could be
305+
// referenced from, let's say, a member variable, but in
306+
// that case the referenced type is the inner alias, so
307+
// we're good there. If we wouldn't, a more complex solution
308+
// would be needed.
309+
TypeKind::TemplateAlias(inner, _) => {
310+
if for_name_checking {
311+
return ctx.resolve_item(inner).real_canonical_name(ctx, count_namespaces, false);
312+
}
313+
Some("")
314+
}
315+
// Else use the proper name, or fallback to a name with an
316+
// id.
317+
_ => {
318+
ty.name()
319+
}
320+
}.map(ToOwned::to_owned)
321+
.unwrap_or_else(|| format!("_bindgen_ty{}", self.id()))
285322
}
286323
ItemKind::Function(ref fun) => {
287324
let mut base = fun.name().to_owned();
@@ -329,7 +366,12 @@ impl Item {
329366

330367
// TODO: allow modification of the mangling functions, maybe even per
331368
// item type?
332-
format!("{}_{}", parent.canonical_name(ctx), base_name)
369+
let parent = parent.canonical_name(ctx);
370+
if parent.is_empty() {
371+
base_name.to_owned()
372+
} else {
373+
format!("{}_{}", parent, base_name)
374+
}
333375
}
334376

335377
pub fn as_module_mut(&mut self) -> Option<&mut Module> {
@@ -444,7 +486,7 @@ impl ClangItemParser for Item {
444486
if cursor.kind() == clangll::CXCursor_UnexposedDecl {
445487
Err(ParseError::Recurse)
446488
} else {
447-
error!("Unhandled cursor kind: {}", ::clang::kind_to_str(cursor.kind()));
489+
error!("Unhandled cursor kind: {} ({})", ::clang::kind_to_str(cursor.kind()), cursor.kind());
448490
Err(ParseError::Continue)
449491
}
450492
}
@@ -661,7 +703,7 @@ impl ItemCanonicalName for Item {
661703
if let Some(other_canon_type) = self.annotations.use_instead_of() {
662704
return other_canon_type.to_owned();
663705
}
664-
self.real_canonical_name(ctx, ctx.options().enable_cxx_namespaces)
706+
self.real_canonical_name(ctx, ctx.options().enable_cxx_namespaces, false)
665707
}
666708
}
667709

@@ -698,7 +740,18 @@ impl ItemCanonicalPath for Item {
698740
}
699741

700742
let mut parent_path = self.parent_id().canonical_path(&ctx);
701-
parent_path.push(self.real_canonical_name(ctx, true));
743+
if parent_path.last().map_or(false, |parent_name| parent_name.is_empty()) {
744+
// This only happens (or should only happen) when we're an alias,
745+
// and our parent is a templated alias, in which case the last
746+
// component of the path will be empty.
747+
let is_alias = match *self.expect_type().kind() {
748+
TypeKind::Alias(..) => true,
749+
_ => false,
750+
};
751+
debug_assert!(is_alias, "How can this ever happen?");
752+
parent_path.pop().unwrap();
753+
}
754+
parent_path.push(self.real_canonical_name(ctx, true, false));
702755

703756
parent_path
704757
}

src/ir/ty.rs

+65-3
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,14 @@ impl Type {
146146
type_resolver.resolve_type(t).can_derive_debug(type_resolver)
147147
}
148148
TypeKind::ResolvedTypeRef(t) |
149+
TypeKind::TemplateAlias(t, _) |
149150
TypeKind::Alias(_, t) => {
150151
type_resolver.resolve_type(t).can_derive_debug(type_resolver)
151152
}
152153
TypeKind::Comp(ref info) => {
153154
info.can_derive_debug(type_resolver, self.layout(type_resolver))
154155
}
155-
_ => true,
156+
_ => true,
156157
}
157158
}
158159

@@ -177,6 +178,7 @@ impl Type {
177178
pub fn can_derive_copy_in_array(&self, type_resolver: &BindgenContext, item: &Item) -> bool {
178179
match self.kind {
179180
TypeKind::ResolvedTypeRef(t) |
181+
TypeKind::TemplateAlias(t, _) |
180182
TypeKind::Alias(_, t) |
181183
TypeKind::Array(t, _) => {
182184
type_resolver.resolve_item(t)
@@ -194,6 +196,7 @@ impl Type {
194196
type_resolver.resolve_item(t).can_derive_copy_in_array(type_resolver)
195197
}
196198
TypeKind::ResolvedTypeRef(t) |
199+
TypeKind::TemplateAlias(t, _) |
197200
TypeKind::TemplateRef(t, _) |
198201
TypeKind::Alias(_, t) => {
199202
type_resolver.resolve_item(t).can_derive_copy(type_resolver)
@@ -209,6 +212,7 @@ impl Type {
209212
// FIXME: Can we do something about template parameters? Huh...
210213
match self.kind {
211214
TypeKind::TemplateRef(t, _) |
215+
TypeKind::TemplateAlias(t, _) |
212216
TypeKind::Alias(_, t) |
213217
TypeKind::ResolvedTypeRef(t) |
214218
TypeKind::Array(t, _) => {
@@ -225,6 +229,7 @@ impl Type {
225229
pub fn has_destructor(&self, type_resolver: &BindgenContext) -> bool {
226230
self.is_opaque(type_resolver) || match self.kind {
227231
TypeKind::TemplateRef(t, _) |
232+
TypeKind::TemplateAlias(t, _) |
228233
TypeKind::Alias(_, t) |
229234
TypeKind::ResolvedTypeRef(t) |
230235
TypeKind::Array(t, _) => {
@@ -263,7 +268,8 @@ impl Type {
263268
type_resolver.resolve_type(sig.return_type())
264269
.signature_contains_named_type(type_resolver, ty)
265270
},
266-
TypeKind::TemplateRef(_inner, ref template_args) => {
271+
TypeKind::TemplateAlias(_, ref template_args) |
272+
TypeKind::TemplateRef(_, ref template_args) => {
267273
template_args.iter().any(|arg| {
268274
type_resolver.resolve_type(*arg)
269275
.signature_contains_named_type(type_resolver, ty)
@@ -292,6 +298,7 @@ impl Type {
292298

293299
TypeKind::ResolvedTypeRef(inner) |
294300
TypeKind::Alias(_, inner) |
301+
TypeKind::TemplateAlias(inner, _) |
295302
TypeKind::TemplateRef(inner, _)
296303
=> type_resolver.resolve_type(inner).canonical_type(type_resolver),
297304

@@ -327,6 +334,9 @@ pub enum TypeKind {
327334
Float(FloatKind),
328335
/// A type alias, with a name, that points to another type.
329336
Alias(String, ItemId),
337+
/// A templated alias, pointing to an inner Alias type, with template
338+
/// parameters.
339+
TemplateAlias(ItemId, Vec<ItemId>),
330340
/// An array of a type and a lenght.
331341
Array(ItemId, usize),
332342
/// A function type, with a given signature.
@@ -371,6 +381,7 @@ impl Type {
371381
}
372382
TypeKind::ResolvedTypeRef(inner) |
373383
TypeKind::Alias(_, inner) |
384+
TypeKind::TemplateAlias(inner, _) |
374385
TypeKind::TemplateRef(inner, _)
375386
=> type_resolver.resolve_type(inner).is_unsized(type_resolver),
376387
TypeKind::Named(..) |
@@ -444,6 +455,57 @@ impl Type {
444455
.expect("C'mon");
445456
TypeKind::Comp(complex)
446457
}
458+
CXCursor_TypeAliasTemplateDecl => {
459+
debug!("TypeAliasTemplateDecl");
460+
461+
// We need to manually unwind this one.
462+
let mut inner = Err(ParseError::Continue);
463+
let mut args = vec![];
464+
465+
location.visit(|cur, _| {
466+
match cur.kind() {
467+
CXCursor_TypeAliasDecl => {
468+
debug_assert!(cur.cur_type().kind() == CXType_Typedef);
469+
inner = Item::from_ty(&cur.cur_type(),
470+
Some(*cur),
471+
Some(potential_id),
472+
ctx);
473+
}
474+
CXCursor_TemplateTypeParameter => {
475+
// See the comment in src/ir/comp.rs
476+
// about the same situation.
477+
if cur.spelling().is_empty() {
478+
return CXChildVisit_Continue;
479+
}
480+
481+
let default_type =
482+
Item::from_ty(&cur.cur_type(),
483+
Some(*cur),
484+
Some(potential_id),
485+
ctx).ok();
486+
let param =
487+
Item::named_type(cur.spelling(),
488+
default_type,
489+
potential_id, ctx);
490+
args.push(param);
491+
}
492+
_ => {}
493+
}
494+
CXChildVisit_Continue
495+
});
496+
497+
if inner.is_err() {
498+
error!("Failed to parse templated type alias {:?}", location);
499+
return Err(ParseError::Continue);
500+
}
501+
502+
if args.is_empty() {
503+
error!("Failed to get any template parameter, maybe a specialization? {:?}", location);
504+
return Err(ParseError::Continue);
505+
}
506+
507+
TypeKind::TemplateAlias(inner.unwrap(), args)
508+
}
447509
CXCursor_TemplateRef => {
448510
let referenced = location.referenced();
449511
return Self::from_clang_ty(potential_id,
@@ -521,7 +583,7 @@ impl Type {
521583
let signature = try!(FunctionSig::from_ty(ty, &location.unwrap_or(cursor), ctx));
522584
TypeKind::Function(signature)
523585
}
524-
CXType_Typedef => {
586+
CXType_Typedef => {
525587
let inner = cursor.typedef_type();
526588
let inner =
527589
Item::from_ty_or_ref(inner, location, parent_id, ctx);

tests/expectations/template_alias.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
pub type Wrapped<T> = T;
8+
#[repr(C)]
9+
#[derive(Debug, Copy, Clone)]
10+
pub struct Rooted<T> {
11+
pub ptr: Wrapped<T>,
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
pub type Wrapped<T> = T;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
pub mod root {
8+
use root;
9+
pub mod JS {
10+
use root;
11+
pub mod detail {
12+
use root;
13+
pub type Wrapped<T> = T;
14+
}
15+
#[repr(C)]
16+
#[derive(Debug, Copy, Clone)]
17+
pub struct Rooted<T> {
18+
pub ptr: root::JS::detail::Wrapped<T>,
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)