Skip to content

Commit d702d31

Browse files
committed
Generate opaque blobs for uses of partially specialized templates
This adds `TypeKind::Opaque` which signifies that we do not understand anything about the given type and that we should just generate an opaque blob based on the type's layout. It explicitly uses the opaque type kind for partially specialized templates.
1 parent 187df63 commit d702d31

File tree

6 files changed

+150
-11
lines changed

6 files changed

+150
-11
lines changed

src/codegen/mod.rs

+19-5
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ impl CodeGenerator for Type {
520520
TypeKind::Reference(..) |
521521
TypeKind::Function(..) |
522522
TypeKind::ResolvedTypeRef(..) |
523+
TypeKind::Opaque |
523524
TypeKind::Named => {
524525
// These items don't need code generation, they only need to be
525526
// converted to rust types in fields, arguments, and such.
@@ -2170,7 +2171,6 @@ impl ToRustTy for Type {
21702171
aster::AstBuilder::new().ty().path().ids(path).build()
21712172
}
21722173
TypeKind::TemplateInstantiation(ref inst) => {
2173-
// PS: Sorry for the duplication here.
21742174
let decl = inst.template_definition();
21752175
let mut ty = decl.to_rust_ty(ctx).unwrap();
21762176

@@ -2183,6 +2183,21 @@ impl ToRustTy for Type {
21832183
}
21842184
}
21852185

2186+
let decl_params = if let Some(params) = decl.self_template_params(ctx) {
2187+
params
2188+
} else {
2189+
// This can happen if we generated an opaque type for a
2190+
// partial template specialization, in which case we just
2191+
// use the opaque type's layout. If we don't have a layout,
2192+
// we cross our fingers and hope for the best :-/
2193+
debug_assert_eq!(*ctx.resolve_type_through_type_refs(decl).kind(),
2194+
TypeKind::Opaque);
2195+
let layout = self.layout(ctx).unwrap_or(Layout::zero());
2196+
ty = BlobTyBuilder::new(layout).build().unwrap();
2197+
2198+
vec![]
2199+
};
2200+
21862201
// TODO: If the decl type is a template class/struct
21872202
// declaration's member template declaration, it could rely on
21882203
// generic template parameters from its outer template
@@ -2191,10 +2206,6 @@ impl ToRustTy for Type {
21912206
// reconstruct them somehow. We don't have any means of doing
21922207
// that reconstruction at this time.
21932208

2194-
let decl_params = decl.self_template_params(ctx)
2195-
.expect("instantiation's referenced template declaration \
2196-
should be a template declaration");
2197-
21982209
if let ast::TyKind::Path(_, ref mut path) = ty.node {
21992210
let template_args = inst.template_arguments()
22002211
.iter()
@@ -2262,6 +2273,9 @@ impl ToRustTy for Type {
22622273

22632274
utils::build_templated_path(item, ctx, template_params.unwrap_or(vec![]))
22642275
}
2276+
TypeKind::Opaque => {
2277+
BlobTyBuilder::new(self.layout(ctx).unwrap_or(Layout::zero())).build()
2278+
}
22652279
TypeKind::BlockPointer => {
22662280
let void = raw_type(ctx, "c_void");
22672281
void.to_ptr(/* is_const = */

src/ir/context.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,10 @@ impl<'ctx> BindgenContext<'ctx> {
250250
item,
251251
declaration,
252252
location);
253-
debug_assert!(declaration.is_some() || !item.kind().is_type() ||
254-
item.kind().expect_type().is_builtin_or_named(),
253+
debug_assert!(declaration.is_some() ||
254+
!item.kind().is_type() ||
255+
item.kind().expect_type().is_builtin_or_named() ||
256+
*item.kind().expect_type().kind() == TypeKind::Opaque,
255257
"Adding a type without declaration?");
256258

257259
let id = item.id();
@@ -692,6 +694,21 @@ impl<'ctx> BindgenContext<'ctx> {
692694
}
693695
}
694696

697+
/// Resolve the given `ItemId` into a `Type`, and keep doing so while we see
698+
/// `ResolvedTypeRef`s to other items until we get to the final `Type`.
699+
pub fn resolve_type_through_type_refs(&self, item_id: ItemId) -> &Type {
700+
assert!(self.collected_typerefs());
701+
702+
let mut id = item_id;
703+
loop {
704+
let ty = self.resolve_type(id);
705+
match *ty.kind() {
706+
TypeKind::ResolvedTypeRef(next_id) => id = next_id,
707+
_ => return ty,
708+
}
709+
}
710+
}
711+
695712
/// Get the current module.
696713
pub fn current_module(&self) -> ItemId {
697714
self.current_module

src/ir/layout.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
33
use super::context::BindgenContext;
44
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
5-
use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
5+
use super::ty::{Type, TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
6+
use clang;
67
use std::{cmp, mem};
78

89
/// A type that represents the struct layout of a type.
@@ -65,9 +66,17 @@ impl Layout {
6566
}
6667

6768
/// When we are treating a type as opaque, it is just a blob with a `Layout`.
69+
#[derive(Clone, Debug, PartialEq)]
6870
pub struct Opaque(pub Layout);
6971

7072
impl Opaque {
73+
/// Construct a new opaque type from the given clang type.
74+
pub fn from_clang_ty(ty: &clang::Type) -> Type {
75+
let layout = Layout::new(ty.size(), ty.align());
76+
let ty_kind = TypeKind::Opaque;
77+
Type::new(None, Some(layout), ty_kind, false)
78+
}
79+
7180
/// Return the known rust type we should use to create a correctly-aligned
7281
/// field with this layout.
7382
pub fn known_rust_type_for_array(&self) -> Option<&'static str> {

src/ir/ty.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use super::enum_ty::Enum;
88
use super::function::FunctionSig;
99
use super::int::IntKind;
1010
use super::item::{Item, ItemAncestors};
11-
use super::layout::Layout;
11+
use super::layout::{Layout, Opaque};
1212
use super::objc::ObjCInterface;
1313
use super::template::{AsNamed, TemplateInstantiation};
1414
use super::traversal::{EdgeKind, Trace, Tracer};
@@ -427,6 +427,7 @@ impl Type {
427427
TypeKind::Named |
428428
TypeKind::Array(..) |
429429
TypeKind::Comp(..) |
430+
TypeKind::Opaque |
430431
TypeKind::Int(..) |
431432
TypeKind::Float(..) |
432433
TypeKind::Complex(..) |
@@ -522,6 +523,7 @@ impl DotAttributes for TypeKind {
522523
TypeKind::Void => "Void",
523524
TypeKind::NullPtr => "NullPtr",
524525
TypeKind::Comp(..) => "Comp",
526+
TypeKind::Opaque => "Opaque",
525527
TypeKind::Int(..) => "Int",
526528
TypeKind::Float(..) => "Float",
527529
TypeKind::Complex(..) => "Complex",
@@ -606,6 +608,7 @@ impl TemplateDeclaration for TypeKind {
606608
TypeKind::Comp(ref comp) => comp.self_template_params(ctx),
607609
TypeKind::TemplateAlias(_, ref args) => Some(args.clone()),
608610

611+
TypeKind::Opaque |
609612
TypeKind::TemplateInstantiation(..) |
610613
TypeKind::Void |
611614
TypeKind::NullPtr |
@@ -665,6 +668,9 @@ impl CanDeriveDefault for Type {
665668
TypeKind::Comp(ref info) => {
666669
info.can_derive_default(ctx, self.layout(ctx))
667670
}
671+
TypeKind::Opaque => {
672+
self.layout.map_or(true, |l| l.opaque().can_derive_default(ctx, ()))
673+
}
668674
TypeKind::Void |
669675
TypeKind::Named |
670676
TypeKind::TemplateInstantiation(..) |
@@ -703,6 +709,9 @@ impl<'a> CanDeriveCopy<'a> for Type {
703709
TypeKind::Comp(ref info) => {
704710
info.can_derive_copy(ctx, (item, self.layout(ctx)))
705711
}
712+
TypeKind::Opaque => {
713+
self.layout.map_or(true, |l| l.opaque().can_derive_copy(ctx, ()))
714+
}
706715
_ => true,
707716
}
708717
}
@@ -758,6 +767,11 @@ pub enum TypeKind {
758767
/// A compound type, that is, a class, struct, or union.
759768
Comp(CompInfo),
760769

770+
/// An opaque type that we just don't understand. All usage of this shoulf
771+
/// result in an opaque blob of bytes generated from the containing type's
772+
/// layout.
773+
Opaque,
774+
761775
/// An integer type, of a given kind. `bool` and `char` are also considered
762776
/// integers.
763777
Int(IntKind),
@@ -840,6 +854,7 @@ impl Type {
840854
match self.kind {
841855
TypeKind::Void => true,
842856
TypeKind::Comp(ref ci) => ci.is_unsized(ctx),
857+
TypeKind::Opaque => self.layout.map_or(true, |l| l.size == 0),
843858
TypeKind::Array(inner, size) => {
844859
size == 0 || ctx.resolve_type(inner).is_unsized(ctx)
845860
}
@@ -919,8 +934,9 @@ impl Type {
919934
if location.kind() == CXCursor_ClassTemplatePartialSpecialization {
920935
// Sorry! (Not sorry)
921936
warn!("Found a partial template specialization; bindgen does not \
922-
support partial template specialization");
923-
return Err(ParseError::Continue);
937+
support partial template specialization! Constructing \
938+
opaque type instead.");
939+
return Ok(ParseResult::New(Opaque::from_clang_ty(&canonical_ty), None));
924940
}
925941

926942
let kind = if location.kind() == CXCursor_TemplateRef ||
@@ -1337,6 +1353,7 @@ impl Trace for Type {
13371353
}
13381354

13391355
// None of these variants have edges to other items and types.
1356+
TypeKind::Opaque |
13401357
TypeKind::UnresolvedTypeRef(_, _, None) |
13411358
TypeKind::Named |
13421359
TypeKind::Void |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Default, Copy, Clone)]
9+
pub struct Base {
10+
pub _address: u8,
11+
}
12+
#[repr(C)]
13+
#[derive(Debug, Default, Copy, Clone)]
14+
pub struct Derived {
15+
pub b: bool,
16+
}
17+
#[test]
18+
fn __bindgen_test_layout__bindgen_ty_id_20_instantiation_14() {
19+
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat ! (
20+
"Size of template specialization: " , stringify ! (
21+
[u32; 2usize] ) ));
22+
assert_eq!(::std::mem::align_of::<[u32; 2usize]>() , 4usize , concat ! (
23+
"Alignment of template specialization: " , stringify ! (
24+
[u32; 2usize] ) ));
25+
}
26+
#[repr(C)]
27+
#[derive(Debug, Default, Copy)]
28+
pub struct Usage {
29+
pub _address: u8,
30+
}
31+
extern "C" {
32+
#[link_name = "_ZN5Usage13static_memberE"]
33+
pub static mut Usage_static_member: [u32; 2usize];
34+
}
35+
#[test]
36+
fn bindgen_test_layout_Usage() {
37+
assert_eq!(::std::mem::size_of::<Usage>() , 1usize , concat ! (
38+
"Size of: " , stringify ! ( Usage ) ));
39+
assert_eq! (::std::mem::align_of::<Usage>() , 1usize , concat ! (
40+
"Alignment of " , stringify ! ( Usage ) ));
41+
}
42+
impl Clone for Usage {
43+
fn clone(&self) -> Self { *self }
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// This was originally a test case generated by creducing errors in SpiderMonkey
2+
// bindings generation. I've tried to make it understandable by giving more
3+
// meaningful names to everything, and a couple comments.
4+
//
5+
// We don't support partial template specialization, but we *should*
6+
// successfully parse this header, and generate bindings for it, but the usage
7+
// of the partial template specialization should result in opaque blobs.
8+
9+
// A base class providing a method.
10+
template <typename T>
11+
class Base {
12+
public:
13+
void some_method(T, T);
14+
};
15+
16+
// A template with a default representation.
17+
template <typename U>
18+
class Derived {
19+
bool b;
20+
};
21+
22+
// A partial specialization for pointers. Note that this should have a different
23+
// and larger layout than the template it is specializing.
24+
template <typename U>
25+
class Derived<U*> : public Base<U*> {
26+
int x;
27+
int y;
28+
};
29+
30+
// A struct that uses the partial specialization and method from the partial
31+
// specialization's base class.
32+
struct Usage {
33+
Usage() {
34+
static_member.some_method(this, this);
35+
}
36+
37+
static Derived<Usage*> static_member;
38+
};

0 commit comments

Comments
 (0)