diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-11-16 15:18:49 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-16 15:18:49 +0000 |
commit | 5514d9cec51d5ec7cc30dd6cdbfadfdddbe0aab3 (patch) | |
tree | 55051cad7f474f411d79ca1e86cc23d63138716d /gcc | |
parent | dcd758595f646a480947265ccc9833fdd3976b75 (diff) | |
parent | 6d1333ef46cba6ed9e1ace817f9cc649b7f7a1df (diff) | |
download | gcc-5514d9cec51d5ec7cc30dd6cdbfadfdddbe0aab3.zip gcc-5514d9cec51d5ec7cc30dd6cdbfadfdddbe0aab3.tar.gz gcc-5514d9cec51d5ec7cc30dd6cdbfadfdddbe0aab3.tar.bz2 |
Merge #801
801: operator overloading r=philberty a=philberty
This change adds operator overloading by following how the C++ front-end
does it. We are relying on GCC to inline the operator overloads which does
occur once optimizations are enabled. It also brings back the desurgared
compound assignment expression (e2b761b13e6ccd3a7af4100183bb13e32b5b0da0)
for lang_items such as add_assign. You can find more information on how the algorithm works in:
- c47d5cbdee9b701fb7753b44530fcb51f80b20fa
- a7fb60bb626f7b936bf117636db777a5f0df30c9
These were refactored in: 0f74fe23c6d602c257ba94b2522bd9d6a594609e
Fixes #249
Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Diffstat (limited to 'gcc')
33 files changed, 1491 insertions, 314 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 15c0a8f..f3302c2e 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -90,6 +90,7 @@ GRS_OBJS = \ rust/rust-hir-type-check-path.o \ rust/rust-compile-intrinsic.o \ rust/rust-base62.o \ + rust/rust-compile-expr.o \ $(END) # removed object files from here diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 72f2609..05779e7 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -542,6 +542,13 @@ protected: class AttrInput { public: + enum AttrInputType + { + LITERAL, + META_ITEM, + TOKEN_TREE, + }; + virtual ~AttrInput () {} // Unique pointer custom clone function @@ -564,6 +571,8 @@ public: // Returns whether attr input has been parsed to meta item syntax. virtual bool is_meta_item () const = 0; + virtual AttrInputType get_attr_input_type () const = 0; + protected: // pure virtual clone implementation virtual AttrInput *clone_attr_input_impl () const = 0; @@ -650,6 +659,11 @@ public: bool check_cfg_predicate (const Session &session) const override; + AttrInputType get_attr_input_type () const final override + { + return AttrInput::AttrInputType::META_ITEM; + } + // Clones this object. std::unique_ptr<AttrInputMetaItemContainer> clone_attr_input_meta_item_container () const @@ -767,6 +781,11 @@ public: } bool is_meta_item () const override { return false; } + + AttrInputType get_attr_input_type () const final override + { + return AttrInput::AttrInputType::TOKEN_TREE; + } }; /* Forward decl - definition moved to rust-expr.h as it requires LiteralExpr to diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index 05c78b7..3463f5a 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -102,13 +102,7 @@ protected: // Literal expression attribute body (non-macro attribute) class AttrInputLiteral : public AttrInput { - // Literal expression WITHOUT SUFFIX - // std::unique_ptr<LiteralExpr> literal_expr; - LiteralExpr - literal_expr; // as not using polymorphic behaviour, doesn't require pointer - // TODO: will require pointer if LiteralExpr is changed to have subclassing - - // TODO: should this store location data? + LiteralExpr literal_expr; public: AttrInputLiteral (LiteralExpr lit_expr) : literal_expr (std::move (lit_expr)) @@ -127,6 +121,13 @@ public: bool is_meta_item () const override { return false; } + LiteralExpr &get_literal () { return literal_expr; } + + AttrInputType get_attr_input_type () const final override + { + return AttrInput::AttrInputType::LITERAL; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc new file mode 100644 index 0000000..594cfff --- /dev/null +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -0,0 +1,394 @@ +// Copyright (C) 2020-2021 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-compile.h" +#include "rust-compile-item.h" +#include "rust-compile-expr.h" +#include "rust-compile-struct-field-expr.h" +#include "rust-hir-trait-resolve.h" +#include "rust-hir-path-probe.h" +#include "rust-hir-type-bounds.h" +#include "rust-hir-dot-operator.h" + +namespace Rust { +namespace Compile { + +void +CompileExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) +{ + auto op = expr.get_expr_type (); + auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); + auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); + + // 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::OperatorToLangItem (expr.get_expr_type ()); + translated = resolve_operator_overload (lang_item_type, expr, lhs, rhs, + expr.get_lhs (), expr.get_rhs ()); + return; + } + + translated + = ctx->get_backend ()->arithmetic_or_logical_expression (op, lhs, rhs, + expr.get_locus ()); +} + +void +CompileExpr::visit (HIR::CompoundAssignmentExpr &expr) +{ + fncontext fn = ctx->peek_fn (); + + auto op = expr.get_expr_type (); + auto lhs = CompileExpr::Compile (expr.get_left_expr ().get (), ctx); + auto rhs = CompileExpr::Compile (expr.get_right_expr ().get (), ctx); + + // 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::CompoundAssignmentOperatorToLangItem ( + expr.get_expr_type ()); + auto compound_assignment + = resolve_operator_overload (lang_item_type, expr, lhs, rhs, + expr.get_left_expr ().get (), + expr.get_right_expr ().get ()); + auto assignment + = ctx->get_backend ()->expression_statement (fn.fndecl, + compound_assignment); + ctx->add_statement (assignment); + + return; + } + + auto operator_expr + = ctx->get_backend ()->arithmetic_or_logical_expression (op, lhs, rhs, + expr.get_locus ()); + Bstatement *assignment + = ctx->get_backend ()->assignment_statement (fn.fndecl, lhs, operator_expr, + expr.get_locus ()); + 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, + TyTy::FnType *fntype, + Bexpression *receiver_ref, + std::vector<HIR::Expr *> &arguments, + Location expr_locus) +{ + size_t offs = 0; + const Resolver::TraitItemReference *ref = nullptr; + for (auto &bound : dyn->get_object_items ()) + { + const Resolver::TraitItemReference *item = bound.first; + auto t = item->get_tyty (); + rust_assert (t->get_kind () == TyTy::TypeKind::FNDEF); + auto ft = static_cast<TyTy::FnType *> (t); + + if (ft->get_id () == fntype->get_id ()) + { + ref = item; + break; + } + offs++; + } + + if (ref == nullptr) + return ctx->get_backend ()->error_expression (); + + // get any indirection sorted out + if (receiver->get_kind () == TyTy::TypeKind::REF) + { + TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver); + auto indirect_ty = r->get_base (); + Btype *indrect_compiled_tyty + = TyTyResolveCompile::compile (ctx, indirect_ty); + + Bexpression *indirect + = ctx->get_backend ()->indirect_expression (indrect_compiled_tyty, + receiver_ref, true, + expr_locus); + receiver_ref = indirect; + } + + // access the offs + 1 for the fnptr and offs=0 for the reciever obj + Bexpression *self_argument + = ctx->get_backend ()->struct_field_expression (receiver_ref, 0, + expr_locus); + + // access the vtable for the fn + Bexpression *fn_vtable_access + = ctx->get_backend ()->struct_field_expression (receiver_ref, offs + 1, + expr_locus); + + // cast it to the correct fntype + Btype *expected_fntype = TyTyResolveCompile::compile (ctx, fntype, true); + Bexpression *fn_convert_expr + = ctx->get_backend ()->convert_expression (expected_fntype, + fn_vtable_access, expr_locus); + + fncontext fnctx = ctx->peek_fn (); + Bblock *enclosing_scope = ctx->peek_enclosing_scope (); + bool is_address_taken = false; + Bstatement *ret_var_stmt = nullptr; + Bvariable *fn_convert_expr_tmp + = ctx->get_backend ()->temporary_variable (fnctx.fndecl, enclosing_scope, + expected_fntype, fn_convert_expr, + is_address_taken, expr_locus, + &ret_var_stmt); + ctx->add_statement (ret_var_stmt); + + std::vector<Bexpression *> args; + args.push_back (self_argument); + for (auto &argument : arguments) + { + Bexpression *compiled_expr = CompileExpr::Compile (argument, ctx); + args.push_back (compiled_expr); + } + + Bexpression *fn_expr + = ctx->get_backend ()->var_expression (fn_convert_expr_tmp, expr_locus); + + return ctx->get_backend ()->call_expression (fnctx.fndecl, fn_expr, args, + nullptr, expr_locus); +} + +Bexpression * +CompileExpr::resolve_method_address (TyTy::FnType *fntype, HirId ref, + TyTy::BaseType *receiver, + HIR::PathIdentSegment &segment, + Analysis::NodeMapping expr_mappings, + Location expr_locus) +{ + // lookup compiled functions since it may have already been compiled + Bfunction *fn = nullptr; + if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn)) + { + return ctx->get_backend ()->function_code_expression (fn, expr_locus); + } + + // Now we can try and resolve the address since this might be a forward + // declared function, generic function which has not be compiled yet or + // its an not yet trait bound function + HIR::ImplItem *resolved_item + = ctx->get_mappings ()->lookup_hir_implitem (expr_mappings.get_crate_num (), + ref, nullptr); + if (resolved_item != nullptr) + { + if (!fntype->has_subsititions_defined ()) + return CompileInherentImplItem::Compile (receiver, resolved_item, ctx, + true); + + return CompileInherentImplItem::Compile (receiver, resolved_item, ctx, + true, fntype); + } + + // it might be resolved to a trait item + HIR::TraitItem *trait_item = ctx->get_mappings ()->lookup_hir_trait_item ( + expr_mappings.get_crate_num (), ref); + HIR::Trait *trait = ctx->get_mappings ()->lookup_trait_item_mapping ( + trait_item->get_mappings ().get_hirid ()); + + Resolver::TraitReference *trait_ref + = &Resolver::TraitReference::error_node (); + bool ok = ctx->get_tyctx ()->lookup_trait_reference ( + trait->get_mappings ().get_defid (), &trait_ref); + rust_assert (ok); + + // the type resolver can only resolve type bounds to their trait + // item so its up to us to figure out if this path should resolve + // to an trait-impl-block-item or if it can be defaulted to the + // trait-impl-item's definition + + auto root = receiver->get_root (); + std::vector<Resolver::PathProbeCandidate> candidates + = Resolver::PathProbeType::Probe (root, segment, true, false, true); + + if (candidates.size () == 0) + { + // this means we are defaulting back to the trait_item if + // possible + Resolver::TraitItemReference *trait_item_ref = nullptr; + bool ok = trait_ref->lookup_hir_trait_item (*trait_item, &trait_item_ref); + rust_assert (ok); // found + rust_assert (trait_item_ref->is_optional ()); // has definition + + // FIXME Optional means it has a definition and an associated + // block which can be a default implementation, if it does not + // contain an implementation we should actually return + // error_mark_node + + return CompileTraitItem::Compile (receiver, + trait_item_ref->get_hir_trait_item (), + ctx, fntype, true, expr_locus); + } + else + { + std::vector<Resolver::Adjustment> adjustments; + Resolver::PathProbeCandidate *candidate + = Resolver::MethodResolution::Select (candidates, root, adjustments); + + // FIXME this will be a case to return error_mark_node, there is + // an error scenario where a Trait Foo has a method Bar, but this + // receiver does not implement this trait or has an incompatible + // implementation and we should just return error_mark_node + rust_assert (candidate != nullptr); + rust_assert (candidate->is_impl_candidate ()); + + HIR::ImplItem *impl_item = candidate->item.impl.impl_item; + if (!fntype->has_subsititions_defined ()) + return CompileInherentImplItem::Compile (receiver, impl_item, ctx, + true); + + return CompileInherentImplItem::Compile (receiver, impl_item, ctx, true, + fntype); + } +} + +Bexpression * +CompileExpr::resolve_operator_overload ( + Analysis::RustLangItem::ItemType lang_item_type, HIR::OperatorExpr &expr, + Bexpression *lhs, Bexpression *rhs, HIR::Expr *lhs_expr, HIR::Expr *rhs_expr) +{ + TyTy::FnType *fntype; + bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload ( + expr.get_mappings ().get_hirid (), &fntype); + rust_assert (is_op_overload); + + // lookup the resolved name + NodeId resolved_node_id = UNKNOWN_NODEID; + bool ok = ctx->get_resolver ()->lookup_resolved_name ( + expr.get_mappings ().get_nodeid (), &resolved_node_id); + rust_assert (ok); + + // reverse lookup + HirId ref; + ok = ctx->get_mappings ()->lookup_node_to_hir ( + expr.get_mappings ().get_crate_num (), resolved_node_id, &ref); + rust_assert (ok); + + TyTy::BaseType *receiver = nullptr; + ok = ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hirid (), + &receiver); + rust_assert (ok); + + bool is_dyn_dispatch + = receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC; + bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM; + if (is_generic_receiver) + { + TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver); + receiver = p->resolve (); + } + + if (is_dyn_dispatch) + { + const TyTy::DynamicObjectType *dyn + = static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ()); + + std::vector<HIR::Expr *> arguments; + 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 ()); + } + + // lookup compiled functions since it may have already been compiled + HIR::PathIdentSegment segment_name ( + Analysis::RustLangItem::ToString (lang_item_type)); + Bexpression *fn_expr + = resolve_method_address (fntype, ref, receiver, segment_name, + expr.get_mappings (), expr.get_locus ()); + + // lookup the autoderef mappings + std::vector<Resolver::Adjustment> *adjustments = nullptr; + ok = ctx->get_tyctx ()->lookup_autoderef_mappings ( + expr.get_mappings ().get_hirid (), &adjustments); + rust_assert (ok); + + // FIXME refactor this out + Bexpression *self = lhs; + for (auto &adjustment : *adjustments) + { + switch (adjustment.get_type ()) + { + case Resolver::Adjustment::AdjustmentType::IMM_REF: + case Resolver::Adjustment::AdjustmentType::MUT_REF: + self + = ctx->get_backend ()->address_expression (self, + lhs_expr->get_locus ()); + break; + + case Resolver::Adjustment::AdjustmentType::DEREF_REF: + Btype *expected_type + = TyTyResolveCompile::compile (ctx, adjustment.get_expected ()); + self + = ctx->get_backend ()->indirect_expression (expected_type, self, + true, /* known_valid*/ + lhs_expr->get_locus ()); + break; + } + } + + std::vector<Bexpression *> args; + args.push_back (self); // adjusted self + 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, + nullptr, expr.get_locus ()); +} + +} // namespace Compile +} // namespace Rust diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index f43db50..b4079f7 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -388,6 +388,8 @@ public: ctx->add_statement (assignment); } + void visit (HIR::CompoundAssignmentExpr &expr) override; + void visit (HIR::ArrayIndexExpr &expr) override { Bexpression *array = CompileExpr::Compile (expr.get_array_expr (), ctx); @@ -448,17 +450,7 @@ public: constructor.push_back (translated_expr); } - void visit (HIR::ArithmeticOrLogicalExpr &expr) override - { - auto op = expr.get_expr_type (); - auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); - auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); - auto location = expr.get_locus (); - - translated - = ctx->get_backend ()->arithmetic_or_logical_expression (op, lhs, rhs, - location); - } + void visit (HIR::ArithmeticOrLogicalExpr &expr) override; void visit (HIR::ComparisonExpr &expr) override { @@ -482,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 { @@ -999,6 +983,26 @@ public: expr.get_locus ()); } +protected: + Bexpression *compile_dyn_dispatch_call (const TyTy::DynamicObjectType *dyn, + TyTy::BaseType *receiver, + TyTy::FnType *fntype, + Bexpression *receiver_ref, + std::vector<HIR::Expr *> &arguments, + Location expr_locus); + + Bexpression *resolve_method_address (TyTy::FnType *fntype, HirId ref, + TyTy::BaseType *receiver, + HIR::PathIdentSegment &segment, + Analysis::NodeMapping expr_mappings, + Location expr_locus); + + Bexpression * + resolve_operator_overload (Analysis::RustLangItem::ItemType lang_item_type, + HIR::OperatorExpr &expr, Bexpression *lhs, + Bexpression *rhs, HIR::Expr *lhs_expr, + HIR::Expr *rhs_expr); + private: CompileExpr (Context *ctx) : HIRCompileBase (ctx), translated (nullptr), capacity_expr (nullptr) diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index e9aca2c..e53993a 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -242,220 +242,21 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) const TyTy::DynamicObjectType *dyn = static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ()); - size_t offs = 0; - const Resolver::TraitItemReference *ref = nullptr; - for (auto &bound : dyn->get_object_items ()) - { - const Resolver::TraitItemReference *item = bound.first; - auto t = item->get_tyty (); - rust_assert (t->get_kind () == TyTy::TypeKind::FNDEF); - auto ft = static_cast<TyTy::FnType *> (t); - - if (ft->get_id () == fntype->get_id ()) - { - ref = item; - break; - } - offs++; - } - - if (ref == nullptr) - { - translated = ctx->get_backend ()->error_expression (); - return; - } - - // get any indirection sorted out - auto receiver_ref = self; - if (receiver->get_kind () == TyTy::TypeKind::REF) - { - TyTy::ReferenceType *r - = static_cast<TyTy::ReferenceType *> (receiver); - auto indirect_ty = r->get_base (); - Btype *indrect_compiled_tyty - = TyTyResolveCompile::compile (ctx, indirect_ty); - - Bexpression *indirect - = ctx->get_backend ()->indirect_expression (indrect_compiled_tyty, - receiver_ref, true, - expr.get_locus ()); - receiver_ref = indirect; - } + std::vector<HIR::Expr *> arguments; + for (auto &arg : expr.get_arguments ()) + arguments.push_back (arg.get ()); - // access the offs + 1 for the fnptr and offs=0 for the reciever obj - Bexpression *self_argument - = ctx->get_backend ()->struct_field_expression (receiver_ref, 0, - expr.get_locus ()); - - // access the vtable for the fn - Bexpression *fn_vtable_access - = ctx->get_backend ()->struct_field_expression (receiver_ref, offs + 1, - expr.get_locus ()); - - // cast it to the correct fntype - Btype *expected_fntype = TyTyResolveCompile::compile (ctx, fntype, true); - Bexpression *fn_convert_expr - = ctx->get_backend ()->convert_expression (expected_fntype, - fn_vtable_access, - expr.get_locus ()); - - fncontext fnctx = ctx->peek_fn (); - Bblock *enclosing_scope = ctx->peek_enclosing_scope (); - bool is_address_taken = false; - Bstatement *ret_var_stmt = nullptr; - - Bvariable *fn_convert_expr_tmp = ctx->get_backend ()->temporary_variable ( - fnctx.fndecl, enclosing_scope, expected_fntype, fn_convert_expr, - is_address_taken, expr.get_locus (), &ret_var_stmt); - ctx->add_statement (ret_var_stmt); - - std::vector<Bexpression *> args; - args.push_back (self_argument); - for (auto &argument : expr.get_arguments ()) - { - Bexpression *compiled_expr - = CompileExpr::Compile (argument.get (), ctx); - args.push_back (compiled_expr); - } - - Bexpression *fn_expr - = ctx->get_backend ()->var_expression (fn_convert_expr_tmp, - expr.get_locus ()); - - translated - = ctx->get_backend ()->call_expression (fnctx.fndecl, fn_expr, args, - nullptr, expr.get_locus ()); + translated = compile_dyn_dispatch_call (dyn, receiver, fntype, self, + arguments, expr.get_locus ()); return; } - // address of compiled function - Bexpression *fn_expr = ctx->get_backend ()->error_expression (); - // lookup compiled functions since it may have already been compiled - Bfunction *fn = nullptr; - if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn)) - { - fn_expr - = ctx->get_backend ()->function_code_expression (fn, expr.get_locus ()); - } - else - { - // Now we can try and resolve the address since this might be a forward - // declared function, generic function which has not be compiled yet or - // its an not yet trait bound function - HIR::ImplItem *resolved_item = ctx->get_mappings ()->lookup_hir_implitem ( - expr.get_mappings ().get_crate_num (), ref, nullptr); - if (resolved_item == nullptr) - { - // it might be resolved to a trait item - HIR::TraitItem *trait_item - = ctx->get_mappings ()->lookup_hir_trait_item ( - expr.get_mappings ().get_crate_num (), ref); - HIR::Trait *trait = ctx->get_mappings ()->lookup_trait_item_mapping ( - trait_item->get_mappings ().get_hirid ()); - - Resolver::TraitReference *trait_ref - = &Resolver::TraitReference::error_node (); - bool ok = ctx->get_tyctx ()->lookup_trait_reference ( - trait->get_mappings ().get_defid (), &trait_ref); - rust_assert (ok); - - // the type resolver can only resolve type bounds to their trait - // item so its up to us to figure out if this path should resolve - // to an trait-impl-block-item or if it can be defaulted to the - // trait-impl-item's definition - - auto root = receiver->get_root (); - std::vector<Resolver::PathProbeCandidate> candidates - = Resolver::PathProbeType::Probe ( - root, expr.get_method_name ().get_segment (), true, false, true); - - if (candidates.size () == 0) - { - // this means we are defaulting back to the trait_item if - // possible - Resolver::TraitItemReference *trait_item_ref = nullptr; - bool ok = trait_ref->lookup_hir_trait_item (*trait_item, - &trait_item_ref); - rust_assert (ok); // found - rust_assert (trait_item_ref->is_optional ()); // has definition - - // FIXME Optional means it has a definition and an associated - // block which can be a default implementation, if it does not - // contain an implementation we should actually return - // error_mark_node - - TyTy::BaseType *self_type = nullptr; - if (!ctx->get_tyctx ()->lookup_type ( - expr.get_receiver ()->get_mappings ().get_hirid (), - &self_type)) - { - rust_error_at (expr.get_locus (), - "failed to resolve type for self param"); - return; - } - - fn_expr = CompileTraitItem::Compile ( - self_type, trait_item_ref->get_hir_trait_item (), ctx, fntype, - true, expr.get_locus ()); - } - else - { - std::vector<Resolver::Adjustment> adjustments; - Resolver::PathProbeCandidate *candidate - = Resolver::MethodResolution::Select (candidates, root, - adjustments); - - // FIXME this will be a case to return error_mark_node, there is - // an error scenario where a Trait Foo has a method Bar, but this - // receiver does not implement this trait or has an incompatible - // implementation and we should just return error_mark_node - rust_assert (candidate != nullptr); - rust_assert (candidate->is_impl_candidate ()); - - HIR::ImplItem *impl_item = candidate->item.impl.impl_item; - - TyTy::BaseType *self_type = nullptr; - if (!ctx->get_tyctx ()->lookup_type ( - expr.get_receiver ()->get_mappings ().get_hirid (), - &self_type)) - { - rust_error_at (expr.get_locus (), - "failed to resolve type for self param"); - return; - } - - if (!fntype->has_subsititions_defined ()) - fn_expr - = CompileInherentImplItem::Compile (self_type, impl_item, ctx, - true); - else - fn_expr - = CompileInherentImplItem::Compile (self_type, impl_item, ctx, - true, fntype); - } - } - else - { - TyTy::BaseType *self_type = nullptr; - if (!ctx->get_tyctx ()->lookup_type ( - expr.get_receiver ()->get_mappings ().get_hirid (), &self_type)) - { - rust_error_at (expr.get_locus (), - "failed to resolve type for self param"); - return; - } - - if (!fntype->has_subsititions_defined ()) - fn_expr - = CompileInherentImplItem::Compile (self_type, resolved_item, ctx, - true); - else - fn_expr - = CompileInherentImplItem::Compile (self_type, resolved_item, ctx, - true, fntype); - } - } + HIR::PathExprSegment method_name = expr.get_method_name (); + HIR::PathIdentSegment segment_name = method_name.get_segment (); + Bexpression *fn_expr + = resolve_method_address (fntype, ref, receiver, segment_name, + expr.get_mappings (), expr.get_locus ()); // lookup the autoderef mappings std::vector<Resolver::Adjustment> *adjustments = nullptr; diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h index 54cb6113..f36096b 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -452,11 +452,8 @@ public: expr.get_locus ()); } - /* Compound assignment expression is compiled away. */ void visit (AST::CompoundAssignmentExpr &expr) override { - /* First we need to find the corresponding arithmetic or logical operator. - */ ArithmeticOrLogicalOperator op; switch (expr.get_expr_type ()) { @@ -503,15 +500,10 @@ public: Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); - HIR::Expr *operator_expr - = new HIR::ArithmeticOrLogicalExpr (mapping, asignee_expr->clone_expr (), - std::unique_ptr<HIR::Expr> (value), - op, expr.get_locus ()); - translated - = new HIR::AssignmentExpr (mapping, - std::unique_ptr<HIR::Expr> (asignee_expr), - std::unique_ptr<HIR::Expr> (operator_expr), - expr.get_locus ()); + + translated = new HIR::CompoundAssignmentExpr ( + mapping, std::unique_ptr<HIR::Expr> (asignee_expr), + std::unique_ptr<HIR::Expr> (value), op, expr.get_locus ()); } void visit (AST::StructExprStruct &struct_expr) override diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h index db0425f..65a4921 100644 --- a/gcc/rust/hir/rust-ast-lower-item.h +++ b/gcc/rust/hir/rust-ast-lower-item.h @@ -613,29 +613,6 @@ public: if (trait.has_generics ()) { generic_params = lower_generic_params (trait.get_generic_params ()); - - for (auto &generic_param : generic_params) - { - switch (generic_param->get_kind ()) - { - case HIR::GenericParam::GenericKind::TYPE: { - const HIR::TypeParam &t - = static_cast<const HIR::TypeParam &> (*generic_param); - - if (t.has_type ()) - { - // see https://github.com/rust-lang/rust/issues/36887 - rust_error_at ( - t.get_locus (), - "defaults for type parameters are not allowed here"); - } - } - break; - - default: - break; - } - } } std::vector<std::unique_ptr<HIR::TypeParamBound>> type_param_bounds; diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index 575d1f6..901feda 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -666,6 +666,80 @@ protected: } }; +class CompoundAssignmentExpr : public OperatorExpr +{ +public: + using ExprType = ArithmeticOrLogicalOperator; + +private: + // Note: overloading trait specified in comments + ExprType expr_type; + std::unique_ptr<Expr> right_expr; + +public: + std::string as_string () const override; + + ExprType get_expr_type () const { return expr_type; } + + // Use pointers in constructor to enable polymorphism + CompoundAssignmentExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> value_to_assign_to, + std::unique_ptr<Expr> value_to_assign, + ExprType expr_kind, Location locus) + : OperatorExpr (std::move (mappings), std::move (value_to_assign_to), + AST::AttrVec (), locus), + expr_type (expr_kind), right_expr (std::move (value_to_assign)) + {} + // outer attributes not allowed + + // Have clone in copy constructor + CompoundAssignmentExpr (CompoundAssignmentExpr const &other) + : OperatorExpr (other), expr_type (other.expr_type), + right_expr (other.right_expr->clone_expr ()) + {} + + // Overload assignment operator to clone + CompoundAssignmentExpr &operator= (CompoundAssignmentExpr const &other) + { + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + right_expr = other.right_expr->clone_expr (); + expr_type = other.expr_type; + // outer_attrs = other.outer_attrs; + + return *this; + } + + // move constructors + CompoundAssignmentExpr (CompoundAssignmentExpr &&other) = default; + CompoundAssignmentExpr &operator= (CompoundAssignmentExpr &&other) = default; + + void accept_vis (HIRVisitor &vis) override; + + std::unique_ptr<Expr> &get_left_expr () + { + rust_assert (main_or_left_expr != nullptr); + return main_or_left_expr; + } + + std::unique_ptr<Expr> &get_right_expr () + { + rust_assert (right_expr != nullptr); + return right_expr; + } + + void visit_lhs (HIRVisitor &vis) { main_or_left_expr->accept_vis (vis); } + void visit_rhs (HIRVisitor &vis) { right_expr->accept_vis (vis); } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + CompoundAssignmentExpr *clone_expr_without_block_impl () const override + { + return new CompoundAssignmentExpr (*this); + } +}; + // Expression in parentheses (i.e. like literally just any 3 + (2 * 6)) class GroupedExpr : public ExprWithoutBlock { @@ -1635,7 +1709,6 @@ class MethodCallExpr : public ExprWithoutBlock { std::unique_ptr<Expr> receiver; PathExprSegment method_name; - // inlined form of CallParams std::vector<std::unique_ptr<Expr> > params; Location locus; @@ -1643,10 +1716,6 @@ class MethodCallExpr : public ExprWithoutBlock public: std::string as_string () const override; - /*inline std::vector<std::unique_ptr<Expr>> get_params() const { - return params; - }*/ - MethodCallExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> call_receiver, PathExprSegment method_path, diff --git a/gcc/rust/hir/tree/rust-hir-full-test.cc b/gcc/rust/hir/tree/rust-hir-full-test.cc index bacef82..843e32c 100644 --- a/gcc/rust/hir/tree/rust-hir-full-test.cc +++ b/gcc/rust/hir/tree/rust-hir-full-test.cc @@ -1316,6 +1316,67 @@ AssignmentExpr::as_string () const } std::string +CompoundAssignmentExpr::as_string () const +{ + std::string operator_str; + operator_str.reserve (1); + + // get operator string + switch (expr_type) + { + case ArithmeticOrLogicalOperator::ADD: + operator_str = "+"; + break; + case ArithmeticOrLogicalOperator::SUBTRACT: + operator_str = "-"; + break; + case ArithmeticOrLogicalOperator::MULTIPLY: + operator_str = "*"; + break; + case ArithmeticOrLogicalOperator::DIVIDE: + operator_str = "/"; + break; + case ArithmeticOrLogicalOperator::MODULUS: + operator_str = "%"; + break; + case ArithmeticOrLogicalOperator::BITWISE_AND: + operator_str = "&"; + break; + case ArithmeticOrLogicalOperator::BITWISE_OR: + operator_str = "|"; + break; + case ArithmeticOrLogicalOperator::BITWISE_XOR: + operator_str = "^"; + break; + case ArithmeticOrLogicalOperator::LEFT_SHIFT: + operator_str = "<<"; + break; + case ArithmeticOrLogicalOperator::RIGHT_SHIFT: + operator_str = ">>"; + break; + default: + gcc_unreachable (); + break; + } + + operator_str += "="; + + std::string str ("CompoundAssignmentExpr: "); + if (main_or_left_expr == nullptr || right_expr == nullptr) + { + str += "error. this is probably a parsing failure."; + } + else + { + str += "\n left: " + main_or_left_expr->as_string (); + str += "\n right: " + right_expr->as_string (); + str += "\n operator: " + operator_str; + } + + return str; +} + +std::string AsyncBlockExpr::as_string () const { std::string str = "AsyncBlockExpr: "; @@ -3819,6 +3880,12 @@ AssignmentExpr::accept_vis (HIRVisitor &vis) } void +CompoundAssignmentExpr::accept_vis (HIRVisitor &vis) +{ + vis.visit (*this); +} + +void GroupedExpr::accept_vis (HIRVisitor &vis) { vis.visit (*this); diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h b/gcc/rust/hir/tree/rust-hir-visitor.h index 0487446..ea125d9 100644 --- a/gcc/rust/hir/tree/rust-hir-visitor.h +++ b/gcc/rust/hir/tree/rust-hir-visitor.h @@ -47,6 +47,7 @@ public: virtual void visit (LazyBooleanExpr &expr) = 0; virtual void visit (TypeCastExpr &expr) = 0; virtual void visit (AssignmentExpr &expr) = 0; + virtual void visit (CompoundAssignmentExpr &expr) = 0; virtual void visit (GroupedExpr &expr) = 0; virtual void visit (ArrayElemsValues &elems) = 0; virtual void visit (ArrayElemsCopied &elems) = 0; diff --git a/gcc/rust/lint/rust-lint-marklive-base.h b/gcc/rust/lint/rust-lint-marklive-base.h index b67705b..e0494d7 100644 --- a/gcc/rust/lint/rust-lint-marklive-base.h +++ b/gcc/rust/lint/rust-lint-marklive-base.h @@ -53,7 +53,7 @@ public: virtual void visit (HIR::LazyBooleanExpr &) override {} virtual void visit (HIR::TypeCastExpr &) override {} virtual void visit (HIR::AssignmentExpr &) override {} - + virtual void visit (HIR::CompoundAssignmentExpr &) override {} virtual void visit (HIR::GroupedExpr &) override {} virtual void visit (HIR::ArrayElemsValues &) override {} diff --git a/gcc/rust/lint/rust-lint-marklive.h b/gcc/rust/lint/rust-lint-marklive.h index ca5d894..bcf792b 100644 --- a/gcc/rust/lint/rust-lint-marklive.h +++ b/gcc/rust/lint/rust-lint-marklive.h @@ -186,6 +186,12 @@ public: expr.visit_rhs (*this); } + void visit (HIR::CompoundAssignmentExpr &expr) override + { + expr.visit_lhs (*this); + expr.visit_rhs (*this); + } + void visit (HIR::IfExpr &expr) override { expr.get_if_condition ()->accept_vis (*this); diff --git a/gcc/rust/resolve/rust-ast-verify-assignee.h b/gcc/rust/resolve/rust-ast-verify-assignee.h index 6fbf5fe..d362fe4 100644 --- a/gcc/rust/resolve/rust-ast-verify-assignee.h +++ b/gcc/rust/resolve/rust-ast-verify-assignee.h @@ -75,6 +75,13 @@ public: } } + void visit (AST::DereferenceExpr &expr) override + { + expr.get_dereferenced_expr ()->accept_vis (*this); + } + + void visit (AST::PathInExpression &expr) override { ok = true; } + private: VerifyAsignee (NodeId parent) : ResolverBase (parent), ok (false) {} diff --git a/gcc/rust/typecheck/rust-autoderef.h b/gcc/rust/typecheck/rust-autoderef.h index a4799ec..db34755 100644 --- a/gcc/rust/typecheck/rust-autoderef.h +++ b/gcc/rust/typecheck/rust-autoderef.h @@ -68,6 +68,47 @@ private: const TyTy::BaseType *expected; }; +class Adjuster +{ +public: + Adjuster (const TyTy::BaseType *ty) : base (ty) {} + + TyTy::BaseType *adjust_type (std::vector<Adjustment> adjustments) + { + TyTy::BaseType *ty = base->clone (); + for (auto &adjustment : adjustments) + { + switch (adjustment.get_type ()) + { + case Resolver::Adjustment::AdjustmentType::IMM_REF: + ty = new TyTy::ReferenceType (ty->get_ref (), + TyTy::TyVar (ty->get_ref ()), + Mutability::Imm); + break; + + case Resolver::Adjustment::AdjustmentType::MUT_REF: + ty = new TyTy::ReferenceType (ty->get_ref (), + TyTy::TyVar (ty->get_ref ()), + Mutability::Mut); + break; + + case Resolver::Adjustment::AdjustmentType::DEREF_REF: + // FIXME this really needs to support deref lang-item operator + // overloads + rust_assert (ty->get_kind () == TyTy::TypeKind::REF); + const TyTy::ReferenceType *rr + = static_cast<const TyTy::ReferenceType *> (ty); + ty = rr->get_base (); + break; + } + } + return ty; + } + +private: + const TyTy::BaseType *base; +}; + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-const-fold-base.h b/gcc/rust/typecheck/rust-hir-const-fold-base.h index 9cbf1ab..0b41053 100644 --- a/gcc/rust/typecheck/rust-hir-const-fold-base.h +++ b/gcc/rust/typecheck/rust-hir-const-fold-base.h @@ -56,7 +56,7 @@ public: virtual void visit (HIR::LazyBooleanExpr &) override {} virtual void visit (HIR::TypeCastExpr &) override {} virtual void visit (HIR::AssignmentExpr &) override {} - + virtual void visit (HIR::CompoundAssignmentExpr &) override {} virtual void visit (HIR::GroupedExpr &) override {} virtual void visit (HIR::ArrayElemsValues &) override {} diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h index d318b9c..0c618d3 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.h +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -119,9 +119,10 @@ public: static std::vector<PathProbeCandidate> Probe (const TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name, bool probe_impls, - bool probe_bounds, bool ignore_mandatory_trait_items) + bool probe_bounds, bool ignore_mandatory_trait_items, + DefId specific_trait_id = UNKNOWN_DEFID) { - PathProbeType probe (receiver, segment_name); + PathProbeType probe (receiver, segment_name, specific_trait_id); if (probe_impls) { if (receiver->get_kind () == TyTy::TypeKind::ADT) @@ -145,6 +146,13 @@ public: for (auto &candidate : probed_bounds) { const TraitReference *trait_ref = candidate.first; + if (specific_trait_id != UNKNOWN_DEFID) + { + if (trait_ref->get_mappings ().get_defid () + != specific_trait_id) + continue; + } + HIR::ImplBlock *impl = candidate.second; probe.process_associated_trait_for_candidates ( trait_ref, impl, ignore_mandatory_trait_items); @@ -154,6 +162,13 @@ public: for (const TyTy::TypeBoundPredicate &predicate : receiver->get_specified_bounds ()) { + const TraitReference *trait_ref = predicate.get (); + if (specific_trait_id != UNKNOWN_DEFID) + { + if (trait_ref->get_mappings ().get_defid () != specific_trait_id) + continue; + } + probe.process_predicate_for_candidates (predicate, ignore_mandatory_trait_items); } @@ -221,6 +236,9 @@ public: protected: void process_enum_item_for_candiates (const TyTy::ADTType *adt) { + if (specific_trait_id != UNKNOWN_DEFID) + return; + TyTy::VariantDef *v; if (!adt->lookup_variant (search.as_string (), &v)) return; @@ -385,9 +403,9 @@ protected: protected: PathProbeType (const TyTy::BaseType *receiver, - const HIR::PathIdentSegment &query) + const HIR::PathIdentSegment &query, DefId specific_trait_id) : TypeCheckBase (), receiver (receiver), search (query), - current_impl (nullptr) + current_impl (nullptr), specific_trait_id (specific_trait_id) {} std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> @@ -427,6 +445,7 @@ protected: const HIR::PathIdentSegment &search; std::vector<PathProbeCandidate> candidates; HIR::ImplBlock *current_impl; + DefId specific_trait_id; }; class ReportMultipleCandidateError : private TypeCheckBase @@ -507,7 +526,8 @@ private: PathProbeImplTrait (const TyTy::BaseType *receiver, const HIR::PathIdentSegment &query, const TraitReference *trait_reference) - : PathProbeType (receiver, query), trait_reference (trait_reference) + : PathProbeType (receiver, query, UNKNOWN_DEFID), + trait_reference (trait_reference) {} const TraitReference *trait_reference; diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index cee6999..b2deb91 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -116,7 +116,7 @@ TraitItemReference::resolve_item (HIR::TraitItemFunc &func) // need to get the return type from this TyTy::FnType *resolved_fn_type = static_cast<TyTy::FnType *> (item_tyty); auto expected_ret_tyty = resolved_fn_type->get_return_type (); - context->push_return_type (expected_ret_tyty); + context->push_return_type (TypeCheckContextItem (&func), expected_ret_tyty); auto block_expr_ty = TypeCheckExpr::Resolve (func.get_block_expr ().get (), false); diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index a32b4da..54591ce 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -24,6 +24,7 @@ #include "rust-tyty-visitor.h" #include "rust-hir-type-check-type.h" #include "rust-hir-trait-ref.h" +#include "rust-expr.h" namespace Rust { namespace Resolver { @@ -206,6 +207,31 @@ private: // loop of trying to resolve traits as required by the types tref->on_resolved (); + // does this have any lang-item attributes? + for (auto &attr : trait_reference->get_outer_attrs ()) + { + bool is_lang_item = attr.get_path ().as_string ().compare ("lang") == 0 + && attr.has_attr_input () + && attr.get_attr_input ().get_attr_input_type () + == AST::AttrInput::AttrInputType::LITERAL; + if (is_lang_item) + { + auto &literal + = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ()); + const auto &lang_item_type_str + = literal.get_literal ().as_string (); + auto lang_item_type + = Analysis::RustLangItem::Parse (lang_item_type_str); + if (lang_item_type == Analysis::RustLangItem::ItemType::UNKNOWN) + { + rust_error_at (attr.get_locus (), "unknown lang item"); + return tref; + } + mappings->insert_lang_item ( + lang_item_type, trait_reference->get_mappings ().get_defid ()); + } + } + return tref; } diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h index eb96fd1..52dea21 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.h +++ b/gcc/rust/typecheck/rust-hir-type-check-base.h @@ -58,7 +58,7 @@ public: virtual void visit (HIR::LazyBooleanExpr &) override {} virtual void visit (HIR::TypeCastExpr &) override {} virtual void visit (HIR::AssignmentExpr &) override {} - + virtual void visit (HIR::CompoundAssignmentExpr &) override {} virtual void visit (HIR::GroupedExpr &) override {} virtual void visit (HIR::ArrayElemsValues &) override {} diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 2a6bae9..99696ae 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -470,6 +470,39 @@ public: result->clone ()); } + void visit (HIR::CompoundAssignmentExpr &expr) override + { + infered = new TyTy::TupleType (expr.get_mappings ().get_hirid ()); + + auto lhs = TypeCheckExpr::Resolve (expr.get_left_expr ().get (), false); + auto rhs = TypeCheckExpr::Resolve (expr.get_right_expr ().get (), false); + + // we dont care about the result of the unify from a compound assignment + // since this is a unit-type expr + auto result = lhs->unify (rhs); + if (result->get_kind () == TyTy::TypeKind::ERROR) + return; + + auto lang_item_type + = Analysis::RustLangItem::CompoundAssignmentOperatorToLangItem ( + expr.get_expr_type ()); + bool operator_overloaded + = resolve_operator_overload (lang_item_type, expr, lhs, rhs); + if (operator_overloaded) + return; + + bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ()); + bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ()); + bool valid = valid_lhs && valid_rhs; + if (!valid) + { + rust_error_at (expr.get_locus (), + "cannot apply this operator to types %s and %s", + lhs->as_string ().c_str (), rhs->as_string ().c_str ()); + return; + } + } + void visit (HIR::IdentifierExpr &expr) override { NodeId ast_node_id = expr.get_mappings ().get_nodeid (); @@ -699,6 +732,13 @@ public: auto lhs = TypeCheckExpr::Resolve (expr.get_lhs (), false); auto rhs = TypeCheckExpr::Resolve (expr.get_rhs (), false); + auto lang_item_type + = Analysis::RustLangItem::OperatorToLangItem (expr.get_expr_type ()); + bool operator_overloaded + = resolve_operator_overload (lang_item_type, expr, lhs, rhs); + if (operator_overloaded) + return; + bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ()); bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ()); bool valid = valid_lhs && valid_rhs; @@ -711,8 +751,6 @@ public: } infered = lhs->unify (rhs); - infered->append_reference (lhs->get_ref ()); - infered->append_reference (rhs->get_ref ()); } void visit (HIR::ComparisonExpr &expr) override @@ -736,17 +774,15 @@ public: // we expect the lhs and rhs must be bools at this point TyTy::BoolType elhs (expr.get_mappings ().get_hirid ()); lhs = elhs.unify (lhs); - if (lhs == nullptr || lhs->get_kind () == TyTy::TypeKind::ERROR) + if (lhs->get_kind () == TyTy::TypeKind::ERROR) return; TyTy::BoolType rlhs (expr.get_mappings ().get_hirid ()); rhs = elhs.unify (rhs); - if (lhs == nullptr || lhs->get_kind () == TyTy::TypeKind::ERROR) + if (lhs->get_kind () == TyTy::TypeKind::ERROR) return; infered = lhs->unify (rhs); - infered->append_reference (lhs->get_ref ()); - infered->append_reference (rhs->get_ref ()); } void visit (HIR::NegationExpr &expr) override @@ -754,6 +790,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 ()) { @@ -1174,6 +1219,203 @@ public: infered = expr_to_convert->cast (tyty_to_convert_to); } +protected: + bool + resolve_operator_overload (Analysis::RustLangItem::ItemType lang_item_type, + HIR::OperatorExpr &expr, TyTy::BaseType *lhs, + TyTy::BaseType *rhs) + { + // in order to probe of the correct type paths we need the root type, which + // strips any references + const TyTy::BaseType *root = lhs->get_root (); + + // look up lang item for arithmetic type + std::vector<PathProbeCandidate> candidates; + std::string associated_item_name + = Analysis::RustLangItem::ToString (lang_item_type); + DefId respective_lang_item_id = UNKNOWN_DEFID; + bool lang_item_defined + = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id); + + // probe for the lang-item + if (lang_item_defined) + { + bool receiver_is_type_param + = root->get_kind () == TyTy::TypeKind::PARAM; + bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC; + + bool receiver_is_generic = receiver_is_type_param || receiver_is_dyn; + bool probe_bounds = true; + bool probe_impls = !receiver_is_generic; + bool ignore_mandatory_trait_items = !receiver_is_generic; + + candidates = PathProbeType::Probe ( + root, HIR::PathIdentSegment (associated_item_name), probe_impls, + probe_bounds, ignore_mandatory_trait_items, respective_lang_item_id); + } + + // autoderef + std::vector<Adjustment> adjustments; + PathProbeCandidate *resolved_candidate + = MethodResolution::Select (candidates, lhs, adjustments); + + // is this the case we are recursive + // handle the case where we are within the impl block for this lang_item + // otherwise we end up with a recursive operator overload such as the i32 + // operator overload trait + if (lang_item_defined && resolved_candidate != nullptr) + { + TypeCheckContextItem &fn_context = context->peek_context (); + if (fn_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM) + { + auto &impl_item = fn_context.get_impl_item (); + HIR::ImplBlock *parent = impl_item.first; + HIR::Function *fn = impl_item.second; + + if (parent->has_trait_ref () + && fn->get_function_name ().compare (associated_item_name) == 0) + { + TraitReference *trait_reference + = TraitResolver::Lookup (*parent->get_trait_ref ().get ()); + if (!trait_reference->is_error ()) + { + TyTy::BaseType *lookup = nullptr; + bool ok + = context->lookup_type (fn->get_mappings ().get_hirid (), + &lookup); + rust_assert (ok); + rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF); + + TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup); + rust_assert (fntype->is_method ()); + + Adjuster adj (lhs); + TyTy::BaseType *adjusted = adj.adjust_type (adjustments); + + bool is_lang_item_impl + = trait_reference->get_mappings ().get_defid () + == respective_lang_item_id; + bool self_is_lang_item_self + = fntype->get_self_type ()->is_equal (*adjusted); + bool recursive_operator_overload + = is_lang_item_impl && self_is_lang_item_self; + + lang_item_defined = !recursive_operator_overload; + } + } + } + } + + bool have_implementation_for_lang_item = resolved_candidate != nullptr; + if (!lang_item_defined || !have_implementation_for_lang_item) + { + // no operator overload exists for this + return false; + } + + // now its just like a method-call-expr + context->insert_receiver (expr.get_mappings ().get_hirid (), lhs); + + // store the adjustments for code-generation to know what to do + context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (), + std::move (adjustments)); + + TyTy::BaseType *lookup_tyty = resolved_candidate->ty; + NodeId resolved_node_id + = resolved_candidate->is_impl_candidate () + ? resolved_candidate->item.impl.impl_item->get_impl_mappings () + .get_nodeid () + : resolved_candidate->item.trait.item_ref->get_mappings () + .get_nodeid (); + + rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::BaseType *lookup = lookup_tyty; + TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup); + rust_assert (fn->is_method ()); + + if (root->get_kind () == TyTy::TypeKind::ADT) + { + const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (root); + if (adt->has_substitutions () && fn->needs_substitution ()) + { + // consider the case where we have: + // + // struct Foo<X,Y>(X,Y); + // + // impl<T> Foo<T, i32> { + // fn test<X>(self, a:X) -> (T,X) { (self.0, a) } + // } + // + // In this case we end up with an fn type of: + // + // fn <T,X> test(self:Foo<T,i32>, a:X) -> (T,X) + // + // This means the instance or self we are calling this method for + // will be substituted such that we can get the inherited type + // arguments but then need to use the turbo fish if available or + // infer the remaining arguments. Luckily rust does not allow for + // default types GenericParams on impl blocks since these must + // always be at the end of the list + + auto s = fn->get_self_type ()->get_root (); + rust_assert (s->can_eq (adt, false, false)); + rust_assert (s->get_kind () == TyTy::TypeKind::ADT); + const TyTy::ADTType *self_adt + = static_cast<const TyTy::ADTType *> (s); + + // we need to grab the Self substitutions as the inherit type + // parameters for this + if (self_adt->needs_substitution ()) + { + rust_assert (adt->was_substituted ()); + + TyTy::SubstitutionArgumentMappings used_args_in_prev_segment + = GetUsedSubstArgs::From (adt); + + TyTy::SubstitutionArgumentMappings inherit_type_args + = self_adt->solve_mappings_from_receiver_for_self ( + used_args_in_prev_segment); + + // there may or may not be inherited type arguments + if (!inherit_type_args.is_error ()) + { + // need to apply the inherited type arguments to the + // function + lookup = fn->handle_substitions (inherit_type_args); + } + } + } + } + + // type check the arguments if required + TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup); + 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 (); + + // store the expected fntype + context->insert_operator_overload (expr.get_mappings ().get_hirid (), type); + + // set up the resolved name on the path + resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), + resolved_node_id); + + // return the result of the function back + infered = function_ret_tyty; + + return true; + } + private: TypeCheckExpr (bool inside_loop) : TypeCheckBase (), infered (nullptr), infered_array_elems (nullptr), @@ -1253,7 +1495,7 @@ private: Location root_array_expr_locus; bool inside_loop; -}; +}; // namespace Resolver } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h index 062d60b..64853f5 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h @@ -310,9 +310,10 @@ class TypeCheckImplItem : public TypeCheckBase public: using Rust::Resolver::TypeCheckBase::visit; - static void Resolve (HIR::ImplItem *item, TyTy::BaseType *self) + static void Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item, + TyTy::BaseType *self) { - TypeCheckImplItem resolver (self); + TypeCheckImplItem resolver (parent, self); item->accept_vis (resolver); } @@ -336,7 +337,8 @@ public: // need to get the return type from this TyTy::FnType *resolve_fn_type = static_cast<TyTy::FnType *> (lookup); auto expected_ret_tyty = resolve_fn_type->get_return_type (); - context->push_return_type (expected_ret_tyty); + context->push_return_type (TypeCheckContextItem (parent, &function), + expected_ret_tyty); auto block_expr_ty = TypeCheckExpr::Resolve (function.get_definition ().get (), false); @@ -346,8 +348,11 @@ public: } protected: - TypeCheckImplItem (TyTy::BaseType *self) : TypeCheckBase (), self (self) {} + TypeCheckImplItem (HIR::ImplBlock *parent, TyTy::BaseType *self) + : TypeCheckBase (), parent (parent), self (self) + {} + HIR::ImplBlock *parent; TyTy::BaseType *self; }; @@ -357,11 +362,12 @@ class TypeCheckImplItemWithTrait : public TypeCheckImplItem public: static const TraitItemReference & - Resolve (HIR::ImplItem *item, TyTy::BaseType *self, + Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self, TraitReference &trait_reference, std::vector<TyTy::SubstitutionParamMapping> substitutions) { - TypeCheckImplItemWithTrait resolver (self, trait_reference, substitutions); + TypeCheckImplItemWithTrait resolver (parent, self, trait_reference, + substitutions); item->accept_vis (resolver); return resolver.resolved_trait_item; } @@ -514,9 +520,10 @@ public: private: TypeCheckImplItemWithTrait ( - TyTy::BaseType *self, TraitReference &trait_reference, + HIR::ImplBlock *parent, TyTy::BaseType *self, + TraitReference &trait_reference, std::vector<TyTy::SubstitutionParamMapping> substitutions) - : TypeCheckImplItem (self), trait_reference (trait_reference), + : TypeCheckImplItem (parent, self), trait_reference (trait_reference), resolved_trait_item (TraitItemReference::error_node ()), substitutions (substitutions) { diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 706f649..cc102df 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -118,11 +118,12 @@ public: for (auto &impl_item : impl_block.get_impl_items ()) { if (!is_trait_impl_block) - TypeCheckImplItem::Resolve (impl_item.get (), self); + TypeCheckImplItem::Resolve (&impl_block, impl_item.get (), self); else { auto &trait_item_ref - = TypeCheckImplItemWithTrait::Resolve (impl_item.get (), self, + = TypeCheckImplItemWithTrait::Resolve (&impl_block, + impl_item.get (), self, *trait_reference, substitutions); trait_item_refs.push_back (trait_item_ref); @@ -210,7 +211,8 @@ public: // need to get the return type from this TyTy::FnType *resolved_fn_type = static_cast<TyTy::FnType *> (lookup); auto expected_ret_tyty = resolved_fn_type->get_return_type (); - context->push_return_type (expected_ret_tyty); + context->push_return_type (TypeCheckContextItem (&function), + expected_ret_tyty); auto block_expr_ty = TypeCheckExpr::Resolve (function.get_definition ().get (), false); diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h index 8df43d9..fb0e047 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h @@ -424,7 +424,8 @@ public: TyTy::FnType *resolved_fn_type = fnType; auto expected_ret_tyty = resolved_fn_type->get_return_type (); - context->push_return_type (expected_ret_tyty); + context->push_return_type (TypeCheckContextItem (&function), + expected_ret_tyty); auto block_expr_ty = TypeCheckExpr::Resolve (function.get_definition ().get (), false); diff --git a/gcc/rust/typecheck/rust-hir-type-check-util.h b/gcc/rust/typecheck/rust-hir-type-check-util.h index 4595ca3..f078df6 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-util.h +++ b/gcc/rust/typecheck/rust-hir-type-check-util.h @@ -51,7 +51,7 @@ public: virtual void visit (HIR::LazyBooleanExpr &) override {} virtual void visit (HIR::TypeCastExpr &) override {} virtual void visit (HIR::AssignmentExpr &) override {} - + virtual void visit (HIR::CompoundAssignmentExpr &) override {} virtual void visit (HIR::GroupedExpr &) override {} virtual void visit (HIR::ArrayElemsValues &) override {} diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index aa10f41..1add4fa 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -28,6 +28,68 @@ namespace Rust { namespace Resolver { +class TypeCheckContextItem +{ +public: + enum ItemType + { + ITEM, + IMPL_ITEM, + TRAIT_ITEM, + }; + + TypeCheckContextItem (HIR::Function *item) + : type (ItemType::ITEM), item (item) + {} + + TypeCheckContextItem (HIR::ImplBlock *impl_block, HIR::Function *item) + : type (ItemType::IMPL_ITEM), item (impl_block, item) + {} + + TypeCheckContextItem (HIR::TraitItemFunc *trait_item) + : type (ItemType::TRAIT_ITEM), item (trait_item) + {} + + ItemType get_type () const { return type; } + + HIR::Function *get_item () + { + rust_assert (get_type () == ItemType::ITEM); + return item.item; + } + + std::pair<HIR::ImplBlock *, HIR::Function *> &get_impl_item () + { + rust_assert (get_type () == ItemType::IMPL_ITEM); + return item.impl_item; + }; + + HIR::TraitItemFunc *get_trait_item () + { + rust_assert (get_type () == ItemType::TRAIT_ITEM); + return item.trait_item; + } + +private: + union Item + { + HIR::Function *item; + std::pair<HIR::ImplBlock *, HIR::Function *> impl_item; + HIR::TraitItemFunc *trait_item; + + Item (HIR::Function *item) : item (item) {} + + Item (HIR::ImplBlock *impl_block, HIR::Function *item) + : impl_item ({impl_block, item}) + {} + + Item (HIR::TraitItemFunc *trait_item) : trait_item (trait_item) {} + }; + + ItemType type; + Item item; +}; + class TypeCheckContext { public: @@ -49,7 +111,9 @@ public: bool lookup_type_by_node_id (NodeId ref, HirId *id); TyTy::BaseType *peek_return_type (); - void push_return_type (TyTy::BaseType *return_type); + TypeCheckContextItem &peek_context (); + void push_return_type (TypeCheckContextItem item, + TyTy::BaseType *return_type); void pop_return_type (); void iterate (std::function<bool (HirId, TyTy::BaseType *)> cb) @@ -232,13 +296,32 @@ public: return true; } + void insert_operator_overload (HirId id, TyTy::FnType *call_site) + { + auto it = operator_overloads.find (id); + rust_assert (it == operator_overloads.end ()); + + operator_overloads[id] = call_site; + } + + bool lookup_operator_overload (HirId id, TyTy::FnType **call) + { + auto it = operator_overloads.find (id); + if (it == operator_overloads.end ()) + return false; + + *call = it->second; + return true; + } + private: TypeCheckContext (); std::map<NodeId, HirId> node_id_refs; std::map<HirId, TyTy::BaseType *> resolved; std::vector<std::unique_ptr<TyTy::BaseType>> builtins; - std::vector<TyTy::BaseType *> return_type_stack; + std::vector<std::pair<TypeCheckContextItem, TyTy::BaseType *>> + return_type_stack; std::vector<TyTy::BaseType *> loop_type_stack; std::map<DefId, TraitReference> trait_context; std::map<HirId, TyTy::BaseType *> receiver_context; @@ -253,6 +336,9 @@ private: // adjustment mappings std::map<HirId, std::vector<Adjustment>> autoderef_mappings; + // operator overloads + std::map<HirId, TyTy::FnType *> operator_overloads; + // variants std::map<HirId, HirId> variants; }; diff --git a/gcc/rust/typecheck/rust-tyctx.cc b/gcc/rust/typecheck/rust-tyctx.cc index 02907d7..31f8ae5 100644 --- a/gcc/rust/typecheck/rust-tyctx.cc +++ b/gcc/rust/typecheck/rust-tyctx.cc @@ -122,13 +122,14 @@ TypeCheckContext::lookup_type_by_node_id (NodeId ref, HirId *id) TyTy::BaseType * TypeCheckContext::peek_return_type () { - return return_type_stack.back (); + return return_type_stack.back ().second; } void -TypeCheckContext::push_return_type (TyTy::BaseType *return_type) +TypeCheckContext::push_return_type (TypeCheckContextItem item, + TyTy::BaseType *return_type) { - return_type_stack.push_back (return_type); + return_type_stack.push_back ({std::move (item), return_type}); } void @@ -137,5 +138,11 @@ TypeCheckContext::pop_return_type () return_type_stack.pop_back (); } +TypeCheckContextItem & +TypeCheckContext::peek_context () +{ + return return_type_stack.back ().first; +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index 4fe64d45..4f8c389 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -23,13 +23,185 @@ #include "rust-location.h" #include "rust-mapping-common.h" #include "rust-canonical-path.h" - #include "rust-ast-full-decls.h" #include "rust-hir-full-decls.h" +#include "operator.h" namespace Rust { namespace Analysis { +// https://github.com/rust-lang/rust/blob/master/library/core/src/ops/arith.rs +class RustLangItem +{ +public: + enum ItemType + { + ADD, + SUBTRACT, + MULTIPLY, + DIVIDE, + REMAINDER, + + NEGATION, + NOT, + + ADD_ASSIGN, + SUB_ASSIGN, + MUL_ASSIGN, + DIV_ASSIGN, + REM_ASSIGN, + + UNKNOWN, + }; + + static ItemType Parse (const std::string &item) + { + if (item.compare ("add") == 0) + { + return ItemType::ADD; + } + else if (item.compare ("sub") == 0) + { + return ItemType::SUBTRACT; + } + else if (item.compare ("mul") == 0) + { + return ItemType::MULTIPLY; + } + else if (item.compare ("div") == 0) + { + return ItemType::DIVIDE; + } + else if (item.compare ("rem") == 0) + { + return ItemType::REMAINDER; + } + else if (item.compare ("neg") == 0) + { + return ItemType::NEGATION; + } + else if (item.compare ("not") == 0) + { + return ItemType::NOT; + } + else if (item.compare ("add_assign") == 0) + { + return ItemType::ADD_ASSIGN; + } + else if (item.compare ("sub_assign") == 0) + { + return ItemType::SUB_ASSIGN; + } + else if (item.compare ("mul_assign") == 0) + { + return ItemType::MUL_ASSIGN; + } + else if (item.compare ("div_assign") == 0) + { + return ItemType::DIV_ASSIGN; + } + else if (item.compare ("rem_assign") == 0) + { + return ItemType::REM_ASSIGN; + } + + return ItemType::UNKNOWN; + } + + static std::string ToString (ItemType type) + { + switch (type) + { + case ADD: + return "add"; + case SUBTRACT: + return "sub"; + case MULTIPLY: + return "mul"; + case DIVIDE: + return "div"; + case REMAINDER: + return "rem"; + case NEGATION: + return "neg"; + case NOT: + return "not"; + case ADD_ASSIGN: + return "add_assign"; + case SUB_ASSIGN: + return "sub_assign"; + case MUL_ASSIGN: + return "mul_assign"; + case DIV_ASSIGN: + return "div_assign"; + case REM_ASSIGN: + return "rem_assign"; + + case UNKNOWN: + break; + } + return "<UNKNOWN>"; + } + + static ItemType OperatorToLangItem (ArithmeticOrLogicalOperator op) + { + switch (op) + { + case ArithmeticOrLogicalOperator::ADD: + return ItemType::ADD; + case ArithmeticOrLogicalOperator::SUBTRACT: + return ItemType::SUBTRACT; + case ArithmeticOrLogicalOperator::MULTIPLY: + return ItemType::MULTIPLY; + case ArithmeticOrLogicalOperator::DIVIDE: + return ItemType::DIVIDE; + case ArithmeticOrLogicalOperator::MODULUS: + return ItemType::REMAINDER; + + default: + return ItemType::UNKNOWN; + } + return ItemType::UNKNOWN; + } + + static ItemType + CompoundAssignmentOperatorToLangItem (ArithmeticOrLogicalOperator op) + { + switch (op) + { + case ArithmeticOrLogicalOperator::ADD: + return ItemType::ADD_ASSIGN; + case ArithmeticOrLogicalOperator::SUBTRACT: + return ItemType::SUB_ASSIGN; + case ArithmeticOrLogicalOperator::MULTIPLY: + return ItemType::MUL_ASSIGN; + case ArithmeticOrLogicalOperator::DIVIDE: + return ItemType::DIV_ASSIGN; + case ArithmeticOrLogicalOperator::MODULUS: + return ItemType::REM_ASSIGN; + + 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; + } +}; + class NodeMapping { public: @@ -237,9 +409,9 @@ public: const Resolver::CanonicalPath *p = nullptr; if (lookup_canonical_path (crate, id, &p)) { - // if we have already stored a canonical path this is ok so long as this - // new path is equal or is smaller that the existing one but in that - // case we ignore it. + // if we have already stored a canonical path this is ok so long as + // this new path is equal or is smaller that the existing one but in + // that case we ignore it. if (p->is_equal (path)) return; else @@ -267,6 +439,24 @@ public: return true; } + void insert_lang_item (RustLangItem::ItemType item_type, DefId id) + { + auto it = lang_item_mappings.find (item_type); + rust_assert (it == lang_item_mappings.end ()); + + lang_item_mappings[item_type] = id; + } + + bool lookup_lang_item (RustLangItem::ItemType item_type, DefId *id) + { + auto it = lang_item_mappings.find (item_type); + if (it == lang_item_mappings.end ()) + return false; + + *id = it->second; + return true; + } + private: Mappings (); @@ -304,6 +494,9 @@ private: hirGenericParamMappings; std::map<HirId, HIR::Trait *> hirTraitItemsToTraitMappings; + // this maps the lang=<item_type> to DefId mappings + std::map<RustLangItem::ItemType, DefId> lang_item_mappings; + // canonical paths std::map<CrateNum, std::map<NodeId, const Resolver::CanonicalPath> > paths; diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_1.rs b/gcc/testsuite/rust/execute/torture/operator_overload_1.rs new file mode 100644 index 0000000..e52b394 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_1.rs @@ -0,0 +1,40 @@ +/* { dg-output "3\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "add"] +pub trait Add<Rhs = Self> { + type Output; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + fn add(self, rhs: Rhs) -> Self::Output; + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + // { dg-warning "unused name .rhs." "" { target *-*-* } .-2 } + // { dg-warning "unused name .Add::add." "" { target *-*-* } .-3 } +} + +impl Add for i32 { + type Output = i32; + + fn add(self, other: i32) -> i32 { + let res = self + other; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res); + } + + res + } +} + +fn main() -> i32 { + let a; + a = 1 + 2; + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_2.rs b/gcc/testsuite/rust/execute/torture/operator_overload_2.rs new file mode 100644 index 0000000..9d5615d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_2.rs @@ -0,0 +1,42 @@ +/* { dg-output "3\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "add"] +pub trait Add<Rhs = Self> { + type Output; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + fn add(self, rhs: Rhs) -> Self::Output; + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + // { dg-warning "unused name .rhs." "" { target *-*-* } .-2 } + // { dg-warning "unused name .Add::add." "" { target *-*-* } .-3 } +} + +struct Foo(i32); + +impl Add for Foo { + type Output = Foo; + + fn add(self, other: Foo) -> Foo { + let res = Foo(self.0 + other.0); + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res.0); + } + + res + } +} + +fn main() -> i32 { + let a; + a = Foo(1) + Foo(2); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/operator_overload_3.rs b/gcc/testsuite/rust/execute/torture/operator_overload_3.rs new file mode 100644 index 0000000..bd99b50 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/operator_overload_3.rs @@ -0,0 +1,59 @@ +/* { dg-output "3\n3\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "add"] +pub trait Add<Rhs = Self> { + type Output; + // { dg-warning "unused name" "" { target *-*-* } .-1 } + + fn add(self, rhs: Rhs) -> Self::Output; + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + // { dg-warning "unused name .rhs." "" { target *-*-* } .-2 } + // { dg-warning "unused name .Add::add." "" { target *-*-* } .-3 } +} + +impl Add for i32 { + type Output = i32; + + fn add(self, other: i32) -> i32 { + let res = self + other; + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res); + } + + res + } +} + +struct Foo(i32); +impl Add for Foo { + type Output = Foo; + + fn add(self, other: Foo) -> Foo { + let res = Foo(self.0 + other.0); + + unsafe { + let a = "%i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, res.0); + } + + res + } +} + +fn main() -> i32 { + let a; + a = Foo(1) + Foo(2); + + 0 +} 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 +} |