1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 //! This module implements the gating necessary for preventing certain compiler
14 //! features from being used by default. This module will crawl a pre-expanded
15 //! AST to ensure that there are no features which are used that are not
18 //! Features are enabled in programs via the crate-level attributes of
19 //! `#![feature(...)]` with a comma-separated list of features.
21 //! For the purpose of future feature-tracking, once code for detection of feature
22 //! gate usage is added, *do not remove it again* even once the feature
25 use self::AttributeType
::*;
26 use self::AttributeGate
::*;
29 use ast
::{self, NodeId, PatKind}
;
31 use codemap
::{CodeMap, Spanned}
;
34 use visit
::{self, FnKind, Visitor}
;
36 use parse
::token
::InternedString
;
38 use std
::ascii
::AsciiExt
;
43 fn f(features
: &mut Features
) -> &mut bool
{
46 f
as fn(&mut Features
) -> &mut bool
50 macro_rules
! declare_features
{
51 ($
((active
, $feature
: ident
, $ver
: expr
, $issue
: expr
),)+) => {
52 /// Represents active features that are currently being implemented or
53 /// currently being considered for addition/removal.
54 const ACTIVE_FEATURES
: &'
static [(&'
static str, &'
static str,
55 Option
<u32>, fn(&mut Features
) -> &mut bool
)] = &[
56 $
((stringify
!($feature
), $ver
, $issue
, setter
!($feature
))),+
59 /// A set of features to be used by later passes.
61 /// #![feature] attrs for stable language features, for error reporting
62 pub declared_stable_lang_features
: Vec
<(InternedString
, Span
)>,
63 /// #![feature] attrs for non-language (library) features
64 pub declared_lib_features
: Vec
<(InternedString
, Span
)>,
65 $
(pub $feature
: bool
),+
69 pub fn new() -> Features
{
71 declared_stable_lang_features
: Vec
::new(),
72 declared_lib_features
: Vec
::new(),
79 ($
((removed
, $feature
: ident
, $ver
: expr
, $issue
: expr
),)+) => {
80 /// Represents features which has since been removed (it was once Active)
81 const REMOVED_FEATURES
: &'
static [(&'
static str, &'
static str, Option
<u32>)] = &[
82 $
((stringify
!($feature
), $ver
, $issue
)),+
86 ($
((accepted
, $feature
: ident
, $ver
: expr
, $issue
: expr
),)+) => {
87 /// Those language feature has since been Accepted (it was once Active)
88 const ACCEPTED_FEATURES
: &'
static [(&'
static str, &'
static str, Option
<u32>)] = &[
89 $
((stringify
!($feature
), $ver
, $issue
)),+
94 // If you change this list without updating src/doc/reference.md, @cmr will be sad
95 // Don't ever remove anything from this list; set them to 'Removed'.
96 // The version numbers here correspond to the version in which the current status
97 // was set. This is most important for knowing when a particular feature became
99 // NB: The featureck.py script parses this information directly out of the source
100 // so take care when modifying it.
103 (active
, asm
, "1.0.0", Some(29722)),
104 (active
, concat_idents
, "1.0.0", Some(29599)),
105 (active
, link_args
, "1.0.0", Some(29596)),
106 (active
, log_syntax
, "1.0.0", Some(29598)),
107 (active
, non_ascii_idents
, "1.0.0", Some(28979)),
108 (active
, plugin_registrar
, "1.0.0", Some(29597)),
109 (active
, thread_local
, "1.0.0", Some(29594)),
110 (active
, trace_macros
, "1.0.0", Some(29598)),
112 // rustc internal, for now:
113 (active
, intrinsics
, "1.0.0", None
),
114 (active
, lang_items
, "1.0.0", None
),
116 (active
, link_llvm_intrinsics
, "1.0.0", Some(29602)),
117 (active
, linkage
, "1.0.0", Some(29603)),
118 (active
, quote
, "1.0.0", Some(29601)),
119 (active
, simd
, "1.0.0", Some(27731)),
123 (active
, rustc_diagnostic_macros
, "1.0.0", None
),
124 (active
, advanced_slice_patterns
, "1.0.0", Some(23121)),
125 (active
, box_syntax
, "1.0.0", Some(27779)),
126 (active
, placement_in_syntax
, "1.0.0", Some(27779)),
127 (active
, reflect
, "1.0.0", Some(27749)),
128 (active
, unboxed_closures
, "1.0.0", Some(29625)),
131 (active
, pushpop_unsafe
, "1.2.0", None
),
133 (active
, allocator
, "1.0.0", Some(27389)),
134 (active
, fundamental
, "1.0.0", Some(29635)),
135 (active
, linked_from
, "1.3.0", Some(29629)),
136 (active
, main
, "1.0.0", Some(29634)),
137 (active
, needs_allocator
, "1.4.0", Some(27389)),
138 (active
, on_unimplemented
, "1.0.0", Some(29628)),
139 (active
, plugin
, "1.0.0", Some(29597)),
140 (active
, simd_ffi
, "1.0.0", Some(27731)),
141 (active
, start
, "1.0.0", Some(29633)),
142 (active
, structural_match
, "1.8.0", Some(31434)),
143 (active
, panic_runtime
, "1.10.0", Some(32837)),
144 (active
, needs_panic_runtime
, "1.10.0", Some(32837)),
146 // OIBIT specific features
147 (active
, optin_builtin_traits
, "1.0.0", Some(13231)),
149 // macro reexport needs more discussion and stabilization
150 (active
, macro_reexport
, "1.0.0", Some(29638)),
152 // Allows use of #[staged_api]
154 (active
, staged_api
, "1.0.0", None
),
156 // Allows using items which are missing stability attributes
158 (active
, unmarked_api
, "1.0.0", None
),
160 // Allows using #![no_core]
161 (active
, no_core
, "1.3.0", Some(29639)),
163 // Allows using `box` in patterns; RFC 469
164 (active
, box_patterns
, "1.0.0", Some(29641)),
166 // Allows using the unsafe_destructor_blind_to_params attribute;
168 (active
, dropck_parametricity
, "1.3.0", Some(28498)),
170 // Allows the use of custom attributes; RFC 572
171 (active
, custom_attribute
, "1.0.0", Some(29642)),
173 // Allows the use of #[derive(Anything)] as sugar for
174 // #[derive_Anything].
175 (active
, custom_derive
, "1.0.0", Some(29644)),
177 // Allows the use of rustc_* attributes; RFC 572
178 (active
, rustc_attrs
, "1.0.0", Some(29642)),
180 // Allows the use of #[allow_internal_unstable]. This is an
181 // attribute on macro_rules! and can't use the attribute handling
182 // below (it has to be checked before expansion possibly makes
183 // macros disappear).
186 (active
, allow_internal_unstable
, "1.0.0", None
),
188 // #23121. Array patterns have some hazards yet.
189 (active
, slice_patterns
, "1.0.0", Some(23121)),
191 // Allows the definition of associated constants in `trait` or `impl`
193 (active
, associated_consts
, "1.0.0", Some(29646)),
195 // Allows the definition of `const fn` functions.
196 (active
, const_fn
, "1.2.0", Some(24111)),
198 // Allows indexing into constant arrays.
199 (active
, const_indexing
, "1.4.0", Some(29947)),
201 // Allows using #[prelude_import] on glob `use` items.
204 (active
, prelude_import
, "1.2.0", None
),
206 // Allows the definition recursive static items.
207 (active
, static_recursion
, "1.3.0", Some(29719)),
209 // Allows default type parameters to influence type inference.
210 (active
, default_type_parameter_fallback
, "1.3.0", Some(27336)),
212 // Allows associated type defaults
213 (active
, associated_type_defaults
, "1.2.0", Some(29661)),
215 // allow `repr(simd)`, and importing the various simd intrinsics
216 (active
, repr_simd
, "1.4.0", Some(27731)),
218 // Allows cfg(target_feature = "...").
219 (active
, cfg_target_feature
, "1.4.0", Some(29717)),
221 // allow `extern "platform-intrinsic" { ... }`
222 (active
, platform_intrinsics
, "1.4.0", Some(27731)),
225 // rust runtime internal
226 (active
, unwind_attributes
, "1.4.0", None
),
228 // allow the use of `#[naked]` on functions.
229 (active
, naked_functions
, "1.9.0", Some(32408)),
231 // allow `#[no_debug]`
232 (active
, no_debug
, "1.5.0", Some(29721)),
234 // allow `#[omit_gdb_pretty_printer_section]`
236 (active
, omit_gdb_pretty_printer_section
, "1.5.0", None
),
238 // Allows cfg(target_vendor = "...").
239 (active
, cfg_target_vendor
, "1.5.0", Some(29718)),
241 // Allow attributes on expressions and non-item statements
242 (active
, stmt_expr_attributes
, "1.6.0", Some(15701)),
244 // allow using type ascription in expressions
245 (active
, type_ascription
, "1.6.0", Some(23416)),
247 // Allows cfg(target_thread_local)
248 (active
, cfg_target_thread_local
, "1.7.0", Some(29594)),
251 (active
, abi_vectorcall
, "1.7.0", None
),
254 (active
, inclusive_range_syntax
, "1.7.0", Some(28237)),
256 // impl specialization (RFC 1210)
257 (active
, specialization
, "1.7.0", Some(31844)),
259 // pub(restricted) visibilities (RFC 1422)
260 (active
, pub_restricted
, "1.9.0", Some(32409)),
262 // Allow Drop types in statics/const functions (RFC 1440)
263 (active
, drop_types_in_const
, "1.9.0", Some(33156)),
265 // Allows cfg(target_has_atomic = "...").
266 (active
, cfg_target_has_atomic
, "1.9.0", Some(32976)),
268 // Allows `..` in tuple (struct) patterns
269 (active
, dotdot_in_tuple_patterns
, "1.10.0", Some(33627)),
271 // Allows `impl Trait` in function return types.
272 (active
, conservative_impl_trait
, "1.12.0", Some(34511)),
274 // Allows tuple structs and variants in more contexts,
275 // Permits numeric fields in struct expressions and patterns.
276 (active
, relaxed_adts
, "1.12.0", Some(35626)),
279 (active
, never_type
, "1.13.0", Some(35121)),
281 // Allows all literals in attribute lists and values of key-value pairs.
282 (active
, attr_literals
, "1.13.0", Some(34981)),
284 // Allows the sysV64 ABI to be specified on all platforms
285 // instead of just the platforms on which it is the C ABI
286 (active
, abi_sysv64
, "1.13.0", Some(36167)),
288 // Use the import semantics from RFC 1560.
289 (active
, item_like_imports
, "1.13.0", Some(35120)),
292 (active
, rustc_macro
, "1.13.0", Some(35900)),
294 // Allows untagged unions `union U { ... }`
295 (active
, untagged_unions
, "1.13.0", Some(32836)),
297 // elide `'static` lifetimes in `static`s and `const`s
298 (active
, static_in_const
, "1.13.0", Some(35897)),
300 // Used to identify the `compiler_builtins` crate
302 (active
, compiler_builtins
, "1.13.0", None
),
306 (removed
, import_shadowing
, "1.0.0", None
),
307 (removed
, managed_boxes
, "1.0.0", None
),
308 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
309 (removed
, negate_unsigned
, "1.0.0", Some(29645)),
310 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
311 (removed
, opt_out_copy
, "1.0.0", None
),
312 (removed
, quad_precision_float
, "1.0.0", None
),
313 (removed
, struct_inherit
, "1.0.0", None
),
314 (removed
, test_removed_feature
, "1.0.0", None
),
315 (removed
, visible_private_types
, "1.0.0", None
),
316 (removed
, unsafe_no_drop_flag
, "1.0.0", None
),
320 (accepted
, associated_types
, "1.0.0", None
),
321 // allow overloading augmented assignment operations like `a += b`
322 (accepted
, augmented_assignments
, "1.8.0", Some(28235)),
323 // allow empty structs and enum variants with braces
324 (accepted
, braced_empty_structs
, "1.8.0", Some(29720)),
325 (accepted
, default_type_params
, "1.0.0", None
),
326 (accepted
, globs
, "1.0.0", None
),
327 (accepted
, if_let
, "1.0.0", None
),
328 // A temporary feature gate used to enable parser extensions needed
329 // to bootstrap fix for #5723.
330 (accepted
, issue_5723_bootstrap
, "1.0.0", None
),
331 (accepted
, macro_rules
, "1.0.0", None
),
332 // Allows using #![no_std]
333 (accepted
, no_std
, "1.6.0", None
),
334 (accepted
, slicing_syntax
, "1.0.0", None
),
335 (accepted
, struct_variant
, "1.0.0", None
),
336 // These are used to test this portion of the compiler, they don't actually
338 (accepted
, test_accepted_feature
, "1.0.0", None
),
339 (accepted
, tuple_indexing
, "1.0.0", None
),
340 // Allows macros to appear in the type position.
341 (accepted
, type_macros
, "1.13.0", Some(27245)),
342 (accepted
, while_let
, "1.0.0", None
),
343 // Allows `#[deprecated]` attribute
344 (accepted
, deprecated
, "1.9.0", Some(29935)),
346 (accepted
, question_mark
, "1.14.0", Some(31436)),
348 // (changing above list without updating src/doc/reference.md makes @cmr sad)
350 #[derive(PartialEq, Copy, Clone, Debug)]
351 pub enum AttributeType
{
352 /// Normal, builtin attribute that is consumed
353 /// by the compiler before the unused_attribute check
356 /// Builtin attribute that may not be consumed by the compiler
357 /// before the unused_attribute check. These attributes
358 /// will be ignored by the unused_attribute lint
361 /// Builtin attribute that is only allowed at the crate level
365 pub enum AttributeGate
{
366 /// Is gated by a given feature gate, reason
367 /// and function to check if enabled
368 Gated(&'
static str, &'
static str, fn(&Features
) -> bool
),
370 /// Ungated attribute, can be used on all release channels
375 impl ::std
::fmt
::Debug
for AttributeGate
{
376 fn fmt(&self, fmt
: &mut ::std
::fmt
::Formatter
) -> ::std
::fmt
::Result
{
378 Gated(ref name
, ref expl
, _
) => write
!(fmt
, "Gated({}, {})", name
, expl
),
379 Ungated
=> write
!(fmt
, "Ungated")
384 macro_rules
! cfg_fn
{
385 ($field
: ident
) => {{
386 fn f(features
: &Features
) -> bool
{
389 f
as fn(&Features
) -> bool
393 // Attributes that have a special meaning to rustc or rustdoc
394 pub const KNOWN_ATTRIBUTES
: &'
static [(&'
static str, AttributeType
, AttributeGate
)] = &[
397 ("warn", Normal
, Ungated
),
398 ("allow", Normal
, Ungated
),
399 ("forbid", Normal
, Ungated
),
400 ("deny", Normal
, Ungated
),
402 ("macro_reexport", Normal
, Ungated
),
403 ("macro_use", Normal
, Ungated
),
404 ("macro_export", Normal
, Ungated
),
405 ("plugin_registrar", Normal
, Ungated
),
407 ("cfg", Normal
, Ungated
),
408 ("cfg_attr", Normal
, Ungated
),
409 ("main", Normal
, Ungated
),
410 ("start", Normal
, Ungated
),
411 ("test", Normal
, Ungated
),
412 ("bench", Normal
, Ungated
),
413 ("simd", Normal
, Ungated
),
414 ("repr", Normal
, Ungated
),
415 ("path", Normal
, Ungated
),
416 ("abi", Normal
, Ungated
),
417 ("automatically_derived", Normal
, Ungated
),
418 ("no_mangle", Normal
, Ungated
),
419 ("no_link", Normal
, Ungated
),
420 ("derive", Normal
, Ungated
),
421 ("should_panic", Normal
, Ungated
),
422 ("ignore", Normal
, Ungated
),
423 ("no_implicit_prelude", Normal
, Ungated
),
424 ("reexport_test_harness_main", Normal
, Ungated
),
425 ("link_args", Normal
, Ungated
),
426 ("macro_escape", Normal
, Ungated
),
429 ("structural_match", Whitelisted
, Gated("structural_match",
430 "the semantics of constant patterns is \
432 cfg_fn
!(structural_match
))),
434 // Not used any more, but we can't feature gate it
435 ("no_stack_check", Normal
, Ungated
),
437 ("plugin", CrateLevel
, Gated("plugin",
438 "compiler plugins are experimental \
442 ("no_std", CrateLevel
, Ungated
),
443 ("no_core", CrateLevel
, Gated("no_core",
444 "no_core is experimental",
446 ("lang", Normal
, Gated("lang_items",
447 "language items are subject to change",
448 cfg_fn
!(lang_items
))),
449 ("linkage", Whitelisted
, Gated("linkage",
450 "the `linkage` attribute is experimental \
451 and not portable across platforms",
453 ("thread_local", Whitelisted
, Gated("thread_local",
454 "`#[thread_local]` is an experimental feature, and does \
455 not currently handle destructors. There is no \
456 corresponding `#[task_local]` mapping to the task \
458 cfg_fn
!(thread_local
))),
460 ("rustc_on_unimplemented", Normal
, Gated("on_unimplemented",
461 "the `#[rustc_on_unimplemented]` attribute \
462 is an experimental feature",
463 cfg_fn
!(on_unimplemented
))),
464 ("allocator", Whitelisted
, Gated("allocator",
465 "the `#[allocator]` attribute is an experimental feature",
466 cfg_fn
!(allocator
))),
467 ("needs_allocator", Normal
, Gated("needs_allocator",
468 "the `#[needs_allocator]` \
469 attribute is an experimental \
471 cfg_fn
!(needs_allocator
))),
472 ("panic_runtime", Whitelisted
, Gated("panic_runtime",
473 "the `#[panic_runtime]` attribute is \
474 an experimental feature",
475 cfg_fn
!(panic_runtime
))),
476 ("needs_panic_runtime", Whitelisted
, Gated("needs_panic_runtime",
477 "the `#[needs_panic_runtime]` \
478 attribute is an experimental \
480 cfg_fn
!(needs_panic_runtime
))),
481 ("rustc_variance", Normal
, Gated("rustc_attrs",
482 "the `#[rustc_variance]` attribute \
483 is just used for rustc unit tests \
484 and will never be stable",
485 cfg_fn
!(rustc_attrs
))),
486 ("rustc_error", Whitelisted
, Gated("rustc_attrs",
487 "the `#[rustc_error]` attribute \
488 is just used for rustc unit tests \
489 and will never be stable",
490 cfg_fn
!(rustc_attrs
))),
491 ("rustc_if_this_changed", Whitelisted
, Gated("rustc_attrs",
492 "the `#[rustc_if_this_changed]` attribute \
493 is just used for rustc unit tests \
494 and will never be stable",
495 cfg_fn
!(rustc_attrs
))),
496 ("rustc_then_this_would_need", Whitelisted
, Gated("rustc_attrs",
497 "the `#[rustc_if_this_changed]` attribute \
498 is just used for rustc unit tests \
499 and will never be stable",
500 cfg_fn
!(rustc_attrs
))),
501 ("rustc_dirty", Whitelisted
, Gated("rustc_attrs",
502 "the `#[rustc_dirty]` attribute \
503 is just used for rustc unit tests \
504 and will never be stable",
505 cfg_fn
!(rustc_attrs
))),
506 ("rustc_clean", Whitelisted
, Gated("rustc_attrs",
507 "the `#[rustc_clean]` attribute \
508 is just used for rustc unit tests \
509 and will never be stable",
510 cfg_fn
!(rustc_attrs
))),
511 ("rustc_metadata_dirty", Whitelisted
, Gated("rustc_attrs",
512 "the `#[rustc_metadata_dirty]` attribute \
513 is just used for rustc unit tests \
514 and will never be stable",
515 cfg_fn
!(rustc_attrs
))),
516 ("rustc_metadata_clean", Whitelisted
, Gated("rustc_attrs",
517 "the `#[rustc_metadata_clean]` attribute \
518 is just used for rustc unit tests \
519 and will never be stable",
520 cfg_fn
!(rustc_attrs
))),
521 ("rustc_partition_reused", Whitelisted
, Gated("rustc_attrs",
523 is just used for rustc unit tests \
524 and will never be stable",
525 cfg_fn
!(rustc_attrs
))),
526 ("rustc_partition_translated", Whitelisted
, Gated("rustc_attrs",
528 is just used for rustc unit tests \
529 and will never be stable",
530 cfg_fn
!(rustc_attrs
))),
531 ("rustc_symbol_name", Whitelisted
, Gated("rustc_attrs",
532 "internal rustc attributes will never be stable",
533 cfg_fn
!(rustc_attrs
))),
534 ("rustc_item_path", Whitelisted
, Gated("rustc_attrs",
535 "internal rustc attributes will never be stable",
536 cfg_fn
!(rustc_attrs
))),
537 ("rustc_move_fragments", Normal
, Gated("rustc_attrs",
538 "the `#[rustc_move_fragments]` attribute \
539 is just used for rustc unit tests \
540 and will never be stable",
541 cfg_fn
!(rustc_attrs
))),
542 ("rustc_mir", Whitelisted
, Gated("rustc_attrs",
543 "the `#[rustc_mir]` attribute \
544 is just used for rustc unit tests \
545 and will never be stable",
546 cfg_fn
!(rustc_attrs
))),
547 ("rustc_inherit_overflow_checks", Whitelisted
, Gated("rustc_attrs",
548 "the `#[rustc_inherit_overflow_checks]` \
549 attribute is just used to control \
550 overflow checking behavior of several \
551 libcore functions that are inlined \
552 across crates and will never be stable",
553 cfg_fn
!(rustc_attrs
))),
554 ("compiler_builtins", Whitelisted
, Gated("compiler_builtins",
555 "the `#[compiler_builtins]` attribute is used to \
556 identify the `compiler_builtins` crate which \
557 contains compiler-rt intrinsics and will never be \
559 cfg_fn
!(compiler_builtins
))),
561 ("allow_internal_unstable", Normal
, Gated("allow_internal_unstable",
562 EXPLAIN_ALLOW_INTERNAL_UNSTABLE
,
563 cfg_fn
!(allow_internal_unstable
))),
565 ("fundamental", Whitelisted
, Gated("fundamental",
566 "the `#[fundamental]` attribute \
567 is an experimental feature",
568 cfg_fn
!(fundamental
))),
570 ("linked_from", Normal
, Gated("linked_from",
571 "the `#[linked_from]` attribute \
572 is an experimental feature",
573 cfg_fn
!(linked_from
))),
575 ("rustc_macro_derive", Normal
, Gated("rustc_macro",
576 "the `#[rustc_macro_derive]` attribute \
577 is an experimental feature",
578 cfg_fn
!(rustc_macro
))),
580 ("rustc_copy_clone_marker", Whitelisted
, Gated("rustc_attrs",
581 "internal implementation detail",
582 cfg_fn
!(rustc_attrs
))),
584 // FIXME: #14408 whitelist docs since rustdoc looks at them
585 ("doc", Whitelisted
, Ungated
),
587 // FIXME: #14406 these are processed in trans, which happens after the
589 ("cold", Whitelisted
, Ungated
),
590 ("naked", Whitelisted
, Gated("naked_functions",
591 "the `#[naked]` attribute \
592 is an experimental feature",
593 cfg_fn
!(naked_functions
))),
594 ("export_name", Whitelisted
, Ungated
),
595 ("inline", Whitelisted
, Ungated
),
596 ("link", Whitelisted
, Ungated
),
597 ("link_name", Whitelisted
, Ungated
),
598 ("link_section", Whitelisted
, Ungated
),
599 ("no_builtins", Whitelisted
, Ungated
),
600 ("no_mangle", Whitelisted
, Ungated
),
601 ("no_debug", Whitelisted
, Gated("no_debug",
602 "the `#[no_debug]` attribute \
603 is an experimental feature",
605 ("omit_gdb_pretty_printer_section", Whitelisted
, Gated("omit_gdb_pretty_printer_section",
606 "the `#[omit_gdb_pretty_printer_section]` \
607 attribute is just used for the Rust test \
609 cfg_fn
!(omit_gdb_pretty_printer_section
))),
610 ("unsafe_destructor_blind_to_params",
612 Gated("dropck_parametricity",
613 "unsafe_destructor_blind_to_params has unstable semantics \
614 and may be removed in the future",
615 cfg_fn
!(dropck_parametricity
))),
616 ("unwind", Whitelisted
, Gated("unwind_attributes", "#[unwind] is experimental",
617 cfg_fn
!(unwind_attributes
))),
620 ("prelude_import", Whitelisted
, Gated("prelude_import",
621 "`#[prelude_import]` is for use by rustc only",
622 cfg_fn
!(prelude_import
))),
624 // FIXME: #14407 these are only looked at on-demand so we can't
625 // guarantee they'll have already been checked
626 ("rustc_deprecated", Whitelisted
, Ungated
),
627 ("must_use", Whitelisted
, Ungated
),
628 ("stable", Whitelisted
, Ungated
),
629 ("unstable", Whitelisted
, Ungated
),
630 ("deprecated", Normal
, Ungated
),
632 ("rustc_paren_sugar", Normal
, Gated("unboxed_closures",
633 "unboxed_closures are still evolving",
634 cfg_fn
!(unboxed_closures
))),
635 ("rustc_reflect_like", Whitelisted
, Gated("reflect",
636 "defining reflective traits is still evolving",
639 // Crate level attributes
640 ("crate_name", CrateLevel
, Ungated
),
641 ("crate_type", CrateLevel
, Ungated
),
642 ("crate_id", CrateLevel
, Ungated
),
643 ("feature", CrateLevel
, Ungated
),
644 ("no_start", CrateLevel
, Ungated
),
645 ("no_main", CrateLevel
, Ungated
),
646 ("no_builtins", CrateLevel
, Ungated
),
647 ("recursion_limit", CrateLevel
, Ungated
),
650 // cfg(...)'s that are feature gated
651 const GATED_CFGS
: &'
static [(&'
static str, &'
static str, fn(&Features
) -> bool
)] = &[
652 // (name in cfg, feature, function to check if the feature is enabled)
653 ("target_feature", "cfg_target_feature", cfg_fn
!(cfg_target_feature
)),
654 ("target_vendor", "cfg_target_vendor", cfg_fn
!(cfg_target_vendor
)),
655 ("target_thread_local", "cfg_target_thread_local", cfg_fn
!(cfg_target_thread_local
)),
656 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn
!(cfg_target_has_atomic
)),
657 ("rustc_macro", "rustc_macro", cfg_fn
!(rustc_macro
)),
660 #[derive(Debug, Eq, PartialEq)]
661 pub struct GatedCfg
{
667 pub fn gate(cfg
: &ast
::MetaItem
) -> Option
<GatedCfg
> {
668 let name
= cfg
.name();
670 .position(|info
| info
.0 == name
)
679 pub fn check_and_emit(&self, sess
: &ParseSess
, features
: &Features
) {
680 let (cfg
, feature
, has_feature
) = GATED_CFGS
[self.index
];
681 if !has_feature(features
) && !sess
.codemap().span_allows_unstable(self.span
) {
682 let explain
= format
!("`cfg({})` is experimental and subject to change", cfg
);
683 emit_feature_err(sess
, feature
, self.span
, GateIssue
::Language
, &explain
);
689 features
: &'a Features
,
690 parse_sess
: &'a ParseSess
,
692 plugin_attributes
: &'a
[(String
, AttributeType
)],
695 macro_rules
! gate_feature_fn
{
696 ($cx
: expr
, $has_feature
: expr
, $span
: expr
, $name
: expr
, $explain
: expr
) => {{
697 let (cx
, has_feature
, span
, name
, explain
) = ($cx
, $has_feature
, $span
, $name
, $explain
);
698 let has_feature
: bool
= has_feature(&$cx
.features
);
699 debug
!("gate_feature(feature = {:?}, span = {:?}); has? {}", name
, span
, has_feature
);
700 if !has_feature
&& !cx
.cm
.span_allows_unstable(span
) {
701 emit_feature_err(cx
.parse_sess
, name
, span
, GateIssue
::Language
, explain
);
706 macro_rules
! gate_feature
{
707 ($cx
: expr
, $feature
: ident
, $span
: expr
, $explain
: expr
) => {
708 gate_feature_fn
!($cx
, |x
:&Features
| x
.$feature
, $span
, stringify
!($feature
), $explain
)
712 impl<'a
> Context
<'a
> {
713 fn check_attribute(&self, attr
: &ast
::Attribute
, is_macro
: bool
) {
714 debug
!("check_attribute(attr = {:?})", attr
);
715 let name
= &*attr
.name();
716 for &(n
, ty
, ref gateage
) in KNOWN_ATTRIBUTES
{
718 if let &Gated(ref name
, ref desc
, ref has_feature
) = gateage
{
719 gate_feature_fn
!(self, has_feature
, attr
.span
, name
, desc
);
721 debug
!("check_attribute: {:?} is known, {:?}, {:?}", name
, ty
, gateage
);
725 for &(ref n
, ref ty
) in self.plugin_attributes
{
727 // Plugins can't gate attributes, so we don't check for it
728 // unlike the code above; we only use this loop to
729 // short-circuit to avoid the checks below
730 debug
!("check_attribute: {:?} is registered by a plugin, {:?}", name
, ty
);
734 if name
.starts_with("rustc_") {
735 gate_feature
!(self, rustc_attrs
, attr
.span
,
736 "unless otherwise specified, attributes \
737 with the prefix `rustc_` \
738 are reserved for internal compiler diagnostics");
739 } else if name
.starts_with("derive_") {
740 gate_feature
!(self, custom_derive
, attr
.span
, EXPLAIN_DERIVE_UNDERSCORE
);
742 // Only run the custom attribute lint during regular
743 // feature gate checking. Macro gating runs
744 // before the plugin attributes are registered
745 // so we skip this then
747 gate_feature
!(self, custom_attribute
, attr
.span
,
748 &format
!("The attribute `{}` is currently \
749 unknown to the compiler and \
751 added to it in the future",
758 pub fn check_attribute(attr
: &ast
::Attribute
, parse_sess
: &ParseSess
,
759 cm
: &CodeMap
, features
: &Features
) {
761 features
: features
, parse_sess
: parse_sess
,
762 cm
: cm
, plugin_attributes
: &[]
764 cx
.check_attribute(attr
, true);
767 pub fn find_lang_feature_accepted_version(feature
: &str) -> Option
<&'
static str> {
768 ACCEPTED_FEATURES
.iter().find(|t
| t
.0 == feature
).map(|t
| t
.1)
771 fn find_lang_feature_issue(feature
: &str) -> Option
<u32> {
772 if let Some(info
) = ACTIVE_FEATURES
.iter().find(|t
| t
.0 == feature
) {
774 // FIXME (#28244): enforce that active features have issue numbers
775 // assert!(issue.is_some())
778 // search in Accepted or Removed features
779 ACCEPTED_FEATURES
.iter().chain(REMOVED_FEATURES
.iter())
780 .find(|t
| t
.0 == feature
)
790 pub fn emit_feature_err(sess
: &ParseSess
, feature
: &str, span
: Span
, issue
: GateIssue
,
792 let diag
= &sess
.span_diagnostic
;
794 let issue
= match issue
{
795 GateIssue
::Language
=> find_lang_feature_issue(feature
),
796 GateIssue
::Library(lib
) => lib
,
799 let mut err
= if let Some(n
) = issue
{
800 diag
.struct_span_err(span
, &format
!("{} (see issue #{})", explain
, n
))
802 diag
.struct_span_err(span
, explain
)
805 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
806 if sess
.unstable_features
.is_nightly_build() {
807 err
.help(&format
!("add #![feature({})] to the \
808 crate attributes to enable",
815 const EXPLAIN_BOX_SYNTAX
: &'
static str =
816 "box expression syntax is experimental; you can call `Box::new` instead.";
818 pub const EXPLAIN_STMT_ATTR_SYNTAX
: &'
static str =
819 "attributes on non-item statements and expressions are experimental.";
821 pub const EXPLAIN_ASM
: &'
static str =
822 "inline assembly is not stable enough for use and is subject to change";
824 pub const EXPLAIN_LOG_SYNTAX
: &'
static str =
825 "`log_syntax!` is not stable enough for use and is subject to change";
827 pub const EXPLAIN_CONCAT_IDENTS
: &'
static str =
828 "`concat_idents` is not stable enough for use and is subject to change";
830 pub const EXPLAIN_TRACE_MACROS
: &'
static str =
831 "`trace_macros` is not stable enough for use and is subject to change";
832 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE
: &'
static str =
833 "allow_internal_unstable side-steps feature gating and stability checks";
835 pub const EXPLAIN_CUSTOM_DERIVE
: &'
static str =
836 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
838 pub const EXPLAIN_DERIVE_UNDERSCORE
: &'
static str =
839 "attributes of the form `#[derive_*]` are reserved for the compiler";
841 pub const EXPLAIN_PLACEMENT_IN
: &'
static str =
842 "placement-in expression syntax is experimental and subject to change.";
844 struct PostExpansionVisitor
<'a
> {
845 context
: &'a Context
<'a
>,
848 macro_rules
! gate_feature_post
{
849 ($cx
: expr
, $feature
: ident
, $span
: expr
, $explain
: expr
) => {{
850 let (cx
, span
) = ($cx
, $span
);
851 if !cx
.context
.cm
.span_allows_unstable(span
) {
852 gate_feature
!(cx
.context
, $feature
, span
, $explain
)
857 impl<'a
> PostExpansionVisitor
<'a
> {
858 fn check_abi(&self, abi
: Abi
, span
: Span
) {
860 Abi
::RustIntrinsic
=> {
861 gate_feature_post
!(&self, intrinsics
, span
,
862 "intrinsics are subject to change");
864 Abi
::PlatformIntrinsic
=> {
865 gate_feature_post
!(&self, platform_intrinsics
, span
,
866 "platform intrinsics are experimental and possibly buggy");
869 gate_feature_post
!(&self, abi_vectorcall
, span
,
870 "vectorcall is experimental and subject to change");
873 gate_feature_post
!(&self, unboxed_closures
, span
,
874 "rust-call ABI is subject to change");
877 gate_feature_post
!(&self, abi_sysv64
, span
,
878 "sysv64 ABI is experimental and subject to change");
885 fn contains_novel_literal(item
: &ast
::MetaItem
) -> bool
{
886 use ast
::MetaItemKind
::*;
887 use ast
::NestedMetaItemKind
::*;
891 NameValue(_
, ref lit
) => !lit
.node
.is_str(),
892 List(_
, ref list
) => list
.iter().any(|li
| {
894 MetaItem(ref mi
) => contains_novel_literal(&**mi
),
901 impl<'a
> Visitor
for PostExpansionVisitor
<'a
> {
902 fn visit_attribute(&mut self, attr
: &ast
::Attribute
) {
903 if !self.context
.cm
.span_allows_unstable(attr
.span
) {
904 // check for gated attributes
905 self.context
.check_attribute(attr
, false);
908 if contains_novel_literal(&*(attr
.node
.value
)) {
909 gate_feature_post
!(&self, attr_literals
, attr
.span
,
910 "non-string literals in attributes, or string \
911 literals in top-level positions, are experimental");
915 fn visit_name(&mut self, sp
: Span
, name
: ast
::Name
) {
916 if !name
.as_str().is_ascii() {
917 gate_feature_post
!(&self, non_ascii_idents
, sp
,
918 "non-ascii idents are not fully supported.");
922 fn visit_item(&mut self, i
: &ast
::Item
) {
924 ast
::ItemKind
::ExternCrate(_
) => {
925 if attr
::contains_name(&i
.attrs
[..], "macro_reexport") {
926 gate_feature_post
!(&self, macro_reexport
, i
.span
,
927 "macros reexports are experimental \
928 and possibly buggy");
932 ast
::ItemKind
::ForeignMod(ref foreign_module
) => {
933 if attr
::contains_name(&i
.attrs
[..], "link_args") {
934 gate_feature_post
!(&self, link_args
, i
.span
,
935 "the `link_args` attribute is not portable \
936 across platforms, it is recommended to \
937 use `#[link(name = \"foo\")]` instead")
939 self.check_abi(foreign_module
.abi
, i
.span
);
942 ast
::ItemKind
::Fn(..) => {
943 if attr
::contains_name(&i
.attrs
[..], "plugin_registrar") {
944 gate_feature_post
!(&self, plugin_registrar
, i
.span
,
945 "compiler plugins are experimental and possibly buggy");
947 if attr
::contains_name(&i
.attrs
[..], "start") {
948 gate_feature_post
!(&self, start
, i
.span
,
949 "a #[start] function is an experimental \
950 feature whose signature may change \
953 if attr
::contains_name(&i
.attrs
[..], "main") {
954 gate_feature_post
!(&self, main
, i
.span
,
955 "declaration of a nonstandard #[main] \
956 function may change over time, for now \
957 a top-level `fn main()` is required");
961 ast
::ItemKind
::Struct(..) => {
962 if attr
::contains_name(&i
.attrs
[..], "simd") {
963 gate_feature_post
!(&self, simd
, i
.span
,
964 "SIMD types are experimental and possibly buggy");
965 self.context
.parse_sess
.span_diagnostic
.span_warn(i
.span
,
966 "the `#[simd]` attribute \
968 `#[repr(simd)]` instead");
970 for attr
in &i
.attrs
{
971 if attr
.name() == "repr" {
972 for item
in attr
.meta_item_list().unwrap_or(&[]) {
973 if item
.check_name("simd") {
974 gate_feature_post
!(&self, repr_simd
, i
.span
,
975 "SIMD types are experimental \
976 and possibly buggy");
984 ast
::ItemKind
::Union(..) => {
985 gate_feature_post
!(&self, untagged_unions
,
987 "unions are unstable and possibly buggy");
990 ast
::ItemKind
::DefaultImpl(..) => {
991 gate_feature_post
!(&self, optin_builtin_traits
,
993 "default trait implementations are experimental \
994 and possibly buggy");
997 ast
::ItemKind
::Impl(_
, polarity
, _
, _
, _
, _
) => {
999 ast
::ImplPolarity
::Negative
=> {
1000 gate_feature_post
!(&self, optin_builtin_traits
,
1002 "negative trait bounds are not yet fully implemented; \
1003 use marker types for now");
1012 visit
::walk_item(self, i
);
1015 fn visit_foreign_item(&mut self, i
: &ast
::ForeignItem
) {
1016 let links_to_llvm
= match attr
::first_attr_value_str_by_name(&i
.attrs
,
1018 Some(val
) => val
.starts_with("llvm."),
1022 gate_feature_post
!(&self, link_llvm_intrinsics
, i
.span
,
1023 "linking to LLVM intrinsics is experimental");
1026 visit
::walk_foreign_item(self, i
)
1029 fn visit_ty(&mut self, ty
: &ast
::Ty
) {
1031 ast
::TyKind
::BareFn(ref bare_fn_ty
) => {
1032 self.check_abi(bare_fn_ty
.abi
, ty
.span
);
1034 ast
::TyKind
::ImplTrait(..) => {
1035 gate_feature_post
!(&self, conservative_impl_trait
, ty
.span
,
1036 "`impl Trait` is experimental");
1038 ast
::TyKind
::Never
=> {
1039 gate_feature_post
!(&self, never_type
, ty
.span
,
1040 "The `!` type is experimental");
1044 visit
::walk_ty(self, ty
)
1047 fn visit_fn_ret_ty(&mut self, ret_ty
: &ast
::FunctionRetTy
) {
1048 if let ast
::FunctionRetTy
::Ty(ref output_ty
) = *ret_ty
{
1049 match output_ty
.node
{
1050 ast
::TyKind
::Never
=> return,
1053 self.visit_ty(output_ty
)
1057 fn visit_expr(&mut self, e
: &ast
::Expr
) {
1059 ast
::ExprKind
::Box(_
) => {
1060 gate_feature_post
!(&self, box_syntax
, e
.span
, EXPLAIN_BOX_SYNTAX
);
1062 ast
::ExprKind
::Type(..) => {
1063 gate_feature_post
!(&self, type_ascription
, e
.span
,
1064 "type ascription is experimental");
1066 ast
::ExprKind
::Range(_
, _
, ast
::RangeLimits
::Closed
) => {
1067 gate_feature_post
!(&self, inclusive_range_syntax
,
1069 "inclusive range syntax is experimental");
1071 ast
::ExprKind
::InPlace(..) => {
1072 gate_feature_post
!(&self, placement_in_syntax
, e
.span
, EXPLAIN_PLACEMENT_IN
);
1076 visit
::walk_expr(self, e
);
1079 fn visit_pat(&mut self, pattern
: &ast
::Pat
) {
1080 match pattern
.node
{
1081 PatKind
::Vec(_
, Some(_
), ref last
) if !last
.is_empty() => {
1082 gate_feature_post
!(&self, advanced_slice_patterns
,
1084 "multiple-element slice matches anywhere \
1085 but at the end of a slice (e.g. \
1086 `[0, ..xs, 0]`) are experimental")
1088 PatKind
::Vec(..) => {
1089 gate_feature_post
!(&self, slice_patterns
,
1091 "slice pattern syntax is experimental");
1093 PatKind
::Box(..) => {
1094 gate_feature_post
!(&self, box_patterns
,
1096 "box pattern syntax is experimental");
1098 PatKind
::Tuple(_
, ddpos
)
1099 if ddpos
.is_some() => {
1100 gate_feature_post
!(&self, dotdot_in_tuple_patterns
,
1102 "`..` in tuple patterns is experimental");
1104 PatKind
::TupleStruct(_
, ref fields
, ddpos
)
1105 if ddpos
.is_some() && !fields
.is_empty() => {
1106 gate_feature_post
!(&self, dotdot_in_tuple_patterns
,
1108 "`..` in tuple struct patterns is experimental");
1110 PatKind
::TupleStruct(_
, ref fields
, ddpos
)
1111 if ddpos
.is_none() && fields
.is_empty() => {
1112 gate_feature_post
!(&self, relaxed_adts
, pattern
.span
,
1113 "empty tuple structs patterns are unstable");
1117 visit
::walk_pat(self, pattern
)
1120 fn visit_fn(&mut self,
1122 fn_decl
: &ast
::FnDecl
,
1126 // check for const fn declarations
1128 FnKind
::ItemFn(_
, _
, _
, Spanned { node: ast::Constness::Const, .. }
, _
, _
) => {
1129 gate_feature_post
!(&self, const_fn
, span
, "const fn is unstable");
1132 // stability of const fn methods are covered in
1133 // visit_trait_item and visit_impl_item below; this is
1134 // because default methods don't pass through this
1140 FnKind
::ItemFn(_
, _
, _
, _
, abi
, _
) |
1141 FnKind
::Method(_
, &ast
::MethodSig { abi, .. }
, _
) => {
1142 self.check_abi(abi
, span
);
1146 visit
::walk_fn(self, fn_kind
, fn_decl
, block
, span
);
1149 fn visit_trait_item(&mut self, ti
: &ast
::TraitItem
) {
1151 ast
::TraitItemKind
::Const(..) => {
1152 gate_feature_post
!(&self, associated_consts
,
1154 "associated constants are experimental")
1156 ast
::TraitItemKind
::Method(ref sig
, ref block
) => {
1157 if block
.is_none() {
1158 self.check_abi(sig
.abi
, ti
.span
);
1160 if sig
.constness
.node
== ast
::Constness
::Const
{
1161 gate_feature_post
!(&self, const_fn
, ti
.span
, "const fn is unstable");
1164 ast
::TraitItemKind
::Type(_
, Some(_
)) => {
1165 gate_feature_post
!(&self, associated_type_defaults
, ti
.span
,
1166 "associated type defaults are unstable");
1170 visit
::walk_trait_item(self, ti
);
1173 fn visit_impl_item(&mut self, ii
: &ast
::ImplItem
) {
1174 if ii
.defaultness
== ast
::Defaultness
::Default
{
1175 gate_feature_post
!(&self, specialization
,
1177 "specialization is unstable");
1181 ast
::ImplItemKind
::Const(..) => {
1182 gate_feature_post
!(&self, associated_consts
,
1184 "associated constants are experimental")
1186 ast
::ImplItemKind
::Method(ref sig
, _
) => {
1187 if sig
.constness
.node
== ast
::Constness
::Const
{
1188 gate_feature_post
!(&self, const_fn
, ii
.span
, "const fn is unstable");
1193 visit
::walk_impl_item(self, ii
);
1196 fn visit_variant_data(&mut self, vdata
: &ast
::VariantData
, _
: ast
::Ident
,
1197 _
: &ast
::Generics
, _
: NodeId
, span
: Span
) {
1198 if vdata
.fields().is_empty() {
1199 if vdata
.is_tuple() {
1200 gate_feature_post
!(&self, relaxed_adts
, span
,
1201 "empty tuple structs and enum variants are unstable, \
1202 use unit structs and enum variants instead");
1206 visit
::walk_struct_def(self, vdata
)
1209 fn visit_vis(&mut self, vis
: &ast
::Visibility
) {
1210 let span
= match *vis
{
1211 ast
::Visibility
::Crate(span
) => span
,
1212 ast
::Visibility
::Restricted { ref path, .. }
=> path
.span
,
1215 gate_feature_post
!(&self, pub_restricted
, span
, "`pub(restricted)` syntax is experimental");
1217 visit
::walk_vis(self, vis
)
1221 pub fn get_features(span_handler
: &Handler
, krate_attrs
: &[ast
::Attribute
]) -> Features
{
1222 let mut features
= Features
::new();
1224 for attr
in krate_attrs
{
1225 if !attr
.check_name("feature") {
1229 match attr
.meta_item_list() {
1231 span_err
!(span_handler
, attr
.span
, E0555
,
1232 "malformed feature attribute, expected #![feature(...)]");
1236 let name
= if let Some(word
) = mi
.word() {
1239 span_err
!(span_handler
, mi
.span
, E0556
,
1240 "malformed feature, expected just one word");
1244 if let Some(&(_
, _
, _
, setter
)) = ACTIVE_FEATURES
.iter()
1245 .find(|& &(n
, _
, _
, _
)| name
== n
) {
1246 *(setter(&mut features
)) = true;
1248 else if let Some(&(_
, _
, _
)) = REMOVED_FEATURES
.iter()
1249 .find(|& &(n
, _
, _
)| name
== n
) {
1250 span_err
!(span_handler
, mi
.span
, E0557
, "feature has been removed");
1252 else if let Some(&(_
, _
, _
)) = ACCEPTED_FEATURES
.iter()
1253 .find(|& &(n
, _
, _
)| name
== n
) {
1254 features
.declared_stable_lang_features
.push((name
, mi
.span
));
1256 features
.declared_lib_features
.push((name
, mi
.span
));
1266 pub fn check_crate(krate
: &ast
::Crate
,
1268 features
: &Features
,
1269 plugin_attributes
: &[(String
, AttributeType
)],
1270 unstable
: UnstableFeatures
) {
1271 maybe_stage_features(&sess
.span_diagnostic
, krate
, unstable
);
1276 plugin_attributes
: plugin_attributes
,
1278 visit
::walk_crate(&mut PostExpansionVisitor { context: &ctx }
, krate
);
1281 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1282 pub enum UnstableFeatures
{
1283 /// Hard errors for unstable features are active, as on
1284 /// beta/stable channels.
1286 /// Allow features to me activated, as on nightly.
1288 /// Errors are bypassed for bootstrapping. This is required any time
1289 /// during the build that feature-related lints are set to warn or above
1290 /// because the build turns on warnings-as-errors and uses lots of unstable
1291 /// features. As a result, this is always required for building Rust itself.
1295 impl UnstableFeatures
{
1296 pub fn from_environment() -> UnstableFeatures
{
1297 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1298 let disable_unstable_features
= option_env
!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1299 // Whether we should enable unstable features for bootstrapping
1300 let bootstrap
= env
::var("RUSTC_BOOTSTRAP").is_ok();
1301 match (disable_unstable_features
, bootstrap
) {
1302 (_
, true) => UnstableFeatures
::Cheat
,
1303 (true, _
) => UnstableFeatures
::Disallow
,
1304 (false, _
) => UnstableFeatures
::Allow
1308 pub fn is_nightly_build(&self) -> bool
{
1310 UnstableFeatures
::Allow
| UnstableFeatures
::Cheat
=> true,
1316 fn maybe_stage_features(span_handler
: &Handler
, krate
: &ast
::Crate
,
1317 unstable
: UnstableFeatures
) {
1318 let allow_features
= match unstable
{
1319 UnstableFeatures
::Allow
=> true,
1320 UnstableFeatures
::Disallow
=> false,
1321 UnstableFeatures
::Cheat
=> true
1323 if !allow_features
{
1324 for attr
in &krate
.attrs
{
1325 if attr
.check_name("feature") {
1326 let release_channel
= option_env
!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1327 span_err
!(span_handler
, attr
.span
, E0554
,
1328 "#[feature] may not be used on the {} release channel",