Skip to content

Commit b142d83

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 f88af61 commit b142d83

8 files changed

+127
-25
lines changed

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

+12
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`
@@ -715,6 +718,7 @@ template <Namespace N> class ForeverStack
715718
{}
716719

717720
bool is_root () const;
721+
bool is_prelude () const;
718722
bool is_leaf () const;
719723

720724
void insert_child (Link link, Node child);
@@ -750,7 +754,15 @@ template <Namespace N> class ForeverStack
750754
const Node &cursor () const;
751755
void update_cursor (Node &new_cursor);
752756

757+
/* The forever stack's actual nodes */
753758
Node root;
759+
/*
760+
* A special prelude node used currently for resolving language builtins
761+
* It has the root node as a parent, and acts as a "special case" for name
762+
* resolution
763+
*/
764+
Node prelude;
765+
754766
std::reference_wrapper<Node> cursor_reference;
755767

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

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

+72-10
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
@@ -290,6 +307,20 @@ ForeverStack<N>::get (const Identifier &name)
290307
return resolved_definition;
291308
}
292309

310+
template <Namespace N>
311+
tl::optional<Rib::Definition>
312+
ForeverStack<N>::get_prelude (const Identifier &name)
313+
{
314+
return prelude.rib.get (name.as_string ());
315+
}
316+
317+
template <Namespace N>
318+
tl::optional<Rib::Definition>
319+
ForeverStack<N>::get_prelude (const std::string &name)
320+
{
321+
return prelude.rib.get (name);
322+
}
323+
293324
template <>
294325
tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get (
295326
const Identifier &name)
@@ -389,7 +420,7 @@ ForeverStack<N>::find_starting_point (
389420
break;
390421

391422
auto &seg = unwrap_type_segment (outer_seg);
392-
auto is_self_or_crate
423+
bool is_self_or_crate
393424
= seg.is_crate_path_seg () || seg.is_lower_self_seg ();
394425

395426
// if we're after the first path segment and meet `self` or `crate`, it's
@@ -452,7 +483,7 @@ ForeverStack<N>::resolve_segments (
452483
typename std::vector<S>::const_iterator iterator,
453484
std::function<void (const S &, NodeId)> insert_segment_resolution)
454485
{
455-
auto *current_node = &starting_point;
486+
Node *current_node = &starting_point;
456487
for (; !is_last (iterator, segments); iterator++)
457488
{
458489
auto &outer_seg = *iterator;
@@ -468,7 +499,7 @@ ForeverStack<N>::resolve_segments (
468499
}
469500

470501
auto &seg = unwrap_type_segment (outer_seg);
471-
auto str = seg.as_string ();
502+
std::string str = seg.as_string ();
472503
rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ());
473504

474505
// check that we don't encounter *any* leading keywords afterwards
@@ -483,10 +514,20 @@ ForeverStack<N>::resolve_segments (
483514
* On every iteration this loop either
484515
*
485516
* 1. terminates
486-
* 2. decreases the depth of the node pointed to by current_node
487517
*
488-
* This ensures termination
518+
* 2. decreases the depth of the node pointed to by current_node until
519+
* current_node reaches the root
520+
*
521+
* 3. If the root node is reached, and we were not able to resolve the
522+
* segment, we search the prelude rib for the segment, by setting
523+
* current_node to point to the prelude, and toggling the
524+
* searched_prelude boolean to true. If current_node is the prelude
525+
* rib, and searched_prelude is true, we will exit.
526+
*
527+
* This ensures termination.
528+
*
489529
*/
530+
bool searched_prelude = false;
490531
while (true)
491532
{
492533
// may set the value of child
@@ -522,9 +563,16 @@ ForeverStack<N>::resolve_segments (
522563
}
523564
}
524565

566+
if (current_node->is_root () && !searched_prelude)
567+
{
568+
searched_prelude = true;
569+
current_node = &prelude;
570+
continue;
571+
}
572+
525573
if (!is_start (iterator, segments)
526574
|| current_node->rib.kind == Rib::Kind::Module
527-
|| current_node->is_root ())
575+
|| current_node->is_prelude ())
528576
{
529577
return tl::nullopt;
530578
}
@@ -564,7 +612,12 @@ ForeverStack<N>::resolve_path (
564612
return Rib::Definition::NonShadowable (seg_id);
565613
}
566614

567-
auto res = get (unwrap_type_segment (segments.back ()).as_string ());
615+
tl::optional<Rib::Definition> res
616+
= get (unwrap_type_segment (segments.back ()).as_string ());
617+
618+
if (!res)
619+
res = get_prelude (unwrap_type_segment (segments.back ()).as_string ());
620+
568621
if (res && !res->is_ambiguous ())
569622
insert_segment_resolution (segments.back (), res->get_node_id ());
570623
return res;
@@ -579,16 +632,25 @@ ForeverStack<N>::resolve_path (
579632
return resolve_segments (starting_point.get (), segments, iterator,
580633
insert_segment_resolution);
581634
})
582-
.and_then ([&segments, &insert_segment_resolution] (
635+
.and_then ([this, &segments, &insert_segment_resolution] (
583636
Node final_node) -> tl::optional<Rib::Definition> {
584637
// leave resolution within impl blocks to type checker
585638
if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
586639
return tl::nullopt;
640+
641+
std::string seg_name
642+
= unwrap_type_segment (segments.back ()).as_string ();
643+
587644
// assuming this can't be a lang item segment
588-
auto res = final_node.rib.get (
589-
unwrap_type_segment (segments.back ()).as_string ());
645+
tl::optional<Rib::Definition> res = final_node.rib.get (seg_name);
646+
647+
// Ok we didn't find it in the rib, Lets try the prelude...
648+
if (!res)
649+
res = get_prelude (seg_name);
650+
590651
if (res && !res->is_ambiguous ())
591652
insert_segment_resolution (segments.back (), res->get_node_id ());
653+
592654
return res;
593655
});
594656
}

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

+18-15
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

+4
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id,
107107
std::function<void (void)> lambda,
108108
tl::optional<Identifier> path)
109109
{
110+
// NOTE: You must be at the root node when pushing the prelude rib.
110111
values.push (rib_kind, id, path);
111112
types.push (rib_kind, id, path);
112113
macros.push (rib_kind, id, path);
@@ -126,6 +127,9 @@ NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns,
126127
std::function<void (void)> lambda,
127128
tl::optional<Identifier> path)
128129
{
130+
// This could work... I'm not sure why you would want to do this though.
131+
rust_assert (rib_kind != Rib::Kind::Prelude);
132+
129133
switch (ns)
130134
{
131135
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
@@ -15,6 +15,7 @@ issue-2330.rs
1515
issue-2812.rs
1616
issue-850.rs
1717
issue-855.rs
18+
issue-3315-2.rs
1819
iterators1.rs
1920
lookup_err1.rs
2021
macros/mbe/macro43.rs

0 commit comments

Comments
 (0)