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 : #include "rust-session-manager.h"
22 :
23 : namespace Rust {
24 : namespace Features {
25 :
26 5050 : FeatureCollector::FeatureCollector () : features (CrateFeatures{UNKNOWN_NODEID})
27 5050 : {}
28 :
29 : CrateFeatures
30 5050 : FeatureCollector::collect (AST::Crate &crate)
31 : {
32 5050 : features.valid_lang_features.clear ();
33 5050 : features.valid_lib_features.clear ();
34 5050 : features.crate_id = crate.get_node_id ();
35 :
36 5050 : visit (crate);
37 :
38 5050 : return features;
39 : }
40 :
41 : namespace {
42 : bool
43 12950 : is_feature_attribute (const AST::Attribute &attribute)
44 : {
45 12950 : return Values::Attributes::FEATURE == attribute.get_path ().as_string ();
46 : }
47 :
48 : // check for empty feature, such as `#![feature], this is an error
49 : bool
50 7652 : is_valid_feature_attribute (const AST::Attribute &attribute)
51 : {
52 7652 : return !attribute.empty_input ();
53 : }
54 : } // namespace
55 :
56 : void
57 7645 : FeatureCollector::add_features_from_token_tree (
58 : const AST::DelimTokenTree &delim_ttree)
59 : {
60 7645 : std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
61 7645 : delim_ttree.parse_to_meta_item ());
62 7645 : add_features_from_meta_item_container (*meta_item);
63 7645 : }
64 :
65 : void
66 7651 : FeatureCollector::add_features_from_meta_item_container (
67 : const AST::AttrInputMetaItemContainer &meta_item_container)
68 : {
69 15769 : for (const auto &item : meta_item_container.get_items ())
70 : {
71 8118 : const auto &name_str = item->as_string ();
72 :
73 : // TODO: detect duplicates
74 8118 : if (auto tname = Feature::as_name (name_str))
75 8078 : features.valid_lang_features.insert (*tname);
76 : else
77 40 : features.valid_lib_features.emplace (name_str, item->get_locus ());
78 8118 : }
79 7651 : }
80 :
81 : void
82 12950 : FeatureCollector::identify_feature (const AST::Attribute &attribute)
83 : {
84 12950 : if (is_feature_attribute (attribute))
85 : {
86 7652 : if (!is_valid_feature_attribute (attribute))
87 : {
88 1 : rust_error_at (attribute.get_locus (), ErrorCode::E0556,
89 : "malformed %<feature%> attribute input");
90 1 : return;
91 : }
92 7651 : const auto &attr_input = attribute.get_attr_input ();
93 7651 : auto type = attr_input.get_attr_input_type ();
94 7651 : if (type == AST::AttrInput::AttrInputType::TOKEN_TREE)
95 : {
96 7645 : const auto &delim_ttree = static_cast<const AST::DelimTokenTree &> (
97 7645 : attribute.get_attr_input ());
98 7645 : add_features_from_token_tree (delim_ttree);
99 : }
100 6 : else if (type == AST::AttrInput::AttrInputType::META_ITEM)
101 : {
102 : // We can find a meta item in #[cfg(toto),feature(xxxx)]
103 6 : const auto &meta_item_container
104 : = static_cast<const AST::AttrInputMetaItemContainer &> (attr_input);
105 6 : add_features_from_meta_item_container (meta_item_container);
106 : }
107 : }
108 : }
109 :
110 : void
111 5050 : FeatureCollector::visit (AST::Crate &crate)
112 : {
113 18000 : for (const auto &attribute : crate.inner_attrs)
114 12950 : identify_feature (attribute);
115 5050 : }
116 :
117 : } // namespace Features
118 : } // namespace Rust
|