]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Keep definition provenance to skip enum variants
authorPierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
Tue, 4 Mar 2025 15:41:48 +0000 (16:41 +0100)
committerArthur Cohen <arthur.cohen@embecosm.com>
Mon, 24 Mar 2025 12:07:15 +0000 (13:07 +0100)
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.patry@embecosm.com>
gcc/rust/resolve/rust-forever-stack.h
gcc/rust/resolve/rust-forever-stack.hxx
gcc/rust/resolve/rust-name-resolution-context.cc
gcc/rust/resolve/rust-name-resolution-context.h
gcc/rust/resolve/rust-rib.cc
gcc/rust/resolve/rust-rib.h
gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h

index 64e8a0f0f2c97ba8f79f4e632a98b5dda6d01d45..22efc9731977a1a42bbc2e6a900211daa5fa79d1 100644 (file)
@@ -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
    *
index 9e66c802d5f20bf7a20ae6a728b40d4a90eef28c..628b8c5b6fe83ee9eb872239888962a0680f87a0 100644 (file)
@@ -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;
index 1b375213878523014bb7df96dec711f8c7a14cb2..517a4836aafd40b443e5474387747b2d2b3e5b96 100644 (file)
@@ -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)
index a381411514d2facecf1218d907ad70758fcb5467..ea81bdeed54f73c4a79404430d09ce83c4521f88 100644 (file)
@@ -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);
 
index b0380bb0b78f4fdf79a5fe36b19b5a53a3b7005c..1d53a741858821e56c0fd23ed588fc698b10963f 100644 (file)
@@ -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)
index 767547f985f76c4e41a6cc8ca740740a1df35016..ccc4c277b1254e4ca097d6a317d966481fb185a6 100644 (file)
@@ -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
index 572d5956c0a89068b178981d191725f660ebae66..8863be768a1a390882a7790ded1d0aaf4025056c 100644 (file)
@@ -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
index fabcb5bf707359864431ff3fd78208e8320d271d..559c0d8757f2ae5062aee535bdd36ec548abc0db 100644 (file)
@@ -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