aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiam Naddell <liamnprg@gmail.com>2025-02-11 16:42:41 -0500
committerArthur Cohen <arthur.cohen@embecosm.com>2025-03-24 13:30:41 +0100
commit69f84cbe23ce5358895ddac847d5e907ca234e64 (patch)
tree7911ff76658d1a8a9da23d21fd8f5a981bb831b2
parent7107f9261f7254a951ca9a8d99002f2fa2b32f89 (diff)
downloadgcc-69f84cbe23ce5358895ddac847d5e907ca234e64.zip
gcc-69f84cbe23ce5358895ddac847d5e907ca234e64.tar.gz
gcc-69f84cbe23ce5358895ddac847d5e907ca234e64.tar.bz2
gccrs: Fix modules with same name as builtins causing ICE (#3315)
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 <liamnprg@gmail.com>
-rw-r--r--gcc/rust/resolve/rust-forever-stack.h12
-rw-r--r--gcc/rust/resolve/rust-forever-stack.hxx82
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.cc33
-rw-r--r--gcc/rust/resolve/rust-name-resolution-context.cc4
-rw-r--r--gcc/rust/resolve/rust-rib.h5
-rw-r--r--gcc/testsuite/rust/compile/issue-3315-1.rs8
-rw-r--r--gcc/testsuite/rust/compile/issue-3315-2.rs7
-rw-r--r--gcc/testsuite/rust/compile/nr2/exclude1
8 files changed, 127 insertions, 25 deletions
diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h
index 22efc97..2a4c734 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 90e0ceb..a6e0b30 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -36,6 +36,13 @@ ForeverStack<N>::Node::is_root () const
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
{
return children.empty ();
@@ -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 9cf2b1f..f4ad53a 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 517a483..92c4863 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 ccc4c27..c498328 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 0000000..07581da
--- /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 0000000..71abd6c
--- /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 d36c24b..a4bac9a 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