diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 6de0a20b6a0a..fe82ab42ec87 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -227,8 +227,9 @@ GRS_OBJS = \ rust/rust-dir-owner.o \ rust/rust-unicode.o \ rust/rust-punycode.o \ - rust/rust-lang-item.o \ rust/rust-expand-format-args.o \ + rust/rust-lang-item.o \ + rust/rust-collect-lang-items.o \ $(END) # removed object files from here diff --git a/gcc/rust/ast/rust-collect-lang-items.cc b/gcc/rust/ast/rust-collect-lang-items.cc new file mode 100644 index 000000000000..308720ae69ab --- /dev/null +++ b/gcc/rust/ast/rust-collect-lang-items.cc @@ -0,0 +1,86 @@ +// Copyright (C) 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 +// . + +#include "rust-collect-lang-items.h" +#include "optional.h" +#include "rust-ast-collector.h" +#include "rust-ast.h" +#include "rust-attribute-values.h" +#include "rust-attributes.h" +#include "rust-hir-map.h" + +namespace Rust { +namespace AST { + +template +tl::optional +get_lang_item_attr (const T &maybe_lang_item) +{ + for (const auto &attr : maybe_lang_item.get_outer_attrs ()) + { + const auto &str_path = attr.get_path ().as_string (); + if (!Analysis::Attributes::is_known (str_path)) + { + rust_error_at (attr.get_locus (), "unknown attribute"); + continue; + } + + bool is_lang_item = str_path == Values::Attributes::LANG + && attr.has_attr_input () + && attr.get_attr_input ().get_attr_input_type () + == AST::AttrInput::AttrInputType::LITERAL; + + if (is_lang_item) + { + auto &literal + = static_cast (attr.get_attr_input ()); + const auto &lang_item_type_str = literal.get_literal ().as_string (); + + return LangItem::Parse (lang_item_type_str); + } + } + + return tl::nullopt; +} + +template +void +CollectLangItems::maybe_add_lang_item (const T &item) +{ + if (auto lang_item = get_lang_item_attr (item)) + mappings.insert_lang_item_node (lang_item.value (), item.get_node_id ()); +} + +void +CollectLangItems::visit (AST::Trait &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + +void +CollectLangItems::visit (AST::TraitItemType &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-collect-lang-items.h b/gcc/rust/ast/rust-collect-lang-items.h new file mode 100644 index 000000000000..552648f04eda --- /dev/null +++ b/gcc/rust/ast/rust-collect-lang-items.h @@ -0,0 +1,58 @@ +// Copyright (C) 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 +// . + +#ifndef RUST_COLLECT_LANG_ITEMS_H +#define RUST_COLLECT_LANG_ITEMS_H + +#include "rust-ast-visitor.h" +#include "rust-ast.h" +#include "rust-hir-map.h" +#include "rust-item.h" + +namespace Rust { +namespace AST { + +// This class collects lang items ahead of lowering, as they are now needed for +// some parts of name resolution +class CollectLangItems : public DefaultASTVisitor +{ +public: + CollectLangItems () : mappings (Analysis::Mappings::get ()){}; + + void go (AST::Crate &crate) { DefaultASTVisitor::visit (crate); } + + Analysis::Mappings &mappings; + + // We must implement visitors for all constructs that could be lang items. + // Lang items can be traits, but also enums, and even enum variants. + // + // https://github.com/rust-lang/rust/blob/master/compiler/rustc_hir/src/lang_items.rs + + using DefaultASTVisitor::visit; + + void visit (AST::Trait &item) override; + void visit (AST::TraitItemType &item) override; + +private: + template void maybe_add_lang_item (const T &item); +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_COLLECT_LANG_ITEMS_H diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index 272de0f87172..eac2cba5c752 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -25,6 +25,7 @@ #include "rust-diagnostics.h" #include "rust-item.h" #include "rust-system.h" +#include "rust-attributes.h" namespace Rust { namespace HIR { @@ -751,7 +752,7 @@ ASTLoweringBase::handle_outer_attributes (const ItemWrapper &item) for (const auto &attr : item.get_outer_attrs ()) { const auto &str_path = attr.get_path ().as_string (); - if (!is_known_attribute (str_path)) + if (!Analysis::Attributes::is_known (str_path)) { rust_error_at (attr.get_locus (), "unknown attribute"); continue; @@ -814,13 +815,6 @@ ASTLoweringBase::handle_lang_item_attribute (const ItemWrapper &item, rust_error_at (attr.get_locus (), "unknown lang item"); } -bool -ASTLoweringBase::is_known_attribute (const std::string &attribute_path) const -{ - const auto &lookup = attr_mappings->lookup_builtin (attribute_path); - return !lookup.is_error (); -} - bool ASTLoweringBase::attribute_handled_in_another_pass ( const std::string &attribute_path) const diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 1cf58e814f69..561ba95d14e5 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -17,6 +17,7 @@ // . #include "rust-session-manager.h" +#include "rust-collect-lang-items.h" #include "rust-diagnostics.h" #include "rust-hir-pattern-analysis.h" #include "rust-immutable-name-resolution-context.h" @@ -600,6 +601,8 @@ Session::compile_crate (const char *filename) if (last_step == CompileOptions::CompileStep::Expansion) return; + AST::CollectLangItems ().go (parsed_crate); + auto name_resolution_ctx = Resolver2_0::NameResolutionContext (); // expansion pipeline stage diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc index effe98723909..5878968ed99c 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -29,6 +29,15 @@ namespace Rust { namespace Analysis { +bool +Attributes::is_known (const std::string &attribute_path) +{ + const auto &lookup + = BuiltinAttributeMappings::get ()->lookup_builtin (attribute_path); + + return !lookup.is_error (); +} + using Attrs = Values::Attributes; // https://doc.rust-lang.org/stable/nightly-rustc/src/rustc_feature/builtin_attrs.rs.html#248 diff --git a/gcc/rust/util/rust-attributes.h b/gcc/rust/util/rust-attributes.h index f557b2d46b38..c341b3e0a5db 100644 --- a/gcc/rust/util/rust-attributes.h +++ b/gcc/rust/util/rust-attributes.h @@ -25,6 +25,12 @@ namespace Rust { namespace Analysis { +class Attributes +{ +public: + static bool is_known (const std::string &attribute_path); +}; + enum CompilerPass { UNKNOWN, diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 7315edb2fb8f..2edf0996276b 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -1241,6 +1241,9 @@ Mappings::lookup_builtin_marker () return builtinMarker; } +// FIXME: Before merging: Should we remove the `locus` parameter here? since +// lang items are looked up mostly for code generation, it doesn't make sense to +// error out on the locus of the node trying to access an inexistant lang item DefId Mappings::get_lang_item (LangItem::Kind item_type, location_t locus) { @@ -1277,5 +1280,24 @@ Mappings::lookup_lang_item (LangItem::Kind item_type) return it->second; } +void +Mappings::insert_lang_item_node (LangItem::Kind item_type, NodeId node_id) +{ + auto it = lang_item_nodes.find (item_type); + rust_assert (it == lang_item_nodes.end ()); + + lang_item_nodes.insert ({item_type, node_id}); +} + +tl::optional +Mappings::lookup_lang_item_node (LangItem::Kind item_type) +{ + auto it = lang_item_nodes.find (item_type); + if (it == lang_item_nodes.end ()) + return tl::nullopt; + + return it->second; +} + } // namespace Analysis } // namespace Rust diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index 10ca71c57b69..6117b0ad8e00 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -259,6 +259,9 @@ class Mappings void insert_lang_item (LangItem::Kind item_type, DefId id); tl::optional lookup_lang_item (LangItem::Kind item_type); + void insert_lang_item_node (LangItem::Kind item_type, NodeId node_id); + tl::optional lookup_lang_item_node (LangItem::Kind item_type); + // This will fatal_error when this lang item does not exist DefId get_lang_item (LangItem::Kind item_type, location_t locus); @@ -375,7 +378,12 @@ class Mappings std::map hirGenericParamMappings; std::map hirTraitItemsToTraitMappings; std::map hirPatternMappings; + + // We need to have two maps here, as lang-items need to be used for both AST + // passes and HIR passes. Thus those two maps are created at different times. std::map lang_item_mappings; + std::map lang_item_nodes; + std::map paths; std::map locations; std::map nodeIdToHirMappings;