diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 0e06acec..cf221193 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3476,7 +3476,7 @@ std::string Converter::GetRecordName(const clang::NamedDecl *decl) const { if (auto it = inner_structs_.find(ID); it != inner_structs_.end()) { return it->second; } - return ReplaceAll(Mapper::ToString(decl), "::", "_"); + return Mapper::ToRustName(Mapper::ToString(Mapper::GetTypeForDecl(decl))); } std::vector diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index cd664f1b..26803783 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -723,9 +723,30 @@ bool ParamIsPointer(const clang::Expr *expr, unsigned index) { return GetParamInfo(expr, index).is_pointer(); } +clang::QualType GetTypeForDecl(const clang::NamedDecl *decl) { + if (const auto *spec = + llvm::dyn_cast(decl)) { + llvm::ArrayRef args = + spec->getTemplateArgs().asArray(); + llvm::SmallVector canon(args.begin(), + args.end()); + ctx_->canonicalizeTemplateArguments(canon); + + return ctx_->getTemplateSpecializationType( + clang::ElaboratedTypeKeyword::None, + clang::TemplateName(spec->getSpecializedTemplate()), args, canon); + } + + const auto *rdecl = llvm::dyn_cast(decl); + assert(rdecl && "Unsupported decl type"); + + return ctx_->getTagType(clang::ElaboratedTypeKeyword::None, + rdecl->getQualifier(), rdecl, /*OwnsTag*/ false); +} + void AddRuleForUserDefinedType(clang::NamedDecl *decl) { - auto cpp_name = ToString(decl); - auto rs_name = ReplaceAll(cpp_name, "::", "_"); + auto cpp_name = ToString(GetTypeForDecl(decl)); + auto rs_name = ToRustName(cpp_name); AddTypeRule(cpp_name, TranslationRule::TypeRule::Plain(rs_name)); @@ -767,6 +788,15 @@ 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; + } + return ReplaceAll(name, "::", "_"); +} + std::string ToString(clang::QualType qual_type, ScalarSugar sugar) { assert(ctx_); diff --git a/cpp2rust/converter/mapper.h b/cpp2rust/converter/mapper.h index a967870e..ae6a4145 100644 --- a/cpp2rust/converter/mapper.h +++ b/cpp2rust/converter/mapper.h @@ -43,10 +43,12 @@ enum class ScalarSugar { kPreserve, }; +clang::QualType GetTypeForDecl(const clang::NamedDecl *decl); std::string ToString(clang::QualType qual_type, ScalarSugar sugar = ScalarSugar::kDesugar); std::string ToString(const clang::Expr *expr); std::string ToString(const clang::NamedDecl *decl); +std::string ToRustName(std::string name); void LoadTranslationRules(Model model, clang::ASTContext &ctx, const std::string &rules_dir); diff --git a/tests/unit/class_templates.cpp b/tests/unit/class_templates.cpp new file mode 100644 index 00000000..3588f5d1 --- /dev/null +++ b/tests/unit/class_templates.cpp @@ -0,0 +1,43 @@ +#include +#include + +template class MyContainer { + std::vector vec; + +public: + using value_type = T; + using reference = T &; + using const_reference = const T &; + using size_type = std::size_t; + + bool empty() const { return vec.empty(); } + size_type size() const { return vec.size(); } + const_reference back() const { return vec.back(); } + reference back() { return vec.back(); } + void pop_back() { return vec.pop_back(); } + void push_back(const_reference item) { vec.push_back(item); } +}; + +int main() { + MyContainer imc; + assert(imc.empty()); + imc.push_back(1); + assert(imc.size() == 1 && imc.back() == 1); + imc.pop_back(); + assert(imc.empty()); + + MyContainer cmc; + assert(cmc.empty()); + cmc.push_back('a'); + assert(cmc.size() == 1 && cmc.back() == 'a'); + cmc.pop_back(); + assert(cmc.empty()); + + MyContainer fmc; + assert(fmc.empty()); + fmc.push_back(1.0); + assert(fmc.size() == 1 && fmc.back() == 1.0); + fmc.pop_back(); + assert(fmc.empty()); + return 0; +} diff --git a/tests/unit/out/refcount/class_templates.rs b/tests/unit/out/refcount/class_templates.rs new file mode 100644 index 00000000..3cbce86e --- /dev/null +++ b/tests/unit/out/refcount/class_templates.rs @@ -0,0 +1,160 @@ +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 MyContainer_int_ { + vec_: Value>, +} +impl MyContainer_int_ { + pub fn empty(&self) -> bool { + return (*self.vec_.borrow()).is_empty(); + } + pub fn size(&self) -> usize { + return (*self.vec_.borrow()).len(); + } + pub fn back_const(&self) -> Ptr { + return (self.vec_.as_pointer() as Ptr).to_last(); + } + pub fn back(&self) -> Ptr { + return (self.vec_.as_pointer() as Ptr).to_last(); + } + pub fn pop_back(&self) { + (*self.vec_.borrow_mut()).pop(); + return; + } + pub fn push_back(&self, item: Ptr) { + { + let a0_clone = (item.read()).clone(); + (*self.vec_.borrow_mut()).push(a0_clone) + }; + } +} +impl Clone for MyContainer_int_ { + fn clone(&self) -> Self { + let mut this = Self { + vec_: Rc::new(RefCell::new((*self.vec_.borrow()).clone())), + }; + this + } +} +impl ByteRepr for MyContainer_int_ {} +#[derive(Default)] +pub struct MyContainer_char_ { + vec_: Value>, +} +impl MyContainer_char_ { + pub fn empty(&self) -> bool { + return (*self.vec_.borrow()).is_empty(); + } + pub fn size(&self) -> usize { + return (*self.vec_.borrow()).len(); + } + pub fn back_const(&self) -> Ptr { + return (self.vec_.as_pointer() as Ptr).to_last(); + } + pub fn back(&self) -> Ptr { + return (self.vec_.as_pointer() as Ptr).to_last(); + } + pub fn pop_back(&self) { + (*self.vec_.borrow_mut()).pop(); + return; + } + pub fn push_back(&self, item: Ptr) { + { + let a0_clone = (item.read()).clone(); + (*self.vec_.borrow_mut()).push(a0_clone) + }; + } +} +impl Clone for MyContainer_char_ { + fn clone(&self) -> Self { + let mut this = Self { + vec_: Rc::new(RefCell::new((*self.vec_.borrow()).clone())), + }; + this + } +} +impl ByteRepr for MyContainer_char_ {} +#[derive(Default)] +pub struct MyContainer_float_ { + vec_: Value>, +} +impl MyContainer_float_ { + pub fn empty(&self) -> bool { + return (*self.vec_.borrow()).is_empty(); + } + pub fn size(&self) -> usize { + return (*self.vec_.borrow()).len(); + } + pub fn back_const(&self) -> Ptr { + return (self.vec_.as_pointer() as Ptr).to_last(); + } + pub fn back(&self) -> Ptr { + return (self.vec_.as_pointer() as Ptr).to_last(); + } + pub fn pop_back(&self) { + (*self.vec_.borrow_mut()).pop(); + return; + } + pub fn push_back(&self, item: Ptr) { + { + let a0_clone = (item.read()).clone(); + (*self.vec_.borrow_mut()).push(a0_clone) + }; + } +} +impl Clone for MyContainer_float_ { + fn clone(&self) -> Self { + let mut this = Self { + vec_: Rc::new(RefCell::new((*self.vec_.borrow()).clone())), + }; + this + } +} +impl ByteRepr for MyContainer_float_ {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let imc: Value = Rc::new(RefCell::new(::default())); + assert!(({ (*imc.borrow()).empty() })); + ({ + let _item: Value = Rc::new(RefCell::new(1)); + (*imc.borrow()).push_back(_item.as_pointer()) + }); + assert!( + (({ (*imc.borrow()).size() }) == 1_usize) && ((({ (*imc.borrow()).back() }).read()) == 1) + ); + ({ (*imc.borrow()).pop_back() }); + assert!(({ (*imc.borrow()).empty() })); + let cmc: Value = Rc::new(RefCell::new(::default())); + assert!(({ (*cmc.borrow()).empty() })); + ({ + let _item: Value = Rc::new(RefCell::new(('a' as u8))); + (*cmc.borrow()).push_back(_item.as_pointer()) + }); + assert!( + (({ (*cmc.borrow()).size() }) == 1_usize) + && (((({ (*cmc.borrow()).back() }).read()) as i32) == (('a' as u8) as i32)) + ); + ({ (*cmc.borrow()).pop_back() }); + assert!(({ (*cmc.borrow()).empty() })); + let fmc: Value = Rc::new(RefCell::new(::default())); + assert!(({ (*fmc.borrow()).empty() })); + ({ + let _item: Value = Rc::new(RefCell::new((1.0E+0 as f32))); + (*fmc.borrow()).push_back(_item.as_pointer()) + }); + assert!( + (({ (*fmc.borrow()).size() }) == 1_usize) + && (((({ (*fmc.borrow()).back() }).read()) as f64) == 1.0E+0) + ); + ({ (*fmc.borrow()).pop_back() }); + assert!(({ (*fmc.borrow()).empty() })); + return 0; +} diff --git a/tests/unit/out/unsafe/class_templates.rs b/tests/unit/out/unsafe/class_templates.rs new file mode 100644 index 00000000..151ccbf1 --- /dev/null +++ b/tests/unit/out/unsafe/class_templates.rs @@ -0,0 +1,135 @@ +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(Clone, Default)] +pub struct MyContainer_int_ { + vec_: Vec, +} +impl MyContainer_int_ { + pub unsafe fn empty(&self) -> bool { + return self.vec_.is_empty(); + } + pub unsafe fn size(&self) -> usize { + return self.vec_.len(); + } + pub unsafe fn back_const(&self) -> *const i32 { + return ((self.vec_).last().unwrap()); + } + pub unsafe fn back(&mut self) -> *mut i32 { + return ((self.vec_).last_mut().unwrap()); + } + pub unsafe fn pop_back(&mut self) { + self.vec_.pop(); + return; + } + pub unsafe fn push_back(&mut self, item: *const i32) { + { + let a0_clone = (*item).clone(); + self.vec_.push(a0_clone) + }; + } +} +#[repr(C)] +#[derive(Clone, Default)] +pub struct MyContainer_char_ { + vec_: Vec, +} +impl MyContainer_char_ { + pub unsafe fn empty(&self) -> bool { + return self.vec_.is_empty(); + } + pub unsafe fn size(&self) -> usize { + return self.vec_.len(); + } + pub unsafe fn back_const(&self) -> *const u8 { + return ((self.vec_).last().unwrap()); + } + pub unsafe fn back(&mut self) -> *mut u8 { + return ((self.vec_).last_mut().unwrap()); + } + pub unsafe fn pop_back(&mut self) { + self.vec_.pop(); + return; + } + pub unsafe fn push_back(&mut self, item: *const u8) { + { + let a0_clone = (*item).clone(); + self.vec_.push(a0_clone) + }; + } +} +#[repr(C)] +#[derive(Clone, Default)] +pub struct MyContainer_float_ { + vec_: Vec, +} +impl MyContainer_float_ { + pub unsafe fn empty(&self) -> bool { + return self.vec_.is_empty(); + } + pub unsafe fn size(&self) -> usize { + return self.vec_.len(); + } + pub unsafe fn back_const(&self) -> *const f32 { + return ((self.vec_).last().unwrap()); + } + pub unsafe fn back(&mut self) -> *mut f32 { + return ((self.vec_).last_mut().unwrap()); + } + pub unsafe fn pop_back(&mut self) { + self.vec_.pop(); + return; + } + pub unsafe fn push_back(&mut self, item: *const f32) { + { + let a0_clone = (*item).clone(); + self.vec_.push(a0_clone) + }; + } +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut imc: MyContainer_int_ = ::default(); + assert!((unsafe { imc.empty() })); + (unsafe { + let mut _item = 1; + imc.push_back(&mut _item) + }); + assert!(((unsafe { imc.size() }) == (1_usize)) && ((*(unsafe { imc.back() })) == (1))); + (unsafe { imc.pop_back() }); + assert!((unsafe { imc.empty() })); + let mut cmc: MyContainer_char_ = ::default(); + assert!((unsafe { cmc.empty() })); + (unsafe { + let mut _item = ('a' as u8); + cmc.push_back(&mut _item) + }); + assert!( + ((unsafe { cmc.size() }) == (1_usize)) + && (((*(unsafe { cmc.back() })) as i32) == (('a' as u8) as i32)) + ); + (unsafe { cmc.pop_back() }); + assert!((unsafe { cmc.empty() })); + let mut fmc: MyContainer_float_ = ::default(); + assert!((unsafe { fmc.empty() })); + (unsafe { + let mut _item = (1.0E+0 as f32); + fmc.push_back(&mut _item) + }); + assert!( + ((unsafe { fmc.size() }) == (1_usize)) && (((*(unsafe { fmc.back() })) as f64) == (1.0E+0)) + ); + (unsafe { fmc.pop_back() }); + assert!((unsafe { fmc.empty() })); + return 0; +}