Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const char *>
Expand Down
35 changes: 33 additions & 2 deletions cpp2rust/converter/mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<clang::ClassTemplateSpecializationDecl>(decl)) {
llvm::ArrayRef<clang::TemplateArgument> args =
spec->getTemplateArgs().asArray();
llvm::SmallVector<clang::TemplateArgument, 4> 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<clang::TagDecl>(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));

Expand Down Expand Up @@ -767,6 +788,16 @@ void AddRuleForUserDefinedType(clang::NamedDecl *decl) {
}
}

std::string ToRustName(std::string name) {
size_t pos = 0;
std::string chars = "<>, ";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe Mapper::ToString is a better place to do these replaces. We already have some similar replaces that we do to normalize the output

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ToString handles converting a given C++ construct to its corresponding string representation, whereas ToRustName is responsible for transforming the string representation of an arbitrary C++ construct into a valid Rust name. Given this distinction, wouldn't it be clearer to keep these two functions separate?

Additionally, this normalization is only required when we want to use the string representation of a given C++ construct as a Rust name. It is not required for the other uses of ToString, such as obtaining the string representation of a construct in order to look up or insert a translation rule.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this var to avoid allocations (inline in find_first_of)

while ((pos = name.find_first_of(chars, pos)) != std::string::npos) {
name.replace(pos, 1, 1, '_');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name[pos] = '_';

++pos;
}
return ReplaceAll(name, "::", "_");
}

std::string ToString(clang::QualType qual_type, ScalarSugar sugar) {
assert(ctx_);

Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/mapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
43 changes: 43 additions & 0 deletions tests/unit/class_templates.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include <cassert>
#include <vector>

template <typename T> class MyContainer {
std::vector<T> 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<int> imc;
assert(imc.empty());
imc.push_back(1);
assert(imc.size() == 1 && imc.back() == 1);
imc.pop_back();
assert(imc.empty());

MyContainer<char> cmc;
assert(cmc.empty());
cmc.push_back('a');
assert(cmc.size() == 1 && cmc.back() == 'a');
cmc.pop_back();
assert(cmc.empty());

MyContainer<float> fmc;
assert(fmc.empty());
fmc.push_back('a');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.0?

assert(fmc.size() == 1 && fmc.back() == 'a');
fmc.pop_back();
assert(fmc.empty());
return 0;
}
160 changes: 160 additions & 0 deletions tests/unit/out/refcount/class_templates.rs
Original file line number Diff line number Diff line change
@@ -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<Vec<i32>>,
}
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<i32> {
return (self.vec_.as_pointer() as Ptr<i32>).to_last();
}
pub fn back(&self) -> Ptr<i32> {
return (self.vec_.as_pointer() as Ptr<i32>).to_last();
}
pub fn pop_back(&self) {
(*self.vec_.borrow_mut()).pop();
return;
}
pub fn push_back(&self, item: Ptr<i32>) {
{
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<Vec<u8>>,
}
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<u8> {
return (self.vec_.as_pointer() as Ptr<u8>).to_last();
}
pub fn back(&self) -> Ptr<u8> {
return (self.vec_.as_pointer() as Ptr<u8>).to_last();
}
pub fn pop_back(&self) {
(*self.vec_.borrow_mut()).pop();
return;
}
pub fn push_back(&self, item: Ptr<u8>) {
{
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<Vec<f32>>,
}
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<f32> {
return (self.vec_.as_pointer() as Ptr<f32>).to_last();
}
pub fn back(&self) -> Ptr<f32> {
return (self.vec_.as_pointer() as Ptr<f32>).to_last();
}
pub fn pop_back(&self) {
(*self.vec_.borrow_mut()).pop();
return;
}
pub fn push_back(&self, item: Ptr<f32>) {
{
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<MyContainer_int_> = Rc::new(RefCell::new(<MyContainer_int_>::default()));
assert!(({ (*imc.borrow()).empty() }));
({
let _item: Value<i32> = 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<MyContainer_char_> = Rc::new(RefCell::new(<MyContainer_char_>::default()));
assert!(({ (*cmc.borrow()).empty() }));
({
let _item: Value<u8> = 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<MyContainer_float_> = Rc::new(RefCell::new(<MyContainer_float_>::default()));
assert!(({ (*fmc.borrow()).empty() }));
({
let _item: Value<f32> = Rc::new(RefCell::new((('a' as u8) as f32)));
(*fmc.borrow()).push_back(_item.as_pointer())
});
assert!(
(({ (*fmc.borrow()).size() }) == 1_usize)
&& ((({ (*fmc.borrow()).back() }).read()) == ((('a' as u8) as i32) as f32))
);
({ (*fmc.borrow()).pop_back() });
assert!(({ (*fmc.borrow()).empty() }));
return 0;
}
Loading
Loading