Skip to content

Commit a18bb1a

Browse files
authored
Translate comparison operators that don't return bool (#496)
1 parent 3aca9e8 commit a18bb1a

5 files changed

Lines changed: 791 additions & 5 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4665,6 +4665,32 @@ std::string Converter::GetComparisonCall(const clang::FunctionDecl *op,
46654665
arg(0, lhs), arg(1, rhs));
46664666
}
46674667

4668+
std::string Converter::GetComparisonBool(const clang::FunctionDecl *op,
4669+
const clang::CXXRecordDecl *decl,
4670+
std::string_view lhs,
4671+
std::string_view rhs) {
4672+
auto call = GetComparisonCall(op, decl, lhs, rhs);
4673+
auto ret = op->getReturnType();
4674+
if (ret->isBooleanType()) {
4675+
return call;
4676+
}
4677+
if (ret->isIntegerType()) {
4678+
return std::format("(({}) != 0)", call);
4679+
}
4680+
const auto *record = ret->getAsCXXRecordDecl();
4681+
assert(record && "unsupported comparison operator return type");
4682+
for (const auto *found : record->getVisibleConversionFunctions()) {
4683+
const auto *conversion = clang::dyn_cast<clang::CXXConversionDecl>(found);
4684+
if (conversion && conversion->getConversionType()->isBooleanType()) {
4685+
return std::format("{{ let __cmp = &{}; {}::{}({}) }}", call,
4686+
GetUFCSName(conversion), GetMethodName(conversion),
4687+
GetComparisonReceiver(conversion, record, "__cmp"));
4688+
}
4689+
}
4690+
assert(0 && "comparison operator result has no conversion to bool");
4691+
return call;
4692+
}
4693+
46684694
std::string
46694695
Converter::GetComparisonReferenceArg(const clang::CXXRecordDecl *decl,
46704696
std::string_view value) {
@@ -4692,19 +4718,19 @@ void Converter::ConvertOrdAndPartialOrdTraits(const clang::CXXRecordDecl *decl,
46924718
cmp_body = std::format("if {} {{ std::cmp::Ordering::Less }} else if {} {{ "
46934719
"std::cmp::Ordering::Greater }} else {{ "
46944720
"std::cmp::Ordering::Equal }}",
4695-
GetComparisonCall(lt, decl, "self", "other"),
4696-
GetComparisonCall(lt, decl, "other", "self"));
4721+
GetComparisonBool(lt, decl, "self", "other"),
4722+
GetComparisonBool(lt, decl, "other", "self"));
46974723
}
46984724

46994725
if (eq) {
4700-
eq_body = GetComparisonCall(eq, decl, "self", "other");
4726+
eq_body = GetComparisonBool(eq, decl, "self", "other");
47014727
} else if (cmp) {
47024728
eq_body = std::format("{} == std::cmp::Ordering::Equal",
47034729
GetComparisonCall(cmp, decl, "self", "other"));
47044730
} else {
47054731
eq_body = std::format("!({}) && !({})",
4706-
GetComparisonCall(lt, decl, "self", "other"),
4707-
GetComparisonCall(lt, decl, "other", "self"));
4732+
GetComparisonBool(lt, decl, "self", "other"),
4733+
GetComparisonBool(lt, decl, "other", "self"));
47084734
}
47094735

47104736
ConvertOrdAndPartialOrdTraitsBase(cmp_body, eq_body, GetRecordName(decl));
@@ -4719,6 +4745,10 @@ void Converter::AddOrdTrait(const clang::CXXRecordDecl *decl) {
47194745
fn->getDescribedFunctionTemplate() || !IsSameTypeComparison(fn, decl)) {
47204746
return;
47214747
}
4748+
if (fn->getOverloadedOperator() == clang::OO_Spaceship &&
4749+
!ctx_.CompCategories.lookupInfoForType(fn->getReturnType())) {
4750+
return;
4751+
}
47224752
switch (fn->getOverloadedOperator()) {
47234753
case clang::OO_EqualEqual:
47244754
eq = fn;

‎cpp2rust/converter/converter.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,10 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
680680
const clang::CXXRecordDecl *decl,
681681
std::string_view lhs, std::string_view rhs);
682682

683+
std::string GetComparisonBool(const clang::FunctionDecl *op,
684+
const clang::CXXRecordDecl *decl,
685+
std::string_view lhs, std::string_view rhs);
686+
683687
virtual std::string
684688
GetComparisonReferenceArg(const clang::CXXRecordDecl *decl,
685689
std::string_view value);
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// ADDITIONAL_COMPILE_FLAGS: -std=c++20
2+
#include <algorithm>
3+
#include <cassert>
4+
5+
struct X {
6+
int v;
7+
};
8+
9+
int operator==(X a, X b) { return a.v == b.v ? 2 : 0; }
10+
int operator!=(X a, X b) { return a.v != b.v ? 3 : 0; }
11+
int operator<(X a, X b) { return a.v < b.v ? 4 : 0; }
12+
int operator>(X a, X b) { return a.v > b.v ? 5 : 0; }
13+
int operator<=(X a, X b) { return a.v <= b.v ? 6 : 0; }
14+
int operator>=(X a, X b) { return a.v >= b.v ? 7 : 0; }
15+
16+
struct Result {
17+
int r;
18+
};
19+
20+
struct Custom {
21+
int v;
22+
Result operator<=>(const Custom &o) const { return Result{v - o.v}; }
23+
};
24+
25+
struct Mixed {
26+
int v;
27+
Result operator<=>(const Mixed &o) const { return Result{v - o.v}; }
28+
int operator<(const Mixed &o) const { return v < o.v ? 8 : 0; }
29+
int operator==(const Mixed &o) const { return v == o.v ? 9 : 0; }
30+
};
31+
32+
struct MyBool {
33+
bool value;
34+
explicit MyBool(bool v) : value(v) {}
35+
operator bool() const { return value; }
36+
};
37+
38+
struct Boolish {
39+
int v;
40+
};
41+
42+
MyBool operator==(Boolish a, Boolish b) { return MyBool(a.v == b.v); }
43+
MyBool operator<(Boolish a, Boolish b) { return MyBool(a.v < b.v); }
44+
45+
int main() {
46+
X a{1}, b{2}, c{1};
47+
assert((a == c) == 2);
48+
assert((a == b) == 0);
49+
assert((a != b) == 3);
50+
assert((a < b) == 4);
51+
assert((b > a) == 5);
52+
assert((a <= c) == 6);
53+
assert((a >= c) == 7);
54+
55+
X xs[] = {{3}, {1}, {2}};
56+
std::sort(xs, xs + 3);
57+
assert(xs[0].v == 1 && xs[1].v == 2 && xs[2].v == 3);
58+
59+
Custom p{5}, q{2};
60+
Result r = p <=> q;
61+
assert(r.r == 3);
62+
63+
Mixed m{4}, n{4};
64+
assert((m == n) == 9);
65+
assert((m <=> n).r == 0);
66+
Mixed ms[] = {{6}, {4}, {5}};
67+
std::sort(ms, ms + 3);
68+
assert(ms[0].v == 4 && ms[1].v == 5 && ms[2].v == 6);
69+
assert((ms[0] < ms[1]) == 8);
70+
71+
Boolish b1{1}, b2{2};
72+
assert(b1 == Boolish{1});
73+
assert(!(b2 < b1));
74+
MyBool lt = b1 < b2;
75+
assert(lt.value);
76+
Boolish bs[] = {{3}, {1}, {2}};
77+
std::sort(bs, bs + 3);
78+
assert(bs[0].v == 1 && bs[1].v == 2 && bs[2].v == 3);
79+
return 0;
80+
}

0 commit comments

Comments
 (0)