aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/resolve
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/resolve')
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-base.cc4
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-base.h6
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.cc89
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h1
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-implitem.h19
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.cc73
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-path.cc225
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-stmt.cc2
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-stmt.h55
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-toplevel.h53
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.cc147
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.h143
-rw-r--r--gcc/rust/resolve/rust-ast-resolve.cc2
-rw-r--r--gcc/rust/resolve/rust-default-resolver.cc8
-rw-r--r--gcc/rust/resolve/rust-default-resolver.h2
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.cc153
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.h28
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver.cc34
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver.h7
-rw-r--r--gcc/rust/resolve/rust-finalize-imports-2.0.cc95
-rw-r--r--gcc/rust/resolve/rust-finalize-imports-2.0.h57
-rw-r--r--gcc/rust/resolve/rust-forever-stack.h73
-rw-r--r--gcc/rust/resolve/rust-forever-stack.hxx340
-rw-r--r--gcc/rust/resolve/rust-ice-finalizer.cc36
-rw-r--r--gcc/rust/resolve/rust-ice-finalizer.h65
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.cc397
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.h19
-rw-r--r--gcc/rust/resolve/rust-name-resolution-context.cc69
-rw-r--r--gcc/rust/resolve/rust-name-resolution-context.h175
-rw-r--r--gcc/rust/resolve/rust-name-resolver.cc7
-rw-r--r--gcc/rust/resolve/rust-name-resolver.h35
-rw-r--r--gcc/rust/resolve/rust-rib.cc19
-rw-r--r--gcc/rust/resolve/rust-rib.h48
-rw-r--r--gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc86
-rw-r--r--gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h22
35 files changed, 1938 insertions, 656 deletions
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc
index 6c35a22..b781ce33 100644
--- a/gcc/rust/resolve/rust-ast-resolve-base.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-base.cc
@@ -328,6 +328,10 @@ ResolverBase::visit (AST::InlineAsm &)
{}
void
+ResolverBase::visit (AST::LlvmInlineAsm &)
+{}
+
+void
ResolverBase::visit (AST::TypeParam &)
{}
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h
index 0d497f8..5bb9e4f 100644
--- a/gcc/rust/resolve/rust-ast-resolve-base.h
+++ b/gcc/rust/resolve/rust-ast-resolve-base.h
@@ -27,6 +27,11 @@
namespace Rust {
namespace Resolver {
+inline void
+redefined_error (const rich_location &loc)
+{
+ rust_error_at (loc, "redefined multiple times");
+}
class ResolverBase : public AST::ASTVisitor
{
@@ -105,6 +110,7 @@ public:
void visit (AST::AwaitExpr &);
void visit (AST::AsyncBlockExpr &);
void visit (AST::InlineAsm &);
+ void visit (AST::LlvmInlineAsm &);
void visit (AST::TypeParam &);
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc
index 6524376..6242235 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc
@@ -22,8 +22,8 @@
#include "rust-ast-resolve-type.h"
#include "rust-ast-resolve-pattern.h"
#include "rust-ast-resolve-path.h"
-#include "diagnostic.h"
#include "rust-expr.h"
+#include "rust-ice-finalizer.h"
namespace Rust {
namespace Resolver {
@@ -108,46 +108,6 @@ ResolveExpr::visit (AST::AssignmentExpr &expr)
ResolveExpr::go (expr.get_right_expr (), prefix, canonical_prefix);
}
-/* The "break rust" Easter egg.
-
- Backstory: once upon a time, there used to be a bug in rustc: it would ICE
- during typechecking on a 'break' with an expression outside of a loop. The
- issue has been reported [0] and fixed [1], but in recognition of this, as a
- special Easter egg, "break rust" was made to intentionally cause an ICE.
-
- [0]: https://github.com/rust-lang/rust/issues/43162
- [1]: https://github.com/rust-lang/rust/pull/43745
-
- This was made in a way that does not break valid programs: namely, it only
- happens when the 'break' is outside of a loop (so invalid anyway).
-
- GCC Rust supports this essential feature as well, but in a slightly
- different way. Instead of delaying the error until type checking, we emit
- it here in the resolution phase. We, too, only do this to programs that
- are already invalid: we only emit our funny ICE if the name "rust" (which
- must be immediately inside a break-with-a-value expression) fails to
- resolve. Note that "break (rust)" does not trigger our ICE, only using
- "break rust" directly does, and only if there's no "rust" in scope. We do
- this in the same way regardless of whether the "break" is outside of a loop
- or inside one.
-
- As a GNU extension, we also support "break gcc", much to the same effect,
- subject to the same rules. */
-
-/* The finalizer for our funny ICE. This prints a custom message instead of
- the default bug reporting instructions, as there is no bug to report. */
-
-static void ATTRIBUTE_NORETURN
-funny_ice_text_finalizer (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic,
- diagnostic_t diag_kind)
-{
- gcc_assert (diag_kind == DK_ICE_NOBT);
- default_diagnostic_text_finalizer (text_output, diagnostic, diag_kind);
- fnotice (stderr, "You have broken GCC Rust. This is a feature.\n");
- exit (ICE_EXIT_CODE);
-}
-
void
ResolveExpr::visit (AST::IdentifierExpr &expr)
{
@@ -249,7 +209,7 @@ ResolveExpr::visit (AST::IfLetExpr &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// We know expr.get_patterns () has one pattern at most
// so there's no reason to handle it like an AltPattern.
@@ -279,7 +239,7 @@ ResolveExpr::visit (AST::IfLetExprConseqElse &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// We know expr.get_patterns () has one pattern at most
// so there's no reason to handle it like an AltPattern.
@@ -308,7 +268,7 @@ ResolveExpr::visit (AST::BlockExpr &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
if (expr.has_label ())
{
@@ -327,7 +287,7 @@ ResolveExpr::visit (AST::BlockExpr &expr)
CanonicalPath::new_seg (label.get_node_id (), label_name),
label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rust_error_at (label.get_locus (), "label redefined multiple times");
+ rust_error_at (label.get_locus (), "label defined multiple times");
rust_error_at (locus, "was defined here");
});
}
@@ -408,6 +368,17 @@ ResolveExpr::visit (AST::InlineAsm &expr)
{
translate_operand (expr, prefix, canonical_prefix);
}
+
+void
+ResolveExpr::visit (AST::LlvmInlineAsm &expr)
+{
+ for (auto &output : expr.get_outputs ())
+ ResolveExpr::go (*output.expr, prefix, canonical_prefix);
+
+ for (auto &input : expr.get_inputs ())
+ ResolveExpr::go (*input.expr, prefix, canonical_prefix);
+}
+
void
ResolveExpr::visit (AST::UnsafeBlockExpr &expr)
{
@@ -499,7 +470,7 @@ ResolveExpr::visit (AST::LoopExpr &expr)
CanonicalPath::new_seg (expr.get_node_id (), label_name),
label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rust_error_at (label.get_locus (), "label redefined multiple times");
+ rust_error_at (label.get_locus (), "label defined multiple times");
rust_error_at (locus, "was defined here");
});
}
@@ -511,7 +482,7 @@ ResolveExpr::visit (AST::BreakExpr &expr)
{
if (expr.has_label ())
{
- auto label = expr.get_label ().get_lifetime ();
+ auto label = expr.get_label_unchecked ().get_lifetime ();
if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED)
{
rust_error_at (label.get_locus (),
@@ -526,8 +497,8 @@ ResolveExpr::visit (AST::BreakExpr &expr)
&resolved_node))
{
rust_error_at (label.get_locus (), ErrorCode::E0426,
- "use of undeclared label %qs in %<break%>",
- label.get_lifetime_name ().c_str ());
+ "use of undeclared label %qs",
+ label.as_string ().c_str ());
return;
}
resolver->insert_resolved_label (label.get_node_id (), resolved_node);
@@ -575,7 +546,7 @@ ResolveExpr::visit (AST::WhileLoopExpr &expr)
CanonicalPath::new_seg (label.get_node_id (), label_name),
label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rust_error_at (label.get_locus (), "label redefined multiple times");
+ rust_error_at (label.get_locus (), "label defined multiple times");
rust_error_at (locus, "was defined here");
});
}
@@ -604,7 +575,7 @@ ResolveExpr::visit (AST::ForLoopExpr &expr)
CanonicalPath::new_seg (label.get_node_id (), label_name),
label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label,
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rust_error_at (label.get_locus (), "label redefined multiple times");
+ rust_error_at (label.get_locus (), "label defined multiple times");
rust_error_at (locus, "was defined here");
});
}
@@ -616,7 +587,7 @@ ResolveExpr::visit (AST::ForLoopExpr &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// resolve the expression
PatternDeclaration::go (expr.get_pattern (), Rib::ItemType::Var);
@@ -634,7 +605,7 @@ ResolveExpr::visit (AST::ContinueExpr &expr)
{
if (expr.has_label ())
{
- auto label = expr.get_label ();
+ auto label = expr.get_label_unchecked ();
if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED)
{
rust_error_at (label.get_locus (),
@@ -648,9 +619,9 @@ ResolveExpr::visit (AST::ContinueExpr &expr)
label.get_lifetime_name ()),
&resolved_node))
{
- rust_error_at (expr.get_label ().get_locus (), ErrorCode::E0426,
- "use of undeclared label %qs in %<continue%>",
- label.get_lifetime_name ().c_str ());
+ rust_error_at (expr.get_label_unchecked ().get_locus (),
+ ErrorCode::E0426, "use of undeclared label %qs",
+ label.as_string ().c_str ());
return;
}
resolver->insert_resolved_label (label.get_node_id (), resolved_node);
@@ -682,7 +653,7 @@ ResolveExpr::visit (AST::MatchExpr &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// resolve
AST::MatchArm &arm = match_case.get_arm ();
@@ -751,7 +722,7 @@ ResolveExpr::visit (AST::ClosureExprInner &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
std::vector<PatternBinding> bindings
= {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
@@ -781,7 +752,7 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
std::vector<PatternBinding> bindings
= {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h
index 562a3bd..b296d66 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.h
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -57,6 +57,7 @@ public:
void visit (AST::IfLetExprConseqElse &expr) override;
void visit (AST::BlockExpr &expr) override;
void visit (AST::InlineAsm &expr) override;
+ void visit (AST::LlvmInlineAsm &expr) override;
void visit (AST::UnsafeBlockExpr &expr) override;
void visit (AST::ArrayElemsValues &elems) override;
void visit (AST::ArrayExpr &expr) override;
diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h
index 2ca1296..2081697 100644
--- a/gcc/rust/resolve/rust-ast-resolve-implitem.h
+++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h
@@ -51,7 +51,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, type.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
}
@@ -67,7 +67,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, constant.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
}
@@ -84,7 +84,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, function.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
}
@@ -124,7 +124,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, function.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (function.get_node_id (), cpath);
@@ -144,7 +144,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, constant.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (constant.get_node_id (), cpath);
@@ -162,7 +162,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, type.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (type.get_node_id (), cpath);
@@ -202,7 +202,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, function.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -221,7 +221,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -239,8 +239,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, type.get_locus ());
r.add_range (locus);
-
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc
index b26ac34..30f6d43 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-item.cc
@@ -61,11 +61,11 @@ ResolveTraitItems::visit (AST::Function &function)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
if (function.has_generics ())
- for (auto &generic : function.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (function.get_generic_params (), prefix,
+ canonical_prefix);
if (function.has_return_type ())
ResolveType::go (function.get_return_type ());
@@ -188,8 +188,8 @@ ResolveItem::visit (AST::TypeAlias &alias)
resolver->get_type_scope ().push (scope_node_id);
if (alias.has_generics ())
- for (auto &generic : alias.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (alias.get_generic_params (), prefix,
+ canonical_prefix);
if (alias.has_where_clause ())
ResolveWhereClause::Resolve (alias.get_where_clause ());
@@ -216,7 +216,7 @@ ResolveItem::visit (AST::Module &module)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// FIXME: Should we reinsert a child here? Any reason we ResolveTopLevel::go
// in ResolveTopLevel::visit (AST::Module) as well as here?
@@ -250,8 +250,8 @@ ResolveItem::visit (AST::TupleStruct &struct_decl)
resolver->get_type_scope ().push (scope_node_id);
if (struct_decl.has_generics ())
- for (auto &generic : struct_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
+ canonical_prefix);
if (struct_decl.has_where_clause ())
ResolveWhereClause::Resolve (struct_decl.get_where_clause ());
@@ -284,8 +284,8 @@ ResolveItem::visit (AST::Enum &enum_decl)
resolver->get_type_scope ().push (scope_node_id);
if (enum_decl.has_generics ())
- for (auto &generic : enum_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, cpath);
+ ResolveGenericParams::go (enum_decl.get_generic_params (), prefix,
+ canonical_prefix);
if (enum_decl.has_where_clause ())
ResolveWhereClause::Resolve (enum_decl.get_where_clause ());
@@ -356,6 +356,8 @@ ResolveItem::visit (AST::EnumItemDiscriminant &item)
auto cpath = canonical_prefix.append (decl);
mappings.insert_canonical_path (item.get_node_id (), cpath);
+
+ ResolveExpr::go (item.get_expr (), path, cpath);
}
void
@@ -374,8 +376,8 @@ ResolveItem::visit (AST::StructStruct &struct_decl)
resolver->get_type_scope ().push (scope_node_id);
if (struct_decl.has_generics ())
- for (auto &generic : struct_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
+ canonical_prefix);
if (struct_decl.has_where_clause ())
ResolveWhereClause::Resolve (struct_decl.get_where_clause ());
@@ -409,8 +411,8 @@ ResolveItem::visit (AST::Union &union_decl)
resolver->get_type_scope ().push (scope_node_id);
if (union_decl.has_generics ())
- for (auto &generic : union_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (union_decl.get_generic_params (), prefix,
+ canonical_prefix);
if (union_decl.has_where_clause ())
ResolveWhereClause::Resolve (union_decl.get_where_clause ());
@@ -473,11 +475,11 @@ ResolveItem::visit (AST::Function &function)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
if (function.has_generics ())
- for (auto &generic : function.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (function.get_generic_params (), prefix,
+ canonical_prefix);
// resolve any where clause items
if (function.has_where_clause ())
@@ -567,8 +569,8 @@ ResolveItem::visit (AST::InherentImpl &impl_block)
resolve_visibility (impl_block.get_visibility ());
if (impl_block.has_generics ())
- for (auto &generic : impl_block.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (impl_block.get_generic_params (), prefix,
+ canonical_prefix);
// resolve any where clause items
if (impl_block.has_where_clause ())
@@ -648,11 +650,11 @@ ResolveItem::visit (AST::TraitImpl &impl_block)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
if (impl_block.has_generics ())
- for (auto &generic : impl_block.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (impl_block.get_generic_params (), prefix,
+ canonical_prefix);
// resolve any where clause items
if (impl_block.has_where_clause ())
@@ -776,10 +778,10 @@ ResolveItem::visit (AST::Trait &trait)
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- ResolveGenericParam::go (trait.get_implicit_self (), prefix,
- canonical_prefix);
- for (auto &generic : trait.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go_single (trait.get_implicit_self (), prefix,
+ canonical_prefix);
+ ResolveGenericParams::go (trait.get_generic_params (), prefix,
+ canonical_prefix);
// Self is an implicit TypeParam so lets mark it as such
resolver->get_type_scope ().append_reference_for_def (
@@ -903,7 +905,18 @@ flatten_list (const AST::UseTreeList &list, std::vector<Import> &imports)
for (auto import = imports.begin () + start_idx; import != imports.end ();
import++)
- import->add_prefix (prefix);
+ {
+ // avoid duplicate node ids
+ auto prefix_copy
+ = AST::SimplePath ({}, prefix.has_opening_scope_resolution (),
+ prefix.get_locus ());
+ for (auto &seg : prefix.get_segments ())
+ prefix_copy.get_segments ().push_back (
+ AST::SimplePathSegment (seg.get_segment_name (),
+ seg.get_locus ()));
+
+ import->add_prefix (std::move (prefix_copy));
+ }
}
}
@@ -1040,12 +1053,12 @@ ResolveExternItem::visit (AST::Function &function)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// resolve the generics
if (function.has_generics ())
- for (auto &generic : function.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (function.get_generic_params (), prefix,
+ canonical_prefix);
if (function.has_return_type ())
ResolveType::go (function.get_return_type ());
diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc
index ea39fd4..fb6715d 100644
--- a/gcc/rust/resolve/rust-ast-resolve-path.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-path.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2020-2025 Free Software Foundation, Inc.
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
// This file is part of GCC.
@@ -18,6 +18,7 @@
#include "rust-ast-resolve-path.h"
#include "rust-ast-resolve-type.h"
+#include "rust-hir-map.h"
#include "rust-path.h"
namespace Rust {
@@ -49,6 +50,10 @@ ResolvePath::go (AST::SimplePath &expr)
NodeId
ResolvePath::resolve_path (AST::PathInExpression &expr)
{
+ if (expr.is_lang_item ())
+ return Analysis::Mappings::get ().get_lang_item_node (
+ expr.get_lang_item ());
+
NodeId resolved_node_id = UNKNOWN_NODEID;
NodeId module_scope_id = resolver->peek_current_module_scope ();
NodeId previous_resolved_node_id = module_scope_id;
@@ -63,8 +68,7 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
if (in_middle_of_path && segment.is_lower_self_seg ())
{
rust_error_at (segment.get_locus (), ErrorCode::E0433,
- "failed to resolve: %qs in paths can only be used "
- "in start position",
+ "%qs in paths can only be used in start position",
segment.as_string ().c_str ());
return UNKNOWN_NODEID;
}
@@ -75,8 +79,16 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
// what is the current crate scope node id?
module_scope_id = crate_scope_id;
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment.get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
continue;
}
else if (segment.is_super_path_seg ())
@@ -90,8 +102,16 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
module_scope_id = resolver->peek_parent_module_scope ();
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment.get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
continue;
}
@@ -135,23 +155,45 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
ident_seg.as_string ());
if (resolver->get_name_scope ().lookup (path, &resolved_node))
{
- resolver->insert_resolved_name (segment.get_node_id (),
- resolved_node);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
resolved_node_id = resolved_node;
}
// check the type scope
else if (resolver->get_type_scope ().lookup (path, &resolved_node))
{
- resolver->insert_resolved_type (segment.get_node_id (),
- resolved_node);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_type (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
resolved_node_id = resolved_node;
}
else if (segment.is_lower_self_seg ())
{
module_scope_id = crate_scope_id;
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment.get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
continue;
}
else
@@ -174,20 +216,38 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_name (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
}
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_type (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_type (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
}
else
{
rust_error_at (segment.get_locus (),
- "Cannot find path %qs in this scope",
+ "Cannot find path %<%s%> in this scope",
segment.as_string ().c_str ());
return UNKNOWN_NODEID;
}
@@ -207,7 +267,7 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
else if (is_first_segment)
{
rust_error_at (segment.get_locus (), ErrorCode::E0433,
- "Cannot find path %qs in this scope",
+ "Cannot find path %<%s%> in this scope",
segment.as_string ().c_str ());
return UNKNOWN_NODEID;
}
@@ -219,15 +279,29 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
// name scope first
if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
{
- resolver->insert_resolved_name (expr.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_name (expr.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_name (expr.get_node_id (),
+ resolved_node_id);
}
// check the type scope
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node_id))
{
- resolver->insert_resolved_type (expr.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_type (expr.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_type (expr.get_node_id (),
+ resolved_node_id);
}
else
{
@@ -279,14 +353,29 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
// what is the current crate scope node id?
module_scope_id = crate_scope_id;
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment.get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
resolved_node_id = module_scope_id;
continue;
}
else if (segment.is_super_path_seg ())
{
+ if (!is_first_segment)
+ {
+ rust_error_at (
+ segment.get_locus (), ErrorCode::E0433,
+ "%<super%> in paths can only be used in start position");
+ return UNKNOWN_NODEID;
+ }
if (module_scope_id == crate_scope_id)
{
rust_error_at (segment.get_locus (),
@@ -296,8 +385,16 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
module_scope_id = resolver->peek_parent_module_scope ();
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment.get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
resolved_node_id = module_scope_id;
continue;
@@ -313,20 +410,36 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_name (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
}
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_type (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_type (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
}
else
{
rust_error_at (segment.get_locus (),
- "Cannot find path %qs in this scope",
+ "Cannot find path %<%s%> in this scope",
segment.as_string ().c_str ());
return UNKNOWN_NODEID;
}
@@ -342,15 +455,31 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
if (resolver->get_name_scope ().lookup (path, &resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_name (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
}
// check the type scope
else if (resolver->get_type_scope ().lookup (path, &resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_type (segment.get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_type (segment.get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
}
}
@@ -374,7 +503,7 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
if (resolved_node_id == UNKNOWN_NODEID)
{
rust_error_at (segment.get_locus (),
- "cannot find simple path segment %qs in this scope",
+ "cannot find simple path segment %<%s%> in this scope",
segment.as_string ().c_str ());
return UNKNOWN_NODEID;
}
@@ -393,15 +522,29 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
// name scope first
if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
{
- resolver->insert_resolved_name (expr.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_name (expr.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_name (expr.get_node_id (),
+ resolved_node_id);
}
// check the type scope
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node_id))
{
- resolver->insert_resolved_type (expr.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_type (expr.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_type (expr.get_node_id (),
+ resolved_node_id);
}
else
{
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.cc b/gcc/rust/resolve/rust-ast-resolve-stmt.cc
index 226d8e8..bfba302 100644
--- a/gcc/rust/resolve/rust-ast-resolve-stmt.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.cc
@@ -70,7 +70,7 @@ ResolveStmt::visit (AST::StaticItem &var)
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, var.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
ResolveType::go (var.get_type ());
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h
index 6dfac91..d413a7c 100644
--- a/gcc/rust/resolve/rust-ast-resolve-stmt.h
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h
@@ -63,7 +63,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, constant.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
ResolveType::go (constant.get_type ());
@@ -73,9 +73,10 @@ public:
void visit (AST::LetStmt &stmt) override
{
if (stmt.has_init_expr ())
- {
- ResolveExpr::go (stmt.get_init_expr (), prefix, canonical_prefix);
- }
+ ResolveExpr::go (stmt.get_init_expr (), prefix, canonical_prefix);
+
+ if (stmt.has_else_expr ())
+ ResolveExpr::go (stmt.get_else_expr (), prefix, canonical_prefix);
PatternDeclaration::go (stmt.get_pattern (), Rib::ItemType::Var);
if (stmt.has_type ())
@@ -97,17 +98,15 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, struct_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId scope_node_id = struct_decl.get_node_id ();
resolver->get_type_scope ().push (scope_node_id);
if (struct_decl.has_generics ())
- {
- for (auto &generic : struct_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
- }
+ ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
+ canonical_prefix);
for (AST::TupleField &field : struct_decl.get_fields ())
ResolveType::go (field.get_field_type ());
@@ -130,17 +129,15 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, enum_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId scope_node_id = enum_decl.get_node_id ();
resolver->get_type_scope ().push (scope_node_id);
if (enum_decl.has_generics ())
- {
- for (auto &generic : enum_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
- }
+ ResolveGenericParams::go (enum_decl.get_generic_params (), prefix,
+ canonical_prefix);
for (auto &variant : enum_decl.get_variants ())
ResolveStmt::go (*variant, path, canonical_prefix, path);
@@ -162,7 +159,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
// Done, no fields.
@@ -182,7 +179,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
for (auto &field : item.get_tuple_fields ())
@@ -208,7 +205,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
for (auto &field : item.get_struct_fields ())
@@ -234,7 +231,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
// Done, no fields.
@@ -255,17 +252,15 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, struct_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId scope_node_id = struct_decl.get_node_id ();
resolver->get_type_scope ().push (scope_node_id);
if (struct_decl.has_generics ())
- {
- for (auto &generic : struct_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
- }
+ ResolveGenericParams::go (struct_decl.get_generic_params (), prefix,
+ canonical_prefix);
for (AST::StructField &field : struct_decl.get_fields ())
{
@@ -293,15 +288,15 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, union_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId scope_node_id = union_decl.get_node_id ();
resolver->get_type_scope ().push (scope_node_id);
if (union_decl.has_generics ())
- for (auto &generic : union_decl.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (union_decl.get_generic_params (), prefix,
+ canonical_prefix);
for (AST::StructField &field : union_decl.get_variants ())
{
@@ -329,7 +324,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, function.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId scope_node_id = function.get_node_id ();
@@ -338,11 +333,11 @@ public:
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
if (function.has_generics ())
- for (auto &generic : function.get_generic_params ())
- ResolveGenericParam::go (*generic, prefix, canonical_prefix);
+ ResolveGenericParams::go (function.get_generic_params (), prefix,
+ canonical_prefix);
if (function.has_return_type ())
ResolveType::go (function.get_return_type ());
diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
index 565ca92..f52fb8a 100644
--- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h
+++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
@@ -58,7 +58,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, module.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -88,7 +88,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, alias.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -110,7 +110,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, struct_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -132,7 +132,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, enum_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
resolver->push_new_module_scope (enum_decl.get_node_id ());
@@ -158,7 +158,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (item.get_node_id (), cpath);
@@ -180,7 +180,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (item.get_node_id (), cpath);
@@ -202,7 +202,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (item.get_node_id (), cpath);
@@ -224,7 +224,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, item.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
mappings.insert_canonical_path (item.get_node_id (), cpath);
@@ -242,14 +242,21 @@ public:
auto path = prefix.append (decl);
auto cpath = canonical_prefix.append (decl);
- resolver->get_type_scope ().insert (
- path, struct_decl.get_node_id (), struct_decl.get_locus (), false,
- Rib::ItemType::Type,
- [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rich_location r (line_table, struct_decl.get_locus ());
- r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
- });
+ auto duplicate_item
+ = [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
+ rich_location r (line_table, struct_decl.get_locus ());
+ r.add_range (locus);
+ redefined_error (r);
+ };
+
+ resolver->get_type_scope ().insert (path, struct_decl.get_node_id (),
+ struct_decl.get_locus (), false,
+ Rib::ItemType::Type, duplicate_item);
+
+ if (struct_decl.is_unit_struct ())
+ resolver->get_name_scope ().insert (path, struct_decl.get_node_id (),
+ struct_decl.get_locus (), false,
+ Rib::ItemType::Type, duplicate_item);
NodeId current_module = resolver->peek_current_module_scope ();
mappings.insert_module_child_item (current_module, decl);
@@ -270,7 +277,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, union_decl.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -290,7 +297,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, var.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -311,7 +318,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, constant.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -333,7 +340,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, function.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
NodeId current_module = resolver->peek_current_module_scope ();
@@ -381,7 +388,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, impl_block.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
for (auto &impl_item : impl_block.get_impl_items ())
@@ -401,7 +408,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, trait.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
for (auto &item : trait.get_trait_items ())
@@ -473,7 +480,7 @@ public:
[&] (const CanonicalPath &, NodeId, location_t locus) -> void {
rich_location r (line_table, extern_crate.get_locus ());
r.add_range (locus);
- rust_error_at (r, "redefined multiple times");
+ redefined_error (r);
});
}
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc
index 63c9dac..8fd69c3 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-type.cc
@@ -27,6 +27,49 @@ namespace Resolver {
// rust-ast-resolve-type.h
+NodeId
+ResolveType::go (AST::Type &type)
+{
+ ResolveType resolver;
+ type.accept_vis (resolver);
+ return resolver.resolved_node;
+}
+
+void
+ResolveType::visit (AST::BareFunctionType &fntype)
+{
+ for (auto &param : fntype.get_function_params ())
+ ResolveType::go (param.get_type ());
+
+ if (fntype.has_return_type ())
+ ResolveType::go (fntype.get_return_type ());
+}
+
+void
+ResolveType::visit (AST::TupleType &tuple)
+{
+ if (tuple.is_unit_type ())
+ {
+ resolved_node = resolver->get_unit_type_node_id ();
+ return;
+ }
+
+ for (auto &elem : tuple.get_elems ())
+ ResolveType::go (*elem);
+}
+
+void
+ResolveType::visit (AST::TypePath &path)
+{
+ ResolveRelativeTypePath::go (path, resolved_node);
+}
+
+void
+ResolveType::visit (AST::QualifiedPathInType &path)
+{
+ ResolveRelativeQualTypePath::go (path);
+}
+
void
ResolveType::visit (AST::ArrayType &type)
{
@@ -72,7 +115,7 @@ ResolveType::visit (AST::RawPointerType &type)
void
ResolveType::visit (AST::InferredType &)
{
- // FIXME
+ // nothing to do
}
void
@@ -87,6 +130,19 @@ ResolveType::visit (AST::SliceType &type)
resolved_node = ResolveType::go (type.get_elem_type ());
}
+void
+ResolveType::visit (AST::ImplTraitType &type)
+{
+ for (auto &bound : type.get_type_param_bounds ())
+ ResolveTypeBound::go (*bound);
+}
+
+void
+ResolveType::visit (AST::ImplTraitTypeOneBound &type)
+{
+ ResolveTypeBound::go (type.get_trait_bound ());
+}
+
// resolve relative type-paths
bool
@@ -120,8 +176,7 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
if (in_middle_of_path && segment->is_lower_self_seg ())
{
rust_error_at (segment->get_locus (), ErrorCode::E0433,
- "failed to resolve: %qs in paths can only be used "
- "in start position",
+ "%qs in paths can only be used in start position",
segment->as_string ().c_str ());
return false;
}
@@ -193,14 +248,28 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
= CanonicalPath::new_seg (segment->get_node_id (), ident_string);
if (resolver->get_type_scope ().lookup (path, &resolved_node))
{
- resolver->insert_resolved_type (segment->get_node_id (),
- resolved_node);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_type (segment->get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment->get_node_id (),
+ resolved_node);
resolved_node_id = resolved_node;
}
else if (resolver->get_name_scope ().lookup (path, &resolved_node))
{
- resolver->insert_resolved_name (segment->get_node_id (),
- resolved_node);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment->get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment->get_node_id (),
+ resolved_node);
resolved_node_id = resolved_node;
}
else if (!segment->is_lang_item () && segment->is_lower_self_seg ())
@@ -208,8 +277,16 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
// what is the current crate scope node id?
module_scope_id = crate_scope_id;
previous_resolved_node_id = module_scope_id;
- resolver->insert_resolved_name (segment->get_node_id (),
- module_scope_id);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok = resolver->lookup_resolved_name (segment->get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == module_scope_id);
+ else
+ resolver->insert_resolved_name (segment->get_node_id (),
+ module_scope_id);
continue;
}
@@ -227,15 +304,33 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_name (segment->get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_name (segment->get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_name (segment->get_node_id (),
+ resolved_node);
}
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node))
{
resolved_node_id = resolved_node;
- resolver->insert_resolved_type (segment->get_node_id (),
- resolved_node);
+
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_type (segment->get_node_id (),
+ &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node);
+ else
+ resolver->insert_resolved_type (segment->get_node_id (),
+ resolved_node);
}
else
{
@@ -260,8 +355,8 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
else if (is_first_segment)
{
rust_error_at (segment->get_locus (), ErrorCode::E0412,
- "failed to resolve TypePath: %s in this scope",
- segment->as_string ().c_str ());
+ "could not resolve type path %qs",
+ segment->get_ident_segment ().as_string ().c_str ());
return false;
}
}
@@ -271,15 +366,29 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
// name scope first
if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
{
- resolver->insert_resolved_name (path.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_name (path.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_name (path.get_node_id (),
+ resolved_node_id);
}
// check the type scope
else if (resolver->get_type_scope ().decl_was_declared_here (
resolved_node_id))
{
- resolver->insert_resolved_type (path.get_node_id (),
- resolved_node_id);
+ NodeId existing = UNKNOWN_NODEID;
+ bool ok
+ = resolver->lookup_resolved_type (path.get_node_id (), &existing);
+
+ if (ok)
+ rust_assert (existing == resolved_node_id);
+ else
+ resolver->insert_resolved_type (path.get_node_id (),
+ resolved_node_id);
}
else
{
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h
index 662f2f5..f1481fc 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.h
+++ b/gcc/rust/resolve/rust-ast-resolve-type.h
@@ -61,61 +61,23 @@ class ResolveType : public ResolverBase
using Rust::Resolver::ResolverBase::visit;
public:
- static NodeId go (AST::Type &type)
- {
- ResolveType resolver;
- type.accept_vis (resolver);
- return resolver.resolved_node;
- }
-
- void visit (AST::BareFunctionType &fntype) override
- {
- for (auto &param : fntype.get_function_params ())
- ResolveType::go (param.get_type ());
-
- if (fntype.has_return_type ())
- ResolveType::go (fntype.get_return_type ());
- }
-
- void visit (AST::TupleType &tuple) override
- {
- if (tuple.is_unit_type ())
- {
- resolved_node = resolver->get_unit_type_node_id ();
- return;
- }
-
- for (auto &elem : tuple.get_elems ())
- ResolveType::go (*elem);
- }
-
- void visit (AST::TypePath &path) override
- {
- ResolveRelativeTypePath::go (path, resolved_node);
- }
-
- void visit (AST::QualifiedPathInType &path) override
- {
- ResolveRelativeQualTypePath::go (path);
- }
+ static NodeId go (AST::Type &type);
+ void visit (AST::BareFunctionType &fntype) override;
+ void visit (AST::TupleType &tuple) override;
+ void visit (AST::TypePath &path) override;
+ void visit (AST::QualifiedPathInType &path) override;
void visit (AST::ArrayType &type) override;
-
void visit (AST::ReferenceType &type) override;
-
void visit (AST::InferredType &type) override;
-
void visit (AST::NeverType &type) override;
-
void visit (AST::RawPointerType &type) override;
-
void visit (AST::TraitObjectTypeOneBound &type) override;
-
void visit (AST::TraitObjectType &type) override;
-
void visit (AST::ParenthesisedType &type) override;
-
void visit (AST::SliceType &type) override;
+ void visit (AST::ImplTraitType &type) override;
+ void visit (AST::ImplTraitTypeOneBound &type) override;
private:
ResolveType () : ResolverBase () {}
@@ -142,66 +104,83 @@ private:
ResolveTypeBound () : ResolverBase () {}
};
-class ResolveGenericParam : public ResolverBase
+class ResolveGenericParams : public ResolverBase
{
using Rust::Resolver::ResolverBase::visit;
public:
- static NodeId go (AST::GenericParam &param, const CanonicalPath &prefix,
- const CanonicalPath &canonical_prefix)
+ static void go (std::vector<std::unique_ptr<AST::GenericParam>> &params,
+ const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
{
- ResolveGenericParam resolver (prefix, canonical_prefix);
- param.accept_vis (resolver);
- return resolver.resolved_node;
+ ResolveGenericParams resolver (prefix, canonical_prefix);
+
+ // this needs to be done in two phases as they can be used and defined later
+ // in bounds
+ for (auto &param : params)
+ param->accept_vis (resolver);
+
+ resolver.first_pass = false;
+
+ for (auto &param : params)
+ param->accept_vis (resolver);
}
- void visit (AST::ConstGenericParam &param) override
+ static void go_single (AST::GenericParam &param, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
{
- ResolveType::go (param.get_type ());
-
- if (param.has_default_value ())
- ResolveExpr::go (param.get_default_value ().get_expression (), prefix,
- canonical_prefix);
+ ResolveGenericParams resolver (prefix, canonical_prefix);
- ok = true;
+ param.accept_vis (resolver);
+ resolver.first_pass = false;
+ param.accept_vis (resolver);
}
- void visit (AST::TypeParam &param) override
+ void visit (AST::ConstGenericParam &param) override
{
- // if it has a type lets resolve it
- if (param.has_type ())
+ if (first_pass)
ResolveType::go (param.get_type ());
+ else if (param.has_default_value ())
+ ResolveExpr::go (param.get_default_value_unchecked ().get_expression (),
+ prefix, canonical_prefix);
+ }
- if (param.has_type_param_bounds ())
+ void visit (AST::TypeParam &param) override
+ {
+ if (first_pass)
+ {
+ // if it has a type lets resolve it
+ if (param.has_type ())
+ ResolveType::go (param.get_type ());
+
+ auto seg = CanonicalPath::new_seg (
+ param.get_node_id (), param.get_type_representation ().as_string ());
+ resolver->get_type_scope ().insert (
+ seg, param.get_node_id (), param.get_locus (), false,
+ Rib::ItemType::Type,
+ [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
+ rust_error_at (param.get_locus (),
+ "generic param defined multiple times");
+ rust_error_at (locus, "was defined here");
+ });
+
+ mappings.insert_canonical_path (param.get_node_id (), seg);
+ }
+ else if (param.has_type_param_bounds ())
{
for (auto &bound : param.get_type_param_bounds ())
- {
- ResolveTypeBound::go (*bound);
- }
+ ResolveTypeBound::go (*bound);
}
-
- auto seg
- = CanonicalPath::new_seg (param.get_node_id (),
- param.get_type_representation ().as_string ());
- resolver->get_type_scope ().insert (
- seg, param.get_node_id (), param.get_locus (), false, Rib::ItemType::Type,
- [&] (const CanonicalPath &, NodeId, location_t locus) -> void {
- rust_error_at (param.get_locus (),
- "generic param redefined multiple times");
- rust_error_at (locus, "was defined here");
- });
-
- mappings.insert_canonical_path (param.get_node_id (), seg);
}
private:
- ResolveGenericParam (const CanonicalPath &prefix,
- const CanonicalPath &canonical_prefix)
- : ResolverBase (), ok (false), prefix (prefix),
+ ResolveGenericParams (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ : ResolverBase (), first_pass (true), prefix (prefix),
canonical_prefix (canonical_prefix)
{}
- bool ok;
+ bool first_pass;
const CanonicalPath &prefix;
const CanonicalPath &canonical_prefix;
};
diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc
index a093ef7..3e3c992 100644
--- a/gcc/rust/resolve/rust-ast-resolve.cc
+++ b/gcc/rust/resolve/rust-ast-resolve.cc
@@ -75,7 +75,7 @@ NameResolution::go (AST::Crate &crate)
resolver->get_label_scope ().push (scope_node_id);
resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
- resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_label_scope ().peek ());
// get the root segment
CanonicalPath crate_prefix
diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc
index 7528e79..480034c 100644
--- a/gcc/rust/resolve/rust-default-resolver.cc
+++ b/gcc/rust/resolve/rust-default-resolver.cc
@@ -179,5 +179,13 @@ DefaultResolver::visit (AST::StaticItem &item)
ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis);
}
+void
+DefaultResolver::visit (AST::TypeParam &param)
+{
+ auto expr_vis = [this, &param] () { AST::DefaultASTVisitor::visit (param); };
+
+ ctx.scoped (Rib::Kind::ForwardTypeParamBan, param.get_node_id (), expr_vis);
+}
+
} // namespace Resolver2_0
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-default-resolver.h b/gcc/rust/resolve/rust-default-resolver.h
index 587d7d4..2a987ef 100644
--- a/gcc/rust/resolve/rust-default-resolver.h
+++ b/gcc/rust/resolve/rust-default-resolver.h
@@ -50,6 +50,8 @@ public:
void visit (AST::InherentImpl &) override;
void visit (AST::TraitImpl &) override;
+ void visit (AST::TypeParam &) override;
+
// type dec nodes, which visit their fields or variants by default
void visit (AST::StructStruct &) override;
void visit (AST::TupleStruct &) override;
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
index 342f102..3390f09 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -22,11 +22,13 @@
#include "rust-toplevel-name-resolver-2.0.h"
#include "rust-attributes.h"
#include "rust-finalize-imports-2.0.h"
+#include "rust-attribute-values.h"
namespace Rust {
namespace Resolver2_0 {
-Early::Early (NameResolutionContext &ctx) : DefaultResolver (ctx), dirty (false)
+Early::Early (NameResolutionContext &ctx)
+ : DefaultResolver (ctx), toplevel (TopLevel (ctx)), dirty (false)
{}
void
@@ -51,16 +53,10 @@ void
Early::go (AST::Crate &crate)
{
// First we go through TopLevel resolution to get all our declared items
- auto toplevel = TopLevel (ctx);
toplevel.go (crate);
// We start with resolving the list of imports that `TopLevel` has built for
// us
- for (auto &&import : toplevel.get_imports_to_resolve ())
- build_import_mapping (std::move (import));
-
- // Once this is done, we finalize their resolution
- FinalizeImports (std::move (import_mappings), toplevel, ctx).go (crate);
dirty = toplevel.is_dirty ();
// We now proceed with resolving macros, which can be nested in almost any
@@ -74,7 +70,7 @@ Early::go (AST::Crate &crate)
bool
Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob)
{
- auto resolved = ctx.types.resolve_path (glob.to_resolve.get_segments ());
+ auto resolved = ctx.resolve_path (glob.to_resolve, Namespace::Types);
if (!resolved.has_value ())
return false;
@@ -144,6 +140,10 @@ Early::build_import_mapping (
// be moved into the newly created import mappings
auto path = import.to_resolve;
+ // used to skip the "unresolved import" error
+ // if we output other errors during resolution
+ size_t old_error_count = macro_resolve_errors.size ();
+
switch (import.kind)
{
case TopLevel::ImportKind::Kind::Glob:
@@ -157,7 +157,7 @@ Early::build_import_mapping (
break;
}
- if (!found)
+ if (!found && old_error_count == macro_resolve_errors.size ())
collect_error (Error (path.get_final_segment ().get_locus (),
ErrorCode::E0433, "unresolved import %qs",
path.as_string ().c_str ()));
@@ -226,11 +226,24 @@ Early::visit (AST::BlockExpr &block)
void
Early::visit (AST::Module &module)
{
- textual_scope.push ();
+ bool is_macro_use = false;
+
+ for (const auto &attr : module.get_outer_attrs ())
+ {
+ if (attr.get_path ().as_string () == Values::Attributes::MACRO_USE)
+ {
+ is_macro_use = true;
+ break;
+ }
+ }
+
+ if (!is_macro_use)
+ textual_scope.push ();
DefaultResolver::visit (module);
- textual_scope.pop ();
+ if (!is_macro_use)
+ textual_scope.pop ();
}
void
@@ -259,13 +272,14 @@ Early::visit (AST::MacroInvocation &invoc)
// we won't have changed `definition` from `nullopt` if there are more
// than one segments in our path
if (!definition.has_value ())
- definition = ctx.macros.resolve_path (path.get_segments ());
+ definition = ctx.resolve_path (path.get_segments (), Namespace::Macros);
// if the definition still does not have a value, then it's an error
if (!definition.has_value ())
{
collect_error (Error (invoc.get_locus (), ErrorCode::E0433,
- "could not resolve macro invocation"));
+ "could not resolve macro invocation %qs",
+ path.as_string ().c_str ()));
return;
}
@@ -300,8 +314,8 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs)
auto traits = attr.get_traits_to_derive ();
for (auto &trait : traits)
{
- auto definition
- = ctx.macros.resolve_path (trait.get ().get_segments ());
+ auto definition = ctx.resolve_path (trait.get ().get_segments (),
+ Namespace::Macros);
if (!definition.has_value ())
{
// FIXME: Change to proper error message
@@ -314,18 +328,17 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs)
auto pm_def = mappings.lookup_derive_proc_macro_def (
definition->get_node_id ());
- rust_assert (pm_def.has_value ());
-
- mappings.insert_derive_proc_macro_invocation (trait,
- pm_def.value ());
+ if (pm_def.has_value ())
+ mappings.insert_derive_proc_macro_invocation (trait,
+ pm_def.value ());
}
}
else if (Analysis::BuiltinAttributeMappings::get ()
->lookup_builtin (name)
.is_error ()) // Do not resolve builtins
{
- auto definition
- = ctx.macros.resolve_path (attr.get_path ().get_segments ());
+ auto definition = ctx.resolve_path (attr.get_path ().get_segments (),
+ Namespace::Macros);
if (!definition.has_value ())
{
// FIXME: Change to proper error message
@@ -359,5 +372,103 @@ Early::visit (AST::StructStruct &s)
DefaultResolver::visit (s);
}
+void
+Early::finalize_simple_import (const Early::ImportPair &mapping)
+{
+ // FIXME: We probably need to store namespace information
+
+ auto locus = mapping.import_kind.to_resolve.get_locus ();
+ auto data = mapping.data;
+ auto identifier
+ = mapping.import_kind.to_resolve.get_final_segment ().get_segment_name ();
+
+ for (auto &&definition : data.definitions ())
+ toplevel
+ .insert_or_error_out (
+ identifier, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
+}
+
+void
+Early::finalize_glob_import (NameResolutionContext &ctx,
+ const Early::ImportPair &mapping)
+{
+ auto module = Analysis::Mappings::get ().lookup_ast_module (
+ mapping.data.module ().get_node_id ());
+ rust_assert (module);
+
+ GlobbingVisitor glob_visitor (ctx);
+ glob_visitor.go (module.value ());
+}
+
+void
+Early::finalize_rebind_import (const Early::ImportPair &mapping)
+{
+ // We can fetch the value here as `resolve_rebind` will only be called on
+ // imports of the right kind
+ auto &path = mapping.import_kind.to_resolve;
+ auto &rebind = mapping.import_kind.rebind.value ();
+ auto data = mapping.data;
+
+ location_t locus = UNKNOWN_LOCATION;
+ std::string declared_name;
+
+ // FIXME: This needs to be done in `FinalizeImports`
+ switch (rebind.get_new_bind_type ())
+ {
+ case AST::UseTreeRebind::NewBindType::IDENTIFIER:
+ declared_name = rebind.get_identifier ().as_string ();
+ locus = rebind.get_identifier ().get_locus ();
+ break;
+ case AST::UseTreeRebind::NewBindType::NONE: {
+ const auto &segments = path.get_segments ();
+ // We don't want to insert `self` with `use module::self`
+ if (path.get_final_segment ().is_lower_self_seg ())
+ {
+ rust_assert (segments.size () > 1);
+ declared_name = segments[segments.size () - 2].as_string ();
+ }
+ else
+ declared_name = path.get_final_segment ().as_string ();
+ locus = path.get_final_segment ().get_locus ();
+ break;
+ }
+ case AST::UseTreeRebind::NewBindType::WILDCARD:
+ rust_unreachable ();
+ break;
+ }
+
+ for (auto &&definition : data.definitions ())
+ toplevel.insert_or_error_out (
+ declared_name, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
+}
+
+void
+Early::visit (AST::UseDeclaration &decl)
+{
+ auto &imports = toplevel.get_imports_to_resolve ();
+ auto current_import = imports.find (decl.get_node_id ());
+ if (current_import != imports.end ())
+ {
+ build_import_mapping (*current_import);
+ }
+
+ // Once this is done, we finalize their resolution
+ for (const auto &mapping : import_mappings.get (decl.get_node_id ()))
+ switch (mapping.import_kind.kind)
+ {
+ case TopLevel::ImportKind::Kind::Glob:
+ finalize_glob_import (ctx, mapping);
+ break;
+ case TopLevel::ImportKind::Kind::Simple:
+ finalize_simple_import (mapping);
+ break;
+ case TopLevel::ImportKind::Kind::Rebind:
+ finalize_rebind_import (mapping);
+ break;
+ }
+
+ DefaultResolver::visit (decl);
+}
+
} // namespace Resolver2_0
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
index a7ad0f7..e78bec0 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
@@ -34,6 +34,7 @@ class Early : public DefaultResolver
{
using DefaultResolver::visit;
+ TopLevel toplevel;
bool dirty;
public:
@@ -59,6 +60,7 @@ public:
void visit (AST::Function &) override;
void visit (AST::StructStruct &) override;
+ void visit (AST::UseDeclaration &) override;
struct ImportData
{
@@ -216,7 +218,6 @@ private:
std::vector<std::pair<Rib::Definition, Namespace>>
resolve_path_in_all_ns (const P &path)
{
- const auto &segments = path.get_segments ();
std::vector<std::pair<Rib::Definition, Namespace>> resolved;
// Pair a definition with the namespace it was found in
@@ -227,9 +228,21 @@ private:
};
};
- ctx.values.resolve_path (segments).map (pair_with_ns (Namespace::Values));
- ctx.types.resolve_path (segments).map (pair_with_ns (Namespace::Types));
- ctx.macros.resolve_path (segments).map (pair_with_ns (Namespace::Macros));
+ std::vector<Error> value_errors;
+ std::vector<Error> type_errors;
+ std::vector<Error> macro_errors;
+
+ ctx.resolve_path (path, value_errors, Namespace::Values)
+ .map (pair_with_ns (Namespace::Values));
+ ctx.resolve_path (path, type_errors, Namespace::Types)
+ .map (pair_with_ns (Namespace::Types));
+ ctx.resolve_path (path, macro_errors, Namespace::Macros)
+ .map (pair_with_ns (Namespace::Macros));
+
+ if (!value_errors.empty () && !type_errors.empty ()
+ && !macro_errors.empty ())
+ for (auto &ent : value_errors)
+ collect_error (std::move (ent));
return resolved;
}
@@ -243,6 +256,13 @@ private:
std::vector<Error> macro_resolve_errors;
void collect_error (Error e) { macro_resolve_errors.push_back (e); }
+
+ void finalize_simple_import (const Early::ImportPair &mapping);
+
+ void finalize_glob_import (NameResolutionContext &ctx,
+ const Early::ImportPair &mapping);
+
+ void finalize_rebind_import (const Early::ImportPair &mapping);
};
} // namespace Resolver2_0
diff --git a/gcc/rust/resolve/rust-early-name-resolver.cc b/gcc/rust/resolve/rust-early-name-resolver.cc
index 34bac98..fc9a26c 100644
--- a/gcc/rust/resolve/rust-early-name-resolver.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver.cc
@@ -156,9 +156,10 @@ EarlyNameResolver::visit (AST::ConstGenericParam &)
void
EarlyNameResolver::visit (AST::PathInExpression &path)
{
- for (auto &segment : path.get_segments ())
- if (segment.has_generic_args ())
- resolve_generic_args (segment.get_generic_args ());
+ if (!path.is_lang_item ())
+ for (auto &segment : path.get_segments ())
+ if (segment.has_generic_args ())
+ resolve_generic_args (segment.get_generic_args ());
}
void
@@ -476,7 +477,8 @@ EarlyNameResolver::visit (AST::MacroInvocation &invoc)
bool found = resolver.get_macro_scope ().lookup (seg, &resolved_node);
if (!found)
{
- rust_error_at (invoc.get_locus (), "unknown macro: [%s]",
+ rust_error_at (invoc.get_locus (), ErrorCode::E0433,
+ "could not resolve macro invocation %qs",
seg.get ().c_str ());
return;
}
@@ -560,30 +562,6 @@ EarlyNameResolver::visit (AST::TupleStructPattern &pattern)
}
void
-EarlyNameResolver::visit (AST::TraitBound &)
-{}
-
-void
-EarlyNameResolver::visit (AST::ImplTraitType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::TraitObjectType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::ParenthesisedType &)
-{}
-
-void
-EarlyNameResolver::visit (AST::ImplTraitTypeOneBound &)
-{}
-
-void
-EarlyNameResolver::visit (AST::TraitObjectTypeOneBound &)
-{}
-
-void
EarlyNameResolver::visit (AST::TupleType &)
{}
diff --git a/gcc/rust/resolve/rust-early-name-resolver.h b/gcc/rust/resolve/rust-early-name-resolver.h
index 48562df..26fc84d 100644
--- a/gcc/rust/resolve/rust-early-name-resolver.h
+++ b/gcc/rust/resolve/rust-early-name-resolver.h
@@ -36,6 +36,7 @@ public:
private:
using AST::DefaultASTVisitor::visit;
+
/**
* Execute a lambda within a scope. This is equivalent to calling
* `enter_scope` before your code and `exit_scope` after. This ensures
@@ -181,12 +182,6 @@ private:
virtual void visit (AST::StructPatternFieldIdent &field);
virtual void visit (AST::StructPattern &pattern);
virtual void visit (AST::TupleStructPattern &pattern);
- virtual void visit (AST::TraitBound &bound);
- virtual void visit (AST::ImplTraitType &type);
- virtual void visit (AST::TraitObjectType &type);
- virtual void visit (AST::ParenthesisedType &type);
- virtual void visit (AST::ImplTraitTypeOneBound &type);
- virtual void visit (AST::TraitObjectTypeOneBound &type);
virtual void visit (AST::TupleType &type);
virtual void visit (AST::RawPointerType &type);
virtual void visit (AST::ReferenceType &type);
diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.cc b/gcc/rust/resolve/rust-finalize-imports-2.0.cc
index 71916ae..b0e8651 100644
--- a/gcc/rust/resolve/rust-finalize-imports-2.0.cc
+++ b/gcc/rust/resolve/rust-finalize-imports-2.0.cc
@@ -125,100 +125,5 @@ GlobbingVisitor::visit (AST::UseDeclaration &use)
// Handle cycles ?
}
-void
-finalize_simple_import (TopLevel &toplevel, const Early::ImportPair &mapping)
-{
- // FIXME: We probably need to store namespace information
-
- auto locus = mapping.import_kind.to_resolve.get_locus ();
- auto data = mapping.data;
- auto identifier
- = mapping.import_kind.to_resolve.get_final_segment ().get_segment_name ();
-
- for (auto &&definition : data.definitions ())
- toplevel
- .insert_or_error_out (
- identifier, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
-}
-
-void
-finalize_glob_import (NameResolutionContext &ctx,
- const Early::ImportPair &mapping)
-{
- auto module = Analysis::Mappings::get ().lookup_ast_module (
- mapping.data.module ().get_node_id ());
- rust_assert (module);
-
- GlobbingVisitor glob_visitor (ctx);
- glob_visitor.go (module.value ());
-}
-
-void
-finalize_rebind_import (TopLevel &toplevel, const Early::ImportPair &mapping)
-{
- // We can fetch the value here as `resolve_rebind` will only be called on
- // imports of the right kind
- auto &path = mapping.import_kind.to_resolve;
- auto &rebind = mapping.import_kind.rebind.value ();
- auto data = mapping.data;
-
- location_t locus = UNKNOWN_LOCATION;
- std::string declared_name;
-
- // FIXME: This needs to be done in `FinalizeImports`
- switch (rebind.get_new_bind_type ())
- {
- case AST::UseTreeRebind::NewBindType::IDENTIFIER:
- declared_name = rebind.get_identifier ().as_string ();
- locus = rebind.get_identifier ().get_locus ();
- break;
- case AST::UseTreeRebind::NewBindType::NONE:
- declared_name = path.get_final_segment ().as_string ();
- locus = path.get_final_segment ().get_locus ();
- break;
- case AST::UseTreeRebind::NewBindType::WILDCARD:
- rust_unreachable ();
- break;
- }
-
- for (auto &&definition : data.definitions ())
- toplevel.insert_or_error_out (
- declared_name, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
-}
-
-FinalizeImports::FinalizeImports (Early::ImportMappings &&data,
- TopLevel &toplevel,
- NameResolutionContext &ctx)
- : DefaultResolver (ctx), data (std::move (data)), toplevel (toplevel),
- ctx (ctx)
-{}
-
-void
-FinalizeImports::go (AST::Crate &crate)
-{
- for (auto &item : crate.items)
- item->accept_vis (*this);
-}
-
-void
-FinalizeImports::visit (AST::UseDeclaration &use)
-{
- auto import_mappings = data.get (use.get_node_id ());
-
- for (const auto &mapping : import_mappings)
- switch (mapping.import_kind.kind)
- {
- case TopLevel::ImportKind::Kind::Glob:
- finalize_glob_import (ctx, mapping);
- break;
- case TopLevel::ImportKind::Kind::Simple:
- finalize_simple_import (toplevel, mapping);
- break;
- case TopLevel::ImportKind::Kind::Rebind:
- finalize_rebind_import (toplevel, mapping);
- break;
- }
-}
-
} // namespace Resolver2_0
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.h b/gcc/rust/resolve/rust-finalize-imports-2.0.h
index 0fba5a5..d587a5e 100644
--- a/gcc/rust/resolve/rust-finalize-imports-2.0.h
+++ b/gcc/rust/resolve/rust-finalize-imports-2.0.h
@@ -49,62 +49,5 @@ private:
NameResolutionContext &ctx;
};
-// TODO: Fix documentation
-// How do we do that?
-//
-// We want to resolve in the EarlyNameResolver, but we want to declare in the
-// TopLevel Should the TopLevel declare stubs? How does rustc do it? How to do
-// that for globbing? Should we do globbing afterwards once we've declared all
-// the Uses*?
-//
-// Basically, for each use declare it in a separate map - in the
-// EarlyNameResolver resolve and fix the ForeverStack? Emptying the maps each
-// time?
-//
-// e.g. TopLevel builds a std::vector<NodeId, SimplePath> use_trees_to_resolve;
-// Early goes through and resolves the SimplePath, then replaces the NodeId with
-// the resolved one? Do we even need to do that?
-//
-// rustc just creates an empty definition for the use tree.
-//
-// What about globbing? std::vector<GlobbulesPath> globules;
-// Early goes through and visits the module's path and calls the
-// GlobbingVisitor?
-//
-// the file `imports.rs` goes through and *finalizes* imports. So we can
-// probably add a FinalizeImport pass after the TopLevel and the Early.
-// - TopLevel takes care of declaring these use trees
-// - Early takes care of resolving them to definition points
-// - Finalize takes care of mapping the use's definition point to the actual
-// definition point
-// - We need to work more on that last bit to know exactly what is being
-// inserted, but probably it's going to mutate the ForeverStack - is that okay?
-// - Oh actually maybe no!
-// - TopLevel creates a map of UseTrees with paths to resolve. This should
-// probably be an ImportKind enum or whatever
-// - Early resolves them, creates a map of SimplePath with the associated
-// definition: Map<ImportKind, ImportData>
-// - Finalizes visits all UseTrees and inserts the Definitions found for
-// each ImportKind - easy!
-// - yay!
-
-class FinalizeImports : DefaultResolver
-{
-public:
- FinalizeImports (Early::ImportMappings &&data, TopLevel &toplevel,
- NameResolutionContext &ctx);
-
- void go (AST::Crate &crate);
-
-private:
- using AST::DefaultASTVisitor::visit;
-
- void visit (AST::UseDeclaration &) override;
-
- Early::ImportMappings data;
- TopLevel &toplevel;
- NameResolutionContext &ctx;
-};
-
} // namespace Resolver2_0
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h
index 66e1266..81468e5 100644
--- a/gcc/rust/resolve/rust-forever-stack.h
+++ b/gcc/rust/resolve/rust-forever-stack.h
@@ -547,13 +547,18 @@ template <Namespace N> class ForeverStack
{
public:
ForeverStack ()
- // FIXME: Is that valid? Do we use the root? If yes, we should give the
- // crate's node id to ForeverStack's constructor
: root (Node (Rib (Rib::Kind::Normal), UNKNOWN_NODEID)),
+ lang_prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID, root)),
+ extern_prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID)),
cursor_reference (root)
{
rust_assert (root.is_root ());
rust_assert (root.is_leaf ());
+
+ // TODO: Should we be using the forever stack root as the crate scope?
+ // TODO: Is this how we should be getting the crate node id?
+ auto &mappings = Analysis::Mappings::get ();
+ root.id = *mappings.crate_num_to_nodeid (mappings.get_current_crate ());
}
/**
@@ -588,6 +593,9 @@ public:
*/
tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id);
+ tl::expected<NodeId, DuplicateNameError> insert_variant (Identifier name,
+ NodeId id);
+
/**
* Insert a new shadowable definition in the innermost `Rib` in this stack
*
@@ -651,6 +659,8 @@ public:
* the current map, an empty one otherwise.
*/
tl::optional<Rib::Definition> get (const Identifier &name);
+ tl::optional<Rib::Definition> get_lang_prelude (const Identifier &name);
+ tl::optional<Rib::Definition> get_lang_prelude (const std::string &name);
/**
* Resolve a path to its definition in the current `ForeverStack`
@@ -661,7 +671,10 @@ public:
* current map, an empty one otherwise.
*/
template <typename S>
- tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments);
+ tl::optional<Rib::Definition> resolve_path (
+ const std::vector<S> &segments, bool has_opening_scope_resolution,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors);
// FIXME: Documentation
tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const;
@@ -670,7 +683,7 @@ public:
tl::optional<Rib &> to_rib (NodeId rib_id);
tl::optional<const Rib &> to_rib (NodeId rib_id) const;
- std::string as_debug_string ();
+ std::string as_debug_string () const;
/**
* Used to check if a module is a descendant of another module
@@ -713,6 +726,7 @@ private:
{}
bool is_root () const;
+ bool is_prelude () const;
bool is_leaf () const;
void insert_child (Link link, Node child);
@@ -748,13 +762,25 @@ 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 lang_prelude;
+ /*
+ * The extern prelude, used for resolving external crates
+ */
+ Node extern_prelude;
+
std::reference_wrapper<Node> cursor_reference;
void stream_rib (std::stringstream &stream, const Rib &rib,
- const std::string &next, const std::string &next_next);
+ const std::string &next, const std::string &next_next) const;
void stream_node (std::stringstream &stream, unsigned indentation,
- const Node &node);
+ const Node &node) const;
/* Helper types and functions for `resolve_path` */
@@ -764,14 +790,22 @@ private:
Node &find_closest_module (Node &starting_point);
template <typename S>
- tl::optional<SegIterator<S>>
- find_starting_point (const std::vector<S> &segments,
- std::reference_wrapper<Node> &starting_point);
+ tl::optional<SegIterator<S>> find_starting_point (
+ const std::vector<S> &segments,
+ std::reference_wrapper<Node> &starting_point,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors);
template <typename S>
- tl::optional<Node &> resolve_segments (Node &starting_point,
- const std::vector<S> &segments,
- SegIterator<S> iterator);
+ tl::optional<Node &> resolve_segments (
+ Node &starting_point, const std::vector<S> &segments,
+ SegIterator<S> iterator,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors);
+
+ tl::optional<Rib::Definition> resolve_final_segment (Node &final_node,
+ std::string &seg_name,
+ bool is_lower_self);
/* Helper functions for forward resolution (to_canonical_path, to_rib...) */
struct DfsResult
@@ -797,6 +831,21 @@ private:
tl::optional<Node &> dfs_node (Node &starting_point, NodeId to_find);
tl::optional<const Node &> dfs_node (const Node &starting_point,
NodeId to_find) const;
+
+public:
+ bool forward_declared (NodeId definition, NodeId usage)
+ {
+ if (peek ().kind != Rib::Kind::ForwardTypeParamBan)
+ return false;
+
+ const auto &definition_rib = dfs_rib (cursor (), definition);
+
+ if (!definition_rib)
+ return false;
+
+ return (definition_rib
+ && definition_rib.value ().kind == Rib::Kind::ForwardTypeParamBan);
+ }
};
} // namespace Resolver2_0
diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx
index d3d7889..069111e 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -20,7 +20,9 @@
#include "rust-ast.h"
#include "rust-diagnostics.h"
#include "rust-forever-stack.h"
+#include "rust-edition.h"
#include "rust-rib.h"
+#include "rust-unwrap-segment.h"
#include "optional.h"
namespace Rust {
@@ -35,6 +37,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 ();
@@ -62,6 +71,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->lang_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
@@ -172,6 +191,14 @@ ForeverStack<Namespace::Labels>::insert (Identifier name, NodeId node)
Rib::Definition::Shadowable (node));
}
+template <>
+inline tl::expected<NodeId, DuplicateNameError>
+ForeverStack<Namespace::Types>::insert_variant (Identifier name, NodeId node)
+{
+ return insert_inner (peek (), name.as_string (),
+ Rib::Definition::NonShadowable (node, true));
+}
+
template <Namespace N>
Rib &
ForeverStack<N>::peek ()
@@ -274,10 +301,12 @@ ForeverStack<N>::get (const Identifier &name)
return candidate.map_or (
[&resolved_definition] (Rib::Definition found) {
- // for most namespaces, we do not need to care about various ribs - they
- // are available from all contexts if defined in the current scope, or
- // an outermore one. so if we do have a candidate, we can return it
- // directly and stop iterating
+ if (found.is_variant ())
+ return KeepGoing::Yes;
+ // for most namespaces, we do not need to care about various ribs -
+ // they are available from all contexts if defined in the current
+ // scope, or an outermore one. so if we do have a candidate, we can
+ // return it directly and stop iterating
resolved_definition = found;
return KeepGoing::No;
@@ -289,6 +318,20 @@ ForeverStack<N>::get (const Identifier &name)
return resolved_definition;
}
+template <Namespace N>
+tl::optional<Rib::Definition>
+ForeverStack<N>::get_lang_prelude (const Identifier &name)
+{
+ return lang_prelude.rib.get (name.as_string ());
+}
+
+template <Namespace N>
+tl::optional<Rib::Definition>
+ForeverStack<N>::get_lang_prelude (const std::string &name)
+{
+ return lang_prelude.rib.get (name);
+}
+
template <>
tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get (
const Identifier &name)
@@ -355,12 +398,13 @@ ForeverStack<N>::find_closest_module (Node &starting_point)
* segments */
template <typename S>
static inline bool
-check_leading_kw_at_start (const S &segment, bool condition)
+check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment,
+ bool condition)
{
if (condition)
- rust_error_at (
+ collect_errors.emplace_back (
segment.get_locus (), ErrorCode::E0433,
- "leading path segment %qs can only be used at the beginning of a path",
+ "%qs in paths can only be used in start position",
segment.as_string ().c_str ());
return condition;
@@ -375,52 +419,60 @@ template <Namespace N>
template <typename S>
tl::optional<typename std::vector<S>::const_iterator>
ForeverStack<N>::find_starting_point (
- const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point)
+ const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors)
{
auto iterator = segments.begin ();
- // If we need to do path segment resolution, then we start
- // at the closest module. In order to resolve something like `foo::bar!()`, we
- // need to get back to the surrounding module, and look for a child module
- // named `foo`.
- if (segments.size () > 1)
- starting_point = find_closest_module (starting_point);
-
for (; !is_last (iterator, segments); iterator++)
{
- auto &seg = *iterator;
- auto is_self_or_crate
+ auto &outer_seg = *iterator;
+
+ if (unwrap_segment_get_lang_item (outer_seg).has_value ())
+ break;
+
+ auto &seg = unwrap_type_segment (outer_seg);
+ 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
// an error - we should only be seeing `super` keywords at this point
- if (check_leading_kw_at_start (seg, !is_start (iterator, segments)
- && is_self_or_crate))
+ if (check_leading_kw_at_start (collect_errors, seg,
+ !is_start (iterator, segments)
+ && is_self_or_crate))
return tl::nullopt;
if (seg.is_crate_path_seg ())
{
starting_point = root;
+ insert_segment_resolution (outer_seg, starting_point.get ().id);
iterator++;
break;
}
if (seg.is_lower_self_seg ())
{
- // do nothing and exit
+ // insert segment resolution and exit
+ starting_point = find_closest_module (starting_point);
+ insert_segment_resolution (outer_seg, starting_point.get ().id);
iterator++;
break;
}
if (seg.is_super_path_seg ())
{
+ starting_point = find_closest_module (starting_point);
if (starting_point.get ().is_root ())
{
- rust_error_at (seg.get_locus (), ErrorCode::E0433,
- "too many leading %<super%> keywords");
+ collect_errors.emplace_back (
+ seg.get_locus (), ErrorCode::E0433,
+ "too many leading %<super%> keywords");
return tl::nullopt;
}
starting_point
= find_closest_module (starting_point.get ().parent.value ());
+
+ insert_segment_resolution (outer_seg, starting_point.get ().id);
continue;
}
@@ -438,73 +490,223 @@ template <typename S>
tl::optional<typename ForeverStack<N>::Node &>
ForeverStack<N>::resolve_segments (
Node &starting_point, const std::vector<S> &segments,
- typename std::vector<S>::const_iterator iterator)
+ typename std::vector<S>::const_iterator iterator,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors)
{
- auto *current_node = &starting_point;
+ Node *current_node = &starting_point;
for (; !is_last (iterator, segments); iterator++)
{
- auto &seg = *iterator;
- auto str = seg.as_string ();
+ auto &outer_seg = *iterator;
+
+ if (auto lang_item = unwrap_segment_get_lang_item (outer_seg))
+ {
+ NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (
+ lang_item.value ());
+ current_node = &dfs_node (root, seg_id).value ();
+
+ insert_segment_resolution (outer_seg, seg_id);
+ continue;
+ }
+
+ auto &seg = unwrap_type_segment (outer_seg);
+ 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
- if (check_leading_kw_at_start (seg, seg.is_crate_path_seg ()
- || seg.is_super_path_seg ()
- || seg.is_lower_self_seg ()))
+ if (check_leading_kw_at_start (collect_errors, seg,
+ seg.is_crate_path_seg ()
+ || seg.is_super_path_seg ()
+ || seg.is_lower_self_seg ()))
return tl::nullopt;
tl::optional<typename ForeverStack<N>::Node &> child = tl::nullopt;
- for (auto &kv : current_node->children)
+ /*
+ * On every iteration this loop either
+ *
+ * 1. terminates
+ *
+ * 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)
{
- auto &link = kv.first;
+ // may set the value of child
+ for (auto &kv : current_node->children)
+ {
+ auto &link = kv.first;
+
+ if (link.path.map_or (
+ [&str] (Identifier path) {
+ auto &path_str = path.as_string ();
+ return str == path_str;
+ },
+ false))
+ {
+ child = kv.second;
+ break;
+ }
+ }
- if (link.path.map_or (
- [&str] (Identifier path) {
- auto &path_str = path.as_string ();
- return str == path_str;
- },
- false))
+ if (child.has_value ())
{
- child = kv.second;
break;
}
- }
- if (!child.has_value ())
- {
- rust_error_at (seg.get_locus (), ErrorCode::E0433,
- "failed to resolve path segment %qs", str.c_str ());
- return tl::nullopt;
+ if (N == Namespace::Types)
+ {
+ auto rib_lookup = current_node->rib.get (seg.as_string ());
+ if (rib_lookup && !rib_lookup->is_ambiguous ())
+ {
+ insert_segment_resolution (outer_seg,
+ rib_lookup->get_node_id ());
+ return tl::nullopt;
+ }
+ }
+
+ if (current_node->is_root () && !searched_prelude)
+ {
+ searched_prelude = true;
+ current_node = &lang_prelude;
+ continue;
+ }
+
+ if (!is_start (iterator, segments)
+ || current_node->rib.kind == Rib::Kind::Module
+ || current_node->is_prelude ())
+ {
+ return tl::nullopt;
+ }
+
+ current_node = &current_node->parent.value ();
}
+ // if child didn't contain a value
+ // the while loop above should have return'd or kept looping
current_node = &child.value ();
+ insert_segment_resolution (outer_seg, current_node->id);
}
return *current_node;
}
+template <>
+inline tl::optional<Rib::Definition>
+ForeverStack<Namespace::Types>::resolve_final_segment (Node &final_node,
+ std::string &seg_name,
+ bool is_lower_self)
+{
+ if (is_lower_self)
+ return Rib::Definition::NonShadowable (final_node.id);
+ else
+ return final_node.rib.get (seg_name);
+}
+
+template <Namespace N>
+tl::optional<Rib::Definition>
+ForeverStack<N>::resolve_final_segment (Node &final_node, std::string &seg_name,
+ bool is_lower_self)
+{
+ return final_node.rib.get (seg_name);
+}
+
template <Namespace N>
template <typename S>
tl::optional<Rib::Definition>
-ForeverStack<N>::resolve_path (const std::vector<S> &segments)
+ForeverStack<N>::resolve_path (
+ const std::vector<S> &segments, bool has_opening_scope_resolution,
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors)
{
// TODO: What to do if segments.empty() ?
+ // handle paths with opening scopes
+ std::function<void (void)> cleanup_current = [] () {};
+ if (has_opening_scope_resolution)
+ {
+ Node *last_current = &cursor_reference.get ();
+ if (get_rust_edition () == Edition::E2015)
+ cursor_reference = root;
+ else
+ cursor_reference = extern_prelude;
+ cleanup_current
+ = [this, last_current] () { cursor_reference = *last_current; };
+ }
+
// if there's only one segment, we just use `get`
if (segments.size () == 1)
- return get (segments.back ().as_string ());
+ {
+ auto &seg = segments.front ();
+ if (auto lang_item = unwrap_segment_get_lang_item (seg))
+ {
+ NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node (
+ lang_item.value ());
+
+ insert_segment_resolution (seg, seg_id);
+ cleanup_current ();
+ // TODO: does NonShadowable matter?
+ return Rib::Definition::NonShadowable (seg_id);
+ }
+
+ tl::optional<Rib::Definition> res
+ = get (unwrap_type_segment (segments.back ()).as_string ());
+
+ if (!res)
+ res = get_lang_prelude (
+ unwrap_type_segment (segments.back ()).as_string ());
+
+ if (res && !res->is_ambiguous ())
+ insert_segment_resolution (segments.back (), res->get_node_id ());
+ cleanup_current ();
+ return res;
+ }
std::reference_wrapper<Node> starting_point = cursor ();
- return find_starting_point (segments, starting_point)
- .and_then ([this, &segments, &starting_point] (
- typename std::vector<S>::const_iterator iterator) {
- return resolve_segments (starting_point.get (), segments, iterator);
- })
- .and_then ([&segments] (Node final_node) {
- return final_node.rib.get (segments.back ().as_string ());
- });
+ auto res
+ = find_starting_point (segments, starting_point, insert_segment_resolution,
+ collect_errors)
+ .and_then (
+ [this, &segments, &starting_point, &insert_segment_resolution,
+ &collect_errors] (typename std::vector<S>::const_iterator iterator) {
+ return resolve_segments (starting_point.get (), segments, iterator,
+ insert_segment_resolution, collect_errors);
+ })
+ .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;
+
+ auto &seg = unwrap_type_segment (segments.back ());
+ std::string seg_name = seg.as_string ();
+
+ // assuming this can't be a lang item segment
+ tl::optional<Rib::Definition> res
+ = resolve_final_segment (final_node, seg_name,
+ seg.is_lower_self_seg ());
+ // Ok we didn't find it in the rib, Lets try the prelude...
+ if (!res)
+ res = get_lang_prelude (seg_name);
+
+ if (res && !res->is_ambiguous ())
+ insert_segment_resolution (segments.back (), res->get_node_id ());
+
+ return res;
+ });
+ cleanup_current ();
+ return res;
}
template <Namespace N>
@@ -595,7 +797,7 @@ ForeverStack<N>::to_canonical_path (NodeId id) const
auto &link = kv.first;
auto &child = kv.second;
- if (link.id == child.id)
+ if (current.id == child.id)
{
outer_link = &link;
break;
@@ -613,7 +815,12 @@ ForeverStack<N>::to_canonical_path (NodeId id) const
return KeepGoing::Yes;
});
- auto path = Resolver::CanonicalPath::create_empty ();
+ auto &mappings = Analysis::Mappings::get ();
+ CrateNum crate_num = mappings.lookup_crate_num (root.id).value ();
+ auto path = Resolver::CanonicalPath::new_seg (
+ root.id, mappings.get_crate_name (crate_num).value ());
+ path.set_crate_num (crate_num);
+
for (const auto &segment : segments)
path = path.append (segment);
@@ -638,9 +845,8 @@ tl::optional<const Rib &>
ForeverStack<N>::dfs_rib (const ForeverStack<N>::Node &starting_point,
NodeId to_find) const
{
- return dfs_node (starting_point, to_find).map ([] (Node &x) -> Rib & {
- return x.rib;
- });
+ return dfs_node (starting_point, to_find)
+ .map ([] (const Node &x) -> const Rib & { return x.rib; });
}
template <Namespace N>
@@ -699,15 +905,19 @@ template <Namespace N>
void
ForeverStack<N>::stream_rib (std::stringstream &stream, const Rib &rib,
const std::string &next,
- const std::string &next_next)
+ const std::string &next_next) const
{
+ std::string rib_kind = Rib::kind_to_string (rib.kind);
+ stream << next << "rib [" << rib_kind << "]: {";
if (rib.get_values ().empty ())
{
- stream << next << "rib: {},\n";
+ stream << "}\n";
return;
}
-
- stream << next << "rib: {\n";
+ else
+ {
+ stream << "\n";
+ }
for (const auto &kv : rib.get_values ())
stream << next_next << kv.first << ": " << kv.second.to_string () << "\n";
@@ -718,7 +928,7 @@ ForeverStack<N>::stream_rib (std::stringstream &stream, const Rib &rib,
template <Namespace N>
void
ForeverStack<N>::stream_node (std::stringstream &stream, unsigned indentation,
- const ForeverStack<N>::Node &node)
+ const ForeverStack<N>::Node &node) const
{
auto indent = std::string (indentation, ' ');
auto next = std::string (indentation + 4, ' ');
@@ -750,7 +960,7 @@ ForeverStack<N>::stream_node (std::stringstream &stream, unsigned indentation,
template <Namespace N>
std::string
-ForeverStack<N>::as_debug_string ()
+ForeverStack<N>::as_debug_string () const
{
std::stringstream stream;
diff --git a/gcc/rust/resolve/rust-ice-finalizer.cc b/gcc/rust/resolve/rust-ice-finalizer.cc
new file mode 100644
index 0000000..bd4763f
--- /dev/null
+++ b/gcc/rust/resolve/rust-ice-finalizer.cc
@@ -0,0 +1,36 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ice-finalizer.h"
+
+namespace Rust {
+namespace Resolver {
+
+void ATTRIBUTE_NORETURN
+funny_ice_text_finalizer (diagnostic_text_output_format &text_output,
+ const diagnostic_info *diagnostic,
+ diagnostic_t diag_kind)
+{
+ gcc_assert (diag_kind == DK_ICE_NOBT);
+ default_diagnostic_text_finalizer (text_output, diagnostic, diag_kind);
+ fnotice (stderr, "You have broken GCC Rust. This is a feature.\n");
+ exit (ICE_EXIT_CODE);
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ice-finalizer.h b/gcc/rust/resolve/rust-ice-finalizer.h
new file mode 100644
index 0000000..85ab88f
--- /dev/null
+++ b/gcc/rust/resolve/rust-ice-finalizer.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_ICE_FINALIZER_H
+#define RUST_ICE_FINALIZER_H
+
+#include "rust-linemap.h"
+#include "diagnostic.h"
+
+namespace Rust {
+namespace Resolver {
+
+/* The "break rust" Easter egg.
+
+ Backstory: once upon a time, there used to be a bug in rustc: it would ICE
+ during typechecking on a 'break' with an expression outside of a loop. The
+ issue has been reported [0] and fixed [1], but in recognition of this, as a
+ special Easter egg, "break rust" was made to intentionally cause an ICE.
+
+ [0]: https://github.com/rust-lang/rust/issues/43162
+ [1]: https://github.com/rust-lang/rust/pull/43745
+
+ This was made in a way that does not break valid programs: namely, it only
+ happens when the 'break' is outside of a loop (so invalid anyway).
+
+ GCC Rust supports this essential feature as well, but in a slightly
+ different way. Instead of delaying the error until type checking, we emit
+ it here in the resolution phase. We, too, only do this to programs that
+ are already invalid: we only emit our funny ICE if the name "rust" (which
+ must be immediately inside a break-with-a-value expression) fails to
+ resolve. Note that "break (rust)" does not trigger our ICE, only using
+ "break rust" directly does, and only if there's no "rust" in scope. We do
+ this in the same way regardless of whether the "break" is outside of a loop
+ or inside one.
+
+ As a GNU extension, we also support "break gcc", much to the same effect,
+ subject to the same rules. */
+
+/* The finalizer for our funny ICE. This prints a custom message instead of
+ the default bug reporting instructions, as there is no bug to report. */
+
+void ATTRIBUTE_NORETURN
+funny_ice_text_finalizer (diagnostic_text_output_format &text_output,
+ const diagnostic_info *diagnostic,
+ diagnostic_t diag_kind);
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif /* ! RUST_ICE_FINALIZER_H */
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 5aea6a4..6ec0422 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
@@ -27,6 +27,8 @@
#include "rust-system.h"
#include "rust-tyty.h"
#include "rust-hir-type-check.h"
+#include "rust-ice-finalizer.h"
+#include "rust-ast.h"
namespace Rust {
namespace Resolver2_0 {
@@ -89,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);
+ // 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);
- }
+ 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 ();
@@ -125,6 +129,54 @@ Late::new_label (Identifier name, NodeId id)
}
void
+Late::visit (AST::ForLoopExpr &expr)
+{
+ visit_outer_attrs (expr);
+
+ ctx.bindings.enter (BindingSource::For);
+
+ visit (expr.get_pattern ());
+
+ ctx.bindings.exit ();
+
+ visit (expr.get_iterator_expr ());
+ visit (expr.get_loop_label ());
+ visit (expr.get_loop_block ());
+}
+
+void
+Late::visit (AST::IfLetExpr &expr)
+{
+ visit_outer_attrs (expr);
+
+ ctx.bindings.enter (BindingSource::Let);
+
+ for (auto &pattern : expr.get_patterns ())
+ visit (pattern);
+
+ ctx.bindings.exit ();
+
+ visit (expr.get_value_expr ());
+ visit (expr.get_if_block ());
+}
+
+void
+Late::visit (AST::MatchArm &arm)
+{
+ visit_outer_attrs (arm);
+
+ ctx.bindings.enter (BindingSource::Match);
+
+ for (auto &pattern : arm.get_patterns ())
+ visit (pattern);
+
+ ctx.bindings.exit ();
+
+ if (arm.has_match_arm_guard ())
+ visit (arm.get_guard_expr ());
+}
+
+void
Late::visit (AST::LetStmt &let)
{
DefaultASTVisitor::visit_outer_attrs (let);
@@ -134,8 +186,16 @@ Late::visit (AST::LetStmt &let)
// this makes variable shadowing work properly
if (let.has_init_expr ())
visit (let.get_init_expr ());
+
+ ctx.bindings.enter (BindingSource::Let);
+
visit (let.get_pattern ());
+ ctx.bindings.exit ();
+
+ if (let.has_else_expr ())
+ visit (let.get_init_expr ());
+
// how do we deal with the fact that `let a = blipbloup` should look for a
// label and cannot go through function ribs, but `let a = blipbloup()` can?
@@ -160,9 +220,68 @@ Late::visit (AST::IdentifierPattern &identifier)
// but values does not allow shadowing... since functions cannot shadow
// do we insert functions in labels as well?
+ if (ctx.bindings.peek ().is_and_bound (identifier.get_ident ()))
+ {
+ if (ctx.bindings.peek ().get_source () == BindingSource::Param)
+ rust_error_at (
+ identifier.get_locus (), ErrorCode::E0415,
+ "identifier %qs is bound more than once in the same parameter list",
+ identifier.as_string ().c_str ());
+ else
+ rust_error_at (
+ identifier.get_locus (), ErrorCode::E0416,
+ "identifier %qs is bound more than once in the same pattern",
+ identifier.as_string ().c_str ());
+ return;
+ }
+
+ ctx.bindings.peek ().insert_ident (identifier.get_ident ());
+
+ if (ctx.bindings.peek ().is_or_bound (identifier.get_ident ()))
+ {
+ // FIXME: map usage instead
+ std::ignore = ctx.values.insert_shadowable (identifier.get_ident (),
+ identifier.get_node_id ());
+ }
+ else
+ {
+ // We do want to ignore duplicated data because some situations rely on
+ // it.
+ std::ignore = ctx.values.insert_shadowable (identifier.get_ident (),
+ identifier.get_node_id ());
+ }
+}
+
+void
+Late::visit (AST::AltPattern &pattern)
+{
+ ctx.bindings.peek ().push (Binding::Kind::Or);
+ for (auto &alt : pattern.get_alts ())
+ {
+ ctx.bindings.peek ().push (Binding::Kind::Product);
+ visit (alt);
+ ctx.bindings.peek ().merge ();
+ }
+ ctx.bindings.peek ().merge ();
+}
+
+void
+Late::visit_function_params (AST::Function &function)
+{
+ ctx.bindings.enter (BindingSource::Param);
+
+ for (auto &param : function.get_function_params ())
+ visit (param);
+
+ ctx.bindings.exit ();
+}
+
+void
+Late::visit (AST::StructPatternFieldIdent &field)
+{
// We do want to ignore duplicated data because some situations rely on it.
- std::ignore = ctx.values.insert_shadowable (identifier.get_ident (),
- identifier.get_node_id ());
+ std::ignore = ctx.values.insert_shadowable (field.get_identifier (),
+ field.get_node_id ());
}
void
@@ -178,12 +297,74 @@ Late::visit (AST::SelfParam &param)
}
void
+Late::visit (AST::BreakExpr &expr)
+{
+ if (expr.has_label ())
+ resolve_label (expr.get_label_unchecked ().get_lifetime ());
+
+ if (expr.has_break_expr ())
+ {
+ auto &break_expr = expr.get_break_expr ();
+ if (break_expr.get_expr_kind () == AST::Expr::Kind::Identifier)
+ {
+ /* This is a break with an expression, and the expression is
+ just a single identifier. See if the identifier is either
+ "rust" or "gcc", in which case we have "break rust" or "break
+ gcc", and so may need to emit our funny error. We cannot yet
+ emit the error here though, because the identifier may still
+ be in scope, and ICE'ing on valid programs would not be very
+ funny. */
+ std::string ident
+ = static_cast<AST::IdentifierExpr &> (expr.get_break_expr ())
+ .as_string ();
+ if (ident == "rust" || ident == "gcc")
+ funny_error = true;
+ }
+ }
+
+ DefaultResolver::visit (expr);
+
+ funny_error = false;
+}
+
+void
+Late::visit (AST::LoopLabel &label)
+{
+ auto &lifetime = label.get_lifetime ();
+ ctx.labels.insert (Identifier (lifetime.as_string (), lifetime.get_locus ()),
+ lifetime.get_node_id ());
+}
+
+void
+Late::resolve_label (AST::Lifetime &lifetime)
+{
+ if (auto resolved = ctx.labels.get (lifetime.as_string ()))
+ {
+ if (resolved->get_node_id () != lifetime.get_node_id ())
+ ctx.map_usage (Usage (lifetime.get_node_id ()),
+ Definition (resolved->get_node_id ()));
+ }
+ else
+ rust_error_at (lifetime.get_locus (), ErrorCode::E0426,
+ "use of undeclared label %qs",
+ lifetime.as_string ().c_str ());
+}
+
+void
+Late::visit (AST::ContinueExpr &expr)
+{
+ if (expr.has_label ())
+ resolve_label (expr.get_label_unchecked ());
+
+ DefaultResolver::visit (expr);
+}
+
+void
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;
@@ -192,42 +373,95 @@ Late::visit (AST::IdentifierExpr &expr)
{
resolved = type;
}
+ else if (funny_error)
+ {
+ diagnostic_text_finalizer (global_dc) = Resolver::funny_ice_text_finalizer;
+ emit_diagnostic (DK_ICE_NOBT, expr.get_locus (), -1,
+ "are you trying to break %s? how dare you?",
+ expr.as_string ().c_str ());
+ }
else
{
- rust_error_at (expr.get_locus (),
- "could not resolve identifier expression: %qs",
- expr.get_ident ().as_string ().c_str ());
+ if (auto type = ctx.types.get_lang_prelude (expr.get_ident ()))
+ {
+ resolved = type;
+ }
+ else
+ {
+ rust_error_at (expr.get_locus (), ErrorCode::E0425,
+ "cannot find value %qs in this scope",
+ expr.get_ident ().as_string ().c_str ());
+ return;
+ }
+ }
+
+ if (resolved->is_ambiguous ())
+ {
+ rust_error_at (expr.get_locus (), ErrorCode::E0659, "%qs is ambiguous",
+ expr.as_string ().c_str ());
return;
}
ctx.map_usage (Usage (expr.get_node_id ()),
Definition (resolved->get_node_id ()));
- // in the old resolver, resolutions are kept in the resolver, not the mappings
- // :/ how do we deal with that?
- // ctx.mappings.insert_resolved_name(expr, resolved);
-
// For empty types, do we perform a lookup in ctx.types or should the
// toplevel instead insert a name in ctx.values? (like it currently does)
}
void
+Late::visit (AST::StructExprFieldIdentifier &expr)
+{
+ tl::optional<Rib::Definition> resolved = tl::nullopt;
+
+ if (auto value = ctx.values.get (expr.get_field_name ()))
+ {
+ resolved = value;
+ }
+ // seems like we don't need a type namespace lookup
+ else
+ {
+ rust_error_at (expr.get_locus (), "could not resolve struct field: %qs",
+ expr.get_field_name ().as_string ().c_str ());
+ return;
+ }
+
+ if (resolved->is_ambiguous ())
+ {
+ rust_error_at (expr.get_locus (), ErrorCode::E0659, "%qs is ambiguous",
+ expr.as_string ().c_str ());
+ return;
+ }
+
+ ctx.map_usage (Usage (expr.get_node_id ()),
+ Definition (resolved->get_node_id ()));
+}
+
+void
Late::visit (AST::PathInExpression &expr)
{
// TODO: How do we have a nice error with `can't capture dynamic environment
// in a function item` error here?
// do we emit it in `get<Namespace::Labels>`?
- auto resolved
- = ctx.values.resolve_path (expr.get_segments ()).or_else ([&] () {
- return ctx.types.resolve_path (expr.get_segments ());
- });
+ DefaultResolver::visit (expr);
+
+ if (expr.is_lang_item ())
+ {
+ ctx.map_usage (Usage (expr.get_node_id ()),
+ Definition (Analysis::Mappings::get ().get_lang_item_node (
+ expr.get_lang_item ())));
+ return;
+ }
+
+ auto resolved = ctx.resolve_path (expr, Namespace::Values, Namespace::Types);
if (!resolved)
{
- rust_error_at (expr.get_locus (),
- "could not resolve path expression: %qs",
- expr.as_simple_path ().as_string ().c_str ());
+ if (!ctx.lookup (expr.get_segments ().front ().get_node_id ()))
+ rust_error_at (expr.get_locus (), ErrorCode::E0433,
+ "Cannot find path %qs in this scope",
+ expr.as_simple_path ().as_string ().c_str ());
return;
}
@@ -250,17 +484,37 @@ Late::visit (AST::TypePath &type)
// maybe we can overload `resolve_path<Namespace::Types>` to only do
// typepath-like path resolution? that sounds good
- auto str = type.get_segments ().back ()->get_ident_segment ().as_string ();
- auto values = ctx.types.peek ().get_values ();
+ DefaultResolver::visit (type);
- if (auto resolved = ctx.types.get (str))
- ctx.map_usage (Usage (type.get_node_id ()),
- Definition (resolved->get_node_id ()));
- else
- rust_error_at (type.get_locus (), "could not resolve type path %qs",
- str.c_str ());
+ // this *should* mostly work
+ // TODO: make sure typepath-like path resolution (?) is working
+ auto resolved = ctx.resolve_path (type, Namespace::Types);
- DefaultResolver::visit (type);
+ if (!resolved.has_value ())
+ {
+ if (!ctx.lookup (type.get_segments ().front ()->get_node_id ()))
+ rust_error_at (type.get_locus (), "could not resolve type path %qs",
+ type.as_string ().c_str ());
+ return;
+ }
+
+ if (resolved->is_ambiguous ())
+ {
+ rust_error_at (type.get_locus (), ErrorCode::E0659, "%qs is ambiguous",
+ type.as_string ().c_str ());
+ return;
+ }
+
+ if (ctx.types.forward_declared (resolved->get_node_id (),
+ type.get_node_id ()))
+ {
+ rust_error_at (type.get_locus (), ErrorCode::E0128,
+ "type parameters with a default cannot use forward "
+ "declared identifiers");
+ }
+
+ ctx.map_usage (Usage (type.get_node_id ()),
+ Definition (resolved->get_node_id ()));
}
void
@@ -286,7 +540,11 @@ Late::visit (AST::StructStruct &s)
void
Late::visit (AST::StructExprStruct &s)
{
- auto resolved = ctx.types.resolve_path (s.get_struct_name ().get_segments ());
+ visit_outer_attrs (s);
+ visit_inner_attrs (s);
+ DefaultResolver::visit (s.get_struct_name ());
+
+ auto resolved = ctx.resolve_path (s.get_struct_name (), Namespace::Types);
ctx.map_usage (Usage (s.get_struct_name ().get_node_id ()),
Definition (resolved->get_node_id ()));
@@ -295,22 +553,32 @@ Late::visit (AST::StructExprStruct &s)
void
Late::visit (AST::StructExprStructBase &s)
{
- auto resolved = ctx.types.resolve_path (s.get_struct_name ().get_segments ());
+ visit_outer_attrs (s);
+ visit_inner_attrs (s);
+ DefaultResolver::visit (s.get_struct_name ());
+ visit (s.get_struct_base ());
+
+ auto resolved = ctx.resolve_path (s.get_struct_name (), Namespace::Types);
ctx.map_usage (Usage (s.get_struct_name ().get_node_id ()),
Definition (resolved->get_node_id ()));
- DefaultResolver::visit (s);
}
void
Late::visit (AST::StructExprStructFields &s)
{
- auto resolved = ctx.types.resolve_path (s.get_struct_name ().get_segments ());
+ visit_outer_attrs (s);
+ visit_inner_attrs (s);
+ DefaultResolver::visit (s.get_struct_name ());
+ if (s.has_struct_base ())
+ visit (s.get_struct_base ());
+ for (auto &field : s.get_fields ())
+ visit (field);
+
+ auto resolved = ctx.resolve_path (s.get_struct_name (), Namespace::Types);
ctx.map_usage (Usage (s.get_struct_name ().get_node_id ()),
Definition (resolved->get_node_id ()));
-
- DefaultResolver::visit (s);
}
// needed because Late::visit (AST::GenericArg &) is non-virtual
@@ -345,5 +613,52 @@ Late::visit (AST::GenericArg &arg)
DefaultResolver::visit (arg);
}
+template <class Closure>
+static void
+add_captures (Closure &closure, NameResolutionContext &ctx)
+{
+ auto vals = ctx.values.peek ().get_values ();
+ for (auto &val : vals)
+ {
+ ctx.mappings.add_capture (closure.get_node_id (),
+ val.second.get_node_id ());
+ }
+}
+
+void
+Late::visit (AST::ClosureExprInner &closure)
+{
+ add_captures (closure, ctx);
+
+ visit_outer_attrs (closure);
+
+ ctx.bindings.enter (BindingSource::Param);
+
+ for (auto &param : closure.get_params ())
+ visit (param);
+
+ ctx.bindings.exit ();
+
+ visit (closure.get_definition_expr ());
+}
+
+void
+Late::visit (AST::ClosureExprInnerTyped &closure)
+{
+ add_captures (closure, ctx);
+
+ visit_outer_attrs (closure);
+
+ ctx.bindings.enter (BindingSource::Param);
+
+ for (auto &param : closure.get_params ())
+ visit (param);
+
+ ctx.bindings.exit ();
+
+ visit (closure.get_return_type ());
+ visit (closure.get_definition_block ());
+}
+
} // namespace Resolver2_0
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h b/gcc/rust/resolve/rust-late-name-resolver-2.0.h
index ade78c5..171d9bf 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h
@@ -21,6 +21,7 @@
#include "rust-ast-full.h"
#include "rust-default-resolver.h"
+#include "rust-expr.h"
namespace Rust {
namespace Resolver2_0 {
@@ -36,15 +37,27 @@ public:
void new_label (Identifier name, NodeId id);
+ // Specialized visit bits
+ void visit_function_params (AST::Function &function) override;
+
// some more label declarations
void visit (AST::LetStmt &) override;
// TODO: Do we need this?
// void visit (AST::Method &) override;
void visit (AST::IdentifierPattern &) override;
+ void visit (AST::StructPatternFieldIdent &) override;
+ void visit (AST::AltPattern &) override;
void visit (AST::SelfParam &) override;
+ void visit (AST::MatchArm &) override;
+ void visit (AST::ForLoopExpr &) override;
+ void visit (AST::IfLetExpr &) override;
// resolutions
void visit (AST::IdentifierExpr &) override;
+ void visit (AST::StructExprFieldIdentifier &) override;
+ void visit (AST::BreakExpr &) override;
+ void visit (AST::ContinueExpr &) override;
+ void visit (AST::LoopLabel &) override;
void visit (AST::PathInExpression &) override;
void visit (AST::TypePath &) override;
void visit (AST::Trait &) override;
@@ -54,10 +67,16 @@ public:
void visit (AST::StructStruct &) override;
void visit (AST::GenericArgs &) override;
void visit (AST::GenericArg &);
+ void visit (AST::ClosureExprInner &) override;
+ void visit (AST::ClosureExprInnerTyped &) override;
private:
+ void resolve_label (AST::Lifetime &lifetime);
+
/* Setup Rust's builtin types (u8, i32, !...) in the resolver */
void setup_builtin_types ();
+
+ bool funny_error;
};
// TODO: Add missing mappings and data structures
diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc
index 1b37521..f098e48 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.cc
+++ b/gcc/rust/resolve/rust-name-resolution-context.cc
@@ -23,6 +23,65 @@
namespace Rust {
namespace Resolver2_0 {
+BindingLayer::BindingLayer (BindingSource source) : source (source)
+{
+ push (Binding::Kind::Product);
+}
+
+bool
+BindingLayer::bind_test (Identifier ident, Binding::Kind kind)
+{
+ for (auto &bind : bindings)
+ {
+ if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+BindingLayer::push (Binding::Kind kind)
+{
+ bindings.push_back (Binding (kind));
+}
+
+bool
+BindingLayer::is_and_bound (Identifier ident)
+{
+ return bind_test (ident, Binding::Kind::Product);
+}
+
+bool
+BindingLayer::is_or_bound (Identifier ident)
+{
+ return bind_test (ident, Binding::Kind::Or);
+}
+
+void
+BindingLayer::insert_ident (Identifier ident)
+{
+ bindings.back ().set.insert (ident);
+}
+
+void
+BindingLayer::merge ()
+{
+ auto last_binding = bindings.back ();
+ bindings.pop_back ();
+ for (auto &value : last_binding.set)
+ {
+ bindings.back ().set.insert (value);
+ }
+}
+
+BindingSource
+BindingLayer::get_source () const
+{
+ return source;
+}
+
NameResolutionContext::NameResolutionContext ()
: mappings (Analysis::Mappings::get ())
{}
@@ -46,6 +105,12 @@ NameResolutionContext::insert (Identifier name, NodeId id, Namespace ns)
}
tl::expected<NodeId, DuplicateNameError>
+NameResolutionContext::insert_variant (Identifier name, NodeId id)
+{
+ return types.insert_variant (name, id);
+}
+
+tl::expected<NodeId, DuplicateNameError>
NameResolutionContext::insert_shadowable (Identifier name, NodeId id,
Namespace ns)
{
@@ -107,6 +172,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);
@@ -126,6 +192,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-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h
index 183ce7f..19ba750 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.h
+++ b/gcc/rust/resolve/rust-name-resolution-context.h
@@ -23,6 +23,7 @@
#include "rust-forever-stack.h"
#include "rust-hir-map.h"
#include "rust-rib.h"
+#include "rust-stacked-contexts.h"
namespace Rust {
namespace Resolver2_0 {
@@ -156,6 +157,62 @@ public:
NodeId id;
};
+struct Binding
+{
+ enum class Kind
+ {
+ Product,
+ Or,
+ } kind;
+
+ std::unordered_set<Identifier> set;
+
+ Binding (Binding::Kind kind) : kind (kind) {}
+};
+
+/**
+ * Used to identify the source of a binding, and emit the correct error message.
+ */
+enum class BindingSource
+{
+ Match,
+ Let,
+ For,
+ /* Closure param or function param */
+ Param
+};
+
+class BindingLayer
+{
+ BindingSource source;
+ std::vector<Binding> bindings;
+
+ bool bind_test (Identifier ident, Binding::Kind kind);
+
+public:
+ void push (Binding::Kind kind);
+
+ BindingLayer (BindingSource source);
+
+ /**
+ * Identifies if the identifier has been used in a product binding context.
+ * eg. `let (a, a) = test();`
+ */
+ bool is_and_bound (Identifier ident);
+
+ /**
+ * Identifies if the identifier has been used in a or context.
+ * eg. `let (a, 1) | (a, 2) = test()`
+ */
+ bool is_or_bound (Identifier ident);
+
+ void insert_ident (Identifier ident);
+
+ void merge ();
+
+ BindingSource get_source () const;
+};
+
// Now our resolver, which keeps track of all the `ForeverStack`s we could want
class NameResolutionContext
{
@@ -172,6 +229,9 @@ public:
tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id,
Namespace ns);
+ tl::expected<NodeId, DuplicateNameError> insert_variant (Identifier name,
+ NodeId id);
+
tl::expected<NodeId, DuplicateNameError>
insert_shadowable (Identifier name, NodeId id, Namespace ns);
@@ -209,6 +269,7 @@ public:
ForeverStack<Namespace::Labels> labels;
Analysis::Mappings &mappings;
+ StackedContexts<BindingLayer> bindings;
// TODO: Rename
// TODO: Use newtype pattern for Usage and Definition
@@ -216,6 +277,120 @@ public:
tl::optional<NodeId> lookup (NodeId usage) const;
+ template <typename S>
+ tl::optional<Rib::Definition>
+ resolve_path (const std::vector<S> &segments,
+ bool has_opening_scope_resolution,
+ std::vector<Error> &collect_errors, Namespace ns)
+ {
+ std::function<void (const S &, NodeId)> insert_segment_resolution
+ = [this] (const S &seg, NodeId id) {
+ auto seg_id = unwrap_segment_node_id (seg);
+ if (resolved_nodes.find (Usage (seg_id)) == resolved_nodes.end ())
+ map_usage (Usage (seg_id), Definition (id));
+ };
+ switch (ns)
+ {
+ case Namespace::Values:
+ return values.resolve_path (segments, has_opening_scope_resolution,
+ insert_segment_resolution, collect_errors);
+ case Namespace::Types:
+ return types.resolve_path (segments, has_opening_scope_resolution,
+ insert_segment_resolution, collect_errors);
+ case Namespace::Macros:
+ return macros.resolve_path (segments, has_opening_scope_resolution,
+ insert_segment_resolution, collect_errors);
+ case Namespace::Labels:
+ return labels.resolve_path (segments, has_opening_scope_resolution,
+ insert_segment_resolution, collect_errors);
+ default:
+ rust_unreachable ();
+ }
+ }
+
+ template <typename S, typename... Args>
+ tl::optional<Rib::Definition>
+ resolve_path (const std::vector<S> &segments,
+ bool has_opening_scope_resolution,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
+ {
+ std::initializer_list<Namespace> namespaces = {ns_first, ns_args...};
+
+ for (auto ns : namespaces)
+ {
+ std::vector<Error> collect_errors_inner;
+ if (auto ret = resolve_path (segments, has_opening_scope_resolution,
+ collect_errors_inner, ns))
+ return ret;
+ if (!collect_errors_inner.empty ())
+ {
+ if (collect_errors.has_value ())
+ {
+ std::move (collect_errors_inner.begin (),
+ collect_errors_inner.end (),
+ std::back_inserter (collect_errors.value ()));
+ }
+ else
+ {
+ for (auto &e : collect_errors_inner)
+ e.emit ();
+ }
+ return tl::nullopt;
+ }
+ }
+
+ return tl::nullopt;
+ }
+
+ template <typename... Args>
+ tl::optional<Rib::Definition>
+ resolve_path (const AST::SimplePath &path,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
+ {
+ return resolve_path (path.get_segments (),
+ path.has_opening_scope_resolution (), collect_errors,
+ ns_first, ns_args...);
+ }
+
+ template <typename... Args>
+ tl::optional<Rib::Definition>
+ resolve_path (const AST::PathInExpression &path,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
+ {
+ return resolve_path (path.get_segments (), path.opening_scope_resolution (),
+ collect_errors, ns_first, ns_args...);
+ }
+
+ template <typename... Args>
+ tl::optional<Rib::Definition>
+ resolve_path (const AST::TypePath &path,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
+ {
+ return resolve_path (path.get_segments (),
+ path.has_opening_scope_resolution_op (),
+ collect_errors, ns_first, ns_args...);
+ }
+
+ template <typename P, typename... Args>
+ tl::optional<Rib::Definition> resolve_path (const P &path, Namespace ns_first,
+ Args... ns_args)
+ {
+ return resolve_path (path, tl::nullopt, ns_first, ns_args...);
+ }
+
+ template <typename P, typename... Args>
+ tl::optional<Rib::Definition>
+ resolve_path (const P &path_segments, bool has_opening_scope_resolution,
+ Namespace ns_first, Args... ns_args)
+ {
+ return resolve_path (path_segments, has_opening_scope_resolution,
+ tl::nullopt, ns_first, ns_args...);
+ }
+
private:
/* Map of "usage" nodes which have been resolved to a "definition" node */
std::map<Usage, Definition> resolved_nodes;
diff --git a/gcc/rust/resolve/rust-name-resolver.cc b/gcc/rust/resolve/rust-name-resolver.cc
index 0f5b108..dddaa07 100644
--- a/gcc/rust/resolve/rust-name-resolver.cc
+++ b/gcc/rust/resolve/rust-name-resolver.cc
@@ -472,6 +472,8 @@ void
Resolver::insert_resolved_name (NodeId refId, NodeId defId)
{
rust_assert (!flag_name_resolution_2_0);
+ rust_assert (resolved_names.find (refId) == resolved_names.end ());
+
resolved_names[refId] = defId;
get_name_scope ().append_reference_for_def (refId, defId);
insert_captured_item (defId);
@@ -492,9 +494,8 @@ Resolver::lookup_resolved_name (NodeId refId, NodeId *defId)
void
Resolver::insert_resolved_type (NodeId refId, NodeId defId)
{
- // auto it = resolved_types.find (refId);
- // rust_assert (it == resolved_types.end ());
rust_assert (!flag_name_resolution_2_0);
+ rust_assert (resolved_types.find (refId) == resolved_types.end ());
resolved_types[refId] = defId;
get_type_scope ().append_reference_for_def (refId, defId);
@@ -674,6 +675,8 @@ Resolver::decl_needs_capture (NodeId decl_rib_node_id,
const std::set<NodeId> &
Resolver::get_captures (NodeId id) const
{
+ rust_assert (!flag_name_resolution_2_0);
+
auto it = closures_capture_mappings.find (id);
rust_assert (it != closures_capture_mappings.end ());
return it->second;
diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h
index 43b79e5..a3b34a9 100644
--- a/gcc/rust/resolve/rust-name-resolver.h
+++ b/gcc/rust/resolve/rust-name-resolver.h
@@ -204,6 +204,41 @@ public:
void insert_captured_item (NodeId id);
const std::set<NodeId> &get_captures (NodeId id) const;
+ std::string as_debug_string () const
+ {
+ std::stringstream ss;
+
+ ss << "Names:\n";
+ for (auto &n : name_ribs)
+ {
+ ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str ()
+ << "\n";
+ }
+ ss << "Types:\n";
+ for (auto &n : type_ribs)
+ {
+ ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str ()
+ << "\n";
+ }
+ ss << "Macros:\n";
+
+ for (auto &n : macro_ribs)
+ {
+ ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str ()
+ << "\n";
+ }
+
+ ss << "Labels:\n";
+
+ for (auto &n : label_ribs)
+ {
+ ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str ()
+ << "\n";
+ }
+
+ return ss.str ();
+ }
+
protected:
bool decl_needs_capture (NodeId decl_rib_node_id, NodeId closure_rib_node_id,
const Scope &scope);
diff --git a/gcc/rust/resolve/rust-rib.cc b/gcc/rust/resolve/rust-rib.cc
index b0380bb..690bde9 100644
--- a/gcc/rust/resolve/rust-rib.cc
+++ b/gcc/rust/resolve/rust-rib.cc
@@ -22,7 +22,8 @@
namespace Rust {
namespace Resolver2_0 {
-Rib::Definition::Definition (NodeId id, Mode mode)
+Rib::Definition::Definition (NodeId id, Mode mode, bool enum_variant)
+ : enum_variant (enum_variant)
{
switch (mode)
{
@@ -51,6 +52,12 @@ Rib::Definition::is_ambiguous () const
return ids_globbed.size () > 1;
}
+bool
+Rib::Definition::is_variant () const
+{
+ return enum_variant;
+}
+
std::string
Rib::Definition::to_string () const
{
@@ -69,25 +76,27 @@ Rib::Definition::to_string () const
}
}
out << "]";
+ if (enum_variant)
+ out << "(enum variant)";
return out.str ();
}
Rib::Definition
Rib::Definition::Shadowable (NodeId id)
{
- return Definition (id, Mode::SHADOWABLE);
+ return Definition (id, Mode::SHADOWABLE, false);
}
Rib::Definition
-Rib::Definition::NonShadowable (NodeId id)
+Rib::Definition::NonShadowable (NodeId id, bool enum_variant)
{
- return Definition (id, Mode::NON_SHADOWABLE);
+ return Definition (id, Mode::NON_SHADOWABLE, enum_variant);
}
Rib::Definition
Rib::Definition::Globbed (NodeId id)
{
- return Definition (id, Mode::GLOBBED);
+ return Definition (id, Mode::GLOBBED, false);
}
DuplicateNameError::DuplicateNameError (std::string name, NodeId existing)
diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h
index 2eb8de8..c498328 100644
--- a/gcc/rust/resolve/rust-rib.h
+++ b/gcc/rust/resolve/rust-rib.h
@@ -111,7 +111,7 @@ public:
class Definition
{
public:
- static Definition NonShadowable (NodeId id);
+ static Definition NonShadowable (NodeId id, bool enum_variant = false);
static Definition Shadowable (NodeId id);
static Definition Globbed (NodeId id);
@@ -124,11 +124,21 @@ public:
std::vector<NodeId> ids_non_shadowable;
std::vector<NodeId> ids_globbed;
+ // Enum variant should be skipped when dealing with inner definition.
+ // struct E2;
+ //
+ // enum MyEnum<T> /* <-- Should be kept */{
+ // E2 /* <-- Should be skipped */ (E2);
+ // }
+ bool enum_variant;
+
Definition () = default;
Definition &operator= (const Definition &) = default;
Definition (Definition const &) = default;
+ bool is_variant () const;
+
bool is_ambiguous () const;
NodeId get_node_id () const
@@ -155,7 +165,7 @@ public:
GLOBBED
};
- Definition (NodeId id, Mode mode);
+ Definition (NodeId id, Mode mode, bool enum_variant);
};
enum class Kind
@@ -173,8 +183,42 @@ 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)
+ {
+ switch (kind)
+ {
+ case Rib::Kind::Normal:
+ return "Normal";
+ case Rib::Kind::Module:
+ return "Module";
+ case Rib::Kind::Function:
+ return "Function";
+ case Rib::Kind::ConstantItem:
+ return "ConstantItem";
+ case Rib::Kind::TraitOrImpl:
+ return "TraitOrImpl";
+ case Rib::Kind::Item:
+ return "Item";
+ case Rib::Kind::Closure:
+ return "Closure";
+ case Rib::Kind::MacroDefinition:
+ return "Macro definition";
+ case Rib::Kind::ForwardTypeParamBan:
+ return "Forward type param ban";
+ case Rib::Kind::ConstParamType:
+ return "Const Param Type";
+ default:
+ rust_unreachable ();
+ }
+ }
+
Rib (Kind kind);
Rib (Kind kind, std::string identifier, NodeId id);
Rib (Kind kind, std::unordered_map<std::string, NodeId> values);
diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
index 4c6664f..2f036fe 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
@@ -32,21 +32,18 @@ TopLevel::TopLevel (NameResolutionContext &resolver)
template <typename T>
void
-TopLevel::insert_or_error_out (const Identifier &identifier, const T &node,
- Namespace ns)
+TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier,
+ const T &node)
{
- insert_or_error_out (identifier, node.get_locus (), node.get_node_id (), ns);
+ insert_enum_variant_or_error_out (identifier, node.get_locus (),
+ node.get_node_id ());
}
void
-TopLevel::insert_or_error_out (const Identifier &identifier,
- const location_t &locus, const NodeId &node_id,
- Namespace ns)
+TopLevel::check_multiple_insertion_error (
+ tl::expected<NodeId, DuplicateNameError> result, const Identifier &identifier,
+ const location_t &locus, const NodeId node_id)
{
- // keep track of each node's location to provide useful errors
- node_locations.emplace (node_id, locus);
-
- auto result = ctx.insert (identifier, node_id, ns);
if (result)
dirty = true;
else if (result.error ().existing != node_id)
@@ -58,6 +55,37 @@ TopLevel::insert_or_error_out (const Identifier &identifier,
identifier.as_string ().c_str ());
}
}
+void
+TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier,
+ const location_t &locus,
+ const NodeId node_id)
+{
+ // keep track of each node's location to provide useful errors
+ node_locations.emplace (node_id, locus);
+
+ auto result = ctx.insert_variant (identifier, node_id);
+ check_multiple_insertion_error (result, identifier, locus, node_id);
+}
+
+template <typename T>
+void
+TopLevel::insert_or_error_out (const Identifier &identifier, const T &node,
+ Namespace ns)
+{
+ insert_or_error_out (identifier, node.get_locus (), node.get_node_id (), ns);
+}
+
+void
+TopLevel::insert_or_error_out (const Identifier &identifier,
+ const location_t &locus, const NodeId &node_id,
+ Namespace ns)
+{
+ // keep track of each node's location to provide useful errors
+ node_locations.emplace (node_id, locus);
+
+ auto result = ctx.insert (identifier, node_id, ns);
+ check_multiple_insertion_error (result, identifier, locus, node_id);
+}
void
TopLevel::go (AST::Crate &crate)
@@ -85,7 +113,17 @@ TopLevel::visit (AST::Module &module)
// This was copied from the old early resolver method
// 'accumulate_escaped_macros'
if (module.get_kind () == AST::Module::UNLOADED)
- module.load_items ();
+ {
+ module.load_items ();
+
+ // If the module was previously unloaded, then we don't want to visit it
+ // this time around as the CfgStrip hasn't run on its inner items yet.
+ // Skip it for now, mark the visitor as dirty and try again
+
+ dirty = true;
+
+ return;
+ }
DefaultResolver::visit (module);
@@ -97,8 +135,7 @@ TopLevel::visit (AST::Module &module)
void
TopLevel::visit (AST::Trait &trait)
{
- insert_or_error_out (trait.get_identifier ().as_string (), trait,
- Namespace::Types);
+ insert_or_error_out (trait.get_identifier (), trait, Namespace::Types);
DefaultResolver::visit (trait);
}
@@ -110,6 +147,8 @@ TopLevel::visit (AST::InherentImpl &impl)
insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()),
impl.get_type (), Namespace::Types);
+ // We do want to visit with the default visitor instead of default resolver
+ // because we don't want to insert the scope twice.
AST::DefaultASTVisitor::visit (impl);
};
@@ -123,6 +162,8 @@ TopLevel::visit (AST::TraitImpl &impl)
insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()),
impl.get_type (), Namespace::Types);
+ // We do want to visit using the default visitor instead of default resolver
+ // because we don't want to insert the scope twice.
AST::DefaultASTVisitor::visit (impl);
};
@@ -159,7 +200,16 @@ void
TopLevel::visit (AST::ExternCrate &crate)
{
auto &mappings = Analysis::Mappings::get ();
- CrateNum num = *mappings.lookup_crate_name (crate.get_referenced_crate ());
+ auto num_opt = mappings.lookup_crate_name (crate.get_referenced_crate ());
+
+ if (!num_opt)
+ {
+ rust_error_at (crate.get_locus (), "unknown crate %qs",
+ crate.get_referenced_crate ().c_str ());
+ return;
+ }
+
+ CrateNum num = *num_opt;
auto attribute_macros = mappings.lookup_attribute_proc_macros (num);
@@ -323,19 +373,19 @@ TopLevel::visit (AST::TupleStruct &tuple_struct)
void
TopLevel::visit (AST::EnumItem &variant)
{
- insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
+ insert_enum_variant_or_error_out (variant.get_identifier (), variant);
}
void
TopLevel::visit (AST::EnumItemTuple &variant)
{
- insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
+ insert_enum_variant_or_error_out (variant.get_identifier (), variant);
}
void
TopLevel::visit (AST::EnumItemStruct &variant)
{
- insert_or_error_out (variant.get_identifier (), variant, Namespace::Types);
+ insert_enum_variant_or_error_out (variant.get_identifier (), variant);
}
void
@@ -497,6 +547,8 @@ flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths,
{
if (glob.has_path ())
paths.emplace_back (glob.get_path ());
+ else
+ paths.emplace_back (AST::SimplePath ({}, false, glob.get_locus ()));
}
void
diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
index fabcb5b..3ff37ed 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
@@ -108,15 +108,19 @@ public:
{}
};
- std::unordered_map<NodeId, std::vector<ImportKind>> &&
- get_imports_to_resolve ()
+ std::unordered_map<NodeId, std::vector<ImportKind>> &get_imports_to_resolve ()
{
- return std::move (imports_to_resolve);
+ return imports_to_resolve;
}
+ void check_multiple_insertion_error (
+ tl::expected<NodeId, DuplicateNameError> result,
+ const Identifier &identifier, const location_t &locus,
+ const NodeId node_id);
+
/**
- * Insert a new definition or error out if a definition with the same name was
- * already present in the same namespace in the same scope.
+ * Insert a new definition or error out if a definition with the same name
+ * was already present in the same namespace in the same scope.
*
* @param identifier The identifier of the definition to add.
* @param node A reference to the node, so we can get its `NodeId` and
@@ -130,6 +134,14 @@ public:
const location_t &locus, const NodeId &id,
Namespace ns);
+ template <typename T>
+ void insert_enum_variant_or_error_out (const Identifier &identifier,
+ const T &node);
+
+ void insert_enum_variant_or_error_out (const Identifier &identifier,
+ const location_t &locus,
+ const NodeId node_id);
+
private:
// If a new export has been defined whilst visiting the visitor is considered
// dirty