diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 9f91c5b686fd..35169d15e045 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -117,6 +117,7 @@ GRS_OBJS = \ rust/rust-toplevel-name-resolver-2.0.o \ rust/rust-early-name-resolver-2.0.o \ rust/rust-late-name-resolver-2.0.o \ + rust/rust-immutable-name-resolution-context.o \ rust/rust-early-name-resolver.o \ rust/rust-name-resolver.o \ rust/rust-ast-resolve.o \ diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc index 77fcb91520d7..35e78ea7bb69 100644 --- a/gcc/rust/backend/rust-compile-base.cc +++ b/gcc/rust/backend/rust-compile-base.cc @@ -31,6 +31,7 @@ #include "rust-type-util.h" #include "rust-compile-implitem.h" #include "rust-attribute-values.h" +#include "rust-immutable-name-resolution-context.h" #include "fold-const.h" #include "stringpool.h" diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index acfb360c3499..941391d9f51f 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -27,6 +27,7 @@ #include "rust-hir-full.h" #include "rust-mangle.h" #include "rust-tree.h" +#include "rust-immutable-name-resolution-context.h" namespace Rust { namespace Compile { diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index c511cf1074f9..702f87561764 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -2313,11 +2313,23 @@ CompileExpr::generate_closure_function (HIR::ClosureExpr &expr, if (is_block_expr) { auto body_mappings = function_body->get_mappings (); - Resolver::Rib *rib = nullptr; - bool ok - = ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), - &rib); - rust_assert (ok); + if (flag_name_resolution_2_0) + { + auto nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + auto candidate = nr_ctx.values.to_rib (body_mappings.get_nodeid ()); + + rust_assert (candidate.has_value ()); + } + else + { + Resolver::Rib *rib = nullptr; + bool ok + = ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), + &rib); + rust_assert (ok); + } } tree enclosing_scope = NULL_TREE; diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc index 967d154e463b..deea825c3343 100644 --- a/gcc/rust/backend/rust-compile-item.cc +++ b/gcc/rust/backend/rust-compile-item.cc @@ -19,6 +19,7 @@ #include "rust-compile-item.h" #include "rust-compile-implitem.h" #include "rust-compile-extern.h" +#include "rust-immutable-name-resolution-context.h" namespace Rust { namespace Compile { @@ -149,12 +150,32 @@ CompileItem::visit (HIR::Function &function) } } - const Resolver::CanonicalPath *canonical_path = nullptr; - bool ok = ctx->get_mappings ()->lookup_canonical_path ( - function.get_mappings ().get_nodeid (), &canonical_path); - rust_assert (ok); + Resolver::CanonicalPath canonical_path + = Resolver::CanonicalPath::create_empty (); + + if (flag_name_resolution_2_0) + { + // FIXME: What we need to do here is build the CanonicalPath from the name + // resolver 2.0. this isn't super difficult, we just need to get to it + auto nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + auto path = nr_ctx.values.to_canonical_path ( + function.get_mappings ().get_nodeid ()); + + canonical_path = path.value (); + } + else + { + const Resolver::CanonicalPath *path = nullptr; + bool ok = ctx->get_mappings ()->lookup_canonical_path ( + function.get_mappings ().get_nodeid (), &path); + rust_assert (ok); + + canonical_path = *path; + } - const std::string asm_name = ctx->mangle_item (fntype, *canonical_path); + const std::string asm_name = ctx->mangle_item (fntype, canonical_path); // items can be forward compiled which means we may not need to invoke this // code. We might also have already compiled this generic function as well. @@ -181,7 +202,7 @@ CompileItem::visit (HIR::Function &function) function.get_function_params (), function.get_qualifiers (), function.get_visibility (), function.get_outer_attrs (), function.get_locus (), - function.get_definition ().get (), canonical_path, + function.get_definition ().get (), &canonical_path, fntype); reference = address_expression (fndecl, ref_locus); diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc index ab4d5e8b70dc..75a268155eb0 100644 --- a/gcc/rust/resolve/rust-default-resolver.cc +++ b/gcc/rust/resolve/rust-default-resolver.cc @@ -80,6 +80,8 @@ DefaultResolver::visit (AST::Function &function) if (function.has_body ()) function.get_definition ().value ()->accept_vis (*this); + + // TODO: Don't we need to visit the return type here as well? }; ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn); @@ -427,8 +429,18 @@ DefaultResolver::visit (AST::ExternalStaticItem &) {} void -DefaultResolver::visit (AST::ExternalFunctionItem &) -{} +DefaultResolver::visit (AST::ExternalFunctionItem &function) +{ + auto def_fn = [this, &function] () { + for (auto ¶m : function.get_function_params ()) + { + // TODO: So extern function params are not patterns? + param.get_type ()->accept_vis (*this); + } + }; + + ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn); +} void DefaultResolver::visit (AST::MacroMatchRepetition &) diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 867144adf926..d4c01ef0817b 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -100,9 +100,9 @@ ForeverStack::pop () } static tl::expected -insert_inner (Rib &rib, std::string name, NodeId node, bool can_shadow) +insert_inner (Rib &rib, std::string name, Rib::Definition definition) { - return rib.insert (name, node, can_shadow); + return rib.insert (name, definition); } template @@ -115,7 +115,8 @@ ForeverStack::insert (Identifier name, NodeId node) // pass, we might end up in a situation where it is okay to re-add new names. // Do we just ignore that here? Do we keep track of if the Rib is new or not? // should our cursor have info on the current node like "is it newly pushed"? - return insert_inner (innermost_rib, name.as_string (), node, false); + return insert_inner (innermost_rib, name.as_string (), + Rib::Definition::NonShadowable (node)); } template @@ -126,7 +127,8 @@ ForeverStack::insert_at_root (Identifier name, NodeId node) // inserting in the root of the crate is never a shadowing operation, even for // macros - return insert_inner (root_rib, name.as_string (), node, false); + return insert_inner (root_rib, name.as_string (), + Rib::Definition::NonShadowable (node)); } // Specialization for Macros and Labels - where we are allowed to shadow @@ -135,14 +137,16 @@ template <> inline tl::expected ForeverStack::insert (Identifier name, NodeId node) { - return insert_inner (peek (), name.as_string (), node, true); + return insert_inner (peek (), name.as_string (), + Rib::Definition::Shadowable (node)); } template <> inline tl::expected ForeverStack::insert (Identifier name, NodeId node) { - return insert_inner (peek (), name.as_string (), node, true); + return insert_inner (peek (), name.as_string (), + Rib::Definition::Shadowable (node)); } template @@ -455,10 +459,10 @@ template tl::optional::Node &, std::string>> ForeverStack::dfs (ForeverStack::Node &starting_point, NodeId to_find) { - auto &values = starting_point.rib.get_values (); + auto values = starting_point.rib.get_values (); for (auto &kv : values) - if (kv.second == to_find) + if (kv.second.id == to_find) return {{starting_point, kv.first}}; for (auto &child : starting_point.children) @@ -568,7 +572,7 @@ ForeverStack::stream_rib (std::stringstream &stream, const Rib &rib, stream << next << "rib: {\n"; for (const auto &kv : rib.get_values ()) - stream << next_next << kv.first << ": " << kv.second << "\n"; + stream << next_next << kv.first << ": " << kv.second.id << "\n"; stream << next << "},\n"; } diff --git a/gcc/rust/resolve/rust-immutable-name-resolution-context.cc b/gcc/rust/resolve/rust-immutable-name-resolution-context.cc new file mode 100644 index 000000000000..3894e27cd202 --- /dev/null +++ b/gcc/rust/resolve/rust-immutable-name-resolution-context.cc @@ -0,0 +1,56 @@ +// Copyright (C) 2020-2023 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 +// . + +#include "rust-immutable-name-resolution-context.h" + +namespace Rust { +namespace Resolver2_0 { + +static ImmutableNameResolutionContext *instance = nullptr; + +const ImmutableNameResolutionContext & +ImmutableNameResolutionContext::init (const NameResolutionContext &ctx) +{ + rust_assert (!instance); + + instance = new ImmutableNameResolutionContext (ctx); + + return *instance; +} + +const ImmutableNameResolutionContext & +ImmutableNameResolutionContext::get () +{ + rust_assert (instance); + + return *instance; +} + +const NameResolutionContext & +ImmutableNameResolutionContext::resolver () const +{ + return ctx; +} + +ImmutableNameResolutionContext::ImmutableNameResolutionContext ( + const NameResolutionContext &ctx) + : ctx (ctx) +{} + +} // namespace Resolver2_0 +} // namespace Rust diff --git a/gcc/rust/resolve/rust-immutable-name-resolution-context.h b/gcc/rust/resolve/rust-immutable-name-resolution-context.h new file mode 100644 index 000000000000..9f9e7764cd2a --- /dev/null +++ b/gcc/rust/resolve/rust-immutable-name-resolution-context.h @@ -0,0 +1,55 @@ +// Copyright (C) 2020-2023 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 +// . + +#ifndef RUST_IMMUTABLE_NRCTX_H +#define RUST_IMMUTABLE_NRCTX_H + +#include "rust-name-resolution-context.h" + +namespace Rust { +namespace Resolver2_0 { + +/** + * Once the name resolution pass is complete, the typechecker can access it + * + * FIXME: More documentation + */ +class ImmutableNameResolutionContext +{ +public: + /** FIXME: Documentation */ + static const ImmutableNameResolutionContext & + init (const NameResolutionContext &ctx); + + /** FIXME: Documentation */ + static const ImmutableNameResolutionContext &get (); + + const NameResolutionContext &resolver () const; + +private: + ImmutableNameResolutionContext (const NameResolutionContext &ctx); + ImmutableNameResolutionContext (const ImmutableNameResolutionContext &other) + = default; + + const NameResolutionContext &ctx; +}; + +} // namespace Resolver2_0 +} // namespace Rust + +#endif //! RUST_IMMUTABLE_NRCTX_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 5f70f5755824..cb15fc6f8d4b 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -18,8 +18,10 @@ #include "optional.h" #include "rust-ast-full.h" +#include "rust-hir-map.h" #include "rust-late-name-resolver-2.0.h" #include "rust-default-resolver.h" +#include "rust-name-resolution-context.h" #include "rust-path.h" #include "rust-tyty.h" #include "rust-hir-type-check.h" @@ -29,41 +31,76 @@ namespace Resolver2_0 { Late::Late (NameResolutionContext &ctx) : DefaultResolver (ctx) {} +static NodeId +next_node_id () +{ + return Analysis::Mappings::get ()->get_next_node_id (); +}; + +static HirId +next_hir_id () +{ + return Analysis::Mappings::get ()->get_next_hir_id (); +}; + void Late::setup_builtin_types () { - auto next_id = [this] () { return ctx.mappings.get_next_hir_id (); }; - - static const std::pair builtins[] = { - {"u8", new TyTy::UintType (next_id (), TyTy::UintType::U8)}, - {"u16", new TyTy::UintType (next_id (), TyTy::UintType::U16)}, - {"u32", new TyTy::UintType (next_id (), TyTy::UintType::U32)}, - {"u64", new TyTy::UintType (next_id (), TyTy::UintType::U64)}, - {"u128", new TyTy::UintType (next_id (), TyTy::UintType::U128)}, - {"i8", new TyTy::IntType (next_id (), TyTy::IntType::I8)}, - {"i16", new TyTy::IntType (next_id (), TyTy::IntType::I16)}, - {"i32", new TyTy::IntType (next_id (), TyTy::IntType::I32)}, - {"i64", new TyTy::IntType (next_id (), TyTy::IntType::I64)}, - {"i128", new TyTy::IntType (next_id (), TyTy::IntType::I128)}, - {"f32", new TyTy::FloatType (next_id (), TyTy::FloatType::F32)}, - {"f64", new TyTy::FloatType (next_id (), TyTy::FloatType::F64)}, - {"usize", new TyTy::USizeType (next_id ())}, - {"isize", new TyTy::ISizeType (next_id ())}, - // missing char, str, never, () - // does name resolution play a part for this? or is it all at typechecking? - // yeah it seems to be name resolution as well, which makes sense + // access the global type context to setup the TyTys + auto &ty_ctx = *Resolver::TypeCheckContext::get (); + + // Late builtin type struct helper + struct LType + { + std::string name; + NodeId node_id; + NodeId hir_id; + TyTy::BaseType *type; + + explicit LType (std::string name, TyTy::BaseType *type) + : name (name), node_id (next_node_id ()), hir_id (type->get_ref ()), + type (type) + {} + }; + + static const LType builtins[] = { + {LType ("bool", new TyTy::BoolType (next_hir_id ()))}, + {LType ("u8", new TyTy::UintType (next_hir_id (), TyTy::UintType::U8))}, + {LType ("u16", new TyTy::UintType (next_hir_id (), TyTy::UintType::U16))}, + {LType ("u32", new TyTy::UintType (next_hir_id (), TyTy::UintType::U32))}, + {LType ("u64", new TyTy::UintType (next_hir_id (), TyTy::UintType::U64))}, + {LType ("u128", new TyTy::UintType (next_hir_id (), TyTy::UintType::U128))}, + {LType ("i8", new TyTy::IntType (next_hir_id (), TyTy::IntType::I8))}, + {LType ("i16", new TyTy::IntType (next_hir_id (), TyTy::IntType::I16))}, + {LType ("i32", new TyTy::IntType (next_hir_id (), TyTy::IntType::I32))}, + {LType ("i64", new TyTy::IntType (next_hir_id (), TyTy::IntType::I64))}, + {LType ("i128", new TyTy::IntType (next_hir_id (), TyTy::IntType::I128))}, + {LType ("f32", new TyTy::FloatType (next_hir_id (), TyTy::FloatType::F32))}, + {LType ("f64", new TyTy::FloatType (next_hir_id (), TyTy::FloatType::F64))}, + {LType ("usize", new TyTy::USizeType (next_hir_id ()))}, + {LType ("isize", new TyTy::ISizeType (next_hir_id ()))}, + {LType ("char", new TyTy::CharType (next_hir_id ()))}, + {LType ("str", new TyTy::StrType (next_hir_id ()))}, + {LType ("!", new TyTy::NeverType (next_hir_id ()))}, + + // the unit type `()` does not play a part in name-resolution - so we only + // 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.first, builtin.second->get_ref () - /* FIXME: Invalid! This returns an *HirId* */); - + auto ok = ctx.types.insert (builtin.name, builtin.node_id); rust_assert (ok); + + ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id); + ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type); } + + // ...here! + auto *unit_type = TyTy::TupleType::get_unit_type (next_hir_id ()); + ty_ctx.insert_builtin (unit_type->get_ref (), next_node_id (), unit_type); } void @@ -132,7 +169,7 @@ Late::visit (AST::IdentifierExpr &expr) resolved = value; // TODO: else emit error? - ctx.map_usage (expr.get_node_id (), *resolved); + ctx.map_usage (Usage (expr.get_node_id ()), Definition (*resolved)); // in the old resolver, resolutions are kept in the resolver, not the mappings // :/ how do we deal with that? @@ -163,7 +200,7 @@ Late::visit (AST::TypePath &type) auto resolved = ctx.types.get (type.get_segments ().back ()->as_string ()); - ctx.map_usage (type.get_node_id (), *resolved); + ctx.map_usage (Usage (type.get_node_id ()), Definition (*resolved)); } } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index f71ef91505bd..2d16a70a1a0c 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.cc +++ b/gcc/rust/resolve/rust-name-resolution-context.cc @@ -17,6 +17,8 @@ // . #include "rust-name-resolution-context.h" +#include "optional.h" +#include "rust-mapping-common.h" namespace Rust { namespace Resolver2_0 { @@ -44,7 +46,7 @@ NameResolutionContext::insert (Identifier name, NodeId id, Namespace ns) } void -NameResolutionContext::map_usage (NodeId usage, NodeId definition) +NameResolutionContext::map_usage (Usage usage, Definition definition) { auto inserted = resolved_nodes.emplace (usage, definition).second; @@ -52,6 +54,17 @@ NameResolutionContext::map_usage (NodeId usage, NodeId definition) rust_assert (inserted); } +tl::optional +NameResolutionContext::lookup (NodeId usage) +{ + auto it = resolved_nodes.find (Usage (usage)); + + if (it == resolved_nodes.end ()) + return tl::nullopt; + + return it->second.id; +} + void NameResolutionContext::scoped (Rib rib, NodeId id, std::function lambda, diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 7a1924581abd..c8b2f37ecd09 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -19,6 +19,7 @@ #ifndef RUST_NAME_RESOLVER_2_0_H #define RUST_NAME_RESOLVER_2_0_H +#include "optional.h" #include "rust-forever-stack.h" #include "rust-hir-map.h" @@ -132,6 +133,28 @@ change? correct */ +// FIXME: Documentation +class Usage +{ +public: + explicit Usage (NodeId id) : id (id) {} + + // TODO: move to name-resolution-ctx.cc + // storing it as a key in a map + bool operator< (const Usage other) const { return other.id < id; } + + NodeId id; +}; + +// FIXME: Documentation +class Definition +{ +public: + explicit Definition (NodeId id) : id (id) {} + + NodeId id; +}; + // Now our resolver, which keeps track of all the `ForeverStack`s we could want class NameResolutionContext { @@ -180,11 +203,14 @@ class NameResolutionContext Analysis::Mappings &mappings; // TODO: Rename - void map_usage (NodeId usage, NodeId definition); + // TODO: Use newtype pattern for Usage and Definition + void map_usage (Usage usage, Definition definition); + + tl::optional lookup (NodeId usage); private: /* Map of "usage" nodes which have been resolved to a "definition" node */ - std::map resolved_nodes; + std::map resolved_nodes; }; } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-rib.cc b/gcc/rust/resolve/rust-rib.cc index 21fbe2ca530e..4ff8c8da1e3b 100644 --- a/gcc/rust/resolve/rust-rib.cc +++ b/gcc/rust/resolve/rust-rib.cc @@ -17,10 +17,27 @@ // . #include "rust-rib.h" +#include "rust-name-resolution-context.h" namespace Rust { namespace Resolver2_0 { +Rib::Definition::Definition (NodeId id, bool shadowable) + : id (id), shadowable (shadowable) +{} + +Rib::Definition +Rib::Definition::Shadowable (NodeId id) +{ + return Definition (id, true); +} + +Rib::Definition +Rib::Definition::NonShadowable (NodeId id) +{ + return Definition (id, false); +} + DuplicateNameError::DuplicateNameError (std::string name, NodeId existing) : name (name), existing (existing) {} @@ -31,20 +48,23 @@ Rib::Rib (Kind kind, std::string identifier, NodeId id) : Rib (kind, {{identifier, id}}) {} -Rib::Rib (Kind kind, std::unordered_map values) - : kind (kind), values (std::move (values)) -{} +Rib::Rib (Kind kind, std::unordered_map to_insert) + : kind (kind) +{ + for (auto &value : to_insert) + values.insert ({value.first, Definition::NonShadowable (value.second)}); +} tl::expected -Rib::insert (std::string name, NodeId id, bool can_shadow) +Rib::insert (std::string name, Definition def) { - auto res = values.insert ({name, id}); - auto inserted_id = res.first->second; + auto res = values.insert ({name, def}); + auto inserted_id = res.first->second.id; auto existed = !res.second; // if we couldn't insert, the element already exists - exit with an error, // unless shadowing is allowed - if (existed && !can_shadow) + if (existed && !def.shadowable) return tl::make_unexpected (DuplicateNameError (name, inserted_id)); // return the NodeId @@ -59,10 +79,10 @@ Rib::get (const std::string &name) if (it == values.end ()) return {}; - return it->second; + return it->second.id; } -const std::unordered_map & +const std::unordered_map & Rib::get_values () const { return values; diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h index 4ffd00a5d6c3..e74af436c30a 100644 --- a/gcc/rust/resolve/rust-rib.h +++ b/gcc/rust/resolve/rust-rib.h @@ -103,6 +103,24 @@ struct DuplicateNameError class Rib { public: + // TODO: Rename the class? to what? Binding? Declaration? + // This is useful for items which are in namespaces where shadowing is not + // allowed, but which are still shadowable! for example, when you do a glob + // import, if a later import has the same name as an item imported in the glob + // import, that glob imported item will need to get shadowed + class Definition + { + public: + static Definition NonShadowable (NodeId id); + static Definition Shadowable (NodeId id); + + NodeId id; + bool shadowable; + + private: + Definition (NodeId id, bool shadowable); + }; + enum class Kind { Normal, @@ -131,15 +149,14 @@ class Rib * Insert a new node in the rib * * @param name The name associated with the AST node - * @param id Its NodeId - * @param can_shadow If the newly inserted value can shadow an existing one + * @param def The `Definition` to insert * * @return `DuplicateNameError` if the node is already present in the rib. The * `DuplicateNameError` class contains the NodeId of the existing * node. Returns the new NodeId on success. */ - tl::expected insert (std::string name, NodeId id, - bool can_shadow = false); + tl::expected insert (std::string name, + Definition def); /** * Access an inserted NodeId. @@ -149,10 +166,11 @@ class Rib tl::optional get (const std::string &name); /* View all the values stored in the rib */ - const std::unordered_map &get_values () const; + const std::unordered_map &get_values () const; private: - std::unordered_map values; + // TODO: Switch this to (NodeId, shadowable = false); + std::unordered_map values; }; } // namespace Resolver2_0 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 46113a8a46b3..fe13c2886898 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -47,11 +47,8 @@ TopLevel::insert_or_error_out (const Identifier &identifier, auto result = ctx.insert (identifier, node_id, ns); - if (!result) + if (!result && result.error ().existing != node_id) { - // can we do something like check if the node id is the same? if it is the - // same, it's not an error, just the resolver running multiple times? - rich_location rich_loc (line_table, locus); rich_loc.add_range (node_locations[result.error ().existing]); @@ -94,7 +91,7 @@ insert_macros (std::vector ¯os, NameResolutionContext &ctx) { auto res = ctx.macros.insert (macro.get_name (), macro.get_node_id ()); - if (!res) + if (!res && res.error ().existing != macro.get_node_id ()) { rust_error_at (UNKNOWN_LOCATION, ErrorCode::E0428, "macro %qs defined multiple times", @@ -170,7 +167,7 @@ TopLevel::visit (AST::MacroRulesDefinition ¯o) { auto res = ctx.macros.insert_at_root (macro.get_rule_name (), macro.get_node_id ()); - if (!res) + if (!res && res.error ().existing != macro.get_node_id ()) { // TODO: Factor this rich_location rich_loc (line_table, macro.get_locus ()); @@ -332,40 +329,48 @@ TopLevel::handle_use_dec (AST::SimplePath path) auto found = false; - auto resolve_and_insert = [this, &found, &declared_name, - locus] (Namespace ns, - const AST::SimplePath &path) { - tl::optional resolved = tl::nullopt; - - // FIXME: resolve_path needs to return an `expected` so - // that we can improve it with hints or location or w/ever. and maybe - // only emit it the first time. - switch (ns) - { - case Namespace::Values: - resolved = ctx.values.resolve_path (path.get_segments ()); - break; - case Namespace::Types: - resolved = ctx.types.resolve_path (path.get_segments ()); - break; - case Namespace::Macros: - resolved = ctx.macros.resolve_path (path.get_segments ()); - break; - case Namespace::Labels: - // TODO: Is that okay? - rust_unreachable (); - } - - // FIXME: Ugly - (void) resolved.map ([this, &found, &declared_name, locus, ns] (NodeId id) { - found = true; - - // what do we do with the id? - insert_or_error_out (declared_name, locus, id, ns); - - return id; - }); - }; + auto resolve_and_insert + = [this, &found, &declared_name, locus] (Namespace ns, + const AST::SimplePath &path) { + tl::optional resolved = tl::nullopt; + + // FIXME: resolve_path needs to return an `expected` so + // that we can improve it with hints or location or w/ever. and maybe + // only emit it the first time. + switch (ns) + { + case Namespace::Values: + resolved = ctx.values.resolve_path (path.get_segments ()); + break; + case Namespace::Types: + resolved = ctx.types.resolve_path (path.get_segments ()); + break; + case Namespace::Macros: + resolved = ctx.macros.resolve_path (path.get_segments ()); + break; + case Namespace::Labels: + // TODO: Is that okay? + rust_unreachable (); + } + + // FIXME: Ugly + (void) resolved.map ( + [this, &found, &declared_name, locus, ns, path] (NodeId id) { + found = true; + + // what do we do with the id? + insert_or_error_out (declared_name, locus, id, ns); + auto result = node_forwarding.find (id); + if (result != node_forwarding.cend () + && result->second != path.get_node_id ()) + rust_error_at (path.get_locus (), "%<%s%> defined multiple times", + declared_name.c_str ()); + else // No previous thing has inserted this into our scope + node_forwarding.insert ({id, path.get_node_id ()}); + + return id; + }); + }; // do this for all namespaces (even Labels?) @@ -466,6 +471,18 @@ flatten_glob (const AST::UseTreeGlob &glob, std::vector &paths) { if (glob.has_path ()) paths.emplace_back (glob.get_path ()); + + // so what is the plan for glob imports + // 1. figure out the rib which contains all the exports, in each namespace + // 2. for that namespace, go through all the nodes + // 3. filter out the exported ones (is that correct?) + // 4. export them in the current rib, BUT make them shadowable + + // 1. needs us to be able to find a Rib based on a SimplePath - can we already + // do that with resolve path? + // 2. ok + // 3. how do we get the visibiliy information for each node? in the mappings? + // 4. ok } void @@ -483,8 +500,7 @@ TopLevel::visit (AST::UseDeclaration &use) for (auto &path : paths) if (!handle_use_dec (path)) rust_error_at (path.get_final_segment ().get_locus (), ErrorCode::E0433, - "could not resolve import %qs", - path.as_string ().c_str ()); + "unresolved import %qs", path.as_string ().c_str ()); } } // namespace Resolver2_0 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 996899b0848f..9354959a41d8 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -59,6 +59,7 @@ class TopLevel : public DefaultResolver // FIXME: Do we move these to our mappings? std::unordered_map node_locations; + std::unordered_map node_forwarding; void visit (AST::Module &module) override; void visit (AST::MacroRulesDefinition ¯o) override; diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 33aa13364807..f52565cf2356 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -18,6 +18,7 @@ #include "rust-session-manager.h" #include "rust-diagnostics.h" +#include "rust-immutable-name-resolution-context.h" #include "rust-unsafe-checker.h" #include "rust-lex.h" #include "rust-parse.h" @@ -42,6 +43,7 @@ #include "rust-early-name-resolver.h" #include "rust-name-resolution-context.h" #include "rust-early-name-resolver-2.0.h" +#include "rust-late-name-resolver-2.0.h" #include "rust-cfg-strip.h" #include "rust-expand-visitor.h" #include "rust-unicode.h" @@ -67,6 +69,10 @@ const char *kASTDumpFile = "gccrs.ast.dump"; const char *kASTPrettyDumpFile = "gccrs.ast-pretty.dump"; const char *kASTPrettyDumpFileExpanded = "gccrs.ast-pretty-expanded.dump"; const char *kASTExpandedDumpFile = "gccrs.ast-expanded.dump"; +const char *kASTmacroResolutionDumpFile = "gccrs.ast-macro-resolution.dump"; +const char *kASTlabelResolutionDumpFile = "gccrs.ast-label-resolution.dump"; +const char *kASTtypeResolutionDumpFile = "gccrs.ast-type-resolution.dump"; +const char *kASTvalueResolutionDumpFile = "gccrs.ast-value-resolution.dump"; const char *kHIRDumpFile = "gccrs.hir.dump"; const char *kHIRPrettyDumpFile = "gccrs.hir-pretty.dump"; const char *kHIRTypeResolutionDumpFile = "gccrs.type-resolution.dump"; @@ -84,6 +90,7 @@ Session::get_instance () static std::string infer_crate_name (const std::string &filename) + { if (filename == "-") return kDefaultCrateName; @@ -590,8 +597,10 @@ Session::compile_crate (const char *filename) if (last_step == CompileOptions::CompileStep::Expansion) return; + auto name_resolution_ctx = Resolver2_0::NameResolutionContext (); // expansion pipeline stage - expansion (parsed_crate); + + expansion (parsed_crate, name_resolution_ctx); rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m"); if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP)) { @@ -616,12 +625,13 @@ Session::compile_crate (const char *filename) return; // resolution pipeline stage - Resolver::NameResolution::Resolve (parsed_crate); + if (flag_name_resolution_2_0) + Resolver2_0::Late (name_resolution_ctx).go (parsed_crate); + else + Resolver::NameResolution::Resolve (parsed_crate); if (options.dump_option_enabled (CompileOptions::RESOLUTION_DUMP)) - { - // TODO: what do I dump here? resolved names? AST with resolved names? - } + dump_name_resolution (name_resolution_ctx); if (saw_errors ()) return; @@ -649,6 +659,9 @@ Session::compile_crate (const char *filename) if (last_step == CompileOptions::CompileStep::TypeCheck) return; + // name resolution is done, we now freeze the name resolver for type checking + Resolver2_0::ImmutableNameResolutionContext::init (name_resolution_ctx); + // type resolve Resolver::TypeResolution::Resolve (hir); @@ -878,7 +891,7 @@ Session::injection (AST::Crate &crate) } void -Session::expansion (AST::Crate &crate) +Session::expansion (AST::Crate &crate, Resolver2_0::NameResolutionContext &ctx) { rust_debug ("started expansion"); @@ -905,8 +918,6 @@ Session::expansion (AST::Crate &crate) if (saw_errors ()) break; - auto ctx = Resolver2_0::NameResolutionContext (); - if (flag_name_resolution_2_0) { Resolver2_0::Early early (ctx); @@ -975,6 +986,23 @@ Session::dump_ast_pretty (AST::Crate &crate, bool expanded) const out.close (); } +void +Session::dump_name_resolution (Resolver2_0::NameResolutionContext &ctx) const +{ + std::array, 4> content_and_streams = {{ + {ctx.types.as_debug_string (), std::ofstream (kASTtypeResolutionDumpFile)}, + {ctx.macros.as_debug_string (), + std::ofstream (kASTmacroResolutionDumpFile)}, + {ctx.labels.as_debug_string (), + std::ofstream (kASTlabelResolutionDumpFile)}, + {ctx.values.as_debug_string (), + std::ofstream (kASTvalueResolutionDumpFile)}, + }}; + + for (auto &to_dump : content_and_streams) + to_dump.second << to_dump.first; +} + void Session::dump_hir (HIR::Crate &crate) const { diff --git a/gcc/rust/rust-session-manager.h b/gcc/rust/rust-session-manager.h index 0240c0180080..858e3352fe2e 100644 --- a/gcc/rust/rust-session-manager.h +++ b/gcc/rust/rust-session-manager.h @@ -24,6 +24,7 @@ #include "rust-backend.h" #include "rust-hir-map.h" #include "safe-ctype.h" +#include "rust-name-resolution-context.h" #include "config.h" #include "rust-system.h" @@ -395,6 +396,7 @@ struct Session void dump_lex (Parser &parser) const; void dump_ast_pretty (AST::Crate &crate, bool expanded = false) const; + void dump_name_resolution (Resolver2_0::NameResolutionContext &ctx) const; void dump_hir (HIR::Crate &crate) const; void dump_hir_pretty (HIR::Crate &crate) const; @@ -413,7 +415,7 @@ struct Session /* Expansion pipeline stage. TODO maybe move to another object? Expands all * macros, maybe build test harness in future, AST validation, maybe create * macro crate (if not rustdoc).*/ - void expansion (AST::Crate &crate); + void expansion (AST::Crate &crate, Resolver2_0::NameResolutionContext &ctx); // handle cfg_option bool handle_cfg_option (std::string &data); diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index 87313af9a587..d3faa1ccc723 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -17,12 +17,17 @@ // . #include "rust-hir-type-check-item.h" +#include "rust-canonical-path.h" +#include "rust-diagnostics.h" #include "rust-hir-type-check-enumitem.h" #include "rust-hir-type-check-implitem.h" #include "rust-hir-type-check-type.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-pattern.h" #include "rust-hir-trait-resolve.h" +#include "rust-identifier.h" +#include "rust-session-manager.h" +#include "rust-immutable-name-resolution-context.h" #include "rust-substitution-mapper.h" #include "rust-type-util.h" @@ -172,11 +177,30 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) } // get the path - const CanonicalPath *canonical_path = nullptr; - bool ok = mappings->lookup_canonical_path ( - struct_decl.get_mappings ().get_nodeid (), &canonical_path); - rust_assert (ok); - RustIdent ident{*canonical_path, struct_decl.get_locus ()}; + + auto path = CanonicalPath::create_empty (); + + // FIXME: HACK: ARTHUR: Disgusting + if (flag_name_resolution_2_0) + { + auto nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto canonical_path = nr_ctx.values.to_canonical_path ( + struct_decl.get_mappings ().get_nodeid ()); + + path = canonical_path.value (); + } + else + { + const CanonicalPath *canonical_path = nullptr; + bool ok = mappings->lookup_canonical_path ( + struct_decl.get_mappings ().get_nodeid (), &canonical_path); + rust_assert (ok); + + path = *canonical_path; + } + + RustIdent ident{path, struct_decl.get_locus ()}; // its a single variant ADT std::vector variants; @@ -228,12 +252,29 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl) context->insert_type (field.get_mappings (), ty_field->get_field_type ()); } - // get the path - const CanonicalPath *canonical_path = nullptr; - bool ok = mappings->lookup_canonical_path ( - struct_decl.get_mappings ().get_nodeid (), &canonical_path); - rust_assert (ok); - RustIdent ident{*canonical_path, struct_decl.get_locus ()}; + auto path = CanonicalPath::create_empty (); + + // FIXME: HACK: ARTHUR: Disgusting + if (flag_name_resolution_2_0) + { + auto nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto canonical_path = nr_ctx.values.to_canonical_path ( + struct_decl.get_mappings ().get_nodeid ()); + + path = canonical_path.value (); + } + else + { + const CanonicalPath *canonical_path = nullptr; + bool ok = mappings->lookup_canonical_path ( + struct_decl.get_mappings ().get_nodeid (), &canonical_path); + rust_assert (ok); + + path = *canonical_path; + } + + RustIdent ident{path, struct_decl.get_locus ()}; // its a single variant ADT std::vector variants; @@ -470,13 +511,30 @@ TypeCheckItem::visit (HIR::Function &function) TypeCheckPattern::Resolve (param.get_param_name ().get (), param_tyty); } - const CanonicalPath *canonical_path = nullptr; - bool ok - = mappings->lookup_canonical_path (function.get_mappings ().get_nodeid (), - &canonical_path); - rust_assert (ok); + auto path = CanonicalPath::create_empty (); + + // FIXME: HACK: ARTHUR: Disgusting + if (flag_name_resolution_2_0) + { + auto nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto canonical_path = nr_ctx.values.to_canonical_path ( + function.get_mappings ().get_nodeid ()); + + path = canonical_path.value (); + } + else + { + const CanonicalPath *canonical_path = nullptr; + bool ok = mappings->lookup_canonical_path ( + function.get_mappings ().get_nodeid (), &canonical_path); + rust_assert (ok); + + path = *canonical_path; + } + + RustIdent ident{path, function.get_locus ()}; - RustIdent ident{*canonical_path, function.get_locus ()}; auto fnType = new TyTy::FnType (function.get_mappings ().get_hirid (), function.get_mappings ().get_defid (), function.get_function_name ().as_string (), diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc index 2b5d3860ec32..660d7de73df1 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-path.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc @@ -24,6 +24,8 @@ #include "rust-hir-path-probe.h" #include "rust-type-util.h" #include "rust-hir-type-bounds.h" +#include "rust-session-manager.h" +#include "rust-immutable-name-resolution-context.h" namespace Rust { namespace Resolver { @@ -193,12 +195,18 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset, bool is_root = *offset == 0; NodeId ast_node_id = seg.get_mappings ().get_nodeid (); + auto nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + // then lookup the reference_node_id NodeId ref_node_id = UNKNOWN_NODEID; - if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) - { - resolver->lookup_resolved_type (ast_node_id, &ref_node_id); - } + + if (flag_name_resolution_2_0) + // assign the ref_node_id if we've found something + nr_ctx.lookup (expr.get_mappings ().get_nodeid ()) + .map ([&ref_node_id] (NodeId resolved) { ref_node_id = resolved; }); + else if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + resolver->lookup_resolved_type (ast_node_id, &ref_node_id); // ref_node_id is the NodeId that the segments refers to. if (ref_node_id == UNKNOWN_NODEID) diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index 9fa64e10e8a2..1b1f6b6afe10 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -17,10 +17,13 @@ // . #include "rust-hir-type-check-type.h" +#include "options.h" #include "rust-hir-trait-resolve.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-path-probe.h" #include "rust-hir-type-bounds.h" +#include "rust-immutable-name-resolution-context.h" +#include "rust-mapping-common.h" #include "rust-substitution-mapper.h" #include "rust-type-util.h" @@ -123,6 +126,8 @@ TypeCheckType::visit (HIR::TupleType &tuple) void TypeCheckType::visit (HIR::TypePath &path) { + rust_debug ("{ARTHUR}: Path visited: %s", path.as_string ().c_str ()); + // this can happen so we need to look up the root then resolve the // remaining segments if possible size_t offset = 0; @@ -327,12 +332,23 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, bool is_root = *offset == 0; NodeId ast_node_id = seg->get_mappings ().get_nodeid (); + auto nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + // then lookup the reference_node_id NodeId ref_node_id = UNKNOWN_NODEID; - if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) - { - resolver->lookup_resolved_type (ast_node_id, &ref_node_id); - } + + // FIXME: HACK: ARTHUR: Remove this + if (flag_name_resolution_2_0) + // assign the ref_node_id if we've found something + nr_ctx.lookup (path.get_mappings ().get_nodeid ()) + .map ([&ref_node_id, &path] (NodeId resolved) { + rust_warning_at (path.get_locus (), 0, + "{ARTHUR}: found reference: %d", resolved); + ref_node_id = resolved; + }); + else if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + resolver->lookup_resolved_type (ast_node_id, &ref_node_id); // ref_node_id is the NodeId that the segments refers to. if (ref_node_id == UNKNOWN_NODEID) @@ -340,7 +356,7 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, if (is_root) { rust_error_at (seg->get_locus (), - "unknown reference for resolved name: %<%s%>", + "unknown reference for resolved name: %qs", seg->get_ident_segment ().as_string ().c_str ()); return new TyTy::ErrorType (path.get_mappings ().get_hirid ()); } diff --git a/gcc/testsuite/rust/compile/name_resolution13.rs b/gcc/testsuite/rust/compile/name_resolution13.rs index 52a152bf51a5..5fbf47174e24 100644 --- a/gcc/testsuite/rust/compile/name_resolution13.rs +++ b/gcc/testsuite/rust/compile/name_resolution13.rs @@ -1,4 +1,12 @@ +<<<<<<< HEAD // { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +======= +// { dg-options "-frust-name-resolution-2.0" } + +pub mod foo { + pub macro bar() {} +} +>>>>>>> 9cd774074db (Change to name resolution 2.0) fn foo() { let b = 10; diff --git a/gcc/testsuite/rust/compile/name_resolution14.rs b/gcc/testsuite/rust/compile/name_resolution14.rs new file mode 100644 index 000000000000..eaef6a52f160 --- /dev/null +++ b/gcc/testsuite/rust/compile/name_resolution14.rs @@ -0,0 +1,15 @@ +// { dg-options "-frust-name-resolution-2.0" } + +pub mod foo { + pub macro bar() {} +} + +use foo::biz; // { dg-error "unresolved import .foo::biz. .E0433." } + +use foo::{bar, baz, biz}; +// { dg-error "unresolved import .foo::baz. .E0433." "" { target *-*-* } .-1 } +// { dg-error "unresolved import .foo::biz. .E0433." "" { target *-*-* } .-2 } + +fn main() { + bar!(); +} diff --git a/gcc/testsuite/rust/compile/name_resolution15.rs b/gcc/testsuite/rust/compile/name_resolution15.rs new file mode 100644 index 000000000000..06f02d68047d --- /dev/null +++ b/gcc/testsuite/rust/compile/name_resolution15.rs @@ -0,0 +1,19 @@ +#![feature(decl_macro)] + +pub mod foo { + pub struct Foo { + pub a: i32, + } + pub fn Foo() {} + pub macro Foo() {{}} +} + +pub use foo::Foo; + +use self::Foo as Fo; + +fn main() { + let a = Fo(); + let b = Fo { a: 15 }; + let c = Fo!(); +} diff --git a/gcc/testsuite/rust/compile/name_resolution16.rs b/gcc/testsuite/rust/compile/name_resolution16.rs new file mode 100644 index 000000000000..19d90d01ea59 --- /dev/null +++ b/gcc/testsuite/rust/compile/name_resolution16.rs @@ -0,0 +1,17 @@ +#![feature(decl_macro)] + +pub mod foo { + pub struct Foo { + pub a: i32, + } + pub fn Foo() {} + pub macro Foo() {{}} +} + +pub use foo::Foo; + +fn main() { + let a = Foo(); + let b = Foo { a: 15 }; + let c = Foo!(); +} diff --git a/gcc/testsuite/rust/compile/name_resolution17.rs b/gcc/testsuite/rust/compile/name_resolution17.rs new file mode 100644 index 000000000000..485947647a95 --- /dev/null +++ b/gcc/testsuite/rust/compile/name_resolution17.rs @@ -0,0 +1,10 @@ +// { dg-options "-frust-name-resolution-2.0" } + +struct Foo; +fn Foo() {} // { dg-error ".Foo. defined multiple times" } + +struct Marker; +struct Bar { + a: Marker, +} +fn Bar() {} // ok, since `Bar` is not a value here diff --git a/gcc/testsuite/rust/compile/name_resolution18.rs b/gcc/testsuite/rust/compile/name_resolution18.rs new file mode 100644 index 000000000000..5940149d3bbf --- /dev/null +++ b/gcc/testsuite/rust/compile/name_resolution18.rs @@ -0,0 +1,15 @@ +// { dg-options "-frust-name-resolution-2.0" } + +struct Marker; + +struct Foo { + a: Marker, +} + +pub mod foo { + struct Foo { + b: Marker, + } +} + +use foo::Foo; // { dg-error ".Foo. defined multiple times" } diff --git a/gcc/testsuite/rust/compile/name_resolution19.rs b/gcc/testsuite/rust/compile/name_resolution19.rs new file mode 100644 index 000000000000..9a2c84375c7a --- /dev/null +++ b/gcc/testsuite/rust/compile/name_resolution19.rs @@ -0,0 +1,20 @@ +struct Marker; + +fn foo(a: Marker, b: Marker) -> Marker { + let a = b; + + a +} + +fn bar() { + let a = 15; + + fn inner() { + // inner functions cannot capture dynamic environment + let b = a; // { dg-error "cannot find value .a. in this scope" } + } +} + +fn main() { + let m = foo(Marker, Marker); +} diff --git a/gcc/testsuite/rust/compile/name_resolution20.rs b/gcc/testsuite/rust/compile/name_resolution20.rs new file mode 100644 index 000000000000..e6c2dd5ea8f9 --- /dev/null +++ b/gcc/testsuite/rust/compile/name_resolution20.rs @@ -0,0 +1,11 @@ +// { dg-options "-frust-name-resolution-2.0" } + +pub mod foo { + pub macro bar() {} +} + +use foo::bar; + +fn main() { + bar!(); +} diff --git a/gcc/testsuite/rust/compile/name_resolution21.rs b/gcc/testsuite/rust/compile/name_resolution21.rs new file mode 100644 index 000000000000..3d0af2b37b76 --- /dev/null +++ b/gcc/testsuite/rust/compile/name_resolution21.rs @@ -0,0 +1,12 @@ +// { dg-additional-options "-frust-name-resolution-2.0" } + +pub mod foo { + pub macro bar() {} +} + +use foo::bar; +use foo::bar; // { dg-error ".bar. defined multiple times" } + +fn main() { + bar!(); +} diff --git a/gcc/testsuite/rust/compile/nested_macro_definition.rs b/gcc/testsuite/rust/compile/nested_macro_definition.rs deleted file mode 100644 index c0b72506accd..000000000000 --- a/gcc/testsuite/rust/compile/nested_macro_definition.rs +++ /dev/null @@ -1,16 +0,0 @@ -// { dg-options "-frust-name-resolution-2.0" } - -macro_rules! toto { - () => { - macro_rules! tata { - () => { - let _i = 0; - }; - } - }; -} - -pub fn main() { - toto!(); - tata!(); -}