Skip to content

Commit 6b7dc24

Browse files
authored
Derive VaArg and FnPtrArg for cloneable records (#432)
1 parent 49c5f22 commit 6b7dc24

324 files changed

Lines changed: 929 additions & 622 deletions

File tree

Some content is hidden

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

‎cpp2rust/converter/converter.cpp‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ void Converter::EmitGlobalInits(Model model, std::string &out) {
9292

9393
void Converter::EmitOpaqueRecords(std::string &out) {
9494
record_decls_.ForEachUndefined([&](const std::string &name) {
95-
out += "#[derive(Clone, Copy, Default, ByteRepr)]";
95+
out += "#[derive(Clone, Copy, Default, ByteRepr, VaArg, FnPtrArg)]";
9696
out += "pub struct ";
9797
out += name;
9898
out += ";\n";
@@ -4147,6 +4147,10 @@ Converter::GetStructAttributes(const clang::RecordDecl *decl) {
41474147
struct_attrs.emplace_back("Clone");
41484148
}
41494149

4150+
if (RecordImplementsClone(decl)) {
4151+
struct_attrs.emplace_back("VaArg");
4152+
}
4153+
41504154
if (RecordDerivesDefault(decl)) {
41514155
struct_attrs.emplace_back("Default");
41524156
}
@@ -4637,6 +4641,11 @@ void Converter::AddCloneTrait(const clang::RecordDecl *decl) {
46374641
: std::format(" as *mut {}", record_name)));
46384642
}
46394643

4644+
bool Converter::RecordImplementsClone(const clang::RecordDecl *decl) {
4645+
return HasDefaultedCopyConstructor(decl) ||
4646+
GetUserDefinedCopyConstructor(decl) != nullptr;
4647+
}
4648+
46404649
void Converter::AddDefaultTraitForUnion(const clang::RecordDecl *decl) {
46414650
StrCat(std::format("impl Default for {}", GetRecordName(decl)));
46424651
PushBrace impl_brace(*this);

‎cpp2rust/converter/converter.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
660660

661661
virtual void AddCloneTrait(const clang::RecordDecl *decl);
662662

663+
virtual bool RecordImplementsClone(const clang::RecordDecl *decl);
664+
663665
virtual void AddDefaultTrait(const clang::RecordDecl *decl);
664666

665667
virtual void AddDefaultTraitForUnion(const clang::RecordDecl *decl);

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,15 @@ std::string ConverterRefCount::GetShallowCopy(const clang::RecordDecl *decl,
469469
return std::format("{} {{ {} }}", GetRecordName(decl), fields);
470470
}
471471

472+
bool ConverterRefCount::RecordImplementsClone(const clang::RecordDecl *decl) {
473+
if (decl->isUnion() || (HasDefaultedCopyConstructor(decl) &&
474+
RecordHasOnlyReferenceFields(decl))) {
475+
return true;
476+
}
477+
return !clang::isa<clang::CXXRecordDecl>(decl) ||
478+
HasCallableCopyConstructor(decl);
479+
}
480+
472481
void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) {
473482
auto record_name = GetRecordName(decl);
474483

@@ -501,7 +510,7 @@ void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) {
501510
return;
502511
}
503512

504-
if (!HasCallableCopyConstructor(cxx)) {
513+
if (!RecordImplementsClone(decl)) {
505514
return;
506515
}
507516

@@ -2053,6 +2062,10 @@ bool ConverterRefCount::VisitCXXScalarValueInitExpr(
20532062
}
20542063

20552064
void ConverterRefCount::ConvertVariadicArg(clang::Expr *arg) {
2065+
if (arg->getType()->isRecordType()) {
2066+
StrCat(ConvertFreshRValue(arg));
2067+
return;
2068+
}
20562069
if (arg->getType()->isPointerType()) {
20572070
StrCat(ConvertFreshPointer(arg));
20582071
return;
@@ -2160,6 +2173,11 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) {
21602173
attrs.emplace_back("ByteRepr");
21612174
}
21622175

2176+
if (RecordImplementsClone(decl)) {
2177+
attrs.emplace_back("VaArg");
2178+
attrs.emplace_back("FnPtrArg");
2179+
}
2180+
21632181
if (RecordDerivesDefault(decl)) {
21642182
attrs.emplace_back("Default");
21652183
}

‎cpp2rust/converter/models/converter_refcount.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class ConverterRefCount final : public Converter {
4949
std::string_view src);
5050
void AddCloneTrait(const clang::RecordDecl *decl) override;
5151

52+
bool RecordImplementsClone(const clang::RecordDecl *decl) override;
53+
5254
void AddByteReprTrait(const clang::RecordDecl *decl) override;
5355

5456
bool

‎libcc2rs-macros/src/fn_ptr_arg.rs‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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 syn::{DeriveInput, parse_macro_input};
6+
7+
pub fn expand(input: TokenStream) -> TokenStream {
8+
let input = parse_macro_input!(input as DeriveInput);
9+
let name = &input.ident;
10+
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
11+
quote::quote! {
12+
impl #impl_generics ::libcc2rs::FnPtrArg for #name #ty_generics #where_clause {
13+
#[inline]
14+
fn to_repr(&self) -> ::libcc2rs::ArgRepr<'_> {
15+
::libcc2rs::ArgRepr::Record(self)
16+
}
17+
fn from_repr(r: &::libcc2rs::ArgRepr) -> Self {
18+
::libcc2rs::record_from_repr(r)
19+
}
20+
}
21+
}
22+
.into()
23+
}

‎libcc2rs-macros/src/lib.rs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
use proc_macro::TokenStream;
55

66
mod byte_repr;
7+
mod fn_ptr_arg;
78
mod goto;
89
mod state_machine;
910
mod switch;
11+
mod va_arg;
1012

1113
// switch!(match <condition> {
1214
// <pat> [if <guard>] => { /* body; may contain break or continue */ },
@@ -91,3 +93,13 @@ pub fn goto(_input: TokenStream) -> TokenStream {
9193
pub fn derive_byte_repr(input: TokenStream) -> TokenStream {
9294
byte_repr::expand(input)
9395
}
96+
97+
#[proc_macro_derive(VaArg)]
98+
pub fn derive_va_arg(input: TokenStream) -> TokenStream {
99+
va_arg::expand(input)
100+
}
101+
102+
#[proc_macro_derive(FnPtrArg)]
103+
pub fn derive_fn_ptr_arg(input: TokenStream) -> TokenStream {
104+
fn_ptr_arg::expand(input)
105+
}

‎libcc2rs-macros/src/va_arg.rs‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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 syn::{DeriveInput, parse_macro_input};
6+
7+
pub fn expand(input: TokenStream) -> TokenStream {
8+
let input = parse_macro_input!(input as DeriveInput);
9+
let name = &input.ident;
10+
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
11+
quote::quote! {
12+
impl #impl_generics ::core::convert::From<#name #ty_generics> for ::libcc2rs::VaArg
13+
#where_clause
14+
{
15+
fn from(v: #name #ty_generics) -> Self {
16+
::libcc2rs::VaArg::Record(::std::rc::Rc::new(v))
17+
}
18+
}
19+
20+
impl #impl_generics ::libcc2rs::VaArgGet for #name #ty_generics #where_clause {
21+
fn get(v: &::libcc2rs::VaArg) -> Self {
22+
::libcc2rs::va_record_get(v)
23+
}
24+
}
25+
}
26+
.into()
27+
}

‎libcc2rs/src/fn_ptr_arg.rs‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,21 @@
44
// Support for FnPtr::cast synthesizing a call-through adapter automatically,
55
// for any function pointer types T -> U.
66

7+
use std::any::Any;
8+
79
use crate::rc::Ptr;
810
use crate::reinterpret::ByteRepr;
911
use crate::void::{AnyPtr, ErasedPtr};
1012

1113
// A type-erased view of one argument or return value, used only transiently
1214
// (within a single adapted call) and never allocated.
13-
pub(crate) enum ArgRepr<'a> {
15+
pub enum ArgRepr<'a> {
1416
Bytes([u8; 16], usize),
1517
Ptr(&'a dyn ErasedPtr),
18+
Record(&'a dyn Any),
1619
}
1720

18-
pub(crate) trait FnPtrArg: 'static {
21+
pub trait FnPtrArg: 'static {
1922
fn to_repr(&self) -> ArgRepr<'_>;
2023
// Panics if `r` describes a value that isn't a meaningful `Self` (wrong
2124
// kind, or same kind but incompatible size).
@@ -105,7 +108,9 @@ impl<T: ByteRepr> FnPtrArg for Ptr<T> {
105108
Some(exact) => exact.clone(),
106109
None => e.as_bytes().reinterpret_cast(),
107110
},
108-
ArgRepr::Bytes(..) => panic!("ub: calling through incompatible fn pointer type"),
111+
ArgRepr::Bytes(..) | ArgRepr::Record(_) => {
112+
panic!("ub: calling through incompatible fn pointer type")
113+
}
109114
}
110115
}
111116
}
@@ -118,11 +123,23 @@ impl FnPtrArg for AnyPtr {
118123
fn from_repr(r: &ArgRepr) -> Self {
119124
match r {
120125
ArgRepr::Ptr(e) => e.as_bytes().to_any(),
121-
ArgRepr::Bytes(..) => panic!("ub: calling through incompatible fn pointer type"),
126+
ArgRepr::Bytes(..) | ArgRepr::Record(_) => {
127+
panic!("ub: calling through incompatible fn pointer type")
128+
}
122129
}
123130
}
124131
}
125132

133+
pub fn record_from_repr<T: Any + Clone>(r: &ArgRepr) -> T {
134+
match r {
135+
ArgRepr::Record(v) => v
136+
.downcast_ref::<T>()
137+
.expect("ub: calling through incompatible fn pointer type")
138+
.clone(),
139+
_ => panic!("ub: calling through incompatible fn pointer type"),
140+
}
141+
}
142+
126143
// Fixed-capacity, type-erased view of a whole argument list: `FnPtrArgs`
127144
// (below) converts a tuple of arguments to and from this common
128145
// intermediate, so that converting between two argument lists never needs to

‎libcc2rs/src/format.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pub fn format_c(fmt: &str, va: &[VaArg]) -> String {
6262
VaArg::ULong(v) => Arg::ULong(*v),
6363
VaArg::Ptr(p) => Arg::Size(p.to_int()),
6464
VaArg::RawPtr(v) => Arg::Size(*v as usize),
65-
VaArg::Double(_) => {
65+
VaArg::Double(_) | VaArg::Record(_) => {
6666
panic!("format_c: integer conversion expects an integer argument")
6767
}
6868
},

‎libcc2rs/src/lib.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub use ptr_dyn::*;
1818
include!(concat!(env!("OUT_DIR"), "/rule_shims.rs"));
1919

2020
mod fn_ptr_arg;
21+
pub use fn_ptr_arg::{ArgRepr, FnPtrArg, record_from_repr};
2122

2223
mod fn_ptr;
2324
pub use fn_ptr::FnPtr;
@@ -55,4 +56,4 @@ pub use fd::*;
5556
mod format;
5657
pub use format::*;
5758

58-
pub use libcc2rs_macros::{ByteRepr, goto, goto_block, switch};
59+
pub use libcc2rs_macros::{ByteRepr, FnPtrArg, VaArg, goto, goto_block, switch};

0 commit comments

Comments
 (0)