[gcc r14-7387] gccrs: support use declaration to write the type into the correct namespace

Arthur Cohen cohenarthur@gcc.gnu.org
Tue Jan 16 17:27:49 GMT 2024


https://gcc.gnu.org/g:7e7cffb709def41f3df115d7be4ce86b466d5011

commit r14-7387-g7e7cffb709def41f3df115d7be4ce86b466d5011
Author: Philip Herron <herron.philip@googlemail.com>
Date:   Fri Mar 17 22:46:37 2023 +0000

    gccrs: support use declaration to write the type into the correct namespace
    
    This builds upon the previous path resolution fixes so that it returns the
    resolved_node_id or UNKNOWN_NODEID on failure to resolve the use-path.
    It then exports the name to the current module namespace so it can be used.
    
    Fixes #850 #855
    
    gcc/rust/ChangeLog:
    
            * ast/rust-ast.h: add const get_final_segment helper
            * hir/rust-ast-lower-enumitem.h: dont add an item mapping for enumitems
            * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): add enum to enum-items mappings
            * hir/rust-ast-lower-stmt.cc (ASTLoweringStmt::visit): likewise
            * hir/tree/rust-hir-item.h: add non const helper to get variants
            * resolve/rust-ast-resolve-item.cc (ResolveItem::visit): resolve the use declaration
            * resolve/rust-ast-resolve-path.cc (ResolvePath::resolve_path): handle self
            * resolve/rust-ast-resolve-toplevel.h: add enum item mappings to module mappings
            * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::resolve_root_path): ensure variant
            (TypeCheckExpr::resolve_segments): likewise
            * typecheck/rust-type-util.cc (query_type): lookup enum's
            * util/rust-hir-map.cc (Mappings::insert_hir_enumitem): enum item mappings
            (Mappings::lookup_hir_enumitem): likewise
            * util/rust-hir-map.h: likewise
    
    gcc/testsuite/ChangeLog:
    
            * rust/compile/issue-850.rs: New test.
            * rust/compile/issue-855.rs: New test.
    
    Signed-off-by: Philip Herron <herron.philip@googlemail.com>

Diff:
---
 gcc/rust/ast/rust-ast.h                        |  5 +++
 gcc/rust/hir/rust-ast-lower-enumitem.h         |  1 -
 gcc/rust/hir/rust-ast-lower-item.cc            | 15 ++++++---
 gcc/rust/hir/rust-ast-lower-stmt.cc            | 15 ++++++---
 gcc/rust/hir/tree/rust-hir-item.h              |  2 ++
 gcc/rust/resolve/rust-ast-resolve-item.cc      | 23 ++++++++++++--
 gcc/rust/resolve/rust-ast-resolve-path.cc      | 27 +++++++++++++++-
 gcc/rust/resolve/rust-ast-resolve-toplevel.h   | 19 ++++++++++++
 gcc/rust/typecheck/rust-hir-type-check-path.cc | 21 +++++++++++--
 gcc/rust/typecheck/rust-type-util.cc           | 19 ++++++++++--
 gcc/rust/util/rust-hir-map.cc                  | 21 +++++++++++++
 gcc/rust/util/rust-hir-map.h                   |  4 +++
 gcc/testsuite/rust/compile/issue-850.rs        | 43 ++++++++++++++++++++++++++
 gcc/testsuite/rust/compile/issue-855.rs        | 23 ++++++++++++++
 14 files changed, 220 insertions(+), 18 deletions(-)

diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index fe520abd126..5e5913b95f6 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -422,6 +422,11 @@ public:
   }
 
   std::vector<SimplePathSegment> &get_segments () { return segments; }
+
+  const SimplePathSegment &get_final_segment () const
+  {
+    return segments.back ();
+  }
 };
 
 // path-to-string inverse comparison operator
diff --git a/gcc/rust/hir/rust-ast-lower-enumitem.h b/gcc/rust/hir/rust-ast-lower-enumitem.h
index a1e63a195df..d78d8b17a61 100644
--- a/gcc/rust/hir/rust-ast-lower-enumitem.h
+++ b/gcc/rust/hir/rust-ast-lower-enumitem.h
@@ -46,7 +46,6 @@ public:
     auto defid = resolver.translated->get_mappings ().get_defid ();
 
     resolver.mappings->insert_defid_mapping (defid, resolver.translated);
-    resolver.mappings->insert_hir_item (resolver.translated);
     resolver.mappings->insert_location (hirid,
 					resolver.translated->get_locus ());
 
diff --git a/gcc/rust/hir/rust-ast-lower-item.cc b/gcc/rust/hir/rust-ast-lower-item.cc
index b3eca529829..07a5fc87ad0 100644
--- a/gcc/rust/hir/rust-ast-lower-item.cc
+++ b/gcc/rust/hir/rust-ast-lower-item.cc
@@ -274,11 +274,16 @@ ASTLoweringItem::visit (AST::Enum &enum_decl)
 				 mappings->get_next_hir_id (crate_num),
 				 mappings->get_next_localdef_id (crate_num));
 
-  translated = new HIR::Enum (mapping, enum_decl.get_identifier (), vis,
-			      std::move (generic_params),
-			      std::move (where_clause), /* is_unit, */
-			      std::move (items), enum_decl.get_outer_attrs (),
-			      enum_decl.get_locus ());
+  HIR::Enum *hir_enum
+    = new HIR::Enum (mapping, enum_decl.get_identifier (), vis,
+		     std::move (generic_params), std::move (where_clause),
+		     std::move (items), enum_decl.get_outer_attrs (),
+		     enum_decl.get_locus ());
+  translated = hir_enum;
+  for (auto &variant : hir_enum->get_variants ())
+    {
+      mappings->insert_hir_enumitem (hir_enum, variant.get ());
+    }
 }
 
 void
diff --git a/gcc/rust/hir/rust-ast-lower-stmt.cc b/gcc/rust/hir/rust-ast-lower-stmt.cc
index dbff8ad715f..5ba8db002d0 100644
--- a/gcc/rust/hir/rust-ast-lower-stmt.cc
+++ b/gcc/rust/hir/rust-ast-lower-stmt.cc
@@ -301,11 +301,16 @@ ASTLoweringStmt::visit (AST::Enum &enum_decl)
 				 mappings->get_next_hir_id (crate_num),
 				 mappings->get_next_localdef_id (crate_num));
 
-  translated = new HIR::Enum (mapping, enum_decl.get_identifier (), vis,
-			      std::move (generic_params),
-			      std::move (where_clause), /* is_unit, */
-			      std::move (items), enum_decl.get_outer_attrs (),
-			      enum_decl.get_locus ());
+  HIR::Enum *hir_enum
+    = new HIR::Enum (mapping, enum_decl.get_identifier (), vis,
+		     std::move (generic_params), std::move (where_clause),
+		     std::move (items), enum_decl.get_outer_attrs (),
+		     enum_decl.get_locus ());
+  translated = hir_enum;
+  for (auto &variant : hir_enum->get_variants ())
+    {
+      mappings->insert_hir_enumitem (hir_enum, variant.get ());
+    }
 }
 
 void
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index fa52d7aa041..e1a2b4eaeab 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -1966,6 +1966,8 @@ public:
     return items;
   }
 
+  std::vector<std::unique_ptr<EnumItem>> &get_variants () { return items; }
+
 protected:
   /* Use covariance to implement clone function as returning this object
    * rather than base */
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc
index 4f3b924a586..c1590ca3a2f 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-item.cc
@@ -983,7 +983,7 @@ flatten_use_dec_to_paths (const AST::UseDeclaration &use_item)
 void
 ResolveItem::visit (AST::UseDeclaration &use_item)
 {
-  auto to_resolve = flatten_use_dec_to_paths (use_item);
+  std::vector<AST::SimplePath> to_resolve = flatten_use_dec_to_paths (use_item);
 
   // FIXME: I think this does not actually resolve glob use-decls and is going
   // the wrong way about it. RFC #1560 specifies the following:
@@ -993,8 +993,27 @@ ResolveItem::visit (AST::UseDeclaration &use_item)
   // importing module.
   //
   // Which is the opposite of what we're doing if I understand correctly?
+
+  NodeId current_module = resolver->peek_current_module_scope ();
   for (auto &path : to_resolve)
-    ResolvePath::go (&path);
+    {
+      rust_debug ("resolving use-decl path: [%s]", path.as_string ().c_str ());
+      NodeId resolved_node_id = ResolvePath::go (&path);
+      bool ok = resolved_node_id != UNKNOWN_NODEID;
+      if (!ok)
+	continue;
+
+      const AST::SimplePathSegment &final_seg = path.get_final_segment ();
+
+      auto decl
+	= CanonicalPath::new_seg (resolved_node_id, final_seg.as_string ());
+      mappings->insert_module_child_item (current_module, decl);
+
+      resolver->get_type_scope ().insert (decl, resolved_node_id,
+					  path.get_locus (),
+					  Rib::ItemType::Type);
+      rust_debug ("use-decl rexporting: [%s]", decl.get ().c_str ());
+    }
 }
 
 ResolveImplItems::ResolveImplItems (const CanonicalPath &prefix,
diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc
index bd0b0433263..9c3a2eeace0 100644
--- a/gcc/rust/resolve/rust-ast-resolve-path.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-path.cc
@@ -267,17 +267,20 @@ ResolvePath::resolve_path (AST::SimplePath *expr)
   NodeId crate_scope_id = resolver->peek_crate_module_scope ();
   NodeId module_scope_id = resolver->peek_current_module_scope ();
 
+  NodeId previous_resolved_node_id = UNKNOWN_NODEID;
   NodeId resolved_node_id = UNKNOWN_NODEID;
   for (size_t i = 0; i < expr->get_segments ().size (); i++)
     {
-      auto &segment = expr->get_segments ().at (i);
+      AST::SimplePathSegment &segment = expr->get_segments ().at (i);
       bool is_first_segment = i == 0;
+      bool is_final_segment = i >= (expr->get_segments ().size () - 1);
       resolved_node_id = UNKNOWN_NODEID;
 
       if (segment.is_crate_path_seg ())
 	{
 	  // what is the current crate scope node id?
 	  module_scope_id = crate_scope_id;
+	  previous_resolved_node_id = module_scope_id;
 	  resolver->insert_resolved_name (segment.get_node_id (),
 					  module_scope_id);
 	  continue;
@@ -292,6 +295,7 @@ ResolvePath::resolve_path (AST::SimplePath *expr)
 	    }
 
 	  module_scope_id = resolver->peek_parent_module_scope ();
+	  previous_resolved_node_id = module_scope_id;
 	  resolver->insert_resolved_name (segment.get_node_id (),
 					  module_scope_id);
 	  continue;
@@ -348,6 +352,25 @@ ResolvePath::resolve_path (AST::SimplePath *expr)
 	    }
 	}
 
+      // if we still have not resolved and this is the final segment and the
+      // final segment is self its likely the case: pub use
+      //
+      // result::Result::{self, Err, Ok};
+      //
+      // Then the resolved_node_id is just the previous one so long as it is a
+      // resolved node id
+      // rust_debug_loc (segment.get_locus (),
+      //   	      "trying to resolve seg: [%s] first [%s] last [%s]",
+      //   	      segment.get_segment_name ().c_str (),
+      //   	      is_first_segment ? "true" : "false",
+      //   	      is_final_segment ? "true" : "false");
+      if (resolved_node_id == UNKNOWN_NODEID && !is_first_segment
+	  && is_final_segment && segment.is_lower_self ())
+	{
+	  resolved_node_id = previous_resolved_node_id;
+	}
+
+      // final check
       if (resolved_node_id == UNKNOWN_NODEID)
 	{
 	  rust_error_at (segment.get_locus (),
@@ -360,6 +383,8 @@ ResolvePath::resolve_path (AST::SimplePath *expr)
 	{
 	  module_scope_id = resolved_node_id;
 	}
+
+      previous_resolved_node_id = resolved_node_id;
     }
 
   resolved_node = resolved_node_id;
diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
index 9e2fb576481..1ab9af8e40a 100644
--- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h
+++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
@@ -132,9 +132,12 @@ public:
 	rust_error_at (r, "redefined multiple times");
       });
 
+    resolver->push_new_module_scope (enum_decl.get_node_id ());
     for (auto &variant : enum_decl.get_variants ())
       ResolveTopLevel::go (variant.get (), path, cpath);
 
+    resolver->pop_module_scope ();
+
     NodeId current_module = resolver->peek_current_module_scope ();
     mappings->insert_module_child_item (current_module, decl);
     mappings->insert_canonical_path (enum_decl.get_node_id (), cpath);
@@ -156,6 +159,10 @@ public:
       });
 
     mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_module_child (current_module, item.get_node_id ());
   }
 
   void visit (AST::EnumItemTuple &item) override
@@ -174,6 +181,10 @@ public:
       });
 
     mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_module_child (current_module, item.get_node_id ());
   }
 
   void visit (AST::EnumItemStruct &item) override
@@ -192,6 +203,10 @@ public:
       });
 
     mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_module_child (current_module, item.get_node_id ());
   }
 
   void visit (AST::EnumItemDiscriminant &item) override
@@ -210,6 +225,10 @@ public:
       });
 
     mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+    NodeId current_module = resolver->peek_current_module_scope ();
+    mappings->insert_module_child_item (current_module, decl);
+    mappings->insert_module_child (current_module, item.get_node_id ());
   }
 
   void visit (AST::StructStruct &struct_decl) override
diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc
index c496cbf84bd..cdd275c9ff2 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-path.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc
@@ -244,6 +244,19 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
 	  return root_tyty;
 	}
 
+      // is it an enum item?
+      std::pair<HIR::Enum *, HIR::EnumItem *> enum_item_lookup
+	= mappings->lookup_hir_enumitem (ref);
+      bool is_enum_item = enum_item_lookup.first != nullptr
+			  && enum_item_lookup.second != nullptr;
+      if (is_enum_item)
+	{
+	  HirId expr_id = expr.get_mappings ().get_hirid ();
+	  HirId variant_id
+	    = enum_item_lookup.second->get_mappings ().get_hirid ();
+	  context->insert_variant_definition (expr_id, variant_id);
+	}
+
       // if we have a previous segment type
       if (root_tyty != nullptr)
 	{
@@ -349,9 +362,13 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
 	  const TyTy::VariantDef *variant = candidate.item.enum_field.variant;
 
 	  HirId variant_id = variant->get_id ();
-	  HIR::Item *enum_item = mappings->lookup_hir_item (variant_id);
-	  rust_assert (enum_item != nullptr);
+	  std::pair<HIR::Enum *, HIR::EnumItem *> enum_item_lookup
+	    = mappings->lookup_hir_enumitem (variant_id);
+	  bool enum_item_ok = enum_item_lookup.first != nullptr
+			      && enum_item_lookup.second != nullptr;
+	  rust_assert (enum_item_ok);
 
+	  HIR::EnumItem *enum_item = enum_item_lookup.second;
 	  resolved_node_id = enum_item->get_mappings ().get_nodeid ();
 
 	  // insert the id of the variant we are resolved to
diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc
index 419dfe7246d..e0c43c713c5 100644
--- a/gcc/rust/typecheck/rust-type-util.cc
+++ b/gcc/rust/typecheck/rust-type-util.cc
@@ -22,8 +22,6 @@
 #include "rust-hir-type-check-implitem.h"
 #include "rust-hir-type-check-item.h"
 #include "rust-hir-type-check.h"
-#include "rust-hir-visitor.h"
-#include "rust-name-resolver.h"
 #include "rust-casts.h"
 #include "rust-unify.h"
 #include "rust-coercion.h"
@@ -45,6 +43,23 @@ query_type (HirId reference, TyTy::BaseType **result)
 
   context->insert_query (reference);
 
+  std::pair<HIR::Enum *, HIR::EnumItem *> enum_candidiate
+    = mappings->lookup_hir_enumitem (reference);
+  bool enum_candidiate_ok
+    = enum_candidiate.first != nullptr && enum_candidiate.second != nullptr;
+  if (enum_candidiate_ok)
+    {
+      HIR::Enum *parent = enum_candidiate.first;
+      HIR::EnumItem *enum_item = enum_candidiate.second;
+      rust_debug_loc (enum_item->get_locus (), "resolved item {%u} to",
+		      reference);
+
+      *result = TypeCheckItem::Resolve (*parent);
+
+      context->query_completed (reference);
+      return true;
+    }
+
   HIR::Item *item = mappings->lookup_hir_item (reference);
   if (item != nullptr)
     {
diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc
index 535731b48f2..2a731fe9881 100644
--- a/gcc/rust/util/rust-hir-map.cc
+++ b/gcc/rust/util/rust-hir-map.cc
@@ -382,6 +382,27 @@ Mappings::lookup_hir_item (HirId id)
   return it->second;
 }
 
+void
+Mappings::insert_hir_enumitem (HIR::Enum *parent, HIR::EnumItem *item)
+{
+  auto id = item->get_mappings ().get_hirid ();
+  auto result = lookup_hir_enumitem (id);
+  rust_assert (result.first == nullptr);
+
+  hirEnumItemMappings[id] = {parent, item};
+  insert_node_to_hir (item->get_mappings ().get_nodeid (), id);
+}
+
+std::pair<HIR::Enum *, HIR::EnumItem *>
+Mappings::lookup_hir_enumitem (HirId id)
+{
+  auto it = hirEnumItemMappings.find (id);
+  if (it == hirEnumItemMappings.end ())
+    return {nullptr, nullptr};
+
+  return it->second;
+}
+
 void
 Mappings::insert_hir_trait_item (HIR::TraitItem *item)
 {
diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h
index 6356a750551..80d753cce36 100644
--- a/gcc/rust/util/rust-hir-map.h
+++ b/gcc/rust/util/rust-hir-map.h
@@ -114,6 +114,9 @@ public:
   void insert_hir_item (HIR::Item *item);
   HIR::Item *lookup_hir_item (HirId id);
 
+  void insert_hir_enumitem (HIR::Enum *parent, HIR::EnumItem *item);
+  std::pair<HIR::Enum *, HIR::EnumItem *> lookup_hir_enumitem (HirId id);
+
   void insert_hir_trait_item (HIR::TraitItem *item);
   HIR::TraitItem *lookup_hir_trait_item (HirId id);
 
@@ -317,6 +320,7 @@ private:
 
   std::map<HirId, HIR::Module *> hirModuleMappings;
   std::map<HirId, HIR::Item *> hirItemMappings;
+  std::map<HirId, std::pair<HIR::Enum *, HIR::EnumItem *>> hirEnumItemMappings;
   std::map<HirId, HIR::Type *> hirTypeMappings;
   std::map<HirId, HIR::Expr *> hirExprMappings;
   std::map<HirId, HIR::Stmt *> hirStmtMappings;
diff --git a/gcc/testsuite/rust/compile/issue-850.rs b/gcc/testsuite/rust/compile/issue-850.rs
new file mode 100644
index 00000000000..531cbf4f663
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-850.rs
@@ -0,0 +1,43 @@
+extern "C" {
+    fn printf(s: *const i8, ...);
+}
+
+mod option {
+    enum Option<T> {
+        #[lang = "None"]
+        None,
+        #[lang = "Some"]
+        Some(T),
+    }
+}
+
+pub use option::Option::{self, None, Some};
+
+fn divide(numerator: f64, denominator: f64) -> Option<f64> {
+    if denominator == 0.0 {
+        None
+    } else {
+        Some(numerator / denominator)
+    }
+}
+
+fn main() {
+    let result = divide(2.0, 3.0);
+
+    match result {
+        Some(x) => unsafe {
+            let a = "Result: %i\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c, x);
+        },
+        None => unsafe {
+            let a = "Cannot divide by 0\n\0";
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c);
+        },
+    }
+}
diff --git a/gcc/testsuite/rust/compile/issue-855.rs b/gcc/testsuite/rust/compile/issue-855.rs
new file mode 100644
index 00000000000..f48e3a1bfe0
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-855.rs
@@ -0,0 +1,23 @@
+pub use result::Result::{self, Err, Ok};
+
+extern "C" {
+    fn printf(s: *const i8, ...);
+}
+
+mod result {
+    pub enum Result<T, E> {
+        #[lang = "Ok"]
+        Ok(T),
+
+        #[lang = "Err"]
+        Err(E),
+    }
+}
+
+pub fn test(a: i32) -> Result<i32, bool> {
+    if a > 5 {
+        Ok(123)
+    } else {
+        Err(false)
+    }
+}


More information about the Gcc-cvs mailing list