From b05f45e8cb44c27b7d8ff1e59c3701a0595e1751 Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 5 Apr 2026 14:56:13 +0200 Subject: [PATCH 1/2] transpile: Add `bitfields.c` snapshot test --- c2rust-transpile/tests/snapshots.rs | 5 ++ c2rust-transpile/tests/snapshots/bitfields.c | 16 ++++++ ...snapshots__transpile@bitfields.c.2021.snap | 52 +++++++++++++++++++ ...snapshots__transpile@bitfields.c.2024.snap | 52 +++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 c2rust-transpile/tests/snapshots/bitfields.c create mode 100644 c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2021.snap create mode 100644 c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2024.snap diff --git a/c2rust-transpile/tests/snapshots.rs b/c2rust-transpile/tests/snapshots.rs index 8d0d626008..fc77c6901e 100644 --- a/c2rust-transpile/tests/snapshots.rs +++ b/c2rust-transpile/tests/snapshots.rs @@ -311,6 +311,11 @@ fn test_atomics() { transpile("atomics.c").run(); } +#[test] +fn test_bitfields() { + transpile("bitfields.c").expect_compile_error(true).run(); +} + #[test] fn test_bool() { transpile("bool.c").run(); diff --git a/c2rust-transpile/tests/snapshots/bitfields.c b/c2rust-transpile/tests/snapshots/bitfields.c new file mode 100644 index 0000000000..fba8ac6f99 --- /dev/null +++ b/c2rust-transpile/tests/snapshots/bitfields.c @@ -0,0 +1,16 @@ +int printf(const char*, ...); + +struct PacketHeader { + unsigned char version : 3; + unsigned char type : 2; + unsigned char flags : 3; + unsigned short sequence : 10; + unsigned short length : 6; +}; + +void test_bitfields(void) { + struct PacketHeader h = {0}; + h.version = 5; + h.sequence = 513; + printf("version=%u sequence=%u\n", h.version, h.sequence); +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2021.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2021.snap new file mode 100644 index 0000000000..04d0ad8202 --- /dev/null +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2021.snap @@ -0,0 +1,52 @@ +--- +source: c2rust-transpile/tests/snapshots.rs +expression: cat tests/snapshots/bitfields.2021.rs +--- +#![allow( + dead_code, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused_assignments, + unused_mut +)] +#![deny(unsafe_op_in_unsafe_fn)] +extern "C" { + fn printf(_: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct PacketHeader { + #[bitfield(padding)] + pub c2rust_padding: [u8; 1], + #[bitfield(name = "version", ty = "::core::ffi::c_uchar", bits = "0..=2")] + #[bitfield(name = "type_0", ty = "::core::ffi::c_uchar", bits = "3..=4")] + #[bitfield(name = "flags", ty = "::core::ffi::c_uchar", bits = "5..=7")] + #[bitfield(name = "sequence", ty = "::core::ffi::c_ushort", bits = "16..=25")] + #[bitfield(name = "length", ty = "::core::ffi::c_ushort", bits = "26..=31")] + pub version_type_0_flags_sequence_length: [u8; 3], +} +#[no_mangle] +pub unsafe extern "C" fn test_bitfields() { + unsafe { + let mut h: PacketHeader = { + let mut init = PacketHeader { + c2rust_padding: [0; 1], + version_type_0_flags_sequence_length: [0; 3], + }; + init.set_version(0 as ::core::ffi::c_uchar); + init.set_type_0(0); + init.set_flags(0); + init.set_sequence(0); + init.set_length(0); + init + }; + h.set_version(5 as ::core::ffi::c_uchar as ::core::ffi::c_uchar); + h.set_sequence(513 as ::core::ffi::c_ushort as ::core::ffi::c_ushort); + printf( + b"version=%u sequence=%u\n\0".as_ptr() as *const ::core::ffi::c_char, + h.version() as ::core::ffi::c_int, + h.sequence() as ::core::ffi::c_int, + ); + } +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2024.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2024.snap new file mode 100644 index 0000000000..7e32a14921 --- /dev/null +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2024.snap @@ -0,0 +1,52 @@ +--- +source: c2rust-transpile/tests/snapshots.rs +expression: cat tests/snapshots/bitfields.2024.rs +--- +#![allow( + dead_code, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused_assignments, + unused_mut +)] +#![deny(unsafe_op_in_unsafe_fn)] +unsafe extern "C" { + unsafe fn printf(_: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; +} +#[derive(Copy, Clone, BitfieldStruct)] +#[repr(C)] +pub struct PacketHeader { + #[bitfield(padding)] + pub c2rust_padding: [u8; 1], + #[bitfield(name = "version", ty = "::core::ffi::c_uchar", bits = "0..=2")] + #[bitfield(name = "type_0", ty = "::core::ffi::c_uchar", bits = "3..=4")] + #[bitfield(name = "flags", ty = "::core::ffi::c_uchar", bits = "5..=7")] + #[bitfield(name = "sequence", ty = "::core::ffi::c_ushort", bits = "16..=25")] + #[bitfield(name = "length", ty = "::core::ffi::c_ushort", bits = "26..=31")] + pub version_type_0_flags_sequence_length: [u8; 3], +} +#[unsafe(no_mangle)] +pub unsafe extern "C" fn test_bitfields() { + unsafe { + let mut h: PacketHeader = { + let mut init = PacketHeader { + c2rust_padding: [0; 1], + version_type_0_flags_sequence_length: [0; 3], + }; + init.set_version(0 as ::core::ffi::c_uchar); + init.set_type_0(0); + init.set_flags(0); + init.set_sequence(0); + init.set_length(0); + init + }; + h.set_version(5 as ::core::ffi::c_uchar as ::core::ffi::c_uchar); + h.set_sequence(513 as ::core::ffi::c_ushort as ::core::ffi::c_ushort); + printf( + b"version=%u sequence=%u\n\0".as_ptr() as *const ::core::ffi::c_char, + h.version() as ::core::ffi::c_int, + h.sequence() as ::core::ffi::c_int, + ); + } +} From 5109fd793b656ff14ba366594c0079afcc7148ac Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 5 Apr 2026 15:31:52 +0200 Subject: [PATCH 2/2] transpile: Qualify `::c2rust_bitfields::BitfieldStruct` in derives --- c2rust-ast-builder/src/builder.rs | 8 ++++++++ c2rust-transpile/src/translator/structs_unions.rs | 14 +++++--------- .../snapshots__transpile@bitfields.c.2021.snap | 2 +- .../snapshots__transpile@bitfields.c.2024.snap | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/c2rust-ast-builder/src/builder.rs b/c2rust-ast-builder/src/builder.rs index 21c986a759..704afe1693 100644 --- a/c2rust-ast-builder/src/builder.rs +++ b/c2rust-ast-builder/src/builder.rs @@ -2002,6 +2002,14 @@ impl Builder { self.meta(Meta::Path(path)) } + pub fn abs_meta_path(self, path: Pa) -> Meta + where + Pa: Make, + { + let path = mk().abs_path(path); + self.meta_path(path) + } + /// makes a meta item with the given path and some arguments /// # Examples /// diff --git a/c2rust-transpile/src/translator/structs_unions.rs b/c2rust-transpile/src/translator/structs_unions.rs index b332d30b1b..13b127af57 100644 --- a/c2rust-transpile/src/translator/structs_unions.rs +++ b/c2rust-transpile/src/translator/structs_unions.rs @@ -71,8 +71,8 @@ impl<'a> Translation<'a> { let mut derives = vec![]; if !contains_va_list { - derives.push("Copy"); - derives.push("Clone"); + derives.push(mk().meta_path("Copy")); + derives.push(mk().meta_path("Clone")); }; let has_bitfields = fields @@ -82,7 +82,7 @@ impl<'a> Translation<'a> { _ => unreachable!("Found non-field in record field list"), }); if has_bitfields { - derives.push("BitfieldStruct"); + derives.push(mk().abs_meta_path(vec!["c2rust_bitfields", "BitfieldStruct"])); self.use_crate(ExternCrate::C2RustBitfields); } @@ -240,9 +240,7 @@ impl<'a> Translation<'a> { /// Here we output a struct derive to generate bitfield data that looks like this: /// /// ```no_run - /// # use c2rust_bitfields::BitfieldStruct; - /// # - /// #[derive(BitfieldStruct, Clone, Copy)] + /// #[derive(::c2rust_bitfields::BitfieldStruct, Clone, Copy)] /// #[repr(C, align(2))] /// struct Foo { /// #[bitfield(name = "bf1", ty = "std::ffi::c_char", bits = "0..=9")] @@ -341,9 +339,7 @@ impl<'a> Translation<'a> { /// It looks like this in locals and (sectioned) statics: /// /// ```no_run - /// # use c2rust_bitfields::BitfieldStruct; - /// # - /// # #[derive(BitfieldStruct, Clone, Copy)] + /// # #[derive(::c2rust_bitfields::BitfieldStruct, Clone, Copy)] /// # #[repr(C, align(2))] /// # struct Foo { /// # #[bitfield(name = "bf1", ty = "std::ffi::c_char", bits = "0..=9")] diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2021.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2021.snap index 04d0ad8202..4841185269 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2021.snap @@ -14,7 +14,7 @@ expression: cat tests/snapshots/bitfields.2021.rs extern "C" { fn printf(_: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; } -#[derive(Copy, Clone, BitfieldStruct)] +#[derive(Copy, Clone, ::c2rust_bitfields::BitfieldStruct)] #[repr(C)] pub struct PacketHeader { #[bitfield(padding)] diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2024.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2024.snap index 7e32a14921..9542bdf56f 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@bitfields.c.2024.snap @@ -14,7 +14,7 @@ expression: cat tests/snapshots/bitfields.2024.rs unsafe extern "C" { unsafe fn printf(_: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; } -#[derive(Copy, Clone, BitfieldStruct)] +#[derive(Copy, Clone, ::c2rust_bitfields::BitfieldStruct)] #[repr(C)] pub struct PacketHeader { #[bitfield(padding)]