summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-06-22 09:38:25 -0700
committerGitHub <noreply@github.com>2017-06-22 09:38:25 -0700
commit313d7920a0f1835f516e23c2c84d9dda67ab82fd (patch)
tree74b870b203886d342842abd51cb61288fc36e270
parent480c2d197199e7b1f824a01cc63acd33d81f6622 (diff)
parent2000177d0b99cc8cbd901e4ceb81ea60a547e381 (diff)
Auto merge of #773 - fitzgen:allow-making-particular-instantiations-opaque, r=emilio
Allow marking specific template instantiations as opaque If a template has a specialization that bindgen doesn't understand, it can be helpful to mark it as opaque and continue making forward progress in the meantime. This is something we need in the SpiderMonkey bindings. r? @emilio
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--src/codegen/mod.rs39
-rw-r--r--src/ir/comp.rs4
-rw-r--r--src/ir/context.rs4
-rw-r--r--src/ir/item.rs54
-rw-r--r--src/ir/template.rs36
-rw-r--r--src/ir/ty.rs22
-rw-r--r--tests/expectations/tests/issue-674-1.rs9
-rw-r--r--tests/expectations/tests/issue-674-2.rs9
-rw-r--r--tests/expectations/tests/issue-674-3.rs9
-rw-r--r--tests/expectations/tests/opaque-template-instantiation-namespaced.rs128
-rw-r--r--tests/expectations/tests/opaque-template-instantiation.rs75
-rw-r--r--tests/headers/opaque-template-instantiation-namespaced.hpp29
-rw-r--r--tests/headers/opaque-template-instantiation.hpp17
15 files changed, 365 insertions, 74 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b88f8be1..4f5ab457 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,6 @@
[root]
name = "bindgen"
-version = "0.26.1"
+version = "0.26.2"
dependencies = [
"aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index 0f17dc8e..39724baa 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@ name = "bindgen"
readme = "README.md"
repository = "https://github.com/servo/rust-bindgen"
documentation = "https://docs.rs/bindgen"
-version = "0.26.1"
+version = "0.26.2"
build = "build.rs"
exclude = [
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index d926f02b..50ebebf2 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -17,8 +17,8 @@ use ir::dot;
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
use ir::function::{Abi, Function, FunctionSig};
use ir::int::IntKind;
-use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath,
- ItemSet};
+use ir::item::{IsOpaque, Item, ItemAncestors, ItemCanonicalName,
+ ItemCanonicalPath, ItemSet};
use ir::item_kind::ItemKind;
use ir::layout::Layout;
use ir::module::Module;
@@ -580,7 +580,7 @@ impl CodeGenerator for Type {
}
let mut used_template_params = item.used_template_params(ctx);
- let inner_rust_type = if item.is_opaque(ctx) {
+ let inner_rust_type = if item.is_opaque(ctx, &()) {
used_template_params = None;
self.to_opaque(ctx, item)
} else {
@@ -759,8 +759,11 @@ impl CodeGenerator for TemplateInstantiation {
item: &Item) {
// Although uses of instantiations don't need code generation, and are
// just converted to rust types in fields, vars, etc, we take this
- // opportunity to generate tests for their layout here.
- if !ctx.options().layout_tests {
+ // opportunity to generate tests for their layout here. If the
+ // instantiation is opaque, then its presumably because we don't
+ // properly understand it (maybe because of specializations), and so we
+ // shouldn't emit layout tests either.
+ if !ctx.options().layout_tests || self.is_opaque(ctx, item) {
return
}
@@ -1568,7 +1571,7 @@ impl CodeGenerator for CompInfo {
}
// Yeah, sorry about that.
- if item.is_opaque(ctx) {
+ if item.is_opaque(ctx, &()) {
fields.clear();
methods.clear();
@@ -1704,7 +1707,7 @@ impl CodeGenerator for CompInfo {
})
.count() > 1;
- let should_skip_field_offset_checks = item.is_opaque(ctx) ||
+ let should_skip_field_offset_checks = item.is_opaque(ctx, &()) ||
too_many_base_vtables;
let check_field_offset = if should_skip_field_offset_checks {
@@ -2816,7 +2819,7 @@ impl TryToRustTy for Type {
.build())
}
TypeKind::TemplateInstantiation(ref inst) => {
- inst.try_to_rust_ty(ctx, self)
+ inst.try_to_rust_ty(ctx, item)
}
TypeKind::ResolvedTypeRef(inner) => inner.try_to_rust_ty(ctx, &()),
TypeKind::TemplateAlias(inner, _) |
@@ -2828,7 +2831,7 @@ impl TryToRustTy for Type {
.collect::<Vec<_>>();
let spelling = self.name().expect("Unnamed alias?");
- if item.is_opaque(ctx) && !template_params.is_empty() {
+ if item.is_opaque(ctx, &()) && !template_params.is_empty() {
self.try_to_opaque(ctx, item)
} else if let Some(ty) = utils::type_from_named(ctx,
spelling,
@@ -2841,7 +2844,7 @@ impl TryToRustTy for Type {
TypeKind::Comp(ref info) => {
let template_params = item.used_template_params(ctx);
if info.has_non_type_template_params() ||
- (item.is_opaque(ctx) && template_params.is_some()) {
+ (item.is_opaque(ctx, &()) && template_params.is_some()) {
return self.try_to_opaque(ctx, item);
}
@@ -2895,23 +2898,27 @@ impl TryToRustTy for Type {
}
impl TryToOpaque for TemplateInstantiation {
- type Extra = Type;
+ type Extra = Item;
fn try_get_layout(&self,
ctx: &BindgenContext,
- self_ty: &Type)
+ item: &Item)
-> error::Result<Layout> {
- self_ty.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob)
+ item.expect_type().layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob)
}
}
impl TryToRustTy for TemplateInstantiation {
- type Extra = Type;
+ type Extra = Item;
fn try_to_rust_ty(&self,
ctx: &BindgenContext,
- _: &Type)
+ item: &Item)
-> error::Result<P<ast::Ty>> {
+ if self.is_opaque(ctx, item) {
+ return Err(error::Error::InstantiationOfOpaqueType);
+ }
+
let decl = self.template_definition();
let mut ty = decl.try_to_rust_ty(ctx, &())?.unwrap();
@@ -2924,7 +2931,7 @@ impl TryToRustTy for TemplateInstantiation {
extra_assert!(decl.into_resolver()
.through_type_refs()
.resolve(ctx)
- .is_opaque(ctx));
+ .is_opaque(ctx, &()));
return Err(error::Error::InstantiationOfOpaqueType);
}
};
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index 315d342a..6dfc9980 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -4,7 +4,7 @@ use super::annotations::Annotations;
use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
use super::dot::DotAttributes;
-use super::item::Item;
+use super::item::{IsOpaque, Item};
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::template::TemplateParameters;
@@ -1585,7 +1585,7 @@ impl Trace for CompInfo {
// We unconditionally trace `CompInfo`'s template parameters and inner
// types for the the usage analysis. However, we don't want to continue
// tracing anything else, if this type is marked opaque.
- if item.is_opaque(context) {
+ if item.is_opaque(context, &()) {
return;
}
diff --git a/src/ir/context.rs b/src/ir/context.rs
index eb0fd98a..7b4e9b6a 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -2,7 +2,7 @@
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
use super::int::IntKind;
-use super::item::{Item, ItemAncestors, ItemCanonicalPath, ItemSet};
+use super::item::{IsOpaque, Item, ItemAncestors, ItemCanonicalPath, ItemSet};
use super::item_kind::ItemKind;
use super::module::{Module, ModuleKind};
use super::named::{UsedTemplateParameters, analyze};
@@ -339,7 +339,7 @@ impl<'ctx> BindgenContext<'ctx> {
location);
debug_assert!(declaration.is_some() || !item.kind().is_type() ||
item.kind().expect_type().is_builtin_or_named() ||
- item.kind().expect_type().is_opaque(),
+ item.kind().expect_type().is_opaque(self, &item),
"Adding a type without declaration?");
let id = item.id();
diff --git a/src/ir/item.rs b/src/ir/item.rs
index b80ddbd9..3564c6e8 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -61,6 +61,17 @@ pub trait ItemCanonicalPath {
fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String>;
}
+/// A trait for determining if some IR thing is opaque or not.
+pub trait IsOpaque {
+ /// Extra context the IR thing needs to determine if it is opaque or not.
+ type Extra;
+
+ /// Returns `true` if the thing is opaque, and `false` otherwise.
+ ///
+ /// May only be called when `ctx` is in the codegen phase.
+ fn is_opaque(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool;
+}
+
/// A trait for iterating over an item and its parents and up its ancestor chain
/// up to (but not including) the implicit root module.
pub trait ItemAncestors {
@@ -231,7 +242,7 @@ impl Trace for Item {
// don't want to stop collecting types even though they may be
// opaque.
if ty.should_be_traced_unconditionally() ||
- !self.is_opaque(ctx) {
+ !self.is_opaque(ctx, &()) {
ty.trace(ctx, tracer, self);
}
}
@@ -269,7 +280,7 @@ impl CanDeriveDebug for Item {
let result = ctx.options().derive_debug &&
match self.kind {
ItemKind::Type(ref ty) => {
- if self.is_opaque(ctx) {
+ if self.is_opaque(ctx, &()) {
ty.layout(ctx)
.map_or(true, |l| l.opaque().can_derive_debug(ctx, ()))
} else {
@@ -292,7 +303,7 @@ impl CanDeriveDefault for Item {
ctx.options().derive_default &&
match self.kind {
ItemKind::Type(ref ty) => {
- if self.is_opaque(ctx) {
+ if self.is_opaque(ctx, &()) {
ty.layout(ctx)
.map_or(false,
|l| l.opaque().can_derive_default(ctx, ()))
@@ -317,7 +328,7 @@ impl<'a> CanDeriveCopy<'a> for Item {
let result = match self.kind {
ItemKind::Type(ref ty) => {
- if self.is_opaque(ctx) {
+ if self.is_opaque(ctx, &()) {
ty.layout(ctx)
.map_or(true, |l| l.opaque().can_derive_copy(ctx, ()))
} else {
@@ -335,7 +346,7 @@ impl<'a> CanDeriveCopy<'a> for Item {
fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
match self.kind {
ItemKind::Type(ref ty) => {
- if self.is_opaque(ctx) {
+ if self.is_opaque(ctx, &()) {
ty.layout(ctx)
.map_or(true, |l| {
l.opaque().can_derive_copy_in_array(ctx, ())
@@ -593,15 +604,6 @@ impl Item {
ctx.hidden_by_name(&self.canonical_path(ctx), self.id)
}
- /// Is this item opaque?
- pub fn is_opaque(&self, ctx: &BindgenContext) -> bool {
- debug_assert!(ctx.in_codegen_phase(),
- "You're not supposed to call this yet");
- self.annotations.opaque() ||
- self.as_type().map_or(false, |ty| ty.is_opaque()) ||
- ctx.opaque_by_name(&self.canonical_path(ctx))
- }
-
/// Is this a reference to another type?
pub fn is_type_ref(&self) -> bool {
self.as_type().map_or(false, |ty| ty.is_type_ref())
@@ -858,6 +860,28 @@ impl Item {
}
}
+impl IsOpaque for ItemId {
+ type Extra = ();
+
+ fn is_opaque(&self, ctx: &BindgenContext, _: &()) -> bool {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ ctx.resolve_item(*self).is_opaque(ctx, &())
+ }
+}
+
+impl IsOpaque for Item {
+ type Extra = ();
+
+ fn is_opaque(&self, ctx: &BindgenContext, _: &()) -> bool {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ self.annotations.opaque() ||
+ self.as_type().map_or(false, |ty| ty.is_opaque(ctx, self)) ||
+ ctx.opaque_by_name(&self.canonical_path(ctx))
+ }
+}
+
/// A set of items.
pub type ItemSet = BTreeSet<ItemId>;
@@ -874,7 +898,7 @@ impl DotAttributes for Item {
self.id,
self.name(ctx).get()));
- if self.is_opaque(ctx) {
+ if self.is_opaque(ctx, &()) {
writeln!(out, "<tr><td>opaque</td><td>true</td></tr>")?;
}
diff --git a/src/ir/template.rs b/src/ir/template.rs
index 722c1b81..fcba40e1 100644
--- a/src/ir/template.rs
+++ b/src/ir/template.rs
@@ -29,7 +29,7 @@
use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug};
-use super::item::{Item, ItemAncestors};
+use super::item::{IsOpaque, Item, ItemAncestors, ItemCanonicalPath};
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use clang;
@@ -305,6 +305,40 @@ impl TemplateInstantiation {
}
}
+impl IsOpaque for TemplateInstantiation {
+ type Extra = Item;
+
+ /// Is this an opaque template instantiation?
+ fn is_opaque(&self, ctx: &BindgenContext, item: &Item) -> bool {
+ if self.template_definition().is_opaque(ctx, &()) {
+ return true;
+ }
+
+ // TODO(#774): This doesn't properly handle opaque instantiations where
+ // an argument is itself an instantiation because `canonical_name` does
+ // not insert the template arguments into the name, ie it for nested
+ // template arguments it creates "Foo" instead of "Foo<int>". The fully
+ // correct fix is to make `canonical_{name,path}` include template
+ // arguments properly.
+
+ let mut path = item.canonical_path(ctx);
+ let args: Vec<_> = self.template_arguments()
+ .iter()
+ .map(|arg| {
+ let arg_path = arg.canonical_path(ctx);
+ arg_path[1..].join("::")
+ }).collect();
+ {
+ let mut last = path.last_mut().unwrap();
+ last.push('<');
+ last.push_str(&args.join(", "));
+ last.push('>');
+ }
+
+ ctx.opaque_by_name(&path)
+ }
+}
+
impl<'a> CanDeriveCopy<'a> for TemplateInstantiation {
type Extra = ();
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index 3e5f53b0..d19a4889 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -7,7 +7,7 @@ use super::dot::DotAttributes;
use super::enum_ty::Enum;
use super::function::FunctionSig;
use super::int::IntKind;
-use super::item::Item;
+use super::item::{IsOpaque, Item};
use super::layout::{Layout, Opaque};
use super::objc::ObjCInterface;
use super::template::{AsTemplateParam, TemplateInstantiation, TemplateParameters};
@@ -102,14 +102,6 @@ impl Type {
}
}
- /// Is this type of kind `TypeKind::Opaque`?
- pub fn is_opaque(&self) -> bool {
- match self.kind {
- TypeKind::Opaque => true,
- _ => false,
- }
- }
-
/// Is this type of kind `TypeKind::Named`?
pub fn is_named(&self) -> bool {
match self.kind {
@@ -374,6 +366,18 @@ impl Type {
}
}
+impl IsOpaque for Type {
+ type Extra = Item;
+
+ fn is_opaque(&self, ctx: &BindgenContext, item: &Item) -> bool {
+ match self.kind {
+ TypeKind::Opaque => true,
+ TypeKind::TemplateInstantiation(ref inst) => inst.is_opaque(ctx, item),
+ _ => false,
+ }
+ }
+}
+
impl AsTemplateParam for Type {
type Extra = Item;
diff --git a/tests/expectations/tests/issue-674-1.rs b/tests/expectations/tests/issue-674-1.rs
index e8b81dd3..01257c23 100644
--- a/tests/expectations/tests/issue-674-1.rs
+++ b/tests/expectations/tests/issue-674-1.rs
@@ -43,13 +43,4 @@ pub mod root {
impl Clone for CapturingContentInfo {
fn clone(&self) -> Self { *self }
}
- #[test]
- fn __bindgen_test_layout_Maybe_instantiation() {
- assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
- "Size of template specialization: " , stringify ! ( u8 )
- ));
- assert_eq!(::std::mem::align_of::<u8>() , 1usize , concat ! (
- "Alignment of template specialization: " , stringify ! ( u8
- ) ));
- }
}
diff --git a/tests/expectations/tests/issue-674-2.rs b/tests/expectations/tests/issue-674-2.rs
index d7b0bb1c..da0d8287 100644
--- a/tests/expectations/tests/issue-674-2.rs
+++ b/tests/expectations/tests/issue-674-2.rs
@@ -67,15 +67,6 @@ pub mod root {
pub _address: u8,
}
#[test]
- fn __bindgen_test_layout_Rooted_instantiation() {
- assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
- "Size of template specialization: " , stringify ! ( u8 )
- ));
- assert_eq!(::std::mem::align_of::<u8>() , 1usize , concat ! (
- "Alignment of template specialization: " , stringify ! ( u8
- ) ));
- }
- #[test]
fn __bindgen_test_layout_StaticRefPtr_instantiation() {
assert_eq!(::std::mem::size_of::<root::StaticRefPtr>() , 1usize ,
concat ! (
diff --git a/tests/expectations/tests/issue-674-3.rs b/tests/expectations/tests/issue-674-3.rs
index 8fd06b76..6e915a18 100644
--- a/tests/expectations/tests/issue-674-3.rs
+++ b/tests/expectations/tests/issue-674-3.rs
@@ -57,13 +57,4 @@ pub mod root {
impl Clone for nsCSSValue {
fn clone(&self) -> Self { *self }
}
- #[test]
- fn __bindgen_test_layout_nsRefPtrHashtable_instantiation() {
- assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
- "Size of template specialization: " , stringify ! ( u8 )
- ));
- assert_eq!(::std::mem::align_of::<u8>() , 1usize , concat ! (
- "Alignment of template specialization: " , stringify ! ( u8
- ) ));
- }
}
diff --git a/tests/expectations/tests/opaque-template-instantiation-namespaced.rs b/tests/expectations/tests/opaque-template-instantiation-namespaced.rs
new file mode 100644
index 00000000..6623dae2
--- /dev/null
+++ b/tests/expectations/tests/opaque-template-instantiation-namespaced.rs
@@ -0,0 +1,128 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+
+
+#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
+pub mod root {
+ #[allow(unused_imports)]
+ use self::super::root;
+ pub mod zoidberg {
+ #[allow(unused_imports)]
+ use self::super::super::root;
+ #[repr(C)]
+ #[derive(Debug, Copy, Clone)]
+ pub struct Template<T> {
+ pub member: T,
+ pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
+ }
+ impl <T> Default for Template<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy)]
+ pub struct Foo {
+ pub c: ::std::os::raw::c_char,
+ }
+ #[test]
+ fn bindgen_test_layout_Foo() {
+ assert_eq!(::std::mem::size_of::<Foo>() , 1usize , concat ! (
+ "Size of: " , stringify ! ( Foo ) ));
+ assert_eq! (::std::mem::align_of::<Foo>() , 1usize , concat ! (
+ "Alignment of " , stringify ! ( Foo ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Foo ) ) . c as * const _ as usize
+ } , 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( Foo ) , "::" ,
+ stringify ! ( c ) ));
+ }
+ impl Clone for Foo {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy)]
+ pub struct Bar {
+ pub i: ::std::os::raw::c_int,
+ }
+ #[test]
+ fn bindgen_test_layout_Bar() {
+ assert_eq!(::std::mem::size_of::<Bar>() , 4usize , concat ! (
+ "Size of: " , stringify ! ( Bar ) ));
+ assert_eq! (::std::mem::align_of::<Bar>() , 4usize , concat ! (
+ "Alignment of " , stringify ! ( Bar ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . i as * const _ as usize
+ } , 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( i ) ));
+ }
+ impl Clone for Bar {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct ContainsInstantiation {
+ pub not_opaque: root::zoidberg::Template<root::zoidberg::Foo>,
+ }
+ #[test]
+ fn bindgen_test_layout_ContainsInstantiation() {
+ assert_eq!(::std::mem::size_of::<ContainsInstantiation>() , 1usize
+ , concat ! (
+ "Size of: " , stringify ! ( ContainsInstantiation ) ));
+ assert_eq! (::std::mem::align_of::<ContainsInstantiation>() ,
+ 1usize , concat ! (
+ "Alignment of " , stringify ! ( ContainsInstantiation
+ ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const ContainsInstantiation ) ) .
+ not_opaque as * const _ as usize } , 0usize , concat !
+ (
+ "Alignment of field: " , stringify ! (
+ ContainsInstantiation ) , "::" , stringify ! (
+ not_opaque ) ));
+ }
+ impl Clone for ContainsInstantiation {
+ fn clone(&self) -> Self { *self }
+ }
+ impl Default for ContainsInstantiation {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+ }
+ #[repr(C)]
+ #[derive(Debug, Default, Copy)]
+ pub struct ContainsOpaqueInstantiation {
+ pub opaque: u32,
+ }
+ #[test]
+ fn bindgen_test_layout_ContainsOpaqueInstantiation() {
+ assert_eq!(::std::mem::size_of::<ContainsOpaqueInstantiation>() ,
+ 4usize , concat ! (
+ "Size of: " , stringify ! ( ContainsOpaqueInstantiation
+ ) ));
+ assert_eq! (::std::mem::align_of::<ContainsOpaqueInstantiation>()
+ , 4usize , concat ! (
+ "Alignment of " , stringify ! (
+ ContainsOpaqueInstantiation ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const ContainsOpaqueInstantiation ) ) .
+ opaque as * const _ as usize } , 0usize , concat ! (
+ "Alignment of field: " , stringify ! (
+ ContainsOpaqueInstantiation ) , "::" , stringify ! (
+ opaque ) ));
+ }
+ impl Clone for ContainsOpaqueInstantiation {
+ fn clone(&self) -> Self { *self }
+ }
+ }
+ #[test]
+ fn __bindgen_test_layout_Template_instantiation() {
+ assert_eq!(::std::mem::size_of::<root::zoidberg::Template<root::zoidberg::Foo>>()
+ , 1usize , concat ! (
+ "Size of template specialization: " , stringify ! (
+ root::zoidberg::Template<root::zoidberg::Foo> ) ));
+ assert_eq!(::std::mem::align_of::<root::zoidberg::Template<root::zoidberg::Foo>>()
+ , 1usize , concat ! (
+ "Alignment of template specialization: " , stringify ! (
+ root::zoidberg::Template<root::zoidberg::Foo> ) ));
+ }
+}
diff --git a/tests/expectations/tests/opaque-template-instantiation.rs b/tests/expectations/tests/opaque-template-instantiation.rs
new file mode 100644
index 00000000..eb4e92bc
--- /dev/null
+++ b/tests/expectations/tests/opaque-template-instantiation.rs
@@ -0,0 +1,75 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Template<T> {
+ pub member: T,
+ pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
+}
+impl <T> Default for Template<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct ContainsInstantiation {
+ pub not_opaque: Template<::std::os::raw::c_char>,
+}
+#[test]
+fn bindgen_test_layout_ContainsInstantiation() {
+ assert_eq!(::std::mem::size_of::<ContainsInstantiation>() , 1usize ,
+ concat ! ( "Size of: " , stringify ! ( ContainsInstantiation )
+ ));
+ assert_eq! (::std::mem::align_of::<ContainsInstantiation>() , 1usize ,
+ concat ! (
+ "Alignment of " , stringify ! ( ContainsInstantiation ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const ContainsInstantiation ) ) . not_opaque as
+ * const _ as usize } , 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( ContainsInstantiation )
+ , "::" , stringify ! ( not_opaque ) ));
+}
+impl Clone for ContainsInstantiation {
+ fn clone(&self) -> Self { *self }
+}
+impl Default for ContainsInstantiation {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct ContainsOpaqueInstantiation {
+ pub opaque: u32,
+}
+#[test]
+fn bindgen_test_layout_ContainsOpaqueInstantiation() {
+ assert_eq!(::std::mem::size_of::<ContainsOpaqueInstantiation>() , 4usize ,
+ concat ! (
+ "Size of: " , stringify ! ( ContainsOpaqueInstantiation ) ));
+ assert_eq! (::std::mem::align_of::<ContainsOpaqueInstantiation>() , 4usize
+ , concat ! (
+ "Alignment of " , stringify ! ( ContainsOpaqueInstantiation )
+ ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const ContainsOpaqueInstantiation ) ) . opaque
+ as * const _ as usize } , 0usize , concat ! (
+ "Alignment of field: " , stringify ! (
+ ContainsOpaqueInstantiation ) , "::" , stringify ! ( opaque )
+ ));
+}
+impl Clone for ContainsOpaqueInstantiation {
+ fn clone(&self) -> Self { *self }
+}
+#[test]
+fn __bindgen_test_layout_Template_instantiation() {
+ assert_eq!(::std::mem::size_of::<Template<::std::os::raw::c_char>>() ,
+ 1usize , concat ! (
+ "Size of template specialization: " , stringify ! (
+ Template<::std::os::raw::c_char> ) ));
+ assert_eq!(::std::mem::align_of::<Template<::std::os::raw::c_char>>() ,
+ 1usize , concat ! (
+ "Alignment of template specialization: " , stringify ! (
+ Template<::std::os::raw::c_char> ) ));
+}
diff --git a/tests/headers/opaque-template-instantiation-namespaced.hpp b/tests/headers/opaque-template-instantiation-namespaced.hpp
new file mode 100644
index 00000000..31fb0d52
--- /dev/null
+++ b/tests/headers/opaque-template-instantiation-namespaced.hpp
@@ -0,0 +1,29 @@
+// bindgen-flags: --enable-cxx-namespaces --opaque-type 'zoidberg::Template<zoidberg::Bar>' -- -std=c++14
+
+namespace zoidberg {
+
+template <typename T>
+class Template {
+ T member;
+};
+
+struct Foo {
+ char c;
+};
+
+struct Bar {
+ int i;
+};
+
+class ContainsInstantiation {
+ Template<Foo> not_opaque;
+};
+
+class ContainsOpaqueInstantiation {
+ // We should not generate a layout test for this instantiation, and it
+ // should appear as an opaque blob of bytes in
+ // `ContainsOpaqueInstantiation`'s type definition.
+ Template<Bar> opaque;
+};
+
+}
diff --git a/tests/headers/opaque-template-instantiation.hpp b/tests/headers/opaque-template-instantiation.hpp
new file mode 100644
index 00000000..7589b53c
--- /dev/null
+++ b/tests/headers/opaque-template-instantiation.hpp
@@ -0,0 +1,17 @@
+// bindgen-flags: --opaque-type 'Template<int>' -- -std=c++14
+
+template <typename T>
+class Template {
+ T member;
+};
+
+class ContainsInstantiation {
+ Template<char> not_opaque;
+};
+
+class ContainsOpaqueInstantiation {
+ // We should not generate a layout test for this instantiation, and it
+ // should appear as an opaque blob of bytes in
+ // `ContainsOpaqueInstantiation`'s type definition.
+ Template<int> opaque;
+};