Skip to content

Commit 19df995

Browse files
committed
ctest: Emit the enum keyword for enum field tests
Currently the return type for a function is missing the `enum` keyword. Resolve this by using the same logic for struct fields as for translating other paths.
1 parent 1808393 commit 19df995

File tree

6 files changed

+104
-35
lines changed

6 files changed

+104
-35
lines changed

ctest/src/template.rs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -576,18 +576,15 @@ fn static_test_ident(ident: &str) -> BoxStr {
576576
/// Wrap methods that depend on both ffi items and the generator.
577577
pub(crate) struct TranslateHelper<'a> {
578578
filtered_ffi_items: FfiItems,
579-
ffi_items: &'a FfiItems,
580579
generator: &'a TestGenerator,
581580
translator: Translator<'a>,
582581
}
583582

584583
impl<'a> TranslateHelper<'a> {
585584
/// Create a new translation helper.
586585
pub(crate) fn new(ffi_items: &'a FfiItems, generator: &'a TestGenerator) -> Self {
587-
let filtered_ffi_items = ffi_items.clone();
588586
let mut helper = Self {
589-
filtered_ffi_items,
590-
ffi_items,
587+
filtered_ffi_items: ffi_items.clone(),
591588
generator,
592589
translator: Translator::new(ffi_items, generator),
593590
};
@@ -697,15 +694,7 @@ impl<'a> TranslateHelper<'a> {
697694
)
698695
})?;
699696

700-
let item = if self.ffi_items.contains_struct(&ty) {
701-
MapInput::StructType(&ty)
702-
} else if self.ffi_items.contains_union(ident) {
703-
MapInput::UnionType(&ty)
704-
} else if self.generator.c_enums.iter().any(|f| f(&ty)) {
705-
MapInput::CEnumType(&ty)
706-
} else {
707-
MapInput::Type(&ty)
708-
};
697+
let item = self.translator.map_rust_name_to_c(&ty);
709698

710699
Ok(self.generator.rty_to_cty(item))
711700
}

ctest/src/translator.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -234,13 +234,7 @@ impl<'a> Translator<'a> {
234234
}
235235

236236
let name = last.ident.to_string();
237-
let item = if self.ffi_items.contains_struct(&name) {
238-
MapInput::StructType(&name)
239-
} else if self.ffi_items.contains_union(&name) {
240-
MapInput::UnionType(&name)
241-
} else {
242-
MapInput::Type(&name)
243-
};
237+
let item = self.map_rust_name_to_c(&name);
244238

245239
Ok(cdecl::named(
246240
&self.generator.rty_to_cty(item),
@@ -287,6 +281,18 @@ impl<'a> Translator<'a> {
287281
_ => false,
288282
}
289283
}
284+
285+
pub(crate) fn map_rust_name_to_c<'name>(&self, name: &'name str) -> MapInput<'name> {
286+
if self.ffi_items.contains_struct(name) {
287+
MapInput::StructType(name)
288+
} else if self.ffi_items.contains_union(name) {
289+
MapInput::UnionType(name)
290+
} else if self.generator.c_enums.iter().any(|f| f(name)) {
291+
MapInput::CEnumType(name)
292+
} else {
293+
MapInput::Type(name)
294+
}
295+
}
290296
}
291297

292298
/// Translate mutability from Rust to C.

ctest/tests/input/simple.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,19 @@ typedef unsigned long gregset_t[32];
66

77
Byte byte = 0x42;
88

9+
enum Color
10+
{
11+
RED,
12+
BLUE,
13+
GREEN
14+
};
15+
916
struct Person
1017
{
1118
const char *name;
1219
uint8_t age;
1320
void (*job)(uint8_t, const char *);
21+
enum Color favorite_color;
1422
};
1523

1624
union Word
@@ -22,12 +30,5 @@ union Word
2230
#define A "abc"
2331
#define C_B "bac"
2432

25-
enum Color
26-
{
27-
RED,
28-
BLUE,
29-
GREEN
30-
};
31-
3233
extern void *calloc(size_t num, size_t size);
3334
extern Byte byte;

ctest/tests/input/simple.out.with-renames.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,16 @@ CTEST_EXTERN uint64_t ctest_size_of__Person__job(void) {
123123
return sizeof(((struct Person){}).job);
124124
}
125125

126+
// Return the offset of a struct/union field.
127+
CTEST_EXTERN uint64_t ctest_offset_of__Person__favorite_color(void) {
128+
return offsetof(struct Person, favorite_color);
129+
}
130+
131+
// Return the size of a struct/union field.
132+
CTEST_EXTERN uint64_t ctest_size_of__Person__favorite_color(void) {
133+
return sizeof(((struct Person){}).favorite_color);
134+
}
135+
126136
// Return the offset of a struct/union field.
127137
CTEST_EXTERN uint64_t ctest_offset_of__Word__word(void) {
128138
return offsetof(union Word, word);
@@ -170,6 +180,15 @@ ctest_field_ptr__Person__job(struct Person *b) {
170180
return &b->job;
171181
}
172182

183+
// Return a pointer to a struct/union field.
184+
// This field can have a normal data type, or it could be a function pointer or an array, which
185+
// have different syntax. A typedef is used for convenience, but the syntax must be precomputed.
186+
typedef enum Color *ctest_field_ty__Person__favorite_color;
187+
CTEST_EXTERN ctest_field_ty__Person__favorite_color
188+
ctest_field_ptr__Person__favorite_color(struct Person *b) {
189+
return &b->favorite_color;
190+
}
191+
173192
// Return a pointer to a struct/union field.
174193
// This field can have a normal data type, or it could be a function pointer or an array, which
175194
// have different syntax. A typedef is used for convenience, but the syntax must be precomputed.

ctest/tests/input/simple.out.with-renames.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,32 @@ mod generated_tests {
348348
"field size job of Person");
349349
}
350350

351+
/// Make sure that the offset and size of a field in a struct/union is the same.
352+
pub fn ctest_field_size_offset_Person_favorite_color() {
353+
extern "C" {
354+
fn ctest_offset_of__Person__favorite_color() -> u64;
355+
fn ctest_size_of__Person__favorite_color() -> u64;
356+
}
357+
358+
let uninit_ty = MaybeUninit::<Person>::zeroed();
359+
let uninit_ty = uninit_ty.as_ptr();
360+
361+
// SAFETY: we assume the field access doesn't wrap
362+
let ty_ptr = unsafe { &raw const (*uninit_ty).favorite_color };
363+
// SAFETY: we assume that all zeros is a valid bitpattern for `ty_ptr`, otherwise the
364+
// test should be skipped.
365+
let val = unsafe { ty_ptr.read_unaligned() };
366+
367+
// SAFETY: FFI call with no preconditions
368+
let ctest_field_offset = unsafe { ctest_offset_of__Person__favorite_color() };
369+
check_same(offset_of!(Person, favorite_color) as u64, ctest_field_offset,
370+
"field offset favorite_color of Person");
371+
// SAFETY: FFI call with no preconditions
372+
let ctest_field_size = unsafe { ctest_size_of__Person__favorite_color() };
373+
check_same(size_of_val(&val) as u64, ctest_field_size,
374+
"field size favorite_color of Person");
375+
}
376+
351377
/// Make sure that the offset and size of a field in a struct/union is the same.
352378
pub fn ctest_field_size_offset_Word_word() {
353379
extern "C" {
@@ -454,6 +480,24 @@ mod generated_tests {
454480
"field type job of Person");
455481
}
456482

483+
/// Tests if the pointer to the field is the same in Rust and C.
484+
pub fn ctest_field_ptr_Person_favorite_color() {
485+
extern "C" {
486+
fn ctest_field_ptr__Person__favorite_color(a: *const Person) -> *mut u8;
487+
}
488+
489+
let uninit_ty = MaybeUninit::<Person>::zeroed();
490+
let ty_ptr = uninit_ty.as_ptr();
491+
// SAFETY: We don't read `field_ptr`, only compare the pointer itself.
492+
// The assumption is made that this does not wrap the address space.
493+
let field_ptr = unsafe { &raw const ((*ty_ptr).favorite_color) };
494+
495+
// SAFETY: FFI call with no preconditions
496+
let ctest_field_ptr = unsafe { ctest_field_ptr__Person__favorite_color(ty_ptr) };
497+
check_same(field_ptr.cast(), ctest_field_ptr,
498+
"field type favorite_color of Person");
499+
}
500+
457501
/// Tests if the pointer to the field is the same in Rust and C.
458502
pub fn ctest_field_ptr_Word_word() {
459503
extern "C" {
@@ -720,7 +764,7 @@ mod generated_tests {
720764
/// if there are no fields, then everything is padding, if there are fields, then we have to
721765
/// go through each field and figure out the padding.
722766
fn roundtrip_padding__Person() -> Vec<bool> {
723-
if 3 == 0 {
767+
if 4 == 0 {
724768
// FIXME(ctest): What if it's an alias to a struct/union?
725769
return vec![!false; size_of::<Person>()]
726770
}
@@ -753,6 +797,13 @@ mod generated_tests {
753797
let size = size_of_val(&val);
754798
let off = offset_of!(Person, job);
755799
v.push((off, size));
800+
801+
let ty_ptr = unsafe { &raw const ((*bar).favorite_color) };
802+
let val = unsafe { ty_ptr.read_unaligned() };
803+
804+
let size = size_of_val(&val);
805+
let off = offset_of!(Person, favorite_color);
806+
v.push((off, size));
756807
// This vector contains `true` if the byte is padding and `false` if the byte is not
757808
// padding. Initialize all bytes as:
758809
// - padding if we have fields, this means that only the fields will be checked
@@ -1007,11 +1058,11 @@ fn main() {
10071058
// FIXME(ctest): Maybe consider running the tests in parallel, since everything is independent
10081059
// and we already use atomics.
10091060
fn run_all() {
1010-
ctest_const_cstr_A();
1011-
ctest_const_cstr_B();
10121061
ctest_const_RED();
10131062
ctest_const_BLUE();
10141063
ctest_const_GREEN();
1064+
ctest_const_cstr_A();
1065+
ctest_const_cstr_B();
10151066
ctest_size_align_Byte();
10161067
ctest_size_align_gregset_t();
10171068
ctest_size_align_Color();
@@ -1021,11 +1072,13 @@ fn run_all() {
10211072
ctest_field_size_offset_Person_name();
10221073
ctest_field_size_offset_Person_age();
10231074
ctest_field_size_offset_Person_job();
1075+
ctest_field_size_offset_Person_favorite_color();
10241076
ctest_field_size_offset_Word_word();
10251077
ctest_field_size_offset_Word_byte();
10261078
ctest_field_ptr_Person_name();
10271079
ctest_field_ptr_Person_age();
10281080
ctest_field_ptr_Person_job();
1081+
ctest_field_ptr_Person_favorite_color();
10291082
ctest_field_ptr_Word_word();
10301083
ctest_field_ptr_Word_byte();
10311084
ctest_roundtrip_Byte();

ctest/tests/input/simple.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@ pub type Byte = u8;
55
// This should be automatically skipped for roundtripping.
66
pub type gregset_t = [c_ulong; 32];
77

8+
pub type Color = c_int;
9+
pub const RED: Color = 0;
10+
pub const BLUE: Color = RED + 1;
11+
pub const GREEN: Color = BLUE + 1;
12+
813
#[repr(C)]
914
pub struct Person {
1015
pub name: *const c_char,
1116
pub age: u8,
1217
pub job: extern "C" fn(u8, *const c_char),
18+
pub favorite_color: Color,
1319
}
1420

1521
#[repr(C)]
@@ -21,11 +27,6 @@ pub union Word {
2127
const A: *const c_char = c"abc".as_ptr();
2228
const B: *const c_char = c"bac".as_ptr();
2329

24-
pub type Color = c_int;
25-
pub const RED: Color = 0;
26-
pub const BLUE: Color = RED + 1;
27-
pub const GREEN: Color = BLUE + 1;
28-
2930
unsafe extern "C" {
3031
pub fn calloc(num: usize, size: usize) -> *mut c_void;
3132

0 commit comments

Comments
 (0)