]> git.ipfire.org Git - thirdparty/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)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 16 Jan 2024 17:21:13 +0000 (18:21 +0100)
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 fe520abd126fcd8b55747f176d6f1801fb8ac8b2..5e5913b95f60b02957213d13dfdab7624a699019 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 a1e63a195df9cc7f1b4912c0dba2c656121ec463..d78d8b17a6104c603defea989d245720d52006eb 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 b3eca529829170e3e2e0e03b7fdad8d3ffd8cd7c..07a5fc87ad06337689a930471547b376e1c32400 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 fa52d7aa041ac7bff76df281cb64cc5e5097998f..e1a2b4eaeab7d18ce371c7c10deaba50c9137ce1 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 4f3b924a5868c8b9944e1dd44d3397d825b067c8..c1590ca3a2fdd89c0e610265b64c4f4eeb63f57e 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 bd0b04332632bd461e1dcc4c6afb01ab74a43f9b..9c3a2eeace0a0fdf28d8731bbcea7ac2b314094a 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 9e2fb5764815ae0f8d50618b9ded54e8e9aaf070..1ab9af8e40aec7572629be65041fd51cdba0c178 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 c496cbf84bdbdaef05bfee6a56278fe23bf64526..cdd275c9ff257d50fb137bf4013f677f94b63e7d 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 419dfe7246d6cde19381325254b4ece43552ecf7..e0c43c713c5ed175847643ded405114d539a5521 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 535731b48f219edf80ee6b3a4018888377e0d34c..2a731fe98818d2efd6ba19e0cd0adbcb85e72ff6 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 6356a75055121d5c05db14810e9cb6e8370bafec..80d753cce3638f23d012a6e2aa93b02b12a744eb 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)
+    }
+}