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 4975 : FeatureGate::check (AST::Crate &crate)
32 : {
33 4975 : auto &store = Features::EarlyFeatureGateStore::get ();
34 11279 : while (store.has_error ())
35 : {
36 1329 : auto pair = store.get_error ();
37 1329 : gate (pair.first, pair.second.locus, pair.second.message);
38 1329 : }
39 4975 : visit (crate);
40 4975 : }
41 :
42 : void
43 4975 : FeatureGate::visit (AST::Crate &crate)
44 : {
45 4975 : AST::DefaultASTVisitor::visit (crate);
46 :
47 5015 : 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 17750 : for (const auto &attribute : crate.inner_attrs)
67 : {
68 12775 : check_no_core_attribute (attribute);
69 :
70 25550 : if (attribute.get_path ().as_string ()
71 12775 : == 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 4975 : }
78 :
79 : FeatureGate::GateResult
80 14376 : FeatureGate::gate (Feature::Name name, location_t loc,
81 : const std::string &error_msg)
82 : {
83 14376 : if (!features.valid_lang_features.count (name))
84 : {
85 20 : auto &feature = Feature::lookup (name);
86 20 : if (auto issue = feature.issue ())
87 : {
88 11 : auto issue_number = issue.value ();
89 11 : 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 11 : rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
95 : issue_number, issue_number,
96 11 : 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 20 : return GateResult::Gated;
107 : }
108 :
109 : return GateResult::Allowed;
110 : }
111 :
112 : void
113 1774 : FeatureGate::visit (AST::ExternBlock &block)
114 : {
115 1774 : if (block.has_abi ())
116 : {
117 1773 : const auto abi = block.get_abi ();
118 :
119 1773 : if (get_abi_from_string (abi) == ABI::INTRINSIC)
120 600 : gate (Feature::Name::INTRINSICS, block.get_locus (),
121 1200 : "intrinsics are subject to change");
122 1773 : }
123 1774 : AST::DefaultASTVisitor::visit (block);
124 1774 : }
125 :
126 : void
127 12775 : FeatureGate::check_no_core_attribute (const AST::Attribute &attribute)
128 : {
129 12775 : if (attribute.get_path ().as_string () == Values::Attributes::NO_CORE)
130 4976 : gate (Feature::Name::NO_CORE, attribute.get_locus (),
131 9952 : "no_core is experimental");
132 12775 : }
133 :
134 : void
135 33136 : FeatureGate::check_rustc_attri (const std::vector<AST::Attribute> &attributes)
136 : {
137 104651 : for (const AST::Attribute &attr : attributes)
138 : {
139 71515 : auto name = attr.get_path ().as_string ();
140 71515 : if (name.rfind ("rustc_", 0) == 0)
141 : {
142 2715 : gate (Feature::Name::RUSTC_ATTRS, attr.get_locus (),
143 5430 : "internal implementation detail");
144 : }
145 71515 : }
146 33136 : }
147 :
148 : void
149 20927 : FeatureGate::check_may_dangle_attribute (
150 : const std::vector<AST::Attribute> &attributes)
151 : {
152 20943 : for (const AST::Attribute &attr : attributes)
153 : {
154 16 : if (attr.get_path ().as_string () == Values::Attributes::MAY_DANGLE)
155 15 : gate (Feature::Name::DROPCK_EYEPATCH, attr.get_locus (),
156 30 : "`may_dangle` has unstable semantics and may be removed in the "
157 : "future");
158 : }
159 20927 : }
160 :
161 : void
162 44022 : FeatureGate::check_lang_item_attribute (
163 : const std::vector<AST::Attribute> &attributes)
164 : {
165 130422 : for (const AST::Attribute &attr : attributes)
166 : {
167 86400 : const auto &str_path = attr.get_path ().as_string ();
168 86400 : bool is_lang_item = str_path == Values::Attributes::LANG
169 3709 : && attr.has_attr_input ()
170 90109 : && attr.get_attr_input ().get_attr_input_type ()
171 86400 : == AST::AttrInput::AttrInputType::LITERAL;
172 :
173 3709 : if (is_lang_item)
174 3709 : gate (Feature::Name::LANG_ITEMS, attr.get_locus (),
175 7418 : "lang items are subject to change");
176 86400 : }
177 44022 : }
178 :
179 : void
180 36663 : FeatureGate::note_stability_attribute (
181 : const std::vector<AST::Attribute> &attributes)
182 : {
183 110310 : for (const AST::Attribute &attr : attributes)
184 : {
185 73647 : std::string attr_name = attr.get_path ().as_string ();
186 :
187 73647 : Stability stability;
188 :
189 73647 : if (attr_name == Values::Attributes::STABLE)
190 3530 : stability = Stability::STABLE;
191 70117 : else if (attr_name == Values::Attributes::UNSTABLE)
192 694 : stability = Stability::UNSTABLE;
193 69423 : else if (attr_name == Values::Attributes::RUSTC_CONST_STABLE)
194 915 : stability = Stability::STABLE;
195 68508 : else if (attr_name == Values::Attributes::RUSTC_CONST_UNSTABLE)
196 410 : stability = Stability::UNSTABLE;
197 : else
198 68098 : continue;
199 :
200 5549 : if (attr.empty_input ())
201 : // TODO: error?
202 0 : continue;
203 :
204 5549 : auto &attr_input = attr.get_attr_input ();
205 5549 : if (attr_input.get_attr_input_type ()
206 : != AST::AttrInput::AttrInputType::TOKEN_TREE)
207 : // TODO: error?
208 0 : continue;
209 :
210 5549 : std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
211 : static_cast<const AST::DelimTokenTree &> (attr_input)
212 5549 : .parse_to_meta_item ());
213 :
214 16781 : for (auto &item : meta_item->get_items ())
215 : {
216 : // TODO: more thorough error checking?
217 : // ~only the standard libraries should ever exercise this
218 11232 : if (item->is_key_value_pair ())
219 : {
220 11231 : auto &pair = static_cast<const AST::MetaNameValueStr &> (*item);
221 11231 : if (pair.get_name ().as_string () == "feature")
222 5549 : defined_lib_features.emplace (pair.get_value (), stability);
223 : }
224 : }
225 73647 : }
226 36663 : }
227 :
228 : void
229 1819 : FeatureGate::visit (AST::MacroRulesDefinition &rules_def)
230 : {
231 1819 : check_rustc_attri (rules_def.get_outer_attrs ());
232 1819 : note_stability_attribute (rules_def.get_outer_attrs ());
233 1819 : }
234 :
235 : void
236 34844 : FeatureGate::visit (AST::Function &function)
237 : {
238 34844 : if (!function.is_external ())
239 31317 : check_rustc_attri (function.get_outer_attrs ());
240 :
241 106972 : for (const AST::Attribute &attr : function.get_outer_attrs ())
242 : {
243 72128 : if (attr.get_path ().as_string () == "rustc_const_stable")
244 : {
245 915 : gate (Feature::Name::STAGED_API, attr.get_locus (),
246 1830 : "stability attributes may not be used outside of the standard "
247 : "library");
248 : }
249 : }
250 :
251 34844 : check_lang_item_attribute (function.get_outer_attrs ());
252 :
253 34844 : note_stability_attribute (function.get_outer_attrs ());
254 :
255 34844 : AST::DefaultASTVisitor::visit (function);
256 34844 : }
257 :
258 : void
259 5 : FeatureGate::visit (AST::ExternalTypeItem &item)
260 : {
261 : // TODO(mxlol233): The gating needs a complete visiting chain to activate
262 : // `AST::ExternalTypeItem`.
263 5 : gate (Feature::Name::EXTERN_TYPES, item.get_locus (),
264 5 : "extern types are experimental");
265 5 : }
266 :
267 : void
268 13160 : FeatureGate::visit (AST::TraitImpl &impl)
269 : {
270 13160 : if (impl.is_exclam ())
271 26 : gate (Feature::Name::NEGATIVE_IMPLS, impl.get_locus (),
272 52 : "negative_impls are not yet implemented");
273 :
274 13160 : AST::DefaultASTVisitor::visit (impl);
275 13160 : }
276 :
277 : void
278 4466 : FeatureGate::visit (AST::Trait &trait)
279 : {
280 4466 : if (trait.is_auto ())
281 30 : gate (Feature::Name::OPTIN_BUILTIN_TRAITS, trait.get_locus (),
282 60 : "auto traits are experimental and possibly buggy");
283 4466 : check_lang_item_attribute (trait.get_outer_attrs ());
284 4466 : AST::DefaultASTVisitor::visit (trait);
285 4466 : }
286 :
287 : void
288 19 : FeatureGate::visit (AST::BoxExpr &expr)
289 : {
290 19 : gate (
291 : Feature::Name::BOX_SYNTAX, expr.get_locus (),
292 19 : "box expression syntax is experimental; you can call `Box::new` instead");
293 19 : AST::DefaultASTVisitor::visit (expr);
294 19 : }
295 :
296 : void
297 1840 : FeatureGate::visit (AST::LifetimeParam &lifetime_param)
298 : {
299 1840 : check_may_dangle_attribute (lifetime_param.get_outer_attrs ());
300 1840 : AST::DefaultASTVisitor::visit (lifetime_param);
301 1840 : }
302 :
303 : void
304 201 : FeatureGate::visit (AST::ConstGenericParam &const_param)
305 : {
306 201 : check_may_dangle_attribute (const_param.get_outer_attrs ());
307 201 : AST::DefaultASTVisitor::visit (const_param);
308 201 : }
309 :
310 : void
311 18886 : FeatureGate::visit (AST::TypeParam ¶m)
312 : {
313 18886 : check_may_dangle_attribute (param.get_outer_attrs ());
314 18886 : AST::DefaultASTVisitor::visit (param);
315 18886 : }
316 :
317 : void
318 5678 : FeatureGate::visit (AST::BorrowExpr &expr)
319 : {
320 5678 : if (expr.is_raw_borrow ())
321 11 : gate (Feature::Name::RAW_REF_OP, expr.get_locus (),
322 22 : "raw address of syntax is experimental");
323 5678 : }
324 :
325 : void
326 131 : FeatureGate::visit (AST::RangePattern &pattern)
327 : {
328 131 : if (pattern.get_range_kind () == AST::RangeKind::EXCLUDED)
329 23 : gate (Feature::Name::EXCLUSIVE_RANGE_PATTERN, pattern.get_locus (),
330 46 : "exclusive range pattern syntax is experimental");
331 131 : }
332 :
333 : void
334 128 : FeatureGate::visit (AST::UseTreeGlob &use)
335 : {
336 : // At the moment, UseTrees do not have outer attributes, but they should. we
337 : // need to eventually gate `#[prelude_import]` on use-trees based on the
338 : // #[feature(prelude_import)]
339 128 : }
340 :
341 : void
342 2603 : FeatureGate::visit (AST::StructStruct &struct_item)
343 : {
344 2603 : check_lang_item_attribute (struct_item.get_outer_attrs ());
345 2603 : AST::DefaultASTVisitor::visit (struct_item);
346 2603 : }
347 :
348 : void
349 880 : FeatureGate::visit (AST::TraitItemType &trait_item_type)
350 : {
351 880 : check_lang_item_attribute (trait_item_type.get_outer_attrs ());
352 880 : AST::DefaultASTVisitor::visit (trait_item_type);
353 880 : }
354 :
355 : void
356 651 : FeatureGate::visit (AST::Enum &enum_item)
357 : {
358 651 : check_lang_item_attribute (enum_item.get_outer_attrs ());
359 651 : AST::DefaultASTVisitor::visit (enum_item);
360 651 : }
361 :
362 : void
363 578 : FeatureGate::visit (AST::EnumItem &enum_variant)
364 : {
365 578 : check_lang_item_attribute (enum_variant.get_outer_attrs ());
366 578 : AST::DefaultASTVisitor::visit (enum_variant);
367 578 : }
368 :
369 : void
370 114351 : FeatureGate::visit (AST::Attribute &attr)
371 : {
372 114351 : if (attr.get_path ().as_string () == "cfi_encoding")
373 2 : if (gate (Feature::Name::CFI_ENCODING, attr.get_locus (),
374 4 : "#[cfi_encoding] is an experimental feature")
375 2 : == GateResult::Allowed)
376 1 : rust_warning_at (
377 : attr.get_locus (), 0,
378 : "the %<#[cfi_encoding]%> attribute is currently ignored and "
379 : "does nothing - we are waiting on a patchset to land "
380 : "into GCC as the KCFI functionality is not present yet");
381 :
382 114351 : AST::DefaultASTVisitor::visit (attr);
383 114351 : }
384 :
385 : } // namespace Rust
|