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 5049 : FeatureGate::check (AST::Crate &crate)
32 : {
33 5049 : auto &store = Features::EarlyFeatureGateStore::get ();
34 10101 : while (store.has_error ())
35 : {
36 3 : auto pair = store.get_error ();
37 3 : gate (pair.first, pair.second.locus, pair.second.message);
38 3 : }
39 5049 : visit (crate);
40 5049 : }
41 :
42 : void
43 5049 : FeatureGate::visit (AST::Crate &crate)
44 : {
45 5049 : AST::DefaultASTVisitor::visit (crate);
46 :
47 5089 : for (auto &ent : features.valid_lib_features)
48 : {
49 40 : const std::string &feature = ent.first;
50 40 : location_t locus = ent.second;
51 :
52 : // rustc treats these as valid,
53 : // but apparently has special handling for them
54 40 : if (feature == "libc" || feature == "test")
55 0 : continue;
56 :
57 40 : if (defined_lib_features.find (feature) != defined_lib_features.end ())
58 : {
59 : // TODO: emit warning if stable
60 35 : continue;
61 : }
62 :
63 5 : rust_error_at (locus, ErrorCode::E0635, "unknown feature %qs",
64 : feature.c_str ());
65 : }
66 17994 : for (const auto &attribute : crate.inner_attrs)
67 : {
68 12945 : check_no_core_attribute (attribute);
69 :
70 25890 : if (attribute.get_path ().as_string ()
71 12945 : == Values::Attributes::COMPILER_BUILTINS)
72 1 : gate (Feature::Name::COMPILER_BUILTINS, attribute.get_locus (),
73 2 : "the #[compiler_builtins] attribute is used to identify the "
74 : "compiler_builtins crate which contains compiler-rt intrinsics "
75 : "and will never be stable");
76 : }
77 5049 : }
78 :
79 : FeatureGate::GateResult
80 13198 : FeatureGate::gate (Feature::Name name, location_t loc,
81 : const std::string &error_msg)
82 : {
83 13198 : if (!features.valid_lang_features.count (name))
84 : {
85 22 : auto &feature = Feature::lookup (name);
86 22 : if (auto issue = feature.issue ())
87 : {
88 13 : auto issue_number = issue.value ();
89 13 : 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 13 : rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
95 : issue_number, issue_number,
96 13 : feature.as_string ().c_str ());
97 : }
98 : else
99 : {
100 9 : const char *fmt_str
101 : = "%s. add `#![feature(%s)]` to the crate attributes to enable.";
102 9 : rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
103 9 : feature.as_string ().c_str ());
104 : }
105 :
106 22 : return GateResult::Gated;
107 : }
108 :
109 : return GateResult::Allowed;
110 : }
111 :
112 : void
113 1784 : FeatureGate::visit (AST::ExternBlock &block)
114 : {
115 1784 : if (block.has_abi ())
116 : {
117 1783 : const auto abi = block.get_abi ();
118 :
119 1783 : if (get_abi_from_string (abi) == ABI::INTRINSIC)
120 608 : gate (Feature::Name::INTRINSICS, block.get_locus (),
121 1216 : "intrinsics are subject to change");
122 1783 : }
123 1784 : AST::DefaultASTVisitor::visit (block);
124 1784 : }
125 :
126 : void
127 24 : FeatureGate::check_used_attribute (const AST::Attribute &attribute)
128 : {
129 24 : if (attribute.get_path ().as_string () == Values::Attributes::USED)
130 11 : if (attribute.has_attr_input ())
131 7 : gate (Feature::Name::USED_WITH_ARG, attribute.get_locus (),
132 14 : "malformed #[used] attribute input");
133 24 : }
134 :
135 : void
136 12945 : FeatureGate::check_no_core_attribute (const AST::Attribute &attribute)
137 : {
138 12945 : if (attribute.get_path ().as_string () == Values::Attributes::NO_CORE)
139 5050 : gate (Feature::Name::NO_CORE, attribute.get_locus (),
140 10100 : "no_core is experimental");
141 12945 : }
142 :
143 : void
144 33312 : FeatureGate::check_rustc_attri (const std::vector<AST::Attribute> &attributes)
145 : {
146 104824 : for (const AST::Attribute &attr : attributes)
147 : {
148 71512 : auto name = attr.get_path ().as_string ();
149 71512 : if (name.rfind ("rustc_", 0) == 0)
150 : {
151 2712 : gate (Feature::Name::RUSTC_ATTRS, attr.get_locus (),
152 5424 : "internal implementation detail");
153 : }
154 71512 : }
155 33312 : }
156 :
157 : void
158 21118 : FeatureGate::check_may_dangle_attribute (
159 : const std::vector<AST::Attribute> &attributes)
160 : {
161 21134 : for (const AST::Attribute &attr : attributes)
162 : {
163 16 : if (attr.get_path ().as_string () == Values::Attributes::MAY_DANGLE)
164 15 : gate (Feature::Name::DROPCK_EYEPATCH, attr.get_locus (),
165 30 : "`may_dangle` has unstable semantics and may be removed in the "
166 : "future");
167 : }
168 21118 : }
169 :
170 : void
171 44392 : FeatureGate::check_lang_item_attribute (
172 : const std::vector<AST::Attribute> &attributes)
173 : {
174 130858 : for (const AST::Attribute &attr : attributes)
175 : {
176 86466 : const auto &str_path = attr.get_path ().as_string ();
177 86466 : bool is_lang_item = str_path == Values::Attributes::LANG
178 3769 : && attr.has_attr_input ()
179 90235 : && attr.get_attr_input ().get_attr_input_type ()
180 86466 : == AST::AttrInput::AttrInputType::LITERAL;
181 :
182 3769 : if (is_lang_item)
183 3769 : gate (Feature::Name::LANG_ITEMS, attr.get_locus (),
184 7538 : "lang items are subject to change");
185 86466 : }
186 44392 : }
187 :
188 : void
189 36858 : FeatureGate::note_stability_attribute (
190 : const std::vector<AST::Attribute> &attributes)
191 : {
192 110502 : for (const AST::Attribute &attr : attributes)
193 : {
194 73644 : std::string attr_name = attr.get_path ().as_string ();
195 :
196 73644 : Stability stability;
197 :
198 73644 : if (attr_name == Values::Attributes::STABLE)
199 3530 : stability = Stability::STABLE;
200 70114 : else if (attr_name == Values::Attributes::UNSTABLE)
201 694 : stability = Stability::UNSTABLE;
202 69420 : else if (attr_name == Values::Attributes::RUSTC_CONST_STABLE)
203 915 : stability = Stability::STABLE;
204 68505 : else if (attr_name == Values::Attributes::RUSTC_CONST_UNSTABLE)
205 410 : stability = Stability::UNSTABLE;
206 : else
207 68095 : continue;
208 :
209 5549 : if (attr.empty_input ())
210 : // TODO: error?
211 0 : continue;
212 :
213 5549 : auto &attr_input = attr.get_attr_input ();
214 5549 : if (attr_input.get_attr_input_type ()
215 : != AST::AttrInput::AttrInputType::TOKEN_TREE)
216 : // TODO: error?
217 0 : continue;
218 :
219 5549 : std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
220 : static_cast<const AST::DelimTokenTree &> (attr_input)
221 5549 : .parse_to_meta_item ());
222 :
223 16781 : for (auto &item : meta_item->get_items ())
224 : {
225 : // TODO: more thorough error checking?
226 : // ~only the standard libraries should ever exercise this
227 11232 : if (item->is_key_value_pair ())
228 : {
229 11231 : auto &pair = static_cast<const AST::MetaNameValueStr &> (*item);
230 11231 : if (pair.get_name ().as_string () == "feature")
231 5549 : defined_lib_features.emplace (pair.get_value (), stability);
232 : }
233 : }
234 73644 : }
235 36858 : }
236 :
237 : void
238 1815 : FeatureGate::visit (AST::MacroRulesDefinition &rules_def)
239 : {
240 1815 : check_rustc_attri (rules_def.get_outer_attrs ());
241 1815 : note_stability_attribute (rules_def.get_outer_attrs ());
242 1815 : }
243 :
244 : void
245 35043 : FeatureGate::visit (AST::Function &function)
246 : {
247 35043 : if (!function.is_external ())
248 31497 : check_rustc_attri (function.get_outer_attrs ());
249 :
250 107171 : for (const AST::Attribute &attr : function.get_outer_attrs ())
251 : {
252 72128 : if (attr.get_path ().as_string () == "rustc_const_stable")
253 : {
254 915 : gate (Feature::Name::STAGED_API, attr.get_locus (),
255 1830 : "stability attributes may not be used outside of the standard "
256 : "library");
257 : }
258 : }
259 :
260 35043 : check_lang_item_attribute (function.get_outer_attrs ());
261 :
262 35043 : note_stability_attribute (function.get_outer_attrs ());
263 :
264 35043 : AST::DefaultASTVisitor::visit (function);
265 35043 : }
266 :
267 : void
268 5 : FeatureGate::visit (AST::ExternalTypeItem &item)
269 : {
270 : // TODO(mxlol233): The gating needs a complete visiting chain to activate
271 : // `AST::ExternalTypeItem`.
272 5 : gate (Feature::Name::EXTERN_TYPES, item.get_locus (),
273 5 : "extern types are experimental");
274 :
275 5 : AST::DefaultASTVisitor::visit (item);
276 5 : }
277 :
278 : void
279 13182 : FeatureGate::visit (AST::TraitImpl &impl)
280 : {
281 13182 : if (impl.is_exclam ())
282 26 : gate (Feature::Name::NEGATIVE_IMPLS, impl.get_locus (),
283 52 : "negative_impls are not yet implemented");
284 :
285 13182 : AST::DefaultASTVisitor::visit (impl);
286 13182 : }
287 :
288 : void
289 4546 : FeatureGate::visit (AST::Trait &trait)
290 : {
291 4546 : if (trait.is_auto ())
292 30 : gate (Feature::Name::OPTIN_BUILTIN_TRAITS, trait.get_locus (),
293 60 : "auto traits are experimental and possibly buggy");
294 4546 : check_lang_item_attribute (trait.get_outer_attrs ());
295 4546 : AST::DefaultASTVisitor::visit (trait);
296 4546 : }
297 :
298 : void
299 19 : FeatureGate::visit (AST::BoxExpr &expr)
300 : {
301 19 : gate (
302 : Feature::Name::BOX_SYNTAX, expr.get_locus (),
303 19 : "box expression syntax is experimental; you can call `Box::new` instead");
304 19 : AST::DefaultASTVisitor::visit (expr);
305 19 : }
306 :
307 : void
308 1860 : FeatureGate::visit (AST::LifetimeParam &lifetime_param)
309 : {
310 1860 : check_may_dangle_attribute (lifetime_param.get_outer_attrs ());
311 1860 : AST::DefaultASTVisitor::visit (lifetime_param);
312 1860 : }
313 :
314 : void
315 203 : FeatureGate::visit (AST::ConstGenericParam &const_param)
316 : {
317 203 : check_may_dangle_attribute (const_param.get_outer_attrs ());
318 203 : AST::DefaultASTVisitor::visit (const_param);
319 203 : }
320 :
321 : void
322 19055 : FeatureGate::visit (AST::TypeParam ¶m)
323 : {
324 19055 : check_may_dangle_attribute (param.get_outer_attrs ());
325 19055 : AST::DefaultASTVisitor::visit (param);
326 19055 : }
327 :
328 : void
329 5683 : FeatureGate::visit (AST::BorrowExpr &expr)
330 : {
331 5683 : if (expr.is_raw_borrow ())
332 11 : gate (Feature::Name::RAW_REF_OP, expr.get_locus (),
333 22 : "raw address of syntax is experimental");
334 5683 : }
335 :
336 : void
337 131 : FeatureGate::visit (AST::RangePattern &pattern)
338 : {
339 131 : if (pattern.get_range_kind () == AST::RangeKind::EXCLUDED)
340 23 : gate (Feature::Name::EXCLUSIVE_RANGE_PATTERN, pattern.get_locus (),
341 46 : "exclusive range pattern syntax is experimental");
342 131 : }
343 :
344 : void
345 128 : FeatureGate::visit (AST::UseTreeGlob &use)
346 : {
347 : // At the moment, UseTrees do not have outer attributes, but they should. we
348 : // need to eventually gate `#[prelude_import]` on use-trees based on the
349 : // #[feature(prelude_import)]
350 128 : }
351 :
352 : void
353 2646 : FeatureGate::visit (AST::StructStruct &struct_item)
354 : {
355 2646 : check_lang_item_attribute (struct_item.get_outer_attrs ());
356 2646 : AST::DefaultASTVisitor::visit (struct_item);
357 2646 : }
358 :
359 : void
360 901 : FeatureGate::visit (AST::TraitItemType &trait_item_type)
361 : {
362 901 : check_lang_item_attribute (trait_item_type.get_outer_attrs ());
363 901 : AST::DefaultASTVisitor::visit (trait_item_type);
364 901 : }
365 :
366 : void
367 665 : FeatureGate::visit (AST::Enum &enum_item)
368 : {
369 665 : check_lang_item_attribute (enum_item.get_outer_attrs ());
370 665 : AST::DefaultASTVisitor::visit (enum_item);
371 665 : }
372 :
373 : void
374 591 : FeatureGate::visit (AST::EnumItem &enum_variant)
375 : {
376 591 : check_lang_item_attribute (enum_variant.get_outer_attrs ());
377 591 : AST::DefaultASTVisitor::visit (enum_variant);
378 591 : }
379 : void
380 132 : FeatureGate::visit (AST::StaticItem &static_item)
381 : {
382 156 : for (const auto &attr : static_item.get_outer_attrs ())
383 24 : check_used_attribute (attr);
384 :
385 132 : AST::DefaultASTVisitor::visit (static_item);
386 132 : }
387 :
388 : void
389 2 : FeatureGate::visit (AST::TraitAlias &trait_alias)
390 : {
391 2 : gate (Feature::Name::TRAIT_ALIAS, trait_alias.get_locus (),
392 2 : "trait aliases are experimental");
393 :
394 2 : AST::DefaultASTVisitor::visit (trait_alias);
395 2 : }
396 :
397 : void
398 114598 : FeatureGate::visit (AST::Attribute &attr)
399 : {
400 114598 : if (attr.get_path ().as_string () == "cfi_encoding")
401 2 : if (gate (Feature::Name::CFI_ENCODING, attr.get_locus (),
402 4 : "#[cfi_encoding] is an experimental feature")
403 2 : == GateResult::Allowed)
404 1 : rust_warning_at (
405 : attr.get_locus (), 0,
406 : "the %<#[cfi_encoding]%> attribute is currently ignored and "
407 : "does nothing - we are waiting on a patchset to land "
408 : "into GCC as the KCFI functionality is not present yet");
409 :
410 114598 : AST::DefaultASTVisitor::visit (attr);
411 114598 : }
412 :
413 : } // namespace Rust
|