Skip to content

Commit e891887

Browse files
committed
gccrs: add support for lang_item eq and PartialEq trait
The Eq and Partial Ord are very similar to the operator overloads we support for add/sub/etc... but they differ in that usually the function call name matches the name of the lang item. This time we need to have support to send in a new path for the method call on the lang item we want instead of just the name of the lang item. NOTE: this test case doesnt work correctly yet we need to support the derive of partial eq on enums to generate the correct comparison code for that. Fixes #3302 gcc/rust/ChangeLog: * backend/rust-compile-expr.cc (CompileExpr::visit): handle partial_eq possible call * backend/rust-compile-expr.h: handle case where lang item calls differ from name * hir/tree/rust-hir-expr.cc (OperatorExprMeta::OperatorExprMeta): new helper * hir/tree/rust-hir-expr.h: likewise * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): handle partial_eq (TypeCheckExpr::resolve_operator_overload): likewise * typecheck/rust-hir-type-check-expr.h: likewise * util/rust-lang-item.cc (LangItem::ComparisonToLangItem): map comparison to lang item (LangItem::ComparisonToSegment): likewise * util/rust-lang-item.h: new lang items PartialOrd and Eq * util/rust-operators.h (enum class): likewise gcc/testsuite/ChangeLog: * rust/compile/nr2/exclude: nr2 cant handle this * rust/compile/cmp1.rs: New test. Signed-off-by: Philip Herron <[email protected]>
1 parent 5bccf14 commit e891887

11 files changed

+194
-13
lines changed

gcc/rust/backend/rust-compile-expr.cc

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,26 @@ CompileExpr::visit (HIR::ComparisonExpr &expr)
279279
auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx);
280280
auto location = expr.get_locus ();
281281

282+
// this might be an operator overload situation lets check
283+
TyTy::FnType *fntype;
284+
bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
285+
expr.get_mappings ().get_hirid (), &fntype);
286+
if (is_op_overload)
287+
{
288+
auto seg_name = LangItem::ComparisonToSegment (expr.get_expr_type ());
289+
auto segment = HIR::PathIdentSegment (seg_name);
290+
auto lang_item_type
291+
= LangItem::ComparisonToLangItem (expr.get_expr_type ());
292+
293+
rhs = address_expression (rhs, EXPR_LOCATION (rhs));
294+
295+
translated = resolve_operator_overload (
296+
lang_item_type, expr, lhs, rhs, expr.get_lhs (),
297+
tl::optional<std::reference_wrapper<HIR::Expr>> (expr.get_rhs ()),
298+
segment);
299+
return;
300+
}
301+
282302
translated = Backend::comparison_expression (op, lhs, rhs, location);
283303
}
284304

@@ -1478,7 +1498,8 @@ CompileExpr::get_receiver_from_dyn (const TyTy::DynamicObjectType *dyn,
14781498
tree
14791499
CompileExpr::resolve_operator_overload (
14801500
LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr, tree lhs, tree rhs,
1481-
HIR::Expr &lhs_expr, tl::optional<std::reference_wrapper<HIR::Expr>> rhs_expr)
1501+
HIR::Expr &lhs_expr, tl::optional<std::reference_wrapper<HIR::Expr>> rhs_expr,
1502+
HIR::PathIdentSegment specified_segment)
14821503
{
14831504
TyTy::FnType *fntype;
14841505
bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
@@ -1499,7 +1520,10 @@ CompileExpr::resolve_operator_overload (
14991520
}
15001521

15011522
// lookup compiled functions since it may have already been compiled
1502-
HIR::PathIdentSegment segment_name (LangItem::ToString (lang_item_type));
1523+
HIR::PathIdentSegment segment_name
1524+
= specified_segment.is_error ()
1525+
? HIR::PathIdentSegment (LangItem::ToString (lang_item_type))
1526+
: specified_segment;
15031527
tree fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ());
15041528

15051529
// lookup the autoderef mappings

gcc/rust/backend/rust-compile-expr.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ class CompileExpr : private HIRCompileBase, protected HIR::HIRExpressionVisitor
9999
tree resolve_operator_overload (
100100
LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr, tree lhs,
101101
tree rhs, HIR::Expr &lhs_expr,
102-
tl::optional<std::reference_wrapper<HIR::Expr>> rhs_expr);
102+
tl::optional<std::reference_wrapper<HIR::Expr>> rhs_expr,
103+
HIR::PathIdentSegment specified_segment
104+
= HIR::PathIdentSegment::create_error ());
103105

104106
tree compile_bool_literal (const HIR::LiteralExpr &expr,
105107
const TyTy::BaseType *tyty);

gcc/rust/hir/tree/rust-hir-expr.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,12 @@ OperatorExprMeta::OperatorExprMeta (HIR::ArrayIndexExpr &expr)
12981298
locus (expr.get_locus ())
12991299
{}
13001300

1301+
OperatorExprMeta::OperatorExprMeta (HIR::ComparisonExpr &expr)
1302+
: node_mappings (expr.get_mappings ()),
1303+
lvalue_mappings (expr.get_expr ().get_mappings ()),
1304+
locus (expr.get_locus ())
1305+
{}
1306+
13011307
AnonConst::AnonConst (NodeId id, std::unique_ptr<Expr> expr)
13021308
: id (id), expr (std::move (expr))
13031309
{

gcc/rust/hir/tree/rust-hir-expr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2816,6 +2816,8 @@ class OperatorExprMeta
28162816

28172817
OperatorExprMeta (HIR::ArrayIndexExpr &expr);
28182818

2819+
OperatorExprMeta (HIR::ComparisonExpr &expr);
2820+
28192821
const Analysis::NodeMapping &get_mappings () const { return node_mappings; }
28202822

28212823
const Analysis::NodeMapping &get_lvalue_mappings () const

gcc/rust/typecheck/rust-hir-type-check-expr.cc

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,21 @@ TypeCheckExpr::visit (HIR::ComparisonExpr &expr)
344344
auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
345345
auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
346346

347+
auto borrowed_rhs
348+
= new TyTy::ReferenceType (mappings.get_next_hir_id (),
349+
TyTy::TyVar (rhs->get_ref ()), Mutability::Imm);
350+
context->insert_implicit_type (borrowed_rhs->get_ref (), borrowed_rhs);
351+
352+
auto seg_name = LangItem::ComparisonToSegment (expr.get_expr_type ());
353+
auto segment = HIR::PathIdentSegment (seg_name);
354+
auto lang_item_type = LangItem::ComparisonToLangItem (expr.get_expr_type ());
355+
356+
bool operator_overloaded
357+
= resolve_operator_overload (lang_item_type, expr, lhs, borrowed_rhs,
358+
segment);
359+
if (operator_overloaded)
360+
return;
361+
347362
unify_site (expr.get_mappings ().get_hirid (),
348363
TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
349364
TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
@@ -1640,10 +1655,10 @@ TypeCheckExpr::visit (HIR::ClosureExpr &expr)
16401655
}
16411656

16421657
bool
1643-
TypeCheckExpr::resolve_operator_overload (LangItem::Kind lang_item_type,
1644-
HIR::OperatorExprMeta expr,
1645-
TyTy::BaseType *lhs,
1646-
TyTy::BaseType *rhs)
1658+
TypeCheckExpr::resolve_operator_overload (
1659+
LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr,
1660+
TyTy::BaseType *lhs, TyTy::BaseType *rhs,
1661+
HIR::PathIdentSegment specified_segment)
16471662
{
16481663
// look up lang item for arithmetic type
16491664
std::string associated_item_name = LangItem::ToString (lang_item_type);
@@ -1661,7 +1676,9 @@ TypeCheckExpr::resolve_operator_overload (LangItem::Kind lang_item_type,
16611676
current_context = context->peek_context ();
16621677
}
16631678

1664-
auto segment = HIR::PathIdentSegment (associated_item_name);
1679+
auto segment = specified_segment.is_error ()
1680+
? HIR::PathIdentSegment (associated_item_name)
1681+
: specified_segment;
16651682
auto candidates = MethodResolver::Probe (lhs, segment);
16661683

16671684
// remove any recursive candidates

gcc/rust/typecheck/rust-hir-type-check-expr.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ class TypeCheckExpr : private TypeCheckBase, private HIR::HIRExpressionVisitor
9797
protected:
9898
bool resolve_operator_overload (LangItem::Kind lang_item_type,
9999
HIR::OperatorExprMeta expr,
100-
TyTy::BaseType *lhs, TyTy::BaseType *rhs);
100+
TyTy::BaseType *lhs, TyTy::BaseType *rhs,
101+
HIR::PathIdentSegment specified_segment
102+
= HIR::PathIdentSegment::create_error ());
101103

102104
bool resolve_fn_trait_call (HIR::CallExpr &expr,
103105
TyTy::BaseType *function_tyty,

gcc/rust/util/rust-lang-item.cc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{
9898

9999
{"into_iter", Kind::INTOITER_INTOITER},
100100
{"next", Kind::ITERATOR_NEXT},
101+
102+
{"eq", Kind::EQ},
103+
{"partial_ord", Kind::PARTIAL_ORD},
101104
}};
102105

103106
tl::optional<LangItem::Kind>
@@ -145,6 +148,47 @@ LangItem::OperatorToLangItem (ArithmeticOrLogicalOperator op)
145148
rust_unreachable ();
146149
}
147150

151+
LangItem::Kind
152+
LangItem::ComparisonToLangItem (ComparisonOperator op)
153+
{
154+
switch (op)
155+
{
156+
case ComparisonOperator::NOT_EQUAL:
157+
case ComparisonOperator::EQUAL:
158+
return LangItem::Kind::EQ;
159+
160+
case ComparisonOperator::GREATER_THAN:
161+
case ComparisonOperator::LESS_THAN:
162+
case ComparisonOperator::GREATER_OR_EQUAL:
163+
case ComparisonOperator::LESS_OR_EQUAL:
164+
return LangItem::Kind::PARTIAL_ORD;
165+
}
166+
167+
rust_unreachable ();
168+
}
169+
170+
std::string
171+
LangItem::ComparisonToSegment (ComparisonOperator op)
172+
{
173+
switch (op)
174+
{
175+
case ComparisonOperator::NOT_EQUAL:
176+
return "ne";
177+
case ComparisonOperator::EQUAL:
178+
return "eq";
179+
case ComparisonOperator::GREATER_THAN:
180+
return "gt";
181+
case ComparisonOperator::LESS_THAN:
182+
return "lt";
183+
case ComparisonOperator::GREATER_OR_EQUAL:
184+
return "ge";
185+
case ComparisonOperator::LESS_OR_EQUAL:
186+
return "le";
187+
}
188+
189+
rust_unreachable ();
190+
}
191+
148192
LangItem::Kind
149193
LangItem::CompoundAssignmentOperatorToLangItem (ArithmeticOrLogicalOperator op)
150194
{

gcc/rust/util/rust-lang-item.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ class LangItem
4545

4646
NEGATION,
4747
NOT,
48+
EQ,
49+
PARTIAL_ORD,
4850

4951
ADD_ASSIGN,
5052
SUB_ASSIGN,
@@ -136,6 +138,9 @@ class LangItem
136138
static Kind
137139
CompoundAssignmentOperatorToLangItem (ArithmeticOrLogicalOperator op);
138140
static Kind NegationOperatorToLangItem (NegationOperator op);
141+
static Kind ComparisonToLangItem (ComparisonOperator op);
142+
143+
static std::string ComparisonToSegment (ComparisonOperator op);
139144
};
140145

141146
} // namespace Rust

gcc/rust/util/rust-operators.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ enum class ComparisonOperator
4343
{
4444
EQUAL, // std::cmp::PartialEq::eq
4545
NOT_EQUAL, // std::cmp::PartialEq::ne
46-
GREATER_THAN, // std::cmp::PartialEq::gt
47-
LESS_THAN, // std::cmp::PartialEq::lt
48-
GREATER_OR_EQUAL, // std::cmp::PartialEq::ge
49-
LESS_OR_EQUAL // std::cmp::PartialEq::le
46+
GREATER_THAN, // std::cmp::PartialOrd::gt
47+
LESS_THAN, // std::cmp::PartialOrd::lt
48+
GREATER_OR_EQUAL, // std::cmp::PartialOrd::ge
49+
LESS_OR_EQUAL // std::cmp::PartialOrd::le
5050
};
5151

5252
enum class LazyBooleanOperator

gcc/testsuite/rust/compile/cmp1.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// { dg-options "-w" }
2+
// taken from https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/library/core/src/cmp.rs#L98
3+
4+
#[lang = "sized"]
5+
pub trait Sized {}
6+
7+
#[lang = "eq"]
8+
#[stable(feature = "rust1", since = "1.0.0")]
9+
#[doc(alias = "==")]
10+
#[doc(alias = "!=")]
11+
pub trait PartialEq<Rhs: ?Sized = Self> {
12+
/// This method tests for `self` and `other` values to be equal, and is used
13+
/// by `==`.
14+
#[must_use]
15+
#[stable(feature = "rust1", since = "1.0.0")]
16+
fn eq(&self, other: &Rhs) -> bool;
17+
18+
/// This method tests for `!=`.
19+
#[inline]
20+
#[must_use]
21+
#[stable(feature = "rust1", since = "1.0.0")]
22+
fn ne(&self, other: &Rhs) -> bool {
23+
!self.eq(other)
24+
}
25+
}
26+
27+
enum BookFormat {
28+
Paperback,
29+
Hardback,
30+
Ebook,
31+
}
32+
33+
impl PartialEq<BookFormat> for BookFormat {
34+
fn eq(&self, other: &BookFormat) -> bool {
35+
self == other
36+
}
37+
}
38+
39+
pub struct Book {
40+
isbn: i32,
41+
format: BookFormat,
42+
}
43+
44+
// Implement <Book> == <BookFormat> comparisons
45+
impl PartialEq<BookFormat> for Book {
46+
fn eq(&self, other: &BookFormat) -> bool {
47+
self.format == *other
48+
}
49+
}
50+
51+
// Implement <BookFormat> == <Book> comparisons
52+
impl PartialEq<Book> for BookFormat {
53+
fn eq(&self, other: &Book) -> bool {
54+
*self == other.format
55+
}
56+
}
57+
58+
// Implement <Book> == <Book> comparisons
59+
impl PartialEq<Book> for Book {
60+
fn eq(&self, other: &Book) -> bool {
61+
self.isbn == other.isbn
62+
}
63+
}
64+
65+
pub fn main() {
66+
let b1 = Book {
67+
isbn: 1,
68+
format: BookFormat::Paperback,
69+
};
70+
let b2 = Book {
71+
isbn: 2,
72+
format: BookFormat::Paperback,
73+
};
74+
75+
let _c1: bool = b1 == BookFormat::Paperback;
76+
let _c2: bool = BookFormat::Paperback == b2;
77+
let _c3: bool = b1 != b2;
78+
}

gcc/testsuite/rust/compile/nr2/exclude

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,4 +196,5 @@ additional-trait-bounds2.rs
196196
auto_traits2.rs
197197
auto_traits3.rs
198198
issue-3140.rs
199+
cmp1.rs
199200
# please don't delete the trailing newline

0 commit comments

Comments
 (0)