Skip to content

Commit 265cc23

Browse files
authored
Translate friend functions and friend specializations (#351)
1 parent 0c564cf commit 265cc23

5 files changed

Lines changed: 352 additions & 1 deletion

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,21 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) {
756756
if (auto *var_decl = clang::dyn_cast<clang::VarDecl>(d)) {
757757
VisitVarDecl(var_decl);
758758
}
759+
if (auto *friend_decl = clang::dyn_cast<clang::FriendDecl>(d)) {
760+
if (auto *fn = clang::dyn_cast_or_null<clang::FunctionDecl>(
761+
friend_decl->getFriendDecl());
762+
fn && fn->isThisDeclarationADefinition()) {
763+
VisitFunctionDecl(fn);
764+
}
765+
if (auto *tmpl = clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(
766+
friend_decl->getFriendDecl())) {
767+
for (auto *spec : tmpl->specializations()) {
768+
if (spec->isThisDeclarationADefinition()) {
769+
VisitFunctionDecl(spec);
770+
}
771+
}
772+
}
773+
}
759774
}
760775

761776
// Inner records. In rust they live outside the record

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,20 @@ static std::string GetParamSignature(const clang::Decl *decl) {
506506
return args;
507507
}
508508

509+
static std::string GetLexicalSpecializationID(const clang::Decl *decl) {
510+
if (const auto *spec =
511+
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
512+
decl->getLexicalDeclContext());
513+
spec && decl->getLexicalDeclContext() != decl->getDeclContext()) {
514+
return Mapper::ToString(Mapper::GetTypeForDecl(spec));
515+
}
516+
return {};
517+
}
518+
509519
std::string GetID(const clang::Decl *decl) {
510520
assert(decl);
511-
return GetLocationID(decl) + GetParamSignature(decl);
521+
return GetLexicalSpecializationID(decl) + GetLocationID(decl) +
522+
GetParamSignature(decl);
512523
}
513524

514525
std::string GetMethodID(const clang::CXXMethodDecl *decl) {

‎tests/unit/friend.cpp‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <cassert>
2+
3+
struct V {
4+
int x;
5+
friend int get(const V &v) { return v.x; }
6+
friend bool operator==(const V &a, const V &b) { return a.x == b.x; }
7+
template <typename T> friend T scaled(const V &v, T k) { return v.x * k; }
8+
};
9+
10+
template <typename T> struct W {
11+
T x;
12+
friend T get(const W &w) { return w.x; }
13+
};
14+
15+
struct D {
16+
int x;
17+
friend int declared_then_defined(const D &d);
18+
friend int declared_only(const D &d);
19+
};
20+
21+
int declared_then_defined(const D &d) { return d.x + 1; }
22+
23+
int main() {
24+
V a{3};
25+
V b{3};
26+
V c{4};
27+
assert(get(a) == 3);
28+
assert(a == b);
29+
assert(!(a == c));
30+
assert(scaled(c, 2) == 8);
31+
assert(scaled(c, 1.5) == 6.0);
32+
33+
W<int> wi{5};
34+
W<long> wl{6};
35+
assert(get(wi) == 5);
36+
assert(get(wl) == 6);
37+
38+
D d{7};
39+
assert(declared_then_defined(d) == 8);
40+
return 0;
41+
}

‎tests/unit/out/refcount/friend.rs‎

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
extern crate libcc2rs;
2+
use libcc2rs::*;
3+
use std::cell::RefCell;
4+
use std::collections::BTreeMap;
5+
use std::io::prelude::*;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::AsFd;
8+
use std::rc::{Rc, Weak};
9+
pub fn get_0(v: Ptr<V>) -> i32 {
10+
return (*(*v.upgrade().deref()).x.borrow());
11+
}
12+
pub fn operator_eq_1(a: Ptr<V>, b: Ptr<V>) -> bool {
13+
return {
14+
let _lhs = (*(*a.upgrade().deref()).x.borrow());
15+
_lhs == (*(*b.upgrade().deref()).x.borrow())
16+
};
17+
}
18+
pub fn scaled_2(v: Ptr<V>, k: i32) -> i32 {
19+
let k: Value<i32> = Rc::new(RefCell::new(k));
20+
return {
21+
let _lhs = (*(*v.upgrade().deref()).x.borrow());
22+
_lhs * (*k.borrow())
23+
};
24+
}
25+
pub fn scaled_3(v: Ptr<V>, k: f64) -> f64 {
26+
let k: Value<f64> = Rc::new(RefCell::new(k));
27+
return {
28+
let _lhs = ((*(*v.upgrade().deref()).x.borrow()) as f64);
29+
_lhs * (*k.borrow())
30+
};
31+
}
32+
#[derive(Default)]
33+
pub struct V {
34+
pub x: Value<i32>,
35+
}
36+
impl std::cmp::PartialEq for V {
37+
fn eq(&self, other: &Self) -> bool {
38+
{
39+
operator_eq_1(
40+
Rc::new(RefCell::new(self.clone())).as_pointer(),
41+
Rc::new(RefCell::new(other.clone())).as_pointer(),
42+
)
43+
}
44+
}
45+
}
46+
impl std::cmp::Eq for V {}
47+
impl Clone for V {
48+
fn clone(&self) -> Self {
49+
let __this: Value<V> = Rc::new(RefCell::new(Self {
50+
x: Rc::new(RefCell::new((*self.x.borrow()))),
51+
}));
52+
let this: Ptr<V> = __this.as_pointer();
53+
Rc::try_unwrap(__this).ok().unwrap().into_inner()
54+
}
55+
}
56+
impl ByteRepr for V {
57+
fn byte_size() -> usize {
58+
4
59+
}
60+
fn to_bytes(&self, buf: &mut [u8]) {
61+
(*self.x.borrow()).to_bytes(&mut buf[0..4]);
62+
}
63+
fn from_bytes(buf: &[u8]) -> Self {
64+
Self {
65+
x: Rc::new(RefCell::new(<i32>::from_bytes(&buf[0..4]))),
66+
}
67+
}
68+
}
69+
pub fn get_4(w: Ptr<W_int_>) -> i32 {
70+
return (*(*w.upgrade().deref()).x.borrow());
71+
}
72+
#[derive(Default)]
73+
pub struct W_int_ {
74+
pub x: Value<i32>,
75+
}
76+
impl Clone for W_int_ {
77+
fn clone(&self) -> Self {
78+
let __this: Value<W_int_> = Rc::new(RefCell::new(Self {
79+
x: Rc::new(RefCell::new((*self.x.borrow()))),
80+
}));
81+
let this: Ptr<W_int_> = __this.as_pointer();
82+
Rc::try_unwrap(__this).ok().unwrap().into_inner()
83+
}
84+
}
85+
impl ByteRepr for W_int_ {
86+
fn byte_size() -> usize {
87+
4
88+
}
89+
fn to_bytes(&self, buf: &mut [u8]) {
90+
(*self.x.borrow()).to_bytes(&mut buf[0..4]);
91+
}
92+
fn from_bytes(buf: &[u8]) -> Self {
93+
Self {
94+
x: Rc::new(RefCell::new(<i32>::from_bytes(&buf[0..4]))),
95+
}
96+
}
97+
}
98+
pub fn get_5(w: Ptr<W_long_>) -> i64 {
99+
return (*(*w.upgrade().deref()).x.borrow());
100+
}
101+
#[derive(Default)]
102+
pub struct W_long_ {
103+
pub x: Value<i64>,
104+
}
105+
impl Clone for W_long_ {
106+
fn clone(&self) -> Self {
107+
let __this: Value<W_long_> = Rc::new(RefCell::new(Self {
108+
x: Rc::new(RefCell::new((*self.x.borrow()))),
109+
}));
110+
let this: Ptr<W_long_> = __this.as_pointer();
111+
Rc::try_unwrap(__this).ok().unwrap().into_inner()
112+
}
113+
}
114+
impl ByteRepr for W_long_ {
115+
fn byte_size() -> usize {
116+
8
117+
}
118+
fn to_bytes(&self, buf: &mut [u8]) {
119+
(*self.x.borrow()).to_bytes(&mut buf[0..8]);
120+
}
121+
fn from_bytes(buf: &[u8]) -> Self {
122+
Self {
123+
x: Rc::new(RefCell::new(<i64>::from_bytes(&buf[0..8]))),
124+
}
125+
}
126+
}
127+
#[derive(Default)]
128+
pub struct D {
129+
pub x: Value<i32>,
130+
}
131+
impl Clone for D {
132+
fn clone(&self) -> Self {
133+
let __this: Value<D> = Rc::new(RefCell::new(Self {
134+
x: Rc::new(RefCell::new((*self.x.borrow()))),
135+
}));
136+
let this: Ptr<D> = __this.as_pointer();
137+
Rc::try_unwrap(__this).ok().unwrap().into_inner()
138+
}
139+
}
140+
impl ByteRepr for D {
141+
fn byte_size() -> usize {
142+
4
143+
}
144+
fn to_bytes(&self, buf: &mut [u8]) {
145+
(*self.x.borrow()).to_bytes(&mut buf[0..4]);
146+
}
147+
fn from_bytes(buf: &[u8]) -> Self {
148+
Self {
149+
x: Rc::new(RefCell::new(<i32>::from_bytes(&buf[0..4]))),
150+
}
151+
}
152+
}
153+
pub fn declared_then_defined_6(d: Ptr<D>) -> i32 {
154+
return ((*(*d.upgrade().deref()).x.borrow()) + 1);
155+
}
156+
pub fn main() {
157+
std::process::exit(main_0());
158+
}
159+
fn main_0() -> i32 {
160+
let a: Value<V> = Rc::new(RefCell::new(V {
161+
x: Rc::new(RefCell::new(3)),
162+
}));
163+
let b: Value<V> = Rc::new(RefCell::new(V {
164+
x: Rc::new(RefCell::new(3)),
165+
}));
166+
let c: Value<V> = Rc::new(RefCell::new(V {
167+
x: Rc::new(RefCell::new(4)),
168+
}));
169+
assert!((({ get_0(a.as_pointer(),) }) == 3));
170+
assert!(
171+
({
172+
let _a: Ptr<V> = a.as_pointer();
173+
operator_eq_1(_a, b.as_pointer())
174+
})
175+
);
176+
assert!(
177+
!({
178+
let _a: Ptr<V> = a.as_pointer();
179+
operator_eq_1(_a, c.as_pointer())
180+
})
181+
);
182+
assert!((({ scaled_2(c.as_pointer(), 2,) }) == 8));
183+
assert!((({ scaled_3(c.as_pointer(), 1.5E+0,) }) == 6.0E+0));
184+
let wi: Value<W_int_> = Rc::new(RefCell::new(W_int_ {
185+
x: Rc::new(RefCell::new(5)),
186+
}));
187+
let wl: Value<W_long_> = Rc::new(RefCell::new(W_long_ {
188+
x: Rc::new(RefCell::new(6_i64)),
189+
}));
190+
assert!((({ get_4(wi.as_pointer(),) }) == 5));
191+
assert!((({ get_5(wl.as_pointer(),) }) == 6_i64));
192+
let d: Value<D> = Rc::new(RefCell::new(D {
193+
x: Rc::new(RefCell::new(7)),
194+
}));
195+
assert!((({ declared_then_defined_6(d.as_pointer(),) }) == 8));
196+
return 0;
197+
}

‎tests/unit/out/unsafe/friend.rs‎

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
extern crate libc;
2+
use libc::*;
3+
extern crate libcc2rs;
4+
use libcc2rs::*;
5+
use std::collections::BTreeMap;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
8+
use std::rc::Rc;
9+
pub unsafe fn get_0(v: *const V) -> i32 {
10+
return (*v).x;
11+
}
12+
pub unsafe fn operator_eq_1(a: *const V, b: *const V) -> bool {
13+
return (((*a).x) == ((*b).x));
14+
}
15+
pub unsafe fn scaled_2(v: *const V, mut k: i32) -> i32 {
16+
return (((*v).x) * (k));
17+
}
18+
pub unsafe fn scaled_3(v: *const V, mut k: f64) -> f64 {
19+
return (((*v).x as f64) * (k));
20+
}
21+
#[repr(C)]
22+
#[derive(Copy, Clone, Default)]
23+
pub struct V {
24+
pub x: i32,
25+
}
26+
impl std::cmp::PartialEq for V {
27+
fn eq(&self, other: &Self) -> bool {
28+
unsafe { operator_eq_1(self as *const V, other as *const V) }
29+
}
30+
}
31+
impl std::cmp::Eq for V {}
32+
pub unsafe fn get_4(w: *const W_int_) -> i32 {
33+
return (*w).x;
34+
}
35+
#[repr(C)]
36+
#[derive(Copy, Clone, Default)]
37+
pub struct W_int_ {
38+
pub x: i32,
39+
}
40+
pub unsafe fn get_5(w: *const W_long_) -> i64 {
41+
return (*w).x;
42+
}
43+
#[repr(C)]
44+
#[derive(Copy, Clone, Default)]
45+
pub struct W_long_ {
46+
pub x: i64,
47+
}
48+
#[repr(C)]
49+
#[derive(Copy, Clone, Default)]
50+
pub struct D {
51+
pub x: i32,
52+
}
53+
pub unsafe fn declared_then_defined_6(d: *const D) -> i32 {
54+
return (((*d).x) + (1));
55+
}
56+
pub fn main() {
57+
unsafe {
58+
std::process::exit(main_0() as i32);
59+
}
60+
}
61+
unsafe fn main_0() -> i32 {
62+
let mut a: V = V { x: 3 };
63+
let mut b: V = V { x: 3 };
64+
let mut c: V = V { x: 4 };
65+
assert!(((unsafe { get_0(&a as *const V,) }) == (3)));
66+
assert!(
67+
(unsafe {
68+
let _a: *const V = &a as *const V;
69+
operator_eq_1(_a, &b as *const V)
70+
})
71+
);
72+
assert!(
73+
!(unsafe {
74+
let _a: *const V = &a as *const V;
75+
operator_eq_1(_a, &c as *const V)
76+
})
77+
);
78+
assert!(((unsafe { scaled_2(&c as *const V, 2,) }) == (8)));
79+
assert!(((unsafe { scaled_3(&c as *const V, 1.5E+0,) }) == (6.0E+0)));
80+
let mut wi: W_int_ = W_int_ { x: 5 };
81+
let mut wl: W_long_ = W_long_ { x: 6_i64 };
82+
assert!(((unsafe { get_4(&wi as *const W_int_,) }) == (5)));
83+
assert!(((unsafe { get_5(&wl as *const W_long_,) }) == (6_i64)));
84+
let mut d: D = D { x: 7 };
85+
assert!(((unsafe { declared_then_defined_6(&d as *const D,) }) == (8)));
86+
return 0;
87+
}

0 commit comments

Comments
 (0)