Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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-gate.h"
20 : : #include "rust-abi.h"
21 : : #include "rust-attribute-values.h"
22 : : #include "rust-ast-visitor.h"
23 : : #include "rust-feature.h"
24 : : #include "rust-ast-full.h"
25 : :
26 : : namespace Rust {
27 : :
28 : : void
29 : 4911 : FeatureGate::check (AST::Crate &crate)
30 : : {
31 : 4911 : visit (crate);
32 : 4911 : }
33 : :
34 : : void
35 : 4911 : FeatureGate::visit (AST::Crate &crate)
36 : : {
37 : 4911 : valid_features.clear ();
38 : :
39 : 5720 : for (const auto &attr : crate.inner_attrs)
40 : : {
41 : 809 : if (attr.get_path ().as_string () == "feature")
42 : : {
43 : : // check for empty feature, such as `#![feature], this is an error
44 : 647 : if (attr.empty_input ())
45 : : {
46 : 2 : rust_error_at (attr.get_locus (), ErrorCode::E0556,
47 : : "malformed %<feature%> attribute input");
48 : 2 : continue;
49 : : }
50 : 645 : const auto &attr_input = attr.get_attr_input ();
51 : 645 : auto type = attr_input.get_attr_input_type ();
52 : 645 : if (type == AST::AttrInput::AttrInputType::TOKEN_TREE)
53 : : {
54 : 645 : const auto &option = static_cast<const AST::DelimTokenTree &> (
55 : 645 : attr.get_attr_input ());
56 : 645 : std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
57 : 645 : option.parse_to_meta_item ());
58 : 1290 : for (const auto &item : meta_item->get_items ())
59 : : {
60 : 645 : const auto &name_str = item->as_string ();
61 : 645 : auto tname = Feature::as_name (name_str);
62 : 645 : if (tname.has_value ())
63 : : {
64 : 639 : auto name = tname.value ();
65 : 639 : valid_features.insert (name);
66 : : }
67 : :
68 : : else
69 : 6 : rust_error_at (item->get_locus (), ErrorCode::E0635,
70 : : "unknown feature %qs", name_str.c_str ());
71 : 645 : }
72 : 645 : }
73 : : }
74 : : }
75 : :
76 : 4911 : AST::DefaultASTVisitor::visit (crate);
77 : 4911 : }
78 : :
79 : : void
80 : 629 : FeatureGate::gate (Feature::Name name, location_t loc,
81 : : const std::string &error_msg)
82 : : {
83 : 629 : if (!valid_features.count (name))
84 : : {
85 : 22 : auto feature = Feature::create (name);
86 : 22 : if (auto issue = feature.issue ())
87 : : {
88 : 14 : auto issue_number = issue.value ();
89 : 14 : const char *fmt_str
90 : : = "%s. see issue %u "
91 : : "<https://github.com/rust-lang/rust/issues/%u> for more "
92 : : "information. add `#![feature(%s)]` to the crate attributes to "
93 : : "enable.";
94 : 14 : rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
95 : : issue_number, issue_number,
96 : 14 : feature.as_string ().c_str ());
97 : : }
98 : : else
99 : : {
100 : 8 : const char *fmt_str
101 : : = "%s. add `#![feature(%s)]` to the crate attributes to enable.";
102 : 8 : rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
103 : 8 : feature.as_string ().c_str ());
104 : : }
105 : 22 : }
106 : 629 : }
107 : :
108 : : void
109 : 1278 : FeatureGate::visit (AST::ExternBlock &block)
110 : : {
111 : 1278 : if (block.has_abi ())
112 : : {
113 : 1278 : const auto abi = block.get_abi ();
114 : :
115 : 1278 : if (get_abi_from_string (abi) == ABI::INTRINSIC)
116 : 361 : gate (Feature::Name::INTRINSICS, block.get_locus (),
117 : : "intrinsics are subject to change");
118 : 1278 : }
119 : 1278 : AST::DefaultASTVisitor::visit (block);
120 : 1278 : }
121 : :
122 : : void
123 : 15978 : FeatureGate::check_rustc_attri (const std::vector<AST::Attribute> &attributes)
124 : : {
125 : 17555 : for (const AST::Attribute &attr : attributes)
126 : : {
127 : 1577 : auto name = attr.get_path ().as_string ();
128 : 1577 : if (name.rfind ("rustc_", 0) == 0)
129 : : {
130 : 190 : gate (Feature::Name::RUSTC_ATTRS, attr.get_locus (),
131 : : "internal implementation detail");
132 : : }
133 : 1577 : }
134 : 15978 : }
135 : :
136 : : void
137 : 7875 : FeatureGate::check_may_dangle_attribute (
138 : : const std::vector<AST::Attribute> &attributes)
139 : : {
140 : 7885 : for (const AST::Attribute &attr : attributes)
141 : : {
142 : 10 : if (attr.get_path ().as_string () == Values::Attributes::MAY_DANGLE)
143 : 10 : gate (Feature::Name::DROPCK_EYEPATCH, attr.get_locus (),
144 : : "`may_dangle` has unstable semantics and may be removed in the "
145 : : "future");
146 : : }
147 : 7875 : }
148 : :
149 : : void
150 : 1147 : FeatureGate::visit (AST::MacroRulesDefinition &rules_def)
151 : : {
152 : 1147 : check_rustc_attri (rules_def.get_outer_attrs ());
153 : 1147 : }
154 : :
155 : : void
156 : 16935 : FeatureGate::visit (AST::Function &function)
157 : : {
158 : 16935 : if (!function.is_external ())
159 : 14831 : check_rustc_attri (function.get_outer_attrs ());
160 : :
161 : 16935 : AST::DefaultASTVisitor::visit (function);
162 : 16935 : }
163 : :
164 : : void
165 : 2 : FeatureGate::visit (AST::ExternalTypeItem &item)
166 : : {
167 : : // TODO(mxlol233): The gating needs a complete visiting chain to activate
168 : : // `AST::ExternalTypeItem`.
169 : 2 : gate (Feature::Name::EXTERN_TYPES, item.get_locus (),
170 : : "extern types are experimental");
171 : 2 : }
172 : :
173 : : void
174 : 4130 : FeatureGate::visit (AST::TraitImpl &impl)
175 : : {
176 : 4130 : if (impl.is_exclam ())
177 : 12 : gate (Feature::Name::NEGATIVE_IMPLS, impl.get_locus (),
178 : : "negative_impls are not yet implemented");
179 : :
180 : 4130 : AST::DefaultASTVisitor::visit (impl);
181 : 4130 : }
182 : :
183 : : void
184 : 3240 : FeatureGate::visit (AST::Trait &trait)
185 : : {
186 : 3240 : if (trait.is_auto ())
187 : 40 : gate (Feature::Name::AUTO_TRAITS, trait.get_locus (),
188 : : "auto traits are experimental and possibly buggy");
189 : 3240 : AST::DefaultASTVisitor::visit (trait);
190 : 3240 : }
191 : :
192 : : void
193 : 2 : FeatureGate::visit (AST::BoxExpr &expr)
194 : : {
195 : 2 : gate (
196 : : Feature::Name::BOX_SYNTAX, expr.get_locus (),
197 : : "box expression syntax is experimental; you can call `Box::new` instead");
198 : 2 : AST::DefaultASTVisitor::visit (expr);
199 : 2 : }
200 : :
201 : : void
202 : 439 : FeatureGate::visit (AST::LifetimeParam &lifetime_param)
203 : : {
204 : 439 : check_may_dangle_attribute (lifetime_param.get_outer_attrs ());
205 : 439 : AST::DefaultASTVisitor::visit (lifetime_param);
206 : 439 : }
207 : :
208 : : void
209 : 56 : FeatureGate::visit (AST::ConstGenericParam &const_param)
210 : : {
211 : 56 : check_may_dangle_attribute (const_param.get_outer_attrs ());
212 : 56 : AST::DefaultASTVisitor::visit (const_param);
213 : 56 : }
214 : :
215 : : void
216 : 7380 : FeatureGate::visit (AST::TypeParam ¶m)
217 : : {
218 : 7380 : check_may_dangle_attribute (param.get_outer_attrs ());
219 : 7380 : AST::DefaultASTVisitor::visit (param);
220 : 7380 : }
221 : :
222 : : void
223 : 1376 : FeatureGate::visit (AST::BorrowExpr &expr)
224 : : {
225 : 1376 : if (expr.is_raw_borrow ())
226 : 10 : gate (Feature::Name::RAW_REF_OP, expr.get_locus (),
227 : : "raw address of syntax is experimental");
228 : 1376 : }
229 : :
230 : : void
231 : 23 : FeatureGate::visit (AST::RangePattern &pattern)
232 : : {
233 : 23 : if (pattern.get_range_kind () == AST::RangeKind::EXCLUDED)
234 : 2 : gate (Feature::Name::EXCLUSIVE_RANGE_PATTERN, pattern.get_locus (),
235 : : "exclusive range pattern syntax is experimental");
236 : 23 : }
237 : :
238 : : void
239 : 12 : FeatureGate::visit (AST::UseTreeGlob &use)
240 : : {
241 : : // At the moment, UseTrees do not have outer attributes, but they should. we
242 : : // need to eventually gate `#[prelude_import]` on use-trees based on the
243 : : // #[feature(prelude_import)]
244 : 12 : }
245 : :
246 : : } // namespace Rust
|