diff options
Diffstat (limited to 'gcc/rust/util')
-rw-r--r-- | gcc/rust/util/rust-hir-map.cc | 33 | ||||
-rw-r--r-- | gcc/rust/util/rust-hir-map.h | 10 | ||||
-rw-r--r-- | gcc/rust/util/rust-optional-test.cc | 110 | ||||
-rw-r--r-- | gcc/rust/util/rust-optional.h | 288 |
4 files changed, 22 insertions, 419 deletions
diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 783e899..793d547 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -1035,14 +1035,14 @@ Mappings::insert_module_child (NodeId module, NodeId child) it->second.emplace_back (child); } -Optional<std::vector<NodeId> &> +tl::optional<std::vector<NodeId> &> Mappings::lookup_module_children (NodeId module) { auto it = module_child_map.find (module); if (it == module_child_map.end ()) - return Optional<std::vector<NodeId> &>::none (); + return tl::nullopt; - return Optional<std::vector<NodeId> &>::some (it->second); + return it->second; } void @@ -1059,33 +1059,34 @@ Mappings::insert_module_child_item (NodeId module, it->second.emplace_back (child); } -Optional<std::vector<Resolver::CanonicalPath> &> +tl::optional<std::vector<Resolver::CanonicalPath> &> Mappings::lookup_module_chidren_items (NodeId module) { auto it = module_child_items.find (module); if (it == module_child_items.end ()) - return Optional<std::vector<Resolver::CanonicalPath> &>::none (); + return tl::nullopt; - return Optional<std::vector<Resolver::CanonicalPath> &>::some (it->second); + return it->second; } -Optional<Resolver::CanonicalPath &> +tl::optional<Resolver::CanonicalPath &> Mappings::lookup_module_child (NodeId module, const std::string &item_name) { - Optional<std::vector<Resolver::CanonicalPath> &> children + tl::optional<std::vector<Resolver::CanonicalPath> &> children = lookup_module_chidren_items (module); - if (children.is_none ()) - return Optional<Resolver::CanonicalPath &>::none (); + if (!children.has_value ()) + return tl::nullopt; // lookup the children to match the name if we can - for (auto &child : children.get ()) + for (auto &child : children.value ()) { const std::string &raw_identifier = child.get (); bool found = raw_identifier.compare (item_name) == 0; if (found) - return Optional<Resolver::CanonicalPath &>::some (child); + return child; } - return Optional<Resolver::CanonicalPath &>::none (); + + return tl::nullopt; } void @@ -1095,14 +1096,14 @@ Mappings::insert_child_item_to_parent_module_mapping (NodeId child_item, child_to_parent_module_map.insert ({child_item, parent_module}); } -Optional<NodeId> +tl::optional<NodeId> Mappings::lookup_parent_module (NodeId child_item) { auto it = child_to_parent_module_map.find (child_item); if (it == child_to_parent_module_map.end ()) - return Optional<NodeId>::none (); + return tl::nullopt; - return Optional<NodeId>::some (it->second); + return it->second; } bool diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index 964b626..495bca2 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -19,7 +19,7 @@ #ifndef RUST_HIR_MAP_H #define RUST_HIR_MAP_H -#include "rust-optional.h" +#include "optional.h" #include "rust-system.h" #include "rust-location.h" #include "rust-mapping-common.h" @@ -303,17 +303,17 @@ public: bool lookup_visibility (NodeId id, Privacy::ModuleVisibility &def); void insert_module_child (NodeId module, NodeId child); - Optional<std::vector<NodeId> &> lookup_module_children (NodeId module); + tl::optional<std::vector<NodeId> &> lookup_module_children (NodeId module); void insert_module_child_item (NodeId module, Resolver::CanonicalPath item); - Optional<std::vector<Resolver::CanonicalPath> &> + tl::optional<std::vector<Resolver::CanonicalPath> &> lookup_module_chidren_items (NodeId module); - Optional<Resolver::CanonicalPath &> + tl::optional<Resolver::CanonicalPath &> lookup_module_child (NodeId module, const std::string &item_name); void insert_child_item_to_parent_module_mapping (NodeId child_item, NodeId parent_module); - Optional<NodeId> lookup_parent_module (NodeId child_item); + tl::optional<NodeId> lookup_parent_module (NodeId child_item); bool node_is_module (NodeId query); void insert_ast_item (AST::Item *item); diff --git a/gcc/rust/util/rust-optional-test.cc b/gcc/rust/util/rust-optional-test.cc deleted file mode 100644 index 9fbbe7d..0000000 --- a/gcc/rust/util/rust-optional-test.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (C) 2020-2023 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-system.h" -#include "rust-optional.h" -#include "selftest.h" - -#if CHECKING_P - -static void -rust_optional_create () -{ - auto opt = Rust::Optional<int>::some (15); - - ASSERT_TRUE (opt.is_some ()); - ASSERT_EQ (opt.get (), 15); - - Rust::Optional<int> const_opt = Rust::Optional<int>::some (15); - const int &value = const_opt.get (); - - ASSERT_EQ (value, 15); -} - -static void -rust_optional_operators () -{ - auto opt = Rust::Optional<int>::some (15); - - // as bool - ASSERT_TRUE (opt); - - // deref - ASSERT_EQ (*opt, 15); - - class Methodable - { - public: - int method () { return 15; } - }; - - auto m_opt = Rust::Optional<Methodable>::some (Methodable ()); - ASSERT_EQ (m_opt->method (), 15); -} - -static void -rust_optional_take () -{ - auto opt = Rust::Optional<int>::some (15); - auto value = opt.take (); - - ASSERT_EQ (value, 15); - ASSERT_TRUE (opt.is_none ()); -} - -static void -rust_optional_map () -{ - auto opt = Rust::Optional<int>::some (15); - auto twice = opt.map<int> ([] (int value) { return value * 2; }); - - ASSERT_FALSE (opt); - ASSERT_TRUE (twice); - ASSERT_EQ (*twice, 30); -} - -static void -rust_optional_reference () -{ - auto value = std::vector<std::string> (); - value.emplace_back ("rust"); - value.emplace_back ("+"); - value.emplace_back ("gcc"); - value.emplace_back ("="); - value.emplace_back ("<3"); - - auto opt = Rust::Optional<std::vector<std::string> &>::some (value); - - ASSERT_EQ (opt->at (0), "rust"); - ASSERT_EQ (opt->at (2), "gcc"); -} - -#endif /* #if CHECKING_P */ - -void -rust_optional_test () -{ -#if CHECKING_P - rust_optional_create (); - rust_optional_operators (); - rust_optional_take (); - rust_optional_map (); - rust_optional_reference (); - -#endif /* #if CHECKING_P */ -} diff --git a/gcc/rust/util/rust-optional.h b/gcc/rust/util/rust-optional.h deleted file mode 100644 index bdfbd28..0000000 --- a/gcc/rust/util/rust-optional.h +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright (C) 2020-2023 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/>. - -#ifndef RUST_OPTIONAL_H -#define RUST_OPTIONAL_H - -#include "config.h" -#include "rust-system.h" - -#include "selftest.h" - -namespace Rust { - -/** - * Tagged union to try and simulate a sum type. This is safer and more ergonomic - * than one of the two alternatives we're currently using in the compiler: - * - * 1. Storing a raw pointer, which can be `nullptr` or valid - * - * This is wildly unsafe, and usable in conjunction with local references, stack - * variables, or pointers managed elsewhere, which can cause crashes, hard to - * debug issues or undefined behavior. Likewise, if you do not check for the - * pointer's validity, this will cause a crash. - * - * 2. Storing an extra boolean alongside the object - * - * This causes implementors to use a "dummy object": Either an empty version or - * an error version. But what happens if what you really wanted to store was - * the empty or error version? You can also easily incorporate logic bugs if you - * forget to check for the associated boolean. - * - * The `Optional<T>` type has the same "ergonomic" cost: You need to check - * whether your option is valid or not. However, the main advantage is that it - * is more restrictive: You can only acess the member it contains "safely". - * It is similar to storing a value + an associated boolean, but has the - * advantage of making up only one member in your class. - * You also benefit from some helper methods such as `map()`. - * - * You also get helper functions and operator overloading to "seamlessly" - * replace raw pointer alternatives. - * - * ```c++ - * MyType *raw_pointer = something_that_can_fail(); - * if (raw_pointer) - * raw_pointer->method(); - * - * // or - * - * Optional<MyType> opt = something_that_can_fail2(); - * if (opt) - * opt->method(); - * - * // equivalent to - * - * if (opt.is_some()) - * opt.get().method(); - * ``` - */ -template <typename T> class Optional -{ -private: - struct tag_some - { - }; - struct tag_none - { - }; - - bool field_is_some; - - union - { - T value; - // prevents initialization warnings - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635#c53 - // FIXME: remove - volatile char unused; - }; - - Optional (tag_some, const T &value) : field_is_some (true), value (value) {} - Optional (tag_some, T &&value) : field_is_some (true), value (value) {} - - Optional (tag_none) : field_is_some (false) {} - -public: - Optional (const Optional &other) - { - if ((field_is_some = other.field_is_some)) - new (&value) T (other.value); - } - - Optional (Optional &&other) - { - if ((field_is_some = other.field_is_some)) - new (&value) T (other.value); - } - - Optional &operator= (const Optional &other) - { - if (is_some ()) - value.~T (); - if ((field_is_some = other.field_is_some)) - new (&value) T (other.value); - return *this; - } - - Optional &operator= (Optional &&other) - { - if (is_some ()) - value.~T (); - if ((field_is_some = other.field_is_some)) - new (&value) T (other.value); - return *this; - } - - ~Optional () - { - if (is_some ()) - value.~T (); - } - - static Optional some (const T &value) - { - return Optional (tag_some (), value); - } - - static Optional some (T &&value) { return Optional (tag_some (), value); } - - static Optional none () { return Optional (tag_none ()); } - - bool is_some () const { return field_is_some; } - bool is_none () const { return !is_some (); } - - /** - * Enable boolean-like comparisons. - */ - operator bool () { return is_some (); } - - /** - * Enables dereferencing to access the contained value - */ - T &operator* () { return get (); } - const T &operator* () const { return get (); } - T *operator-> () { return &get (); } - const T *operator-> () const { return &get (); } - - const T &get () const - { - rust_assert (is_some ()); - - return value; - } - - T &get () - { - rust_assert (is_some ()); - - return value; - } - - T take () - { - rust_assert (is_some ()); - - T to_return = std::move (value); - value.~T (); - - field_is_some = false; - - return to_return; - } - - template <typename U> Optional<U> map (std::function<U (T)> functor) - { - if (is_none ()) - return Optional::none (); - - auto value = functor (take ()); - - return Optional::some (value); - } -}; - -template <typename T> class Optional<T &> -{ -private: - T *inner; - - Optional (T *inner) : inner (inner) {} - -public: - static Optional<T &> some (T &value) { return Optional (&value); } - - static Optional<T &> none () { return Optional (nullptr); } - - bool is_some () const { return inner; } - bool is_none () const { return !is_some (); } - - // FIXME: Can we factor this in a single class? - - /** - * Enable boolean-like comparisons. - */ - operator bool () { return is_some (); } - - /** - * Enables dereferencing to access the contained value - */ - T &operator* () { return get (); } - const T &operator* () const { return get (); } - T *operator-> () { return &get (); } - const T *operator-> () const { return &get (); } - - T &get () const - { - rust_assert (is_some ()); - - return *inner; - } - - T &take () - { - rust_assert (is_some ()); - - T *to_return = inner; - inner = nullptr; - - return *to_return; - } - - template <typename U> Optional<U &> map (std::function<U &(T &)> functor) - { - if (is_none ()) - return Optional::none (); - - auto value = functor (take ()); - - return Optional::some (value); - } -}; - -template <typename T, typename U> -bool -operator== (const Optional<T> &t, const Optional<U> &u) -{ - if (t.is_some ()) - return u.is_some () && t.get () == u.get (); - else - return u.is_none (); -} - -} // namespace Rust - -namespace std { - -template <typename T> struct hash<Rust::Optional<T>> -{ - size_t operator() (const Rust::Optional<T> &op) const - { - return op.is_some () ? std::hash<T> () (op.get ()) : 0; - } -}; - -} // namespace std - -#ifdef CHECKING_P - -void -rust_optional_test (); - -#endif // !CHECKING_P - -#endif // !RUST_OPTIONAL_H |