From: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com>

Enum variants shouldn't be accessed directly even from within an enum.
This commit keeps the provenance for enum variants definition so we
can skip them when resolving a value within an enum definition.

gcc/rust/ChangeLog:

        * resolve/rust-forever-stack.h: Add new function to insert enum
        variants and add argument to resolver's get function to explicitely
        skip enum variants.
        * resolve/rust-forever-stack.hxx: Update function
        definitions.
        * resolve/rust-name-resolution-context.cc 
(NameResolutionContext::insert_variant):
        Add function to insert enum variants.
        * resolve/rust-name-resolution-context.h: Add function's prototype.
        * resolve/rust-rib.cc (Rib::Definition::Definition): Add new boolean to
        hint at enum variant provenance.
        (Rib::Definition::is_variant): New getter for variant status.
        (Rib::Definition::Shadowable): Update constructor to opt out of enum
        variants.
        (Rib::Definition::Globbed): Likewise.
        (Rib::Definition::NonShadowable): Change constructor to forward enum
        variant provenance status.
        * resolve/rust-rib.h: Update function prototypes.
        * resolve/rust-toplevel-name-resolver-2.0.cc 
(TopLevel::insert_enum_variant_or_error_out):
        Add function to insert enum variants in the name resolver.
        (TopLevel::visit): Update several enum variant's visitor function
        with the new enum variant name resolving code.
        * resolve/rust-toplevel-name-resolver-2.0.h: Update function
        prototypes.

Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com>
---
 gcc/rust/resolve/rust-forever-stack.h         |  3 ++
 gcc/rust/resolve/rust-forever-stack.hxx       | 18 +++++--
 .../resolve/rust-name-resolution-context.cc   |  6 +++
 .../resolve/rust-name-resolution-context.h    |  3 ++
 gcc/rust/resolve/rust-rib.cc                  | 17 ++++--
 gcc/rust/resolve/rust-rib.h                   | 14 ++++-
 .../rust-toplevel-name-resolver-2.0.cc        | 54 ++++++++++++++-----
 .../resolve/rust-toplevel-name-resolver-2.0.h | 17 +++++-
 8 files changed, 106 insertions(+), 26 deletions(-)

diff --git a/gcc/rust/resolve/rust-forever-stack.h 
b/gcc/rust/resolve/rust-forever-stack.h
index 64e8a0f0f2c..22efc973197 100644
--- a/gcc/rust/resolve/rust-forever-stack.h
+++ b/gcc/rust/resolve/rust-forever-stack.h
@@ -591,6 +591,9 @@ public:
    */
   tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id);
 
+  tl::expected<NodeId, DuplicateNameError> insert_variant (Identifier name,
+                                                          NodeId id);
+
   /**
    * Insert a new shadowable definition in the innermost `Rib` in this stack
    *
diff --git a/gcc/rust/resolve/rust-forever-stack.hxx 
b/gcc/rust/resolve/rust-forever-stack.hxx
index 9e66c802d5f..628b8c5b6fe 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -173,6 +173,14 @@ ForeverStack<Namespace::Labels>::insert (Identifier name, 
NodeId node)
                       Rib::Definition::Shadowable (node));
 }
 
+template <>
+inline tl::expected<NodeId, DuplicateNameError>
+ForeverStack<Namespace::Types>::insert_variant (Identifier name, NodeId node)
+{
+  return insert_inner (peek (), name.as_string (),
+                      Rib::Definition::NonShadowable (node, true));
+}
+
 template <Namespace N>
 Rib &
 ForeverStack<N>::peek ()
@@ -275,10 +283,12 @@ ForeverStack<N>::get (const Identifier &name)
 
     return candidate.map_or (
       [&resolved_definition] (Rib::Definition found) {
-       // for most namespaces, we do not need to care about various ribs - they
-       // are available from all contexts if defined in the current scope, or
-       // an outermore one. so if we do have a candidate, we can return it
-       // directly and stop iterating
+       if (found.is_variant ())
+         return KeepGoing::Yes;
+       // for most namespaces, we do not need to care about various ribs -
+       // they are available from all contexts if defined in the current
+       // scope, or an outermore one. so if we do have a candidate, we can
+       // return it directly and stop iterating
        resolved_definition = found;
 
        return KeepGoing::No;
diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc 
b/gcc/rust/resolve/rust-name-resolution-context.cc
index 1b375213878..517a4836aaf 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.cc
+++ b/gcc/rust/resolve/rust-name-resolution-context.cc
@@ -45,6 +45,12 @@ NameResolutionContext::insert (Identifier name, NodeId id, 
Namespace ns)
     }
 }
 
+tl::expected<NodeId, DuplicateNameError>
+NameResolutionContext::insert_variant (Identifier name, NodeId id)
+{
+  return types.insert_variant (name, id);
+}
+
 tl::expected<NodeId, DuplicateNameError>
 NameResolutionContext::insert_shadowable (Identifier name, NodeId id,
                                          Namespace ns)
diff --git a/gcc/rust/resolve/rust-name-resolution-context.h 
b/gcc/rust/resolve/rust-name-resolution-context.h
index a381411514d..ea81bdeed54 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.h
+++ b/gcc/rust/resolve/rust-name-resolution-context.h
@@ -172,6 +172,9 @@ public:
   tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id,
                                                   Namespace ns);
 
+  tl::expected<NodeId, DuplicateNameError> insert_variant (Identifier name,
+                                                          NodeId id);
+
   tl::expected<NodeId, DuplicateNameError>
   insert_shadowable (Identifier name, NodeId id, Namespace ns);
 
diff --git a/gcc/rust/resolve/rust-rib.cc b/gcc/rust/resolve/rust-rib.cc
index b0380bb0b78..1d53a741858 100644
--- a/gcc/rust/resolve/rust-rib.cc
+++ b/gcc/rust/resolve/rust-rib.cc
@@ -22,7 +22,8 @@
 namespace Rust {
 namespace Resolver2_0 {
 
-Rib::Definition::Definition (NodeId id, Mode mode)
+Rib::Definition::Definition (NodeId id, Mode mode, bool enum_variant)
+  : enum_variant (enum_variant)
 {
   switch (mode)
     {
@@ -51,6 +52,12 @@ Rib::Definition::is_ambiguous () const
     return ids_globbed.size () > 1;
 }
 
+bool
+Rib::Definition::is_variant () const
+{
+  return enum_variant;
+}
+
 std::string
 Rib::Definition::to_string () const
 {
@@ -75,19 +82,19 @@ Rib::Definition::to_string () const
 Rib::Definition
 Rib::Definition::Shadowable (NodeId id)
 {
-  return Definition (id, Mode::SHADOWABLE);
+  return Definition (id, Mode::SHADOWABLE, false);
 }
 
 Rib::Definition
-Rib::Definition::NonShadowable (NodeId id)
+Rib::Definition::NonShadowable (NodeId id, bool enum_variant)
 {
-  return Definition (id, Mode::NON_SHADOWABLE);
+  return Definition (id, Mode::NON_SHADOWABLE, enum_variant);
 }
 
 Rib::Definition
 Rib::Definition::Globbed (NodeId id)
 {
-  return Definition (id, Mode::GLOBBED);
+  return Definition (id, Mode::GLOBBED, false);
 }
 
 DuplicateNameError::DuplicateNameError (std::string name, NodeId existing)
diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h
index 767547f985f..ccc4c277b12 100644
--- a/gcc/rust/resolve/rust-rib.h
+++ b/gcc/rust/resolve/rust-rib.h
@@ -111,7 +111,7 @@ public:
   class Definition
   {
   public:
-    static Definition NonShadowable (NodeId id);
+    static Definition NonShadowable (NodeId id, bool enum_variant = false);
     static Definition Shadowable (NodeId id);
     static Definition Globbed (NodeId id);
 
@@ -124,11 +124,21 @@ public:
     std::vector<NodeId> ids_non_shadowable;
     std::vector<NodeId> ids_globbed;
 
+    // Enum variant should be skipped when dealing with inner definition.
+    // struct E2;
+    //
+    // enum MyEnum<T> /* <-- Should be kept */{
+    //     E2 /* <-- Should be skipped */ (E2);
+    // }
+    bool enum_variant;
+
     Definition () = default;
 
     Definition &operator= (const Definition &) = default;
     Definition (Definition const &) = default;
 
+    bool is_variant () const;
+
     bool is_ambiguous () const;
 
     NodeId get_node_id () const
@@ -155,7 +165,7 @@ public:
       GLOBBED
     };
 
-    Definition (NodeId id, Mode mode);
+    Definition (NodeId id, Mode mode, bool enum_variant);
   };
 
   enum class Kind
diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc 
b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
index 572d5956c0a..8863be768a1 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
@@ -32,21 +32,18 @@ TopLevel::TopLevel (NameResolutionContext &resolver)
 
 template <typename T>
 void
-TopLevel::insert_or_error_out (const Identifier &identifier, const T &node,
-                              Namespace ns)
+TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier,
+                                           const T &node)
 {
-  insert_or_error_out (identifier, node.get_locus (), node.get_node_id (), ns);
+  insert_enum_variant_or_error_out (identifier, node.get_locus (),
+                                   node.get_node_id ());
 }
 
 void
-TopLevel::insert_or_error_out (const Identifier &identifier,
-                              const location_t &locus, const NodeId &node_id,
-                              Namespace ns)
+TopLevel::check_multiple_insertion_error (
+  tl::expected<NodeId, DuplicateNameError> result, const Identifier 
&identifier,
+  const location_t &locus, const NodeId node_id)
 {
-  // keep track of each node's location to provide useful errors
-  node_locations.emplace (node_id, locus);
-
-  auto result = ctx.insert (identifier, node_id, ns);
   if (result)
     dirty = true;
   else if (result.error ().existing != node_id)
@@ -58,6 +55,37 @@ TopLevel::insert_or_error_out (const Identifier &identifier,
                     identifier.as_string ().c_str ());
     }
 }
+void
+TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier,
+                                           const location_t &locus,
+                                           const NodeId node_id)
+{
+  // keep track of each node's location to provide useful errors
+  node_locations.emplace (node_id, locus);
+
+  auto result = ctx.insert_variant (identifier, node_id);
+  check_multiple_insertion_error (result, identifier, locus, node_id);
+}
+
+template <typename T>
+void
+TopLevel::insert_or_error_out (const Identifier &identifier, const T &node,
+                              Namespace ns)
+{
+  insert_or_error_out (identifier, node.get_locus (), node.get_node_id (), ns);
+}
+
+void
+TopLevel::insert_or_error_out (const Identifier &identifier,
+                              const location_t &locus, const NodeId &node_id,
+                              Namespace ns)
+{
+  // keep track of each node's location to provide useful errors
+  node_locations.emplace (node_id, locus);
+
+  auto result = ctx.insert (identifier, node_id, ns);
+  check_multiple_insertion_error (result, identifier, locus, node_id);
+}
 
 void
 TopLevel::go (AST::Crate &crate)
@@ -336,19 +364,19 @@ TopLevel::visit (AST::TupleStruct &tuple_struct)
 void
 TopLevel::visit (AST::EnumItem &variant)
 {
-  insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
+  insert_enum_variant_or_error_out (variant.get_identifier (), variant);
 }
 
 void
 TopLevel::visit (AST::EnumItemTuple &variant)
 {
-  insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
+  insert_enum_variant_or_error_out (variant.get_identifier (), variant);
 }
 
 void
 TopLevel::visit (AST::EnumItemStruct &variant)
 {
-  insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
+  insert_enum_variant_or_error_out (variant.get_identifier (), variant);
 }
 
 void
diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h 
b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
index fabcb5bf707..559c0d8757f 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
@@ -114,9 +114,14 @@ public:
     return std::move (imports_to_resolve);
   }
 
+  void check_multiple_insertion_error (
+    tl::expected<NodeId, DuplicateNameError> result,
+    const Identifier &identifier, const location_t &locus,
+    const NodeId node_id);
+
   /**
-   * Insert a new definition or error out if a definition with the same name 
was
-   * already present in the same namespace in the same scope.
+   * Insert a new definition or error out if a definition with the same name
+   * was already present in the same namespace in the same scope.
    *
    * @param identifier The identifier of the definition to add.
    * @param node A reference to the node, so we can get its `NodeId` and
@@ -130,6 +135,14 @@ public:
                            const location_t &locus, const NodeId &id,
                            Namespace ns);
 
+  template <typename T>
+  void insert_enum_variant_or_error_out (const Identifier &identifier,
+                                        const T &node);
+
+  void insert_enum_variant_or_error_out (const Identifier &identifier,
+                                        const location_t &locus,
+                                        const NodeId node_id);
+
 private:
   // If a new export has been defined whilst visiting the visitor is considered
   // dirty
-- 
2.45.2

Reply via email to