diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index d60d3f2b..c69b91aa 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3798,8 +3798,39 @@ Converter::GetOverloadedFunctionName(const clang::FunctionDecl *decl) { name += '_'; } + if (const auto *targs = decl->getTemplateSpecializationArgs()) { + std::vector args; + for (const auto &arg : targs->asArray()) { + if (arg.getKind() == clang::TemplateArgument::Pack) { + args.insert(args.end(), arg.pack_begin(), arg.pack_end()); + } else { + args.push_back(arg); + } + } + for (const auto &arg : args) { + name += '_'; + switch (arg.getKind()) { + case clang::TemplateArgument::Type: + name += Mapper::ToRustName( + arg.getAsType().getCanonicalType().getAsString()); + break; + case clang::TemplateArgument::Integral: + name += Mapper::ToRustName( + std::string(GetNumAsString(arg.getAsIntegral()))); + break; + default: + name += "targ"; + break; + } + } + } + auto pred = [](char ch) { return ch != ' ' && ch != '_'; }; name.erase(std::find_if(name.rbegin(), name.rend(), pred).base(), name.end()); + + if (decl->isVariadic()) { + name += "_va"; + } if (const auto *method = clang::dyn_cast(decl)) { if (method->isConst()) { name += "_const"; @@ -3819,6 +3850,9 @@ Converter::GetOverloadedFunctionName(const clang::FunctionDecl *decl) { } } + ReplaceAll(name, "[", "arr"); + ReplaceAll(name, "]", "arr"); + ReplaceAll(name, ";", "_"); name.erase(std::remove_if(name.begin(), name.end(), [](char c) { return c == '<' || c == '>' || c == ' ' || @@ -4111,7 +4145,7 @@ void Converter::ConvertCXXMethodDecls( const clang::CXXRecordDecl *decl, const std::string_view signature, bool (*predicate)(clang::CXXMethodDecl *)) { bool first = true; - for (auto *method : decl->methods()) { + auto convert_method = [&](clang::CXXMethodDecl *method) { if (predicate(method)) { if (first) { StrCat(signature, token::kOpenCurlyBracket); @@ -4119,7 +4153,11 @@ void Converter::ConvertCXXMethodDecls( } VisitCXXMethodDecl(method); } + }; + for (auto *method : decl->methods()) { + convert_method(method); } + ForEachTemplateInstantiatedMethod(decl, convert_method); if (!first) { StrCat(token::kCloseCurlyBracket); } diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 3808e353..de204378 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -3,11 +3,13 @@ #include "converter/converter_lib.h" +#include #include #include #include #include #include +#include #include #include @@ -249,7 +251,28 @@ bool IsOverloadedFunction(const clang::FunctionDecl *decl) { return !lookup_result.isSingleResult(); } +void ForEachTemplateInstantiatedMethod( + const clang::CXXRecordDecl *decl, + llvm::function_ref fn) { + for (auto d : decl->decls()) { + if (auto function_template_decl = + llvm::dyn_cast(d)) { + for (auto s : function_template_decl->specializations()) { + if (auto m = clang::dyn_cast(s); + m && !clang::isa(m) && + m->getDefinition()) { + fn(m); + } + } + } + } +} + bool IsOverloadedMethod(const clang::CXXMethodDecl *decl) { + if (decl->getTemplateSpecializationArgs() != nullptr && + IsUserDefinedDecl(decl)) { + return true; + } const auto method_name = decl->getNameAsString(); const auto *record = decl->getParent(); return std::count_if(record->method_begin(), record->method_end(), @@ -502,6 +525,11 @@ static std::string GetParamSignature(const clang::Decl *decl) { for (unsigned i = 0; i < fdecl->getNumParams(); ++i) { args += fdecl->getParamDecl(i)->getType().getAsString(); } + if (const auto *targs = fdecl->getTemplateSpecializationArgs()) { + llvm::raw_string_ostream os(args); + clang::printTemplateArgumentList( + os, targs->asArray(), fdecl->getASTContext().getPrintingPolicy()); + } } return args; } diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 3b518ca9..0c3f584d 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,10 @@ bool IsMutatingCall(const clang::CallExpr *expr); bool IsOverloadedFunction(const clang::FunctionDecl *decl); +void ForEachTemplateInstantiatedMethod( + const clang::CXXRecordDecl *decl, + llvm::function_ref fn); + bool IsOverloadedMethod(const clang::CXXMethodDecl *decl); bool IsUserDefinedCopyConstructor(const clang::CXXConstructorDecl *ctor); diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 835d039c..4def2784 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -828,12 +829,17 @@ void AddRuleForUserDefinedType(clang::NamedDecl *decl) { } std::string ToRustName(std::string name) { - size_t pos = 0; - while ((pos = name.find_first_of("<>, ", pos)) != std::string::npos) { - name[pos] = '_'; - ++pos; - } ReplaceAll(name, "::", "_"); + ReplaceAll(name, "*", "ptr"); + ReplaceAll(name, "&", "ref"); + ReplaceAll(name, "[", "arr"); + ReplaceAll(name, "]", "arr"); + ReplaceAll(name, "-", "neg"); + for (auto &c : name) { + if (!std::isalnum(c) && c != '_') { + c = '_'; + } + } return name; } diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 04863fa6..614f5325 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2734,12 +2734,16 @@ void ConverterRefCount::ConvertLateInstantiatedMethods( !IsMethodOnPtr(method) && !decl_ids_.contains(GetMethodID(method)); }); - for (auto *method : decl->methods()) { + auto convert_method = [&](clang::CXXMethodDecl *method) { if (IsEmittableMethod(method) && method->hasBody() && IsMethodOnPtr(method) && !decl_ids_.contains(GetMethodID(method))) { ConvertMethodOnPtr(method); } + }; + for (auto *method : decl->methods()) { + convert_method(method); } + ForEachTemplateInstantiatedMethod(decl, convert_method); } void ConverterRefCount::ConvertCXXRecordMethods(clang::CXXRecordDecl *decl) { @@ -2751,11 +2755,15 @@ void ConverterRefCount::ConvertCXXRecordMethods(clang::CXXRecordDecl *decl) { !IsMethodOnPtr(method); }); - for (auto *method : decl->methods()) { + auto convert_method = [&](clang::CXXMethodDecl *method) { if (IsMethodOnPtr(method) && method->getDefinition()) { ConvertMethodOnPtr(method); } + }; + for (auto *method : decl->methods()) { + convert_method(method); } + ForEachTemplateInstantiatedMethod(decl, convert_method); if (!GetUserDefinedDestructor(decl) && HasFieldsNeedingDestruction(decl)) { MethodsOnPtrFor(decl).trait_body += diff --git a/tests/unit/out/refcount/overload_mangling.rs b/tests/unit/out/refcount/overload_mangling.rs new file mode 100644 index 00000000..c2e306b4 --- /dev/null +++ b/tests/unit/out/refcount/overload_mangling.rs @@ -0,0 +1,127 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct S { + pub base: Value, +} +impl Clone for S { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + base: Rc::new(RefCell::new((*self.base.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for S { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.base.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + base: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +#[derive(Default)] +pub struct Box { + pub v: Value, +} +impl Clone for Box { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + v: Rc::new(RefCell::new((*self.v.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for Box { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.v.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + v: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let s: Value = Rc::new(RefCell::new(S { + base: Rc::new(RefCell::new(100)), + })); + assert!((({ SImpl::width_i32__char_const(&s.as_pointer(), 3,) }) == 103)); + assert!((({ SImpl::width_i32__int_const(&s.as_pointer(), 3,) }) == 112)); + assert!((({ SImpl::scale_i32__2_const(&s.as_pointer(), 5,) }) == 110)); + assert!((({ SImpl::scale_i32__3_const(&s.as_pointer(), 5,) }) == 115)); + assert!((({ SImpl::count_i32_const(&s.as_pointer(), 1,) }) == 101)); + assert!((({ SImpl::count_i32__int_long_const(&s.as_pointer(), 1,) }) == 103)); + assert!((({ SImpl::plain_i32_const(&s.as_pointer(), 1,) }) == 101)); + assert!((({ SImpl::plain_i64_const(&s.as_pointer(), 1_i64,) }) == 102)); + let b: Value = Rc::new(RefCell::new(Box { + v: Rc::new(RefCell::new(4)), + })); + assert!(((*(*b.borrow()).v.borrow()) == 4)); + return 0; +} +pub trait SImpl { + fn plain_i32_const(&self, x: i32) -> i32; + fn plain_i64_const(&self, x: i64) -> i32; + fn width_i32__char_const(&self, x: i32) -> i32; + fn width_i32__int_const(&self, x: i32) -> i32; + fn scale_i32__2_const(&self, x: i32) -> i32; + fn scale_i32__3_const(&self, x: i32) -> i32; + fn count_i32_const(&self, x: i32) -> i32; + fn count_i32__int_long_const(&self, x: i32) -> i32; +} +impl SImpl for Ptr { + fn plain_i32_const(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*(*(*self).upgrade().deref()).base.borrow()) + (*x.borrow())); + } + fn plain_i64_const(&self, x: i64) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return (((*(*(*self).upgrade().deref()).base.borrow()) + ((*x.borrow()) as i32)) + 1); + } + fn width_i32__char_const(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*(*(*self).upgrade().deref()).base.borrow()) + + ((*x.borrow()) * (::std::mem::size_of::() as i32))); + } + fn width_i32__int_const(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*(*(*self).upgrade().deref()).base.borrow()) + + ((*x.borrow()) * (::std::mem::size_of::() as i32))); + } + fn scale_i32__2_const(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*(*(*self).upgrade().deref()).base.borrow()) + ((*x.borrow()) * 2)); + } + fn scale_i32__3_const(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*(*(*self).upgrade().deref()).base.borrow()) + ((*x.borrow()) * 3)); + } + fn count_i32_const(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return (((*(*(*self).upgrade().deref()).base.borrow()) + (*x.borrow())) + (0 as i32)); + } + fn count_i32__int_long_const(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return (((*(*(*self).upgrade().deref()).base.borrow()) + (*x.borrow())) + (2 as i32)); + } +} diff --git a/tests/unit/out/unsafe/overload_mangling.rs b/tests/unit/out/unsafe/overload_mangling.rs new file mode 100644 index 00000000..266814fd --- /dev/null +++ b/tests/unit/out/unsafe/overload_mangling.rs @@ -0,0 +1,63 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct S { + pub base: i32, +} +impl S { + pub unsafe fn plain_i32_const(&self, mut x: i32) -> i32 { + return ((self.base) + (x)); + } + pub unsafe fn plain_i64_const(&self, mut x: i64) -> i32 { + return (((self.base) + (x as i32)) + (1)); + } + pub unsafe fn width_i32__char_const(&self, mut x: i32) -> i32 { + return ((self.base) + ((x) * (::std::mem::size_of::() as i32))); + } + pub unsafe fn width_i32__int_const(&self, mut x: i32) -> i32 { + return ((self.base) + ((x) * (::std::mem::size_of::() as i32))); + } + pub unsafe fn scale_i32__2_const(&self, mut x: i32) -> i32 { + return ((self.base) + ((x) * (2))); + } + pub unsafe fn scale_i32__3_const(&self, mut x: i32) -> i32 { + return ((self.base) + ((x) * (3))); + } + pub unsafe fn count_i32_const(&self, mut x: i32) -> i32 { + return (((self.base) + (x)) + (0 as i32)); + } + pub unsafe fn count_i32__int_long_const(&self, mut x: i32) -> i32 { + return (((self.base) + (x)) + (2 as i32)); + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Box { + pub v: i32, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut s: S = S { base: 100 }; + assert!(((unsafe { S::width_i32__char_const(&s, 3,) }) == (103))); + assert!(((unsafe { S::width_i32__int_const(&s, 3,) }) == (112))); + assert!(((unsafe { S::scale_i32__2_const(&s, 5,) }) == (110))); + assert!(((unsafe { S::scale_i32__3_const(&s, 5,) }) == (115))); + assert!(((unsafe { S::count_i32_const(&s, 1,) }) == (101))); + assert!(((unsafe { S::count_i32__int_long_const(&s, 1,) }) == (103))); + assert!(((unsafe { S::plain_i32_const(&s, 1,) }) == (101))); + assert!(((unsafe { S::plain_i64_const(&s, 1_i64,) }) == (102))); + let mut b: Box = Box { v: 4 }; + assert!(((b.v) == (4))); + return 0; +} diff --git a/tests/unit/overload_mangling.cpp b/tests/unit/overload_mangling.cpp new file mode 100644 index 00000000..70304c8a --- /dev/null +++ b/tests/unit/overload_mangling.cpp @@ -0,0 +1,33 @@ +#include + +struct S { + int base; + template int width(int x) const { + return base + x * (int)sizeof(T); + } + template int scale(int x) const { return base + x * N; } + template int count(int x) const { + return base + x + (int)sizeof...(Ts); + } + int plain(int x) const { return base + x; } + int plain(long x) const { return base + (int)x + 1; } +}; + +struct Box { + int v; +}; + +int main() { + S s{100}; + assert(s.width(3) == 103); + assert(s.width(3) == 112); + assert(s.scale<2>(5) == 110); + assert(s.scale<3>(5) == 115); + assert(s.count<>(1) == 101); + assert((s.count(1) == 103)); + assert(s.plain(1) == 101); + assert(s.plain(1L) == 102); + Box b{4}; + assert(b.v == 4); + return 0; +}