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 4844 : FeatureGate::check (AST::Crate &crate)
32 : {
33 4844 : auto &store = Features::EarlyFeatureGateStore::get ();
34 11016 : while (store.has_error ())
35 : {
36 1328 : auto pair = store.get_error ();
37 1328 : gate (pair.first, pair.second.locus, pair.second.message);
38 1328 : }
39 4844 : visit (crate);
40 4844 : }
41 :
42 : void
43 4844 : FeatureGate::visit (AST::Crate &crate)
44 : {
45 4844 : AST::DefaultASTVisitor::visit (crate);
46 :
47 4884 : 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 17205 : for (const auto &attribute : crate.inner_attrs)
67 : {
68 12361 : check_no_core_attribute (attribute);
69 :
70 24722 : if (attribute.get_path ().as_string ()
71 12361 : == 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 4844 : }
78 :
79 : void
80 13791 : FeatureGate::gate (Feature::Name name, location_t loc,
81 : const std::string &error_msg)
82 : {
83 13791 : if (!features.valid_lang_features.count (name))
84 : {
85 19 : auto &feature = Feature::lookup (name);
86 19 : if (auto issue = feature.issue ())
87 : {
88 10 : auto issue_number = issue.value ();
89 10 : 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 10 : rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
95 : issue_number, issue_number,
96 10 : 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 13791 : }
107 :
108 : void
109 1729 : FeatureGate::visit (AST::ExternBlock &block)
110 : {
111 1729 : if (block.has_abi ())
112 : {
113 1728 : const auto abi = block.get_abi ();
114 :
115 1728 : if (get_abi_from_string (abi) == ABI::INTRINSIC)
116 578 : gate (Feature::Name::INTRINSICS, block.get_locus (),
117 1156 : "intrinsics are subject to change");
118 1728 : }
119 1729 : AST::DefaultASTVisitor::visit (block);
120 1729 : }
121 :
122 : void
123 12361 : FeatureGate::check_no_core_attribute (const AST::Attribute &attribute)
124 : {
125 12361 : if (attribute.get_path ().as_string () == Values::Attributes::NO_CORE)
126 4845 : gate (Feature::Name::NO_CORE, attribute.get_locus (),
127 9690 : "no_core is experimental");
128 12361 : }
129 :
130 : void
131 29781 : FeatureGate::check_rustc_attri (const std::vector<AST::Attribute> &attributes)
132 : {
133 90800 : for (const AST::Attribute &attr : attributes)
134 : {
135 61019 : auto name = attr.get_path ().as_string ();
136 61019 : if (name.rfind ("rustc_", 0) == 0)
137 : {
138 2605 : gate (Feature::Name::RUSTC_ATTRS, attr.get_locus (),
139 5210 : "internal implementation detail");
140 : }
141 61019 : }
142 29781 : }
143 :
144 : void
145 17942 : FeatureGate::check_may_dangle_attribute (
146 : const std::vector<AST::Attribute> &attributes)
147 : {
148 17947 : for (const AST::Attribute &attr : attributes)
149 : {
150 5 : if (attr.get_path ().as_string () == Values::Attributes::MAY_DANGLE)
151 5 : gate (Feature::Name::DROPCK_EYEPATCH, attr.get_locus (),
152 10 : "`may_dangle` has unstable semantics and may be removed in the "
153 : "future");
154 : }
155 17942 : }
156 :
157 : void
158 39813 : FeatureGate::check_lang_item_attribute (
159 : const std::vector<AST::Attribute> &attributes)
160 : {
161 113951 : for (const AST::Attribute &attr : attributes)
162 : {
163 74138 : const auto &str_path = attr.get_path ().as_string ();
164 74138 : bool is_lang_item = str_path == Values::Attributes::LANG
165 3458 : && attr.has_attr_input ()
166 77596 : && attr.get_attr_input ().get_attr_input_type ()
167 74138 : == AST::AttrInput::AttrInputType::LITERAL;
168 :
169 3458 : if (is_lang_item)
170 3458 : gate (Feature::Name::LANG_ITEMS, attr.get_locus (),
171 6916 : "lang items are subject to change");
172 74138 : }
173 39813 : }
174 :
175 : void
176 33169 : FeatureGate::note_stability_attribute (
177 : const std::vector<AST::Attribute> &attributes)
178 : {
179 96289 : for (const AST::Attribute &attr : attributes)
180 : {
181 63120 : std::string attr_name = attr.get_path ().as_string ();
182 :
183 63120 : Stability stability;
184 :
185 63120 : if (attr_name == Values::Attributes::STABLE)
186 3242 : stability = Stability::STABLE;
187 59878 : else if (attr_name == Values::Attributes::UNSTABLE)
188 582 : stability = Stability::UNSTABLE;
189 59296 : else if (attr_name == Values::Attributes::RUSTC_CONST_STABLE)
190 893 : stability = Stability::STABLE;
191 58403 : else if (attr_name == Values::Attributes::RUSTC_CONST_UNSTABLE)
192 402 : stability = Stability::UNSTABLE;
193 : else
194 58001 : continue;
195 :
196 5119 : if (attr.empty_input ())
197 : // TODO: error?
198 0 : continue;
199 :
200 5119 : auto &attr_input = attr.get_attr_input ();
201 5119 : if (attr_input.get_attr_input_type ()
202 : != AST::AttrInput::AttrInputType::TOKEN_TREE)
203 : // TODO: error?
204 0 : continue;
205 :
206 5119 : std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
207 : static_cast<const AST::DelimTokenTree &> (attr_input)
208 5119 : .parse_to_meta_item ());
209 :
210 15472 : for (auto &item : meta_item->get_items ())
211 : {
212 : // TODO: more thorough error checking?
213 : // ~only the standard libraries should ever exercise this
214 10353 : if (item->is_key_value_pair ())
215 : {
216 10352 : auto &pair = static_cast<const AST::MetaNameValueStr &> (*item);
217 10352 : if (pair.get_name ().as_string () == "feature")
218 5119 : defined_lib_features.emplace (pair.get_value (), stability);
219 : }
220 : }
221 63120 : }
222 33169 : }
223 :
224 : void
225 1697 : FeatureGate::visit (AST::MacroRulesDefinition &rules_def)
226 : {
227 1697 : check_rustc_attri (rules_def.get_outer_attrs ());
228 1697 : note_stability_attribute (rules_def.get_outer_attrs ());
229 1697 : }
230 :
231 : void
232 31472 : FeatureGate::visit (AST::Function &function)
233 : {
234 31472 : if (!function.is_external ())
235 28084 : check_rustc_attri (function.get_outer_attrs ());
236 :
237 93175 : for (const AST::Attribute &attr : function.get_outer_attrs ())
238 : {
239 61703 : if (attr.get_path ().as_string () == "rustc_const_stable")
240 : {
241 893 : gate (Feature::Name::STAGED_API, attr.get_locus (),
242 1786 : "stability attributes may not be used outside of the standard "
243 : "library");
244 : }
245 : }
246 :
247 31472 : check_lang_item_attribute (function.get_outer_attrs ());
248 :
249 31472 : note_stability_attribute (function.get_outer_attrs ());
250 :
251 31472 : AST::DefaultASTVisitor::visit (function);
252 31472 : }
253 :
254 : void
255 3 : FeatureGate::visit (AST::ExternalTypeItem &item)
256 : {
257 : // TODO(mxlol233): The gating needs a complete visiting chain to activate
258 : // `AST::ExternalTypeItem`.
259 3 : gate (Feature::Name::EXTERN_TYPES, item.get_locus (),
260 3 : "extern types are experimental");
261 3 : }
262 :
263 : void
264 11566 : FeatureGate::visit (AST::TraitImpl &impl)
265 : {
266 11566 : if (impl.is_exclam ())
267 20 : gate (Feature::Name::NEGATIVE_IMPLS, impl.get_locus (),
268 40 : "negative_impls are not yet implemented");
269 :
270 11566 : AST::DefaultASTVisitor::visit (impl);
271 11566 : }
272 :
273 : void
274 4139 : FeatureGate::visit (AST::Trait &trait)
275 : {
276 4139 : if (trait.is_auto ())
277 24 : gate (Feature::Name::OPTIN_BUILTIN_TRAITS, trait.get_locus (),
278 48 : "auto traits are experimental and possibly buggy");
279 4139 : check_lang_item_attribute (trait.get_outer_attrs ());
280 4139 : AST::DefaultASTVisitor::visit (trait);
281 4139 : }
282 :
283 : void
284 4 : FeatureGate::visit (AST::BoxExpr &expr)
285 : {
286 4 : gate (
287 : Feature::Name::BOX_SYNTAX, expr.get_locus (),
288 4 : "box expression syntax is experimental; you can call `Box::new` instead");
289 4 : AST::DefaultASTVisitor::visit (expr);
290 4 : }
291 :
292 : void
293 1463 : FeatureGate::visit (AST::LifetimeParam &lifetime_param)
294 : {
295 1463 : check_may_dangle_attribute (lifetime_param.get_outer_attrs ());
296 1463 : AST::DefaultASTVisitor::visit (lifetime_param);
297 1463 : }
298 :
299 : void
300 181 : FeatureGate::visit (AST::ConstGenericParam &const_param)
301 : {
302 181 : check_may_dangle_attribute (const_param.get_outer_attrs ());
303 181 : AST::DefaultASTVisitor::visit (const_param);
304 181 : }
305 :
306 : void
307 16298 : FeatureGate::visit (AST::TypeParam ¶m)
308 : {
309 16298 : check_may_dangle_attribute (param.get_outer_attrs ());
310 16298 : AST::DefaultASTVisitor::visit (param);
311 16298 : }
312 :
313 : void
314 4887 : FeatureGate::visit (AST::BorrowExpr &expr)
315 : {
316 4887 : if (expr.is_raw_borrow ())
317 5 : gate (Feature::Name::RAW_REF_OP, expr.get_locus (),
318 10 : "raw address of syntax is experimental");
319 4887 : }
320 :
321 : void
322 130 : FeatureGate::visit (AST::RangePattern &pattern)
323 : {
324 130 : if (pattern.get_range_kind () == AST::RangeKind::EXCLUDED)
325 22 : gate (Feature::Name::EXCLUSIVE_RANGE_PATTERN, pattern.get_locus (),
326 44 : "exclusive range pattern syntax is experimental");
327 130 : }
328 :
329 : void
330 85 : FeatureGate::visit (AST::UseTreeGlob &use)
331 : {
332 : // At the moment, UseTrees do not have outer attributes, but they should. we
333 : // need to eventually gate `#[prelude_import]` on use-trees based on the
334 : // #[feature(prelude_import)]
335 85 : }
336 :
337 : void
338 2286 : FeatureGate::visit (AST::StructStruct &struct_item)
339 : {
340 2286 : check_lang_item_attribute (struct_item.get_outer_attrs ());
341 2286 : AST::DefaultASTVisitor::visit (struct_item);
342 2286 : }
343 :
344 : void
345 778 : FeatureGate::visit (AST::TraitItemType &trait_item_type)
346 : {
347 778 : check_lang_item_attribute (trait_item_type.get_outer_attrs ());
348 778 : AST::DefaultASTVisitor::visit (trait_item_type);
349 778 : }
350 :
351 : void
352 597 : FeatureGate::visit (AST::Enum &enum_item)
353 : {
354 597 : check_lang_item_attribute (enum_item.get_outer_attrs ());
355 597 : AST::DefaultASTVisitor::visit (enum_item);
356 597 : }
357 :
358 : void
359 541 : FeatureGate::visit (AST::EnumItem &enum_variant)
360 : {
361 541 : check_lang_item_attribute (enum_variant.get_outer_attrs ());
362 541 : AST::DefaultASTVisitor::visit (enum_variant);
363 541 : }
364 :
365 : } // namespace Rust
|