Skip to content

Commit 74e2aea

Browse files
committed
Do not derive things on opaque unions
Unions don't support deriving these things, even if there is only one variant (the opaque layout field).
1 parent 641337d commit 74e2aea

File tree

7 files changed

+105
-4
lines changed

7 files changed

+105
-4
lines changed

src/ir/analysis/derive_debug.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,9 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> {
149149
let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| {
150150
l.opaque().can_trivially_derive_debug()
151151
});
152-
return if layout_can_derive {
152+
return if layout_can_derive &&
153+
!(ty.is_union() &&
154+
self.ctx.options().rust_features().untagged_union()) {
153155
trace!(" we can trivially derive Debug for the layout");
154156
ConstrainResult::Same
155157
} else {

src/ir/analysis/derive_default.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDefault<'ctx, 'gen> {
176176
let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| {
177177
l.opaque().can_trivially_derive_default()
178178
});
179-
return if layout_can_derive {
179+
return if layout_can_derive &&
180+
!(ty.is_union() &&
181+
self.ctx.options().rust_features().untagged_union()) {
180182
trace!(" we can trivially derive Default for the layout");
181183
ConstrainResult::Same
182184
} else {

src/ir/analysis/derive_hash.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,9 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveHash<'ctx, 'gen> {
133133
let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| {
134134
l.opaque().can_trivially_derive_hash()
135135
});
136-
return if layout_can_derive {
136+
return if layout_can_derive &&
137+
!(ty.is_union() &&
138+
self.ctx.options().rust_features().untagged_union()) {
137139
trace!(" we can trivially derive Hash for the layout");
138140
ConstrainResult::Same
139141
} else {

src/ir/analysis/derive_partial_eq.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDerivePartialEq<'ctx, 'gen> {
136136
let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| {
137137
l.opaque().can_trivially_derive_partialeq()
138138
});
139-
return if layout_can_derive {
139+
return if layout_can_derive &&
140+
!(ty.is_union() &&
141+
self.ctx.options().rust_features().untagged_union()) {
140142
trace!(" we can trivially derive PartialEq for the layout");
141143
ConstrainResult::Same
142144
} else {

src/ir/ty.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@ impl Type {
9999
}
100100
}
101101

102+
/// Is this a union?
103+
pub fn is_union(&self) -> bool {
104+
match self.kind {
105+
TypeKind::Comp(ref comp) => comp.is_union(),
106+
_ => false,
107+
}
108+
}
109+
102110
/// Is this type of kind `TypeKind::TypeParam`?
103111
pub fn is_type_param(&self) -> bool {
104112
match self.kind {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Default, Copy, Hash, PartialEq)]
9+
pub struct Doggo {
10+
pub x: ::std::os::raw::c_int,
11+
}
12+
#[test]
13+
fn bindgen_test_layout_Doggo() {
14+
assert_eq!(::std::mem::size_of::<Doggo>() , 4usize , concat ! (
15+
"Size of: " , stringify ! ( Doggo ) ));
16+
assert_eq! (::std::mem::align_of::<Doggo>() , 4usize , concat ! (
17+
"Alignment of " , stringify ! ( Doggo ) ));
18+
assert_eq! (unsafe {
19+
& ( * ( 0 as * const Doggo ) ) . x as * const _ as usize } ,
20+
0usize , concat ! (
21+
"Alignment of field: " , stringify ! ( Doggo ) , "::" ,
22+
stringify ! ( x ) ));
23+
}
24+
impl Clone for Doggo {
25+
fn clone(&self) -> Self { *self }
26+
}
27+
#[repr(C)]
28+
#[derive(Debug, Default, Copy, Hash, PartialEq)]
29+
pub struct Null {
30+
pub _address: u8,
31+
}
32+
#[test]
33+
fn bindgen_test_layout_Null() {
34+
assert_eq!(::std::mem::size_of::<Null>() , 1usize , concat ! (
35+
"Size of: " , stringify ! ( Null ) ));
36+
assert_eq! (::std::mem::align_of::<Null>() , 1usize , concat ! (
37+
"Alignment of " , stringify ! ( Null ) ));
38+
}
39+
impl Clone for Null {
40+
fn clone(&self) -> Self { *self }
41+
}
42+
/// This type is an opaque union. Unions can't derive anything interesting like
43+
/// Debug or Default, even if their layout can, because it would require knowing
44+
/// which variant is in use. Opaque unions still end up as a `union` in the Rust
45+
/// bindings, but they just have one variant. Even so, can't derive. We should
46+
/// probably emit an opaque struct for opaque unions... but until then, we have
47+
/// this test to make sure that opaque unions don't derive and still compile.
48+
#[repr(C)]
49+
#[derive(Copy)]
50+
pub union DoggoOrNull {
51+
pub _bindgen_opaque_blob: u32,
52+
}
53+
#[test]
54+
fn bindgen_test_layout_DoggoOrNull() {
55+
assert_eq!(::std::mem::size_of::<DoggoOrNull>() , 4usize , concat ! (
56+
"Size of: " , stringify ! ( DoggoOrNull ) ));
57+
assert_eq! (::std::mem::align_of::<DoggoOrNull>() , 4usize , concat ! (
58+
"Alignment of " , stringify ! ( DoggoOrNull ) ));
59+
}
60+
impl Clone for DoggoOrNull {
61+
fn clone(&self) -> Self { *self }
62+
}
63+
impl Default for DoggoOrNull {
64+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
65+
}

tests/headers/doggo-or-null.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// bindgen-flags: --opaque-type DoggoOrNull --with-derive-partialeq --with-derive-hash -- -std=c++14
2+
3+
class Doggo {
4+
int x;
5+
};
6+
7+
class Null {};
8+
9+
/**
10+
* This type is an opaque union. Unions can't derive anything interesting like
11+
* Debug or Default, even if their layout can, because it would require knowing
12+
* which variant is in use. Opaque unions still end up as a `union` in the Rust
13+
* bindings, but they just have one variant. Even so, can't derive. We should
14+
* probably emit an opaque struct for opaque unions... but until then, we have
15+
* this test to make sure that opaque unions don't derive and still compile.
16+
*/
17+
union DoggoOrNull {
18+
Doggo doggo;
19+
Null none;
20+
};

0 commit comments

Comments
 (0)