blob: 6a3a1479227f36dd5aa4ec9b072b3a486fbbe006 [file]
// 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