Line data Source code
1 : // Copyright (C) 2020-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-gate.h"
20 : #include "rust-abi.h"
21 : #include "rust-attribute-values.h"
22 : #include "rust-attributes.h"
23 : #include "rust-ast-visitor.h"
24 : #include "rust-feature.h"
25 : #include "rust-ast-full.h"
26 : #include "rust-feature-store.h"
27 :
28 : namespace Rust {
29 :
30 : void
31 4521 : FeatureGate::check (AST::Crate &crate)
32 : {
33 4521 : auto &store = Features::EarlyFeatureGateStore::get ();
34 9046 : while (store.has_error ())
35 : {
36 4 : auto pair = store.get_error ();
37 4 : gate (pair.first, pair.second.locus, pair.second.message);
38 4 : }
39 4521 : visit (crate);
40 4521 : }
41 :
42 : void
43 4521 : FeatureGate::visit (AST::Crate &crate)
44 : {
45 4521 : AST::DefaultASTVisitor::visit (crate);
46 :
47 4526 : for (auto &ent : features.valid_lib_features)
48 : {
49 5 : const std::string &feature = ent.first;
50 5 : location_t locus = ent.second;
51 :
52 : // rustc treats these as valid,
53 : // but apparently has special handling for them
54 5 : if (feature == "libc" || feature == "test")
55 0 : continue;
56 :
57 5 : if (defined_lib_features.find (feature) != defined_lib_features.end ())
58 : {
59 : // TODO: emit warning if stable
60 0 : continue;
61 : }
62 :
63 5 : rust_error_at (locus, ErrorCode::E0635, "unknown feature %qs",
64 : feature.c_str ());
65 : }
66 4521 : check_no_core_attribute (crate.inner_attrs);
67 4521 : }
68 :
69 : void
70 8370 : FeatureGate::gate (Feature::Name name, location_t loc,
71 : const std::string &error_msg)
72 : {
73 8370 : if (!features.valid_lang_features.count (name))
74 : {
75 16 : auto &feature = Feature::lookup (name);
76 16 : if (auto issue = feature.issue ())
77 : {
78 10 : auto issue_number = issue.value ();
79 10 : const char *fmt_str
80 : = "%s. see issue %u "
81 : "<https://github.com/rust-lang/rust/issues/%u> for more "
82 : "information. add `#![feature(%s)]` to the crate attributes to "
83 : "enable.";
84 10 : rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
85 : issue_number, issue_number,
86 10 : feature.as_string ().c_str ());
87 : }
88 : else
89 : {
90 6 : const char *fmt_str
91 : = "%s. add `#![feature(%s)]` to the crate attributes to enable.";
92 6 : rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
93 6 : feature.as_string ().c_str ());
94 : }
95 : }
96 8370 : }
97 :
98 : void
99 1473 : FeatureGate::visit (AST::ExternBlock &block)
100 : {
101 1473 : if (block.has_abi ())
102 : {
103 1473 : const auto abi = block.get_abi ();
104 :
105 1473 : if (get_abi_from_string (abi) == ABI::INTRINSIC)
106 411 : gate (Feature::Name::INTRINSICS, block.get_locus (),
107 822 : "intrinsics are subject to change");
108 1473 : }
109 1473 : AST::DefaultASTVisitor::visit (block);
110 1473 : }
111 :
112 : void
113 4521 : FeatureGate::check_no_core_attribute (
114 : const std::vector<AST::Attribute> &attributes)
115 : {
116 15772 : for (const AST::Attribute &attr : attributes)
117 : {
118 11251 : if (attr.get_path ().as_string () == Values::Attributes::NO_CORE)
119 4522 : gate (Feature::Name::NO_CORE, attr.get_locus (),
120 9044 : "no_core is experimental");
121 : }
122 4521 : }
123 :
124 : void
125 17057 : FeatureGate::check_rustc_attri (const std::vector<AST::Attribute> &attributes)
126 : {
127 27150 : for (const AST::Attribute &attr : attributes)
128 : {
129 10093 : auto name = attr.get_path ().as_string ();
130 10093 : if (name.rfind ("rustc_", 0) == 0)
131 : {
132 264 : gate (Feature::Name::RUSTC_ATTRS, attr.get_locus (),
133 528 : "internal implementation detail");
134 : }
135 10093 : }
136 17057 : }
137 :
138 : void
139 8513 : FeatureGate::check_may_dangle_attribute (
140 : const std::vector<AST::Attribute> &attributes)
141 : {
142 8518 : for (const AST::Attribute &attr : attributes)
143 : {
144 5 : if (attr.get_path ().as_string () == Values::Attributes::MAY_DANGLE)
145 5 : gate (Feature::Name::DROPCK_EYEPATCH, attr.get_locus (),
146 10 : "`may_dangle` has unstable semantics and may be removed in the "
147 : "future");
148 : }
149 8513 : }
150 :
151 : void
152 25379 : FeatureGate::check_lang_item_attribute (
153 : const std::vector<AST::Attribute> &attributes)
154 : {
155 40103 : for (const AST::Attribute &attr : attributes)
156 : {
157 14724 : const auto &str_path = attr.get_path ().as_string ();
158 14724 : bool is_lang_item = str_path == Values::Attributes::LANG
159 3111 : && attr.has_attr_input ()
160 17835 : && attr.get_attr_input ().get_attr_input_type ()
161 14724 : == AST::AttrInput::AttrInputType::LITERAL;
162 :
163 3111 : if (is_lang_item)
164 3111 : gate (Feature::Name::LANG_ITEMS, attr.get_locus (),
165 6222 : "lang items are subject to change");
166 14724 : }
167 25379 : }
168 :
169 : void
170 19272 : FeatureGate::note_stability_attribute (
171 : const std::vector<AST::Attribute> &attributes)
172 : {
173 29536 : for (const AST::Attribute &attr : attributes)
174 : {
175 10264 : std::string attr_name = attr.get_path ().as_string ();
176 :
177 10264 : Stability stability;
178 :
179 10264 : if (attr_name == Values::Attributes::STABLE)
180 643 : stability = Stability::STABLE;
181 9621 : else if (attr_name == Values::Attributes::UNSTABLE)
182 100 : stability = Stability::UNSTABLE;
183 9521 : else if (attr_name == Values::Attributes::RUSTC_CONST_STABLE)
184 158 : stability = Stability::STABLE;
185 9363 : else if (attr_name == Values::Attributes::RUSTC_CONST_UNSTABLE)
186 8 : stability = Stability::UNSTABLE;
187 : else
188 9355 : continue;
189 :
190 909 : if (attr.empty_input ())
191 : // TODO: error?
192 0 : continue;
193 :
194 909 : auto &attr_input = attr.get_attr_input ();
195 909 : if (attr_input.get_attr_input_type ()
196 : != AST::AttrInput::AttrInputType::TOKEN_TREE)
197 : // TODO: error?
198 0 : continue;
199 :
200 909 : std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
201 : static_cast<const AST::DelimTokenTree &> (attr_input)
202 909 : .parse_to_meta_item ());
203 :
204 2727 : for (auto &item : meta_item->get_items ())
205 : {
206 : // TODO: more thorough error checking?
207 : // ~only the standard libraries should ever exercise this
208 1818 : if (item->is_key_value_pair ())
209 : {
210 1818 : auto &pair = static_cast<const AST::MetaNameValueStr &> (*item);
211 1818 : if (pair.get_name ().as_string () == "feature")
212 909 : defined_lib_features.emplace (pair.get_value (), stability);
213 : }
214 : }
215 10264 : }
216 19272 : }
217 :
218 : void
219 971 : FeatureGate::visit (AST::MacroRulesDefinition &rules_def)
220 : {
221 971 : check_rustc_attri (rules_def.get_outer_attrs ());
222 971 : note_stability_attribute (rules_def.get_outer_attrs ());
223 971 : }
224 :
225 : void
226 18301 : FeatureGate::visit (AST::Function &function)
227 : {
228 18301 : if (!function.is_external ())
229 16086 : check_rustc_attri (function.get_outer_attrs ());
230 :
231 18301 : check_lang_item_attribute (function.get_outer_attrs ());
232 :
233 18301 : note_stability_attribute (function.get_outer_attrs ());
234 :
235 18301 : AST::DefaultASTVisitor::visit (function);
236 18301 : }
237 :
238 : void
239 1 : FeatureGate::visit (AST::ExternalTypeItem &item)
240 : {
241 : // TODO(mxlol233): The gating needs a complete visiting chain to activate
242 : // `AST::ExternalTypeItem`.
243 1 : gate (Feature::Name::EXTERN_TYPES, item.get_locus (),
244 1 : "extern types are experimental");
245 1 : }
246 :
247 : void
248 4739 : FeatureGate::visit (AST::TraitImpl &impl)
249 : {
250 4739 : if (impl.is_exclam ())
251 6 : gate (Feature::Name::NEGATIVE_IMPLS, impl.get_locus (),
252 12 : "negative_impls are not yet implemented");
253 :
254 4739 : AST::DefaultASTVisitor::visit (impl);
255 4739 : }
256 :
257 : void
258 3742 : FeatureGate::visit (AST::Trait &trait)
259 : {
260 3742 : if (trait.is_auto ())
261 20 : gate (Feature::Name::OPTIN_BUILTIN_TRAITS, trait.get_locus (),
262 40 : "auto traits are experimental and possibly buggy");
263 3742 : check_lang_item_attribute (trait.get_outer_attrs ());
264 3742 : AST::DefaultASTVisitor::visit (trait);
265 3742 : }
266 :
267 : void
268 1 : FeatureGate::visit (AST::BoxExpr &expr)
269 : {
270 1 : gate (
271 : Feature::Name::BOX_SYNTAX, expr.get_locus (),
272 1 : "box expression syntax is experimental; you can call `Box::new` instead");
273 1 : AST::DefaultASTVisitor::visit (expr);
274 1 : }
275 :
276 : void
277 277 : FeatureGate::visit (AST::LifetimeParam &lifetime_param)
278 : {
279 277 : check_may_dangle_attribute (lifetime_param.get_outer_attrs ());
280 277 : AST::DefaultASTVisitor::visit (lifetime_param);
281 277 : }
282 :
283 : void
284 97 : FeatureGate::visit (AST::ConstGenericParam &const_param)
285 : {
286 97 : check_may_dangle_attribute (const_param.get_outer_attrs ());
287 97 : AST::DefaultASTVisitor::visit (const_param);
288 97 : }
289 :
290 : void
291 8139 : FeatureGate::visit (AST::TypeParam ¶m)
292 : {
293 8139 : check_may_dangle_attribute (param.get_outer_attrs ());
294 8139 : AST::DefaultASTVisitor::visit (param);
295 8139 : }
296 :
297 : void
298 1929 : FeatureGate::visit (AST::BorrowExpr &expr)
299 : {
300 1929 : if (expr.is_raw_borrow ())
301 5 : gate (Feature::Name::RAW_REF_OP, expr.get_locus (),
302 10 : "raw address of syntax is experimental");
303 1929 : }
304 :
305 : void
306 51 : FeatureGate::visit (AST::RangePattern &pattern)
307 : {
308 51 : if (pattern.get_range_kind () == AST::RangeKind::EXCLUDED)
309 20 : gate (Feature::Name::EXCLUSIVE_RANGE_PATTERN, pattern.get_locus (),
310 40 : "exclusive range pattern syntax is experimental");
311 51 : }
312 :
313 : void
314 12 : FeatureGate::visit (AST::UseTreeGlob &use)
315 : {
316 : // At the moment, UseTrees do not have outer attributes, but they should. we
317 : // need to eventually gate `#[prelude_import]` on use-trees based on the
318 : // #[feature(prelude_import)]
319 12 : }
320 :
321 : void
322 1598 : FeatureGate::visit (AST::StructStruct &struct_item)
323 : {
324 1598 : check_lang_item_attribute (struct_item.get_outer_attrs ());
325 1598 : AST::DefaultASTVisitor::visit (struct_item);
326 1598 : }
327 :
328 : void
329 738 : FeatureGate::visit (AST::TraitItemType &trait_item_type)
330 : {
331 738 : check_lang_item_attribute (trait_item_type.get_outer_attrs ());
332 738 : AST::DefaultASTVisitor::visit (trait_item_type);
333 738 : }
334 :
335 : void
336 544 : FeatureGate::visit (AST::Enum &enum_item)
337 : {
338 544 : check_lang_item_attribute (enum_item.get_outer_attrs ());
339 544 : AST::DefaultASTVisitor::visit (enum_item);
340 544 : }
341 :
342 : void
343 456 : FeatureGate::visit (AST::EnumItem &enum_variant)
344 : {
345 456 : check_lang_item_attribute (enum_variant.get_outer_attrs ());
346 456 : AST::DefaultASTVisitor::visit (enum_variant);
347 456 : }
348 :
349 : } // namespace Rust
|