From 3957f30befb61c01958ede6094d806546b970627 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 30 Apr 2026 15:29:17 +0100 Subject: [PATCH 1/8] Add void_cast test --- tests/unit/void_cast.cpp | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 tests/unit/void_cast.cpp diff --git a/tests/unit/void_cast.cpp b/tests/unit/void_cast.cpp new file mode 100644 index 00000000..1362312e --- /dev/null +++ b/tests/unit/void_cast.cpp @@ -0,0 +1,74 @@ +#include + +void unused_param(int x) { (void)x; } + +int side_effect_counter = 0; +int bump_and_return() { + ++side_effect_counter; + return side_effect_counter; +} + +struct Holder { + int field; +}; + +int main() { + unused_param(42); + + int y = 5; + (void)y; + + int z = ((void)y, 7); + assert(z == 7); + + int counter = 0; + int w = ((void)counter, counter = 3, counter); + assert(w == 3); + assert(counter == 3); + + (void)bump_and_return(); + assert(side_effect_counter == 1); + + int v = ((void)bump_and_return(), 99); + assert(side_effect_counter == 2); + assert(v == 99); + + (void)0; + (void)(0); + + (void)(y); + + ((void)0); + ((void)(y)); + + int err = 0; + ((void)(err = 42)); + assert(err == 42); + + int chosen = ((void)(err = 7), 123); + assert(err == 7); + assert(chosen == 123); + + (void)bump_and_return; + assert(side_effect_counter == 2); + + (void)(&bump_and_return); + assert(side_effect_counter == 2); + + (void)(static_cast(&bump_and_return)); + assert(side_effect_counter == 2); + + int storage = 11; + int *p = &storage; + (void)(*p); + + int arr[] = {1, 2, 3}; + (void)(arr[1]); + + Holder h{17}; + (void)(h.field); + Holder *hp = &h; + (void)(hp->field); + + return 0; +} From 697f71a830872198e4dddd00c5a8dc8a06f58541 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 30 Apr 2026 15:30:47 +0100 Subject: [PATCH 2/8] Propagate ExprKind::Void downstream on void cast --- cpp2rust/converter/converter.cpp | 31 +++++++++++++++++-- cpp2rust/converter/converter.h | 2 ++ .../converter/models/converter_refcount.cpp | 1 + 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index ec3fca19..4e1a6afe 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1865,10 +1865,21 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { return false; } +void Converter::ConvertVoidCastExpr(clang::ExplicitCastExpr *expr) { + PushExprKind push(*this, ExprKind::Void); + StrCat("let _ = "); + Convert(expr->getSubExpr()); + if (expr->getSubExpr()->isLValue()) { + StrCat(".clone()"); + } + StrCat(token::kSemiColon); +} + bool Converter::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { auto type = expr->getTypeAsWritten(); auto *sub_expr = expr->getSubExpr(); if (type->isVoidType()) { + ConvertVoidCastExpr(expr); return false; } switch (expr->getStmtClass()) { @@ -1950,7 +1961,10 @@ bool Converter::VisitBinaryOperator(clang::BinaryOperator *expr) { ConvertCast(lhs_type); } } else if (expr->isCommaOp()) { - Convert(lhs); + { + PushExprKind push(*this, ExprKind::Void); + Convert(lhs); + } StrCat(token::kSemiColon); Convert(rhs); } else if (IsUnsignedArithOp(expr)) { @@ -2248,11 +2262,22 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { } bool Converter::VisitParenExpr(clang::ParenExpr *expr) { + // Comma operator becomes (A, B, C) -> { A; B; C } + auto *bin = clang::dyn_cast(expr->getSubExpr()); + // Void cast becomes ((void) A) -> { let _ = A; } + auto *cast = clang::dyn_cast(expr->getSubExpr()); + if ((bin && bin->isCommaOp()) || + (cast && cast->getTypeAsWritten()->isVoidType())) { + PushBrace push(*this); + Convert(expr->getSubExpr()); + return false; + } + // Add cast to avoid ambigous integers. Don't add cast if sub expression is a // pointer dereference because we might want to mutate the dereferenced value. bool should_add_integral_cast = expr->getType()->isIntegralOrEnumerationType() && !isAddrOf() && - !clang::isa(expr->getSubExpr()); + !isVoid() && !clang::isa(expr->getSubExpr()); PushParen outer(*this, should_add_integral_cast); { @@ -3399,7 +3424,7 @@ void Converter::ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *op, void Converter::ConvertAddrOf(clang::Expr *expr, clang::QualType pointer_type) { assert(pointer_type->isPointerType()); - if (IsReferenceType(expr)) { + if (IsReferenceType(expr) || pointer_type->isFunctionPointerType()) { PushExprKind push(*this, ExprKind::AddrOf); Convert(expr); } else { diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 02d5f6f2..bf9a70fd 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -240,6 +240,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitImplicitCastExpr(clang::ImplicitCastExpr *expr); + void ConvertVoidCastExpr(clang::ExplicitCastExpr *expr); + virtual bool VisitExplicitCastExpr(clang::ExplicitCastExpr *expr); virtual bool VisitBinaryOperator(clang::BinaryOperator *expr); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 11e275ed..8a5a5ac3 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1128,6 +1128,7 @@ bool ConverterRefCount::VisitFunctionPointerCast( bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { if (expr->getTypeAsWritten()->isVoidType()) { + ConvertVoidCastExpr(expr); return false; } switch (expr->getStmtClass()) { From d725a50e460b229e73a28b86d059a7981309c077 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 30 Apr 2026 15:31:12 +0100 Subject: [PATCH 3/8] Update tests --- tests/unit/out/refcount/bool_printing.rs | 4 +- tests/unit/out/refcount/continue.rs | 4 +- .../out/refcount/reinterpret_cast_oob_read.rs | 1 + .../refcount/reinterpret_cast_undersize.rs | 1 + tests/unit/out/refcount/string_escape.rs | 4 +- tests/unit/out/refcount/va_arg_printf.rs | 1 + tests/unit/out/refcount/void_cast.rs | 102 ++++++++++++++++++ tests/unit/out/unsafe/bool_printing.rs | 4 +- tests/unit/out/unsafe/continue.rs | 4 +- .../out/unsafe/reinterpret_cast_oob_read.rs | 1 + .../out/unsafe/reinterpret_cast_undersize.rs | 1 + tests/unit/out/unsafe/string_escape.rs | 4 +- tests/unit/out/unsafe/va_arg_printf.rs | 1 + tests/unit/out/unsafe/void_cast.rs | 93 ++++++++++++++++ 14 files changed, 213 insertions(+), 12 deletions(-) create mode 100644 tests/unit/out/refcount/void_cast.rs create mode 100644 tests/unit/out/unsafe/void_cast.rs diff --git a/tests/unit/out/refcount/bool_printing.rs b/tests/unit/out/refcount/bool_printing.rs index dcf2cf70..757575d4 100644 --- a/tests/unit/out/refcount/bool_printing.rs +++ b/tests/unit/out/refcount/bool_printing.rs @@ -23,12 +23,12 @@ fn main_0() -> i32 { write!( libcc2rs::cout(), "{:}\n", - ((((*i1.borrow()) != (*i2.borrow())) as bool) as u8), + (((*i1.borrow()) != (*i2.borrow())) as u8), ); write!( libcc2rs::cout(), "{:}\n", - ((((*i1.borrow()) == (*i2.borrow())) as bool) as u8), + (((*i1.borrow()) == (*i2.borrow())) as u8), ); write!(libcc2rs::cout(), "{:}\n", (({ foo_0() }) as u8),); write!(libcc2rs::cout(), "{:}\n", (({ bar_1() }) as u8),); diff --git a/tests/unit/out/refcount/continue.rs b/tests/unit/out/refcount/continue.rs index 593780e3..50c33632 100644 --- a/tests/unit/out/refcount/continue.rs +++ b/tests/unit/out/refcount/continue.rs @@ -35,14 +35,14 @@ fn main_0() -> i32 { 'loop_: while ((*k2.borrow()) < 5) { let k3: Value = Rc::new(RefCell::new(0)); 'loop_: while ((*k3.borrow()) < 5) { - if ((((((*k1.borrow()) + (*k2.borrow())) + (*k3.borrow())) as i32) % 2) == 0) { + if (((((*k1.borrow()) + (*k2.borrow())) + (*k3.borrow())) % 2) == 0) { (*k3.borrow_mut()).postfix_inc(); continue 'loop_; } (*out.borrow_mut()).prefix_inc(); (*k3.borrow_mut()).postfix_inc(); } - if (((((*k1.borrow()) + (*k2.borrow())) as i32) % 2) == 0) { + if ((((*k1.borrow()) + (*k2.borrow())) % 2) == 0) { (*k2.borrow_mut()).postfix_inc(); continue 'loop_; } diff --git a/tests/unit/out/refcount/reinterpret_cast_oob_read.rs b/tests/unit/out/refcount/reinterpret_cast_oob_read.rs index de214de2..d45fe96f 100644 --- a/tests/unit/out/refcount/reinterpret_cast_oob_read.rs +++ b/tests/unit/out/refcount/reinterpret_cast_oob_read.rs @@ -15,5 +15,6 @@ fn main_0() -> i32 { let x: Value = Rc::new(RefCell::new( ((*bytes.borrow()).offset((4) as isize).read()), )); + let _ = (*x.borrow_mut()).clone(); return 0; } diff --git a/tests/unit/out/refcount/reinterpret_cast_undersize.rs b/tests/unit/out/refcount/reinterpret_cast_undersize.rs index 932d7bb3..4af8af9e 100644 --- a/tests/unit/out/refcount/reinterpret_cast_undersize.rs +++ b/tests/unit/out/refcount/reinterpret_cast_undersize.rs @@ -13,5 +13,6 @@ fn main_0() -> i32 { let b: Value = Rc::new(RefCell::new(66_u8)); let p: Value> = Rc::new(RefCell::new((b.as_pointer()).reinterpret_cast::())); let val: Value = Rc::new(RefCell::new(((*p.borrow()).read()))); + let _ = (*val.borrow_mut()).clone(); return 0; } diff --git a/tests/unit/out/refcount/string_escape.rs b/tests/unit/out/refcount/string_escape.rs index 5909c617..85541a27 100644 --- a/tests/unit/out/refcount/string_escape.rs +++ b/tests/unit/out/refcount/string_escape.rs @@ -23,8 +23,8 @@ fn main_0() -> i32 { ); let i: Value = Rc::new(RefCell::new(0)); 'loop_: while ((*i.borrow()) - < ((((::std::mem::size_of::<[u8; 40]>() as u64 as u64) - .wrapping_div(::std::mem::size_of::() as u64 as u64)) as u64) as i32)) + < (((::std::mem::size_of::<[u8; 40]>() as u64 as u64) + .wrapping_div(::std::mem::size_of::() as u64 as u64)) as i32)) { assert!({ let _lhs = (((*special.borrow()).offset((*i.borrow()) as isize).read()) as i32); diff --git a/tests/unit/out/refcount/va_arg_printf.rs b/tests/unit/out/refcount/va_arg_printf.rs index 181f8423..4a025c69 100644 --- a/tests/unit/out/refcount/va_arg_printf.rs +++ b/tests/unit/out/refcount/va_arg_printf.rs @@ -9,6 +9,7 @@ use std::rc::{Rc, Weak}; pub fn logf_impl_0(fmt: Ptr, ap: VaList) -> i32 { let fmt: Value> = Rc::new(RefCell::new(fmt)); let ap: Value = Rc::new(RefCell::new(ap)); + let _ = (*fmt.borrow()); return { let _lhs = ((*ap.borrow_mut()).arg::()).clone(); _lhs + ((*ap.borrow_mut()).arg::()).clone() diff --git a/tests/unit/out/refcount/void_cast.rs b/tests/unit/out/refcount/void_cast.rs new file mode 100644 index 00000000..4aa0cee9 --- /dev/null +++ b/tests/unit/out/refcount/void_cast.rs @@ -0,0 +1,102 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn unused_param_0(x: i32) { + let x: Value = Rc::new(RefCell::new(x)); + let _ = (*x.borrow_mut()).clone(); +} +thread_local!( + pub static side_effect_counter: Value = Rc::new(RefCell::new(0)); +); +pub fn bump_and_return_1() -> i32 { + (*side_effect_counter.with(Value::clone).borrow_mut()).prefix_inc(); + return (*side_effect_counter.with(Value::clone).borrow()); +} +#[derive(Default)] +pub struct Holder { + pub field: Value, +} +impl Clone for Holder { + fn clone(&self) -> Self { + let mut this = Self { + field: Rc::new(RefCell::new((*self.field.borrow()))), + }; + this + } +} +impl ByteRepr for Holder {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + ({ + let _x: i32 = 42; + unused_param_0(_x) + }); + let y: Value = Rc::new(RefCell::new(5)); + let _ = (*y.borrow_mut()).clone(); + let z: Value = Rc::new(RefCell::new({ + let _ = (*y.borrow_mut()).clone(); + 7 + })); + assert!(((*z.borrow()) == 7)); + let counter: Value = Rc::new(RefCell::new(0)); + let w: Value = Rc::new(RefCell::new({ + let _ = (*counter.borrow_mut()).clone(); + (*counter.borrow_mut()) = 3; + (*counter.borrow()) + })); + assert!(((*w.borrow()) == 3)); + assert!(((*counter.borrow()) == 3)); + let _ = ({ bump_and_return_1() }); + assert!(((*side_effect_counter.with(Value::clone).borrow()) == 1)); + let v: Value = Rc::new(RefCell::new({ + let _ = ({ bump_and_return_1() }); + 99 + })); + assert!(((*side_effect_counter.with(Value::clone).borrow()) == 2)); + assert!(((*v.borrow()) == 99)); + let _ = 0; + let _ = (0); + let _ = (*y.borrow_mut()).clone(); + { + let _ = 0; + }; + { + let _ = (*y.borrow_mut()).clone(); + }; + let err: Value = Rc::new(RefCell::new(0)); + { + let _ = ((*err.borrow_mut()) = 42).clone(); + }; + assert!(((*err.borrow()) == 42)); + let chosen: Value = Rc::new(RefCell::new({ + let _ = ((*err.borrow_mut()) = 7).clone(); + 123 + })); + assert!(((*err.borrow()) == 7)); + assert!(((*chosen.borrow()) == 123)); + let _ = bump_and_return_1.clone(); + assert!(((*side_effect_counter.with(Value::clone).borrow()) == 2)); + let _ = (FnPtr:: i32>::new(bump_and_return_1)); + assert!(((*side_effect_counter.with(Value::clone).borrow()) == 2)); + let _ = ((FnPtr:: i32>::new(bump_and_return_1)).cast:: i32>(None)); + assert!(((*side_effect_counter.with(Value::clone).borrow()) == 2)); + let storage: Value = Rc::new(RefCell::new(11)); + let p: Value> = Rc::new(RefCell::new((storage.as_pointer()))); + let _ = ((*p.borrow()).read()).clone(); + let arr: Value> = Rc::new(RefCell::new(Box::new([1, 2, 3]))); + let _ = ((*arr.borrow_mut())[(1) as usize]).clone(); + let h: Value = Rc::new(RefCell::new(Holder { + field: Rc::new(RefCell::new(17)), + })); + let _ = (*(*h.borrow()).field.borrow_mut()).clone(); + let hp: Value> = Rc::new(RefCell::new((h.as_pointer()))); + let _ = (*(*(*hp.borrow()).upgrade().deref()).field.borrow_mut()).clone(); + return 0; +} diff --git a/tests/unit/out/unsafe/bool_printing.rs b/tests/unit/out/unsafe/bool_printing.rs index ec11b18a..0716902d 100644 --- a/tests/unit/out/unsafe/bool_printing.rs +++ b/tests/unit/out/unsafe/bool_printing.rs @@ -51,7 +51,7 @@ unsafe fn main_0() -> i32 { .into_raw_fd(), ), "{:}\n", - ((((i1) != (i2)) as bool) as u8), + (((i1) != (i2)) as u8), ); write!( std::fs::File::from_raw_fd( @@ -62,7 +62,7 @@ unsafe fn main_0() -> i32 { .into_raw_fd(), ), "{:}\n", - ((((i1) == (i2)) as bool) as u8), + (((i1) == (i2)) as u8), ); write!( std::fs::File::from_raw_fd( diff --git a/tests/unit/out/unsafe/continue.rs b/tests/unit/out/unsafe/continue.rs index ad204b1e..a26dd848 100644 --- a/tests/unit/out/unsafe/continue.rs +++ b/tests/unit/out/unsafe/continue.rs @@ -37,14 +37,14 @@ unsafe fn main_0() -> i32 { 'loop_: while ((k2) < (5)) { let mut k3: i32 = 0; 'loop_: while ((k3) < (5)) { - if ((((((k1) + (k2)) + (k3)) as i32) % (2)) == (0)) { + if (((((k1) + (k2)) + (k3)) % (2)) == (0)) { k3.postfix_inc(); continue 'loop_; } out.prefix_inc(); k3.postfix_inc(); } - if (((((k1) + (k2)) as i32) % (2)) == (0)) { + if ((((k1) + (k2)) % (2)) == (0)) { k2.postfix_inc(); continue 'loop_; } diff --git a/tests/unit/out/unsafe/reinterpret_cast_oob_read.rs b/tests/unit/out/unsafe/reinterpret_cast_oob_read.rs index 3b211f4d..18366d82 100644 --- a/tests/unit/out/unsafe/reinterpret_cast_oob_read.rs +++ b/tests/unit/out/unsafe/reinterpret_cast_oob_read.rs @@ -15,5 +15,6 @@ unsafe fn main_0() -> i32 { let mut val: u32 = 67305985_u32; let mut bytes: *mut u8 = ((&mut val as *mut u32) as *mut u8); let mut x: u8 = (*bytes.offset((4) as isize)); + let _ = x.clone(); return 0; } diff --git a/tests/unit/out/unsafe/reinterpret_cast_undersize.rs b/tests/unit/out/unsafe/reinterpret_cast_undersize.rs index 70f50953..c2363c25 100644 --- a/tests/unit/out/unsafe/reinterpret_cast_undersize.rs +++ b/tests/unit/out/unsafe/reinterpret_cast_undersize.rs @@ -15,5 +15,6 @@ unsafe fn main_0() -> i32 { let mut b: u8 = 66_u8; let mut p: *mut u32 = ((&mut b as *mut u8) as *mut u32); let mut val: u32 = (*p); + let _ = val.clone(); return 0; } diff --git a/tests/unit/out/unsafe/string_escape.rs b/tests/unit/out/unsafe/string_escape.rs index ff21009c..285f6dde 100644 --- a/tests/unit/out/unsafe/string_escape.rs +++ b/tests/unit/out/unsafe/string_escape.rs @@ -22,8 +22,8 @@ unsafe fn main_0() -> i32 { ];; let mut i: i32 = 0; 'loop_: while ((i) - < ((((::std::mem::size_of::<[u8; 40]>() as u64 as u64) - .wrapping_div(::std::mem::size_of::() as u64 as u64)) as u64) as i32)) + < (((::std::mem::size_of::<[u8; 40]>() as u64 as u64) + .wrapping_div(::std::mem::size_of::() as u64 as u64)) as i32)) { assert!((((*special.offset((i) as isize)) as i32) == (expected[(i) as usize] as i32))); i.postfix_inc(); diff --git a/tests/unit/out/unsafe/va_arg_printf.rs b/tests/unit/out/unsafe/va_arg_printf.rs index 364d44de..c44ff0c7 100644 --- a/tests/unit/out/unsafe/va_arg_printf.rs +++ b/tests/unit/out/unsafe/va_arg_printf.rs @@ -7,6 +7,7 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn logf_impl_0(mut fmt: *const u8, mut ap: VaList) -> i32 { + let _ = fmt; return ((ap.arg::()) + (ap.arg::())); } pub unsafe fn logf_1(mut fmt: *const u8, args: &[VaArg]) -> i32 { diff --git a/tests/unit/out/unsafe/void_cast.rs b/tests/unit/out/unsafe/void_cast.rs new file mode 100644 index 00000000..dc96df0f --- /dev/null +++ b/tests/unit/out/unsafe/void_cast.rs @@ -0,0 +1,93 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn unused_param_0(mut x: i32) { + let _ = x.clone(); +} +pub static mut side_effect_counter: i32 = 0; +pub unsafe fn bump_and_return_1() -> i32 { + side_effect_counter.prefix_inc(); + return side_effect_counter; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Holder { + pub field: i32, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + (unsafe { + let _x: i32 = 42; + unused_param_0(_x) + }); + let mut y: i32 = 5; + let _ = y.clone(); + let mut z: i32 = { + let _ = y.clone(); + 7 + }; + assert!(((z) == (7))); + let mut counter: i32 = 0; + let mut w: i32 = { + let _ = counter.clone(); + counter = 3; + counter + }; + assert!(((w) == (3))); + assert!(((counter) == (3))); + let _ = (unsafe { bump_and_return_1() }); + assert!(((side_effect_counter) == (1))); + let mut v: i32 = { + let _ = (unsafe { bump_and_return_1() }); + 99 + }; + assert!(((side_effect_counter) == (2))); + assert!(((v) == (99))); + let _ = 0; + let _ = (0); + let _ = (y).clone(); + { + let _ = 0; + }; + { + let _ = (y).clone(); + }; + let mut err: i32 = 0; + { + let _ = (err = 42).clone(); + }; + assert!(((err) == (42))); + let mut chosen: i32 = { + let _ = (err = 7).clone(); + 123 + }; + assert!(((err) == (7))); + assert!(((chosen) == (123))); + let _ = bump_and_return_1.clone(); + assert!(((side_effect_counter) == (2))); + let _ = (Some(bump_and_return_1)); + assert!(((side_effect_counter) == (2))); + let _ = (std::mem::transmute:: i32>, Option i32>>( + (Some(bump_and_return_1)), + )); + assert!(((side_effect_counter) == (2))); + let mut storage: i32 = 11; + let mut p: *mut i32 = (&mut storage as *mut i32); + let _ = (*p).clone(); + let mut arr: [i32; 3] = [1, 2, 3]; + let _ = (arr[(1) as usize]).clone(); + let mut h: Holder = Holder { field: 17 }; + let _ = (h.field).clone(); + let mut hp: *mut Holder = (&mut h as *mut Holder); + let _ = ((*hp).field).clone(); + return 0; +} From c771573a7197b2fbae8b9f5be2cff4b069fd232c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 30 Apr 2026 15:40:07 +0100 Subject: [PATCH 4/8] Add comma operator test --- tests/unit/comma_operator.cpp | 24 ++++++++++++ tests/unit/out/refcount/comma_operator.rs | 45 ++++++++++++++++++++++ tests/unit/out/unsafe/comma_operator.rs | 47 +++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 tests/unit/comma_operator.cpp create mode 100644 tests/unit/out/refcount/comma_operator.rs create mode 100644 tests/unit/out/unsafe/comma_operator.rs diff --git a/tests/unit/comma_operator.cpp b/tests/unit/comma_operator.cpp new file mode 100644 index 00000000..1c20fee7 --- /dev/null +++ b/tests/unit/comma_operator.cpp @@ -0,0 +1,24 @@ +#include + +int main() { + int x = 1; + int y = (x = 2, x + 1); + assert(x == 2); + assert(y == 3); + + int z = (1, 2, 3); + assert(z == 3); + + int counter = 0; + int w = (counter++, counter++, counter); + assert(counter == 2); + assert(w == 2); + + int a = 0, b = 0; + if ((a = 1, b = 2, a + b > 0)) { + assert(a == 1); + assert(b == 2); + } + + return 0; +} diff --git a/tests/unit/out/refcount/comma_operator.rs b/tests/unit/out/refcount/comma_operator.rs new file mode 100644 index 00000000..5d643a5c --- /dev/null +++ b/tests/unit/out/refcount/comma_operator.rs @@ -0,0 +1,45 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let x: Value = Rc::new(RefCell::new(1)); + let y: Value = Rc::new(RefCell::new({ + (*x.borrow_mut()) = 2; + ((*x.borrow()) + 1) + })); + assert!(((*x.borrow()) == 2)); + assert!(((*y.borrow()) == 3)); + let z: Value = Rc::new(RefCell::new({ + 1; + 2; + 3 + })); + assert!(((*z.borrow()) == 3)); + let counter: Value = Rc::new(RefCell::new(0)); + let w: Value = Rc::new(RefCell::new({ + (*counter.borrow_mut()).postfix_inc(); + (*counter.borrow_mut()).postfix_inc(); + (*counter.borrow()) + })); + assert!(((*counter.borrow()) == 2)); + assert!(((*w.borrow()) == 2)); + let a: Value = Rc::new(RefCell::new(0)); + let b: Value = Rc::new(RefCell::new(0)); + if { + (*a.borrow_mut()) = 1; + (*b.borrow_mut()) = 2; + (((*a.borrow()) + (*b.borrow())) > 0) + } { + assert!(((*a.borrow()) == 1)); + assert!(((*b.borrow()) == 2)); + } + return 0; +} diff --git a/tests/unit/out/unsafe/comma_operator.rs b/tests/unit/out/unsafe/comma_operator.rs new file mode 100644 index 00000000..7defe1c3 --- /dev/null +++ b/tests/unit/out/unsafe/comma_operator.rs @@ -0,0 +1,47 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut x: i32 = 1; + let mut y: i32 = { + x = 2; + ((x) + (1)) + }; + assert!(((x) == (2))); + assert!(((y) == (3))); + let mut z: i32 = { + 1; + 2; + 3 + }; + assert!(((z) == (3))); + let mut counter: i32 = 0; + let mut w: i32 = { + counter.postfix_inc(); + counter.postfix_inc(); + counter + }; + assert!(((counter) == (2))); + assert!(((w) == (2))); + let mut a: i32 = 0; + let mut b: i32 = 0; + if { + a = 1; + b = 2; + (((a) + (b)) > (0)) + } { + assert!(((a) == (1))); + assert!(((b) == (2))); + } + return 0; +} From 779e33aef8576d93c18bf52a6dd9aa46e1239211 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 30 Apr 2026 21:54:38 +0100 Subject: [PATCH 5/8] Drop the let _ = expr; pattern for void casts --- cpp2rust/converter/converter.cpp | 27 ++++++------------- cpp2rust/converter/converter.h | 2 -- .../converter/models/converter_refcount.cpp | 3 ++- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 4e1a6afe..6500fe92 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1865,21 +1865,12 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { return false; } -void Converter::ConvertVoidCastExpr(clang::ExplicitCastExpr *expr) { - PushExprKind push(*this, ExprKind::Void); - StrCat("let _ = "); - Convert(expr->getSubExpr()); - if (expr->getSubExpr()->isLValue()) { - StrCat(".clone()"); - } - StrCat(token::kSemiColon); -} - bool Converter::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { auto type = expr->getTypeAsWritten(); auto *sub_expr = expr->getSubExpr(); if (type->isVoidType()) { - ConvertVoidCastExpr(expr); + PushExprKind push(*this, ExprKind::Void); + Convert(expr->getSubExpr()); return false; } switch (expr->getStmtClass()) { @@ -2263,14 +2254,12 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { bool Converter::VisitParenExpr(clang::ParenExpr *expr) { // Comma operator becomes (A, B, C) -> { A; B; C } - auto *bin = clang::dyn_cast(expr->getSubExpr()); - // Void cast becomes ((void) A) -> { let _ = A; } - auto *cast = clang::dyn_cast(expr->getSubExpr()); - if ((bin && bin->isCommaOp()) || - (cast && cast->getTypeAsWritten()->isVoidType())) { - PushBrace push(*this); - Convert(expr->getSubExpr()); - return false; + if (auto *bin = clang::dyn_cast(expr->getSubExpr())) { + if (bin->isCommaOp()) { + PushBrace push(*this); + Convert(expr->getSubExpr()); + return false; + } } // Add cast to avoid ambigous integers. Don't add cast if sub expression is a diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index bf9a70fd..02d5f6f2 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -240,8 +240,6 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitImplicitCastExpr(clang::ImplicitCastExpr *expr); - void ConvertVoidCastExpr(clang::ExplicitCastExpr *expr); - virtual bool VisitExplicitCastExpr(clang::ExplicitCastExpr *expr); virtual bool VisitBinaryOperator(clang::BinaryOperator *expr); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 8a5a5ac3..d7a6afdc 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1128,7 +1128,8 @@ bool ConverterRefCount::VisitFunctionPointerCast( bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { if (expr->getTypeAsWritten()->isVoidType()) { - ConvertVoidCastExpr(expr); + PushExprKind push(*this, ExprKind::Void); + Convert(expr->getSubExpr()); return false; } switch (expr->getStmtClass()) { From a73306fa802fba0b7ea27439ef405fb02f4e4a96 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 30 Apr 2026 21:54:56 +0100 Subject: [PATCH 6/8] Update tests --- tests/unit/out/refcount/void_cast.rs | 46 ++++++++++++---------------- tests/unit/out/unsafe/void_cast.rs | 46 ++++++++++++---------------- 2 files changed, 40 insertions(+), 52 deletions(-) diff --git a/tests/unit/out/refcount/void_cast.rs b/tests/unit/out/refcount/void_cast.rs index 4aa0cee9..776b078c 100644 --- a/tests/unit/out/refcount/void_cast.rs +++ b/tests/unit/out/refcount/void_cast.rs @@ -8,7 +8,7 @@ use std::os::fd::AsFd; use std::rc::{Rc, Weak}; pub fn unused_param_0(x: i32) { let x: Value = Rc::new(RefCell::new(x)); - let _ = (*x.borrow_mut()).clone(); + (*x.borrow_mut()); } thread_local!( pub static side_effect_counter: Value = Rc::new(RefCell::new(0)); @@ -39,64 +39,58 @@ fn main_0() -> i32 { unused_param_0(_x) }); let y: Value = Rc::new(RefCell::new(5)); - let _ = (*y.borrow_mut()).clone(); + (*y.borrow_mut()); let z: Value = Rc::new(RefCell::new({ - let _ = (*y.borrow_mut()).clone(); + (*y.borrow_mut()); 7 })); assert!(((*z.borrow()) == 7)); let counter: Value = Rc::new(RefCell::new(0)); let w: Value = Rc::new(RefCell::new({ - let _ = (*counter.borrow_mut()).clone(); + (*counter.borrow_mut()); (*counter.borrow_mut()) = 3; (*counter.borrow()) })); assert!(((*w.borrow()) == 3)); assert!(((*counter.borrow()) == 3)); - let _ = ({ bump_and_return_1() }); + ({ bump_and_return_1() }); assert!(((*side_effect_counter.with(Value::clone).borrow()) == 1)); let v: Value = Rc::new(RefCell::new({ - let _ = ({ bump_and_return_1() }); + ({ bump_and_return_1() }); 99 })); assert!(((*side_effect_counter.with(Value::clone).borrow()) == 2)); assert!(((*v.borrow()) == 99)); - let _ = 0; - let _ = (0); - let _ = (*y.borrow_mut()).clone(); - { - let _ = 0; - }; - { - let _ = (*y.borrow_mut()).clone(); - }; + 0; + (0); + (*y.borrow_mut()); + (0); + (*y.borrow_mut()); let err: Value = Rc::new(RefCell::new(0)); - { - let _ = ((*err.borrow_mut()) = 42).clone(); - }; + ((*err.borrow_mut()) = 42); assert!(((*err.borrow()) == 42)); let chosen: Value = Rc::new(RefCell::new({ - let _ = ((*err.borrow_mut()) = 7).clone(); + ((*err.borrow_mut()) = 7); 123 })); assert!(((*err.borrow()) == 7)); assert!(((*chosen.borrow()) == 123)); - let _ = bump_and_return_1.clone(); + bump_and_return_1; assert!(((*side_effect_counter.with(Value::clone).borrow()) == 2)); - let _ = (FnPtr:: i32>::new(bump_and_return_1)); + (FnPtr:: i32>::new(bump_and_return_1)); assert!(((*side_effect_counter.with(Value::clone).borrow()) == 2)); - let _ = ((FnPtr:: i32>::new(bump_and_return_1)).cast:: i32>(None)); + ((FnPtr:: i32>::new(bump_and_return_1)).cast:: i32>(None)); assert!(((*side_effect_counter.with(Value::clone).borrow()) == 2)); let storage: Value = Rc::new(RefCell::new(11)); let p: Value> = Rc::new(RefCell::new((storage.as_pointer()))); - let _ = ((*p.borrow()).read()).clone(); + ((*p.borrow()).read()); let arr: Value> = Rc::new(RefCell::new(Box::new([1, 2, 3]))); - let _ = ((*arr.borrow_mut())[(1) as usize]).clone(); + ((*arr.borrow_mut())[(1) as usize]); let h: Value = Rc::new(RefCell::new(Holder { field: Rc::new(RefCell::new(17)), })); - let _ = (*(*h.borrow()).field.borrow_mut()).clone(); + (*(*h.borrow()).field.borrow_mut()); let hp: Value> = Rc::new(RefCell::new((h.as_pointer()))); - let _ = (*(*(*hp.borrow()).upgrade().deref()).field.borrow_mut()).clone(); + (*(*(*hp.borrow()).upgrade().deref()).field.borrow_mut()); return 0; } diff --git a/tests/unit/out/unsafe/void_cast.rs b/tests/unit/out/unsafe/void_cast.rs index dc96df0f..66f9d5e8 100644 --- a/tests/unit/out/unsafe/void_cast.rs +++ b/tests/unit/out/unsafe/void_cast.rs @@ -7,7 +7,7 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn unused_param_0(mut x: i32) { - let _ = x.clone(); + x; } pub static mut side_effect_counter: i32 = 0; pub unsafe fn bump_and_return_1() -> i32 { @@ -30,64 +30,58 @@ unsafe fn main_0() -> i32 { unused_param_0(_x) }); let mut y: i32 = 5; - let _ = y.clone(); + y; let mut z: i32 = { - let _ = y.clone(); + y; 7 }; assert!(((z) == (7))); let mut counter: i32 = 0; let mut w: i32 = { - let _ = counter.clone(); + counter; counter = 3; counter }; assert!(((w) == (3))); assert!(((counter) == (3))); - let _ = (unsafe { bump_and_return_1() }); + (unsafe { bump_and_return_1() }); assert!(((side_effect_counter) == (1))); let mut v: i32 = { - let _ = (unsafe { bump_and_return_1() }); + (unsafe { bump_and_return_1() }); 99 }; assert!(((side_effect_counter) == (2))); assert!(((v) == (99))); - let _ = 0; - let _ = (0); - let _ = (y).clone(); - { - let _ = 0; - }; - { - let _ = (y).clone(); - }; + 0; + (0); + (y); + (0); + (y); let mut err: i32 = 0; - { - let _ = (err = 42).clone(); - }; + (err = 42); assert!(((err) == (42))); let mut chosen: i32 = { - let _ = (err = 7).clone(); + (err = 7); 123 }; assert!(((err) == (7))); assert!(((chosen) == (123))); - let _ = bump_and_return_1.clone(); + bump_and_return_1; assert!(((side_effect_counter) == (2))); - let _ = (Some(bump_and_return_1)); + (Some(bump_and_return_1)); assert!(((side_effect_counter) == (2))); - let _ = (std::mem::transmute:: i32>, Option i32>>( + (std::mem::transmute:: i32>, Option i32>>( (Some(bump_and_return_1)), )); assert!(((side_effect_counter) == (2))); let mut storage: i32 = 11; let mut p: *mut i32 = (&mut storage as *mut i32); - let _ = (*p).clone(); + (*p); let mut arr: [i32; 3] = [1, 2, 3]; - let _ = (arr[(1) as usize]).clone(); + (arr[(1) as usize]); let mut h: Holder = Holder { field: 17 }; - let _ = (h.field).clone(); + (h.field); let mut hp: *mut Holder = (&mut h as *mut Holder); - let _ = ((*hp).field).clone(); + ((*hp).field); return 0; } From 6dd37dceeb1c261cde39a850189ccc3d453af0c0 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 30 Apr 2026 22:26:52 +0100 Subject: [PATCH 7/8] Only add clone on non-Copy types --- cpp2rust/converter/converter_lib.cpp | 5 +++++ cpp2rust/converter/converter_lib.h | 2 ++ cpp2rust/converter/models/converter_refcount.cpp | 3 +++ 3 files changed, 10 insertions(+) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 6f6a537b..9ad604d7 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -814,4 +814,9 @@ ConstCastType GetConstCastType(clang::QualType to, clang::QualType from) { } } +bool TypeIsCopyable(clang::QualType ty) { + return ty->isIntegerType() || ty->isFunctionPointerType() || + ty->isFunctionType(); +} + } // namespace cpp2rust diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 2522980d..3a3cf25d 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -180,4 +180,6 @@ enum class ConstCastType { ConstCastType GetConstCastType(clang::QualType to, clang::QualType from); +bool TypeIsCopyable(clang::QualType ty); + } // namespace cpp2rust diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index d7a6afdc..d8a3c719 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1130,6 +1130,9 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) { if (expr->getTypeAsWritten()->isVoidType()) { PushExprKind push(*this, ExprKind::Void); Convert(expr->getSubExpr()); + if (!TypeIsCopyable(expr->getSubExpr()->getType())) { + StrCat(".clone()"); + } return false; } switch (expr->getStmtClass()) { From 54082f2f59aec1555d24a8b2e3fd98c90563e6a4 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 30 Apr 2026 22:27:03 +0100 Subject: [PATCH 8/8] Update tests --- tests/unit/out/refcount/reinterpret_cast_oob_read.rs | 2 +- tests/unit/out/refcount/reinterpret_cast_undersize.rs | 2 +- tests/unit/out/refcount/va_arg_printf.rs | 2 +- tests/unit/out/refcount/void_cast.rs | 1 + tests/unit/out/unsafe/reinterpret_cast_oob_read.rs | 2 +- tests/unit/out/unsafe/reinterpret_cast_undersize.rs | 2 +- tests/unit/out/unsafe/va_arg_printf.rs | 2 +- tests/unit/out/unsafe/void_cast.rs | 1 + tests/unit/void_cast.cpp | 1 + 9 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/unit/out/refcount/reinterpret_cast_oob_read.rs b/tests/unit/out/refcount/reinterpret_cast_oob_read.rs index d45fe96f..e80e9c85 100644 --- a/tests/unit/out/refcount/reinterpret_cast_oob_read.rs +++ b/tests/unit/out/refcount/reinterpret_cast_oob_read.rs @@ -15,6 +15,6 @@ fn main_0() -> i32 { let x: Value = Rc::new(RefCell::new( ((*bytes.borrow()).offset((4) as isize).read()), )); - let _ = (*x.borrow_mut()).clone(); + (*x.borrow_mut()); return 0; } diff --git a/tests/unit/out/refcount/reinterpret_cast_undersize.rs b/tests/unit/out/refcount/reinterpret_cast_undersize.rs index 4af8af9e..5191b981 100644 --- a/tests/unit/out/refcount/reinterpret_cast_undersize.rs +++ b/tests/unit/out/refcount/reinterpret_cast_undersize.rs @@ -13,6 +13,6 @@ fn main_0() -> i32 { let b: Value = Rc::new(RefCell::new(66_u8)); let p: Value> = Rc::new(RefCell::new((b.as_pointer()).reinterpret_cast::())); let val: Value = Rc::new(RefCell::new(((*p.borrow()).read()))); - let _ = (*val.borrow_mut()).clone(); + (*val.borrow_mut()); return 0; } diff --git a/tests/unit/out/refcount/va_arg_printf.rs b/tests/unit/out/refcount/va_arg_printf.rs index 4a025c69..b351e887 100644 --- a/tests/unit/out/refcount/va_arg_printf.rs +++ b/tests/unit/out/refcount/va_arg_printf.rs @@ -9,7 +9,7 @@ use std::rc::{Rc, Weak}; pub fn logf_impl_0(fmt: Ptr, ap: VaList) -> i32 { let fmt: Value> = Rc::new(RefCell::new(fmt)); let ap: Value = Rc::new(RefCell::new(ap)); - let _ = (*fmt.borrow()); + (*fmt.borrow()).clone(); return { let _lhs = ((*ap.borrow_mut()).arg::()).clone(); _lhs + ((*ap.borrow_mut()).arg::()).clone() diff --git a/tests/unit/out/refcount/void_cast.rs b/tests/unit/out/refcount/void_cast.rs index 776b078c..e372fef3 100644 --- a/tests/unit/out/refcount/void_cast.rs +++ b/tests/unit/out/refcount/void_cast.rs @@ -84,6 +84,7 @@ fn main_0() -> i32 { let storage: Value = Rc::new(RefCell::new(11)); let p: Value> = Rc::new(RefCell::new((storage.as_pointer()))); ((*p.borrow()).read()); + (*p.borrow_mut()).clone(); let arr: Value> = Rc::new(RefCell::new(Box::new([1, 2, 3]))); ((*arr.borrow_mut())[(1) as usize]); let h: Value = Rc::new(RefCell::new(Holder { diff --git a/tests/unit/out/unsafe/reinterpret_cast_oob_read.rs b/tests/unit/out/unsafe/reinterpret_cast_oob_read.rs index 18366d82..754cca82 100644 --- a/tests/unit/out/unsafe/reinterpret_cast_oob_read.rs +++ b/tests/unit/out/unsafe/reinterpret_cast_oob_read.rs @@ -15,6 +15,6 @@ unsafe fn main_0() -> i32 { let mut val: u32 = 67305985_u32; let mut bytes: *mut u8 = ((&mut val as *mut u32) as *mut u8); let mut x: u8 = (*bytes.offset((4) as isize)); - let _ = x.clone(); + x; return 0; } diff --git a/tests/unit/out/unsafe/reinterpret_cast_undersize.rs b/tests/unit/out/unsafe/reinterpret_cast_undersize.rs index c2363c25..7bbed02e 100644 --- a/tests/unit/out/unsafe/reinterpret_cast_undersize.rs +++ b/tests/unit/out/unsafe/reinterpret_cast_undersize.rs @@ -15,6 +15,6 @@ unsafe fn main_0() -> i32 { let mut b: u8 = 66_u8; let mut p: *mut u32 = ((&mut b as *mut u8) as *mut u32); let mut val: u32 = (*p); - let _ = val.clone(); + val; return 0; } diff --git a/tests/unit/out/unsafe/va_arg_printf.rs b/tests/unit/out/unsafe/va_arg_printf.rs index c44ff0c7..6140a49c 100644 --- a/tests/unit/out/unsafe/va_arg_printf.rs +++ b/tests/unit/out/unsafe/va_arg_printf.rs @@ -7,7 +7,7 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn logf_impl_0(mut fmt: *const u8, mut ap: VaList) -> i32 { - let _ = fmt; + fmt; return ((ap.arg::()) + (ap.arg::())); } pub unsafe fn logf_1(mut fmt: *const u8, args: &[VaArg]) -> i32 { diff --git a/tests/unit/out/unsafe/void_cast.rs b/tests/unit/out/unsafe/void_cast.rs index 66f9d5e8..af4df89d 100644 --- a/tests/unit/out/unsafe/void_cast.rs +++ b/tests/unit/out/unsafe/void_cast.rs @@ -77,6 +77,7 @@ unsafe fn main_0() -> i32 { let mut storage: i32 = 11; let mut p: *mut i32 = (&mut storage as *mut i32); (*p); + (p); let mut arr: [i32; 3] = [1, 2, 3]; (arr[(1) as usize]); let mut h: Holder = Holder { field: 17 }; diff --git a/tests/unit/void_cast.cpp b/tests/unit/void_cast.cpp index 1362312e..78796979 100644 --- a/tests/unit/void_cast.cpp +++ b/tests/unit/void_cast.cpp @@ -61,6 +61,7 @@ int main() { int storage = 11; int *p = &storage; (void)(*p); + (void)(p); int arr[] = {1, 2, 3}; (void)(arr[1]);