From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7905) id EB11F38582BD; Tue, 16 Jan 2024 18:03:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org EB11F38582BD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1705428207; bh=PSXXqB/3f7hDhTuSBvQEeLPewI2AGIBQRssKIelLfk8=; h=From:To:Subject:Date:From; b=lfVIRMS8Mq2BQUS7z1UUdFfSD+bVnMxtngcXXgSE60eQ5oUFkMjmNh1DppDWljh1j RFOVrLPzxuwT9SSkDdJtUOkER0iR2CO6jrtNunGj9lY8Hx7ZuLBEM12wczxtw8ENLR YBGpxpaisbSndSBEVqJSSoOJTr8niE9lc54dgYDU= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Arthur Cohen To: gcc-cvs@gcc.gnu.org Subject: [gcc r14-7874] gccrs: top-level: Add base `TopLevel` visitor X-Act-Checkin: gcc X-Git-Author: Arthur Cohen X-Git-Refname: refs/heads/trunk X-Git-Oldrev: 79df2b3cafa586e2c3ba357e1448be3ad789d24e X-Git-Newrev: daae0c5dffa45f5300b9af372e13a6ae3ef56366 Message-Id: <20240116180327.EB11F38582BD@sourceware.org> Date: Tue, 16 Jan 2024 18:03:27 +0000 (GMT) List-Id: https://gcc.gnu.org/g:daae0c5dffa45f5300b9af372e13a6ae3ef56366 commit r14-7874-gdaae0c5dffa45f5300b9af372e13a6ae3ef56366 Author: Arthur Cohen Date: Thu Jul 20 14:15:14 2023 +0200 gccrs: top-level: Add base `TopLevel` visitor The `TopLevel` pass takes care of collecting definitions, placing them in the proper namespaces, and making them accessible for later resolution passes like `Early` and `Late`. It is meant to be run in a fixed point fashion, as import resolution, macro resolution and macro expansion may generate multiple new definitions. gcc/rust/ChangeLog: * Make-lang.in: Add new object file. * resolve/rust-toplevel-name-resolver-2.0.cc: New file. * resolve/rust-toplevel-name-resolver-2.0.h: New file. Diff: --- gcc/rust/Make-lang.in | 1 + .../resolve/rust-toplevel-name-resolver-2.0.cc | 212 +++++++++++++++++++++ gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h | 76 ++++++++ 3 files changed, 289 insertions(+) diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 2ebe3b2e218..dc56eeafedd 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -111,6 +111,7 @@ GRS_OBJS = \ rust/rust-ast-lower-stmt.o \ rust/rust-rib.o \ rust/rust-name-resolution-context.o \ + rust/rust-toplevel-name-resolver-2.0.o \ rust/rust-early-name-resolver.o \ rust/rust-name-resolver.o \ rust/rust-ast-resolve.o \ diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc new file mode 100644 index 00000000000..73c857e3ba7 --- /dev/null +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -0,0 +1,212 @@ +// 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-toplevel-name-resolver-2.0.h" +#include "rust-ast-full.h" +#include "rust-hir-map.h" + +namespace Rust { +namespace Resolver2_0 { + +TopLevel::TopLevel (NameResolutionContext &resolver) : ctx (resolver) {} + +template +void +TopLevel::insert_or_error_out (const Identifier &identifier, const T &node, + Namespace ns) +{ + auto loc = node.get_locus (); + auto node_id = node.get_node_id (); + + // keep track of each node's location to provide useful errors + node_locations.emplace (node_id, loc); + + auto result = ctx.insert (identifier, node_id, ns); + + if (!result) + { + rich_location rich_loc (line_table, loc); + rich_loc.add_range (node_locations[result.error ().existing]); + + rust_error_at (rich_loc, "already defined"); + } +} + +void +TopLevel::go (AST::Crate &crate) +{ + for (auto &item : crate.items) + item->accept_vis (*this); +} + +void +TopLevel::visit (AST::Module &module) +{ + // FIXME: Do we need to insert the module in the type namespace? + + auto sub_visitor = [this, &module] () { + for (auto &item : module.get_items ()) + item->accept_vis (*this); + }; + + ctx.scoped (Rib::Kind::Module, module.get_node_id (), sub_visitor, + module.get_name ()); +} + +void +TopLevel::visit (AST::MacroRulesDefinition ¯o) +{ + // FIXME: Do we want to insert macro rules here already? Probably, right? + // So that we can easily resolve in `Early`? + insert_or_error_out (macro.get_rule_name (), macro, Namespace::Macros); +} + +void +TopLevel::visit (AST::Function &function) +{ + insert_or_error_out (function.get_function_name (), function, + Namespace::Values); + + auto def_fn + = [this, &function] () { function.get_definition ()->accept_vis (*this); }; + + ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn); +} + +void +TopLevel::visit (AST::Method &method) +{ + insert_or_error_out (method.get_method_name (), method, Namespace::Values); + + method.get_definition ()->accept_vis (*this); +} + +void +TopLevel::visit (AST::BlockExpr &expr) +{ + // extracting the lambda from the `scoped` call otherwise the code looks like + // a hot turd thanks to our .clang-format + + auto sub_vis = [this, &expr] () { + for (auto &stmt : expr.get_statements ()) + stmt->accept_vis (*this); + + if (expr.has_tail_expr ()) + expr.get_tail_expr ()->accept_vis (*this); + }; + + ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), sub_vis); +} + +void +TopLevel::visit (AST::StaticItem &static_item) +{ + auto sub_vis + = [this, &static_item] () { static_item.get_expr ()->accept_vis (*this); }; + + ctx.scoped (Rib::Kind::Item, static_item.get_node_id (), sub_vis); +} + +void +TopLevel::visit (AST::TraitItemFunc &item) +{ + auto def_vis + = [this, &item] () { item.get_definition ()->accept_vis (*this); }; + + if (item.has_definition ()) + ctx.scoped (Rib::Kind::Function, item.get_node_id (), def_vis); +} + +void +TopLevel::visit (AST::StructStruct &struct_item) +{ + insert_or_error_out (struct_item.get_struct_name (), struct_item, + Namespace::Types); + + // Do we need to insert the constructor in the value namespace as well? + + // Do we need to do anything if the struct is a unit struct? + if (struct_item.is_unit_struct ()) + insert_or_error_out (struct_item.get_struct_name (), struct_item, + Namespace::Values); +} + +void +TopLevel::visit (AST::TupleStruct &tuple_struct) +{ + insert_or_error_out (tuple_struct.get_struct_name (), tuple_struct, + Namespace::Types); +} + +void +TopLevel::visit (AST::EnumItem &variant) +{ + insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); +} + +void +TopLevel::visit (AST::EnumItemTuple &variant) +{ + insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); +} + +void +TopLevel::visit (AST::EnumItemStruct &variant) +{ + insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); +} + +void +TopLevel::visit (AST::EnumItemDiscriminant &variant) +{ + insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); +} + +void +TopLevel::visit (AST::Enum &enum_item) +{ + insert_or_error_out (enum_item.get_identifier (), enum_item, + Namespace::Types); + + auto field_vis = [this, &enum_item] () { + for (auto &variant : enum_item.get_variants ()) + variant->accept_vis (*this); + }; + + ctx.scoped (Rib::Kind::Item /* FIXME: Is that correct? */, + enum_item.get_node_id (), field_vis, enum_item.get_identifier ()); +} + +void +TopLevel::visit (AST::Union &union_item) +{ + insert_or_error_out (union_item.get_identifier (), union_item, + Namespace::Types); +} + +void +TopLevel::visit (AST::ConstantItem &const_item) +{ + auto expr_vis + = [this, &const_item] () { const_item.get_expr ()->accept_vis (*this); }; + + ctx.scoped (Rib::Kind::ConstantItem, const_item.get_node_id (), expr_vis); +} + +} // namespace Resolver2_0 +} // namespace Rust diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h new file mode 100644 index 00000000000..db2033fc91c --- /dev/null +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -0,0 +1,76 @@ +// 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_TOPLEVEL_NAME_RESOLVER_2_0_H +#define RUST_TOPLEVEL_NAME_RESOLVER_2_0_H + +#include "rust-ast-visitor.h" +#include "rust-name-resolution-context.h" +#include "rust-ast-resolve-base.h" + +namespace Rust { +namespace Resolver2_0 { + +/** + * The `TopLevel` visitor takes care of collecting all the definitions in a + * crate, and inserting them into the proper namespaces. These definitions can + * then be accessed by subsequent resolvers, such as `Early` or `Late`. + */ +// TODO: Merge Resolver namespaces and use `public ResolverBase` +class TopLevel : public ::Rust::Resolver::ResolverBase +{ + using ::Rust::Resolver::ResolverBase::visit; + +public: + TopLevel (NameResolutionContext &resolver); + + void go (AST::Crate &crate); + +private: + NameResolutionContext &ctx; + + // FIXME: Documentation + template + void insert_or_error_out (const Identifier &identifier, const T &node, + Namespace ns); + + // FIXME: Do we move these to our mappings? + std::unordered_map node_locations; + + void visit (AST::Module &module) override; + void visit (AST::MacroRulesDefinition ¯o) override; + void visit (AST::Function &function) override; + void visit (AST::Method &method) override; + void visit (AST::BlockExpr &expr) override; + void visit (AST::StaticItem &static_item) override; + void visit (AST::TraitItemFunc &item) override; + void visit (AST::StructStruct &struct_item) override; + void visit (AST::TupleStruct &tuple_struct) override; + void visit (AST::EnumItem &variant) override; + void visit (AST::EnumItemTuple &variant) override; + void visit (AST::EnumItemStruct &variant) override; + void visit (AST::EnumItemDiscriminant &variant) override; + void visit (AST::Enum &enum_item) override; + void visit (AST::Union &union_item) override; + void visit (AST::ConstantItem &const_item) override; +}; + +} // namespace Resolver2_0 +} // namespace Rust + +#endif // !RUST_TOPLEVEL_NAME_RESOLVER_2_0_H