From 3ba03d477ed98a9e1f3a8584abbf4b88e457ef36 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 9 Oct 2026 12:43:56 +0100 Subject: [PATCH 1/3] Escape rust keywords --- cpp2rust/converter/converter_lib.cpp | 28 ++++++++++++++-------------- cpp2rust/converter/converter_lib.h | 2 ++ cpp2rust/converter/printer.cpp | 1 + tests/unit/reserved_keywords.cpp | 13 ++++++++++++- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 1aa18fea3..e6732c308 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -914,6 +914,19 @@ static size_t GetDeclId(const clang::NamedDecl *decl, bool internal) { return type_mapping.try_emplace(key, type_mapping.size()).first->second; } +void EscapeRustKeyword(std::string &name) { + for (auto &keyword : rust_keywords) { + if (!name.starts_with(keyword)) + continue; + + auto suffix = std::string_view(name).substr(strlen(keyword)); + if (std::ranges::all_of(suffix, [](char c) { return c == '_'; })) { + name += '_'; + break; + } + } +} + std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { auto name = decl->getDeclName().isIdentifier() ? decl->getName().str() : decl->getNameAsString(); @@ -964,20 +977,7 @@ std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { name += std::to_string(*id); } - // transform decl names that are rust keywords: - // keyword -> keyword_ - // keyword_ -> keyword__ - // etc - for (auto &keyword : rust_keywords) { - if (!name.starts_with(keyword)) - continue; - - auto suffix = std::string_view(name).substr(strlen(keyword)); - if (std::ranges::all_of(suffix, [](char c) { return c == '_'; })) { - name += '_'; - break; - } - } + EscapeRustKeyword(name); if (name.empty()) { auto *pdecl = llvm::dyn_cast(decl); diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index ca5b6e072..768ddcb8e 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -177,6 +177,8 @@ unsigned GetArraySize(clang::QualType array_type); std::string GetID(const clang::Decl *decl); std::string GetMethodID(const clang::CXXMethodDecl *decl); +void EscapeRustKeyword(std::string &name); + std::string GetNamedDeclAsString(const clang::NamedDecl *decl); std::string DisambiguateAnonymousTag(const clang::TagDecl *tag); diff --git a/cpp2rust/converter/printer.cpp b/cpp2rust/converter/printer.cpp index 75e2e357e..a1ef5a3ac 100644 --- a/cpp2rust/converter/printer.cpp +++ b/cpp2rust/converter/printer.cpp @@ -116,6 +116,7 @@ std::string ToRustName(std::string name) { if (stem == "Ptr" || stem == "Value" || stem == "Box") { name += '_'; } + EscapeRustKeyword(name); return name; } diff --git a/tests/unit/reserved_keywords.cpp b/tests/unit/reserved_keywords.cpp index d9c512839..a97275a96 100644 --- a/tests/unit/reserved_keywords.cpp +++ b/tests/unit/reserved_keywords.cpp @@ -46,6 +46,14 @@ struct S { }; #undef F +// Record names +struct type { + int v; +}; +struct loop { + type t; +}; + // Function arguments #define F(n) int n, int foo(KW(F) int dummy) { return 0; } @@ -62,8 +70,11 @@ int main() { KW(F) #undef F + struct loop l = {{3}}; + struct type t = l.t; + // Function call #define F(n) 0, - return foo(KW(F) 0); + return foo(KW(F) t.v - 3); #undef F } From 54296241fc42ef3be0c8b3e85532070002fc04ee Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 9 Oct 2026 13:13:48 +0100 Subject: [PATCH 2/3] Add Err in reserved keywords --- cpp2rust/converter/converter_lib.cpp | 1 + tests/unit/keywords.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index e6732c308..2f7890417 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -73,6 +73,7 @@ static const char rust_keywords[][12] = { "safe", // Standard library keywords "vec", + "Err", }; namespace cpp2rust { diff --git a/tests/unit/keywords.cpp b/tests/unit/keywords.cpp index 62527f586..40e2b75f4 100644 --- a/tests/unit/keywords.cpp +++ b/tests/unit/keywords.cpp @@ -1,7 +1,11 @@ #include +int report(int Err) { return Err + 1; } + int main() { int in = 123; assert(in == 123); + int Err = 1; + assert(report(Err) == 2); return 0; } From a46748a06f95ea62b511226a3866b66a6aafdb7a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 9 Oct 2026 19:39:17 +0100 Subject: [PATCH 3/3] Update tests --- tests/unit/out/refcount/keywords.rs | 5 ++ tests/unit/out/refcount/reserved_keywords.rs | 56 +++++++++++++++++++- tests/unit/out/unsafe/keywords.rs | 5 ++ tests/unit/out/unsafe/reserved_keywords.rs | 53 +++++++++++++++++- 4 files changed, 115 insertions(+), 4 deletions(-) diff --git a/tests/unit/out/refcount/keywords.rs b/tests/unit/out/refcount/keywords.rs index f3216325f..da06433ad 100644 --- a/tests/unit/out/refcount/keywords.rs +++ b/tests/unit/out/refcount/keywords.rs @@ -6,6 +6,9 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; +pub fn report_0(mut Err_: i32) -> i32 { + return (Err_ + 1); +} pub fn main() { __cpp2rust_init_globals(); std::process::exit(main_0()); @@ -13,6 +16,8 @@ pub fn main() { fn main_0() -> i32 { let mut in_: i32 = 123; assert!((in_ == 123)); + let mut Err_: i32 = 1; + assert!((({ report_0(Err_,) }) == 2)); return 0; } pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/reserved_keywords.rs b/tests/unit/out/refcount/reserved_keywords.rs index 62083ae8d..68881cc88 100644 --- a/tests/unit/out/refcount/reserved_keywords.rs +++ b/tests/unit/out/refcount/reserved_keywords.rs @@ -86,6 +86,19 @@ pub struct S { #[offset(148)] pub vec_: i32, } +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(4)] +pub struct type_ { + #[offset(0)] + pub v: i32, +} +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(4)] +pub struct loop_ { + #[offset(0)] + #[byte_size(4)] + pub t: type_, +} pub fn foo_0( mut as_: i32, mut async_: i32, @@ -212,10 +225,49 @@ fn main_0() -> i32 { let mut raw_: i32 = 0; let mut safe_: i32 = 0; let mut vec_: i32 = 0; + let mut l: loop_ = loop_ { t: type_ { v: 3 } }; + let mut t: type_ = l.t.clone(); return ({ foo_0( - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + (t.v - 3), ) }); } diff --git a/tests/unit/out/unsafe/keywords.rs b/tests/unit/out/unsafe/keywords.rs index c7d305bd7..0d1ab8609 100644 --- a/tests/unit/out/unsafe/keywords.rs +++ b/tests/unit/out/unsafe/keywords.rs @@ -6,6 +6,9 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; +pub unsafe fn report_0(mut Err_: i32) -> i32 { + return ((Err_) + (1)); +} pub fn main() { unsafe { __cpp2rust_init_globals(); @@ -15,6 +18,8 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut in_: i32 = 123; assert!(((in_) == (123))); + let mut Err_: i32 = 1; + assert!(((unsafe { report_0(Err_,) }) == (2))); return 0; } pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/reserved_keywords.rs b/tests/unit/out/unsafe/reserved_keywords.rs index 2889774b4..bd35542ca 100644 --- a/tests/unit/out/unsafe/reserved_keywords.rs +++ b/tests/unit/out/unsafe/reserved_keywords.rs @@ -48,6 +48,16 @@ pub struct S { pub safe_: i32, pub vec_: i32, } +#[repr(C)] +#[derive(Copy, Clone, VaArg, FnPtrArg, Default)] +pub struct type_ { + pub v: i32, +} +#[repr(C)] +#[derive(Copy, Clone, VaArg, FnPtrArg, Default)] +pub struct loop_ { + pub t: type_, +} pub unsafe fn foo_0( mut as_: i32, mut async_: i32, @@ -176,10 +186,49 @@ unsafe fn main_0() -> i32 { let mut raw_: i32 = 0; let mut safe_: i32 = 0; let mut vec_: i32 = 0; + let mut l: loop_ = loop_ { t: type_ { v: 3 } }; + let mut t: type_ = l.t; return (unsafe { foo_0( - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ((t.v) - (3)), ) }); }