Generate paths for Enum and EnumItem AST NodeIds and resolve the types
of tuple and struct enum items.

EnumItems always have the Enum as prefix. To make this work for
ResolveStms (declaration statements are not given a canonical path) we
add an enum_prefix to be used when resolving EnumItems.

For ResolveType the tuple and struct fields get resolved using the
Enum type scope.

Add tests for toplevel or stmt enums with duplicate variant names. And
adjust the tuple_enum_variants.rs testcase to expect unused name
warnings.
---
 gcc/rust/resolve/rust-ast-resolve-item.h      |  36 ++++++
 gcc/rust/resolve/rust-ast-resolve-stmt.h      | 105 +++++++++++++++++-
 gcc/rust/resolve/rust-ast-resolve-toplevel.h  |  69 ++++++++++++
 gcc/testsuite/rust/compile/bad_stmt_enums.rs  |  22 ++++
 .../rust/compile/bad_toplevel_enums.rs        |  19 ++++
 .../compile/torture/tuple_enum_variants.rs    |   7 +-
 6 files changed, 254 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/bad_stmt_enums.rs
 create mode 100644 gcc/testsuite/rust/compile/bad_toplevel_enums.rs

diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h 
b/gcc/rust/resolve/rust-ast-resolve-item.h
index d3c053b609f..2a2f956a385 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -260,6 +260,42 @@ public:
     resolver->get_type_scope ().pop ();
   }
 
+  void visit (AST::Enum &enum_decl) override
+  {
+    NodeId scope_node_id = enum_decl.get_node_id ();
+    resolver->get_type_scope ().push (scope_node_id);
+
+    if (enum_decl.has_generics ())
+      {
+       for (auto &generic : enum_decl.get_generic_params ())
+         {
+           ResolveGenericParam::go (generic.get (), enum_decl.get_node_id ());
+         }
+      }
+
+    /* The actual fields are inside the variants.  */
+    for (auto &variant : enum_decl.get_variants ())
+      ResolveItem::go (variant.get ());
+
+    resolver->get_type_scope ().pop ();
+  }
+
+  /* EnumItem doesn't need to be handled, no fields.  */
+
+  void visit (AST::EnumItemTuple &item) override
+  {
+    for (auto &field : item.get_tuple_fields ())
+      ResolveType::go (field.get_field_type ().get (), item.get_node_id ());
+  }
+
+  void visit (AST::EnumItemStruct &item) override
+  {
+    for (auto &field : item.get_struct_fields ())
+      ResolveType::go (field.get_field_type ().get (), item.get_node_id ());
+  }
+
+  /* EnumItemDiscriminant doesn't need to be handled, no fields.  */
+
   void visit (AST::StructStruct &struct_decl) override
   {
     NodeId scope_node_id = struct_decl.get_node_id ();
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h 
b/gcc/rust/resolve/rust-ast-resolve-stmt.h
index b6044327b27..43bf0a421d6 100644
--- a/gcc/rust/resolve/rust-ast-resolve-stmt.h
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h
@@ -33,9 +33,11 @@ class ResolveStmt : public ResolverBase
   using Rust::Resolver::ResolverBase::visit;
 
 public:
-  static void go (AST::Stmt *stmt, NodeId parent)
+  static void go (AST::Stmt *stmt, NodeId parent,
+                 const CanonicalPath &enum_prefix
+                 = CanonicalPath::create_empty ())
   {
-    ResolveStmt resolver (parent);
+    ResolveStmt resolver (parent, enum_prefix);
     stmt->accept_vis (resolver);
   };
 
@@ -98,6 +100,97 @@ public:
     resolver->get_type_scope ().pop ();
   }
 
+  void visit (AST::Enum &enum_decl) override
+  {
+    auto enum_path = CanonicalPath::new_seg (enum_decl.get_node_id (),
+                                            enum_decl.get_identifier ());
+    resolver->get_type_scope ().insert (
+      enum_path, enum_decl.get_node_id (), enum_decl.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+       RichLocation r (enum_decl.get_locus ());
+       r.add_range (locus);
+       rust_error_at (r, "redefined multiple times");
+      });
+
+    NodeId scope_node_id = enum_decl.get_node_id ();
+    resolver->get_type_scope ().push (scope_node_id);
+
+    if (enum_decl.has_generics ())
+      {
+       for (auto &generic : enum_decl.get_generic_params ())
+         {
+           ResolveGenericParam::go (generic.get (), enum_decl.get_node_id ());
+         }
+      }
+
+    for (auto &variant : enum_decl.get_variants ())
+      ResolveStmt::go (variant.get (), parent, enum_path);
+
+    resolver->get_type_scope ().pop ();
+  }
+
+  void visit (AST::EnumItem &item) override
+  {
+    auto path = enum_prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+       RichLocation r (item.get_locus ());
+       r.add_range (locus);
+       rust_error_at (r, "redefined multiple times");
+      });
+
+    // Done, no fields.
+  }
+
+  void visit (AST::EnumItemTuple &item) override
+  {
+    auto path = enum_prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+       RichLocation r (item.get_locus ());
+       r.add_range (locus);
+       rust_error_at (r, "redefined multiple times");
+      });
+
+    for (auto &field : item.get_tuple_fields ())
+      ResolveType::go (field.get_field_type ().get (), item.get_node_id ());
+  }
+
+  void visit (AST::EnumItemStruct &item) override
+  {
+    auto path = enum_prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+       RichLocation r (item.get_locus ());
+       r.add_range (locus);
+       rust_error_at (r, "redefined multiple times");
+      });
+
+    for (auto &field : item.get_struct_fields ())
+      ResolveType::go (field.get_field_type ().get (), item.get_node_id ());
+  }
+
+  void visit (AST::EnumItemDiscriminant &item) override
+  {
+    auto path = enum_prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+       RichLocation r (item.get_locus ());
+       r.add_range (locus);
+       rust_error_at (r, "redefined multiple times");
+      });
+
+    // Done, no fields.
+  }
+
   void visit (AST::StructStruct &struct_decl) override
   {
     auto path = CanonicalPath::new_seg (struct_decl.get_node_id (),
@@ -219,7 +312,13 @@ public:
   }
 
 private:
-  ResolveStmt (NodeId parent) : ResolverBase (parent) {}
+  ResolveStmt (NodeId parent, const CanonicalPath &enum_prefix)
+    : ResolverBase (parent), enum_prefix (enum_prefix)
+  {}
+
+  /* item declaration statements are not given a canonical path, but enum items
+   * (variants) do inherit the enum path/identifier name.  */
+  const CanonicalPath &enum_prefix;
 };
 
 } // namespace Resolver
diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h 
b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
index 12392067be7..6f802a5b6e8 100644
--- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h
+++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
@@ -88,6 +88,75 @@ public:
       });
   }
 
+  void visit (AST::Enum &enum_decl) override
+  {
+    auto path
+      = prefix.append (CanonicalPath::new_seg (enum_decl.get_node_id (),
+                                              enum_decl.get_identifier ()));
+    resolver->get_type_scope ().insert (
+      path, enum_decl.get_node_id (), enum_decl.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+       RichLocation r (enum_decl.get_locus ());
+       r.add_range (locus);
+       rust_error_at (r, "redefined multiple times");
+      });
+
+    for (auto &variant : enum_decl.get_variants ())
+      ResolveTopLevel::go (variant.get (), path);
+  }
+
+  void visit (AST::EnumItem &item) override
+  {
+    auto path = prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+       RichLocation r (item.get_locus ());
+       r.add_range (locus);
+       rust_error_at (r, "redefined multiple times");
+      });
+  }
+
+  void visit (AST::EnumItemTuple &item) override
+  {
+    auto path = prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+       RichLocation r (item.get_locus ());
+       r.add_range (locus);
+       rust_error_at (r, "redefined multiple times");
+      });
+  }
+
+  void visit (AST::EnumItemStruct &item) override
+  {
+    auto path = prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+       RichLocation r (item.get_locus ());
+       r.add_range (locus);
+       rust_error_at (r, "redefined multiple times");
+      });
+  }
+
+  void visit (AST::EnumItemDiscriminant &item) override
+  {
+    auto path = prefix.append (
+      CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+    resolver->get_type_scope ().insert (
+      path, item.get_node_id (), item.get_locus (), false,
+      [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+       RichLocation r (item.get_locus ());
+       r.add_range (locus);
+       rust_error_at (r, "redefined multiple times");
+      });
+  }
+
   void visit (AST::StructStruct &struct_decl) override
   {
     auto path
diff --git a/gcc/testsuite/rust/compile/bad_stmt_enums.rs 
b/gcc/testsuite/rust/compile/bad_stmt_enums.rs
new file mode 100644
index 00000000000..7b09a94fd27
--- /dev/null
+++ b/gcc/testsuite/rust/compile/bad_stmt_enums.rs
@@ -0,0 +1,22 @@
+fn main ()
+{
+  enum EE
+    {
+      Alpha { alpha: i32 },
+      pub Beta (u8),
+      pub Gamma,
+      Gamma { gamma: u32 } // { dg-error "redefined" }
+    }
+
+  struct EE2 { }
+  enum EE2 { } // { dg-error "redefined" }
+
+  enum EE1
+    {
+      pub Alpha,
+      Beta = 41,
+      Beta = 42, // { dg-error "redefined" }
+      pub Gamma = 3,
+      D,
+    }
+}
diff --git a/gcc/testsuite/rust/compile/bad_toplevel_enums.rs 
b/gcc/testsuite/rust/compile/bad_toplevel_enums.rs
new file mode 100644
index 00000000000..b655e30a93d
--- /dev/null
+++ b/gcc/testsuite/rust/compile/bad_toplevel_enums.rs
@@ -0,0 +1,19 @@
+pub enum E
+{
+  pub A { a: i32 },
+  B (u8),
+  pub C,
+  B // { dg-error "redefined" }
+}
+
+enum E2 { }
+struct E2 { } // { dg-error "redefined" }
+
+enum E1
+{
+  A,
+  pub B = 42,
+  C = 3,
+  A { a: u8 }, // { dg-error "redefined" }
+  pub D
+}
diff --git a/gcc/testsuite/rust/compile/torture/tuple_enum_variants.rs 
b/gcc/testsuite/rust/compile/torture/tuple_enum_variants.rs
index 26e3e5d0a71..f65bd3b5c69 100644
--- a/gcc/testsuite/rust/compile/torture/tuple_enum_variants.rs
+++ b/gcc/testsuite/rust/compile/torture/tuple_enum_variants.rs
@@ -1,4 +1,9 @@
-enum E { T0(), T1(i32), T2(i32,u32) }
+enum E        // { dg-warning "unused name" }
+{
+  T0(),       // { dg-warning "unused name" }
+  T1(i32),    // { dg-warning "unused name" }
+  T2(i32,u32) // { dg-warning "unused name" }
+}
 
 /* The following doesn't parse yet...
 fn f(e0: E, e1: E, e2: E) -> (E,E,E,())
-- 
2.32.0

-- 
Gcc-rust mailing list
Gcc-rust@gcc.gnu.org
https://gcc.gnu.org/mailman/listinfo/gcc-rust

Reply via email to