Skip to content

Commit 53cd0e4

Browse files
author
bors-servo
authored
Auto merge of #255 - emilio:type-alias, r=fitzgen
Template alias full and partial specialization improvements. This doesn't completely fix #251, but fixes other related problems. r? @fitzgen
2 parents 3778e69 + 2003f9c commit 53cd0e4

6 files changed

+135
-42
lines changed

src/clang.rs

+23
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,24 @@ impl Cursor {
317317
}
318318
}
319319

320+
/// Returns whether the given location contains a cursor with the given
321+
/// kind in the first level of nesting underneath (doesn't look
322+
/// recursively).
323+
pub fn contains_cursor(&self, kind: Enum_CXCursorKind) -> bool {
324+
let mut found = false;
325+
326+
self.visit(|c| {
327+
if c.kind() == kind {
328+
found = true;
329+
CXChildVisit_Break
330+
} else {
331+
CXChildVisit_Continue
332+
}
333+
});
334+
335+
found
336+
}
337+
320338
/// Is the referent an inlined function?
321339
#[cfg(not(feature="llvm_stable"))]
322340
pub fn is_inlined_function(&self) -> bool {
@@ -721,6 +739,11 @@ impl Type {
721739
pub fn is_valid(&self) -> bool {
722740
self.kind() != CXType_Invalid
723741
}
742+
743+
/// Is this a valid and exposed type?
744+
pub fn is_valid_and_exposed(&self) -> bool {
745+
self.is_valid() && self.kind() != CXType_Unexposed
746+
}
724747
}
725748

726749
/// An iterator for a type's template arguments.

src/ir/context.rs

+65-42
Original file line numberDiff line numberDiff line change
@@ -500,16 +500,12 @@ impl<'ctx> BindgenContext<'ctx> {
500500
wrapping: ItemId,
501501
parent_id: ItemId,
502502
ty: &clang::Type,
503-
location: clang::Cursor)
503+
location: clang::Cursor,
504+
declaration: clang::Cursor)
504505
-> ItemId {
505506
use clangll::*;
506507
let mut args = vec![];
507-
let mut found_invalid_template_ref = false;
508508
location.visit(|c| {
509-
if c.kind() == CXCursor_TemplateRef &&
510-
c.cur_type().kind() == CXType_Invalid {
511-
found_invalid_template_ref = true;
512-
}
513509
if c.kind() == CXCursor_TypeRef {
514510
// The `with_id` id will potentially end up unused if we give up
515511
// on this type (for example, its a tricky partial template
@@ -528,39 +524,46 @@ impl<'ctx> BindgenContext<'ctx> {
528524

529525
let item = {
530526
let wrapping_type = self.resolve_type(wrapping);
531-
let old_args = match *wrapping_type.kind() {
532-
TypeKind::Comp(ref ci) => ci.template_args(),
533-
_ => panic!("how?"),
534-
};
535-
// The following assertion actually fails with partial template
536-
// specialization. But as far as I know there's no way at all to
537-
// grab the specialized types from neither the AST or libclang.
538-
//
539-
// This flaw was already on the old parser, but I now think it has
540-
// no clear solution.
541-
//
542-
// For an easy example in which there's no way at all of getting the
543-
// `int` type, except manually parsing the spelling:
544-
//
545-
// template<typename T, typename U>
546-
// class Incomplete {
547-
// T d;
548-
// U p;
549-
// };
550-
//
551-
// template<typename U>
552-
// class Foo {
553-
// Incomplete<U, int> bar;
554-
// };
555-
//
556-
// debug_assert_eq!(old_args.len(), args.len());
557-
//
558-
// That being said, this is not so common, so just error! and hope
559-
// for the best, returning the previous type, who knows.
560-
if old_args.len() != args.len() {
561-
error!("Found partial template specialization, \
562-
expect dragons!");
563-
return wrapping;
527+
if let TypeKind::Comp(ref ci) = *wrapping_type.kind() {
528+
let old_args = ci.template_args();
529+
530+
// The following assertion actually fails with partial template
531+
// specialization. But as far as I know there's no way at all to
532+
// grab the specialized types from neither the AST or libclang,
533+
// which sucks. The same happens for specialized type alias
534+
// template declarations, where we have that ugly hack up there.
535+
//
536+
// This flaw was already on the old parser, but I now think it
537+
// has no clear solution (apart from patching libclang to
538+
// somehow expose them, of course).
539+
//
540+
// For an easy example in which there's no way at all of getting
541+
// the `int` type, except manually parsing the spelling:
542+
//
543+
// template<typename T, typename U>
544+
// class Incomplete {
545+
// T d;
546+
// U p;
547+
// };
548+
//
549+
// template<typename U>
550+
// class Foo {
551+
// Incomplete<U, int> bar;
552+
// };
553+
//
554+
// debug_assert_eq!(old_args.len(), args.len());
555+
//
556+
// That being said, this is not so common, so just error! and
557+
// hope for the best, returning the previous type, who knows.
558+
if old_args.len() != args.len() {
559+
error!("Found partial template specialization, \
560+
expect dragons!");
561+
return wrapping;
562+
}
563+
} else {
564+
assert_eq!(declaration.kind(),
565+
::clangll::CXCursor_TypeAliasTemplateDecl,
566+
"Expected wrappable type");
564567
}
565568

566569
let type_kind = TypeKind::TemplateRef(wrapping, args);
@@ -589,7 +592,9 @@ impl<'ctx> BindgenContext<'ctx> {
589592
location: Option<clang::Cursor>)
590593
-> Option<ItemId> {
591594
use clangll::{CXCursor_ClassTemplate,
592-
CXCursor_ClassTemplatePartialSpecialization};
595+
CXCursor_ClassTemplatePartialSpecialization,
596+
CXCursor_TypeAliasTemplateDecl,
597+
CXCursor_TypeRef};
593598
debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}",
594599
ty,
595600
location,
@@ -633,15 +638,33 @@ impl<'ctx> BindgenContext<'ctx> {
633638
// argument names don't matter in the global context.
634639
if (declaration.kind() == CXCursor_ClassTemplate ||
635640
declaration.kind() ==
636-
CXCursor_ClassTemplatePartialSpecialization) &&
641+
CXCursor_ClassTemplatePartialSpecialization ||
642+
declaration.kind() == CXCursor_TypeAliasTemplateDecl) &&
637643
*ty != canonical_declaration.cur_type() &&
638644
location.is_some() &&
639645
parent_id.is_some() {
646+
// For specialized type aliases, there's no way to get the
647+
// template parameters as of this writing (for a struct
648+
// specialization we wouldn't be in this branch anyway).
649+
//
650+
// Explicitly return `None` if there aren't any
651+
// unspecialized parameters (contains any `TypeRef`) so we
652+
// resolve the canonical type if there is one and it's
653+
// exposed.
654+
//
655+
// This is _tricky_, I know :(
656+
if declaration.kind() == CXCursor_TypeAliasTemplateDecl &&
657+
!location.unwrap().contains_cursor(CXCursor_TypeRef) &&
658+
ty.canonical_type().is_valid_and_exposed() {
659+
return None;
660+
}
661+
640662
return Some(self.build_template_wrapper(with_id,
641663
id,
642664
parent_id.unwrap(),
643665
ty,
644-
location.unwrap()));
666+
location.unwrap(),
667+
declaration));
645668
}
646669

647670
return Some(self.build_ty_wrapper(with_id, id, parent_id, ty));
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 MaybeWrapped<A> = A;
8+
#[repr(C)]
9+
#[derive(Debug, Copy, Clone)]
10+
pub struct Rooted<T> {
11+
pub ptr: MaybeWrapped<T>,
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Copy)]
9+
pub struct Rooted {
10+
pub ptr: ::std::os::raw::c_int,
11+
}
12+
#[test]
13+
fn bindgen_test_layout_Rooted() {
14+
assert_eq!(::std::mem::size_of::<Rooted>() , 4usize);
15+
assert_eq!(::std::mem::align_of::<Rooted>() , 4usize);
16+
}
17+
impl Clone for Rooted {
18+
fn clone(&self) -> Self { *self }
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// bindgen-flags: -- -std=c++14
2+
template <typename A> using MaybeWrapped = A;
3+
4+
template<class T>
5+
class Rooted {
6+
MaybeWrapped<T> ptr;
7+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// bindgen-flags: --whitelist-type Rooted -- -std=c++14
2+
3+
template <typename a> using MaybeWrapped = a;
4+
class Rooted {
5+
MaybeWrapped<int> ptr;
6+
};
7+
8+
/// <div rustbindgen replaces="MaybeWrapped"></div>
9+
template <typename a> using replaces_MaybeWrapped = a;

0 commit comments

Comments
 (0)