Skip to content

Commit c6c60ed

Browse files
committed
ir: Explicitly discard specialized templated type aliases as already resolved.
1 parent 004a195 commit c6c60ed

7 files changed

+114
-43
lines changed

src/clang.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,11 @@ impl Type {
721721
pub fn is_valid(&self) -> bool {
722722
self.kind() != CXType_Invalid
723723
}
724+
725+
/// Is this a valid and exposed type?
726+
pub fn is_valid_and_exposed(&self) -> bool {
727+
self.is_valid() && self.kind() != CXType_Unexposed
728+
}
724729
}
725730

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

src/ir/context.rs

Lines changed: 60 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -499,16 +499,12 @@ impl<'ctx> BindgenContext<'ctx> {
499499
wrapping: ItemId,
500500
parent_id: ItemId,
501501
ty: &clang::Type,
502-
location: clang::Cursor)
502+
location: clang::Cursor,
503+
declaration: clang::Cursor)
503504
-> ItemId {
504505
use clangll::*;
505506
let mut args = vec![];
506-
let mut found_invalid_template_ref = false;
507507
location.visit(|c| {
508-
if c.kind() == CXCursor_TemplateRef &&
509-
c.cur_type().kind() == CXType_Invalid {
510-
found_invalid_template_ref = true;
511-
}
512508
if c.kind() == CXCursor_TypeRef {
513509
// The `with_id` id will potentially end up unused if we give up
514510
// on this type (for example, its a tricky partial template
@@ -527,39 +523,46 @@ impl<'ctx> BindgenContext<'ctx> {
527523

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

565568
let type_kind = TypeKind::TemplateRef(wrapping, args);
@@ -586,7 +589,8 @@ impl<'ctx> BindgenContext<'ctx> {
586589
location: Option<clang::Cursor>)
587590
-> Option<ItemId> {
588591
use clangll::{CXCursor_ClassTemplate,
589-
CXCursor_ClassTemplatePartialSpecialization};
592+
CXCursor_ClassTemplatePartialSpecialization,
593+
CXCursor_TypeAliasTemplateDecl};
590594
debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}",
591595
ty,
592596
location,
@@ -630,15 +634,29 @@ impl<'ctx> BindgenContext<'ctx> {
630634
// argument names don't matter in the global context.
631635
if (declaration.kind() == CXCursor_ClassTemplate ||
632636
declaration.kind() ==
633-
CXCursor_ClassTemplatePartialSpecialization) &&
637+
CXCursor_ClassTemplatePartialSpecialization ||
638+
declaration.kind() == CXCursor_TypeAliasTemplateDecl) &&
634639
*ty != canonical_declaration.cur_type() &&
635640
location.is_some() &&
636641
parent_id.is_some() {
642+
// For type aliases, there's no way to get the template
643+
// parameters as of this writing if it's a specialization,
644+
// so explicitly return `None` so we resolve the canonical
645+
// type if there is one and it's exposed.
646+
//
647+
// This is _tricky_, I know :(
648+
if declaration.kind() == CXCursor_TypeAliasTemplateDecl &&
649+
ty.canonical_type().is_valid_and_exposed() {
650+
println!("{:?}", ty.canonical_type());
651+
return None;
652+
}
653+
637654
return Some(self.build_template_wrapper(with_id,
638655
id,
639656
parent_id.unwrap(),
640657
ty,
641-
location.unwrap()));
658+
location.unwrap(),
659+
declaration));
642660
}
643661

644662
return Some(self.build_ty_wrapper(with_id, id, parent_id, ty));

tests/expectations/tests/replace_template_alias.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
#[repr(C)]
88
#[derive(Debug, Copy, Clone)]
99
pub struct Rooted<T> {
10-
pub ptr: MaybeWrapped<T>,
10+
pub ptr: ::std::os::raw::c_int,
11+
pub _phantom_0: ::std::marker::PhantomData<T>,
1112
}
1213
/// But the replacement type does use T!
1314
///
Lines changed: 12 additions & 0 deletions
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+
}
Lines changed: 19 additions & 0 deletions
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+
}
Lines changed: 7 additions & 0 deletions
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+
};
Lines changed: 9 additions & 0 deletions
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)