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
42 changes: 11 additions & 31 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1720,7 +1720,6 @@ const clang::Expr *Converter::GetParentExpr(const clang::Expr *expr) {
bool Converter::GetFmtArg(clang::Expr *arg, std::string &fmt,
std::string &fmt_args, const char *&fmt_trait,
std::string &fmt_width) {
std::string arg_str = Printer::ToString(ctx_, arg);
if (auto *str_lit =
clang::dyn_cast<clang::StringLiteral>(arg->IgnoreImplicit())) {
if (!IsAsciiStringLiteral(str_lit)) {
Expand All @@ -1734,20 +1733,20 @@ bool Converter::GetFmtArg(clang::Expr *arg, std::string &fmt,
fmt += trim;
} else if (auto ch = GetEscapedUTF8CharLiteral(arg); !ch.empty()) {
fmt += std::move(ch);
} else if (arg_str.contains("std::endl")) {
} else if (IsStdFunction(arg, "endl")) {
fmt += "\\n";
} else if (arg_str.contains("std::hex")) {
} else if (IsStdFunction(arg, "hex")) {
fmt_trait = "x";
} else if (arg_str.contains("std::dec")) {
} else if (IsStdFunction(arg, "dec")) {
fmt_trait = "";
} else if (arg_str.contains("Setw")) {
} else if (IsStdFunction(arg, "setw")) {
fmt_width = Trim(ToString(arg));
} else if (!arg->getType()->isCharType() &&
Mapper::Map(*this, arg->getType()) !=
std::format("Vec<{}>", CharRustType())) {
fmt += ("{:" + fmt_width + fmt_trait + "}");
fmt_width.clear(); // Reset setw after first usage
arg_str = ToString(arg);
auto arg_str = ToString(arg);
if (arg->getType()->isBooleanType()) {
arg_str = std::format("({} as u8)", std::move(arg_str));
}
Expand All @@ -1767,7 +1766,7 @@ bool Converter::GetRawArg(clang::Expr *arg, std::string &raw_args) {
std::string str = ToString(arg);
raw_args += "(&(" + str + ").iter().take((" + str +
").len() - 1).map(|&c| c as u8).collect::<Vec<u8>>()[..]";
} else if (Printer::ToString(ctx_, arg).contains("std::endl")) {
} else if (IsStdFunction(arg, "endl")) {
raw_args += "(&[b'\\n']";
} else if (clang::isa<clang::StringLiteral>(arg->IgnoreImplicit())) {
raw_args += "(b" + GetEscapedStringLiteral(arg);
Expand Down Expand Up @@ -1853,8 +1852,7 @@ void Converter::ConvertCallToOstream(clang::CallExpr *expr) {
}

void Converter::ConvertPrintf(clang::CallExpr *expr) {
bool is_fprintf =
Printer::ToString(ctx_, expr->getCallee()).starts_with("int fprintf");
bool is_fprintf = IsCDecl(expr->getDirectCallee(), "fprintf");

StrCat("printf(");
for (unsigned i = is_fprintf; i < expr->getNumArgs(); ++i) {
Expand Down Expand Up @@ -2338,9 +2336,8 @@ std::optional<Converter::TempMaterializationCtx>
Converter::ConvertCallExpr(clang::CallExpr *expr) {
auto *callee = expr->getCallee();

auto fn = Printer::ToString(ctx_, callee);
bool is_printf = fn.starts_with("int printf");
bool is_fprintf = fn.starts_with("int fprintf");
bool is_printf = IsCDecl(expr->getDirectCallee(), "printf");
bool is_fprintf = IsCDecl(expr->getDirectCallee(), "fprintf");
unsigned format_arg = is_fprintf ? 1 : 0;
if ((is_printf || is_fprintf) &&
clang::isa<clang::StringLiteral>(
Expand Down Expand Up @@ -4295,7 +4292,7 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
if (clang::isa<clang::IncompleteArrayType>(qual_type)) {
return "[]";
}
if (Printer::ToString(ctx_, qual_type).contains("std::array")) {
if (IsStdDecl(qual_type->getAsCXXRecordDecl(), "array")) {
assert(GetTemplateArgs(qual_type).has_value());
auto template_args = *GetTemplateArgs(qual_type);
assert(template_args.size() == 2);
Expand Down Expand Up @@ -4505,24 +4502,7 @@ void Converter::ConvertVarInit(clang::QualType qual_type, clang::Expr *expr) {
StrCat(keyword_mut_);
}
}
auto *ignore_casts = expr->IgnoreCasts();
// FIXME: this looks very complicated
if (auto *ctor = clang::dyn_cast<clang::CXXConstructExpr>(ignore_casts);
ctor && ctor->getNumArgs() != 0 && IsReferenceType(ctor->getArg(0)) &&
clang::isa<clang::CallExpr>(ctor->getArg(0)->IgnoreCasts()) &&
!Mapper::Contains(
ctx_, clang::cast<clang::CallExpr>(ctor->getArg(0)->IgnoreCasts())
->getCallee()) &&
Printer::ToString(ctx_, ctor->getConstructor()->getThisType()) ==
"std::string") {
{
PushParen paren(*this);
StrCat(token::kStar);
PushInitType init_type(*this, qual_type);
Convert(expr);
}
StrCat(".clone()");
} else if (IsReferenceType(expr) || qual_type->isFunctionPointerType()) {
if (IsReferenceType(expr) || qual_type->isFunctionPointerType()) {
PushExprKind push(*this, ExprKind::AddrOf);
PushInitType init_type(*this, qual_type);
Convert(expr, qual_type);
Expand Down
12 changes: 6 additions & 6 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
const char *keyword_mut = keyword::kMut)
: rs_code_(&rs_code), ctx_(ctx), keyword_unsafe_(keyword_unsafe),
keyword_mut_(keyword_mut) {
if (!GetNameGenerator()) {
name_generator_ = std::make_unique<clang::ASTNameGenerator>(ctx);
SetNameGenerator(name_generator_.get());
if (!GetMangleContext()) {
mangle_context_.reset(ctx.createMangleContext());
SetMangleContext(mangle_context_.get());
}
}

virtual ~Converter() {
if (name_generator_) {
SetNameGenerator(nullptr);
if (mangle_context_) {
SetMangleContext(nullptr);
}
}

Expand Down Expand Up @@ -806,7 +806,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

std::string *rs_code_;
clang::ASTContext &ctx_;
std::unique_ptr<clang::ASTNameGenerator> name_generator_;
std::unique_ptr<clang::MangleContext> mangle_context_;
clang::FunctionDecl *curr_function_ = nullptr;
bool in_function_formals_ = false;
enum class MethodTarget : uint8_t {
Expand Down
80 changes: 61 additions & 19 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

#include "converter/lex.h"
#include "converter/mapper.h"
#include "converter/printer.h"
#include "converter/rules/registry.h"

// https://doc.rust-lang.org/reference/keywords.html
Expand Down Expand Up @@ -668,19 +667,38 @@ bool IsConvertibleFunctionDecl(const clang::FunctionDecl *decl) {
return decl->hasBody() && decl->isThisDeclarationADefinition();
}

bool IsStdDecl(const clang::NamedDecl *decl, llvm::StringRef name) {
return decl && decl->isInStdNamespace() && decl->getIdentifier() &&
decl->getName() == name;
}

bool IsUniquePtr(clang::QualType type) {
auto *record_decl = type.getNonReferenceType()->getAsCXXRecordDecl();
return record_decl && record_decl->getNameAsString() == "unique_ptr";
return IsStdDecl(type.getNonReferenceType()->getAsCXXRecordDecl(),
"unique_ptr");
}

bool IsCallToOstream(clang::CallExpr *expr) {
if (auto *op = clang::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
if (auto *record_decl = expr->getType()->getAsCXXRecordDecl()) {
return record_decl->getNameAsString() == "basic_ostream" &&
op->getOperator() == clang::OverloadedOperatorKind::OO_LessLess;
}
auto *op = clang::dyn_cast<clang::CXXOperatorCallExpr>(expr);
return op &&
op->getOperator() == clang::OverloadedOperatorKind::OO_LessLess &&
IsStdDecl(expr->getType()->getAsCXXRecordDecl(), "basic_ostream");
}

bool IsCDecl(const clang::NamedDecl *decl, llvm::StringRef name) {
auto *function = clang::dyn_cast_or_null<clang::FunctionDecl>(decl);
return function && function->isExternC() && function->getIdentifier() &&
function->getName() == name;
}

bool IsStdFunction(const clang::Expr *expr, llvm::StringRef name) {
expr = expr->IgnoreUnlessSpelledInSource();
const clang::NamedDecl *decl = nullptr;
if (auto *call = clang::dyn_cast<clang::CallExpr>(expr)) {
decl = call->getDirectCallee();
} else if (auto *ref = clang::dyn_cast<clang::DeclRefExpr>(expr)) {
decl = clang::dyn_cast<clang::FunctionDecl>(ref->getDecl());
}
return false;
return IsStdDecl(decl, name);
}

bool IsAsciiStringLiteral(const clang::StringLiteral *str) {
Expand Down Expand Up @@ -840,40 +858,64 @@ static std::string GetParamSignature(const clang::Decl *decl) {
return args;
}

static clang::ASTNameGenerator *name_generator = nullptr;
static clang::MangleContext *mangle_context = nullptr;

void SetNameGenerator(clang::ASTNameGenerator *generator) {
name_generator = generator;
void SetMangleContext(clang::MangleContext *context) {
mangle_context = context;
}

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

static std::string GetMangledName(const clang::Decl *decl) {
assert(name_generator);
return name_generator->getName(decl);
assert(mangle_context);
auto *named = clang::cast<clang::NamedDecl>(decl);
if (!mangle_context->shouldMangleDeclName(named)) {
return named->getNameAsString();
}
clang::GlobalDecl global;
if (auto *ctor = clang::dyn_cast<clang::CXXConstructorDecl>(decl)) {
global = clang::GlobalDecl(ctor, clang::Ctor_Complete);
} else if (auto *dtor = clang::dyn_cast<clang::CXXDestructorDecl>(decl)) {
global = clang::GlobalDecl(dtor, clang::Dtor_Complete);
} else {
global = clang::GlobalDecl(named);
}
std::string name;
llvm::raw_string_ostream os(name);
mangle_context->mangleName(global, os);
return name;
}

static std::string
GetMangledTypeName(const clang::ClassTemplateSpecializationDecl *decl) {
assert(mangle_context);
std::string name;
llvm::raw_string_ostream os(name);
mangle_context->mangleCanonicalTypeName(
decl->getASTContext().getCanonicalTagType(decl), os);
return name;
}

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 += GetMangledName(var);
}
if (const auto *self =
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
id += Printer::ToString(ctx, GetTypeForDecl(ctx, self));
id += GetMangledTypeName(self);
}
if (const auto *spec =
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
decl->getLexicalDeclContext());
spec && decl->getLexicalDeclContext() != decl->getDeclContext()) {
id += Printer::ToString(ctx, GetTypeForDecl(ctx, spec));
id += GetMangledTypeName(spec);
}
for (const auto *dc = decl->getDeclContext(); dc; dc = dc->getParent()) {
if (const auto *spec =
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(dc)) {
id += Printer::ToString(ctx, GetTypeForDecl(ctx, spec));
id += GetMangledTypeName(spec);
}
if (const auto *fn = clang::dyn_cast<clang::FunctionDecl>(dc);
fn && fn->getTemplateSpecializationArgs()) {
Expand Down
10 changes: 8 additions & 2 deletions cpp2rust/converter/converter_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,16 @@ bool IsMethodOnPtr(const clang::CXXMethodDecl *method);

bool IsConvertibleFunctionDecl(const clang::FunctionDecl *decl);

bool IsStdDecl(const clang::NamedDecl *decl, llvm::StringRef name);

bool IsUniquePtr(clang::QualType type);

bool IsCallToOstream(clang::CallExpr *expr);

bool IsCDecl(const clang::NamedDecl *decl, llvm::StringRef name);

bool IsStdFunction(const clang::Expr *expr, llvm::StringRef name);

bool IsAsciiStringLiteral(const clang::StringLiteral *str);

bool IsInitExprOfStringLiteral(const clang::InitListExpr *expr);
Expand Down Expand Up @@ -182,9 +188,9 @@ unsigned GetColumnNumber(const clang::Decl *decl);

unsigned GetArraySize(clang::QualType array_type);

void SetNameGenerator(clang::ASTNameGenerator *generator);
void SetMangleContext(clang::MangleContext *context);

clang::ASTNameGenerator *GetNameGenerator();
clang::MangleContext *GetMangleContext();

std::string GetID(const clang::Decl *decl);
std::string GetMethodID(const clang::CXXMethodDecl *decl);
Expand Down
21 changes: 14 additions & 7 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <clang/AST/RecordLayout.h>
#include <clang/Basic/OperatorKinds.h>
#include <clang/Lex/Lexer.h>
#include <llvm/Support/ErrorHandling.h>

#include <algorithm>
Expand All @@ -15,7 +16,6 @@
#include "converter/converter_lib.h"
#include "converter/lex.h"
#include "converter/mapper.h"
#include "converter/printer.h"
#include "converter/rules/registry.h"

namespace cpp2rust {
Expand Down Expand Up @@ -1234,19 +1234,26 @@ static std::vector<const char *> printf2fmt(std::string &format) {
}

void ConverterRefCount::ConvertPrintf(clang::CallExpr *expr) {
bool is_fprintf =
Printer::ToString(ctx_, expr->getCallee()).starts_with("int fprintf");
bool is_fprintf = IsCDecl(expr->getDirectCallee(), "fprintf");
auto format = GetEscapedStringLiteral(clang::cast<clang::StringLiteral>(
expr->getArg(is_fprintf)->IgnoreImplicit()));
bool ends_newline = format.ends_with("\\n\"");

auto fd = is_fprintf ? Printer::ToString(ctx_, expr->getArg(0)) : "stdout";
if (fd == "stdout" || fd == "__stdoutp") {
llvm::StringRef stream = "stdout";
if (is_fprintf) {
auto loc = expr->getArg(0)->IgnoreParenImpCasts()->getBeginLoc();
stream = loc.isMacroID()
? clang::Lexer::getImmediateMacroName(
loc, ctx_.getSourceManager(), ctx_.getLangOpts())
: "";
}
if (stream == "stdout") {
StrCat(ends_newline ? "println!(" : "print!(");
} else if (fd == "stderr" || fd == "__stderrp") {
} else if (stream == "stderr") {
StrCat(ends_newline ? "eprintln!(" : "eprint!(");
} else {
llvm::errs() << "Unknown fprintf fd: " << fd << '\n';
llvm::errs() << "Unknown fprintf fd:\n";
expr->getArg(0)->dump(llvm::errs(), ctx_);
exit(1);
}
if (ends_newline) {
Expand Down
Loading