rust/rust-builtins.o \
rust/rust-feature.o \
rust/rust-feature-gate.o \
+ rust/rust-feature-collector.o \
rust/rust-ast-validation.o \
rust/rust-dir-owner.o \
rust/rust-unicode.o \
--- /dev/null
+// Copyright (C) 2026 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-feature-collector.h"
+#include "rust-attribute-values.h"
+
+namespace Rust {
+namespace Features {
+
+FeatureCollector::FeatureCollector () : features (CrateFeatures{UNKNOWN_NODEID})
+{}
+
+CrateFeatures
+FeatureCollector::collect (AST::Crate &crate)
+{
+ features.valid_lang_features.clear ();
+ features.valid_lib_features.clear ();
+ features.crate_id = crate.get_node_id ();
+
+ visit (crate);
+
+ return features;
+}
+
+namespace {
+bool
+is_feature_attribute (const AST::Attribute &attribute)
+{
+ return Values::Attributes::FEATURE == attribute.get_path ().as_string ();
+}
+
+// check for empty feature, such as `#![feature], this is an error
+bool
+is_valid_feature_attribute (const AST::Attribute &attribute)
+{
+ return !attribute.empty_input ();
+}
+} // namespace
+
+void
+FeatureCollector::add_features_from_token_tree (
+ const AST::DelimTokenTree &delim_ttree)
+{
+ std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
+ delim_ttree.parse_to_meta_item ());
+ add_features_from_meta_item_container (*meta_item);
+}
+
+void
+FeatureCollector::add_features_from_meta_item_container (
+ const AST::AttrInputMetaItemContainer &meta_item_container)
+{
+ for (const auto &item : meta_item_container.get_items ())
+ {
+ const auto &name_str = item->as_string ();
+
+ // TODO: detect duplicates
+ if (auto tname = Feature::as_name (name_str))
+ features.valid_lang_features.insert (*tname);
+ else
+ features.valid_lib_features.emplace (name_str, item->get_locus ());
+ }
+}
+
+void
+FeatureCollector::identify_feature (const AST::Attribute &attribute)
+{
+ if (is_feature_attribute (attribute))
+ {
+ if (!is_valid_feature_attribute (attribute))
+ {
+ rust_error_at (attribute.get_locus (), ErrorCode::E0556,
+ "malformed %<feature%> attribute input");
+ return;
+ }
+ const auto &attr_input = attribute.get_attr_input ();
+ auto type = attr_input.get_attr_input_type ();
+ if (type == AST::AttrInput::AttrInputType::TOKEN_TREE)
+ {
+ const auto &delim_ttree = static_cast<const AST::DelimTokenTree &> (
+ attribute.get_attr_input ());
+ add_features_from_token_tree (delim_ttree);
+ }
+ else if (type == AST::AttrInput::AttrInputType::META_ITEM)
+ {
+ // We can find a meta item in #[cfg(toto),feature(xxxx)]
+ const auto &meta_item_container
+ = static_cast<const AST::AttrInputMetaItemContainer &> (attr_input);
+ add_features_from_meta_item_container (meta_item_container);
+ }
+ }
+}
+
+void
+FeatureCollector::visit (AST::Crate &crate)
+{
+ for (const auto &attribute : crate.inner_attrs)
+ identify_feature (attribute);
+}
+
+} // namespace Features
+} // namespace Rust
--- /dev/null
+// Copyright (C) 2026 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_FEATURE_COLLECTOR_H
+#define RUST_FEATURE_COLLECTOR_H
+
+#include "rust-feature.h"
+#include "rust-ast-visitor.h"
+
+namespace Rust {
+namespace Features {
+
+/** Helper structure gathering all features enabled within a given crate
+ * using the #![feature(XXXXX)] syntax.
+ **/
+struct CrateFeatures
+{
+ // The node id identifying the crate those features belong to.
+ NodeId crate_id;
+ // Language features that have been declared within the crate.
+ std::set<Feature::Name> valid_lang_features;
+ // Library features that have been declared within the crate.
+ std::map<std::string, location_t> valid_lib_features;
+
+ CrateFeatures (NodeId crate_id) : crate_id (crate_id) {}
+};
+
+class FeatureCollector : public AST::DefaultASTVisitor
+{
+public:
+ FeatureCollector ();
+
+ CrateFeatures collect (AST::Crate &crate);
+
+private:
+ CrateFeatures features;
+
+ using AST::DefaultASTVisitor::visit;
+ void visit (AST::Crate &crate) override;
+ void identify_feature (const AST::Attribute &attribute);
+ void add_features_from_token_tree (const AST::DelimTokenTree &delim_ttree);
+ void add_features_from_meta_item_container (
+ const AST::AttrInputMetaItemContainer &meta_item_container);
+};
+} // namespace Features
+} // namespace Rust
+
+#endif /* ! RUST_FEATURE_COLLECTOR_H */
#include "rust-feature-gate.h"
#include "rust-abi.h"
#include "rust-attribute-values.h"
+#include "rust-attributes.h"
#include "rust-ast-visitor.h"
#include "rust-feature.h"
#include "rust-ast-full.h"
void
FeatureGate::visit (AST::Crate &crate)
{
- valid_lang_features.clear ();
- valid_lib_features.clear ();
-
- // avoid clearing defined features (?)
-
- for (const auto &attr : crate.inner_attrs)
- {
- if (attr.get_path ().as_string () == "feature")
- {
- // check for empty feature, such as `#![feature], this is an error
- if (attr.empty_input ())
- {
- rust_error_at (attr.get_locus (), ErrorCode::E0556,
- "malformed %<feature%> attribute input");
- continue;
- }
- const auto &attr_input = attr.get_attr_input ();
- auto type = attr_input.get_attr_input_type ();
- if (type == AST::AttrInput::AttrInputType::TOKEN_TREE)
- {
- const auto &option = static_cast<const AST::DelimTokenTree &> (
- attr.get_attr_input ());
- std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
- option.parse_to_meta_item ());
- for (const auto &item : meta_item->get_items ())
- {
- const auto &name_str = item->as_string ();
-
- // TODO: detect duplicates
- if (auto tname = Feature::as_name (name_str))
- valid_lang_features.insert (tname.value ());
- else
- valid_lib_features.emplace (name_str, item->get_locus ());
- }
- }
- else if (type == AST::AttrInput::AttrInputType::META_ITEM)
- {
- const auto &meta_item
- = static_cast<const AST::AttrInputMetaItemContainer &> (
- attr_input);
- for (const auto &item : meta_item.get_items ())
- {
- const auto &name_str = item->as_string ();
-
- // TODO: detect duplicates
- if (auto tname = Feature::as_name (name_str))
- valid_lang_features.insert (tname.value ());
- else
- valid_lib_features.emplace (name_str, item->get_locus ());
- }
- }
- }
- }
-
AST::DefaultASTVisitor::visit (crate);
- for (auto &ent : valid_lib_features)
+ for (auto &ent : features.valid_lib_features)
{
const std::string &feature = ent.first;
location_t locus = ent.second;
FeatureGate::gate (Feature::Name name, location_t loc,
const std::string &error_msg)
{
- if (!valid_lang_features.count (name))
+ if (!features.valid_lang_features.count (name))
{
auto &feature = Feature::lookup (name);
if (auto issue = feature.issue ())
#include "rust-ast-visitor.h"
#include "rust-feature.h"
+#include "rust-feature-collector.h"
namespace Rust {
class FeatureGate : public AST::DefaultASTVisitor
{
public:
- FeatureGate () {}
+ FeatureGate (Features::CrateFeatures &features) : features (features) {}
using AST::DefaultASTVisitor::visit;
check_lang_item_attribute (const std::vector<AST::Attribute> &attributes);
void note_stability_attribute (const std::vector<AST::Attribute> &attributes);
- std::set<Feature::Name> valid_lang_features;
- std::map<std::string, location_t> valid_lib_features;
+ Features::CrateFeatures &features;
enum class Stability
{
#include "rust-hir-type-check.h"
#include "rust-privacy-check.h"
#include "rust-const-checker.h"
+#include "rust-feature-collector.h"
#include "rust-feature-gate.h"
#include "rust-compile.h"
#include "rust-cfg-parser.h"
// feature gating
if (last_step == CompileOptions::CompileStep::FeatureGating)
return;
- FeatureGate ().check (parsed_crate);
+ auto parsed_crate_features
+ = Features::FeatureCollector{}.collect (parsed_crate);
+ FeatureGate (parsed_crate_features).check (parsed_crate);
if (last_step == CompileOptions::CompileStep::NameResolution)
return;
static constexpr auto &PROC_MACRO_ATTRIBUTE = "proc_macro_attribute";
static constexpr auto &TARGET_FEATURE = "target_feature";
+ static constexpr auto &FEATURE = "feature";
// From now on, these are reserved by the compiler and gated through
// #![feature(rustc_attrs)]
static constexpr auto &RUSTC_DEPRECATED = "rustc_deprecated";