Skip to content

Commit 0db209a

Browse files
committed
Add a DeepClone macro to remove manual Clone implementations
FIxes #216
1 parent fc0e1ff commit 0db209a

59 files changed

Lines changed: 187 additions & 708 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -540,45 +540,28 @@ bool ConverterRefCount::RecordDerivesClone(const clang::RecordDecl *decl) {
540540
});
541541
}
542542

543-
void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) {
544-
auto record_name = GetRecordName(decl);
545-
543+
bool ConverterRefCount::RecordDerivesDeepClone(const clang::RecordDecl *decl) {
546544
if (decl->isUnion()) {
547-
StrCat("impl Clone for", record_name);
548-
PushBrace impl_brace(*this);
549-
StrCat("fn clone(&self) -> Self");
550-
PushBrace fn_brace(*this);
551-
StrCat(record_name,
552-
"{ __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())) }");
553-
return;
545+
return true;
554546
}
555-
556547
if (RecordDerivesClone(decl) || !RecordImplementsClone(decl)) {
557-
return;
548+
return false;
558549
}
559550
// Without a user-defined copy constructor, each field is copied with its
560551
// own clone(), and Values are copied deeply.
561552
auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl);
562-
if (!cxx ||
563-
(!GetUserDefinedCopyConstructor(cxx) && cxx->getNumBases() == 0)) {
564-
StrCat(keyword::kImpl, "Clone for", record_name);
565-
PushBrace impl_brace(*this);
566-
StrCat("fn clone(&self) -> Self");
567-
PushBrace fn_brace(*this);
568-
StrCat("Self");
569-
PushBrace init_brace(*this);
570-
for (auto *field : decl->fields()) {
571-
auto name = GetNamedDeclAsString(field);
572-
auto value = std::format("self.{}.clone()", name);
573-
if (IsValueField(ctx_, field)) {
574-
value = std::format(
575-
"Rc::new(RefCell::new((*self.{}.borrow()).clone()))", name);
576-
}
577-
StrCat(std::format("{}: {},", name, value));
578-
}
553+
return !cxx ||
554+
(!GetUserDefinedCopyConstructor(cxx) && cxx->getNumBases() == 0);
555+
}
556+
557+
void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) {
558+
if (RecordDerivesClone(decl) || RecordDerivesDeepClone(decl) ||
559+
!RecordImplementsClone(decl)) {
579560
return;
580561
}
581562

563+
auto record_name = GetRecordName(decl);
564+
auto *cxx = clang::cast<clang::CXXRecordDecl>(decl);
582565
StrCat(keyword::kImpl, "Clone for", record_name, '{');
583566
StrCat("fn clone(&self) -> Self {");
584567

@@ -627,10 +610,10 @@ void ConverterRefCount::EmitRustUnion(clang::RecordDecl *decl) {
627610
std::vector<std::string>(attrs.begin(), attrs.end()));
628611

629612
auto size = ctx_.getTypeSizeInChars(ctx_.getCanonicalTagType(decl));
630-
StrCat(std::format("#[derive(ByteRepr)] #[byte_size({0})] pub struct {1} {{ "
631-
"#[offset(0)] #[byte_size({0})] __bytes: Value<Box<[u8]>> "
632-
"}}",
633-
size.getQuantity(), name));
613+
StrCat(std::format(
614+
"#[derive(ByteRepr, DeepClone)] #[byte_size({0})] pub struct {1} {{ "
615+
"#[offset(0)] #[byte_size({0})] __bytes: Value<Box<[u8]>> }}",
616+
size.getQuantity(), name));
634617

635618
StrCat("impl", name);
636619
{
@@ -2292,6 +2275,8 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) {
22922275

22932276
if (RecordDerivesClone(decl)) {
22942277
attrs.emplace_back("Clone");
2278+
} else if (RecordDerivesDeepClone(decl)) {
2279+
attrs.emplace_back("DeepClone");
22952280
}
22962281

22972282
// Gives access to the fields through pointers to them.

‎cpp2rust/converter/models/converter_refcount.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class ConverterRefCount final : public Converter {
5353

5454
bool RecordDerivesClone(const clang::RecordDecl *decl);
5555

56+
bool RecordDerivesDeepClone(const clang::RecordDecl *decl);
57+
5658
void EmitByteSizeAttr(const clang::RecordDecl *decl) override;
5759

5860
bool

‎libcc2rs-macros/src/deep_clone.rs‎

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (c) 2022-present INESC-ID.
2+
// Distributed under the MIT license that can be found in the LICENSE file.
3+
4+
use proc_macro::TokenStream;
5+
use proc_macro2::TokenStream as TokenStream2;
6+
use quote::quote;
7+
use syn::{Data, DeriveInput, Fields, Index, Type, parse_macro_input};
8+
9+
// Whether `ty` is a Value<_>, which is copied with DeepClone.
10+
fn is_value(ty: &Type) -> bool {
11+
match ty {
12+
Type::Path(path) => path
13+
.path
14+
.segments
15+
.last()
16+
.is_some_and(|segment| segment.ident == "Value"),
17+
_ => false,
18+
}
19+
}
20+
21+
fn clone_field(ty: &Type, field: TokenStream2) -> TokenStream2 {
22+
if is_value(ty) {
23+
quote! { ::libcc2rs::DeepClone::deep_clone(&self.#field) }
24+
} else {
25+
quote! { ::core::clone::Clone::clone(&self.#field) }
26+
}
27+
}
28+
29+
pub fn expand(input: TokenStream) -> TokenStream {
30+
let input = parse_macro_input!(input as DeriveInput);
31+
let name = &input.ident;
32+
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
33+
let Data::Struct(data) = &input.data else {
34+
panic!("derive(DeepClone) is only supported on structs, `{name}` is not one");
35+
};
36+
let body = match &data.fields {
37+
Fields::Named(fields) => {
38+
let fields = fields.named.iter().map(|field| {
39+
let ident = field.ident.as_ref().unwrap();
40+
let value = clone_field(&field.ty, quote! { #ident });
41+
quote! { #ident: #value }
42+
});
43+
quote! { Self { #(#fields,)* } }
44+
}
45+
Fields::Unnamed(fields) => {
46+
let fields = fields.unnamed.iter().enumerate().map(|(i, field)| {
47+
let index = Index::from(i);
48+
clone_field(&field.ty, quote! { #index })
49+
});
50+
quote! { Self(#(#fields,)*) }
51+
}
52+
Fields::Unit => quote! { Self },
53+
};
54+
quote! {
55+
impl #impl_generics ::core::clone::Clone for #name #ty_generics #where_clause {
56+
fn clone(&self) -> Self {
57+
#body
58+
}
59+
}
60+
}
61+
.into()
62+
}

‎libcc2rs-macros/src/lib.rs‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use proc_macro::TokenStream;
55

66
mod byte_repr;
7+
mod deep_clone;
78
mod fn_ptr_arg;
89
mod goto;
910
mod record;
@@ -131,3 +132,18 @@ pub fn derive_fn_ptr_arg(input: TokenStream) -> TokenStream {
131132
pub fn derive_record(input: TokenStream) -> TokenStream {
132133
record::expand(input)
133134
}
135+
136+
// #[derive(DeepClone)]
137+
// pub struct S {
138+
// pub x: Value<T>,
139+
// pub y: U,
140+
// }
141+
//
142+
// Implements Clone for S, copying the Value fields with
143+
// libcc2rs::DeepClone, such that the copy of S doesn't share them with S,
144+
// and the other fields with Clone.
145+
146+
#[proc_macro_derive(DeepClone)]
147+
pub fn derive_deep_clone(input: TokenStream) -> TokenStream {
148+
deep_clone::expand(input)
149+
}

‎libcc2rs/src/lib.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,4 @@ pub use fd::*;
6969
mod format;
7070
pub use format::*;
7171

72-
pub use libcc2rs_macros::{ByteRepr, FnPtrArg, Record, VaArg, goto, goto_block, switch};
72+
pub use libcc2rs_macros::{ByteRepr, DeepClone, FnPtrArg, Record, VaArg, goto, goto_block, switch};

‎libcc2rs/src/rc.rs‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@ use crate::reinterpret::{ByteRepr, OriginalAlloc, with_scratch};
1616

1717
pub type Value<T> = Rc<RefCell<T>>;
1818

19+
// A copy of a Value that doesn't share the value: unlike clone(), which
20+
// shares it by incrementing the reference count, it copies the value into a
21+
// new Value.
22+
pub trait DeepClone {
23+
fn deep_clone(&self) -> Self;
24+
}
25+
26+
impl<T: Clone> DeepClone for Value<T> {
27+
fn deep_clone(&self) -> Self {
28+
Rc::new(RefCell::new(self.borrow().clone()))
29+
}
30+
}
31+
1932
pub(crate) struct ReinterpretedView {
2033
// Pointer to the source of reinterpret
2134
pub(crate) alloc: OriginalAlloc,

‎rules/dirent/shim.rs‎

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright (c) 2022-present INESC-ID.
22
// Distributed under the MIT license that can be found in the LICENSE file.
33

4-
use crate::{ByteRepr, Record, Value, size_of_field};
4+
use crate::{ByteRepr, DeepClone, Record, Value, size_of_field};
55
use std::cell::{Cell, RefCell};
66
use std::mem::{offset_of, size_of};
77
use std::rc::Rc;
88

9-
#[derive(Record, ByteRepr)]
9+
#[derive(DeepClone, Record, ByteRepr)]
1010
#[byte_size(size_of::<::libc::dirent>())]
1111
pub struct Dirent {
1212
#[offset(offset_of!(::libc::dirent, d_ino))]
@@ -54,15 +54,6 @@ impl Dirent {
5454
}
5555
}
5656

57-
impl Clone for Dirent {
58-
fn clone(&self) -> Self {
59-
Self {
60-
d_name: Rc::new(RefCell::new(self.d_name.borrow().clone())),
61-
..*self
62-
}
63-
}
64-
}
65-
6657
pub struct CDir {
6758
pub entries: Vec<(u64, Vec<u8>, u8)>,
6859
pub pos: Cell<usize>,

‎rules/ip/shim.rs‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2022-present INESC-ID.
22
// Distributed under the MIT license that can be found in the LICENSE file.
33

4-
use crate::{AsPointer, ByteRepr, Ptr, Record, Value};
4+
use crate::{AsPointer, ByteRepr, DeepClone, Ptr, Record, Value};
55
use std::cell::RefCell;
66
use std::rc::Rc;
77

@@ -12,7 +12,7 @@ pub struct InAddr {
1212
pub s_addr: u32,
1313
}
1414

15-
#[derive(Record, ByteRepr)]
15+
#[derive(DeepClone, Record, ByteRepr)]
1616
#[byte_size(16)]
1717
pub struct In6Addr {
1818
#[offset(0)]
@@ -34,13 +34,5 @@ impl Default for In6Addr {
3434
}
3535
}
3636

37-
impl Clone for In6Addr {
38-
fn clone(&self) -> Self {
39-
Self {
40-
s6_addr: Rc::new(RefCell::new(self.s6_addr.borrow().clone())),
41-
}
42-
}
43-
}
44-
4537
impl ByteRepr for ::libc::in_addr {}
4638
impl ByteRepr for ::libc::in6_addr {}

‎rules/socket/shim.rs‎

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright (c) 2022-present INESC-ID.
22
// Distributed under the MIT license that can be found in the LICENSE file.
33

4-
use crate::{ByteRepr, In6Addr, InAddr, Ptr, Record, Value};
4+
use crate::{ByteRepr, DeepClone, In6Addr, InAddr, Ptr, Record, Value};
55
use std::cell::RefCell;
66
use std::rc::Rc;
77

88
// The fields are at the offsets of the byte representation below.
9-
#[derive(Record, ByteRepr)]
9+
#[derive(DeepClone, Record, ByteRepr)]
1010
#[byte_size(16)]
1111
pub struct Sockaddr {
1212
#[offset(0)]
@@ -16,7 +16,7 @@ pub struct Sockaddr {
1616
pub sa_data: Value<Box<[u8]>>,
1717
}
1818

19-
#[derive(Record, ByteRepr)]
19+
#[derive(DeepClone, Record, ByteRepr)]
2020
#[byte_size(16)]
2121
pub struct SockaddrIn {
2222
#[offset(0)]
@@ -30,7 +30,7 @@ pub struct SockaddrIn {
3030
pub sin_zero: Value<Box<[u8]>>,
3131
}
3232

33-
#[derive(Default, Record, ByteRepr)]
33+
#[derive(Clone, Default, Record, ByteRepr)]
3434
#[byte_size(28)]
3535
pub struct SockaddrIn6 {
3636
#[offset(0)]
@@ -45,7 +45,7 @@ pub struct SockaddrIn6 {
4545
pub sin6_scope_id: u32,
4646
}
4747

48-
#[derive(Record, ByteRepr)]
48+
#[derive(DeepClone, Record, ByteRepr)]
4949
#[byte_size(110)]
5050
pub struct SockaddrUn {
5151
#[offset(0)]
@@ -55,7 +55,7 @@ pub struct SockaddrUn {
5555
pub sun_path: Value<Box<[u8]>>,
5656
}
5757

58-
#[derive(Record, ByteRepr)]
58+
#[derive(DeepClone, Record, ByteRepr)]
5959
#[byte_size(128)]
6060
pub struct SockaddrStorage {
6161
#[offset(0)]
@@ -222,56 +222,6 @@ impl Default for SockaddrStorage {
222222
}
223223
}
224224

225-
impl Clone for Sockaddr {
226-
fn clone(&self) -> Self {
227-
Self {
228-
sa_family: self.sa_family,
229-
sa_data: Rc::new(RefCell::new(self.sa_data.borrow().clone())),
230-
}
231-
}
232-
}
233-
234-
impl Clone for SockaddrIn {
235-
fn clone(&self) -> Self {
236-
Self {
237-
sin_family: self.sin_family,
238-
sin_port: self.sin_port,
239-
sin_addr: self.sin_addr.clone(),
240-
sin_zero: Rc::new(RefCell::new(self.sin_zero.borrow().clone())),
241-
}
242-
}
243-
}
244-
245-
impl Clone for SockaddrIn6 {
246-
fn clone(&self) -> Self {
247-
Self {
248-
sin6_family: self.sin6_family,
249-
sin6_port: self.sin6_port,
250-
sin6_flowinfo: self.sin6_flowinfo,
251-
sin6_addr: self.sin6_addr.clone(),
252-
sin6_scope_id: self.sin6_scope_id,
253-
}
254-
}
255-
}
256-
257-
impl Clone for SockaddrUn {
258-
fn clone(&self) -> Self {
259-
Self {
260-
sun_family: self.sun_family,
261-
sun_path: Rc::new(RefCell::new(self.sun_path.borrow().clone())),
262-
}
263-
}
264-
}
265-
266-
impl Clone for SockaddrStorage {
267-
fn clone(&self) -> Self {
268-
Self {
269-
ss_family: self.ss_family,
270-
__pad: Rc::new(RefCell::new(self.__pad.borrow().clone())),
271-
}
272-
}
273-
}
274-
275225
impl ByteRepr for ::libc::sockaddr {}
276226
impl ByteRepr for ::libc::sockaddr_in {}
277227
impl ByteRepr for ::libc::sockaddr_in6 {}

0 commit comments

Comments
 (0)