Skip to content

Transfer the packed attribute on unions to repr(packed) #347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion c2rust-transpile/src/c_ast/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1946,6 +1946,8 @@ impl ConversionContext {
let name = expect_opt_str(&node.extras[0]).unwrap().map(str::to_string);
let has_def = from_value(node.extras[1].clone())
.expect("Expected has_def flag on struct");
let attrs = from_value::<Vec<Value>>(node.extras[2].clone())
.expect("Expected attribute array on record");
let fields: Option<Vec<CDeclId>> = if has_def {
Some(
node.children
Expand All @@ -1962,7 +1964,18 @@ impl ConversionContext {
None
};

let record = CDeclKind::Union { name, fields };
let mut is_packed = false;
for attr in attrs {
match from_value::<String>(attr.clone())
.expect("Records attributes should be strings")
.as_str()
{
"packed" => is_packed = true,
_ => {}
}
}

let record = CDeclKind::Union { name, fields, is_packed };

self.add_decl(new_id, located(node, record));
self.processed_nodes.insert(new_id, RECORD_DECL);
Expand Down
1 change: 1 addition & 0 deletions c2rust-transpile/src/c_ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,7 @@ pub enum CDeclKind {
Union {
name: Option<String>,
fields: Option<Vec<CFieldId>>,
is_packed: bool,
},

// Field
Expand Down
10 changes: 8 additions & 2 deletions c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1614,6 +1614,7 @@ impl<'c> Translation<'c> {

CDeclKind::Union {
fields: Some(ref fields),
is_packed,
..
} => {
let name = self
Expand Down Expand Up @@ -1642,21 +1643,26 @@ impl<'c> Translation<'c> {
}
}

let mut repr = vec!["C"];
if is_packed {
repr.push("packed");
}

Ok(if field_syns.is_empty() {
// Empty unions are a GNU extension, but Rust doesn't allow empty unions.
ConvertedDecl::Item(
mk().span(s)
.pub_()
.call_attr("derive", vec!["Copy", "Clone"])
.call_attr("repr", vec!["C"])
.call_attr("repr", repr)
.struct_item(name, vec![], false),
)
} else {
ConvertedDecl::Item(
mk().span(s)
.pub_()
.call_attr("derive", vec!["Copy", "Clone"])
.call_attr("repr", vec!["C"])
.call_attr("repr", repr)
.union_item(name, field_syns),
)
})
Expand Down
4 changes: 2 additions & 2 deletions tests/unions/src/test_unions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ extern "C" {
fn entry(_: c_uint, _: *mut c_int);
}

const BUFFER_SIZE: usize = 18;
const BUFFER_SIZE: usize = 19;

pub fn test_buffer() {
let mut buffer = [0; BUFFER_SIZE];
let mut rust_buffer = [0; BUFFER_SIZE];
let expected_buffer = [12, 12, 0, 1, 2, 3, 4, 0, 5, 6, 7, 8, 0, 8, 9, 10, 12, 17];
let expected_buffer = [12, 12, 0, 5, 1, 2, 3, 4, 0, 5, 6, 7, 8, 0, 8, 9, 10, 12, 18];

unsafe {
entry(BUFFER_SIZE as u32, buffer.as_mut_ptr());
Expand Down
6 changes: 6 additions & 0 deletions tests/unions/src/unions.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ union union_with_anon_struct {
};
};

union __attribute__((packed)) packed_union {
int as_int;
char as_chars[5];
};

void entry(const unsigned int buffer_size, int buffer[const])
{
int i = 0;
Expand All @@ -35,6 +40,7 @@ void entry(const unsigned int buffer_size, int buffer[const])
buffer[i++] = sizeof(union my_union);
buffer[i++] = sizeof(union my_union_flipped);
buffer[i++] = sizeof(union empty_union);
buffer[i++] = sizeof(union packed_union);
buffer[i++] = u1.as_int;
buffer[i++] = u2.as_int;
buffer[i++] = u3.as_chars[0];
Expand Down