88
99#if defined(__cplusplus )
1010 #define CTEST_ALIGNOF (T ) alignof(T)
11- #define CTEST_EXTERN extern "C"
11+ #define CTEST_EXTERN extern "C"
1212#else
1313 #define CTEST_ALIGNOF (T ) _Alignof(T)
1414 #define CTEST_EXTERN
@@ -62,6 +62,12 @@ CTEST_EXTERN uint64_t ctest_size_of__Byte(void) { return sizeof(Byte); }
6262// Return the alignment of a type.
6363CTEST_EXTERN uint64_t ctest_align_of__Byte (void ) { return CTEST_ALIGNOF (Byte ); }
6464
65+ // Return the size of a type.
66+ CTEST_EXTERN uint64_t ctest_size_of__volatile_char (void ) { return sizeof (volatile_char ); }
67+
68+ // Return the alignment of a type.
69+ CTEST_EXTERN uint64_t ctest_align_of__volatile_char (void ) { return CTEST_ALIGNOF (volatile_char ); }
70+
6571// Return the size of a type.
6672CTEST_EXTERN uint64_t ctest_size_of__gregset_t (void ) { return sizeof (gregset_t ); }
6773
@@ -93,6 +99,13 @@ CTEST_EXTERN uint32_t ctest_signededness_of__Byte(void) {
9399 return all_ones < 0 ;
94100}
95101
102+ // Return `1` if the type is signed, otherwise return `0`.
103+ // Casting -1 to the aliased type if signed evaluates to `-1 < 0`, if unsigned to `MAX_VALUE < 0`
104+ CTEST_EXTERN uint32_t ctest_signededness_of__volatile_char (void ) {
105+ volatile_char all_ones = (volatile_char ) - 1 ;
106+ return all_ones < 0 ;
107+ }
108+
96109// Return the offset of a struct/union field.
97110CTEST_EXTERN uint64_t ctest_offset_of__Person__name (void ) {
98111 return offsetof(struct Person , name );
@@ -208,9 +221,15 @@ ctest_field_ptr__Word__byte(union Word *b) {
208221}
209222
210223#ifdef _MSC_VER
211- // Disable signed/unsigned conversion warnings on MSVC.
212- // These trigger even if the conversion is explicit.
213- # pragma warning(disable:4365)
224+ // Disable signed/unsigned conversion warnings on MSVC.
225+ // These trigger even if the conversion is explicit.
226+ #pragma warning(disable:4365)
227+ #endif
228+
229+ #ifdef __GNUC__
230+ // GCC emits a warning with `-Wextra` if we return a typedef to a type marked `volatile`.
231+ #pragma GCC diagnostic push
232+ #pragma GCC diagnostic ignored "-Wignored-qualifiers"
214233#endif
215234
216235// Tests whether the struct/union/alias `x` when passed by value to C and back to Rust
@@ -240,6 +259,33 @@ CTEST_EXTERN Byte ctest_roundtrip__Byte(
240259 return value ;
241260}
242261
262+ // Tests whether the struct/union/alias `x` when passed by value to C and back to Rust
263+ // remains unchanged.
264+ // It checks if the size is the same as well as if the padding bytes are all in the correct place.
265+ CTEST_EXTERN volatile_char ctest_roundtrip__volatile_char (
266+ volatile_char value ,
267+ const uint8_t is_padding_byte [sizeof (volatile_char )],
268+ uint8_t value_bytes [sizeof (volatile_char )]
269+ ) {
270+ int size = (int )sizeof (volatile_char );
271+ // Mark `p` as volatile so that the C compiler does not optimize away the pattern we create.
272+ // Otherwise the Rust side would not be able to see it.
273+ volatile uint8_t * p = (volatile uint8_t * )& value ;
274+ int i = 0 ;
275+ for (i = 0 ; i < size ; ++ i ) {
276+ // We skip padding bytes in both Rust and C because writing to it is undefined.
277+ // Instead we just make sure the the placement of the padding bytes remains the same.
278+ if (is_padding_byte [i ]) { continue ; }
279+ value_bytes [i ] = p [i ];
280+ // After we check that the pattern remained unchanged from Rust to C, we invert the pattern
281+ // and send it back to Rust to make sure that it remains unchanged from C to Rust.
282+ uint8_t d = (uint8_t )(255 ) - (uint8_t )(i % 256 );
283+ d = d == 0 ? 42 : d ;
284+ p [i ] = d ;
285+ }
286+ return value ;
287+ }
288+
243289// Tests whether the struct/union/alias `x` when passed by value to C and back to Rust
244290// remains unchanged.
245291// It checks if the size is the same as well as if the padding bytes are all in the correct place.
@@ -321,14 +367,20 @@ CTEST_EXTERN union Word ctest_roundtrip__Word(
321367 return value ;
322368}
323369
370+ #ifdef __GNUC__
371+ // Pop allow for `-Wignored-qualifiers`
372+ #pragma GCC diagnostic pop
373+ #endif
374+
324375#ifdef _MSC_VER
325- # pragma warning(default:4365)
376+ // Pop allow for 4365
377+ #pragma warning(default:4365)
326378#endif
327379
328380#ifdef _MSC_VER
329- // Disable function pointer type conversion warnings on MSVC.
330- // The conversion may fail only if we call that function, however we only check its address.
331- # pragma warning(disable:4191)
381+ // Disable function pointer type conversion warnings on MSVC.
382+ // The conversion may fail only if we call that function, however we only check its address.
383+ # pragma warning(disable:4191)
332384#endif
333385
334386// Return a function pointer.
@@ -337,7 +389,8 @@ CTEST_EXTERN ctest_void_func ctest_foreign_fn__calloc(void) {
337389}
338390
339391#ifdef _MSC_VER
340- # pragma warning(default:4191)
392+ // Pop allow for 4191
393+ #pragma warning(default:4191)
341394#endif
342395
343396// Return a pointer to the static variable content.
0 commit comments