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