Skip to content

Commit 199b540

Browse files
liamnaddellP-E-P
authored andcommitted
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 <[email protected]>
1 parent 6a4363f commit 199b540

File tree

8 files changed

+127
-25
lines changed

8 files changed

+127
-25
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,7 @@ template <Namespace N> class ForeverStack
548548
public:
549549
ForeverStack ()
550550
: root (Node (Rib (Rib::Kind::Normal), UNKNOWN_NODEID)),
551+
prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID, root)),
551552
cursor_reference (root)
552553
{
553554
rust_assert (root.is_root ());
@@ -657,6 +658,8 @@ template <Namespace N> class ForeverStack
657658
* the current map, an empty one otherwise.
658659
*/
659660
tl::optional<Rib::Definition> get (const Identifier &name);
661+
tl::optional<Rib::Definition> get_prelude (const Identifier &name);
662+
tl::optional<Rib::Definition> get_prelude (const std::string &name);
660663

661664
/**
662665
* Resolve a path to its definition in the current `ForeverStack`
@@ -721,6 +724,7 @@ template <Namespace N> class ForeverStack
721724
{}
722725

723726
bool is_root () const;
727+
bool is_prelude () const;
724728
bool is_leaf () const;
725729

726730
void insert_child (Link link, Node child);
@@ -756,7 +760,15 @@ template <Namespace N> class ForeverStack
756760
const Node &cursor () const;
757761
void update_cursor (Node &new_cursor);
758762

763+
/* The forever stack's actual nodes */
759764
Node root;
765+
/*
766+
* A special prelude node used currently for resolving language builtins
767+
* It has the root node as a parent, and acts as a "special case" for name
768+
* resolution
769+
*/
770+
Node prelude;
771+
760772
std::reference_wrapper<Node> cursor_reference;
761773

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

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

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ ForeverStack<N>::Node::is_root () const
3434
return !parent.has_value ();
3535
}
3636

37+
template <Namespace N>
38+
bool
39+
ForeverStack<N>::Node::is_prelude () const
40+
{
41+
return rib.kind == Rib::Kind::Prelude;
42+
}
43+
3744
template <Namespace N>
3845
bool
3946
ForeverStack<N>::Node::is_leaf () const
@@ -63,6 +70,16 @@ template <Namespace N>
6370
void
6471
ForeverStack<N>::push_inner (Rib rib, Link link)
6572
{
73+
if (rib.kind == Rib::Kind::Prelude)
74+
{
75+
// If you push_inner into the prelude from outside the root, you will pop
76+
// back into the root, which could screw up a traversal.
77+
rust_assert (&cursor_reference.get () == &root);
78+
// Prelude doesn't have an access path
79+
rust_assert (!link.path);
80+
update_cursor (this->prelude);
81+
return;
82+
}
6683
// If the link does not exist, we create it and emplace a new `Node` with the
6784
// current node as its parent. `unordered_map::emplace` returns a pair with
6885
// the iterator and a boolean. If the value already exists, the iterator
@@ -300,6 +317,20 @@ ForeverStack<N>::get (const Identifier &name)
300317
return resolved_definition;
301318
}
302319

320+
template <Namespace N>
321+
tl::optional<Rib::Definition>
322+
ForeverStack<N>::get_prelude (const Identifier &name)
323+
{
324+
return prelude.rib.get (name.as_string ());
325+
}
326+
327+
template <Namespace N>
328+
tl::optional<Rib::Definition>
329+
ForeverStack<N>::get_prelude (const std::string &name)
330+
{
331+
return prelude.rib.get (name);
332+
}
333+
303334
template <>
304335
tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get (
305336
const Identifier &name)
@@ -399,7 +430,7 @@ ForeverStack<N>::find_starting_point (
399430
break;
400431

401432
auto &seg = unwrap_type_segment (outer_seg);
402-
auto is_self_or_crate
433+
bool is_self_or_crate
403434
= seg.is_crate_path_seg () || seg.is_lower_self_seg ();
404435

405436
// if we're after the first path segment and meet `self` or `crate`, it's
@@ -457,7 +488,7 @@ ForeverStack<N>::resolve_segments (
457488
typename std::vector<S>::const_iterator iterator,
458489
std::function<void (const S &, NodeId)> insert_segment_resolution)
459490
{
460-
auto *current_node = &starting_point;
491+
Node *current_node = &starting_point;
461492
for (; !is_last (iterator, segments); iterator++)
462493
{
463494
auto &outer_seg = *iterator;
@@ -473,7 +504,7 @@ ForeverStack<N>::resolve_segments (
473504
}
474505

475506
auto &seg = unwrap_type_segment (outer_seg);
476-
auto str = seg.as_string ();
507+
std::string str = seg.as_string ();
477508
rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ());
478509

479510
// check that we don't encounter *any* leading keywords afterwards
@@ -488,10 +519,20 @@ ForeverStack<N>::resolve_segments (
488519
* On every iteration this loop either
489520
*
490521
* 1. terminates
491-
* 2. decreases the depth of the node pointed to by current_node
492522
*
493-
* This ensures termination
523+
* 2. decreases the depth of the node pointed to by current_node until
524+
* current_node reaches the root
525+
*
526+
* 3. If the root node is reached, and we were not able to resolve the
527+
* segment, we search the prelude rib for the segment, by setting
528+
* current_node to point to the prelude, and toggling the
529+
* searched_prelude boolean to true. If current_node is the prelude
530+
* rib, and searched_prelude is true, we will exit.
531+
*
532+
* This ensures termination.
533+
*
494534
*/
535+
bool searched_prelude = false;
495536
while (true)
496537
{
497538
// may set the value of child
@@ -527,9 +568,16 @@ ForeverStack<N>::resolve_segments (
527568
}
528569
}
529570

571+
if (current_node->is_root () && !searched_prelude)
572+
{
573+
searched_prelude = true;
574+
current_node = &prelude;
575+
continue;
576+
}
577+
530578
if (!is_start (iterator, segments)
531579
|| current_node->rib.kind == Rib::Kind::Module
532-
|| current_node->is_root ())
580+
|| current_node->is_prelude ())
533581
{
534582
return tl::nullopt;
535583
}
@@ -569,7 +617,12 @@ ForeverStack<N>::resolve_path (
569617
return Rib::Definition::NonShadowable (seg_id);
570618
}
571619

572-
auto res = get (unwrap_type_segment (segments.back ()).as_string ());
620+
tl::optional<Rib::Definition> res
621+
= get (unwrap_type_segment (segments.back ()).as_string ());
622+
623+
if (!res)
624+
res = get_prelude (unwrap_type_segment (segments.back ()).as_string ());
625+
573626
if (res && !res->is_ambiguous ())
574627
insert_segment_resolution (segments.back (), res->get_node_id ());
575628
return res;
@@ -584,16 +637,25 @@ ForeverStack<N>::resolve_path (
584637
return resolve_segments (starting_point.get (), segments, iterator,
585638
insert_segment_resolution);
586639
})
587-
.and_then ([&segments, &insert_segment_resolution] (
640+
.and_then ([this, &segments, &insert_segment_resolution] (
588641
Node final_node) -> tl::optional<Rib::Definition> {
589642
// leave resolution within impl blocks to type checker
590643
if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
591644
return tl::nullopt;
645+
646+
std::string seg_name
647+
= unwrap_type_segment (segments.back ()).as_string ();
648+
592649
// assuming this can't be a lang item segment
593-
auto res = final_node.rib.get (
594-
unwrap_type_segment (segments.back ()).as_string ());
650+
tl::optional<Rib::Definition> res = final_node.rib.get (seg_name);
651+
652+
// Ok we didn't find it in the rib, Lets try the prelude...
653+
if (!res)
654+
res = get_prelude (seg_name);
655+
595656
if (res && !res->is_ambiguous ())
596657
insert_segment_resolution (segments.back (), res->get_node_id ());
658+
597659
return res;
598660
});
599661
}

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

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,18 @@ 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+
auto ok = ctx.types.insert (builtin.name, builtin.node_id);
100+
rust_assert (ok);
101+
102+
ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id);
103+
ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type);
104+
}
105+
});
104106

105107
// ...here!
106108
auto *unit_type = TyTy::TupleType::get_unit_type ();
@@ -213,7 +215,6 @@ Late::visit (AST::IdentifierExpr &expr)
213215
// TODO: same thing as visit(PathInExpression) here?
214216

215217
tl::optional<Rib::Definition> resolved = tl::nullopt;
216-
217218
if (auto value = ctx.values.get (expr.get_ident ()))
218219
{
219220
resolved = value;
@@ -231,10 +232,12 @@ Late::visit (AST::IdentifierExpr &expr)
231232
}
232233
else
233234
{
234-
rust_error_at (expr.get_locus (),
235-
"could not resolve identifier expression: %qs",
236-
expr.get_ident ().as_string ().c_str ());
237-
return;
235+
if (auto typ = ctx.types.get_prelude (expr.get_ident ()))
236+
resolved = typ;
237+
else
238+
rust_error_at (expr.get_locus (),
239+
"could not resolve identifier expression: %qs",
240+
expr.get_ident ().as_string ().c_str ());
238241
}
239242

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

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id,
113113
std::function<void (void)> lambda,
114114
tl::optional<Identifier> path)
115115
{
116+
// NOTE: You must be at the root node when pushing the prelude rib.
116117
values.push (rib_kind, id, path);
117118
types.push (rib_kind, id, path);
118119
macros.push (rib_kind, id, path);
@@ -132,6 +133,9 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns,
132133
std::function<void (void)> lambda,
133134
tl::optional<Identifier> path)
134135
{
136+
// This could work... I'm not sure why you would want to do this though.
137+
rust_assert (rib_kind != Rib::Kind::Prelude);
138+
135139
switch (ns)
136140
{
137141
case Namespace::Values:

gcc/rust/resolve/rust-rib.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ class Rib
183183
ForwardTypeParamBan,
184184
/* Const generic, as in the following example: fn foo<T, const X: T>() {} */
185185
ConstParamType,
186+
/* Prelude rib, used for both the language prelude (i32,usize,etc) and the
187+
* (future) {std,core}::prelude::* import. A regular rib with the
188+
* restriction that you cannot `use` items from the Prelude
189+
*/
190+
Prelude,
186191
} kind;
187192

188193
static std::string kind_to_string (Rib::Kind kind)
Lines changed: 8 additions & 0 deletions
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+
}
Lines changed: 7 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ issue-2330.rs
1313
issue-2812.rs
1414
issue-850.rs
1515
issue-855.rs
16+
issue-3315-2.rs
1617
iterators1.rs
1718
lookup_err1.rs
1819
macros/mbe/macro43.rs

0 commit comments

Comments
 (0)