Line data Source code
1 : // Copyright (C) 2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-feature-collector.h"
20 : #include "rust-attribute-values.h"
21 :
22 : namespace Rust {
23 : namespace Features {
24 :
25 4522 : FeatureCollector::FeatureCollector () : features (CrateFeatures{UNKNOWN_NODEID})
26 4522 : {}
27 :
28 : CrateFeatures
29 4522 : FeatureCollector::collect (AST::Crate &crate)
30 : {
31 4522 : features.valid_lang_features.clear ();
32 4522 : features.valid_lib_features.clear ();
33 4522 : features.crate_id = crate.get_node_id ();
34 :
35 4522 : visit (crate);
36 :
37 4522 : return features;
38 : }
39 :
40 : namespace {
41 : bool
42 11256 : is_feature_attribute (const AST::Attribute &attribute)
43 : {
44 11256 : return Values::Attributes::FEATURE == attribute.get_path ().as_string ();
45 : }
46 :
47 : // check for empty feature, such as `#![feature], this is an error
48 : bool
49 6604 : is_valid_feature_attribute (const AST::Attribute &attribute)
50 : {
51 6604 : return !attribute.empty_input ();
52 : }
53 : } // namespace
54 :
55 : void
56 6602 : FeatureCollector::add_features_from_token_tree (
57 : const AST::DelimTokenTree &delim_ttree)
58 : {
59 6602 : std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
60 6602 : delim_ttree.parse_to_meta_item ());
61 6602 : add_features_from_meta_item_container (*meta_item);
62 6602 : }
63 :
64 : void
65 6603 : FeatureCollector::add_features_from_meta_item_container (
66 : const AST::AttrInputMetaItemContainer &meta_item_container)
67 : {
68 13377 : for (const auto &item : meta_item_container.get_items ())
69 : {
70 6774 : const auto &name_str = item->as_string ();
71 :
72 : // TODO: detect duplicates
73 6774 : if (auto tname = Feature::as_name (name_str))
74 6769 : features.valid_lang_features.insert (*tname);
75 : else
76 5 : features.valid_lib_features.emplace (name_str, item->get_locus ());
77 6774 : }
78 6603 : }
79 :
80 : void
81 11256 : FeatureCollector::identify_feature (const AST::Attribute &attribute)
82 : {
83 11256 : if (is_feature_attribute (attribute))
84 : {
85 6604 : if (!is_valid_feature_attribute (attribute))
86 : {
87 1 : rust_error_at (attribute.get_locus (), ErrorCode::E0556,
88 : "malformed %<feature%> attribute input");
89 1 : return;
90 : }
91 6603 : const auto &attr_input = attribute.get_attr_input ();
92 6603 : auto type = attr_input.get_attr_input_type ();
93 6603 : if (type == AST::AttrInput::AttrInputType::TOKEN_TREE)
94 : {
95 6602 : const auto &delim_ttree = static_cast<const AST::DelimTokenTree &> (
96 6602 : attribute.get_attr_input ());
97 6602 : add_features_from_token_tree (delim_ttree);
98 : }
99 1 : else if (type == AST::AttrInput::AttrInputType::META_ITEM)
100 : {
101 : // We can find a meta item in #[cfg(toto),feature(xxxx)]
102 1 : const auto &meta_item_container
103 : = static_cast<const AST::AttrInputMetaItemContainer &> (attr_input);
104 1 : add_features_from_meta_item_container (meta_item_container);
105 : }
106 : }
107 : }
108 :
109 : void
110 4522 : FeatureCollector::visit (AST::Crate &crate)
111 : {
112 15778 : for (const auto &attribute : crate.inner_attrs)
113 11256 : identify_feature (attribute);
114 4522 : }
115 :
116 : } // namespace Features
117 : } // namespace Rust
|