From 8981e9eb8b5af68b00c3afb307bdf4e8a6cf95b8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Apr 2026 14:04:30 +0000 Subject: [PATCH 1/4] perf: eliminate spurious string copies in cpp2rust converter - mapper.cpp: use std::move() when passing local strings to normalizeTranslationRule() to avoid unnecessary copies in ToString() - converter.cpp recordDerivesCopy: cache Mapper::Map(f->getType()) result to avoid calling it twice per field - converter.cpp GetDefaultAsString: cache Mapper::ToString(qual_type) result to avoid calling it twice in successive else-if branches - converter.cpp EmitRustStruct/VisitCXXRecordDecl: replace std::string(keyword::kImpl) + ' ' + name with std::format to avoid constructing multiple temporary strings - converter_lib.cpp GetFileName: construct std::filesystem::path directly from StringRef iterators, eliminating the intermediate file_name_as_string copy and reusing file_path.string() as fallback Agent-Logs-Url: https://github.com/Cpp2Rust/cpp2rust/sessions/b538d15a-35a7-4c43-93f3-6621eabaf105 Co-authored-by: nunoplopes <2998477+nunoplopes@users.noreply.github.com> --- cpp2rust/converter/converter.cpp | 78 +++++++++++++++------------- cpp2rust/converter/converter_lib.cpp | 5 +- cpp2rust/converter/lex.h | 4 +- cpp2rust/converter/mapper.cpp | 4 +- 4 files changed, 47 insertions(+), 44 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 1b3ed81e..f0a98968 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -552,7 +552,8 @@ static bool recordDerivesCopy(const clang::RecordDecl *decl) { for (auto f : decl->fields()) { // Records that contain std::vector, std::array, std::string or anything // that is translated to Vec<>, do not derive Copy - if (Mapper::Map(f->getType()).starts_with("Vec<")) { + auto mapped = Mapper::Map(f->getType()); + if (mapped.starts_with("Vec<")) { return false; } @@ -560,7 +561,7 @@ static bool recordDerivesCopy(const clang::RecordDecl *decl) { return false; } - if (Mapper::Map(f->getType()).starts_with("BTreeMap<")) { + if (mapped.starts_with("BTreeMap<")) { return false; } @@ -653,7 +654,7 @@ void Converter::EmitRustStruct(clang::RecordDecl *decl) { auto struct_name = GetRecordName(cxx); ConvertCXXMethodDecls( - cxx, std::string(keyword::kImpl) + ' ' + struct_name, + cxx, std::format("{} {}", keyword::kImpl, struct_name), [](const auto *method) { return !method->isImplicit() && !(method->getDefinition() && @@ -701,7 +702,7 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { if (decl->isStruct() || decl->isClass()) { for (auto c : GetTemplateInstantiatedCtors(decl)) { if (!decl_ids_.contains(GetID(c))) { - StrCat(std::string(keyword::kImpl) + ' ' + GetRecordName(decl)); + StrCat(keyword::kImpl, GetRecordName(decl)); PushBrace brace(*this); VisitCXXMethodDecl(c); } @@ -2785,40 +2786,43 @@ std::string Converter::GetDefaultAsString(clang::QualType qual_type) { } else if (auto *array_type = clang::dyn_cast(qual_type)) { return GetDefaultAsString(array_type->getElementType()); - } else if (Mapper::ToString(qual_type) == "struct std::pair") { - auto template_args = *GetTemplateArgs(qual_type); - auto first_type = template_args[0].getAsType(); - auto second_type = template_args[1].getAsType(); - return std::format("({}, {})", GetDefaultAsString(first_type), - GetDefaultAsString(second_type)); - } else if (Mapper::ToString(qual_type).contains("std::array")) { - assert(GetTemplateArgs(qual_type).has_value()); - auto template_args = *GetTemplateArgs(qual_type); - assert(template_args.size() == 2); - auto array_size = template_args[1]; - unsigned size = 0; - switch (array_size.getKind()) { - case clang::TemplateArgument::Expression: { - auto array_size_expr = array_size.getAsExpr(); - assert(array_size_expr && !array_size_expr->isValueDependent()); - clang::Expr::EvalResult result; - ENSURE(array_size_expr->EvaluateAsInt(result, ctx_)); - size = result.Val.getInt().getZExtValue(); - break; - } - case clang::TemplateArgument::Integral: { - size = array_size.getAsIntegral().getZExtValue(); - break; - } - default: - assert(0 && "Unsupported array size kind"); - break; - } - return std::format( - "std::array::from_fn::<_, {}, _>(|_| Default::default()).to_vec()", - size); } else { - return GetDefaultAsStringFallback(qual_type); + auto qual_type_str = Mapper::ToString(qual_type); + if (qual_type_str == "struct std::pair") { + auto template_args = *GetTemplateArgs(qual_type); + auto first_type = template_args[0].getAsType(); + auto second_type = template_args[1].getAsType(); + return std::format("({}, {})", GetDefaultAsString(first_type), + GetDefaultAsString(second_type)); + } else if (qual_type_str.contains("std::array")) { + assert(GetTemplateArgs(qual_type).has_value()); + auto template_args = *GetTemplateArgs(qual_type); + assert(template_args.size() == 2); + auto array_size = template_args[1]; + unsigned size = 0; + switch (array_size.getKind()) { + case clang::TemplateArgument::Expression: { + auto array_size_expr = array_size.getAsExpr(); + assert(array_size_expr && !array_size_expr->isValueDependent()); + clang::Expr::EvalResult result; + ENSURE(array_size_expr->EvaluateAsInt(result, ctx_)); + size = result.Val.getInt().getZExtValue(); + break; + } + case clang::TemplateArgument::Integral: { + size = array_size.getAsIntegral().getZExtValue(); + break; + } + default: + assert(0 && "Unsupported array size kind"); + break; + } + return std::format( + "std::array::from_fn::<_, {}, _>(|_| Default::default()).to_vec()", + size); + } else { + return GetDefaultAsStringFallback(qual_type); + } } } diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 4d561fcc..88a4c9b1 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -268,11 +268,10 @@ std::string GetFileName(const clang::Decl *decl) { const auto &ctx = decl->getASTContext(); const auto full_location = ctx.getFullLoc(decl->getBeginLoc()); const auto file_name = ctx.getSourceManager().getFilename(full_location); - const auto file_name_as_string = file_name.str(); - const std::filesystem::path file_path(file_name_as_string); + const std::filesystem::path file_path(file_name.begin(), file_name.end()); return std::filesystem::exists(file_path) ? std::filesystem::canonical(file_path).string() - : file_name_as_string; + : file_path.string(); } unsigned GetLineNumber(const clang::Decl *decl) { diff --git a/cpp2rust/converter/lex.h b/cpp2rust/converter/lex.h index db69958d..9629daac 100644 --- a/cpp2rust/converter/lex.h +++ b/cpp2rust/converter/lex.h @@ -13,7 +13,7 @@ inline constexpr const char *kSemiColon = ";\n"; inline constexpr char kComma = ','; inline constexpr char kColon = ':'; inline constexpr const char *kDoubleColon = "::"; -inline constexpr const char *kAssign = "="; +inline constexpr char kAssign = '='; inline constexpr char kOpenParen = '('; inline constexpr char kCloseParen = ')'; inline constexpr char kDot = '.'; @@ -22,7 +22,7 @@ inline constexpr const char *kDiff = "!="; inline constexpr char kZero = '0'; inline constexpr char kOne = '1'; inline constexpr char kRef = '&'; -inline constexpr const char *kStar = "*"; +inline constexpr char kStar = '*'; inline constexpr const char *kArrow = "->"; inline constexpr char kHash = '#'; inline constexpr char kMinus = '-'; diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 425cf805..a57600fa 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -732,7 +732,7 @@ std::string ToString(clang::QualType qual_type) { std::string type; llvm::raw_string_ostream os(type); normalizeQualType(qual_type).print(os, getPrintPolicy()); - return normalizeTranslationRule(type); + return normalizeTranslationRule(std::move(type)); } std::string ToString(const clang::NamedDecl *decl) { @@ -753,7 +753,7 @@ std::string ToString(const clang::NamedDecl *decl) { if (!func_decl) { decl->printQualifiedName(os, getPrintPolicy()); - return normalizeTranslationRule(out); + return normalizeTranslationRule(std::move(out)); } os << ToString(func_decl->getReturnType()) << " "; From 4c1beff88d721e3cd9d996d1d5f64507f4fb1f54 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 28 Apr 2026 15:17:48 +0100 Subject: [PATCH 2/4] edits --- cpp2rust/converter/mapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index a57600fa..9193b32f 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -798,7 +798,7 @@ std::string ToString(const clang::NamedDecl *decl) { } } - return normalizeTranslationRule(os.str()); + return normalizeTranslationRule(std::move(out)); } std::string ToString(const clang::Expr *expr) { From 3638feef16020134fdb75f5dbe88cccb4e2ebf28 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 28 Apr 2026 15:34:12 +0100 Subject: [PATCH 3/4] edits --- cpp2rust/converter/converter.cpp | 8 +++++--- cpp2rust/converter/lex.h | 2 +- cpp2rust/converter/models/converter_refcount.cpp | 8 +++++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index f0a98968..5cad686c 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1876,7 +1876,7 @@ bool Converter::VisitBinaryOperator(clang::BinaryOperator *expr) { auto *rhs = expr->getRHS(); auto lhs_type = lhs->getType(); auto rhs_type = rhs->getType(); - std::string opcode_as_string = expr->getOpcodeStr().str(); + std::string_view opcode_as_string = expr->getOpcodeStr(); if (auto *cmpd_assign_op = llvm::dyn_cast(expr); @@ -1902,7 +1902,9 @@ bool Converter::VisitBinaryOperator(clang::BinaryOperator *expr) { Convert(lhs); ConvertCast(computation_result_type); } - StrCat(std::regex_replace(opcode_as_string, std::regex("="), "")); + std::string op(opcode_as_string); + op.erase(std::remove(op.begin(), op.end(), '='), op.end()); + StrCat(op); Convert(rhs); } if (lhs_type->isBooleanType()) { @@ -2207,7 +2209,7 @@ bool Converter::VisitParenExpr(clang::ParenExpr *expr) { bool Converter::ConvertCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr) { switch (expr->getOperator()) { case clang::OverloadedOperatorKind::OO_Equal: - ConvertAssignment(expr->getArg(0), expr->getArg(1), token::kAssign); + ConvertAssignment(expr->getArg(0), expr->getArg(1), "="); break; case clang::OverloadedOperatorKind::OO_Star: case clang::OverloadedOperatorKind::OO_Arrow: diff --git a/cpp2rust/converter/lex.h b/cpp2rust/converter/lex.h index 9629daac..cf7da5db 100644 --- a/cpp2rust/converter/lex.h +++ b/cpp2rust/converter/lex.h @@ -22,7 +22,7 @@ inline constexpr const char *kDiff = "!="; inline constexpr char kZero = '0'; inline constexpr char kOne = '1'; inline constexpr char kRef = '&'; -inline constexpr char kStar = '*'; +inline constexpr const char *kStar = "*"; inline constexpr const char *kArrow = "->"; inline constexpr char kHash = '#'; inline constexpr char kMinus = '-'; diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 0442ae75..93890277 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1144,7 +1144,7 @@ bool ConverterRefCount::VisitBinaryOperator(clang::BinaryOperator *expr) { auto *rhs = expr->getRHS(); auto lhs_type = lhs->getType(); auto rhs_type = rhs->getType(); - std::string opcode_as_string = expr->getOpcodeStr().str(); + std::string_view opcode_as_string = expr->getOpcodeStr(); if (auto *assign = llvm::dyn_cast(expr); assign && lhs_type != assign->getComputationResultType()) { @@ -1165,7 +1165,9 @@ bool ConverterRefCount::VisitBinaryOperator(clang::BinaryOperator *expr) { StrCat(ConvertRValue(lhs)); ConvertCast(computation_result_type); } - StrCat(std::regex_replace(opcode_as_string, std::regex("="), "")); + std::string op(opcode_as_string); + op.erase(std::remove(op.begin(), op.end(), '='), op.end()); + StrCat(op); Convert(rhs); } if (lhs_type->isBooleanType()) { @@ -1805,7 +1807,7 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr( clang::CXXOperatorCallExpr *expr) { switch (expr->getOperator()) { case clang::OverloadedOperatorKind::OO_Equal: - ConvertAssignment(expr->getArg(0), expr->getArg(1), token::kAssign); + ConvertAssignment(expr->getArg(0), expr->getArg(1), "="); break; case clang::OverloadedOperatorKind::OO_Arrow: From 554bed8013a5c4c8795a32989a2268f50d13c9df Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 28 Apr 2026 16:28:02 +0100 Subject: [PATCH 4/4] edits --- cpp2rust/converter/models/converter_refcount.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 93890277..f19a7d8a 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "compiler.h" #include "converter/converter_lib.h"