diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index cf33029e6..5865851e5 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1775,6 +1775,14 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) { return false; } + // p->~T() is a no-op when T has nothing to destruct + if (auto *dtor = clang::dyn_cast_or_null( + expr->getCalleeDecl()); + dtor && !RecordNeedsDestruction(dtor->getParent())) { + SetFreshType(expr->getType()); + return false; + } + if (IsImplicitAssignmentCall(expr) && !Mapper::Contains(expr->getCallee())) { auto *call = clang::cast(expr); ConvertAssignment(call->getImplicitObjectArgument(), call->getArg(0), "="); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index e139bf48b..ba78ac736 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1103,6 +1103,13 @@ bool ConverterRefCount::VisitCallExpr(clang::CallExpr *expr) { return false; } + // p->~T() is a no-op when T has nothing to destruct + if (auto *dtor = clang::dyn_cast_or_null( + expr->getCalleeDecl()); + dtor && !RecordNeedsDestruction(dtor->getParent())) { + return false; + } + if (IsImplicitAssignmentCall(expr) && !Mapper::Contains(expr->getCallee())) { auto *call = clang::cast(expr); ConvertAssignment(call->getImplicitObjectArgument(), call->getArg(0), "="); diff --git a/tests/unit/out/refcount/scalar_builtin_construct_destruct.rs b/tests/unit/out/refcount/scalar_builtin_construct_destruct.rs index 7d9d73f41..f48910e47 100644 --- a/tests/unit/out/refcount/scalar_builtin_construct_destruct.rs +++ b/tests/unit/out/refcount/scalar_builtin_construct_destruct.rs @@ -6,6 +6,32 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct Pod { + pub v: Value, +} +impl Clone for Pod { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + v: Rc::new(RefCell::new((*self.v.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for Pod { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.v.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + v: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} pub fn zero_0() -> Ptr { return Ptr::::null(); } @@ -15,6 +41,9 @@ pub fn zero_1() -> i64 { pub fn destroy_2(p: Ptr) { let p: Value> = Rc::new(RefCell::new(p)); } +pub fn destroy_3(p: Ptr) { + let p: Value> = Rc::new(RefCell::new(p)); +} pub fn main() { __cpp2rust_init_globals(); std::process::exit(main_0()); @@ -30,6 +59,11 @@ fn main_0() -> i32 { let x: Value = Rc::new(RefCell::new(5)); ({ destroy_2((x.as_pointer())) }); assert!(((*x.borrow()) == 5)); + let pod: Value = Rc::new(RefCell::new(Pod { + v: Rc::new(RefCell::new(7)), + })); + ({ destroy_3((pod.as_pointer())) }); + assert!(((*(*pod.borrow()).v.borrow()) == 7)); return 0; } pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/scalar_builtin_construct_destruct.rs b/tests/unit/out/unsafe/scalar_builtin_construct_destruct.rs index 574c59266..148fec472 100644 --- a/tests/unit/out/unsafe/scalar_builtin_construct_destruct.rs +++ b/tests/unit/out/unsafe/scalar_builtin_construct_destruct.rs @@ -6,6 +6,11 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Pod { + pub v: i32, +} pub unsafe fn zero_0() -> *mut i32 { return std::ptr::null_mut(); } @@ -13,6 +18,7 @@ pub unsafe fn zero_1() -> i64 { return 0_i64; } pub unsafe fn destroy_2(mut p: *mut i32) {} +pub unsafe fn destroy_3(mut p: *mut Pod) {} pub fn main() { unsafe { __cpp2rust_init_globals(); @@ -30,6 +36,9 @@ unsafe fn main_0() -> i32 { let mut x: i32 = 5; (unsafe { destroy_2((&mut x as *mut i32)) }); assert!(((x) == (5))); + let mut pod: Pod = Pod { v: 7 }; + (unsafe { destroy_3((&mut pod as *mut Pod)) }); + assert!(((pod.v) == (7))); return 0; } pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/scalar_builtin_construct_destruct.cpp b/tests/unit/scalar_builtin_construct_destruct.cpp index 53dd21e3c..148477a3a 100644 --- a/tests/unit/scalar_builtin_construct_destruct.cpp +++ b/tests/unit/scalar_builtin_construct_destruct.cpp @@ -1,5 +1,9 @@ #include +struct Pod { + int v; +}; + template T zero() { return T(); } template void destroy(T *p) { p->~T(); } @@ -18,5 +22,10 @@ int main() { using I = int; x.~I(); assert(x == 5); + + Pod pod{7}; + destroy(&pod); + pod.~Pod(); + assert(pod.v == 7); return 0; }