Skip to content

Commit 98f7902

Browse files
committed
Fix modules with same name as builtins causing ICE (#3315)
gcc/rust/ChangeLog: * resolve/rust-forever-stack.h: Add a dedicated prelude node for the Language prelude * resolve/rust-forever-stack.hxx: 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: Add code for handling the prelude corner case * resolve/rust-rib.h: 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>
1 parent f21bf4b commit 98f7902

8 files changed

+93
-15
lines changed

gcc/rust/resolve/rust-forever-stack.h

+7
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,7 @@ template <Namespace N> class ForeverStack
550550
// FIXME: Is that valid? Do we use the root? If yes, we should give the
551551
// crate's node id to ForeverStack's constructor
552552
: root (Node (Rib (Rib::Kind::Normal), UNKNOWN_NODEID)),
553+
prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID, root)),
553554
cursor_reference (root)
554555
{
555556
rust_assert (root.is_root ());
@@ -651,6 +652,8 @@ template <Namespace N> class ForeverStack
651652
* the current map, an empty one otherwise.
652653
*/
653654
tl::optional<Rib::Definition> get (const Identifier &name);
655+
tl::optional<Rib::Definition> get_prelude (const Identifier &name);
656+
tl::optional<Rib::Definition> get_prelude (const std::string &name);
654657

655658
/**
656659
* Resolve a path to its definition in the current `ForeverStack`
@@ -750,7 +753,11 @@ template <Namespace N> class ForeverStack
750753
const Node &cursor () const;
751754
void update_cursor (Node &new_cursor);
752755

756+
/* The forever stack's actual nodes */
753757
Node root;
758+
/* TODO: Document */
759+
Node prelude;
760+
754761
std::reference_wrapper<Node> cursor_reference;
755762

756763
void stream_rib (std::stringstream &stream, const Rib &rib,

gcc/rust/resolve/rust-forever-stack.hxx

+31
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ template <Namespace N>
6363
void
6464
ForeverStack<N>::push_inner (Rib rib, Link link)
6565
{
66+
if (rib.kind == Rib::Kind::Prelude)
67+
{
68+
// If you push_inner into the prelude from outside the root, you will pop
69+
// back into the
70+
// root, which could screw up a traversal.
71+
rust_assert (&cursor_reference.get () == &root);
72+
update_cursor (this->prelude);
73+
return;
74+
}
6675
// If the link does not exist, we create it and emplace a new `Node` with the
6776
// current node as its parent. `unordered_map::emplace` returns a pair with
6877
// the iterator and a boolean. If the value already exists, the iterator
@@ -290,6 +299,20 @@ ForeverStack<N>::get (const Identifier &name)
290299
return resolved_definition;
291300
}
292301

302+
template <Namespace N>
303+
tl::optional<Rib::Definition>
304+
ForeverStack<N>::get_prelude (const Identifier &name)
305+
{
306+
return prelude.rib.get (name.as_string ());
307+
}
308+
309+
template <Namespace N>
310+
tl::optional<Rib::Definition>
311+
ForeverStack<N>::get_prelude (const std::string &name)
312+
{
313+
return prelude.rib.get (name);
314+
}
315+
293316
template <>
294317
tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get (
295318
const Identifier &name)
@@ -512,6 +535,14 @@ ForeverStack<N>::resolve_path (
512535
if (segments.size () == 1)
513536
{
514537
auto res = get (unwrap_type_segment (segments.back ()).as_string ());
538+
if (!res)
539+
{
540+
// idk maybe try in the prelude then :/
541+
// NOTE: one day we may need to support multisegment resolution in the
542+
// prelude.
543+
res
544+
= get_prelude (unwrap_type_segment (segments.back ()).as_string ());
545+
}
515546
if (res && !res->is_ambiguous ())
516547
insert_segment_resolution (segments.back (), res->get_node_id ());
517548
return res;

gcc/rust/resolve/rust-late-name-resolver-2.0.cc

+26-15
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,22 @@ Late::setup_builtin_types ()
9191
// insert it in the type context...
9292
};
9393

94-
for (const auto &builtin : builtins)
95-
{
96-
// we should be able to use `insert_at_root` or `insert` here, since we're
97-
// at the root :) hopefully!
98-
auto ok = ctx.types.insert (builtin.name, builtin.node_id);
99-
rust_assert (ok);
100-
101-
ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id);
102-
ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type);
103-
}
94+
// There's a special Rib for putting prelude items, since prelude items need
95+
// to satisfy certain special rules.
96+
ctx.scoped (Rib::Kind::Prelude, 0, [this, &ty_ctx] (void) -> void {
97+
for (const auto &builtin : builtins)
98+
{
99+
// we should be able to use `insert_at_root` or `insert` here, since
100+
// we're at the root :) hopefully! Globbed declaration allows
101+
// user-defined items in the `types` namespace
102+
// to shadow builtins. Probably unwise, but allowed by rustc!
103+
auto ok = ctx.types.insert_globbed (builtin.name, builtin.node_id);
104+
rust_assert (ok);
105+
106+
ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id);
107+
ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type);
108+
}
109+
});
104110

105111
// ...here!
106112
auto *unit_type = TyTy::TupleType::get_unit_type ();
@@ -213,7 +219,6 @@ Late::visit (AST::IdentifierExpr &expr)
213219
// TODO: same thing as visit(PathInExpression) here?
214220

215221
tl::optional<Rib::Definition> resolved = tl::nullopt;
216-
217222
if (auto value = ctx.values.get (expr.get_ident ()))
218223
{
219224
resolved = value;
@@ -231,10 +236,16 @@ Late::visit (AST::IdentifierExpr &expr)
231236
}
232237
else
233238
{
234-
rust_error_at (expr.get_locus (),
235-
"could not resolve identifier expression: %qs",
236-
expr.get_ident ().as_string ().c_str ());
237-
return;
239+
if (auto typ = ctx.types.get_prelude (expr.get_ident ()))
240+
{
241+
resolved = typ;
242+
}
243+
else
244+
{
245+
rust_error_at (expr.get_locus (),
246+
"could not resolve identifier expression: %qs",
247+
expr.get_ident ().as_string ().c_str ());
248+
}
238249
}
239250

240251
ctx.map_usage (Usage (expr.get_node_id ()),

gcc/rust/resolve/rust-name-resolution-context.cc

+8
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id,
107107
std::function<void (void)> lambda,
108108
tl::optional<Identifier> path)
109109
{
110+
// Prelude doesn't have an access path
111+
// TODO: Assert current cursor is at the root
112+
if (rib_kind == Rib::Kind::Prelude)
113+
rust_assert (!path);
114+
110115
values.push (rib_kind, id, path);
111116
types.push (rib_kind, id, path);
112117
macros.push (rib_kind, id, path);
@@ -126,6 +131,9 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns,
126131
std::function<void (void)> lambda,
127132
tl::optional<Identifier> path)
128133
{
134+
// This could work... I'm not sure why you would want to do this though.
135+
rust_assert (rib_kind != Rib::Kind::Prelude);
136+
129137
switch (ns)
130138
{
131139
case Namespace::Values:

gcc/rust/resolve/rust-rib.h

+5
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ class Rib
173173
ForwardTypeParamBan,
174174
/* Const generic, as in the following example: fn foo<T, const X: T>() {} */
175175
ConstParamType,
176+
/* Prelude rib, used for both the language prelude (i32,usize,etc) and the
177+
* (future) {std,core}::prelude::* import. A regular rib with the
178+
* restriction that you cannot `use` items from the Prelude
179+
*/
180+
Prelude,
176181
} kind;
177182

178183
Rib (Kind kind);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//You should be able to create a module of the same name as a builtin type
2+
3+
mod i32 {
4+
}
5+
6+
fn main() -> isize {
7+
0
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
mod i32 {
2+
}
3+
4+
fn main() -> isize {
5+
let i:i32 = 0 as i32;
6+
i as isize
7+
}

gcc/testsuite/rust/compile/nr2/exclude

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ issue-2782.rs
4141
issue-2812.rs
4242
issue-850.rs
4343
issue-855.rs
44+
issue-3315-2.rs
4445
iterators1.rs
4546
lookup_err1.rs
4647
macros/mbe/macro20.rs

0 commit comments

Comments
 (0)