From: Liam Naddell <liamn...@gmail.com>

gcc/rust/ChangeLog:

        * resolve/rust-forever-stack.h (ForeverStack): Add a dedicated prelude 
node for
        the Language prelude
        * resolve/rust-forever-stack.hxx (ForeverStack): Add support code for 
the
        prelude node
        * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Move
        language prelude builtins to the prelude context
        * resolve/rust-name-resolution-context.cc
        (NameResolutionContext::scoped): Add code for handling
        the prelude corner case
        * resolve/rust-rib.h (Rib::Kind): Add a special Prelude rib type

gcc/testsuite/ChangeLog:

        * rust/compile/issue-3315-1.rs: Add test for module with same name
        as builtin
        * rust/compile/issue-3315-2.rs: Test with utilization of i32
        type
        * rust/compile/nr2/exclude: issue-3315-2.rs Does not work with
        NR2.0

Signed-off-by: Liam Naddell <liamn...@gmail.com>
---
 gcc/rust/resolve/rust-forever-stack.h         | 12 +++
 gcc/rust/resolve/rust-forever-stack.hxx       | 82 ++++++++++++++++---
 .../resolve/rust-late-name-resolver-2.0.cc    | 33 ++++----
 .../resolve/rust-name-resolution-context.cc   |  4 +
 gcc/rust/resolve/rust-rib.h                   |  5 ++
 gcc/testsuite/rust/compile/issue-3315-1.rs    |  8 ++
 gcc/testsuite/rust/compile/issue-3315-2.rs    |  7 ++
 gcc/testsuite/rust/compile/nr2/exclude        |  1 +
 8 files changed, 127 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issue-3315-1.rs
 create mode 100644 gcc/testsuite/rust/compile/issue-3315-2.rs

diff --git a/gcc/rust/resolve/rust-forever-stack.h 
b/gcc/rust/resolve/rust-forever-stack.h
index 22efc973197..2a4c7348728 100644
--- a/gcc/rust/resolve/rust-forever-stack.h
+++ b/gcc/rust/resolve/rust-forever-stack.h
@@ -548,6 +548,7 @@ template <Namespace N> class ForeverStack
 public:
   ForeverStack ()
     : root (Node (Rib (Rib::Kind::Normal), UNKNOWN_NODEID)),
+      prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID, root)),
       cursor_reference (root)
   {
     rust_assert (root.is_root ());
@@ -657,6 +658,8 @@ public:
    * the current map, an empty one otherwise.
    */
   tl::optional<Rib::Definition> get (const Identifier &name);
+  tl::optional<Rib::Definition> get_prelude (const Identifier &name);
+  tl::optional<Rib::Definition> get_prelude (const std::string &name);
 
   /**
    * Resolve a path to its definition in the current `ForeverStack`
@@ -721,6 +724,7 @@ private:
     {}
 
     bool is_root () const;
+    bool is_prelude () const;
     bool is_leaf () const;
 
     void insert_child (Link link, Node child);
@@ -756,7 +760,15 @@ private:
   const Node &cursor () const;
   void update_cursor (Node &new_cursor);
 
+  /* The forever stack's actual nodes */
   Node root;
+  /*
+   * A special prelude node used currently for resolving language builtins
+   * It has the root node as a parent, and acts as a "special case" for name
+   * resolution
+   */
+  Node prelude;
+
   std::reference_wrapper<Node> cursor_reference;
 
   void stream_rib (std::stringstream &stream, const Rib &rib,
diff --git a/gcc/rust/resolve/rust-forever-stack.hxx 
b/gcc/rust/resolve/rust-forever-stack.hxx
index 90e0ceb9f81..a6e0b30a57b 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -34,6 +34,13 @@ ForeverStack<N>::Node::is_root () const
   return !parent.has_value ();
 }
 
+template <Namespace N>
+bool
+ForeverStack<N>::Node::is_prelude () const
+{
+  return rib.kind == Rib::Kind::Prelude;
+}
+
 template <Namespace N>
 bool
 ForeverStack<N>::Node::is_leaf () const
@@ -63,6 +70,16 @@ template <Namespace N>
 void
 ForeverStack<N>::push_inner (Rib rib, Link link)
 {
+  if (rib.kind == Rib::Kind::Prelude)
+    {
+      // If you push_inner into the prelude from outside the root, you will pop
+      // back into the root, which could screw up a traversal.
+      rust_assert (&cursor_reference.get () == &root);
+      // Prelude doesn't have an access path
+      rust_assert (!link.path);
+      update_cursor (this->prelude);
+      return;
+    }
   // If the link does not exist, we create it and emplace a new `Node` with the
   // current node as its parent. `unordered_map::emplace` returns a pair with
   // the iterator and a boolean. If the value already exists, the iterator
@@ -300,6 +317,20 @@ ForeverStack<N>::get (const Identifier &name)
   return resolved_definition;
 }
 
+template <Namespace N>
+tl::optional<Rib::Definition>
+ForeverStack<N>::get_prelude (const Identifier &name)
+{
+  return prelude.rib.get (name.as_string ());
+}
+
+template <Namespace N>
+tl::optional<Rib::Definition>
+ForeverStack<N>::get_prelude (const std::string &name)
+{
+  return prelude.rib.get (name);
+}
+
 template <>
 tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get (
   const Identifier &name)
@@ -399,7 +430,7 @@ ForeverStack<N>::find_starting_point (
        break;
 
       auto &seg = unwrap_type_segment (outer_seg);
-      auto is_self_or_crate
+      bool is_self_or_crate
        = seg.is_crate_path_seg () || seg.is_lower_self_seg ();
 
       // if we're after the first path segment and meet `self` or `crate`, it's
@@ -457,7 +488,7 @@ ForeverStack<N>::resolve_segments (
   typename std::vector<S>::const_iterator iterator,
   std::function<void (const S &, NodeId)> insert_segment_resolution)
 {
-  auto *current_node = &starting_point;
+  Node *current_node = &starting_point;
   for (; !is_last (iterator, segments); iterator++)
     {
       auto &outer_seg = *iterator;
@@ -473,7 +504,7 @@ ForeverStack<N>::resolve_segments (
        }
 
       auto &seg = unwrap_type_segment (outer_seg);
-      auto str = seg.as_string ();
+      std::string str = seg.as_string ();
       rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ());
 
       // check that we don't encounter *any* leading keywords afterwards
@@ -488,10 +519,20 @@ ForeverStack<N>::resolve_segments (
        * On every iteration this loop either
        *
        * 1. terminates
-       * 2. decreases the depth of the node pointed to by current_node
        *
-       * This ensures termination
+       * 2. decreases the depth of the node pointed to by current_node until
+       *    current_node reaches the root
+       *
+       * 3. If the root node is reached, and we were not able to resolve the
+       *    segment, we search the prelude rib for the segment, by setting
+       *    current_node to point to the prelude, and toggling the
+       *    searched_prelude boolean to true. If current_node is the prelude
+       *    rib, and searched_prelude is true, we will exit.
+       *
+       * This ensures termination.
+       *
        */
+      bool searched_prelude = false;
       while (true)
        {
          // may set the value of child
@@ -527,9 +568,16 @@ ForeverStack<N>::resolve_segments (
                }
            }
 
+         if (current_node->is_root () && !searched_prelude)
+           {
+             searched_prelude = true;
+             current_node = &prelude;
+             continue;
+           }
+
          if (!is_start (iterator, segments)
              || current_node->rib.kind == Rib::Kind::Module
-             || current_node->is_root ())
+             || current_node->is_prelude ())
            {
              return tl::nullopt;
            }
@@ -569,7 +617,12 @@ ForeverStack<N>::resolve_path (
          return Rib::Definition::NonShadowable (seg_id);
        }
 
-      auto res = get (unwrap_type_segment (segments.back ()).as_string ());
+      tl::optional<Rib::Definition> res
+       = get (unwrap_type_segment (segments.back ()).as_string ());
+
+      if (!res)
+       res = get_prelude (unwrap_type_segment (segments.back ()).as_string ());
+
       if (res && !res->is_ambiguous ())
        insert_segment_resolution (segments.back (), res->get_node_id ());
       return res;
@@ -584,16 +637,25 @@ ForeverStack<N>::resolve_path (
       return resolve_segments (starting_point.get (), segments, iterator,
                               insert_segment_resolution);
     })
-    .and_then ([&segments, &insert_segment_resolution] (
+    .and_then ([this, &segments, &insert_segment_resolution] (
                 Node final_node) -> tl::optional<Rib::Definition> {
       // leave resolution within impl blocks to type checker
       if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
        return tl::nullopt;
+
+      std::string seg_name
+       = unwrap_type_segment (segments.back ()).as_string ();
+
       // assuming this can't be a lang item segment
-      auto res = final_node.rib.get (
-       unwrap_type_segment (segments.back ()).as_string ());
+      tl::optional<Rib::Definition> res = final_node.rib.get (seg_name);
+
+      // Ok we didn't find it in the rib, Lets try the prelude...
+      if (!res)
+       res = get_prelude (seg_name);
+
       if (res && !res->is_ambiguous ())
        insert_segment_resolution (segments.back (), res->get_node_id ());
+
       return res;
     });
 }
diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc 
b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
index 9cf2b1f81c9..f4ad53a02ad 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
@@ -91,16 +91,18 @@ Late::setup_builtin_types ()
     // insert it in the type context...
   };
 
-  for (const auto &builtin : builtins)
-    {
-      // we should be able to use `insert_at_root` or `insert` here, since 
we're
-      // at the root :) hopefully!
-      auto ok = ctx.types.insert (builtin.name, builtin.node_id);
-      rust_assert (ok);
-
-      ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id);
-      ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type);
-    }
+  // There's a special Rib for putting prelude items, since prelude items need
+  // to satisfy certain special rules.
+  ctx.scoped (Rib::Kind::Prelude, 0, [this, &ty_ctx] (void) -> void {
+    for (const auto &builtin : builtins)
+      {
+       auto ok = ctx.types.insert (builtin.name, builtin.node_id);
+       rust_assert (ok);
+
+       ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id);
+       ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type);
+      }
+  });
 
   // ...here!
   auto *unit_type = TyTy::TupleType::get_unit_type ();
@@ -213,7 +215,6 @@ Late::visit (AST::IdentifierExpr &expr)
   // TODO: same thing as visit(PathInExpression) here?
 
   tl::optional<Rib::Definition> resolved = tl::nullopt;
-
   if (auto value = ctx.values.get (expr.get_ident ()))
     {
       resolved = value;
@@ -231,10 +232,12 @@ Late::visit (AST::IdentifierExpr &expr)
     }
   else
     {
-      rust_error_at (expr.get_locus (),
-                    "could not resolve identifier expression: %qs",
-                    expr.get_ident ().as_string ().c_str ());
-      return;
+      if (auto typ = ctx.types.get_prelude (expr.get_ident ()))
+       resolved = typ;
+      else
+       rust_error_at (expr.get_locus (),
+                      "could not resolve identifier expression: %qs",
+                      expr.get_ident ().as_string ().c_str ());
     }
 
   ctx.map_usage (Usage (expr.get_node_id ()),
diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc 
b/gcc/rust/resolve/rust-name-resolution-context.cc
index 517a4836aaf..92c48633e56 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.cc
+++ b/gcc/rust/resolve/rust-name-resolution-context.cc
@@ -113,6 +113,7 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId 
id,
                               std::function<void (void)> lambda,
                               tl::optional<Identifier> path)
 {
+  // NOTE: You must be at the root node when pushing the prelude rib.
   values.push (rib_kind, id, path);
   types.push (rib_kind, id, path);
   macros.push (rib_kind, id, path);
@@ -132,6 +133,9 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, 
Namespace ns,
                               std::function<void (void)> lambda,
                               tl::optional<Identifier> path)
 {
+  // This could work... I'm not sure why you would want to do this though.
+  rust_assert (rib_kind != Rib::Kind::Prelude);
+
   switch (ns)
     {
     case Namespace::Values:
diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h
index ccc4c277b12..c498328a808 100644
--- a/gcc/rust/resolve/rust-rib.h
+++ b/gcc/rust/resolve/rust-rib.h
@@ -183,6 +183,11 @@ public:
     ForwardTypeParamBan,
     /* Const generic, as in the following example: fn foo<T, const X: T>() {} 
*/
     ConstParamType,
+    /* Prelude rib, used for both the language prelude (i32,usize,etc) and the
+     * (future) {std,core}::prelude::* import. A regular rib with the
+     * restriction that you cannot `use` items from the Prelude
+     */
+    Prelude,
   } kind;
 
   static std::string kind_to_string (Rib::Kind kind)
diff --git a/gcc/testsuite/rust/compile/issue-3315-1.rs 
b/gcc/testsuite/rust/compile/issue-3315-1.rs
new file mode 100644
index 00000000000..07581dab117
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3315-1.rs
@@ -0,0 +1,8 @@
+//You should be able to create a module of the same name as a builtin type
+
+mod i32 {
+}
+
+fn main() -> isize {
+  0
+}
diff --git a/gcc/testsuite/rust/compile/issue-3315-2.rs 
b/gcc/testsuite/rust/compile/issue-3315-2.rs
new file mode 100644
index 00000000000..71abd6cc1d7
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3315-2.rs
@@ -0,0 +1,7 @@
+mod i32 {
+}
+
+fn main() -> isize {
+  let i:i32 = 0 as i32;
+  i as isize
+}
diff --git a/gcc/testsuite/rust/compile/nr2/exclude 
b/gcc/testsuite/rust/compile/nr2/exclude
index d36c24b95e3..a4bac9ac836 100644
--- a/gcc/testsuite/rust/compile/nr2/exclude
+++ b/gcc/testsuite/rust/compile/nr2/exclude
@@ -13,6 +13,7 @@ issue-2330.rs
 issue-2812.rs
 issue-850.rs
 issue-855.rs
+issue-3315-2.rs
 iterators1.rs
 lookup_err1.rs
 macros/mbe/macro43.rs
-- 
2.45.2

Reply via email to