diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 936b89bfac..da92ccfea8 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 dd910a1b72..589ee3d201 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 b08ad85741..4500beed2b 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 @@ -61,15 +61,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_ptr = &raw mut arr[side_effect() as usize]; + *c2rust_lvalue_ptr += 1; + let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue_ptr; + let c2rust_lvalue_ptr_0 = &raw mut arr[side_effect() as usize]; + *c2rust_lvalue_ptr_0 -= 1; + let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_ptr_0; + let c2rust_lvalue_ptr_1 = &raw mut arr[side_effect() as usize]; + let c2rust_fresh0 = *c2rust_lvalue_ptr_1; + *c2rust_lvalue_ptr_1 = *c2rust_lvalue_ptr_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_ptr_2 = &raw mut arr[side_effect() as usize]; + let c2rust_fresh1 = *c2rust_lvalue_ptr_2; + *c2rust_lvalue_ptr_2 = *c2rust_lvalue_ptr_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 a07f19747f..22a7657f1f 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 @@ -61,15 +61,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_ptr = &raw mut arr[side_effect() as usize]; + *c2rust_lvalue_ptr += 1; + let mut pre_inc: ::core::ffi::c_int = *c2rust_lvalue_ptr; + let c2rust_lvalue_ptr_0 = &raw mut arr[side_effect() as usize]; + *c2rust_lvalue_ptr_0 -= 1; + let mut pre_dec: ::core::ffi::c_int = *c2rust_lvalue_ptr_0; + let c2rust_lvalue_ptr_1 = &raw mut arr[side_effect() as usize]; + let c2rust_fresh0 = *c2rust_lvalue_ptr_1; + *c2rust_lvalue_ptr_1 = *c2rust_lvalue_ptr_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_ptr_2 = &raw mut arr[side_effect() as usize]; + let c2rust_fresh1 = *c2rust_lvalue_ptr_2; + *c2rust_lvalue_ptr_2 = *c2rust_lvalue_ptr_2 - 1; let mut post_dec: ::core::ffi::c_int = c2rust_fresh1; } #[unsafe(no_mangle)]