Repository: immunant/c2rust (language: rust)

Issue:
c2rust Translation Failure with Enums in Compound Literals
## Description

When translating C code that initializes a struct's integer field from an enum using `memcpy` with a compound literal, `c2rust` fails, indicating potential unimplemented handling or a bug in translating such memory operations.

## Source C code

```c
#include <stdio.h>
#include <string.h> 
typedef enum {
    b=2
} a;

typedef struct {
    int data; 
} d_struct;

d_struct d;
int main() {
    // Initialize d with the value of `b` using compound literal and memcpy
    memcpy(&d.data, &((a){b}), sizeof(a));
    printf("Stored enum value: %d\n", d.data);
    return 0; }
```

## Output by GCC and Clang

```
Stored enum value: 2
```

[godbolt view](https://godbolt.org/z/9s1j9d7PT)

## Observed Behavior: Transpilation Failure with the following error message

```bash
$ c2rust-transpile compile_commands.json -e -o transpiled_code --binary runner
Transpiling runner.c
error: Failed to translate main: Init list not implemented for Enum(CDeclId(1131))
```

I think this is related to `memcpy` as the following alternative for `memcpy` is correctly handled by `c2rust`

```c
#include <stdio.h>
typedef enum {
    b=2
} a;

typedef struct {
    int data; 
} d_struct;

d_struct d;

int main() {
    a tmp = b;  
    *(int*)&d.data = tmp;
    printf("Stored enum value: %d\n", d.data);
    return 0; }
```



Discussion / hints:
This is not an issue with `memcpy` but with translation of enums in compound literals; the below code is a minimal reproducer:
```C
typedef enum {
    b=2
} a;

int main() {
    (a){b};
    return 0;
}
```
This seems to resolve the error:
```diff

diff --git a/c2rust-transpile/src/translator/literals.rs b/c2rust-transpile/src/translator/literals.rs
index d8eb64db6..861bb1467 100644
--- a/c2rust-transpile/src/translator/literals.rs
+++ b/c2rust-transpile/src/translator/literals.rs
@@ -246,6 +246,10 @@ impl<'c> Translation<'c> {
                 let id = ids.first().unwrap();
                 self.convert_expr(ctx.used(), *id)
             }
+            CTypeKind::Enum(_) => {
+                let id = ids.first().unwrap();
+                self.convert_expr(ctx.used(), *id)
+            }
             CTypeKind::Vector(CQualTypeId { ctype, .. }, len) => {
                 self.vector_list_initializer(ctx, ids, ctype, len)
             }
```
Thank you for your response, @fw-immunant 
I updated the title. 

Should I give it a try and create a PR for this?
> Should I give it a try and create a PR for this?

Yeah, that would be great!  Thanks!

Fix patch:
diff --git a/c2rust-transpile/src/translator/literals.rs b/c2rust-transpile/src/translator/literals.rs
index 3924aaa657..a04dee2e0f 100644
--- a/c2rust-transpile/src/translator/literals.rs
+++ b/c2rust-transpile/src/translator/literals.rs
@@ -254,6 +254,10 @@ impl<'c> Translation<'c> {
                 let id = ids.first().unwrap();
                 self.convert_expr(ctx.used(), *id)
             }
+            CTypeKind::Enum(_) => {
+                let id = ids.first().unwrap();
+                self.convert_expr(ctx.used(), *id)
+            }
             CTypeKind::Vector(CQualTypeId { ctype, .. }, len) => {
                 self.vector_list_initializer(ctx, ids, ctype, len)
             }


Test patch:
diff --git a/tests/enums/src/enum_compound.c b/tests/enums/src/enum_compound.c
new file mode 100644
index 0000000000..370c282c50
--- /dev/null
+++ b/tests/enums/src/enum_compound.c
@@ -0,0 +1,13 @@
+
+typedef enum {
+    B = 2
+} a;
+
+void entry6(const unsigned buffer_size, int buffer[]) {
+  if (buffer_size < 1) {
+    return; 
+  }
+  
+  // Using a compound literal with enum to assign the value
+  buffer[0] = (a) { B };
+}
diff --git a/tests/enums/src/test_enums.rs b/tests/enums/src/test_enums.rs
index 2410ab12f0..b95fe8b95f 100644
--- a/tests/enums/src/test_enums.rs
+++ b/tests/enums/src/test_enums.rs
@@ -7,6 +7,7 @@ use crate::non_canonical_enum_def::{
     hrtimer_restart, rust_abc, HRTIMER_NORESTART, HRTIMER_RESTART,
 };
 use crate::top_enum::{rust_entry4, E as otherE};
+use crate::enum_compound::rust_entry6;
 
 use libc::{c_int, c_uint};
 
@@ -21,6 +22,8 @@ extern "C" {
     fn entry4(_: c_uint, _: *mut c_int);
 
     fn entry5(_: c_uint, _: *mut c_int);
+
+    fn entry6(_: c_uint, _: *mut c_int);
 }
 
 const BUFFER_SIZE: usize = 10;
@@ -28,6 +31,7 @@ const BUFFER_SIZE2: usize = 7;
 const BUFFER_SIZE3: usize = 4;
 const BUFFER_SIZE4: usize = 1;
 const BUFFER_SIZE5: usize = 6;
+const BUFFER_SIZE6: usize = 1;
 
 pub fn test_variants() {
     assert_eq!(A as u32, 0);
@@ -103,3 +107,17 @@ pub fn test_buffer5() {
     assert_eq!(buffer, rust_buffer);
     assert_eq!(buffer, expected_buffer);
 }
+
+pub fn test_buffer6() {
+    let mut buffer = [0; BUFFER_SIZE6];
+    let mut rust_buffer = [0; BUFFER_SIZE6];
+    let expected_buffer = [2];
+
+    unsafe {
+        entry6(BUFFER_SIZE6 as u32, buffer.as_mut_ptr());
+        rust_entry6(BUFFER_SIZE6 as u32, rust_buffer.as_mut_ptr());
+    }
+
+    assert_eq!(buffer, rust_buffer);
+    assert_eq!(buffer, expected_buffer);
+}