Skip to content

Commit 77d6962

Browse files
author
bors-servo
authored
Auto merge of rust-lang#762 - emilio:much-brokenness, r=fitzgen
Moar bitfield fixes Now with the right branch name. See individual commits for details.
2 parents b08b59a + 700a3ea commit 77d6962

20 files changed

+2750
-488
lines changed

bindgen-integration/cpp/Test.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,29 @@ Date2::assert(unsigned short nWeekDay,
7676
this->byte == byte;
7777
}
7878

79+
bool
80+
Fifth::assert(unsigned short nWeekDay,
81+
unsigned short nMonthDay,
82+
unsigned short nMonth,
83+
unsigned short nYear,
84+
unsigned char byte)
85+
{
86+
return this->nWeekDay == nWeekDay &&
87+
this->nMonthDay == nMonthDay &&
88+
this->nMonth == nMonth &&
89+
this->nYear == nYear &&
90+
this->byte == byte;
91+
}
92+
93+
bool
94+
Sixth::assert(unsigned char byte,
95+
unsigned char nWeekDay,
96+
unsigned char nMonth,
97+
unsigned char nMonthDay) {
98+
return this->nWeekDay == nWeekDay &&
99+
this->nMonthDay == nMonthDay &&
100+
this->nMonth == nMonth &&
101+
this->byte == byte;
102+
};
103+
79104
} // namespace bitfields

bindgen-integration/cpp/Test.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,36 @@ struct Date2 {
9292
unsigned short byte);
9393
};
9494

95+
96+
struct Fifth {
97+
unsigned short nWeekDay : 3; // 0..7 (3 bits)
98+
unsigned short nMonthDay : 6; // 0..31 (6 bits)
99+
unsigned short nMonth : 5; // 0..12 (5 bits)
100+
unsigned short nYear : 8; // 0..100 (8 bits)
101+
unsigned char byte;
102+
103+
/// Returns true if the bitfields match the arguments, false otherwise.
104+
bool assert(unsigned short nWeekDay,
105+
unsigned short nMonthDay,
106+
unsigned short nMonth,
107+
unsigned short nYear,
108+
unsigned char byte);
109+
};
110+
111+
struct Sixth {
112+
unsigned char byte;
113+
unsigned char nWeekDay : 3;
114+
unsigned char nMonth : 5;
115+
unsigned char nMonthDay : 6;
116+
117+
/// Returns true if the bitfields match the arguments, false otherwise.
118+
bool assert(unsigned char byte,
119+
unsigned char nWeekDay,
120+
unsigned char nMonth,
121+
unsigned char nMonthDay);
122+
};
123+
124+
95125
} // namespace bitfields
96126

97127
struct AutoRestoreBool {

bindgen-integration/src/lib.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,48 @@ fn test_bitfields_date2() {
137137
});
138138
}
139139

140+
#[test]
141+
fn test_bitfields_fifth() {
142+
let mut date: bindings::bitfields::Fifth = unsafe {
143+
mem::zeroed()
144+
};
145+
146+
assert!(unsafe {
147+
date.assert(0, 0, 0, 0, 0)
148+
});
149+
150+
date.byte = 255; // Set this first, to ensure we don't override it.
151+
152+
date.set_nWeekDay(6); // saturdays are the best
153+
date.set_nMonthDay(20);
154+
date.set_nMonth(11);
155+
date.set_nYear(95);
156+
157+
assert!(unsafe {
158+
date.assert(6, 20, 11, 95, 255)
159+
});
160+
}
161+
162+
#[test]
163+
fn test_bitfields_sixth() {
164+
let mut date: bindings::bitfields::Sixth = unsafe {
165+
mem::zeroed()
166+
};
167+
168+
assert!(unsafe {
169+
date.assert(0, 0, 0, 0)
170+
});
171+
172+
date.byte = 255;
173+
date.set_nWeekDay(6); // saturdays are the best
174+
date.set_nMonthDay(20);
175+
date.set_nMonth(11);
176+
177+
assert!(unsafe {
178+
date.assert(255, 6, 11, 20)
179+
});
180+
}
181+
140182
#[test]
141183
fn test_bitfield_constructors() {
142184
use std::mem;

src/codegen/mod.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,9 +1113,9 @@ impl Bitfield {
11131113
#[inline]
11141114
$fn_prefix $ctor_name($params $param_name : $bitfield_ty)
11151115
-> $unit_field_int_ty {
1116-
($body |
1117-
(($param_name as $bitfield_int_ty as $unit_field_int_ty) << $offset) &
1118-
($mask as $unit_field_int_ty))
1116+
($body |
1117+
(($param_name as $bitfield_int_ty as $unit_field_int_ty) << $offset) &
1118+
($mask as $unit_field_int_ty))
11191119
}
11201120
}
11211121
).unwrap()
@@ -1147,12 +1147,18 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
11471147
.build_ty(field_ty.clone());
11481148
fields.extend(Some(field));
11491149

1150-
let unit_field_int_ty = match self.layout().size {
1150+
let mut field_int_size = self.layout().size;
1151+
if !field_int_size.is_power_of_two() {
1152+
field_int_size = field_int_size.next_power_of_two();
1153+
}
1154+
1155+
let unit_field_int_ty = match field_int_size {
11511156
8 => quote_ty!(ctx.ext_cx(), u64),
11521157
4 => quote_ty!(ctx.ext_cx(), u32),
11531158
2 => quote_ty!(ctx.ext_cx(), u16),
11541159
1 => quote_ty!(ctx.ext_cx(), u8),
1155-
_ => {
1160+
size => {
1161+
debug_assert!(size > 8);
11561162
// Can't generate bitfield accessors for unit sizes larget than
11571163
// 64 bits at the moment.
11581164
struct_layout.saw_bitfield_unit(self.layout());
@@ -1273,7 +1279,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
12731279
let bitfield_ty = bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
12741280

12751281
let offset = self.offset_into_unit();
1276-
let mask: usize = self.mask();
1282+
let mask = self.mask();
12771283

12781284
let impl_item = quote_item!(
12791285
ctx.ext_cx(),
@@ -1282,7 +1288,9 @@ impl<'a> FieldCodegen<'a> for Bitfield {
12821288
pub fn $getter_name(&self) -> $bitfield_ty {
12831289
let mask = $mask as $unit_field_int_ty;
12841290
let unit_field_val: $unit_field_int_ty = unsafe {
1285-
::$prefix::mem::transmute(self.$unit_field_ident)
1291+
::$prefix::ptr::read_unaligned(
1292+
&self.$unit_field_ident as *const _ as *const $unit_field_int_ty
1293+
)
12861294
};
12871295
let val = (unit_field_val & mask) >> $offset;
12881296
unsafe {
@@ -1296,14 +1304,19 @@ impl<'a> FieldCodegen<'a> for Bitfield {
12961304
let val = val as $bitfield_int_ty as $unit_field_int_ty;
12971305

12981306
let mut unit_field_val: $unit_field_int_ty = unsafe {
1299-
::$prefix::mem::transmute(self.$unit_field_ident)
1307+
::$prefix::ptr::read_unaligned(
1308+
&self.$unit_field_ident as *const _ as *const $unit_field_int_ty)
13001309
};
1310+
13011311
unit_field_val &= !mask;
13021312
unit_field_val |= (val << $offset) & mask;
13031313

1304-
self.$unit_field_ident = unsafe {
1305-
::$prefix::mem::transmute(unit_field_val)
1306-
};
1314+
unsafe {
1315+
::$prefix::ptr::write_unaligned(
1316+
&mut self.$unit_field_ident as *mut _ as *mut $unit_field_int_ty,
1317+
unit_field_val
1318+
);
1319+
}
13071320
}
13081321
}
13091322
).unwrap();

src/ir/comp.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -293,18 +293,15 @@ impl Bitfield {
293293

294294
/// Get the mask value that when &'ed with this bitfield's allocation unit
295295
/// produces this bitfield's value.
296-
///
297-
/// TODO(emilio): This should probably use the target's word size, and what
298-
/// about bitfields that are bigger than that?
299-
pub fn mask(&self) -> usize {
296+
pub fn mask(&self) -> u64 {
300297
use std::mem;
301-
use std::usize;
298+
use std::u64;
302299

303300
let unoffseted_mask =
304-
if self.width() as usize == mem::size_of::<usize>() * 8 {
305-
usize::MAX
301+
if self.width() as u64 == mem::size_of::<u64>() as u64 * 8 {
302+
u64::MAX
306303
} else {
307-
((1usize << self.width()) - 1usize)
304+
((1u64 << self.width()) - 1u64)
308305
};
309306

310307
unoffseted_mask << self.offset_into_unit()
@@ -488,8 +485,9 @@ fn bitfields_to_allocation_units<E, I>(ctx: &BindgenContext,
488485
where E: Extend<Field>
489486
{
490487
*bitfield_unit_count += 1;
491-
let layout = Layout::new(bytes_from_bits_pow2(unit_size_in_bits),
492-
bytes_from_bits_pow2(unit_align_in_bits));
488+
let align = bytes_from_bits_pow2(unit_align_in_bits);
489+
let size = align_to(unit_size_in_bits, align * 8) / 8;
490+
let layout = Layout::new(size, align);
493491
fields.extend(Some(Field::Bitfields(BitfieldUnit {
494492
nth: *bitfield_unit_count,
495493
layout: layout,

0 commit comments

Comments
 (0)