Skip to content

C2Rust emits Rust that fails borrow-checking for volatile + __sync_add_and_fetch (E0499: multiple mutable borrows) #1683

@lynae99

Description

@lynae99

C2Rust generates Rust code that fails to compile when translating a local volatile uint32_t updated via __sync_add_and_fetch.
The generated Rust keeps a &mut atomic_var in a temporary (let fresh0 = &mut atomic_var;) and also performs ptr::write_volatile(&mut atomic_var as *mut u32, ...) in the same expression, causing Rust borrow checker error E0499 (“cannot borrow as mutable more than once at a time”).
Reproducer

#include <stdint.h>

int main(void) {
    volatile uint32_t atomic_var = 777;
    atomic_var = __sync_add_and_fetch(&atomic_var, 1);
    return 0;
}

C2Rust generates code

#![allow(
    dead_code,
    non_camel_case_types,
    non_snake_case,
    non_upper_case_globals,
    unused_assignments,
    unused_mut
)]
#![feature(core_intrinsics)]
pub type __uint32_t = u32;
pub type uint32_t = __uint32_t;
unsafe fn main_0() -> ::core::ffi::c_int {
    let mut atomic_var: uint32_t = 777 as uint32_t;
    let fresh0 = &mut atomic_var;
    let fresh1 = 1 as ::core::ffi::c_int as uint32_t;
    ::core::ptr::write_volatile(
        &mut atomic_var as *mut uint32_t,
        ::core::intrinsics::atomic_xadd_seqcst(fresh0, fresh1) + fresh1,
    );
    return 0 as ::core::ffi::c_int;
}
pub fn main() {
    unsafe { ::std::process::exit(main_0() as i32) }
}

Rust compilation fails with:

error[E0499]: cannot borrow `atomic_var` as mutable more than once at a time

Environment

  • c2rust version: v0.21.0
  • platform: Ubuntu 24.04
  • Rust: nightly-2022-08-08
  • Clang version: 17.0.6

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions