aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-11-15 18:13:32 +0000
committerPhilip Herron <philip.herron@embecosm.com>2021-11-16 15:09:53 +0000
commit04a49acfa3caa7a85a1a9edd24d69da0ad575ad5 (patch)
treed6bf4186cb815ff8b0bdf691c9659cf14bca8efd /gcc
parent0f74fe23c6d602c257ba94b2522bd9d6a594609e (diff)
downloadgcc-04a49acfa3caa7a85a1a9edd24d69da0ad575ad5.zip
gcc-04a49acfa3caa7a85a1a9edd24d69da0ad575ad5.tar.gz
gcc-04a49acfa3caa7a85a1a9edd24d69da0ad575ad5.tar.bz2
Add negation operator overload support
Unary operator expressions can be treated as simply having a nullptr rvalue. This patch updates the shared operator overloading code to allow for a nullptr rhs to canonicalize the code path for all operator overloads. Fixes #249
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc31
-rw-r--r--gcc/rust/backend/rust-compile-expr.h10
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h26
-rw-r--r--gcc/rust/util/rust-hir-map.h34
-rw-r--r--gcc/testsuite/rust/execute/torture/operator_overload_4.rs36
-rw-r--r--gcc/testsuite/rust/execute/torture/operator_overload_5.rs36
6 files changed, 147 insertions, 26 deletions
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 8902574..594cfff 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -92,6 +92,31 @@ CompileExpr::visit (HIR::CompoundAssignmentExpr &expr)
ctx->add_statement (assignment);
}
+void
+CompileExpr::visit (HIR::NegationExpr &expr)
+{
+ auto op = expr.get_expr_type ();
+ auto negated_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx);
+ auto location = expr.get_locus ();
+
+ // this might be an operator overload situation lets check
+ TyTy::FnType *fntype;
+ bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload (
+ expr.get_mappings ().get_hirid (), &fntype);
+ if (is_op_overload)
+ {
+ auto lang_item_type
+ = Analysis::RustLangItem::NegationOperatorToLangItem (op);
+ translated
+ = resolve_operator_overload (lang_item_type, expr, negated_expr,
+ nullptr, expr.get_expr ().get (), nullptr);
+ return;
+ }
+
+ translated
+ = ctx->get_backend ()->negation_expression (op, negated_expr, location);
+}
+
Bexpression *
CompileExpr::compile_dyn_dispatch_call (const TyTy::DynamicObjectType *dyn,
TyTy::BaseType *receiver,
@@ -311,7 +336,8 @@ CompileExpr::resolve_operator_overload (
= static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ());
std::vector<HIR::Expr *> arguments;
- arguments.push_back (rhs_expr);
+ if (rhs_expr != nullptr) // can be null for negation_expr (unary ones)
+ arguments.push_back (rhs_expr);
return compile_dyn_dispatch_call (dyn, receiver, fntype, lhs, arguments,
expr.get_locus ());
@@ -356,7 +382,8 @@ CompileExpr::resolve_operator_overload (
std::vector<Bexpression *> args;
args.push_back (self); // adjusted self
- args.push_back (rhs);
+ if (rhs != nullptr) // can be null for negation_expr (unary ones)
+ args.push_back (rhs);
auto fncontext = ctx->peek_fn ();
return ctx->get_backend ()->call_expression (fncontext.fndecl, fn_expr, args,
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h
index 7238d45..b4079f7 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -474,15 +474,7 @@ public:
= ctx->get_backend ()->lazy_boolean_expression (op, lhs, rhs, location);
}
- void visit (HIR::NegationExpr &expr) override
- {
- auto op = expr.get_expr_type ();
- auto negated_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx);
- auto location = expr.get_locus ();
-
- translated
- = ctx->get_backend ()->negation_expression (op, negated_expr, location);
- }
+ void visit (HIR::NegationExpr &expr) override;
void visit (HIR::TypeCastExpr &expr) override
{
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 37cd6b3..642bde2 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -792,6 +792,15 @@ public:
auto negated_expr_ty
= TypeCheckExpr::Resolve (expr.get_expr ().get (), false);
+ // check for operator overload
+ auto lang_item_type = Analysis::RustLangItem::NegationOperatorToLangItem (
+ expr.get_expr_type ());
+ bool operator_overloaded
+ = resolve_operator_overload (lang_item_type, expr, negated_expr_ty,
+ nullptr);
+ if (operator_overloaded)
+ return;
+
// https://doc.rust-lang.org/reference/expressions/operator-expr.html#negation-operators
switch (expr.get_expr_type ())
{
@@ -1380,11 +1389,18 @@ protected:
}
}
- // type check the arguments
+ // type check the arguments if required
TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup);
- rust_assert (type->num_params () == 2);
- auto fnparam = type->param_at (1);
- fnparam.second->unify (rhs); // typecheck the rhs
+ if (rhs == nullptr)
+ {
+ rust_assert (type->num_params () == 1);
+ }
+ else
+ {
+ rust_assert (type->num_params () == 2);
+ auto fnparam = type->param_at (1);
+ fnparam.second->unify (rhs); // typecheck the rhs
+ }
// get the return type
TyTy::BaseType *function_ret_tyty = fn->get_return_type ()->clone ();
@@ -1481,7 +1497,7 @@ private:
Location root_array_expr_locus;
bool inside_loop;
-};
+}; // namespace Resolver
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h
index bcbd582..4f8c389 100644
--- a/gcc/rust/util/rust-hir-map.h
+++ b/gcc/rust/util/rust-hir-map.h
@@ -43,6 +43,7 @@ public:
REMAINDER,
NEGATION,
+ NOT,
ADD_ASSIGN,
SUB_ASSIGN,
@@ -79,6 +80,10 @@ public:
{
return ItemType::NEGATION;
}
+ else if (item.compare ("not") == 0)
+ {
+ return ItemType::NOT;
+ }
else if (item.compare ("add_assign") == 0)
{
return ItemType::ADD_ASSIGN;
@@ -119,6 +124,8 @@ public:
return "rem";
case NEGATION:
return "neg";
+ case NOT:
+ return "not";
case ADD_ASSIGN:
return "add_assign";
case SUB_ASSIGN:
@@ -151,11 +158,7 @@ public:
case ArithmeticOrLogicalOperator::MODULUS:
return ItemType::REMAINDER;
- case ArithmeticOrLogicalOperator::BITWISE_AND:
- case ArithmeticOrLogicalOperator::BITWISE_OR:
- case ArithmeticOrLogicalOperator::BITWISE_XOR:
- case ArithmeticOrLogicalOperator::LEFT_SHIFT:
- case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
+ default:
return ItemType::UNKNOWN;
}
return ItemType::UNKNOWN;
@@ -177,11 +180,22 @@ public:
case ArithmeticOrLogicalOperator::MODULUS:
return ItemType::REM_ASSIGN;
- case ArithmeticOrLogicalOperator::BITWISE_AND:
- case ArithmeticOrLogicalOperator::BITWISE_OR:
- case ArithmeticOrLogicalOperator::BITWISE_XOR:
- case ArithmeticOrLogicalOperator::LEFT_SHIFT:
- case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
+ default:
+ return ItemType::UNKNOWN;
+ }
+ return ItemType::UNKNOWN;
+ }
+
+ static ItemType NegationOperatorToLangItem (NegationOperator op)
+ {
+ switch (op)
+ {
+ case NegationOperator::NEGATE:
+ return ItemType::NEGATION;
+ case NegationOperator::NOT:
+ return ItemType::NOT;
+
+ default:
return ItemType::UNKNOWN;
}
return ItemType::UNKNOWN;
diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_4.rs b/gcc/testsuite/rust/execute/torture/operator_overload_4.rs
new file mode 100644
index 0000000..eca19de
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/operator_overload_4.rs
@@ -0,0 +1,36 @@
+/* { dg-output "neg\n" } */
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+#[lang = "neg"]
+pub trait Neg {
+ type Output;
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+
+ fn neg(self) -> Self::Output;
+ // { dg-warning "unused name .self." "" { target *-*-* } .-1 }
+ // { dg-warning "unused name .Neg::neg." "" { target *-*-* } .-2 }
+}
+
+impl Neg for i32 {
+ type Output = i32;
+
+ fn neg(self) -> i32 {
+ unsafe {
+ let a = "neg\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c);
+ }
+ -self
+ }
+}
+
+fn main() -> i32 {
+ let a: i32 = 1;
+ let _b = -a;
+
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_5.rs b/gcc/testsuite/rust/execute/torture/operator_overload_5.rs
new file mode 100644
index 0000000..ffdc8c2
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/operator_overload_5.rs
@@ -0,0 +1,36 @@
+/* { dg-output "not\n" } */
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+#[lang = "not"]
+pub trait Not {
+ type Output;
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+
+ fn not(self) -> Self::Output;
+ // { dg-warning "unused name .self." "" { target *-*-* } .-1 }
+ // { dg-warning "unused name .Not::not." "" { target *-*-* } .-2 }
+}
+
+impl Not for i32 {
+ type Output = i32;
+
+ fn not(self) -> i32 {
+ unsafe {
+ let a = "not\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c);
+ }
+ !self
+ }
+}
+
+fn main() -> i32 {
+ let a: i32 = 1;
+ let _b = !a;
+
+ 0
+}