Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 45 additions & 19 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ bool Converter::VisitBuiltinType(clang::BuiltinType *type) {
bool Converter::VisitRecordType(clang::RecordType *type) {
auto *decl = type->getDecl();
if (auto lambda = AsLambdaClass(clang::QualType(type, 0))) {
if (lambda->isGenericLambda()) {
StrCat("FnPtr<Generic>");
return false;
}
auto proto = lambda->getLambdaCallOperator()
->getType()
->castAs<clang::FunctionProtoType>();
Expand Down Expand Up @@ -1877,7 +1881,8 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) {
expr->getCalleeDecl());
conversion && conversion->getParent()->isLambda()) {
ConvertLambdaToFunctionPointer(clang::cast<clang::CXXMemberCallExpr>(expr)
->getImplicitObjectArgument());
->getImplicitObjectArgument(),
conversion);
return false;
}

Expand Down Expand Up @@ -1958,16 +1963,31 @@ bool Converter::VisitCallExpr(clang::CallExpr *expr) {
return false;
}

void Converter::ConvertLambdaToFunctionPointer(clang::Expr *lambda) {
void Converter::ConvertLambdaToFunctionPointer(
clang::Expr *lambda, const clang::CXXConversionDecl *conversion) {
StrCat("Some");
PushParen paren(*this);
ConvertLambdaClosure(AsLambdaClass(lambda->getType()));
ConvertLambdaClosure(AsLambdaClass(lambda->getType()),
AsLambdaCallOperator(conversion));
computed_expr_type_ = ComputedExprType::FreshPointer;
}

void Converter::EmitFnPtrCall(clang::Expr *callee) {
if (AsLambdaClass(callee->getType())) {
StrCat(ConvertRValue(callee), ".call");
void Converter::ConvertLambdaCall(clang::CallExpr *expr,
const clang::CXXRecordDecl *lambda) {
StrCat(ConvertRValue(GetCallee(expr)));
if (lambda->isGenericLambda()) {
auto call_operator = expr->getDirectCallee();
auto proto = call_operator->getType()->castAs<clang::FunctionProtoType>();
StrCat(std::format(".spec::<{}>({})", ConvertFunctionPointerType(proto),
GetLambdaSpecializationIndex(call_operator)));
}
StrCat(".call");
}

void Converter::EmitFnPtrCall(clang::CallExpr *expr) {
auto callee = GetCallee(expr);
if (auto lambda = AsLambdaClass(callee->getType())) {
ConvertLambdaCall(expr, lambda);
return;
}
{
Expand Down Expand Up @@ -2014,8 +2034,9 @@ Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) {
auto callee = GetCallee(expr);
unsigned arg_begin = 0;
if (auto op_call = llvm::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
if (clang::isa_and_nonnull<clang::CXXMethodDecl>(
op_call->getDirectCallee())) {
if (auto method = clang::dyn_cast_or_null<clang::CXXMethodDecl>(
op_call->getDirectCallee());
method && !method->isExplicitObjectMemberFunction()) {
arg_begin = 1;
}
}
Expand Down Expand Up @@ -2221,7 +2242,7 @@ void Converter::EmitCall(CallInfo &&info) {
EmitHoistedArgs(info);

if (info.is_fn_ptr_call) {
EmitFnPtrCall(GetCallee(info.expr));
EmitFnPtrCall(info.expr);
} else if (info.is_libc_passthrough) {
auto *direct_callee = info.expr->getDirectCallee();
assert(direct_callee);
Expand Down Expand Up @@ -3926,32 +3947,37 @@ bool Converter::VisitConstantExpr(clang::ConstantExpr *expr) {

bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) {
auto decl = expr->getLambdaClass();
if (decl->captures().empty()) {
if (decl->captures().empty() && !decl->isGenericLambda()) {
ConvertCapturelessLambda(decl);
return false;
}
StrCat(LambdaMacro());
PushParen paren(*this);
if (decl->isGenericLambda()) {
StrCat("Generic", token::kComma);
}
{
PushBrace captures(*this);
auto init = expr->capture_init_begin();
for (auto field : decl->fields()) {
ConvertLambdaCapture(field, *init++);
}
}
StrCat(token::kComma);
ConvertLambdaClosure(decl);
ForEachLambdaCallOperator(decl, [&](clang::CXXMethodDecl *call_operator) {
StrCat(token::kComma);
ConvertLambdaClosure(decl, call_operator);
});
computed_expr_type_ = ComputedExprType::FreshValue;
return false;
}

void Converter::ConvertCapturelessLambda(const clang::CXXRecordDecl *decl) {
auto proto = decl->getLambdaCallOperator()
->getType()
->castAs<clang::FunctionProtoType>();
assert(!decl->isGenericLambda());
auto call_operator = decl->getLambdaCallOperator();
auto proto = call_operator->getType()->castAs<clang::FunctionProtoType>();
StrCat(std::format("FnPtr::<{}>::new", ConvertFunctionPointerType(proto)));
PushParen paren(*this);
ConvertLambdaClosure(decl);
ConvertLambdaClosure(decl, call_operator);
computed_expr_type_ = ComputedExprType::FreshValue;
}

Expand All @@ -3964,8 +3990,8 @@ void Converter::ConvertLambdaCapture(const clang::FieldDecl *field,
StrCat(token::kSemiColon);
}

void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl) {
auto call_operator = decl->getLambdaCallOperator();
void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl,
clang::CXXMethodDecl *call_operator) {
StrCat('|');
for (auto p : call_operator->parameters()) {
StrCat(GetNamedDeclAsString(p), token::kColon, ToString(p->getType()),
Expand All @@ -3975,7 +4001,7 @@ void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl) {
ConvertFunctionReturnType(call_operator);
PushBrace body(*this);
std::optional<PushBrace> unsafe_brace;
if (decl->captures().empty()) {
if (decl->captures().empty() && !decl->isGenericLambda()) {
StrCat(keyword_unsafe_);
unsafe_brace.emplace(*this);
}
Expand Down
12 changes: 9 additions & 3 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,14 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

void ConvertGenericCallExpr(clang::CallExpr *expr);

virtual void EmitFnPtrCall(clang::Expr *callee);
virtual void EmitFnPtrCall(clang::CallExpr *expr);

virtual void ConvertLambdaToFunctionPointer(clang::Expr *lambda);
void ConvertLambdaCall(clang::CallExpr *expr,
const clang::CXXRecordDecl *lambda);

virtual void
ConvertLambdaToFunctionPointer(clang::Expr *lambda,
const clang::CXXConversionDecl *conversion);

virtual void
ConvertFunctionToFunctionPointer(const clang::FunctionDecl *fn_decl);
Expand Down Expand Up @@ -479,7 +484,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
virtual void ConvertLambdaCapture(const clang::FieldDecl *field,
clang::Expr *init);

void ConvertLambdaClosure(const clang::CXXRecordDecl *decl);
void ConvertLambdaClosure(const clang::CXXRecordDecl *decl,
clang::CXXMethodDecl *call_operator);

virtual bool VisitImplicitValueInitExpr(clang::ImplicitValueInitExpr *expr);
virtual bool VisitCXXScalarValueInitExpr(clang::CXXScalarValueInitExpr *expr);
Expand Down
56 changes: 56 additions & 0 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,58 @@ AsLambdaOperatorCall(const clang::FunctionDecl *fn) {
return method;
}

void ForEachLambdaCallOperator(
const clang::CXXRecordDecl *decl,
llvm::function_ref<void(clang::CXXMethodDecl *)> fn) {
if (!decl->isGenericLambda()) {
fn(decl->getLambdaCallOperator());
return;
}
for (auto spec : decl->getDependentLambdaCallOperator()->specializations()) {
fn(clang::cast<clang::CXXMethodDecl>(spec));
}
}

clang::CXXMethodDecl *
AsLambdaCallOperator(const clang::CXXConversionDecl *conversion) {
auto decl = conversion->getParent();
if (!decl->isGenericLambda()) {
return decl->getLambdaCallOperator();
}
auto args = conversion->getTemplateSpecializationArgs()->asArray();
clang::CXXMethodDecl *found = nullptr;
ForEachLambdaCallOperator(decl, [&](clang::CXXMethodDecl *op) {
auto op_args = op->getTemplateSpecializationArgs()->asArray();
if (llvm::equal(args, op_args,
[](const clang::TemplateArgument &a,
const clang::TemplateArgument &b) {
return a.structurallyEquals(b);
})) {
found = op;
}
});
if (!found) {
llvm::report_fatal_error("no call operator matches the lambda conversion");
}
return found;
}

unsigned
GetLambdaSpecializationIndex(const clang::FunctionDecl *call_operator) {
std::optional<unsigned> index;
unsigned i = 0;
ForEachLambdaCallOperator(
clang::cast<clang::CXXMethodDecl>(call_operator)->getParent(),
[&](const clang::CXXMethodDecl *op) {
if (op->getCanonicalDecl() == call_operator->getCanonicalDecl()) {
index = i;
}
++i;
});
assert(index);
return *index;
}

const clang::LambdaCapture *AsLambdaCapture(const clang::FieldDecl *field) {
auto decl = clang::dyn_cast<clang::CXXRecordDecl>(field->getParent());
if (!decl || !decl->isLambda()) {
Expand Down Expand Up @@ -1689,6 +1741,10 @@ clang::Expr *GetCallee(clang::CallExpr *expr) {
return op_call->getArg(0);
}
}
if (auto member_call = clang::dyn_cast<clang::CXXMemberCallExpr>(expr);
member_call && AsLambdaOperatorCall(member_call->getMethodDecl())) {
return member_call->getImplicitObjectArgument();
}
return expr->getCallee();
}

Expand Down
9 changes: 9 additions & 0 deletions cpp2rust/converter/converter_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,15 @@ const clang::CXXRecordDecl *AsLambdaClass(clang::QualType type);

const clang::CXXMethodDecl *AsLambdaOperatorCall(const clang::FunctionDecl *fn);

void ForEachLambdaCallOperator(
const clang::CXXRecordDecl *decl,
llvm::function_ref<void(clang::CXXMethodDecl *)> fn);

clang::CXXMethodDecl *
AsLambdaCallOperator(const clang::CXXConversionDecl *conversion);

unsigned GetLambdaSpecializationIndex(const clang::FunctionDecl *call_operator);

const clang::LambdaCapture *AsLambdaCapture(const clang::FieldDecl *field);

bool IsLambdaCopyOrMoveConstructor(const clang::CXXConstructorDecl *ctor);
Expand Down
20 changes: 15 additions & 5 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1311,7 +1311,8 @@ bool ConverterRefCount::VisitCallExpr(clang::CallExpr *expr) {
expr->getCalleeDecl());
conversion && conversion->getParent()->isLambda()) {
ConvertLambdaToFunctionPointer(clang::cast<clang::CXXMemberCallExpr>(expr)
->getImplicitObjectArgument());
->getImplicitObjectArgument(),
conversion);
return false;
}

Expand Down Expand Up @@ -1546,9 +1547,10 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
return Converter::VisitImplicitCastExpr(expr);
}

void ConverterRefCount::EmitFnPtrCall(clang::Expr *callee) {
if (AsLambdaClass(callee->getType())) {
StrCat(ConvertRValue(callee), ".call");
void ConverterRefCount::EmitFnPtrCall(clang::CallExpr *expr) {
auto callee = GetCallee(expr);
if (auto lambda = AsLambdaClass(callee->getType())) {
ConvertLambdaCall(expr, lambda);
return;
}
Convert(callee);
Expand All @@ -1572,8 +1574,16 @@ void ConverterRefCount::ConvertLambdaCapture(const clang::FieldDecl *field,
Converter::ConvertLambdaCapture(field, init);
}

void ConverterRefCount::ConvertLambdaToFunctionPointer(clang::Expr *lambda) {
void ConverterRefCount::ConvertLambdaToFunctionPointer(
clang::Expr *lambda, const clang::CXXConversionDecl *conversion) {
StrCat(ConvertFreshRValue(lambda));
auto decl = AsLambdaClass(lambda->getType());
if (decl->isGenericLambda()) {
auto call_operator = AsLambdaCallOperator(conversion);
auto proto = call_operator->getType()->castAs<clang::FunctionProtoType>();
StrCat(std::format(".spec::<{}>({})", ConvertFunctionPointerType(proto),
GetLambdaSpecializationIndex(call_operator)));
}
}

void ConverterRefCount::ConvertFunctionToFunctionPointer(
Expand Down
5 changes: 3 additions & 2 deletions cpp2rust/converter/models/converter_refcount.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class ConverterRefCount final : public Converter {

void ConvertPrintf(clang::CallExpr *expr) override;

void EmitFnPtrCall(clang::Expr *callee) override;
void EmitFnPtrCall(clang::CallExpr *expr) override;

bool VisitLambdaExpr(clang::LambdaExpr *expr) override;

Expand All @@ -124,7 +124,8 @@ class ConverterRefCount final : public Converter {
void ConvertLambdaCapture(const clang::FieldDecl *field,
clang::Expr *init) override;

void ConvertLambdaToFunctionPointer(clang::Expr *lambda) override;
void ConvertLambdaToFunctionPointer(
clang::Expr *lambda, const clang::CXXConversionDecl *conversion) override;

void
ConvertFunctionToFunctionPointer(const clang::FunctionDecl *fn_decl) override;
Expand Down
Loading
Loading