Skip to content

Commit ecd9770

Browse files
author
bors-servo
authored
Auto merge of #572 - fitzgen:sm-layout-test-failures, r=emilio
Generate better opaque blobs in the face of non-type parameters When instantiating templates whose definitions have non-type generic parameters, prefer the layout of the instantiation type to the garbage we get from the definition's layout. In general, an instantiation's layout will always be a better choice than the definition's layout, regardless of non-type parameters. Fixes #569 r? @emilio
2 parents fdea868 + 8b17b65 commit ecd9770

7 files changed

+218
-64
lines changed

src/codegen/mod.rs

+82-62
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,19 @@ impl CodeGenerator for Type {
561561
let layout = self.layout(ctx).unwrap_or_else(Layout::zero);
562562
BlobTyBuilder::new(layout).build()
563563
} else {
564-
inner_item.to_rust_ty(ctx)
564+
let inner_rust_ty = inner_item.to_rust_ty(ctx);
565+
566+
// We get a unit if the inner type is a template definition
567+
// that is opaque or has non-type template parameters and
568+
// doesn't know its layout. Its possible that we have better
569+
// information about the layout, and in the worst case, just
570+
// make sure we don't return a zero-sized type.
571+
if inner_rust_ty == aster::AstBuilder::new().ty().unit() {
572+
let layout = self.layout(ctx).unwrap_or_else(|| Layout::for_size(1));
573+
BlobTyBuilder::new(layout).build()
574+
} else {
575+
inner_rust_ty
576+
}
565577
};
566578

567579
{
@@ -2265,67 +2277,7 @@ impl ToRustTy for Type {
22652277
aster::AstBuilder::new().ty().path().ids(path).build()
22662278
}
22672279
TypeKind::TemplateInstantiation(ref inst) => {
2268-
let decl = inst.template_definition();
2269-
let mut ty = decl.to_rust_ty(ctx).unwrap();
2270-
2271-
// If we gave up when making a type for the template definition,
2272-
// check if maybe we can make a better opaque blob for the
2273-
// instantiation.
2274-
if ty == aster::AstBuilder::new().ty().unit().unwrap() {
2275-
if let Some(layout) = self.layout(ctx) {
2276-
ty = BlobTyBuilder::new(layout).build().unwrap()
2277-
}
2278-
}
2279-
2280-
let decl_params = if let Some(params) =
2281-
decl.self_template_params(ctx) {
2282-
params
2283-
} else {
2284-
// This can happen if we generated an opaque type for a
2285-
// partial template specialization, in which case we just
2286-
// use the opaque type's layout. If we don't have a layout,
2287-
// we cross our fingers and hope for the best :-/
2288-
debug_assert!(ctx.resolve_type_through_type_refs(decl)
2289-
.is_opaque());
2290-
let layout = self.layout(ctx).unwrap_or(Layout::zero());
2291-
ty = BlobTyBuilder::new(layout).build().unwrap();
2292-
2293-
vec![]
2294-
};
2295-
2296-
// TODO: If the decl type is a template class/struct
2297-
// declaration's member template declaration, it could rely on
2298-
// generic template parameters from its outer template
2299-
// class/struct. When we emit bindings for it, it could require
2300-
// *more* type arguments than we have here, and we will need to
2301-
// reconstruct them somehow. We don't have any means of doing
2302-
// that reconstruction at this time.
2303-
2304-
if let ast::TyKind::Path(_, ref mut path) = ty.node {
2305-
let template_args = inst.template_arguments()
2306-
.iter()
2307-
.zip(decl_params.iter())
2308-
// Only pass type arguments for the type parameters that
2309-
// the decl uses.
2310-
.filter(|&(_, param)| ctx.uses_template_parameter(decl, *param))
2311-
.map(|(arg, _)| arg.to_rust_ty(ctx))
2312-
.collect::<Vec<_>>();
2313-
2314-
path.segments.last_mut().unwrap().parameters = if
2315-
template_args.is_empty() {
2316-
None
2317-
} else {
2318-
Some(P(ast::PathParameters::AngleBracketed(
2319-
ast::AngleBracketedParameterData {
2320-
lifetimes: vec![],
2321-
types: P::from_vec(template_args),
2322-
bindings: P::from_vec(vec![]),
2323-
}
2324-
)))
2325-
}
2326-
}
2327-
2328-
P(ty)
2280+
inst.to_rust_ty(ctx, self)
23292281
}
23302282
TypeKind::ResolvedTypeRef(inner) => inner.to_rust_ty(ctx),
23312283
TypeKind::TemplateAlias(inner, _) |
@@ -2409,6 +2361,74 @@ impl ToRustTy for Type {
24092361
}
24102362
}
24112363

2364+
impl ToRustTy for TemplateInstantiation {
2365+
type Extra = Type;
2366+
2367+
fn to_rust_ty(&self, ctx: &BindgenContext, self_ty: &Type) -> P<ast::Ty> {
2368+
let decl = self.template_definition();
2369+
let mut ty = decl.to_rust_ty(ctx).unwrap();
2370+
2371+
if ty == aster::AstBuilder::new().ty().unit().unwrap() {
2372+
// If we gave up when making a type for the template definition,
2373+
// check if maybe we can make a better opaque blob for the
2374+
// instantiation. If not, at least don't use a zero-sized type.
2375+
if let Some(layout) = self_ty.layout(ctx) {
2376+
return BlobTyBuilder::new(layout).build();
2377+
} else {
2378+
return quote_ty!(ctx.ext_cx(), u8);
2379+
}
2380+
}
2381+
2382+
let decl_params = match decl.self_template_params(ctx) {
2383+
Some(params) => params,
2384+
None => {
2385+
// This can happen if we generated an opaque type for a
2386+
// partial template specialization, in which case we just
2387+
// use the opaque type's layout. If we don't have a layout,
2388+
// we cross our fingers and hope for the best :-/
2389+
debug_assert!(ctx.resolve_type_through_type_refs(decl)
2390+
.is_opaque());
2391+
let layout = self_ty.layout(ctx).unwrap_or(Layout::zero());
2392+
return BlobTyBuilder::new(layout).build();
2393+
}
2394+
};
2395+
2396+
// TODO: If the decl type is a template class/struct
2397+
// declaration's member template declaration, it could rely on
2398+
// generic template parameters from its outer template
2399+
// class/struct. When we emit bindings for it, it could require
2400+
// *more* type arguments than we have here, and we will need to
2401+
// reconstruct them somehow. We don't have any means of doing
2402+
// that reconstruction at this time.
2403+
2404+
if let ast::TyKind::Path(_, ref mut path) = ty.node {
2405+
let template_args = self.template_arguments()
2406+
.iter()
2407+
.zip(decl_params.iter())
2408+
// Only pass type arguments for the type parameters that
2409+
// the decl uses.
2410+
.filter(|&(_, param)| ctx.uses_template_parameter(decl, *param))
2411+
.map(|(arg, _)| arg.to_rust_ty(ctx))
2412+
.collect::<Vec<_>>();
2413+
2414+
path.segments.last_mut().unwrap().parameters = if
2415+
template_args.is_empty() {
2416+
None
2417+
} else {
2418+
Some(P(ast::PathParameters::AngleBracketed(
2419+
ast::AngleBracketedParameterData {
2420+
lifetimes: vec![],
2421+
types: P::from_vec(template_args),
2422+
bindings: P::from_vec(vec![]),
2423+
}
2424+
)))
2425+
}
2426+
}
2427+
2428+
P(ty)
2429+
}
2430+
}
2431+
24122432
impl ToRustTy for FunctionSig {
24132433
type Extra = Item;
24142434

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
pub const ENUM_VARIANT_1: _bindgen_ty_1 = _bindgen_ty_1::ENUM_VARIANT_1;
8+
pub const ENUM_VARIANT_2: _bindgen_ty_1 = _bindgen_ty_1::ENUM_VARIANT_2;
9+
#[repr(u32)]
10+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
11+
pub enum _bindgen_ty_1 { ENUM_VARIANT_1 = 0, ENUM_VARIANT_2 = 1, }
12+
pub type JS_Alias = u8;
13+
#[repr(C)]
14+
pub struct JS_Base {
15+
pub f: JS_Alias,
16+
}
17+
impl Default for JS_Base {
18+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
19+
}
20+
#[repr(C)]
21+
pub struct JS_AutoIdVector {
22+
pub _base: JS_Base,
23+
}
24+
#[test]
25+
fn bindgen_test_layout_JS_AutoIdVector() {
26+
assert_eq!(::std::mem::size_of::<JS_AutoIdVector>() , 1usize , concat ! (
27+
"Size of: " , stringify ! ( JS_AutoIdVector ) ));
28+
assert_eq! (::std::mem::align_of::<JS_AutoIdVector>() , 1usize , concat !
29+
( "Alignment of " , stringify ! ( JS_AutoIdVector ) ));
30+
}
31+
impl Default for JS_AutoIdVector {
32+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
33+
}
34+
#[test]
35+
fn __bindgen_test_layout_JS_Base_instantiation_16() {
36+
assert_eq!(::std::mem::size_of::<JS_Base>() , 1usize , concat ! (
37+
"Size of template specialization: " , stringify ! ( JS_Base )
38+
));
39+
assert_eq!(::std::mem::align_of::<JS_Base>() , 1usize , concat ! (
40+
"Alignment of template specialization: " , stringify ! (
41+
JS_Base ) ));
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
pub type Array16 = u8;
8+
pub type ArrayInt4 = [u32; 4usize];
9+
#[repr(C)]
10+
pub struct UsesArray {
11+
pub array_char_16: [u8; 16usize],
12+
pub array_bool_8: [u8; 8usize],
13+
pub array_int_4: ArrayInt4,
14+
}
15+
#[test]
16+
fn bindgen_test_layout_UsesArray() {
17+
assert_eq!(::std::mem::size_of::<UsesArray>() , 40usize , concat ! (
18+
"Size of: " , stringify ! ( UsesArray ) ));
19+
assert_eq! (::std::mem::align_of::<UsesArray>() , 4usize , concat ! (
20+
"Alignment of " , stringify ! ( UsesArray ) ));
21+
assert_eq! (unsafe {
22+
& ( * ( 0 as * const UsesArray ) ) . array_char_16 as * const
23+
_ as usize } , 0usize , concat ! (
24+
"Alignment of field: " , stringify ! ( UsesArray ) , "::" ,
25+
stringify ! ( array_char_16 ) ));
26+
assert_eq! (unsafe {
27+
& ( * ( 0 as * const UsesArray ) ) . array_bool_8 as * const _
28+
as usize } , 16usize , concat ! (
29+
"Alignment of field: " , stringify ! ( UsesArray ) , "::" ,
30+
stringify ! ( array_bool_8 ) ));
31+
assert_eq! (unsafe {
32+
& ( * ( 0 as * const UsesArray ) ) . array_int_4 as * const _
33+
as usize } , 24usize , concat ! (
34+
"Alignment of field: " , stringify ! ( UsesArray ) , "::" ,
35+
stringify ! ( array_int_4 ) ));
36+
}
37+
impl Default for UsesArray {
38+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
39+
}
40+
#[test]
41+
fn __bindgen_test_layout_Array_instantiation_18() {
42+
assert_eq!(::std::mem::size_of::<[u32; 4usize]>() , 16usize , concat ! (
43+
"Size of template specialization: " , stringify ! (
44+
[u32; 4usize] ) ));
45+
assert_eq!(::std::mem::align_of::<[u32; 4usize]>() , 4usize , concat ! (
46+
"Alignment of template specialization: " , stringify ! (
47+
[u32; 4usize] ) ));
48+
}

tests/expectations/tests/opaque_pointer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl Default for Opaque {
3535
#[repr(C)]
3636
#[derive(Debug, Copy)]
3737
pub struct WithOpaquePtr {
38-
pub whatever: *mut (),
38+
pub whatever: *mut u8,
3939
pub other: u32,
4040
pub t: OtherOpaque,
4141
}

tests/expectations/tests/type_alias_empty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
#![allow(non_snake_case)]
55

66

7-
pub type bool_constant = ();
7+
pub type bool_constant = u8;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// bindgen-flags: -- -std=c++14
2+
3+
// Generated by C-Reduce, cleaned up and given names for readability.
4+
5+
template <int, typename>
6+
struct HasNonTypeTemplateParam {
7+
// But doesn't use the non-type template param nor its type param...
8+
};
9+
10+
enum {
11+
ENUM_VARIANT_1,
12+
ENUM_VARIANT_2
13+
};
14+
15+
namespace JS {
16+
17+
template <typename T>
18+
using Alias = HasNonTypeTemplateParam<ENUM_VARIANT_1, T>;
19+
20+
template <typename U>
21+
class Base {
22+
Alias<U> f;
23+
};
24+
25+
class AutoIdVector : Base<int> {};
26+
27+
}

tests/headers/non-type-params.hpp

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// bindgen-flags: -- -std=c++14
2+
3+
template <typename T, unsigned int Capacity>
4+
struct Array {
5+
T elements[Capacity];
6+
};
7+
8+
template <typename T>
9+
using Array16 = Array<T, 16>;
10+
11+
using ArrayInt4 = Array<int, 4>;
12+
13+
struct UsesArray {
14+
Array16<char> array_char_16;
15+
Array<bool, 8> array_bool_8;
16+
ArrayInt4 array_int_4;
17+
};

0 commit comments

Comments
 (0)