Skip to content

Commit 21010af

Browse files
authored
Translate friend operators (#412)
1 parent 79a9acd commit 21010af

11 files changed

Lines changed: 1392 additions & 11 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,16 +1036,24 @@ void Converter::DefineImplicitMembers(clang::CXXRecordDecl *decl) {
10361036
sema_->DefineImplicitMoveAssignment(decl->getLocation(), method);
10371037
}
10381038
}
1039-
for (auto *method : decl->methods()) {
1040-
if (IsComparisonOperator(method) && method->isDefaulted() &&
1041-
!method->doesThisDeclarationHaveABody()) {
1039+
auto define_defaulted_comparison = [&](clang::FunctionDecl *fn) {
1040+
if (!fn || !IsComparisonOperator(fn) || !fn->isDefaulted() ||
1041+
fn->doesThisDeclarationHaveABody()) {
1042+
return;
1043+
}
10421044
#if CLANG_VERSION_MAJOR >= 24
1043-
auto kind = method->getDefaultedComparisonKind();
1045+
auto kind = fn->getDefaultedComparisonKind();
10441046
#else
1045-
auto kind = sema_->getDefaultedComparisonKind(method);
1047+
auto kind = sema_->getDefaultedComparisonKind(fn);
10461048
#endif
1047-
sema_->DefineDefaultedComparison(decl->getLocation(), method, kind);
1048-
}
1049+
sema_->DefineDefaultedComparison(decl->getLocation(), fn, kind);
1050+
};
1051+
for (auto *method : decl->methods()) {
1052+
define_defaulted_comparison(method);
1053+
}
1054+
for (auto *friend_decl : decl->friends()) {
1055+
define_defaulted_comparison(clang::dyn_cast_or_null<clang::FunctionDecl>(
1056+
friend_decl->getFriendDecl()));
10491057
}
10501058
sema_->TUScope = saved_tu_scope;
10511059
}
@@ -4620,13 +4628,28 @@ void Converter::AddOrdTrait(const clang::CXXRecordDecl *decl) {
46204628
break;
46214629
}
46224630
};
4631+
auto consider_decl = [&](const clang::NamedDecl *found) {
4632+
if (const auto *tmpl =
4633+
clang::dyn_cast<clang::FunctionTemplateDecl>(found)) {
4634+
for (const auto *spec : tmpl->specializations()) {
4635+
consider(spec);
4636+
}
4637+
return;
4638+
}
4639+
consider(clang::dyn_cast<clang::FunctionDecl>(found));
4640+
};
46234641
for (const auto *method : decl->methods()) {
46244642
consider(method);
46254643
}
46264644
for (auto op : {clang::OO_EqualEqual, clang::OO_Less, clang::OO_Spaceship}) {
46274645
auto name = ctx_.DeclarationNames.getCXXOperatorName(op);
46284646
for (const auto *found : decl->getDeclContext()->lookup(name)) {
4629-
consider(clang::dyn_cast<clang::FunctionDecl>(found));
4647+
consider_decl(found);
4648+
}
4649+
}
4650+
for (const auto *friend_decl : decl->friends()) {
4651+
if (const auto *found = friend_decl->getFriendDecl()) {
4652+
consider_decl(found);
46304653
}
46314654
}
46324655

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -908,9 +908,12 @@ bool IsUserOperatorCall(const clang::CXXOperatorCallExpr *expr) {
908908
if (!callee) {
909909
return false;
910910
}
911-
if (const auto *method = clang::dyn_cast<clang::CXXMethodDecl>(callee);
912-
method && method->isDefaulted() && IsComparisonOperator(method)) {
913-
return IsUserDefinedDecl(method->getParent());
911+
if (callee->isDefaulted() && IsComparisonOperator(callee)) {
912+
const clang::Decl *owner = callee;
913+
if (const auto *method = clang::dyn_cast<clang::CXXMethodDecl>(callee)) {
914+
owner = method->getParent();
915+
}
916+
return IsUserDefinedDecl(owner);
914917
}
915918
if (const auto *method = clang::dyn_cast<clang::CXXMethodDecl>(callee);
916919
method && IsConvertibleMoveAssignment(method)) {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
project(friend_operator LANGUAGES CXX)
3+
add_executable(app a.cpp b.cpp)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <assert.h>
2+
3+
#include "s.h"
4+
5+
int main() {
6+
S s1{1, 2};
7+
S s2{1, 2};
8+
S s3{1, 3};
9+
assert(s1 == s2);
10+
assert(s1 != s3);
11+
assert(!(s1 == s3));
12+
assert(s1 < s3);
13+
assert(!(s3 < s1));
14+
assert(compare(s1, s3) == -1);
15+
assert(compare(s3, s1) == 1);
16+
assert(compare(s1, s2) == 0);
17+
return 0;
18+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include "s.h"
2+
3+
bool operator==(const S &x, const S &y) { return x.a == y.a && x.b == y.b; }
4+
5+
bool operator!=(const S &x, const S &y) { return !(x == y); }
6+
7+
bool operator<(const S &x, const S &y) {
8+
return x.a < y.a || (x.a == y.a && x.b < y.b);
9+
}
10+
11+
int compare(const S &x, const S &y) {
12+
if (x < y) {
13+
return -1;
14+
}
15+
if (y < x) {
16+
return 1;
17+
}
18+
return 0;
19+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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+
#[derive(Default)]
10+
pub struct S {
11+
pub a: Value<i32>,
12+
pub b: Value<i32>,
13+
}
14+
impl Clone for S {
15+
fn clone(&self) -> Self {
16+
let __this: Value<S> = Rc::new(RefCell::new(Self {
17+
a: Rc::new(RefCell::new((*self.a.borrow()))),
18+
b: Rc::new(RefCell::new((*self.b.borrow()))),
19+
}));
20+
let this: Ptr<S> = __this.as_pointer();
21+
Rc::try_unwrap(__this).ok().unwrap().into_inner()
22+
}
23+
}
24+
impl ByteRepr for S {
25+
fn byte_size() -> usize {
26+
8
27+
}
28+
fn to_bytes(&self, buf: &mut [u8]) {
29+
(*self.a.borrow()).to_bytes(&mut buf[0..4]);
30+
(*self.b.borrow()).to_bytes(&mut buf[4..8]);
31+
}
32+
fn from_bytes(buf: &[u8]) -> Self {
33+
Self {
34+
a: Rc::new(RefCell::new(<i32>::from_bytes(&buf[0..4]))),
35+
b: Rc::new(RefCell::new(<i32>::from_bytes(&buf[4..8]))),
36+
}
37+
}
38+
}
39+
pub fn main() {
40+
__cpp2rust_init_globals();
41+
std::process::exit(main_0());
42+
}
43+
fn main_0() -> i32 {
44+
let s1: Value<S> = Rc::new(RefCell::new(S {
45+
a: Rc::new(RefCell::new(1)),
46+
b: Rc::new(RefCell::new(2)),
47+
}));
48+
let s2: Value<S> = Rc::new(RefCell::new(S {
49+
a: Rc::new(RefCell::new(1)),
50+
b: Rc::new(RefCell::new(2)),
51+
}));
52+
let s3: Value<S> = Rc::new(RefCell::new(S {
53+
a: Rc::new(RefCell::new(1)),
54+
b: Rc::new(RefCell::new(3)),
55+
}));
56+
assert!(
57+
({
58+
let _x: Ptr<S> = s1.as_pointer();
59+
operator_eq_0(_x, s2.as_pointer())
60+
})
61+
);
62+
assert!(
63+
({
64+
let _x: Ptr<S> = s1.as_pointer();
65+
operator_ne_1(_x, s3.as_pointer())
66+
})
67+
);
68+
assert!(
69+
!({
70+
let _x: Ptr<S> = s1.as_pointer();
71+
operator_eq_0(_x, s3.as_pointer())
72+
})
73+
);
74+
assert!(
75+
({
76+
let _x: Ptr<S> = s1.as_pointer();
77+
operator_lt_2(_x, s3.as_pointer())
78+
})
79+
);
80+
assert!(
81+
!({
82+
let _x: Ptr<S> = s3.as_pointer();
83+
operator_lt_2(_x, s1.as_pointer())
84+
})
85+
);
86+
assert!((({ compare_3(s1.as_pointer(), s3.as_pointer(),) }) == -1_i32));
87+
assert!((({ compare_3(s3.as_pointer(), s1.as_pointer(),) }) == 1));
88+
assert!((({ compare_3(s1.as_pointer(), s2.as_pointer(),) }) == 0));
89+
return 0;
90+
}
91+
pub fn operator_eq_0(x: Ptr<S>, y: Ptr<S>) -> bool {
92+
return ({
93+
let _lhs = (*(*x.upgrade().deref()).a.borrow());
94+
_lhs == (*(*y.upgrade().deref()).a.borrow())
95+
}) && ({
96+
let _lhs = (*(*x.upgrade().deref()).b.borrow());
97+
_lhs == (*(*y.upgrade().deref()).b.borrow())
98+
});
99+
}
100+
pub fn operator_ne_1(x: Ptr<S>, y: Ptr<S>) -> bool {
101+
return !({
102+
let _x: Ptr<S> = (x).clone();
103+
let _y: Ptr<S> = (y).clone();
104+
operator_eq_0(_x, _y)
105+
});
106+
}
107+
pub fn operator_lt_2(x: Ptr<S>, y: Ptr<S>) -> bool {
108+
return ({
109+
let _lhs = (*(*x.upgrade().deref()).a.borrow());
110+
_lhs < (*(*y.upgrade().deref()).a.borrow())
111+
}) || (({
112+
let _lhs = (*(*x.upgrade().deref()).a.borrow());
113+
_lhs == (*(*y.upgrade().deref()).a.borrow())
114+
}) && ({
115+
let _lhs = (*(*x.upgrade().deref()).b.borrow());
116+
_lhs < (*(*y.upgrade().deref()).b.borrow())
117+
}));
118+
}
119+
pub fn compare_3(x: Ptr<S>, y: Ptr<S>) -> i32 {
120+
if ({
121+
let _x: Ptr<S> = (x).clone();
122+
let _y: Ptr<S> = (y).clone();
123+
operator_lt_2(_x, _y)
124+
}) {
125+
return -1_i32;
126+
}
127+
if ({
128+
let _x: Ptr<S> = (y).clone();
129+
let _y: Ptr<S> = (x).clone();
130+
operator_lt_2(_x, _y)
131+
}) {
132+
return 1;
133+
}
134+
return 0;
135+
}
136+
pub fn __cpp2rust_init_globals() {}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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+
#[repr(C)]
10+
#[derive(Copy, Clone, Default)]
11+
pub struct S {
12+
pub a: i32,
13+
pub b: i32,
14+
}
15+
pub fn main() {
16+
unsafe {
17+
__cpp2rust_init_globals();
18+
std::process::exit(main_0() as i32);
19+
}
20+
}
21+
unsafe fn main_0() -> i32 {
22+
let mut s1: S = S { a: 1, b: 2 };
23+
let mut s2: S = S { a: 1, b: 2 };
24+
let mut s3: S = S { a: 1, b: 3 };
25+
assert!(
26+
(unsafe {
27+
let _x: *const S = &s1;
28+
operator_eq_0(_x, &s2)
29+
})
30+
);
31+
assert!(
32+
(unsafe {
33+
let _x: *const S = &s1;
34+
operator_ne_1(_x, &s3)
35+
})
36+
);
37+
assert!(
38+
!(unsafe {
39+
let _x: *const S = &s1;
40+
operator_eq_0(_x, &s3)
41+
})
42+
);
43+
assert!(
44+
(unsafe {
45+
let _x: *const S = &s1;
46+
operator_lt_2(_x, &s3)
47+
})
48+
);
49+
assert!(
50+
!(unsafe {
51+
let _x: *const S = &s3;
52+
operator_lt_2(_x, &s1)
53+
})
54+
);
55+
assert!(((unsafe { compare_3(&s1, &s3,) }) == (-1_i32)));
56+
assert!(((unsafe { compare_3(&s3, &s1,) }) == (1)));
57+
assert!(((unsafe { compare_3(&s1, &s2,) }) == (0)));
58+
return 0;
59+
}
60+
pub unsafe fn operator_eq_0(x: *const S, y: *const S) -> bool {
61+
return (((*x).a) == ((*y).a)) && (((*x).b) == ((*y).b));
62+
}
63+
pub unsafe fn operator_ne_1(x: *const S, y: *const S) -> bool {
64+
return !(unsafe {
65+
let _x: *const S = x;
66+
let _y: *const S = y;
67+
operator_eq_0(_x, _y)
68+
});
69+
}
70+
pub unsafe fn operator_lt_2(x: *const S, y: *const S) -> bool {
71+
return (((*x).a) < ((*y).a)) || ((((*x).a) == ((*y).a)) && (((*x).b) < ((*y).b)));
72+
}
73+
pub unsafe fn compare_3(x: *const S, y: *const S) -> i32 {
74+
if (unsafe {
75+
let _x: *const S = x;
76+
let _y: *const S = y;
77+
operator_lt_2(_x, _y)
78+
}) {
79+
return -1_i32;
80+
}
81+
if (unsafe {
82+
let _x: *const S = y;
83+
let _y: *const S = x;
84+
operator_lt_2(_x, _y)
85+
}) {
86+
return 1;
87+
}
88+
return 0;
89+
}
90+
pub unsafe fn __cpp2rust_init_globals() {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
3+
struct S {
4+
int a;
5+
int b;
6+
7+
friend bool operator==(const S &x, const S &y);
8+
friend bool operator!=(const S &x, const S &y);
9+
friend bool operator<(const S &x, const S &y);
10+
};
11+
12+
int compare(const S &x, const S &y);

0 commit comments

Comments
 (0)