Skip to content

Commit 527e0e5

Browse files
committed
Handle unions that have non-Copy types
Fixes #895
1 parent ba9809d commit 527e0e5

File tree

4 files changed

+115
-7
lines changed

4 files changed

+115
-7
lines changed

src/codegen/mod.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ struct CodegenResult<'a> {
8383
/// need to be referenced by anything.
8484
codegen_id: &'a Cell<usize>,
8585

86+
/// Whether a bindgen union has been generated at least once.
87+
saw_bindgen_union: bool,
88+
8689
/// Whether an union has been generated at least once.
8790
saw_union: bool,
8891

@@ -123,6 +126,7 @@ impl<'a> CodegenResult<'a> {
123126
CodegenResult {
124127
items: vec![],
125128
saw_union: false,
129+
saw_bindgen_union: false,
126130
saw_incomplete_array: false,
127131
saw_objc: false,
128132
codegen_id: codegen_id,
@@ -137,6 +141,11 @@ impl<'a> CodegenResult<'a> {
137141
self.saw_union = true;
138142
}
139143

144+
fn saw_bindgen_union(&mut self) {
145+
self.saw_union();
146+
self.saw_bindgen_union = true;
147+
}
148+
140149
fn saw_incomplete_array(&mut self) {
141150
self.saw_incomplete_array = true;
142151
}
@@ -350,7 +359,7 @@ impl CodeGenerator for Module {
350359
}
351360

352361
if item.id() == ctx.root_module() {
353-
if result.saw_union && !ctx.options().rust_features().untagged_union() {
362+
if result.saw_bindgen_union {
354363
utils::prepend_union_types(ctx, &mut *result);
355364
}
356365
if result.saw_incomplete_array {
@@ -912,7 +921,7 @@ impl<'a> FieldCodegen<'a> for FieldData {
912921
let ty = self.ty().to_rust_ty_or_opaque(ctx, &());
913922

914923
// NB: If supported, we use proper `union` types.
915-
let ty = if parent.is_union() && !ctx.options().rust_features().untagged_union() {
924+
let ty = if parent.is_union() && !parent.can_be_rust_union(ctx) {
916925
if ctx.options().enable_cxx_namespaces {
917926
quote_ty!(ctx.ext_cx(), root::__BindgenUnionField<$ty>)
918927
} else {
@@ -1449,7 +1458,7 @@ impl CodeGenerator for CompInfo {
14491458
}
14501459

14511460
let canonical_name = item.canonical_name(ctx);
1452-
let builder = if is_union && ctx.options().rust_features().untagged_union() {
1461+
let builder = if is_union && self.can_be_rust_union(ctx) {
14531462
aster::AstBuilder::new()
14541463
.item()
14551464
.pub_()
@@ -1528,6 +1537,9 @@ impl CodeGenerator for CompInfo {
15281537
}
15291538
if is_union {
15301539
result.saw_union();
1540+
if !self.can_be_rust_union(ctx) {
1541+
result.saw_bindgen_union();
1542+
}
15311543
}
15321544

15331545
let layout = item.kind().expect_type().layout(ctx);
@@ -1556,7 +1568,7 @@ impl CodeGenerator for CompInfo {
15561568
());
15571569
}
15581570

1559-
if is_union && !ctx.options().rust_features().untagged_union() {
1571+
if is_union && !self.can_be_rust_union(ctx) {
15601572
let layout = layout.expect("Unable to get layout information?");
15611573
let ty = BlobTyBuilder::new(layout).build();
15621574
let field = StructFieldBuilder::named("bindgen_union_field")

src/ir/comp.rs

+17
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use super::traversal::{EdgeKind, Trace, Tracer};
1010
use super::template::TemplateParameters;
1111
use clang;
1212
use codegen::struct_layout::{align_to, bytes_from_bits_pow2};
13+
use ir::derive::CanDeriveCopy;
1314
use parse::{ClangItemParser, ParseError};
1415
use peeking_take_while::PeekableExt;
1516
use std::cell::Cell;
@@ -1316,6 +1317,22 @@ impl CompInfo {
13161317
pub fn compute_bitfield_units(&mut self, ctx: &BindgenContext) {
13171318
self.fields.compute_bitfield_units(ctx);
13181319
}
1320+
1321+
/// Returns whether the current union can be represented as a Rust `union`
1322+
///
1323+
/// Requirements:
1324+
/// 1. Current RustTarget allows for `untagged_union`
1325+
/// 2. Each field can derive `Copy`
1326+
pub fn can_be_rust_union(&self, ctx: &BindgenContext) -> bool {
1327+
ctx.options().rust_features().untagged_union() &&
1328+
self.fields().iter().all(|f|
1329+
match f {
1330+
&Field::DataMember(ref field_data) => field_data.ty().can_derive_copy(ctx),
1331+
&Field::Bitfields(_) => false,
1332+
}
1333+
)
1334+
}
1335+
13191336
}
13201337

13211338
impl DotAttributes for CompInfo {

tests/expectations/tests/issue-493.rs

+82
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,33 @@
44
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
55

66

7+
#[repr(C)]
8+
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
9+
impl <T> __BindgenUnionField<T> {
10+
#[inline]
11+
pub fn new() -> Self { __BindgenUnionField(::std::marker::PhantomData) }
12+
#[inline]
13+
pub unsafe fn as_ref(&self) -> &T { ::std::mem::transmute(self) }
14+
#[inline]
15+
pub unsafe fn as_mut(&mut self) -> &mut T { ::std::mem::transmute(self) }
16+
}
17+
impl <T> ::std::default::Default for __BindgenUnionField<T> {
18+
#[inline]
19+
fn default() -> Self { Self::new() }
20+
}
21+
impl <T> ::std::clone::Clone for __BindgenUnionField<T> {
22+
#[inline]
23+
fn clone(&self) -> Self { Self::new() }
24+
}
25+
impl <T> ::std::marker::Copy for __BindgenUnionField<T> { }
26+
impl <T> ::std::fmt::Debug for __BindgenUnionField<T> {
27+
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
28+
fmt.write_str("__BindgenUnionField")
29+
}
30+
}
31+
impl <T> ::std::hash::Hash for __BindgenUnionField<T> {
32+
fn hash<H: ::std::hash::Hasher>(&self, _state: &mut H) { }
33+
}
734
#[repr(C)]
835
#[derive(Debug, Default, Copy, Clone, Hash)]
936
pub struct basic_string {
@@ -27,3 +54,58 @@ pub const basic_string___min_cap: basic_string__bindgen_ty_1 =
2754
#[repr(i32)]
2855
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2956
pub enum basic_string__bindgen_ty_1 { __min_cap = 0, }
57+
#[repr(C)]
58+
pub struct basic_string___short {
59+
pub __bindgen_anon_1: basic_string___short__bindgen_ty_1,
60+
pub __data_: *mut basic_string_value_type,
61+
}
62+
#[repr(C)]
63+
pub union basic_string___short__bindgen_ty_1 {
64+
pub __size_: ::std::os::raw::c_uchar,
65+
pub __lx: basic_string_value_type,
66+
}
67+
impl Default for basic_string___short__bindgen_ty_1 {
68+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
69+
}
70+
impl Default for basic_string___short {
71+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
72+
}
73+
#[repr(C)]
74+
pub struct basic_string___ulx {
75+
pub __lx: __BindgenUnionField<basic_string___long>,
76+
pub __lxx: __BindgenUnionField<basic_string___short>,
77+
pub bindgen_union_field: [u8; 0usize],
78+
}
79+
impl Default for basic_string___ulx {
80+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
81+
}
82+
pub const basic_string___n_words: basic_string__bindgen_ty_2 =
83+
basic_string__bindgen_ty_2::__n_words;
84+
#[repr(i32)]
85+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
86+
pub enum basic_string__bindgen_ty_2 { __n_words = 0, }
87+
#[repr(C)]
88+
#[derive(Debug, Copy, Clone, Hash)]
89+
pub struct basic_string___raw {
90+
pub __words: *mut basic_string_size_type,
91+
}
92+
impl Default for basic_string___raw {
93+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
94+
}
95+
#[repr(C)]
96+
pub struct basic_string___rep {
97+
pub __bindgen_anon_1: basic_string___rep__bindgen_ty_1,
98+
}
99+
#[repr(C)]
100+
pub struct basic_string___rep__bindgen_ty_1 {
101+
pub __l: __BindgenUnionField<basic_string___long>,
102+
pub __s: __BindgenUnionField<basic_string___short>,
103+
pub __r: __BindgenUnionField<basic_string___raw>,
104+
pub bindgen_union_field: [u8; 0usize],
105+
}
106+
impl Default for basic_string___rep__bindgen_ty_1 {
107+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
108+
}
109+
impl Default for basic_string___rep {
110+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
111+
}

tests/headers/issue-493.hpp

-3
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ class basic_string
1818
enum {__min_cap = (sizeof(__long) - 1)/sizeof(value_type) > 2 ?
1919
(sizeof(__long) - 1)/sizeof(value_type) : 2};
2020

21-
// TODO(tmfink) uncomment once test passes
22-
#if 0
2321
struct __short
2422
{
2523
union
@@ -48,5 +46,4 @@ class basic_string
4846
__raw __r;
4947
};
5048
};
51-
#endif
5249
};

0 commit comments

Comments
 (0)