Skip to content

Commit 9da14db

Browse files
authored
Merge branch 'master' into split-mapper
2 parents fe88312 + b9f3781 commit 9da14db

329 files changed

Lines changed: 1553 additions & 1118 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: 22 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ void Converter::EmitGlobalInits(Model model, std::string &out) {
9494

9595
void Converter::EmitOpaqueRecords(std::string &out) {
9696
record_decls_.ForEachUndefined([&](const std::string &name) {
97-
out += "#[derive(Clone, Copy, Default, ByteRepr)]";
97+
out += "#[derive(Clone, Copy, Default, ByteRepr, VaArg, FnPtrArg)]";
9898
out += "pub struct ";
9999
out += name;
100100
out += ";\n";
@@ -1113,7 +1113,7 @@ std::string Converter::GetCtorName(clang::CXXConstructorDecl *decl) {
11131113
CanUseCopyOrMoveName(decl, name)) {
11141114
return name;
11151115
}
1116-
return GetOverloadedFunctionName(decl);
1116+
return std::format("new_{}", GetCtorIndex(decl));
11171117
}
11181118
return GetNumberOfConvertingCtors(decl->getParent()) != 1
11191119
? std::format("new_{}", GetCtorIndex(decl))
@@ -2182,8 +2182,15 @@ Converter::ConvertCallExpr(clang::CallExpr *expr) {
21822182
} else if (IsTransparentStdCall(expr)) {
21832183
Convert(expr->getArg(0));
21842184
} else if (IsBuiltinConstantP(callee)) {
2185-
StrCat(expr->getArg(0)->isCXX11ConstantExpr(ctx_) ? token::kOne
2186-
: token::kZero);
2185+
clang::APValue V;
2186+
StrCat(expr->getArg(0)->isCXX11ConstantExpr(ctx_
2187+
#if CLANG_VERSION_MAJOR >= 24
2188+
,
2189+
V
2190+
#endif
2191+
)
2192+
? token::kOne
2193+
: token::kZero);
21872194
} else if (Mapper::Contains(ctx_, callee)) {
21882195
auto **args = expr->getArgs();
21892196
auto num_args = expr->getNumArgs();
@@ -4052,28 +4059,13 @@ std::string Converter::ConvertVarDefaultInit(clang::QualType qual_type) {
40524059
}
40534060

40544061
std::string
4055-
Converter::GetOverloadedFunctionName(const clang::FunctionDecl *decl) {
4062+
Converter::GetOverloadedFunctionName(const clang::CXXMethodDecl *decl) {
40564063
auto name = GetFunctionBaseName(decl);
40574064
if (auto *conversion = clang::dyn_cast<clang::CXXConversionDecl>(decl)) {
40584065
name = GetConversionName(
40594066
conversion, GetUnsafeTypeAsString(conversion->getConversionType()));
40604067
}
4061-
if (auto *ctor = clang::dyn_cast<clang::CXXConstructorDecl>(decl);
4062-
ctor && !ctor->getParent()->getIdentifier()) {
4063-
name = GetRecordName(ctor->getParent());
4064-
}
4065-
4066-
if (decl->getNumParams() != 0U) {
4067-
name += '_';
4068-
}
4069-
4070-
for (auto *parameter : decl->parameters()) {
4071-
name += GetUnsafeTypeAsString(parameter->getType());
4072-
if (parameter->getType()->isRValueReferenceType()) {
4073-
name += "_rv";
4074-
}
4075-
name += '_';
4076-
}
4068+
name += std::format("_{}", GetMethodIndex(decl));
40774069

40784070
if (const auto *targs = decl->getTemplateSpecializationArgs()) {
40794071
std::vector<clang::TemplateArgument> args;
@@ -4102,31 +4094,6 @@ Converter::GetOverloadedFunctionName(const clang::FunctionDecl *decl) {
41024094
}
41034095
}
41044096

4105-
auto pred = [](char ch) { return ch != ' ' && ch != '_'; };
4106-
name.erase(std::find_if(name.rbegin(), name.rend(), pred).base(), name.end());
4107-
4108-
if (decl->isVariadic()) {
4109-
name += "_va";
4110-
}
4111-
if (const auto *method = clang::dyn_cast<clang::CXXMethodDecl>(decl)) {
4112-
if (method->isConst()) {
4113-
name += "_const";
4114-
}
4115-
if (method->isVolatile()) {
4116-
name += "_volatile";
4117-
}
4118-
switch (method->getRefQualifier()) {
4119-
case clang::RQ_LValue:
4120-
name += "_lref";
4121-
break;
4122-
case clang::RQ_RValue:
4123-
name += "_rref";
4124-
break;
4125-
case clang::RQ_None:
4126-
break;
4127-
}
4128-
}
4129-
41304097
ToIdentifier(name);
41314098
return name;
41324099
}
@@ -4156,6 +4123,10 @@ Converter::GetStructAttributes(const clang::RecordDecl *decl) {
41564123
struct_attrs.emplace_back("Clone");
41574124
}
41584125

4126+
if (RecordImplementsClone(decl)) {
4127+
struct_attrs.emplace_back("VaArg");
4128+
}
4129+
41594130
if (RecordDerivesDefault(decl)) {
41604131
struct_attrs.emplace_back("Default");
41614132
}
@@ -4647,6 +4618,11 @@ void Converter::AddCloneTrait(const clang::RecordDecl *decl) {
46474618
: std::format(" as *mut {}", record_name)));
46484619
}
46494620

4621+
bool Converter::RecordImplementsClone(const clang::RecordDecl *decl) {
4622+
return HasDefaultedCopyConstructor(decl) ||
4623+
GetUserDefinedCopyConstructor(decl) != nullptr;
4624+
}
4625+
46504626
void Converter::AddDefaultTraitForUnion(const clang::RecordDecl *decl) {
46514627
StrCat(std::format("impl Default for {}", GetRecordName(decl)));
46524628
PushBrace impl_brace(*this);

‎cpp2rust/converter/converter.h‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
583583
virtual std::string ConvertVarDefaultInit(clang::QualType qual_type);
584584

585585
virtual std::string
586-
GetOverloadedFunctionName(const clang::FunctionDecl *decl);
586+
GetOverloadedFunctionName(const clang::CXXMethodDecl *decl);
587587

588588
virtual std::string GetRecordName(const clang::NamedDecl *decl) const;
589589

@@ -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/converter_lib.cpp‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,24 @@ bool IsOverloadedMethod(const clang::CXXMethodDecl *decl) {
354354
}) > 1;
355355
}
356356

357+
unsigned GetMethodIndex(const clang::CXXMethodDecl *decl) {
358+
const clang::Decl *key = decl->getCanonicalDecl();
359+
if (auto *tmpl = decl->getPrimaryTemplate()) {
360+
key = tmpl->getCanonicalDecl();
361+
}
362+
unsigned index = 0;
363+
for (auto *d : decl->getParent()->decls()) {
364+
if (clang::isa<clang::CXXMethodDecl, clang::FunctionTemplateDecl>(d)) {
365+
++index;
366+
if (d->getCanonicalDecl() == key) {
367+
return index;
368+
}
369+
}
370+
}
371+
assert(false && "method not found in its record");
372+
return 0;
373+
}
374+
357375
const char *GetCopyOrMoveName(const clang::CXXMethodDecl *method) {
358376
if (auto *ctor = clang::dyn_cast<clang::CXXConstructorDecl>(method)) {
359377
if (ctor->isCopyConstructor()) {

‎cpp2rust/converter/converter_lib.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ void ForEachTemplateInstantiatedMethod(
8181

8282
bool IsOverloadedMethod(const clang::CXXMethodDecl *decl);
8383

84+
unsigned GetMethodIndex(const clang::CXXMethodDecl *decl);
85+
8486
const char *GetCopyOrMoveName(const clang::CXXMethodDecl *method);
8587

8688
bool CanUseCopyOrMoveName(const clang::CXXMethodDecl *decl,

‎cpp2rust/converter/models/converter_refcount.cpp‎

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

476+
bool ConverterRefCount::RecordImplementsClone(const clang::RecordDecl *decl) {
477+
if (decl->isUnion() || (HasDefaultedCopyConstructor(decl) &&
478+
RecordHasOnlyReferenceFields(decl))) {
479+
return true;
480+
}
481+
return !clang::isa<clang::CXXRecordDecl>(decl) ||
482+
HasCallableCopyConstructor(decl);
483+
}
484+
476485
void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) {
477486
auto record_name = GetRecordName(decl);
478487

@@ -505,7 +514,7 @@ void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) {
505514
return;
506515
}
507516

508-
if (!HasCallableCopyConstructor(cxx)) {
517+
if (!RecordImplementsClone(decl)) {
509518
return;
510519
}
511520

@@ -2059,6 +2068,10 @@ bool ConverterRefCount::VisitCXXScalarValueInitExpr(
20592068
}
20602069

20612070
void ConverterRefCount::ConvertVariadicArg(clang::Expr *arg) {
2071+
if (arg->getType()->isRecordType()) {
2072+
StrCat(ConvertFreshRValue(arg));
2073+
return;
2074+
}
20622075
if (arg->getType()->isPointerType()) {
20632076
StrCat(ConvertFreshPointer(arg));
20642077
return;
@@ -2166,6 +2179,11 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) {
21662179
attrs.emplace_back("ByteRepr");
21672180
}
21682181

2182+
if (RecordImplementsClone(decl)) {
2183+
attrs.emplace_back("VaArg");
2184+
attrs.emplace_back("FnPtrArg");
2185+
}
2186+
21692187
if (RecordDerivesDefault(decl)) {
21702188
attrs.emplace_back("Default");
21712189
}

‎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

0 commit comments

Comments
 (0)