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};
33 use errors::{DiagnosticBuilder, Handler};
34 use visit::{self, FnKind, Visitor};
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<(Symbol, Span)>,
63 /// #![feature] attrs for non-language (library) features
64 pub declared_lib_features: Vec<(Symbol, 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)),
130 (active, allocator, "1.0.0", Some(27389)),
131 (active, fundamental, "1.0.0", Some(29635)),
132 (active, main, "1.0.0", Some(29634)),
133 (active, needs_allocator, "1.4.0", Some(27389)),
134 (active, on_unimplemented, "1.0.0", Some(29628)),
135 (active, plugin, "1.0.0", Some(29597)),
136 (active, simd_ffi, "1.0.0", Some(27731)),
137 (active, start, "1.0.0", Some(29633)),
138 (active, structural_match, "1.8.0", Some(31434)),
139 (active, panic_runtime, "1.10.0", Some(32837)),
140 (active, needs_panic_runtime, "1.10.0", Some(32837)),
142 // OIBIT specific features
143 (active, optin_builtin_traits, "1.0.0", Some(13231)),
145 // macro reexport needs more discussion and stabilization
146 (active, macro_reexport, "1.0.0", Some(29638)),
148 // Allows use of #[staged_api]
150 (active, staged_api, "1.0.0", None),
152 // Allows using #![no_core]
153 (active, no_core, "1.3.0", Some(29639)),
155 // Allows using `box` in patterns; RFC 469
156 (active, box_patterns, "1.0.0", Some(29641)),
158 // Allows using the unsafe_destructor_blind_to_params attribute;
160 (active, dropck_parametricity, "1.3.0", Some(28498)),
162 // Allows using the may_dangle attribute; RFC 1327
163 (active, dropck_eyepatch, "1.10.0", Some(34761)),
165 // Allows the use of custom attributes; RFC 572
166 (active, custom_attribute, "1.0.0", Some(29642)),
168 // Allows the use of #[derive(Anything)] as sugar for
169 // #[derive_Anything].
170 (active, custom_derive, "1.0.0", Some(29644)),
172 // Allows the use of rustc_* attributes; RFC 572
173 (active, rustc_attrs, "1.0.0", Some(29642)),
175 // Allows the use of #[allow_internal_unstable]. This is an
176 // attribute on macro_rules! and can't use the attribute handling
177 // below (it has to be checked before expansion possibly makes
178 // macros disappear).
181 (active, allow_internal_unstable, "1.0.0", None),
183 // #23121. Array patterns have some hazards yet.
184 (active, slice_patterns, "1.0.0", Some(23121)),
186 // Allows the definition of associated constants in `trait` or `impl`
188 (active, associated_consts, "1.0.0", Some(29646)),
190 // Allows the definition of `const fn` functions.
191 (active, const_fn, "1.2.0", Some(24111)),
193 // Allows indexing into constant arrays.
194 (active, const_indexing, "1.4.0", Some(29947)),
196 // Allows using #[prelude_import] on glob `use` items.
199 (active, prelude_import, "1.2.0", None),
201 // Allows the definition recursive static items.
202 (active, static_recursion, "1.3.0", Some(29719)),
204 // Allows default type parameters to influence type inference.
205 (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
207 // Allows associated type defaults
208 (active, associated_type_defaults, "1.2.0", Some(29661)),
210 // allow `repr(simd)`, and importing the various simd intrinsics
211 (active, repr_simd, "1.4.0", Some(27731)),
213 // Allows cfg(target_feature = "...").
214 (active, cfg_target_feature, "1.4.0", Some(29717)),
216 // allow `extern "platform-intrinsic" { ... }`
217 (active, platform_intrinsics, "1.4.0", Some(27731)),
220 // rust runtime internal
221 (active, unwind_attributes, "1.4.0", None),
223 // allow the use of `#[naked]` on functions.
224 (active, naked_functions, "1.9.0", Some(32408)),
226 // allow `#[no_debug]`
227 (active, no_debug, "1.5.0", Some(29721)),
229 // allow `#[omit_gdb_pretty_printer_section]`
231 (active, omit_gdb_pretty_printer_section, "1.5.0", None),
233 // Allows cfg(target_vendor = "...").
234 (active, cfg_target_vendor, "1.5.0", Some(29718)),
236 // Allow attributes on expressions and non-item statements
237 (active, stmt_expr_attributes, "1.6.0", Some(15701)),
239 // allow using type ascription in expressions
240 (active, type_ascription, "1.6.0", Some(23416)),
242 // Allows cfg(target_thread_local)
243 (active, cfg_target_thread_local, "1.7.0", Some(29594)),
246 (active, abi_vectorcall, "1.7.0", None),
249 (active, inclusive_range_syntax, "1.7.0", Some(28237)),
251 // impl specialization (RFC 1210)
252 (active, specialization, "1.7.0", Some(31844)),
254 // pub(restricted) visibilities (RFC 1422)
255 (active, pub_restricted, "1.9.0", Some(32409)),
257 // Allow Drop types in statics/const functions (RFC 1440)
258 (active, drop_types_in_const, "1.9.0", Some(33156)),
260 // Allows cfg(target_has_atomic = "...").
261 (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
263 // Allows `impl Trait` in function return types.
264 (active, conservative_impl_trait, "1.12.0", Some(34511)),
266 // Permits numeric fields in struct expressions and patterns.
267 (active, relaxed_adts, "1.12.0", Some(35626)),
270 (active, never_type, "1.13.0", Some(35121)),
272 // Allows all literals in attribute lists and values of key-value pairs.
273 (active, attr_literals, "1.13.0", Some(34981)),
275 // Allows the sysV64 ABI to be specified on all platforms
276 // instead of just the platforms on which it is the C ABI
277 (active, abi_sysv64, "1.13.0", Some(36167)),
279 // Allows untagged unions `union U { ... }`
280 (active, untagged_unions, "1.13.0", Some(32836)),
282 // elide `'static` lifetimes in `static`s and `const`s
283 (active, static_in_const, "1.13.0", Some(35897)),
285 // Used to identify the `compiler_builtins` crate
287 (active, compiler_builtins, "1.13.0", None),
289 // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
290 (active, generic_param_attrs, "1.11.0", Some(34761)),
292 // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
293 (active, field_init_shorthand, "1.14.0", Some(37340)),
295 // The #![windows_subsystem] attribute
296 (active, windows_subsystem, "1.14.0", Some(37499)),
298 // Allows using `Self` and associated types in struct expressions and patterns.
299 (active, more_struct_aliases, "1.14.0", Some(37544)),
302 // Allows #[link(..., cfg(..))]
303 (active, link_cfg, "1.14.0", Some(37406)),
305 (active, use_extern_macros, "1.15.0", Some(35896)),
307 // Allows `break {expr}` with a value inside `loop`s.
308 (active, loop_break_value, "1.14.0", Some(37339)),
310 // Allows #[target_feature(...)]
311 (active, target_feature, "1.15.0", None),
313 // `extern "ptx-*" fn()`
314 (active, abi_ptx, "1.15.0", None),
317 (active, i128_type, "1.16.0", Some(35118)),
319 // The `unadjusted` ABI. Perma unstable.
320 (active, abi_unadjusted, "1.16.0", None),
322 // Allows attributes on struct literal fields.
323 (active, struct_field_attributes, "1.16.0", Some(38814)),
325 // `extern "msp430-interrupt" fn()`
326 (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
330 (removed, import_shadowing, "1.0.0", None),
331 (removed, managed_boxes, "1.0.0", None),
332 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
333 (removed, negate_unsigned, "1.0.0", Some(29645)),
334 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
335 (removed, opt_out_copy, "1.0.0", None),
336 (removed, quad_precision_float, "1.0.0", None),
337 (removed, struct_inherit, "1.0.0", None),
338 (removed, test_removed_feature, "1.0.0", None),
339 (removed, visible_private_types, "1.0.0", None),
340 (removed, unsafe_no_drop_flag, "1.0.0", None),
341 // Allows using items which are missing stability attributes
343 (removed, unmarked_api, "1.0.0", None),
344 (removed, pushpop_unsafe, "1.2.0", None),
348 (accepted, associated_types, "1.0.0", None),
349 // allow overloading augmented assignment operations like `a += b`
350 (accepted, augmented_assignments, "1.8.0", Some(28235)),
351 // allow empty structs and enum variants with braces
352 (accepted, braced_empty_structs, "1.8.0", Some(29720)),
353 (accepted, default_type_params, "1.0.0", None),
354 (accepted, globs, "1.0.0", None),
355 (accepted, if_let, "1.0.0", None),
356 // A temporary feature gate used to enable parser extensions needed
357 // to bootstrap fix for #5723.
358 (accepted, issue_5723_bootstrap, "1.0.0", None),
359 (accepted, macro_rules, "1.0.0", None),
360 // Allows using #![no_std]
361 (accepted, no_std, "1.6.0", None),
362 (accepted, slicing_syntax, "1.0.0", None),
363 (accepted, struct_variant, "1.0.0", None),
364 // These are used to test this portion of the compiler, they don't actually
366 (accepted, test_accepted_feature, "1.0.0", None),
367 (accepted, tuple_indexing, "1.0.0", None),
368 // Allows macros to appear in the type position.
369 (accepted, type_macros, "1.13.0", Some(27245)),
370 (accepted, while_let, "1.0.0", None),
371 // Allows `#[deprecated]` attribute
372 (accepted, deprecated, "1.9.0", Some(29935)),
374 (accepted, question_mark, "1.13.0", Some(31436)),
375 // Allows `..` in tuple (struct) patterns
376 (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
377 (accepted, item_like_imports, "1.14.0", Some(35120)),
379 (accepted, proc_macro, "1.15.0", Some(35900)),
381 // (changing above list without updating src/doc/reference.md makes @cmr sad)
383 #[derive(PartialEq, Copy, Clone, Debug)]
384 pub enum AttributeType {
385 /// Normal, builtin attribute that is consumed
386 /// by the compiler before the unused_attribute check
389 /// Builtin attribute that may not be consumed by the compiler
390 /// before the unused_attribute check. These attributes
391 /// will be ignored by the unused_attribute lint
394 /// Builtin attribute that is only allowed at the crate level
398 pub enum AttributeGate {
399 /// Is gated by a given feature gate, reason
400 /// and function to check if enabled
401 Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
403 /// Ungated attribute, can be used on all release channels
408 fn is_deprecated(&self) -> bool {
410 Gated(Stability::Deprecated(_), ..) => true,
416 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
419 // Argument is tracking issue link.
420 Deprecated(&'static str),
424 impl ::std::fmt::Debug for AttributeGate {
425 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
427 Gated(ref stab, ref name, ref expl, _) =>
428 write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
429 Ungated => write!(fmt, "Ungated")
434 macro_rules! cfg_fn {
435 ($field: ident) => {{
436 fn f(features: &Features) -> bool {
439 f as fn(&Features) -> bool
443 pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
444 BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
447 // Attributes that have a special meaning to rustc or rustdoc
448 pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
451 ("warn", Normal, Ungated),
452 ("allow", Normal, Ungated),
453 ("forbid", Normal, Ungated),
454 ("deny", Normal, Ungated),
456 ("macro_reexport", Normal, Ungated),
457 ("macro_use", Normal, Ungated),
458 ("macro_export", Normal, Ungated),
459 ("plugin_registrar", Normal, Ungated),
461 ("cfg", Normal, Ungated),
462 ("cfg_attr", Normal, Ungated),
463 ("main", Normal, Ungated),
464 ("start", Normal, Ungated),
465 ("test", Normal, Ungated),
466 ("bench", Normal, Ungated),
467 ("simd", Normal, Ungated),
468 ("repr", Normal, Ungated),
469 ("path", Normal, Ungated),
470 ("abi", Normal, Ungated),
471 ("automatically_derived", Normal, Ungated),
472 ("no_mangle", Normal, Ungated),
473 ("no_link", Normal, Ungated),
474 ("derive", Normal, Ungated),
475 ("should_panic", Normal, Ungated),
476 ("ignore", Normal, Ungated),
477 ("no_implicit_prelude", Normal, Ungated),
478 ("reexport_test_harness_main", Normal, Ungated),
479 ("link_args", Normal, Ungated),
480 ("macro_escape", Normal, Ungated),
483 ("structural_match", Whitelisted, Gated(Stability::Unstable,
485 "the semantics of constant patterns is \
487 cfg_fn!(structural_match))),
489 // Not used any more, but we can't feature gate it
490 ("no_stack_check", Normal, Ungated),
492 ("plugin", CrateLevel, Gated(Stability::Unstable,
494 "compiler plugins are experimental \
498 ("no_std", CrateLevel, Ungated),
499 ("no_core", CrateLevel, Gated(Stability::Unstable,
501 "no_core is experimental",
503 ("lang", Normal, Gated(Stability::Unstable,
505 "language items are subject to change",
506 cfg_fn!(lang_items))),
507 ("linkage", Whitelisted, Gated(Stability::Unstable,
509 "the `linkage` attribute is experimental \
510 and not portable across platforms",
512 ("thread_local", Whitelisted, Gated(Stability::Unstable,
514 "`#[thread_local]` is an experimental feature, and does \
515 not currently handle destructors. There is no \
516 corresponding `#[task_local]` mapping to the task \
518 cfg_fn!(thread_local))),
520 ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
522 "the `#[rustc_on_unimplemented]` attribute \
523 is an experimental feature",
524 cfg_fn!(on_unimplemented))),
525 ("allocator", Whitelisted, Gated(Stability::Unstable,
527 "the `#[allocator]` attribute is an experimental feature",
528 cfg_fn!(allocator))),
529 ("needs_allocator", Normal, Gated(Stability::Unstable,
531 "the `#[needs_allocator]` \
532 attribute is an experimental \
534 cfg_fn!(needs_allocator))),
535 ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
537 "the `#[panic_runtime]` attribute is \
538 an experimental feature",
539 cfg_fn!(panic_runtime))),
540 ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
541 "needs_panic_runtime",
542 "the `#[needs_panic_runtime]` \
543 attribute is an experimental \
545 cfg_fn!(needs_panic_runtime))),
546 ("rustc_variance", Normal, Gated(Stability::Unstable,
548 "the `#[rustc_variance]` attribute \
549 is just used for rustc unit tests \
550 and will never be stable",
551 cfg_fn!(rustc_attrs))),
552 ("rustc_error", Whitelisted, Gated(Stability::Unstable,
554 "the `#[rustc_error]` attribute \
555 is just used for rustc unit tests \
556 and will never be stable",
557 cfg_fn!(rustc_attrs))),
558 ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
560 "the `#[rustc_if_this_changed]` attribute \
561 is just used for rustc unit tests \
562 and will never be stable",
563 cfg_fn!(rustc_attrs))),
564 ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
566 "the `#[rustc_if_this_changed]` attribute \
567 is just used for rustc unit tests \
568 and will never be stable",
569 cfg_fn!(rustc_attrs))),
570 ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
572 "the `#[rustc_dirty]` attribute \
573 is just used for rustc unit tests \
574 and will never be stable",
575 cfg_fn!(rustc_attrs))),
576 ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
578 "the `#[rustc_clean]` attribute \
579 is just used for rustc unit tests \
580 and will never be stable",
581 cfg_fn!(rustc_attrs))),
582 ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
584 "the `#[rustc_metadata_dirty]` attribute \
585 is just used for rustc unit tests \
586 and will never be stable",
587 cfg_fn!(rustc_attrs))),
588 ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
590 "the `#[rustc_metadata_clean]` attribute \
591 is just used for rustc unit tests \
592 and will never be stable",
593 cfg_fn!(rustc_attrs))),
594 ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
597 is just used for rustc unit tests \
598 and will never be stable",
599 cfg_fn!(rustc_attrs))),
600 ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
603 is just used for rustc unit tests \
604 and will never be stable",
605 cfg_fn!(rustc_attrs))),
606 ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
608 "internal rustc attributes will never be stable",
609 cfg_fn!(rustc_attrs))),
610 ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
612 "internal rustc attributes will never be stable",
613 cfg_fn!(rustc_attrs))),
614 ("rustc_move_fragments", Normal, Gated(Stability::Unstable,
616 "the `#[rustc_move_fragments]` attribute \
617 is just used for rustc unit tests \
618 and will never be stable",
619 cfg_fn!(rustc_attrs))),
620 ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
622 "the `#[rustc_mir]` attribute \
623 is just used for rustc unit tests \
624 and will never be stable",
625 cfg_fn!(rustc_attrs))),
626 ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
628 "the `#[rustc_inherit_overflow_checks]` \
629 attribute is just used to control \
630 overflow checking behavior of several \
631 libcore functions that are inlined \
632 across crates and will never be stable",
633 cfg_fn!(rustc_attrs))),
634 ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
636 "the `#[compiler_builtins]` attribute is used to \
637 identify the `compiler_builtins` crate which \
638 contains compiler-rt intrinsics and will never be \
640 cfg_fn!(compiler_builtins))),
642 ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
643 "allow_internal_unstable",
644 EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
645 cfg_fn!(allow_internal_unstable))),
647 ("fundamental", Whitelisted, Gated(Stability::Unstable,
649 "the `#[fundamental]` attribute \
650 is an experimental feature",
651 cfg_fn!(fundamental))),
653 ("proc_macro_derive", Normal, Ungated),
655 ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
657 "internal implementation detail",
658 cfg_fn!(rustc_attrs))),
660 // FIXME: #14408 whitelist docs since rustdoc looks at them
661 ("doc", Whitelisted, Ungated),
663 // FIXME: #14406 these are processed in trans, which happens after the
665 ("cold", Whitelisted, Ungated),
666 ("naked", Whitelisted, Gated(Stability::Unstable,
668 "the `#[naked]` attribute \
669 is an experimental feature",
670 cfg_fn!(naked_functions))),
671 ("target_feature", Whitelisted, Gated(
672 Stability::Unstable, "target_feature",
673 "the `#[target_feature]` attribute is an experimental feature",
674 cfg_fn!(target_feature))),
675 ("export_name", Whitelisted, Ungated),
676 ("inline", Whitelisted, Ungated),
677 ("link", Whitelisted, Ungated),
678 ("link_name", Whitelisted, Ungated),
679 ("link_section", Whitelisted, Ungated),
680 ("no_builtins", Whitelisted, Ungated),
681 ("no_mangle", Whitelisted, Ungated),
682 ("no_debug", Whitelisted, Gated(
683 Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
685 "the `#[no_debug]` attribute is an experimental feature",
687 ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
688 "omit_gdb_pretty_printer_section",
689 "the `#[omit_gdb_pretty_printer_section]` \
690 attribute is just used for the Rust test \
692 cfg_fn!(omit_gdb_pretty_printer_section))),
693 ("unsafe_destructor_blind_to_params",
695 Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761"),
696 "dropck_parametricity",
697 "unsafe_destructor_blind_to_params has been replaced by \
698 may_dangle and will be removed in the future",
699 cfg_fn!(dropck_parametricity))),
702 Gated(Stability::Unstable,
704 "may_dangle has unstable semantics and may be removed in the future",
705 cfg_fn!(dropck_eyepatch))),
706 ("unwind", Whitelisted, Gated(Stability::Unstable,
708 "#[unwind] is experimental",
709 cfg_fn!(unwind_attributes))),
712 ("prelude_import", Whitelisted, Gated(Stability::Unstable,
714 "`#[prelude_import]` is for use by rustc only",
715 cfg_fn!(prelude_import))),
717 // FIXME: #14407 these are only looked at on-demand so we can't
718 // guarantee they'll have already been checked
719 ("rustc_deprecated", Whitelisted, Ungated),
720 ("must_use", Whitelisted, Ungated),
721 ("stable", Whitelisted, Ungated),
722 ("unstable", Whitelisted, Ungated),
723 ("deprecated", Normal, Ungated),
725 ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
727 "unboxed_closures are still evolving",
728 cfg_fn!(unboxed_closures))),
729 ("rustc_reflect_like", Whitelisted, Gated(Stability::Unstable,
731 "defining reflective traits is still evolving",
734 ("windows_subsystem", Whitelisted, Gated(Stability::Unstable,
736 "the windows subsystem attribute \
737 is currently unstable",
738 cfg_fn!(windows_subsystem))),
740 // Crate level attributes
741 ("crate_name", CrateLevel, Ungated),
742 ("crate_type", CrateLevel, Ungated),
743 ("crate_id", CrateLevel, Ungated),
744 ("feature", CrateLevel, Ungated),
745 ("no_start", CrateLevel, Ungated),
746 ("no_main", CrateLevel, Ungated),
747 ("no_builtins", CrateLevel, Ungated),
748 ("recursion_limit", CrateLevel, Ungated),
749 ("type_length_limit", CrateLevel, Ungated),
752 // cfg(...)'s that are feature gated
753 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
754 // (name in cfg, feature, function to check if the feature is enabled)
755 ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
756 ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
757 ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
758 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
761 #[derive(Debug, Eq, PartialEq)]
762 pub struct GatedCfg {
768 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
769 let name = &*cfg.name().as_str();
771 .position(|info| info.0 == name)
780 pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
781 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
782 if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
783 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
784 emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
790 features: &'a Features,
791 parse_sess: &'a ParseSess,
793 plugin_attributes: &'a [(String, AttributeType)],
796 macro_rules! gate_feature_fn {
797 ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
798 let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
799 let has_feature: bool = has_feature(&$cx.features);
800 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
801 if !has_feature && !cx.cm.span_allows_unstable(span) {
802 emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
807 macro_rules! gate_feature {
808 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
809 gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
813 impl<'a> Context<'a> {
814 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
815 debug!("check_attribute(attr = {:?})", attr);
816 let name = &*attr.name().as_str();
817 for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
819 if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
820 gate_feature_fn!(self, has_feature, attr.span, name, desc);
822 debug!("check_attribute: {:?} is builtin, {:?}, {:?}", name, ty, gateage);
826 for &(ref n, ref ty) in self.plugin_attributes {
828 // Plugins can't gate attributes, so we don't check for it
829 // unlike the code above; we only use this loop to
830 // short-circuit to avoid the checks below
831 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
835 if name.starts_with("rustc_") {
836 gate_feature!(self, rustc_attrs, attr.span,
837 "unless otherwise specified, attributes \
838 with the prefix `rustc_` \
839 are reserved for internal compiler diagnostics");
840 } else if name.starts_with("derive_") {
841 gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
842 } else if attr::is_known(attr) {
843 debug!("check_attribute: {:?} is known", name);
845 // Only run the custom attribute lint during regular
846 // feature gate checking. Macro gating runs
847 // before the plugin attributes are registered
848 // so we skip this then
850 gate_feature!(self, custom_attribute, attr.span,
851 &format!("The attribute `{}` is currently \
852 unknown to the compiler and \
854 added to it in the future",
861 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
862 cm: &CodeMap, features: &Features) {
864 features: features, parse_sess: parse_sess,
865 cm: cm, plugin_attributes: &[]
867 cx.check_attribute(attr, true);
870 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
871 ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
874 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
875 if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
877 // FIXME (#28244): enforce that active features have issue numbers
878 // assert!(issue.is_some())
881 // search in Accepted or Removed features
882 ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES.iter())
883 .find(|t| t.0 == feature)
893 pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
895 feature_err(sess, feature, span, issue, explain).emit();
898 pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
899 explain: &str) -> DiagnosticBuilder<'a> {
900 let diag = &sess.span_diagnostic;
902 let issue = match issue {
903 GateIssue::Language => find_lang_feature_issue(feature),
904 GateIssue::Library(lib) => lib,
907 let mut err = if let Some(n) = issue {
908 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
910 diag.struct_span_err(span, explain)
913 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
914 if sess.unstable_features.is_nightly_build() {
915 err.help(&format!("add #![feature({})] to the \
916 crate attributes to enable",
923 const EXPLAIN_BOX_SYNTAX: &'static str =
924 "box expression syntax is experimental; you can call `Box::new` instead.";
926 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
927 "attributes on non-item statements and expressions are experimental.";
929 pub const EXPLAIN_ASM: &'static str =
930 "inline assembly is not stable enough for use and is subject to change";
932 pub const EXPLAIN_LOG_SYNTAX: &'static str =
933 "`log_syntax!` is not stable enough for use and is subject to change";
935 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
936 "`concat_idents` is not stable enough for use and is subject to change";
938 pub const EXPLAIN_TRACE_MACROS: &'static str =
939 "`trace_macros` is not stable enough for use and is subject to change";
940 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
941 "allow_internal_unstable side-steps feature gating and stability checks";
943 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
944 "`#[derive]` for custom traits is not stable enough for use. It is deprecated and will \
945 be removed in v1.15";
947 pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
948 "`#[derive]` for custom traits is deprecated and will be removed in v1.15. Prefer using \
949 procedural macro custom derive";
951 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
952 "attributes of the form `#[derive_*]` are reserved for the compiler";
954 pub const EXPLAIN_PLACEMENT_IN: &'static str =
955 "placement-in expression syntax is experimental and subject to change.";
957 struct PostExpansionVisitor<'a> {
958 context: &'a Context<'a>,
961 macro_rules! gate_feature_post {
962 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
963 let (cx, span) = ($cx, $span);
964 if !cx.context.cm.span_allows_unstable(span) {
965 gate_feature!(cx.context, $feature, span, $explain)
970 impl<'a> PostExpansionVisitor<'a> {
971 fn check_abi(&self, abi: Abi, span: Span) {
973 Abi::RustIntrinsic => {
974 gate_feature_post!(&self, intrinsics, span,
975 "intrinsics are subject to change");
977 Abi::PlatformIntrinsic => {
978 gate_feature_post!(&self, platform_intrinsics, span,
979 "platform intrinsics are experimental and possibly buggy");
982 gate_feature_post!(&self, abi_vectorcall, span,
983 "vectorcall is experimental and subject to change");
986 gate_feature_post!(&self, unboxed_closures, span,
987 "rust-call ABI is subject to change");
990 gate_feature_post!(&self, abi_sysv64, span,
991 "sysv64 ABI is experimental and subject to change");
994 gate_feature_post!(&self, abi_ptx, span,
995 "PTX ABIs are experimental and subject to change");
998 gate_feature_post!(&self, abi_unadjusted, span,
999 "unadjusted ABI is an implementation detail and perma-unstable");
1001 Abi::Msp430Interrupt => {
1002 gate_feature_post!(&self, abi_msp430_interrupt, span,
1003 "msp430-interrupt ABI is experimental and subject to change");
1018 fn contains_novel_literal(item: &ast::MetaItem) -> bool {
1019 use ast::MetaItemKind::*;
1020 use ast::NestedMetaItemKind::*;
1024 NameValue(ref lit) => !lit.node.is_str(),
1025 List(ref list) => list.iter().any(|li| {
1027 MetaItem(ref mi) => contains_novel_literal(&mi),
1034 fn starts_with_digit(s: &str) -> bool {
1035 s.as_bytes().first().cloned().map_or(false, |b| b >= b'0' && b <= b'9')
1038 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1039 fn visit_attribute(&mut self, attr: &ast::Attribute) {
1040 if !self.context.cm.span_allows_unstable(attr.span) {
1041 // check for gated attributes
1042 self.context.check_attribute(attr, false);
1045 if contains_novel_literal(&attr.value) {
1046 gate_feature_post!(&self, attr_literals, attr.span,
1047 "non-string literals in attributes, or string \
1048 literals in top-level positions, are experimental");
1052 fn visit_name(&mut self, sp: Span, name: ast::Name) {
1053 if !name.as_str().is_ascii() {
1054 gate_feature_post!(&self, non_ascii_idents, sp,
1055 "non-ascii idents are not fully supported.");
1059 fn visit_item(&mut self, i: &'a ast::Item) {
1061 ast::ItemKind::ExternCrate(_) => {
1062 if attr::contains_name(&i.attrs[..], "macro_reexport") {
1063 gate_feature_post!(&self, macro_reexport, i.span,
1064 "macros reexports are experimental \
1065 and possibly buggy");
1069 ast::ItemKind::ForeignMod(ref foreign_module) => {
1070 if attr::contains_name(&i.attrs[..], "link_args") {
1071 gate_feature_post!(&self, link_args, i.span,
1072 "the `link_args` attribute is not portable \
1073 across platforms, it is recommended to \
1074 use `#[link(name = \"foo\")]` instead")
1076 self.check_abi(foreign_module.abi, i.span);
1079 ast::ItemKind::Fn(..) => {
1080 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1081 gate_feature_post!(&self, plugin_registrar, i.span,
1082 "compiler plugins are experimental and possibly buggy");
1084 if attr::contains_name(&i.attrs[..], "start") {
1085 gate_feature_post!(&self, start, i.span,
1086 "a #[start] function is an experimental \
1087 feature whose signature may change \
1090 if attr::contains_name(&i.attrs[..], "main") {
1091 gate_feature_post!(&self, main, i.span,
1092 "declaration of a nonstandard #[main] \
1093 function may change over time, for now \
1094 a top-level `fn main()` is required");
1098 ast::ItemKind::Struct(..) => {
1099 if attr::contains_name(&i.attrs[..], "simd") {
1100 gate_feature_post!(&self, simd, i.span,
1101 "SIMD types are experimental and possibly buggy");
1102 self.context.parse_sess.span_diagnostic.span_warn(i.span,
1103 "the `#[simd]` attribute \
1104 is deprecated, use \
1105 `#[repr(simd)]` instead");
1107 for attr in &i.attrs {
1108 if attr.name() == "repr" {
1109 for item in attr.meta_item_list().unwrap_or(&[]) {
1110 if item.check_name("simd") {
1111 gate_feature_post!(&self, repr_simd, i.span,
1112 "SIMD types are experimental \
1113 and possibly buggy");
1121 ast::ItemKind::Union(..) => {
1122 gate_feature_post!(&self, untagged_unions,
1124 "unions are unstable and possibly buggy");
1127 ast::ItemKind::DefaultImpl(..) => {
1128 gate_feature_post!(&self, optin_builtin_traits,
1130 "default trait implementations are experimental \
1131 and possibly buggy");
1134 ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
1136 ast::ImplPolarity::Negative => {
1137 gate_feature_post!(&self, optin_builtin_traits,
1139 "negative trait bounds are not yet fully implemented; \
1140 use marker types for now");
1149 visit::walk_item(self, i);
1152 fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
1153 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
1154 Some(val) => val.as_str().starts_with("llvm."),
1158 gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1159 "linking to LLVM intrinsics is experimental");
1162 visit::walk_foreign_item(self, i)
1165 fn visit_ty(&mut self, ty: &'a ast::Ty) {
1167 ast::TyKind::BareFn(ref bare_fn_ty) => {
1168 self.check_abi(bare_fn_ty.abi, ty.span);
1170 ast::TyKind::ImplTrait(..) => {
1171 gate_feature_post!(&self, conservative_impl_trait, ty.span,
1172 "`impl Trait` is experimental");
1174 ast::TyKind::Never => {
1175 gate_feature_post!(&self, never_type, ty.span,
1176 "The `!` type is experimental");
1180 visit::walk_ty(self, ty)
1183 fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
1184 if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
1185 match output_ty.node {
1186 ast::TyKind::Never => return,
1189 self.visit_ty(output_ty)
1193 fn visit_expr(&mut self, e: &'a ast::Expr) {
1195 ast::ExprKind::Box(_) => {
1196 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1198 ast::ExprKind::Type(..) => {
1199 gate_feature_post!(&self, type_ascription, e.span,
1200 "type ascription is experimental");
1202 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1203 gate_feature_post!(&self, inclusive_range_syntax,
1205 "inclusive range syntax is experimental");
1207 ast::ExprKind::InPlace(..) => {
1208 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1210 ast::ExprKind::Struct(_, ref fields, _) => {
1211 for field in fields {
1212 if field.is_shorthand {
1213 gate_feature_post!(&self, field_init_shorthand, field.span,
1214 "struct field shorthands are unstable");
1216 if starts_with_digit(&field.ident.node.name.as_str()) {
1217 gate_feature_post!(&self, relaxed_adts,
1219 "numeric fields in struct expressions are unstable");
1223 ast::ExprKind::Break(_, Some(_)) => {
1224 gate_feature_post!(&self, loop_break_value, e.span,
1225 "`break` with a value is experimental");
1227 ast::ExprKind::Lit(ref lit) => {
1228 if let ast::LitKind::Int(_, ref ty) = lit.node {
1230 ast::LitIntType::Signed(ast::IntTy::I128) |
1231 ast::LitIntType::Unsigned(ast::UintTy::U128) => {
1232 gate_feature_post!(&self, i128_type, e.span,
1233 "128-bit integers are not stable");
1241 visit::walk_expr(self, e);
1244 fn visit_pat(&mut self, pattern: &'a ast::Pat) {
1245 match pattern.node {
1246 PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
1247 gate_feature_post!(&self, advanced_slice_patterns,
1249 "multiple-element slice matches anywhere \
1250 but at the end of a slice (e.g. \
1251 `[0, ..xs, 0]`) are experimental")
1253 PatKind::Slice(..) => {
1254 gate_feature_post!(&self, slice_patterns,
1256 "slice pattern syntax is experimental");
1258 PatKind::Box(..) => {
1259 gate_feature_post!(&self, box_patterns,
1261 "box pattern syntax is experimental");
1263 PatKind::Struct(_, ref fields, _) => {
1264 for field in fields {
1265 if starts_with_digit(&field.node.ident.name.as_str()) {
1266 gate_feature_post!(&self, relaxed_adts,
1268 "numeric fields in struct patterns are unstable");
1274 visit::walk_pat(self, pattern)
1277 fn visit_fn(&mut self,
1278 fn_kind: FnKind<'a>,
1279 fn_decl: &'a ast::FnDecl,
1282 // check for const fn declarations
1284 FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => {
1285 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1288 // stability of const fn methods are covered in
1289 // visit_trait_item and visit_impl_item below; this is
1290 // because default methods don't pass through this
1296 FnKind::ItemFn(_, _, _, _, abi, _, _) |
1297 FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
1298 self.check_abi(abi, span);
1302 visit::walk_fn(self, fn_kind, fn_decl, span);
1305 fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1307 ast::TraitItemKind::Const(..) => {
1308 gate_feature_post!(&self, associated_consts,
1310 "associated constants are experimental")
1312 ast::TraitItemKind::Method(ref sig, ref block) => {
1313 if block.is_none() {
1314 self.check_abi(sig.abi, ti.span);
1316 if sig.constness.node == ast::Constness::Const {
1317 gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1320 ast::TraitItemKind::Type(_, Some(_)) => {
1321 gate_feature_post!(&self, associated_type_defaults, ti.span,
1322 "associated type defaults are unstable");
1326 visit::walk_trait_item(self, ti);
1329 fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
1330 if ii.defaultness == ast::Defaultness::Default {
1331 gate_feature_post!(&self, specialization,
1333 "specialization is unstable");
1337 ast::ImplItemKind::Const(..) => {
1338 gate_feature_post!(&self, associated_consts,
1340 "associated constants are experimental")
1342 ast::ImplItemKind::Method(ref sig, _) => {
1343 if sig.constness.node == ast::Constness::Const {
1344 gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1349 visit::walk_impl_item(self, ii);
1352 fn visit_vis(&mut self, vis: &'a ast::Visibility) {
1353 let span = match *vis {
1354 ast::Visibility::Crate(span) => span,
1355 ast::Visibility::Restricted { ref path, .. } => path.span,
1358 gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental");
1360 visit::walk_vis(self, vis)
1363 fn visit_generics(&mut self, g: &'a ast::Generics) {
1364 for t in &g.ty_params {
1365 if !t.attrs.is_empty() {
1366 gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
1367 "attributes on type parameter bindings are experimental");
1370 visit::walk_generics(self, g)
1373 fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) {
1374 if !lifetime_def.attrs.is_empty() {
1375 gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
1376 "attributes on lifetime bindings are experimental");
1378 visit::walk_lifetime_def(self, lifetime_def)
1382 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1383 let mut features = Features::new();
1385 for attr in krate_attrs {
1386 if !attr.check_name("feature") {
1390 match attr.meta_item_list() {
1392 span_err!(span_handler, attr.span, E0555,
1393 "malformed feature attribute, expected #![feature(...)]");
1397 let name = if let Some(word) = mi.word() {
1400 span_err!(span_handler, mi.span, E0556,
1401 "malformed feature, expected just one word");
1405 if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1406 .find(|& &(n, _, _, _)| name == n) {
1407 *(setter(&mut features)) = true;
1409 else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1410 .find(|& &(n, _, _)| name == n) {
1411 span_err!(span_handler, mi.span, E0557, "feature has been removed");
1413 else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1414 .find(|& &(n, _, _)| name == n) {
1415 features.declared_stable_lang_features.push((name, mi.span));
1417 features.declared_lib_features.push((name, mi.span));
1427 pub fn check_crate(krate: &ast::Crate,
1429 features: &Features,
1430 plugin_attributes: &[(String, AttributeType)],
1431 unstable: UnstableFeatures) {
1432 maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1437 plugin_attributes: plugin_attributes,
1439 visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1442 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1443 pub enum UnstableFeatures {
1444 /// Hard errors for unstable features are active, as on
1445 /// beta/stable channels.
1447 /// Allow features to be activated, as on nightly.
1449 /// Errors are bypassed for bootstrapping. This is required any time
1450 /// during the build that feature-related lints are set to warn or above
1451 /// because the build turns on warnings-as-errors and uses lots of unstable
1452 /// features. As a result, this is always required for building Rust itself.
1456 impl UnstableFeatures {
1457 pub fn from_environment() -> UnstableFeatures {
1458 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1459 let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1460 // Whether we should enable unstable features for bootstrapping
1461 let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
1462 match (disable_unstable_features, bootstrap) {
1463 (_, true) => UnstableFeatures::Cheat,
1464 (true, _) => UnstableFeatures::Disallow,
1465 (false, _) => UnstableFeatures::Allow
1469 pub fn is_nightly_build(&self) -> bool {
1471 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1477 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1478 unstable: UnstableFeatures) {
1479 let allow_features = match unstable {
1480 UnstableFeatures::Allow => true,
1481 UnstableFeatures::Disallow => false,
1482 UnstableFeatures::Cheat => true
1484 if !allow_features {
1485 for attr in &krate.attrs {
1486 if attr.check_name("feature") {
1487 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1488 span_err!(span_handler, attr.span, E0554,
1489 "#[feature] may not be used on the {} release channel",