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
31 changes: 26 additions & 5 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "converter/converter.h"

#include <clang/AST/APValue.h>
#include <clang/AST/IgnoreExpr.h>
#include <clang/AST/ParentMapContext.h>
#include <clang/Basic/LangOptions.h>
#include <clang/Basic/SourceManager.h>
Expand Down Expand Up @@ -514,6 +515,9 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) {
ENSURE(decl_ids_.insert(GetID(decl)).second);
global_inits_.push_back(ForceGlobalInit(decl));
} else if (decl->isStaticLocal()) {
if (!globals_.insert(name).second) {
return false;
}
StrCat(keyword::kStatic, keyword_mut_);
} else if (decl->isLocalVarDecl()) {
StrCat(keyword::kLet);
Expand Down Expand Up @@ -2004,6 +2008,16 @@ std::string Converter::GetFunctionRefName(const clang::FunctionDecl *fn_decl) {

void Converter::ConvertFunctionToFunctionPointer(
const clang::FunctionDecl *fn_decl) {
if (auto *method = clang::dyn_cast<clang::CXXMethodDecl>(fn_decl);
method && method->isLambdaStaticInvoker()) {
assert(!method->getParent()->isGenericLambda());
StrCat("Some");
PushParen paren(*this);
ConvertLambdaClosure(method->getParent(),
method->getParent()->getLambdaCallOperator());
computed_expr_type_ = ComputedExprType::FreshPointer;
return;
}
StrCat(std::format("Some({})", GetFunctionRefName(fn_decl)));
computed_expr_type_ = ComputedExprType::FreshPointer;
}
Expand Down Expand Up @@ -2055,7 +2069,11 @@ Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) {
unsigned num_named_params =
function ? function->getNumParams() : proto->getNumParams();
info.is_variadic = function ? function->isVariadic() : proto->isVariadic();
info.is_fn_ptr_call = !function || AsLambdaClass(callee->getType());
info.is_fn_ptr_call =
!function || AsLambdaClass(callee->getType()) ||
clang::isa<clang::SubstNonTypeTemplateParmExpr>(
clang::IgnoreExprNodes(callee, clang::IgnoreParensSingleStep,
clang::IgnoreImplicitCastsSingleStep));
info.is_libc_passthrough = RuleRegistry::IsLibcPassthrough(ctx_, expr);

for (unsigned i = 0; i < num_named_params && i < num_args; ++i) {
Expand Down Expand Up @@ -3232,6 +3250,13 @@ std::string Converter::ConvertDeclRef(clang::Expr *expr,
}

bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
if (auto param =
clang::dyn_cast<clang::TemplateParamObjectDecl>(expr->getDecl());
param && AsLambdaClass(param->getType())) {
StrCat(GetDefaultAsString(param->getType()));
computed_expr_type_ = ComputedExprType::FreshValue;
return false;
}
if (auto init = AsLambdaUncapturedConstant(curr_function_, expr)) {
Convert(init);
return false;
Expand Down Expand Up @@ -4259,10 +4284,6 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
std::string Converter::GetDefaultAsString(clang::QualType qual_type) {
if (auto lambda = AsLambdaClass(qual_type);
lambda && lambda->captures().empty()) {
if (HasStaticLocal(lambda->getLambdaCallOperator()->getBody())) {
llvm::report_fatal_error("default-constructed lambda with a static local "
"is not supported yet");
}
Buffer buf(*this);
ConvertCapturelessLambda(lambda);
return std::move(buf).str();
Expand Down
16 changes: 14 additions & 2 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
// Distributed under the MIT license that can be found in the LICENSE file.

#include <clang/AST/ASTContext.h>
#include <clang/AST/Mangle.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Sema/Sema.h>

#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
Expand All @@ -32,9 +34,18 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
const char *keyword_unsafe = "unsafe",
const char *keyword_mut = keyword::kMut)
: rs_code_(&rs_code), ctx_(ctx), keyword_unsafe_(keyword_unsafe),
keyword_mut_(keyword_mut) {}
keyword_mut_(keyword_mut) {
if (!GetNameGenerator()) {
name_generator_ = std::make_unique<clang::ASTNameGenerator>(ctx);
SetNameGenerator(name_generator_.get());
}
}

virtual ~Converter() = default;
virtual ~Converter() {
if (name_generator_) {
SetNameGenerator(nullptr);
}
}

Converter(const Converter &) = delete;
Converter &operator=(const Converter &) = delete;
Expand Down Expand Up @@ -784,6 +795,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

std::string *rs_code_;
clang::ASTContext &ctx_;
std::unique_ptr<clang::ASTNameGenerator> name_generator_;
clang::FunctionDecl *curr_function_ = nullptr;
bool in_function_formals_ = false;
enum class MethodTarget : uint8_t {
Expand Down
60 changes: 38 additions & 22 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,24 @@ std::string GetNumAsString(llvm::APFloat value) {
bool IsUserDefinedDecl(const clang::Decl *decl) {
const auto &ctx = decl->getASTContext();
const auto &src_mgr = ctx.getSourceManager();
if (auto fn = llvm::dyn_cast<clang::FunctionDecl>(decl)) {
if (const clang::FunctionDecl *definition = nullptr;
fn->isDefined(definition)) {
decl = definition;
} else if (llvm::any_of(fn->redecls(), [&](auto redecl) {
return src_mgr.isInSystemHeader(redecl->getLocation());
})) {
return false;
}
} else if (auto var = llvm::dyn_cast<clang::VarDecl>(decl)) {
if (auto definition = var->getDefinition()) {
decl = definition;
} else if (llvm::any_of(var->redecls(), [&](auto redecl) {
return src_mgr.isInSystemHeader(redecl->getLocation());
})) {
return false;
}
}
auto src_loc = decl->getLocation();
if (auto *spec =
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl);
Expand Down Expand Up @@ -822,12 +840,25 @@ static std::string GetParamSignature(const clang::Decl *decl) {
return args;
}

static clang::ASTNameGenerator *name_generator = nullptr;

void SetNameGenerator(clang::ASTNameGenerator *generator) {
name_generator = generator;
}

clang::ASTNameGenerator *GetNameGenerator() { return name_generator; }

static std::string GetMangledName(const clang::Decl *decl) {
assert(name_generator);
return name_generator->getName(decl);
}

static std::string GetLexicalSpecializationID(const clang::Decl *decl) {
auto &ctx = decl->getASTContext();
std::string id;
if (const auto *var =
clang::dyn_cast<clang::VarTemplateSpecializationDecl>(decl)) {
id += clang::ASTNameGenerator(var->getASTContext()).getName(var);
id += GetMangledName(var);
}
if (const auto *self =
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
Expand All @@ -846,7 +877,7 @@ static std::string GetLexicalSpecializationID(const clang::Decl *decl) {
}
if (const auto *fn = clang::dyn_cast<clang::FunctionDecl>(dc);
fn && fn->getTemplateSpecializationArgs()) {
id += clang::ASTNameGenerator(fn->getASTContext()).getName(fn);
id += GetMangledName(fn);
}
}
return id;
Expand Down Expand Up @@ -919,9 +950,7 @@ std::string DisambiguateAnonymousTag(const clang::TagDecl *tag) {
static std::unordered_map<std::string, size_t> type_mapping;

static size_t GetDeclId(const clang::NamedDecl *decl, bool internal) {
std::string key =
clang::ASTNameGenerator(decl->getASTContext()).getName(decl) +
GetParamSignature(decl);
std::string key = GetMangledName(decl) + GetParamSignature(decl);
if (internal) {
key += GetLocationID(decl);
}
Expand Down Expand Up @@ -982,9 +1011,11 @@ std::string GetNamedDeclAsString(const clang::NamedDecl *decl) {
target = record;
}
}
auto *record = clang::dyn_cast<clang::CXXRecordDecl>(target);
return std::format(
"anon_{}", type_mapping.try_emplace(GetID(target), type_mapping.size())
.first->second);
"{}_{}", record && record->isLambda() ? "lambda" : "anon",
type_mapping.try_emplace(GetID(target), type_mapping.size())
.first->second);
}

std::optional<size_t> id;
Expand Down Expand Up @@ -1346,21 +1377,6 @@ clang::QualType GetDeclRefType(const clang::FunctionDecl *fn,
return field ? field->getType() : decl->getType();
}

bool HasStaticLocal(const clang::Stmt *stmt) {
if (!stmt) {
return false;
}
if (auto decl_stmt = clang::dyn_cast<clang::DeclStmt>(stmt)) {
for (auto decl : decl_stmt->decls()) {
if (auto var = clang::dyn_cast<clang::VarDecl>(decl);
var && var->isStaticLocal()) {
return true;
}
}
}
return llvm::any_of(stmt->children(), HasStaticLocal);
}

bool IsUserOperatorCall(const clang::CXXOperatorCallExpr *expr) {
const auto *callee = expr->getDirectCallee();
if (!callee || AsLambdaOperatorCall(callee)) {
Expand Down
7 changes: 5 additions & 2 deletions cpp2rust/converter/converter_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <clang/AST/Decl.h>
#include <clang/AST/DeclCXX.h>
#include <clang/AST/Expr.h>
#include <clang/AST/Mangle.h>
#include <clang/AST/StmtCXX.h>
#include <clang/AST/Type.h>
#include <llvm/ADT/APSInt.h>
Expand Down Expand Up @@ -181,6 +182,10 @@ unsigned GetColumnNumber(const clang::Decl *decl);

unsigned GetArraySize(clang::QualType array_type);

void SetNameGenerator(clang::ASTNameGenerator *generator);

clang::ASTNameGenerator *GetNameGenerator();

std::string GetID(const clang::Decl *decl);
std::string GetMethodID(const clang::CXXMethodDecl *decl);

Expand Down Expand Up @@ -247,8 +252,6 @@ clang::QualType GetDeclRefType(const clang::FunctionDecl *fn,
const clang::Expr *expr,
const clang::ValueDecl *decl);

bool HasStaticLocal(const clang::Stmt *stmt);

bool IsSameTypeComparison(const clang::FunctionDecl *fn,
const clang::CXXRecordDecl *record);

Expand Down
6 changes: 6 additions & 0 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1567,6 +1567,12 @@ void ConverterRefCount::ConvertLambdaToFunctionPointer(

void ConverterRefCount::ConvertFunctionToFunctionPointer(
const clang::FunctionDecl *fn_decl) {
if (auto *method = clang::dyn_cast<clang::CXXMethodDecl>(fn_decl);
method && method->isLambdaStaticInvoker()) {
ConvertCapturelessLambda(method->getParent());
computed_expr_type_ = ComputedExprType::FreshPointer;
return;
}
StrCat(std::format("FnPtr::<{}>::new({})",
ConvertFunctionPointerType(
fn_decl->getType()->getAs<clang::FunctionProtoType>()),
Expand Down
10 changes: 6 additions & 4 deletions cpp2rust/converter/rules/rules_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,10 +389,7 @@ std::string ConstructorKey(const std::string &class_key) {
}

std::string FunctionKey(const clang::FunctionDecl *decl) {
if (const clang::FunctionDecl *definition = nullptr;
decl->isDefined(definition) &&
!decl->getASTContext().getSourceManager().isInSystemHeader(
definition->getLocation())) {
if (decl->isDefined() && IsUserDefinedDecl(decl)) {
return {};
}
if (auto method = llvm::dyn_cast<clang::CXXMethodDecl>(decl)) {
Expand All @@ -409,6 +406,11 @@ std::string DeclKey(const clang::NamedDecl *decl) {
if (auto fn = decl->getAsFunction()) {
return FunctionKey(fn);
}
if (auto var = llvm::dyn_cast<clang::VarDecl>(decl);
var && var->hasDefinition() != clang::VarDecl::DeclarationOnly &&
IsUserDefinedDecl(var)) {
return {};
}
if (auto record = llvm::dyn_cast<clang::RecordDecl>(decl->getDeclContext())) {
return MemberKey(ClassKey(record), MemberName(decl->getDeclName()));
}
Expand Down
1 change: 1 addition & 0 deletions tests/unit/lambda_as_field.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// ADDITIONAL_COMPILE_FLAGS: -std=c++23
// no-compile
// Blocked by https://github.com/Cpp2Rust/cpp2rust/issues/435
#include <assert.h>
#include <utility>

Expand Down
1 change: 1 addition & 0 deletions tests/unit/lambda_decltype_type.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// ADDITIONAL_COMPILE_FLAGS: -std=c++23
// no-compile
// Blocked by https://github.com/Cpp2Rust/cpp2rust/issues/435
#include <assert.h>

template <typename Cmp> struct Sorted {
Expand Down
9 changes: 5 additions & 4 deletions tests/unit/lambda_immediate_init.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// no-compile: refcount
// translation-fail: unsafe
#include <assert.h>

int pick(int x = [] { return 237; }()) { return x; }

struct S {
int j = 10;
int i = [this]() { return j * 2; }();
// Below will only work after: https://github.com/Cpp2Rust/cpp2rust/issues/248
// int i = [this]() { return j * 2; }();
int k = [] { return 3; }() + 1;
};

Expand All @@ -23,11 +22,13 @@ int main() {
assert(pick(1) == 1);

S s;
assert(s.i == 20);
// assert(s.i == 20);
assert(s.k == 4);

/*
S t{5};
assert(t.i == 10);
*/

assert(g == 10);

Expand Down
1 change: 0 additions & 1 deletion tests/unit/lambda_static_local.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// ADDITIONAL_COMPILE_FLAGS: -std=c++23
// translation-fail
#include <assert.h>

static int a;
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/lambda_to_fn_ptr.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// ADDITIONAL_COMPILE_FLAGS: -std=c++23
// translation-fail
// no-compile
#include <assert.h>
#include <stdarg.h>

Expand Down
Loading
Loading