From 8ac47a16df5065d4edbeabf63218b2af8d9da299 Mon Sep 17 00:00:00 2001 From: Rua Date: Fri, 15 May 2026 15:12:55 +0200 Subject: [PATCH 1/8] transpile: Use `c2rust_lvalue` name for fresh lvalue variable --- c2rust-transpile/src/translator/named_references.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c2rust-transpile/src/translator/named_references.rs b/c2rust-transpile/src/translator/named_references.rs index ede42c8fab..98c5ba4f01 100644 --- a/c2rust-transpile/src/translator/named_references.rs +++ b/c2rust-transpile/src/translator/named_references.rs @@ -122,7 +122,7 @@ impl<'c> Translation<'c> { } else { // This is the case where we explicitly need to factor out possible side-effects. - let ptr_name = self.renamer.borrow_mut().fresh(); + let ptr_name = self.renamer.borrow_mut().pick_name("c2rust_lvalue"); // let ref mut p = lhs; let compute_ref = mk().local_stmt(Box::new(mk().local( From abf270bec8a19849532e7d01a760bda5e7737465 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 2 May 2026 11:28:08 +0200 Subject: [PATCH 2/8] transpile: Rename unused `if_else` snapshot test and activate it --- c2rust-transpile/tests/snapshots.rs | 5 + .../snapshots/{if_else.c => conditions.c} | 0 ..._transpile@conditions.c.2021.clang15.snap} | 3 +- ...__transpile@conditions.c.2024.clang15.snap | 95 +++++++++++++++++++ 4 files changed, 101 insertions(+), 2 deletions(-) rename c2rust-transpile/tests/snapshots/{if_else.c => conditions.c} (100%) rename c2rust-transpile/tests/snapshots/{snapshots__transpile@if_else.c.snap => snapshots__transpile@conditions.c.2021.clang15.snap} (96%) create mode 100644 c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap diff --git a/c2rust-transpile/tests/snapshots.rs b/c2rust-transpile/tests/snapshots.rs index 4f10e330ea..36a15da67d 100644 --- a/c2rust-transpile/tests/snapshots.rs +++ b/c2rust-transpile/tests/snapshots.rs @@ -354,6 +354,11 @@ fn test_compound_literals() { transpile("compound_literals.c").run(); } +#[test] +fn test_conditions() { + transpile("conditions.c").run(); +} + #[test] fn test_empty_init() { transpile("empty_init.c").run(); diff --git a/c2rust-transpile/tests/snapshots/if_else.c b/c2rust-transpile/tests/snapshots/conditions.c similarity index 100% rename from c2rust-transpile/tests/snapshots/if_else.c rename to c2rust-transpile/tests/snapshots/conditions.c diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@if_else.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2021.clang15.snap similarity index 96% rename from c2rust-transpile/tests/snapshots/snapshots__transpile@if_else.c.snap rename to c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2021.clang15.snap index 05f99290ee..dfc0b11d92 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@if_else.c.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2021.clang15.snap @@ -1,7 +1,6 @@ --- source: c2rust-transpile/tests/snapshots.rs -expression: cat tests/snapshots/if_else.rs -input_file: c2rust-transpile/tests/snapshots/if_else.c +expression: cat tests/snapshots/conditions.2021.clang15.rs --- #![allow( clippy::missing_safety_doc, diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap new file mode 100644 index 0000000000..66ae3f2987 --- /dev/null +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap @@ -0,0 +1,95 @@ +--- +source: c2rust-transpile/tests/snapshots.rs +expression: cat tests/snapshots/conditions.2024.clang15.rs +--- +#![allow( + clippy::missing_safety_doc, + dead_code, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unsafe_op_in_unsafe_fn, + unused_assignments, + unused_mut +)] +#[unsafe(no_mangle)] +pub unsafe extern "C" fn simple_if_else(mut x: ::core::ffi::c_int) -> ::core::ffi::c_int { + if x != 0 { + x += 1 as ::core::ffi::c_int; + } else { + x += 2 as ::core::ffi::c_int; + } + return x; +} +#[unsafe(no_mangle)] +pub unsafe extern "C" fn if_no_else(mut x: ::core::ffi::c_int) -> ::core::ffi::c_int { + if x > 0 as ::core::ffi::c_int { + x += 1 as ::core::ffi::c_int; + } + return x; +} +#[unsafe(no_mangle)] +pub unsafe extern "C" fn multiple_ifs(mut x: ::core::ffi::c_int) -> ::core::ffi::c_int { + if x != 0 { + x += 1 as ::core::ffi::c_int; + } + if x != 0 { + x += 2 as ::core::ffi::c_int; + } + return x; +} +#[unsafe(no_mangle)] +pub unsafe extern "C" fn nested_if_else(mut x: ::core::ffi::c_int) -> ::core::ffi::c_int { + if x > 0 as ::core::ffi::c_int { + if x < 10 as ::core::ffi::c_int { + x += 1 as ::core::ffi::c_int; + } else { + x += 2 as ::core::ffi::c_int; + } + } else { + x -= 1 as ::core::ffi::c_int; + } + return x; +} +#[unsafe(no_mangle)] +pub unsafe extern "C" fn nested_if_no_else(mut x: ::core::ffi::c_int) -> ::core::ffi::c_int { + if x > 0 as ::core::ffi::c_int { + if x < 10 as ::core::ffi::c_int { + x += 1 as ::core::ffi::c_int; + } + x += 2 as ::core::ffi::c_int; + } else { + x -= 1 as ::core::ffi::c_int; + } + return x; +} +#[unsafe(no_mangle)] +pub unsafe extern "C" fn early_returns(mut a: ::core::ffi::c_int) -> ::core::ffi::c_int { + if a == 2 as ::core::ffi::c_int { + return 2 as ::core::ffi::c_int; + } + if a == 3 as ::core::ffi::c_int { + a += 1 as ::core::ffi::c_int; + } + if a == 4 as ::core::ffi::c_int { + return 1 as ::core::ffi::c_int; + } + return 0 as ::core::ffi::c_int; +} +#[unsafe(no_mangle)] +pub unsafe extern "C" fn nested_early_returns(mut x: ::core::ffi::c_int) -> ::core::ffi::c_int { + if x != 0 { + if x != 0 { + x += 1 as ::core::ffi::c_int; + return x; + } + x += 2 as ::core::ffi::c_int; + } else { + if x != 0 { + x += 3 as ::core::ffi::c_int; + return x; + } + x += 4 as ::core::ffi::c_int; + } + return x; +} From c50e86eff10f3ab25fafab29922a07af346a56d8 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 2 May 2026 11:33:12 +0200 Subject: [PATCH 3/8] transpile: Add conditional operators to `conditions.c` snapshot test --- c2rust-transpile/tests/snapshots/conditions.c | 19 +++++ ...__transpile@conditions.c.2021.clang15.snap | 75 +++++++++++++++++++ ...__transpile@conditions.c.2024.clang15.snap | 74 ++++++++++++++++++ 3 files changed, 168 insertions(+) diff --git a/c2rust-transpile/tests/snapshots/conditions.c b/c2rust-transpile/tests/snapshots/conditions.c index 0c14291440..9eb0da5ebc 100644 --- a/c2rust-transpile/tests/snapshots/conditions.c +++ b/c2rust-transpile/tests/snapshots/conditions.c @@ -83,3 +83,22 @@ int nested_early_returns(int x) { } return x; } + +void conditional_operator(const unsigned sz, int buf[const]) { + int x = 0, y = 1; + *(0 ? &y : &x) = 10; + + buf[2] = 1 ? 2 : 3; + buf[3] = 0 ? 2 : 3; +} + +static int id(int i) { return i;} +static int add(int *p, int i, int r) { *p += i; return r;} + +void binary_conditional_operator(const unsigned sz, int buf[const]) { + buf[0] = id(0) ?: id(1); + buf[1] = id(2) ?: id(3); + + (void) (add(buf+2, 2, 0) ?: add(buf+3, 3, 0)); + (void) (add(buf+4, 4, 1) ?: add(buf+5, 5, 0)); +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2021.clang15.snap index dfc0b11d92..559f6aa6d7 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2021.clang15.snap @@ -11,6 +11,7 @@ expression: cat tests/snapshots/conditions.2021.clang15.rs unused_assignments, unused_mut )] +#![feature(raw_ref_op)] #[no_mangle] pub unsafe extern "C" fn simple_if_else(mut x: ::core::ffi::c_int) -> ::core::ffi::c_int { if x != 0 { @@ -92,3 +93,77 @@ pub unsafe extern "C" fn nested_early_returns(mut x: ::core::ffi::c_int) -> ::co } return x; } +#[no_mangle] +pub unsafe extern "C" fn conditional_operator( + sz: ::core::ffi::c_uint, + buf: *mut ::core::ffi::c_int, +) { + let mut x: ::core::ffi::c_int = 0 as ::core::ffi::c_int; + let mut y: ::core::ffi::c_int = 1 as ::core::ffi::c_int; + *if false { &raw mut y } else { &raw mut x } = 10 as ::core::ffi::c_int; + *(buf as *mut ::core::ffi::c_int).offset(2 as ::core::ffi::c_int as isize) = if true { + 2 as ::core::ffi::c_int + } else { + 3 as ::core::ffi::c_int + }; + *(buf as *mut ::core::ffi::c_int).offset(3 as ::core::ffi::c_int as isize) = if false { + 2 as ::core::ffi::c_int + } else { + 3 as ::core::ffi::c_int + }; +} +unsafe extern "C" fn id(mut i: ::core::ffi::c_int) -> ::core::ffi::c_int { + return i; +} +unsafe extern "C" fn add( + mut p: *mut ::core::ffi::c_int, + mut i: ::core::ffi::c_int, + mut r: ::core::ffi::c_int, +) -> ::core::ffi::c_int { + *p += i; + return r; +} +#[no_mangle] +pub unsafe extern "C" fn binary_conditional_operator( + sz: ::core::ffi::c_uint, + buf: *mut ::core::ffi::c_int, +) { + let ref mut c2rust_lvalue = id(0 as ::core::ffi::c_int); + *(buf as *mut ::core::ffi::c_int).offset(0 as ::core::ffi::c_int as isize) = + if *c2rust_lvalue != 0 { + *c2rust_lvalue + } else { + id(1 as ::core::ffi::c_int) + }; + let ref mut c2rust_lvalue_0 = id(2 as ::core::ffi::c_int); + *(buf as *mut ::core::ffi::c_int).offset(1 as ::core::ffi::c_int as isize) = + if *c2rust_lvalue_0 != 0 { + *c2rust_lvalue_0 + } else { + id(3 as ::core::ffi::c_int) + }; + if add( + (buf as *mut ::core::ffi::c_int).offset(2 as ::core::ffi::c_int as isize), + 2 as ::core::ffi::c_int, + 0 as ::core::ffi::c_int, + ) == 0 + { + add( + (buf as *mut ::core::ffi::c_int).offset(3 as ::core::ffi::c_int as isize), + 3 as ::core::ffi::c_int, + 0 as ::core::ffi::c_int, + ); + } + if add( + (buf as *mut ::core::ffi::c_int).offset(4 as ::core::ffi::c_int as isize), + 4 as ::core::ffi::c_int, + 1 as ::core::ffi::c_int, + ) == 0 + { + add( + (buf as *mut ::core::ffi::c_int).offset(5 as ::core::ffi::c_int as isize), + 5 as ::core::ffi::c_int, + 0 as ::core::ffi::c_int, + ); + } +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap index 66ae3f2987..89775c69ef 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap @@ -93,3 +93,77 @@ pub unsafe extern "C" fn nested_early_returns(mut x: ::core::ffi::c_int) -> ::co } return x; } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn conditional_operator( + sz: ::core::ffi::c_uint, + buf: *mut ::core::ffi::c_int, +) { + let mut x: ::core::ffi::c_int = 0 as ::core::ffi::c_int; + let mut y: ::core::ffi::c_int = 1 as ::core::ffi::c_int; + *if false { &raw mut y } else { &raw mut x } = 10 as ::core::ffi::c_int; + *(buf as *mut ::core::ffi::c_int).offset(2 as ::core::ffi::c_int as isize) = if true { + 2 as ::core::ffi::c_int + } else { + 3 as ::core::ffi::c_int + }; + *(buf as *mut ::core::ffi::c_int).offset(3 as ::core::ffi::c_int as isize) = if false { + 2 as ::core::ffi::c_int + } else { + 3 as ::core::ffi::c_int + }; +} +unsafe extern "C" fn id(mut i: ::core::ffi::c_int) -> ::core::ffi::c_int { + return i; +} +unsafe extern "C" fn add( + mut p: *mut ::core::ffi::c_int, + mut i: ::core::ffi::c_int, + mut r: ::core::ffi::c_int, +) -> ::core::ffi::c_int { + *p += i; + return r; +} +#[unsafe(no_mangle)] +pub unsafe extern "C" fn binary_conditional_operator( + sz: ::core::ffi::c_uint, + buf: *mut ::core::ffi::c_int, +) { + let ref mut c2rust_lvalue = id(0 as ::core::ffi::c_int); + *(buf as *mut ::core::ffi::c_int).offset(0 as ::core::ffi::c_int as isize) = + if *c2rust_lvalue != 0 { + *c2rust_lvalue + } else { + id(1 as ::core::ffi::c_int) + }; + let ref mut c2rust_lvalue_0 = id(2 as ::core::ffi::c_int); + *(buf as *mut ::core::ffi::c_int).offset(1 as ::core::ffi::c_int as isize) = + if *c2rust_lvalue_0 != 0 { + *c2rust_lvalue_0 + } else { + id(3 as ::core::ffi::c_int) + }; + if add( + (buf as *mut ::core::ffi::c_int).offset(2 as ::core::ffi::c_int as isize), + 2 as ::core::ffi::c_int, + 0 as ::core::ffi::c_int, + ) == 0 + { + add( + (buf as *mut ::core::ffi::c_int).offset(3 as ::core::ffi::c_int as isize), + 3 as ::core::ffi::c_int, + 0 as ::core::ffi::c_int, + ); + } + if add( + (buf as *mut ::core::ffi::c_int).offset(4 as ::core::ffi::c_int as isize), + 4 as ::core::ffi::c_int, + 1 as ::core::ffi::c_int, + ) == 0 + { + add( + (buf as *mut ::core::ffi::c_int).offset(5 as ::core::ffi::c_int as isize), + 5 as ::core::ffi::c_int, + 0 as ::core::ffi::c_int, + ); + } +} From 608ba443fda8e8b8371eba1db32021909188feec Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 30 Apr 2026 15:47:46 +0200 Subject: [PATCH 4/8] transpile: Don't use named reference for binary conditionals --- c2rust-transpile/src/translator/mod.rs | 43 ++++++++++++------- ...__transpile@conditions.c.2021.clang15.snap | 12 +++--- ...__transpile@conditions.c.2024.clang15.snap | 12 +++--- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index a86e745bdd..e6f9e09f41 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3341,10 +3341,12 @@ impl<'c> Translation<'c> { } BinaryConditional(ty, lhs, rhs) => { + let rhs = self.convert_expr(ctx, rhs, None)?; + if ctx.is_unused() { - let mut lhs = self.convert_condition(ctx, false, lhs)?; - let rhs = self.convert_expr(ctx, rhs, None)?; - lhs = lhs.merge_unsafe(rhs.is_unsafe()); + let lhs = self + .convert_condition(ctx, false, lhs)? + .merge_unsafe(rhs.is_unsafe()); Ok(lhs.and_then(|val| { WithStmts::new( @@ -3359,19 +3361,28 @@ impl<'c> Translation<'c> { ) })) } else { - self.name_reference_write_read(ctx, lhs)?.try_map( - |NamedReference { - rvalue: lhs_val, .. - }| { - let cond = self.match_bool(ctx, true, ty.ctype, lhs_val.clone())?; - let ite = mk().ifte_expr( - cond, - mk().block(vec![mk().expr_stmt(lhs_val)]), - Some(self.convert_expr(ctx, rhs, None)?.to_expr()), - ); - Ok(ite) - }, - ) + let lhs = self + .convert_expr(ctx.used(), lhs, None)? + .merge_unsafe(rhs.is_unsafe()); + let fresh_name = self.renamer.borrow_mut().fresh(); + + lhs.and_then_try(|lhs| { + let fresh_stmt = mk().local_stmt(Box::new(mk().local( + mk().ident_pat(&fresh_name), + None, + Some(lhs), + ))); + + let cond = + self.match_bool(ctx, true, ty.ctype, mk().ident_expr(&fresh_name))?; + let ite = mk().ifte_expr( + cond, + mk().block(vec![mk().expr_stmt(mk().ident_expr(&fresh_name))]), + Some(rhs.to_expr()), + ); + + Ok(WithStmts::new(vec![fresh_stmt], ite)) + }) } } diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2021.clang15.snap index 559f6aa6d7..b1baf9b891 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2021.clang15.snap @@ -128,17 +128,17 @@ pub unsafe extern "C" fn binary_conditional_operator( sz: ::core::ffi::c_uint, buf: *mut ::core::ffi::c_int, ) { - let ref mut c2rust_lvalue = id(0 as ::core::ffi::c_int); + let c2rust_fresh0 = id(0 as ::core::ffi::c_int); *(buf as *mut ::core::ffi::c_int).offset(0 as ::core::ffi::c_int as isize) = - if *c2rust_lvalue != 0 { - *c2rust_lvalue + if c2rust_fresh0 != 0 { + c2rust_fresh0 } else { id(1 as ::core::ffi::c_int) }; - let ref mut c2rust_lvalue_0 = id(2 as ::core::ffi::c_int); + let c2rust_fresh1 = id(2 as ::core::ffi::c_int); *(buf as *mut ::core::ffi::c_int).offset(1 as ::core::ffi::c_int as isize) = - if *c2rust_lvalue_0 != 0 { - *c2rust_lvalue_0 + if c2rust_fresh1 != 0 { + c2rust_fresh1 } else { id(3 as ::core::ffi::c_int) }; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap index 89775c69ef..16343532d5 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@conditions.c.2024.clang15.snap @@ -128,17 +128,17 @@ pub unsafe extern "C" fn binary_conditional_operator( sz: ::core::ffi::c_uint, buf: *mut ::core::ffi::c_int, ) { - let ref mut c2rust_lvalue = id(0 as ::core::ffi::c_int); + let c2rust_fresh0 = id(0 as ::core::ffi::c_int); *(buf as *mut ::core::ffi::c_int).offset(0 as ::core::ffi::c_int as isize) = - if *c2rust_lvalue != 0 { - *c2rust_lvalue + if c2rust_fresh0 != 0 { + c2rust_fresh0 } else { id(1 as ::core::ffi::c_int) }; - let ref mut c2rust_lvalue_0 = id(2 as ::core::ffi::c_int); + let c2rust_fresh1 = id(2 as ::core::ffi::c_int); *(buf as *mut ::core::ffi::c_int).offset(1 as ::core::ffi::c_int as isize) = - if *c2rust_lvalue_0 != 0 { - *c2rust_lvalue_0 + if c2rust_fresh1 != 0 { + c2rust_fresh1 } else { id(3 as ::core::ffi::c_int) }; From 39f4565b597c0b272a5a4a91e3b5a722fe4beb62 Mon Sep 17 00:00:00 2001 From: Rua Date: Wed, 6 May 2026 16:12:44 +0200 Subject: [PATCH 5/8] transpile: Add more side-effect snapshot tests to `exprs.c` --- c2rust-transpile/tests/snapshots/exprs.c | 37 ++++++++++++- ...shots__transpile@exprs.c.2021.clang15.snap | 55 +++++++++++++++++-- ...shots__transpile@exprs.c.2024.clang15.snap | 55 +++++++++++++++++-- 3 files changed, 132 insertions(+), 15 deletions(-) diff --git a/c2rust-transpile/tests/snapshots/exprs.c b/c2rust-transpile/tests/snapshots/exprs.c index 633e854f9f..7d7c283f3f 100644 --- a/c2rust-transpile/tests/snapshots/exprs.c +++ b/c2rust-transpile/tests/snapshots/exprs.c @@ -2,7 +2,13 @@ int puts(const char *str); static int side_effect(){ puts("the return of side effect"); - return 10; + return 0; +} + +static int* lvalue_side_effect(){ + puts("the return of side effect"); + static int VAL = 42; + return &VAL; } void unary_without_side_effect(){ @@ -20,18 +26,43 @@ void unary_without_side_effect(){ } void unary_with_side_effect(){ - char* arr[1] = {0}; + char *arr[1] = {0}; -side_effect(); +side_effect(); ~side_effect(); !side_effect(); &""[side_effect()]; - *arr[side_effect()]; +} + +void inc_decl_with_rvalue_side_effect() { + int arr[1] = {0}; + + // Increment/decrement, expression value not used ++arr[side_effect()]; --arr[side_effect()]; arr[side_effect()]++; arr[side_effect()]--; + + // Increment/decrement, expression value is used + int pre_inc = ++arr[side_effect()]; + int pre_dec = --arr[side_effect()]; + int post_inc = arr[side_effect()]++; + int post_dec = arr[side_effect()]--; +} + +void inc_decl_with_lvalue_side_effect() { + // Increment/decrement, expression value not used + ++*lvalue_side_effect(); + --*lvalue_side_effect(); + (*lvalue_side_effect())++; + (*lvalue_side_effect())--; + + // Increment/decrement, expression value is used + int pre_inc = ++*lvalue_side_effect(); + int pre_dec = --*lvalue_side_effect(); + int post_inc = (*lvalue_side_effect())++; + int post_dec = (*lvalue_side_effect())--; } void unsigned_compound_desugaring(void) { diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap index 56ee5f78bf..a98a872f34 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap @@ -24,7 +24,12 @@ pub const B: C2Rust_Unnamed = 1; pub const A: C2Rust_Unnamed = 0; unsafe extern "C" fn side_effect() -> ::core::ffi::c_int { puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char); - return 10 as ::core::ffi::c_int; + return 0 as ::core::ffi::c_int; +} +unsafe extern "C" fn lvalue_side_effect() -> *mut ::core::ffi::c_int { + puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char); + static mut VAL: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + return &raw mut VAL; } #[no_mangle] pub unsafe extern "C" fn unary_without_side_effect() { @@ -49,11 +54,49 @@ pub unsafe extern "C" fn unary_with_side_effect() { (side_effect() == 0) as ::core::ffi::c_int; (b"\0".as_ptr() as *const ::core::ffi::c_char).offset(side_effect() as isize) as *const ::core::ffi::c_char; - *arr[side_effect() as usize]; - arr[side_effect() as usize] = arr[side_effect() as usize].offset(1); - arr[side_effect() as usize] = arr[side_effect() as usize].offset(-1); - arr[side_effect() as usize] = arr[side_effect() as usize].offset(1); - arr[side_effect() as usize] = arr[side_effect() as usize].offset(-1); +} +#[no_mangle] +pub unsafe extern "C" fn inc_decl_with_rvalue_side_effect() { + let mut arr: [::core::ffi::c_int; 1] = [0 as ::core::ffi::c_int]; + arr[side_effect() as usize] += 1; + arr[side_effect() as usize] -= 1; + arr[side_effect() as usize] += 1; + arr[side_effect() as usize] -= 1; + arr[side_effect() as usize] += 1; + let mut pre_inc: ::core::ffi::c_int = arr[side_effect() as usize]; + arr[side_effect() as usize] -= 1; + let mut pre_dec: ::core::ffi::c_int = arr[side_effect() as usize]; + let c2rust_fresh0 = arr[side_effect() as usize]; + arr[side_effect() as usize] = arr[side_effect() as usize] + 1; + let mut post_inc: ::core::ffi::c_int = c2rust_fresh0; + let c2rust_fresh1 = arr[side_effect() as usize]; + arr[side_effect() as usize] = arr[side_effect() as usize] - 1; + let mut post_dec: ::core::ffi::c_int = c2rust_fresh1; +} +#[no_mangle] +pub unsafe extern "C" fn inc_decl_with_lvalue_side_effect() { + let ref mut c2rust_lvalue = *lvalue_side_effect(); + *c2rust_lvalue += 1; + let ref mut c2rust_lvalue_0 = *lvalue_side_effect(); + *c2rust_lvalue_0 -= 1; + let ref mut c2rust_lvalue_1 = *lvalue_side_effect(); + *c2rust_lvalue_1 += 1; + let ref mut c2rust_lvalue_2 = *lvalue_side_effect(); + *c2rust_lvalue_2 -= 1; + let ref mut c2rust_lvalue_3 = *lvalue_side_effect(); + *c2rust_lvalue_3 += 1; + let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue_3; + let ref mut c2rust_lvalue_4 = *lvalue_side_effect(); + *c2rust_lvalue_4 -= 1; + let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_4; + let ref mut c2rust_lvalue_5 = *lvalue_side_effect(); + let c2rust_fresh2 = *c2rust_lvalue_5; + *c2rust_lvalue_5 = *c2rust_lvalue_5 + 1; + let mut post_inc: ::core::ffi::c_int = c2rust_fresh2; + let ref mut c2rust_lvalue_6 = *lvalue_side_effect(); + let c2rust_fresh3 = *c2rust_lvalue_6; + *c2rust_lvalue_6 = *c2rust_lvalue_6 - 1; + let mut post_dec: ::core::ffi::c_int = c2rust_fresh3; } #[no_mangle] pub unsafe extern "C" fn unsigned_compound_desugaring() { diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap index 04e6019c9c..964a5518fa 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap @@ -24,7 +24,12 @@ pub const B: C2Rust_Unnamed = 1; pub const A: C2Rust_Unnamed = 0; unsafe extern "C" fn side_effect() -> ::core::ffi::c_int { puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char); - return 10 as ::core::ffi::c_int; + return 0 as ::core::ffi::c_int; +} +unsafe extern "C" fn lvalue_side_effect() -> *mut ::core::ffi::c_int { + puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char); + static mut VAL: ::core::ffi::c_int = 42 as ::core::ffi::c_int; + return &raw mut VAL; } #[unsafe(no_mangle)] pub unsafe extern "C" fn unary_without_side_effect() { @@ -49,11 +54,49 @@ pub unsafe extern "C" fn unary_with_side_effect() { (side_effect() == 0) as ::core::ffi::c_int; (b"\0".as_ptr() as *const ::core::ffi::c_char).offset(side_effect() as isize) as *const ::core::ffi::c_char; - *arr[side_effect() as usize]; - arr[side_effect() as usize] = arr[side_effect() as usize].offset(1); - arr[side_effect() as usize] = arr[side_effect() as usize].offset(-1); - arr[side_effect() as usize] = arr[side_effect() as usize].offset(1); - arr[side_effect() as usize] = arr[side_effect() as usize].offset(-1); +} +#[unsafe(no_mangle)] +pub unsafe extern "C" fn inc_decl_with_rvalue_side_effect() { + let mut arr: [::core::ffi::c_int; 1] = [0 as ::core::ffi::c_int]; + arr[side_effect() as usize] += 1; + arr[side_effect() as usize] -= 1; + arr[side_effect() as usize] += 1; + arr[side_effect() as usize] -= 1; + arr[side_effect() as usize] += 1; + let mut pre_inc: ::core::ffi::c_int = arr[side_effect() as usize]; + arr[side_effect() as usize] -= 1; + let mut pre_dec: ::core::ffi::c_int = arr[side_effect() as usize]; + let c2rust_fresh0 = arr[side_effect() as usize]; + arr[side_effect() as usize] = arr[side_effect() as usize] + 1; + let mut post_inc: ::core::ffi::c_int = c2rust_fresh0; + let c2rust_fresh1 = arr[side_effect() as usize]; + arr[side_effect() as usize] = arr[side_effect() as usize] - 1; + let mut post_dec: ::core::ffi::c_int = c2rust_fresh1; +} +#[unsafe(no_mangle)] +pub unsafe extern "C" fn inc_decl_with_lvalue_side_effect() { + let ref mut c2rust_lvalue = *lvalue_side_effect(); + *c2rust_lvalue += 1; + let ref mut c2rust_lvalue_0 = *lvalue_side_effect(); + *c2rust_lvalue_0 -= 1; + let ref mut c2rust_lvalue_1 = *lvalue_side_effect(); + *c2rust_lvalue_1 += 1; + let ref mut c2rust_lvalue_2 = *lvalue_side_effect(); + *c2rust_lvalue_2 -= 1; + let ref mut c2rust_lvalue_3 = *lvalue_side_effect(); + *c2rust_lvalue_3 += 1; + let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue_3; + let ref mut c2rust_lvalue_4 = *lvalue_side_effect(); + *c2rust_lvalue_4 -= 1; + let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_4; + let ref mut c2rust_lvalue_5 = *lvalue_side_effect(); + let c2rust_fresh2 = *c2rust_lvalue_5; + *c2rust_lvalue_5 = *c2rust_lvalue_5 + 1; + let mut post_inc: ::core::ffi::c_int = c2rust_fresh2; + let ref mut c2rust_lvalue_6 = *lvalue_side_effect(); + let c2rust_fresh3 = *c2rust_lvalue_6; + *c2rust_lvalue_6 = *c2rust_lvalue_6 - 1; + let mut post_dec: ::core::ffi::c_int = c2rust_fresh3; } #[unsafe(no_mangle)] pub unsafe extern "C" fn unsigned_compound_desugaring() { From adc576d46e3fbfbf03512540a7faf4a9ccfc27dc Mon Sep 17 00:00:00 2001 From: Rua Date: Wed, 6 May 2026 16:49:03 +0200 Subject: [PATCH 6/8] transpile: Correct uses of `used` in `operators.rs` --- c2rust-transpile/src/translator/operators.rs | 21 ++++++++++----- ...shots__transpile@exprs.c.2021.clang15.snap | 26 ++++++++----------- ...shots__transpile@exprs.c.2024.clang15.snap | 26 ++++++++----------- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/c2rust-transpile/src/translator/operators.rs b/c2rust-transpile/src/translator/operators.rs index a03f240ffe..c45327d4f5 100644 --- a/c2rust-transpile/src/translator/operators.rs +++ b/c2rust-transpile/src/translator/operators.rs @@ -212,7 +212,7 @@ impl<'c> Translation<'c> { ))) } else { let lhs = self.convert_cast( - ctx, + ctx.used(), initial_lhs_type_id, compute_lhs_type_id, WithStmts::new_val(read.clone()), @@ -234,8 +234,15 @@ impl<'c> Translation<'c> { ) })?; - let val = - self.convert_cast(ctx, compute_res_type_id, lhs_type_id, val, None, None, None)?; + let val = self.convert_cast( + ctx.used(), + compute_res_type_id, + lhs_type_id, + val, + None, + None, + None, + )?; Ok(val.map(|val| mk().assign_expr(write.clone(), val))) } @@ -424,7 +431,7 @@ impl<'c> Translation<'c> { .expect("Cannot convert non-assignment operator"); let lhs = self.convert_cast( - ctx, + ctx.used(), initial_lhs_type_id, expr_or_comp_type_id, WithStmts::new_val(read.clone()), @@ -447,7 +454,7 @@ impl<'c> Translation<'c> { )?; let val = self.convert_cast( - ctx, + ctx.used(), result_type_id, expr_type_id, val, @@ -650,7 +657,7 @@ impl<'c> Translation<'c> { }; self.convert_assignment_operator_with_rhs( - ctx.used(), + ctx, op, ty, arg, @@ -789,7 +796,7 @@ impl<'c> Translation<'c> { .map(|a| mk().unary_expr(UnOp::Not(Default::default()), a))), CUnOp::Not => { - let val = self.convert_condition(ctx, false, arg)?; + let val = self.convert_condition(ctx.used(), false, arg)?; Ok(val.map(|x| mk().cast_expr(x, mk().abs_path_ty(vec!["core", "ffi", "c_int"])))) } CUnOp::Extension => { diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap index a98a872f34..4b18761814 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap @@ -75,27 +75,23 @@ pub unsafe extern "C" fn inc_decl_with_rvalue_side_effect() { } #[no_mangle] pub unsafe extern "C" fn inc_decl_with_lvalue_side_effect() { + *lvalue_side_effect() += 1; + *lvalue_side_effect() -= 1; + *lvalue_side_effect() += 1; + *lvalue_side_effect() -= 1; let ref mut c2rust_lvalue = *lvalue_side_effect(); *c2rust_lvalue += 1; + let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue; let ref mut c2rust_lvalue_0 = *lvalue_side_effect(); *c2rust_lvalue_0 -= 1; + let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_0; let ref mut c2rust_lvalue_1 = *lvalue_side_effect(); - *c2rust_lvalue_1 += 1; - let ref mut c2rust_lvalue_2 = *lvalue_side_effect(); - *c2rust_lvalue_2 -= 1; - let ref mut c2rust_lvalue_3 = *lvalue_side_effect(); - *c2rust_lvalue_3 += 1; - let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue_3; - let ref mut c2rust_lvalue_4 = *lvalue_side_effect(); - *c2rust_lvalue_4 -= 1; - let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_4; - let ref mut c2rust_lvalue_5 = *lvalue_side_effect(); - let c2rust_fresh2 = *c2rust_lvalue_5; - *c2rust_lvalue_5 = *c2rust_lvalue_5 + 1; + let c2rust_fresh2 = *c2rust_lvalue_1; + *c2rust_lvalue_1 = *c2rust_lvalue_1 + 1; let mut post_inc: ::core::ffi::c_int = c2rust_fresh2; - let ref mut c2rust_lvalue_6 = *lvalue_side_effect(); - let c2rust_fresh3 = *c2rust_lvalue_6; - *c2rust_lvalue_6 = *c2rust_lvalue_6 - 1; + let ref mut c2rust_lvalue_2 = *lvalue_side_effect(); + let c2rust_fresh3 = *c2rust_lvalue_2; + *c2rust_lvalue_2 = *c2rust_lvalue_2 - 1; let mut post_dec: ::core::ffi::c_int = c2rust_fresh3; } #[no_mangle] diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap index 964a5518fa..39fcf00b6d 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap @@ -75,27 +75,23 @@ pub unsafe extern "C" fn inc_decl_with_rvalue_side_effect() { } #[unsafe(no_mangle)] pub unsafe extern "C" fn inc_decl_with_lvalue_side_effect() { + *lvalue_side_effect() += 1; + *lvalue_side_effect() -= 1; + *lvalue_side_effect() += 1; + *lvalue_side_effect() -= 1; let ref mut c2rust_lvalue = *lvalue_side_effect(); *c2rust_lvalue += 1; + let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue; let ref mut c2rust_lvalue_0 = *lvalue_side_effect(); *c2rust_lvalue_0 -= 1; + let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_0; let ref mut c2rust_lvalue_1 = *lvalue_side_effect(); - *c2rust_lvalue_1 += 1; - let ref mut c2rust_lvalue_2 = *lvalue_side_effect(); - *c2rust_lvalue_2 -= 1; - let ref mut c2rust_lvalue_3 = *lvalue_side_effect(); - *c2rust_lvalue_3 += 1; - let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue_3; - let ref mut c2rust_lvalue_4 = *lvalue_side_effect(); - *c2rust_lvalue_4 -= 1; - let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_4; - let ref mut c2rust_lvalue_5 = *lvalue_side_effect(); - let c2rust_fresh2 = *c2rust_lvalue_5; - *c2rust_lvalue_5 = *c2rust_lvalue_5 + 1; + let c2rust_fresh2 = *c2rust_lvalue_1; + *c2rust_lvalue_1 = *c2rust_lvalue_1 + 1; let mut post_inc: ::core::ffi::c_int = c2rust_fresh2; - let ref mut c2rust_lvalue_6 = *lvalue_side_effect(); - let c2rust_fresh3 = *c2rust_lvalue_6; - *c2rust_lvalue_6 = *c2rust_lvalue_6 - 1; + let ref mut c2rust_lvalue_2 = *lvalue_side_effect(); + let c2rust_fresh3 = *c2rust_lvalue_2; + *c2rust_lvalue_2 = *c2rust_lvalue_2 - 1; let mut post_dec: ::core::ffi::c_int = c2rust_fresh3; } #[unsafe(no_mangle)] From afa06c4a225c7e584993c39b0896d850826f6a97 Mon Sep 17 00:00:00 2001 From: Rua Date: Wed, 6 May 2026 16:56:37 +0200 Subject: [PATCH 7/8] transpile: Use raw pointers for lvalues with side effects --- c2rust-transpile/src/translator/named_references.rs | 7 ++++--- .../snapshots__transpile@exprs.c.2021.clang15.snap | 8 ++++---- .../snapshots__transpile@exprs.c.2024.clang15.snap | 8 ++++---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/c2rust-transpile/src/translator/named_references.rs b/c2rust-transpile/src/translator/named_references.rs index 98c5ba4f01..9282832244 100644 --- a/c2rust-transpile/src/translator/named_references.rs +++ b/c2rust-transpile/src/translator/named_references.rs @@ -124,11 +124,12 @@ impl<'c> Translation<'c> { let ptr_name = self.renamer.borrow_mut().pick_name("c2rust_lvalue"); - // let ref mut p = lhs; + // let p = &raw mut lhs; + self.use_feature("raw_ref_op"); let compute_ref = mk().local_stmt(Box::new(mk().local( - mk().mutbl().ident_ref_pat(&ptr_name), + mk().ident_pat(&ptr_name), None, - Some(reference), + Some(mk().mutbl().raw_borrow_expr(reference)), ))); let write = diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap index 4b18761814..e3068dc0ac 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap @@ -79,17 +79,17 @@ pub unsafe extern "C" fn inc_decl_with_lvalue_side_effect() { *lvalue_side_effect() -= 1; *lvalue_side_effect() += 1; *lvalue_side_effect() -= 1; - let ref mut c2rust_lvalue = *lvalue_side_effect(); + let c2rust_lvalue = &raw mut *lvalue_side_effect(); *c2rust_lvalue += 1; let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue; - let ref mut c2rust_lvalue_0 = *lvalue_side_effect(); + let c2rust_lvalue_0 = &raw mut *lvalue_side_effect(); *c2rust_lvalue_0 -= 1; let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_0; - let ref mut c2rust_lvalue_1 = *lvalue_side_effect(); + let c2rust_lvalue_1 = &raw mut *lvalue_side_effect(); let c2rust_fresh2 = *c2rust_lvalue_1; *c2rust_lvalue_1 = *c2rust_lvalue_1 + 1; let mut post_inc: ::core::ffi::c_int = c2rust_fresh2; - let ref mut c2rust_lvalue_2 = *lvalue_side_effect(); + let c2rust_lvalue_2 = &raw mut *lvalue_side_effect(); let c2rust_fresh3 = *c2rust_lvalue_2; *c2rust_lvalue_2 = *c2rust_lvalue_2 - 1; let mut post_dec: ::core::ffi::c_int = c2rust_fresh3; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap index 39fcf00b6d..762005b6fa 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap @@ -79,17 +79,17 @@ pub unsafe extern "C" fn inc_decl_with_lvalue_side_effect() { *lvalue_side_effect() -= 1; *lvalue_side_effect() += 1; *lvalue_side_effect() -= 1; - let ref mut c2rust_lvalue = *lvalue_side_effect(); + let c2rust_lvalue = &raw mut *lvalue_side_effect(); *c2rust_lvalue += 1; let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue; - let ref mut c2rust_lvalue_0 = *lvalue_side_effect(); + let c2rust_lvalue_0 = &raw mut *lvalue_side_effect(); *c2rust_lvalue_0 -= 1; let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_0; - let ref mut c2rust_lvalue_1 = *lvalue_side_effect(); + let c2rust_lvalue_1 = &raw mut *lvalue_side_effect(); let c2rust_fresh2 = *c2rust_lvalue_1; *c2rust_lvalue_1 = *c2rust_lvalue_1 + 1; let mut post_inc: ::core::ffi::c_int = c2rust_fresh2; - let ref mut c2rust_lvalue_2 = *lvalue_side_effect(); + let c2rust_lvalue_2 = &raw mut *lvalue_side_effect(); let c2rust_fresh3 = *c2rust_lvalue_2; *c2rust_lvalue_2 = *c2rust_lvalue_2 - 1; let mut post_dec: ::core::ffi::c_int = c2rust_fresh3; From e88c08c315cbf3dfb4e74f0c6368eec8bc7decac Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 16 May 2026 21:05:43 +0200 Subject: [PATCH 8/8] transpile: In `name_reference`, also check expression for side effects --- c2rust-transpile/src/translator/mod.rs | 10 +++---- .../src/translator/named_references.rs | 29 ++++--------------- ...shots__transpile@exprs.c.2021.clang15.snap | 20 ++++++++----- ...shots__transpile@exprs.c.2024.clang15.snap | 20 ++++++++----- 4 files changed, 35 insertions(+), 44 deletions(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index e6f9e09f41..7fbb4b71d2 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -18,11 +18,11 @@ use proc_macro2::{Punct, Spacing::*, Span, TokenStream, TokenTree}; use syn::spanned::Spanned as _; use syn::{ AttrStyle, BareVariadic, BinOp, Block, Expr, ExprBinary, ExprBlock, ExprBreak, ExprCast, - ExprField, ExprIndex, ExprParen, ExprReturn, ExprUnary, FnArg, ForeignItem, ForeignItemFn, - ForeignItemMacro, ForeignItemStatic, ForeignItemType, Ident, Item, ItemConst, ItemEnum, - ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod, ItemStatic, ItemStruct, - ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Lit, MacroDelimiter, PathSegment, - ReturnType, Stmt, Type, TypeTuple, UnOp, UseTree, Visibility, + ExprParen, ExprReturn, ExprUnary, FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, + ForeignItemStatic, ForeignItemType, Ident, Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn, + ItemForeignMod, ItemImpl, ItemMacro, ItemMod, ItemStatic, ItemStruct, ItemTrait, + ItemTraitAlias, ItemType, ItemUnion, ItemUse, Lit, MacroDelimiter, PathSegment, ReturnType, + Stmt, Type, TypeTuple, UnOp, UseTree, Visibility, }; use crate::diagnostics::TranslationResult; diff --git a/c2rust-transpile/src/translator/named_references.rs b/c2rust-transpile/src/translator/named_references.rs index 9282832244..f736c4c806 100644 --- a/c2rust-transpile/src/translator/named_references.rs +++ b/c2rust-transpile/src/translator/named_references.rs @@ -18,22 +18,6 @@ fn is_lvalue(e: &Expr) -> bool { ) } -/// Check if something is a side-effect free Rust lvalue. -fn is_simple_lvalue(e: &Expr) -> bool { - use Expr::*; - match *unparen(e) { - Path(..) => true, - Unary(ExprUnary { - op: syn::UnOp::Deref(_), - ref expr, - .. - }) - | Field(ExprField { base: ref expr, .. }) - | Index(ExprIndex { ref expr, .. }) => is_simple_lvalue(expr), - _ => false, - } -} - pub struct NamedReference { pub lvalue: Box, pub rvalue: R, @@ -106,18 +90,17 @@ impl<'c> Translation<'c> { .kind .get_qual_type() .ok_or_else(|| format_err!("bad reference type"))?; + + let is_pure = self.ast_context.is_expr_pure(reference); let read = |write| self.read(reference_ty, write); let reference = self.convert_expr(ctx.used(), reference, Some(reference_ty))?; reference.and_then_try(|reference| { - if !uses_read && is_lvalue(&reference) { + if is_lvalue(&reference) && (is_pure || !uses_read) { + let rvalue = uses_read.then(|| read(reference.clone())).transpose()?; + Ok(WithStmts::new_val(NamedReference { lvalue: reference, - rvalue: None, - })) - } else if is_simple_lvalue(&reference) { - Ok(WithStmts::new_val(NamedReference { - lvalue: reference.clone(), - rvalue: Some(read(reference)?), + rvalue, })) } else { // This is the case where we explicitly need to factor out possible side-effects. diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap index e3068dc0ac..c939f6b488 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap @@ -62,15 +62,19 @@ pub unsafe extern "C" fn inc_decl_with_rvalue_side_effect() { arr[side_effect() as usize] -= 1; arr[side_effect() as usize] += 1; arr[side_effect() as usize] -= 1; - arr[side_effect() as usize] += 1; - let mut pre_inc: ::core::ffi::c_int = arr[side_effect() as usize]; - arr[side_effect() as usize] -= 1; - let mut pre_dec: ::core::ffi::c_int = arr[side_effect() as usize]; - let c2rust_fresh0 = arr[side_effect() as usize]; - arr[side_effect() as usize] = arr[side_effect() as usize] + 1; + let c2rust_lvalue = &raw mut arr[side_effect() as usize]; + *c2rust_lvalue += 1; + let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue; + let c2rust_lvalue_0 = &raw mut arr[side_effect() as usize]; + *c2rust_lvalue_0 -= 1; + let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_0; + let c2rust_lvalue_1 = &raw mut arr[side_effect() as usize]; + let c2rust_fresh0 = *c2rust_lvalue_1; + *c2rust_lvalue_1 = *c2rust_lvalue_1 + 1; let mut post_inc: ::core::ffi::c_int = c2rust_fresh0; - let c2rust_fresh1 = arr[side_effect() as usize]; - arr[side_effect() as usize] = arr[side_effect() as usize] - 1; + let c2rust_lvalue_2 = &raw mut arr[side_effect() as usize]; + let c2rust_fresh1 = *c2rust_lvalue_2; + *c2rust_lvalue_2 = *c2rust_lvalue_2 - 1; let mut post_dec: ::core::ffi::c_int = c2rust_fresh1; } #[no_mangle] diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap index 762005b6fa..558091a5dd 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap @@ -62,15 +62,19 @@ pub unsafe extern "C" fn inc_decl_with_rvalue_side_effect() { arr[side_effect() as usize] -= 1; arr[side_effect() as usize] += 1; arr[side_effect() as usize] -= 1; - arr[side_effect() as usize] += 1; - let mut pre_inc: ::core::ffi::c_int = arr[side_effect() as usize]; - arr[side_effect() as usize] -= 1; - let mut pre_dec: ::core::ffi::c_int = arr[side_effect() as usize]; - let c2rust_fresh0 = arr[side_effect() as usize]; - arr[side_effect() as usize] = arr[side_effect() as usize] + 1; + let c2rust_lvalue = &raw mut arr[side_effect() as usize]; + *c2rust_lvalue += 1; + let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue; + let c2rust_lvalue_0 = &raw mut arr[side_effect() as usize]; + *c2rust_lvalue_0 -= 1; + let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_0; + let c2rust_lvalue_1 = &raw mut arr[side_effect() as usize]; + let c2rust_fresh0 = *c2rust_lvalue_1; + *c2rust_lvalue_1 = *c2rust_lvalue_1 + 1; let mut post_inc: ::core::ffi::c_int = c2rust_fresh0; - let c2rust_fresh1 = arr[side_effect() as usize]; - arr[side_effect() as usize] = arr[side_effect() as usize] - 1; + let c2rust_lvalue_2 = &raw mut arr[side_effect() as usize]; + let c2rust_fresh1 = *c2rust_lvalue_2; + *c2rust_lvalue_2 = *c2rust_lvalue_2 - 1; let mut post_dec: ::core::ffi::c_int = c2rust_fresh1; } #[unsafe(no_mangle)]