From 013ee3322f54b75d66b3a28df0612c7d3caa4ae3 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 13:00:19 +0100 Subject: [PATCH 1/4] Drop printer depdendncies in converter --- cpp2rust/converter/converter.cpp | 23 +++++------ cpp2rust/converter/converter_lib.cpp | 39 +++++++++++++++---- cpp2rust/converter/converter_lib.h | 6 +++ .../converter/models/converter_refcount.cpp | 18 +++++---- 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 5aba7cecc..2354a7cc0 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -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(arg->IgnoreImplicit())) { if (!IsAsciiStringLiteral(str_lit)) { @@ -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)); } @@ -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::>()[..]"; - } else if (Printer::ToString(ctx_, arg).contains("std::endl")) { + } else if (IsStdFunction(arg, "endl")) { raw_args += "(&[b'\\n']"; } else if (clang::isa(arg->IgnoreImplicit())) { raw_args += "(b" + GetEscapedStringLiteral(arg); @@ -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) { @@ -2338,9 +2336,8 @@ std::optional 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( @@ -4295,7 +4292,7 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) { if (clang::isa(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); diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index edfdaa46f..0b7fa621b 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -668,19 +668,42 @@ 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(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(expr); + return op && + op->getOperator() == clang::OverloadedOperatorKind::OO_LessLess && + IsStdDecl(expr->getType()->getAsCXXRecordDecl(), "basic_ostream"); +} + +bool IsCDecl(const clang::NamedDecl *decl, llvm::StringRef name) { + bool is_extern_c = false; + if (auto *function = clang::dyn_cast_or_null(decl)) { + is_extern_c = function->isExternC(); + } else if (auto *var = clang::dyn_cast_or_null(decl)) { + is_extern_c = var->isExternC(); } - return false; + return is_extern_c && decl->getIdentifier() && decl->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(expr)) { + decl = call->getDirectCallee(); + } else if (auto *ref = clang::dyn_cast(expr)) { + decl = clang::dyn_cast(ref->getDecl()); + } + return IsStdDecl(decl, name); } bool IsAsciiStringLiteral(const clang::StringLiteral *str) { diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index f46c81958..892cbf143 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -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); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index c6f98afaf..194812d19 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -15,7 +15,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 { @@ -1234,19 +1233,24 @@ static std::vector 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( 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") { + const clang::NamedDecl *stream = nullptr; + if (auto *ref = clang::dyn_cast( + expr->getArg(0)->IgnoreParenImpCasts())) { + stream = ref->getDecl(); + } + if (!is_fprintf || IsCDecl(stream, "stdout") || + IsCDecl(stream, "__stdoutp")) { StrCat(ends_newline ? "println!(" : "print!("); - } else if (fd == "stderr" || fd == "__stderrp") { + } else if (IsCDecl(stream, "stderr") || IsCDecl(stream, "__stderrp")) { 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) { From ed856e04617cb3ce73628ec45578adef9c04e620 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 13:09:38 +0100 Subject: [PATCH 2/4] Drop untaken branch --- cpp2rust/converter/converter.cpp | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 2354a7cc0..9631cb3cc 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -4502,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(ignore_casts); - ctor && ctor->getNumArgs() != 0 && IsReferenceType(ctor->getArg(0)) && - clang::isa(ctor->getArg(0)->IgnoreCasts()) && - !Mapper::Contains( - ctx_, clang::cast(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); From 505326ecde20aaa947e8dbdb6bc4497ba1a2a771 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 13:14:48 +0100 Subject: [PATCH 3/4] Prefer mangled name over printer --- cpp2rust/converter/converter.h | 12 ++++---- cpp2rust/converter/converter_lib.cpp | 45 +++++++++++++++++++++------- cpp2rust/converter/converter_lib.h | 4 +-- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 28fa6ed71..a3f33758d 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -35,15 +35,15 @@ class Converter : public clang::RecursiveASTVisitor { 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(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); } } @@ -806,7 +806,7 @@ class Converter : public clang::RecursiveASTVisitor { std::string *rs_code_; clang::ASTContext &ctx_; - std::unique_ptr name_generator_; + std::unique_ptr mangle_context_; clang::FunctionDecl *curr_function_ = nullptr; bool in_function_formals_ = false; enum class MethodTarget : uint8_t { diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 0b7fa621b..31f734d52 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -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 @@ -863,21 +862,45 @@ 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(decl); + if (!mangle_context->shouldMangleDeclName(named)) { + return named->getNameAsString(); + } + clang::GlobalDecl global; + if (auto *ctor = clang::dyn_cast(decl)) { + global = clang::GlobalDecl(ctor, clang::Ctor_Complete); + } else if (auto *dtor = clang::dyn_cast(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(decl)) { @@ -885,18 +908,18 @@ static std::string GetLexicalSpecializationID(const clang::Decl *decl) { } if (const auto *self = clang::dyn_cast(decl)) { - id += Printer::ToString(ctx, GetTypeForDecl(ctx, self)); + id += GetMangledTypeName(self); } if (const auto *spec = clang::dyn_cast( 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(dc)) { - id += Printer::ToString(ctx, GetTypeForDecl(ctx, spec)); + id += GetMangledTypeName(spec); } if (const auto *fn = clang::dyn_cast(dc); fn && fn->getTemplateSpecializationArgs()) { diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 892cbf143..3784cb1a8 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -188,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); From d8c452240a844e9e5654ef84c83970fe253c6bc9 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 13:22:04 +0100 Subject: [PATCH 4/4] Stop spelling library specific names __stdoutp and __stderrp --- cpp2rust/converter/converter_lib.cpp | 10 +++------- .../converter/models/converter_refcount.cpp | 17 ++++++++++------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 31f734d52..50b18a9d2 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -685,13 +685,9 @@ bool IsCallToOstream(clang::CallExpr *expr) { } bool IsCDecl(const clang::NamedDecl *decl, llvm::StringRef name) { - bool is_extern_c = false; - if (auto *function = clang::dyn_cast_or_null(decl)) { - is_extern_c = function->isExternC(); - } else if (auto *var = clang::dyn_cast_or_null(decl)) { - is_extern_c = var->isExternC(); - } - return is_extern_c && decl->getIdentifier() && decl->getName() == name; + auto *function = clang::dyn_cast_or_null(decl); + return function && function->isExternC() && function->getIdentifier() && + function->getName() == name; } bool IsStdFunction(const clang::Expr *expr, llvm::StringRef name) { diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 194812d19..470ae4317 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -1238,15 +1239,17 @@ void ConverterRefCount::ConvertPrintf(clang::CallExpr *expr) { expr->getArg(is_fprintf)->IgnoreImplicit())); bool ends_newline = format.ends_with("\\n\""); - const clang::NamedDecl *stream = nullptr; - if (auto *ref = clang::dyn_cast( - expr->getArg(0)->IgnoreParenImpCasts())) { - stream = ref->getDecl(); + 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 (!is_fprintf || IsCDecl(stream, "stdout") || - IsCDecl(stream, "__stdoutp")) { + if (stream == "stdout") { StrCat(ends_newline ? "println!(" : "print!("); - } else if (IsCDecl(stream, "stderr") || IsCDecl(stream, "__stderrp")) { + } else if (stream == "stderr") { StrCat(ends_newline ? "eprintln!(" : "eprint!("); } else { llvm::errs() << "Unknown fprintf fd:\n";