]> git.ipfire.org Git - people/ms/gcc.git/commitdiff
gccrs: support use declaration to write the type into the correct namespace
authorPhilip Herron <herron.philip@googlemail.com>
Fri, 17 Mar 2023 22:46:37 +0000 (22:46 +0000)
committerPhilip Herron <philip.herron@embecosm.com>
Mon, 20 Mar 2023 21:47:57 +0000 (21:47 +0000)
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>
14 files changed:
gcc/rust/ast/rust-ast.h
gcc/rust/hir/rust-ast-lower-enumitem.h
gcc/rust/hir/rust-ast-lower-item.cc
gcc/rust/hir/rust-ast-lower-stmt.cc
gcc/rust/hir/tree/rust-hir-item.h
gcc/rust/resolve/rust-ast-resolve-item.cc
gcc/rust/resolve/rust-ast-resolve-path.cc
gcc/rust/resolve/rust-ast-resolve-toplevel.h
gcc/rust/typecheck/rust-hir-type-check-path.cc
gcc/rust/typecheck/rust-type-util.cc
gcc/rust/util/rust-hir-map.cc
gcc/rust/util/rust-hir-map.h
gcc/testsuite/rust/compile/issue-850.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/issue-855.rs [new file with mode: 0644]

index 585bdb09e68ab9f97117620943619caa16642d0c..2c39cc7c8167c24348728043809497b857a5aac4 100644 (file)
@@ -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
index cc3e9e55de8f42d0cc7b1aac569e860a80bcbac0..a8aa45aa808cb066a65d1923f2441f94d4368774 100644 (file)
@@ -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 ());
 
index 0ad4a84a2c1ebfa39a3e79ba1e9674d1770b0379..eade1bcf695f5ad35877e44d7eaf6c12b70f02b7 100644 (file)
@@ -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
index dbff8ad715f32ef0a190404123661a6a92e3eebb..5ba8db002d02be23d0826b8a271c2d0717fd9657 100644 (file)
@@ -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
index 7a2a39fe771e5c6e06b76afe04cb07e8f1a6cc12..9ff9732cda8d7502e92fed32373326fa3cfc9607 100644 (file)
@@ -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 */
index 385d4b0566a8514693d08d416a479c06a31cbded..de863a036d571fa5fcdf1e2d6d1fcf6323d77559 100644 (file)
@@ -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,
index c5b8deaa107db3c8e485f692993c5b99b5360502..d8e6f90a9a6fe56779484dd26f976003c7f98e95 100644 (file)
@@ -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;
index c705ea860cd759d15c09f53169dab0fba2abc5c5..d784317b896ea803a91770bb2d4a1025d349f292 100644 (file)
@@ -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
index cd0c670338645406f08ba8edede4fbe3f93e2fc7..88c927d36ab64a196f72684f9262c9e4fe7b64c4 100644 (file)
@@ -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
index da9a724aca814beabe7e58f7439f063d15340c88..578e0c4509ebc89850d59d0c6214468c72eb32ee 100644 (file)
@@ -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)
     {
index 57c0a3c0d73626e384f5f81ce9ffc42e881d6c56..12f9be651f4a2aebdcfffc2ffc2f75cb4c8c388a 100644 (file)
@@ -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)
 {
index 9d6affa27e03309cb6143b651170fb56238ad9ff..4fd35d8ae9be38960cbdbd97d62715bcfa419c58 100644 (file)
@@ -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 (file)
index 0000000..531cbf4
--- /dev/null
@@ -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 (file)
index 0000000..f48e3a1
--- /dev/null
@@ -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)
+    }
+}