Repository: immunant/c2rust (language: rust)

Issue:
Missing parentheses on reference applied to a cast 
```c
int main(void) {
    int * x = &(int){0};
}
```

generates

```rust
#![allow(dead_code, mutable_transmutes, non_camel_case_types, non_snake_case, non_upper_case_globals, unused_assignments, unused_mut)]
unsafe fn main_0() -> libc::c_int {
    let mut x: *mut libc::c_int = &mut 0 as libc::c_int as *mut libc::c_int;
    return 0;
}
pub fn main() {
    unsafe { ::std::process::exit(main_0() as i32) }
}
```

but extra parentheses are needed

```rust
    let mut x: *mut libc::c_int = &mut (0 as libc::c_int) as *mut libc::c_int;
```

This can happen in more realistic code when an output function parameter is being ignored `f(&(int){0});`

If someone reads this issue and wonders if this is even legal C, check out [compound literal](https://en.cppreference.com/w/c/language/compound_literal)

> The value category of a compound literal is [lvalue](https://en.cppreference.com/w/c/language/value_category) (its address can be taken). ...




Discussion / hints:

Fix patch:
diff --git a/c2rust-ast-builder/src/builder.rs b/c2rust-ast-builder/src/builder.rs
index 252339c988..ef75b2d796 100644
--- a/c2rust-ast-builder/src/builder.rs
+++ b/c2rust-ast-builder/src/builder.rs
@@ -985,13 +985,13 @@ impl Builder {
     }
 
     pub fn addr_of_expr(self, e: Box<Expr>) -> Box<Expr> {
-        Box::new(Expr::Reference(ExprReference {
+        Box::new(parenthesize_if_necessary(Expr::Reference(ExprReference {
             attrs: self.attrs,
             and_token: Token![&](self.span),
             raw: Default::default(),
             mutability: self.mutbl.to_token(),
             expr: e,
-        }))
+        })))
     }
 
     pub fn mac_expr(self, mac: Macro) -> Box<Expr> {
@@ -2280,7 +2280,7 @@ fn expr_precedence(e: &Expr) -> u8 {
         Expr::Field(_ef) => 16,
         Expr::Call(_) | Expr::Index(_) => 15,
         Expr::Try(_et) => 14,
-        Expr::Unary(_eu) => 13,
+        Expr::Unary(_) | Expr::Reference(_) => 13,
         Expr::Cast(_ec) => 12,
         Expr::Binary(eb) => 2 + binop_precedence(&eb.op),
         Expr::Assign(_) | Expr::AssignOp(_) => 1,
@@ -2376,6 +2376,9 @@ fn parenthesize_if_necessary(mut outer: Expr) -> Expr {
         Expr::Unary(ref mut eu) => {
             parenthesize_if_gt(&mut eu.expr);
         }
+        Expr::Reference(ref mut er) => {
+            parenthesize_if_gt(&mut er.expr);
+        }
         Expr::Binary(ref mut eb) => {
             parenthesize_if_gt(&mut eb.left);
             // Because binops associate right, parenthesize same-precedence RHS


Test patch:
diff --git a/tests/casts/src/casts.c b/tests/casts/src/casts.c
index 98d3ab0cea..349eacbc71 100644
--- a/tests/casts/src/casts.c
+++ b/tests/casts/src/casts.c
@@ -31,4 +31,7 @@ void cast_stuff(void) {
         bool b = true;
         float x15 = b;
         void* x16 = (void*)b;
+
+        // reference applied to a cast requires parens on Rust side
+        int * x = &(int){0};
 }