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, RangeEnd};
33 use errors::{DiagnosticBuilder, Handler, FatalError};
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 unstable features which have since been removed (it was once Active)
81 const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
82 $((stringify!($feature), $ver, $issue)),+
86 ($((stable_removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
87 /// Represents stable features which have since been removed (it was once Accepted)
88 const STABLE_REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
89 $((stringify!($feature), $ver, $issue)),+
93 ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => {
94 /// Those language feature has since been Accepted (it was once Active)
95 const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
96 $((stringify!($feature), $ver, $issue)),+
101 // If you change this, please modify src/doc/unstable-book as well.
103 // Don't ever remove anything from this list; set them to 'Removed'.
105 // The version numbers here correspond to the version in which the current status
106 // was set. This is most important for knowing when a particular feature became
109 // NB: The featureck.py script parses this information directly out of the source
110 // so take care when modifying it.
113 (active, asm, "1.0.0", Some(29722)),
114 (active, concat_idents, "1.0.0", Some(29599)),
115 (active, link_args, "1.0.0", Some(29596)),
116 (active, log_syntax, "1.0.0", Some(29598)),
117 (active, non_ascii_idents, "1.0.0", Some(28979)),
118 (active, plugin_registrar, "1.0.0", Some(29597)),
119 (active, thread_local, "1.0.0", Some(29594)),
120 (active, trace_macros, "1.0.0", Some(29598)),
122 // rustc internal, for now:
123 (active, intrinsics, "1.0.0", None),
124 (active, lang_items, "1.0.0", None),
126 (active, link_llvm_intrinsics, "1.0.0", Some(29602)),
127 (active, linkage, "1.0.0", Some(29603)),
128 (active, quote, "1.0.0", Some(29601)),
129 (active, simd, "1.0.0", Some(27731)),
133 (active, rustc_diagnostic_macros, "1.0.0", None),
134 (active, advanced_slice_patterns, "1.0.0", Some(23121)),
135 (active, box_syntax, "1.0.0", Some(27779)),
136 (active, placement_in_syntax, "1.0.0", Some(27779)),
137 (active, unboxed_closures, "1.0.0", Some(29625)),
139 (active, allocator, "1.0.0", Some(27389)),
140 (active, fundamental, "1.0.0", Some(29635)),
141 (active, main, "1.0.0", Some(29634)),
142 (active, needs_allocator, "1.4.0", Some(27389)),
143 (active, on_unimplemented, "1.0.0", Some(29628)),
144 (active, plugin, "1.0.0", Some(29597)),
145 (active, simd_ffi, "1.0.0", Some(27731)),
146 (active, start, "1.0.0", Some(29633)),
147 (active, structural_match, "1.8.0", Some(31434)),
148 (active, panic_runtime, "1.10.0", Some(32837)),
149 (active, needs_panic_runtime, "1.10.0", Some(32837)),
151 // OIBIT specific features
152 (active, optin_builtin_traits, "1.0.0", Some(13231)),
154 // macro reexport needs more discussion and stabilization
155 (active, macro_reexport, "1.0.0", Some(29638)),
157 // Allows use of #[staged_api]
159 (active, staged_api, "1.0.0", None),
161 // Allows using #![no_core]
162 (active, no_core, "1.3.0", Some(29639)),
164 // Allows using `box` in patterns; RFC 469
165 (active, box_patterns, "1.0.0", Some(29641)),
167 // Allows using the unsafe_destructor_blind_to_params attribute;
169 (active, dropck_parametricity, "1.3.0", Some(28498)),
171 // Allows using the may_dangle attribute; RFC 1327
172 (active, dropck_eyepatch, "1.10.0", Some(34761)),
174 // Allows the use of custom attributes; RFC 572
175 (active, custom_attribute, "1.0.0", Some(29642)),
177 // Allows the use of #[derive(Anything)] as sugar for
178 // #[derive_Anything].
179 (active, custom_derive, "1.0.0", Some(29644)),
181 // Allows the use of rustc_* attributes; RFC 572
182 (active, rustc_attrs, "1.0.0", Some(29642)),
184 // Allows the use of #[allow_internal_unstable]. This is an
185 // attribute on macro_rules! and can't use the attribute handling
186 // below (it has to be checked before expansion possibly makes
187 // macros disappear).
190 (active, allow_internal_unstable, "1.0.0", None),
192 // #23121. Array patterns have some hazards yet.
193 (active, slice_patterns, "1.0.0", Some(23121)),
195 // Allows the definition of associated constants in `trait` or `impl`
197 (active, associated_consts, "1.0.0", Some(29646)),
199 // Allows the definition of `const fn` functions.
200 (active, const_fn, "1.2.0", Some(24111)),
202 // Allows indexing into constant arrays.
203 (active, const_indexing, "1.4.0", Some(29947)),
205 // Allows using #[prelude_import] on glob `use` items.
208 (active, prelude_import, "1.2.0", None),
210 // Allows default type parameters to influence type inference.
211 (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
213 // Allows associated type defaults
214 (active, associated_type_defaults, "1.2.0", Some(29661)),
216 // allow `repr(simd)`, and importing the various simd intrinsics
217 (active, repr_simd, "1.4.0", Some(27731)),
219 // Allows cfg(target_feature = "...").
220 (active, cfg_target_feature, "1.4.0", Some(29717)),
222 // allow `extern "platform-intrinsic" { ... }`
223 (active, platform_intrinsics, "1.4.0", Some(27731)),
226 // rust runtime internal
227 (active, unwind_attributes, "1.4.0", None),
229 // allow the use of `#[naked]` on functions.
230 (active, naked_functions, "1.9.0", Some(32408)),
232 // allow `#[no_debug]`
233 (active, no_debug, "1.5.0", Some(29721)),
235 // allow `#[omit_gdb_pretty_printer_section]`
237 (active, omit_gdb_pretty_printer_section, "1.5.0", None),
239 // Allows cfg(target_vendor = "...").
240 (active, cfg_target_vendor, "1.5.0", Some(29718)),
242 // Allow attributes on expressions and non-item statements
243 (active, stmt_expr_attributes, "1.6.0", Some(15701)),
245 // allow using type ascription in expressions
246 (active, type_ascription, "1.6.0", Some(23416)),
248 // Allows cfg(target_thread_local)
249 (active, cfg_target_thread_local, "1.7.0", Some(29594)),
252 (active, abi_vectorcall, "1.7.0", None),
255 (active, inclusive_range_syntax, "1.7.0", Some(28237)),
258 (active, exclusive_range_pattern, "1.11.0", Some(37854)),
260 // impl specialization (RFC 1210)
261 (active, specialization, "1.7.0", Some(31844)),
263 // Allow Drop types in statics/const functions (RFC 1440)
264 (active, drop_types_in_const, "1.9.0", Some(33156)),
266 // Allows cfg(target_has_atomic = "...").
267 (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
269 // Allows `impl Trait` in function return types.
270 (active, conservative_impl_trait, "1.12.0", Some(34511)),
272 // Permits numeric fields in struct expressions and patterns.
273 (active, relaxed_adts, "1.12.0", Some(35626)),
276 (active, never_type, "1.13.0", Some(35121)),
278 // Allows all literals in attribute lists and values of key-value pairs.
279 (active, attr_literals, "1.13.0", Some(34981)),
281 // Allows the sysV64 ABI to be specified on all platforms
282 // instead of just the platforms on which it is the C ABI
283 (active, abi_sysv64, "1.13.0", Some(36167)),
285 // Allows untagged unions `union U { ... }`
286 (active, untagged_unions, "1.13.0", Some(32836)),
288 // Used to identify the `compiler_builtins` crate
290 (active, compiler_builtins, "1.13.0", None),
292 // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
293 (active, generic_param_attrs, "1.11.0", Some(34761)),
295 // Allows #[link(..., cfg(..))]
296 (active, link_cfg, "1.14.0", Some(37406)),
298 (active, use_extern_macros, "1.15.0", Some(35896)),
300 // Allows `break {expr}` with a value inside `loop`s.
301 (active, loop_break_value, "1.14.0", Some(37339)),
303 // Allows #[target_feature(...)]
304 (active, target_feature, "1.15.0", None),
306 // `extern "ptx-*" fn()`
307 (active, abi_ptx, "1.15.0", None),
310 (active, i128_type, "1.16.0", Some(35118)),
312 // The `unadjusted` ABI. Perma unstable.
313 (active, abi_unadjusted, "1.16.0", None),
316 (active, proc_macro, "1.16.0", Some(38356)),
318 // Allows attributes on struct literal fields.
319 (active, struct_field_attributes, "1.16.0", Some(38814)),
321 // Allows #[link(kind="static-nobundle"...]
322 (active, static_nobundle, "1.16.0", Some(37403)),
324 // `extern "msp430-interrupt" fn()`
325 (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
327 // Coerces non capturing closures to function pointers
328 (active, closure_to_fn_coercion, "1.17.0", Some(39817)),
330 // Used to identify crates that contain sanitizer runtimes
332 (active, sanitizer_runtime, "1.17.0", None),
334 // `extern "x86-interrupt" fn()`
335 (active, abi_x86_interrupt, "1.17.0", Some(40180)),
338 // Allows the `catch {...}` expression
339 (active, catch_expr, "1.17.0", Some(31436)),
341 // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
342 (active, rvalue_static_promotion, "1.15.1", Some(38865)),
344 // Used to preserve symbols (see llvm.used)
345 (active, used, "1.18.0", Some(40289)),
347 // Hack to document `-Z linker-flavor` in The Unstable Book
348 (active, linker_flavor, "1.18.0", Some(41142)),
350 // Allows module-level inline assembly by way of global_asm!()
351 (active, global_asm, "1.18.0", Some(35119)),
355 (removed, import_shadowing, "1.0.0", None),
356 (removed, managed_boxes, "1.0.0", None),
357 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
358 (removed, negate_unsigned, "1.0.0", Some(29645)),
359 (removed, reflect, "1.0.0", Some(27749)),
360 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
361 (removed, opt_out_copy, "1.0.0", None),
362 (removed, quad_precision_float, "1.0.0", None),
363 (removed, struct_inherit, "1.0.0", None),
364 (removed, test_removed_feature, "1.0.0", None),
365 (removed, visible_private_types, "1.0.0", None),
366 (removed, unsafe_no_drop_flag, "1.0.0", None),
367 // Allows using items which are missing stability attributes
369 (removed, unmarked_api, "1.0.0", None),
370 (removed, pushpop_unsafe, "1.2.0", None),
374 (stable_removed, no_stack_check, "1.0.0", None),
378 (accepted, associated_types, "1.0.0", None),
379 // allow overloading augmented assignment operations like `a += b`
380 (accepted, augmented_assignments, "1.8.0", Some(28235)),
381 // allow empty structs and enum variants with braces
382 (accepted, braced_empty_structs, "1.8.0", Some(29720)),
383 (accepted, default_type_params, "1.0.0", None),
384 (accepted, globs, "1.0.0", None),
385 (accepted, if_let, "1.0.0", None),
386 // A temporary feature gate used to enable parser extensions needed
387 // to bootstrap fix for #5723.
388 (accepted, issue_5723_bootstrap, "1.0.0", None),
389 (accepted, macro_rules, "1.0.0", None),
390 // Allows using #![no_std]
391 (accepted, no_std, "1.6.0", None),
392 (accepted, slicing_syntax, "1.0.0", None),
393 (accepted, struct_variant, "1.0.0", None),
394 // These are used to test this portion of the compiler, they don't actually
396 (accepted, test_accepted_feature, "1.0.0", None),
397 (accepted, tuple_indexing, "1.0.0", None),
398 // Allows macros to appear in the type position.
399 (accepted, type_macros, "1.13.0", Some(27245)),
400 (accepted, while_let, "1.0.0", None),
401 // Allows `#[deprecated]` attribute
402 (accepted, deprecated, "1.9.0", Some(29935)),
404 (accepted, question_mark, "1.13.0", Some(31436)),
405 // Allows `..` in tuple (struct) patterns
406 (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
407 (accepted, item_like_imports, "1.14.0", Some(35120)),
408 // Allows using `Self` and associated types in struct expressions and patterns.
409 (accepted, more_struct_aliases, "1.16.0", Some(37544)),
410 // elide `'static` lifetimes in `static`s and `const`s
411 (accepted, static_in_const, "1.17.0", Some(35897)),
412 // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
413 (accepted, field_init_shorthand, "1.17.0", Some(37340)),
414 // Allows the definition recursive static items.
415 (accepted, static_recursion, "1.17.0", Some(29719)),
416 // pub(restricted) visibilities (RFC 1422)
417 (accepted, pub_restricted, "1.18.0", Some(32409)),
418 // The #![windows_subsystem] attribute
419 (accepted, windows_subsystem, "1.18.0", Some(37499)),
421 // If you change this, please modify src/doc/unstable-book as well. You must
422 // move that documentation into the relevant place in the other docs, and
423 // remove the chapter on the flag.
425 #[derive(PartialEq, Copy, Clone, Debug)]
426 pub enum AttributeType {
427 /// Normal, builtin attribute that is consumed
428 /// by the compiler before the unused_attribute check
431 /// Builtin attribute that may not be consumed by the compiler
432 /// before the unused_attribute check. These attributes
433 /// will be ignored by the unused_attribute lint
436 /// Builtin attribute that is only allowed at the crate level
440 pub enum AttributeGate {
441 /// Is gated by a given feature gate, reason
442 /// and function to check if enabled
443 Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
445 /// Ungated attribute, can be used on all release channels
450 fn is_deprecated(&self) -> bool {
452 Gated(Stability::Deprecated(_), ..) => true,
458 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
461 // Argument is tracking issue link.
462 Deprecated(&'static str),
466 impl ::std::fmt::Debug for AttributeGate {
467 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
469 Gated(ref stab, ref name, ref expl, _) =>
470 write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
471 Ungated => write!(fmt, "Ungated")
476 macro_rules! cfg_fn {
477 ($field: ident) => {{
478 fn f(features: &Features) -> bool {
481 f as fn(&Features) -> bool
485 pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
486 BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
489 pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
490 BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name))
493 // Attributes that have a special meaning to rustc or rustdoc
494 pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
497 ("warn", Normal, Ungated),
498 ("allow", Normal, Ungated),
499 ("forbid", Normal, Ungated),
500 ("deny", Normal, Ungated),
502 ("macro_reexport", Normal, Ungated),
503 ("macro_use", Normal, Ungated),
504 ("macro_export", Normal, Ungated),
505 ("plugin_registrar", Normal, Ungated),
507 ("cfg", Normal, Ungated),
508 ("cfg_attr", Normal, Ungated),
509 ("main", Normal, Ungated),
510 ("start", Normal, Ungated),
511 ("test", Normal, Ungated),
512 ("bench", Normal, Ungated),
513 ("simd", Normal, Ungated),
514 ("repr", Normal, Ungated),
515 ("path", Normal, Ungated),
516 ("abi", Normal, Ungated),
517 ("automatically_derived", Normal, Ungated),
518 ("no_mangle", Normal, Ungated),
519 ("no_link", Normal, Ungated),
520 ("derive", Normal, Ungated),
521 ("should_panic", Normal, Ungated),
522 ("ignore", Normal, Ungated),
523 ("no_implicit_prelude", Normal, Ungated),
524 ("reexport_test_harness_main", Normal, Ungated),
525 ("link_args", Normal, Ungated),
526 ("macro_escape", Normal, Ungated),
529 ("structural_match", Whitelisted, Gated(Stability::Unstable,
531 "the semantics of constant patterns is \
533 cfg_fn!(structural_match))),
535 ("plugin", CrateLevel, Gated(Stability::Unstable,
537 "compiler plugins are experimental \
541 ("no_std", CrateLevel, Ungated),
542 ("no_core", CrateLevel, Gated(Stability::Unstable,
544 "no_core is experimental",
546 ("lang", Normal, Gated(Stability::Unstable,
548 "language items are subject to change",
549 cfg_fn!(lang_items))),
550 ("linkage", Whitelisted, Gated(Stability::Unstable,
552 "the `linkage` attribute is experimental \
553 and not portable across platforms",
555 ("thread_local", Whitelisted, Gated(Stability::Unstable,
557 "`#[thread_local]` is an experimental feature, and does \
558 not currently handle destructors. There is no \
559 corresponding `#[task_local]` mapping to the task \
561 cfg_fn!(thread_local))),
563 ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
565 "the `#[rustc_on_unimplemented]` attribute \
566 is an experimental feature",
567 cfg_fn!(on_unimplemented))),
568 ("allocator", Whitelisted, Gated(Stability::Unstable,
570 "the `#[allocator]` attribute is an experimental feature",
571 cfg_fn!(allocator))),
572 ("needs_allocator", Normal, Gated(Stability::Unstable,
574 "the `#[needs_allocator]` \
575 attribute is an experimental \
577 cfg_fn!(needs_allocator))),
578 ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
580 "the `#[panic_runtime]` attribute is \
581 an experimental feature",
582 cfg_fn!(panic_runtime))),
583 ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
584 "needs_panic_runtime",
585 "the `#[needs_panic_runtime]` \
586 attribute is an experimental \
588 cfg_fn!(needs_panic_runtime))),
589 ("rustc_variance", Normal, Gated(Stability::Unstable,
591 "the `#[rustc_variance]` attribute \
592 is just used for rustc unit tests \
593 and will never be stable",
594 cfg_fn!(rustc_attrs))),
595 ("rustc_error", Whitelisted, Gated(Stability::Unstable,
597 "the `#[rustc_error]` attribute \
598 is just used for rustc unit tests \
599 and will never be stable",
600 cfg_fn!(rustc_attrs))),
601 ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
603 "the `#[rustc_if_this_changed]` attribute \
604 is just used for rustc unit tests \
605 and will never be stable",
606 cfg_fn!(rustc_attrs))),
607 ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
609 "the `#[rustc_if_this_changed]` attribute \
610 is just used for rustc unit tests \
611 and will never be stable",
612 cfg_fn!(rustc_attrs))),
613 ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
615 "the `#[rustc_dirty]` attribute \
616 is just used for rustc unit tests \
617 and will never be stable",
618 cfg_fn!(rustc_attrs))),
619 ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
621 "the `#[rustc_clean]` attribute \
622 is just used for rustc unit tests \
623 and will never be stable",
624 cfg_fn!(rustc_attrs))),
625 ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
627 "the `#[rustc_metadata_dirty]` attribute \
628 is just used for rustc unit tests \
629 and will never be stable",
630 cfg_fn!(rustc_attrs))),
631 ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
633 "the `#[rustc_metadata_clean]` attribute \
634 is just used for rustc unit tests \
635 and will never be stable",
636 cfg_fn!(rustc_attrs))),
637 ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
640 is just used for rustc unit tests \
641 and will never be stable",
642 cfg_fn!(rustc_attrs))),
643 ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
646 is just used for rustc unit tests \
647 and will never be stable",
648 cfg_fn!(rustc_attrs))),
649 ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
651 "internal rustc attributes will never be stable",
652 cfg_fn!(rustc_attrs))),
653 ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
655 "internal rustc attributes will never be stable",
656 cfg_fn!(rustc_attrs))),
657 ("rustc_move_fragments", Normal, Gated(Stability::Unstable,
659 "the `#[rustc_move_fragments]` attribute \
660 is just used for rustc unit tests \
661 and will never be stable",
662 cfg_fn!(rustc_attrs))),
663 ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
665 "the `#[rustc_mir]` attribute \
666 is just used for rustc unit tests \
667 and will never be stable",
668 cfg_fn!(rustc_attrs))),
669 ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
671 "the `#[rustc_inherit_overflow_checks]` \
672 attribute is just used to control \
673 overflow checking behavior of several \
674 libcore functions that are inlined \
675 across crates and will never be stable",
676 cfg_fn!(rustc_attrs))),
677 ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
679 "the `#[compiler_builtins]` attribute is used to \
680 identify the `compiler_builtins` crate which \
681 contains compiler-rt intrinsics and will never be \
683 cfg_fn!(compiler_builtins))),
684 ("sanitizer_runtime", Whitelisted, Gated(Stability::Unstable,
686 "the `#[sanitizer_runtime]` attribute is used to \
687 identify crates that contain the runtime of a \
688 sanitizer and will never be stable",
689 cfg_fn!(sanitizer_runtime))),
691 ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
692 "allow_internal_unstable",
693 EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
694 cfg_fn!(allow_internal_unstable))),
696 ("fundamental", Whitelisted, Gated(Stability::Unstable,
698 "the `#[fundamental]` attribute \
699 is an experimental feature",
700 cfg_fn!(fundamental))),
702 ("proc_macro_derive", Normal, Ungated),
704 ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
706 "internal implementation detail",
707 cfg_fn!(rustc_attrs))),
709 // FIXME: #14408 whitelist docs since rustdoc looks at them
710 ("doc", Whitelisted, Ungated),
712 // FIXME: #14406 these are processed in trans, which happens after the
714 ("cold", Whitelisted, Ungated),
715 ("naked", Whitelisted, Gated(Stability::Unstable,
717 "the `#[naked]` attribute \
718 is an experimental feature",
719 cfg_fn!(naked_functions))),
720 ("target_feature", Whitelisted, Gated(
721 Stability::Unstable, "target_feature",
722 "the `#[target_feature]` attribute is an experimental feature",
723 cfg_fn!(target_feature))),
724 ("export_name", Whitelisted, Ungated),
725 ("inline", Whitelisted, Ungated),
726 ("link", Whitelisted, Ungated),
727 ("link_name", Whitelisted, Ungated),
728 ("link_section", Whitelisted, Ungated),
729 ("no_builtins", Whitelisted, Ungated),
730 ("no_mangle", Whitelisted, Ungated),
731 ("no_debug", Whitelisted, Gated(
732 Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
734 "the `#[no_debug]` attribute is an experimental feature",
736 ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
737 "omit_gdb_pretty_printer_section",
738 "the `#[omit_gdb_pretty_printer_section]` \
739 attribute is just used for the Rust test \
741 cfg_fn!(omit_gdb_pretty_printer_section))),
742 ("unsafe_destructor_blind_to_params",
744 Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761"),
745 "dropck_parametricity",
746 "unsafe_destructor_blind_to_params has been replaced by \
747 may_dangle and will be removed in the future",
748 cfg_fn!(dropck_parametricity))),
751 Gated(Stability::Unstable,
753 "may_dangle has unstable semantics and may be removed in the future",
754 cfg_fn!(dropck_eyepatch))),
755 ("unwind", Whitelisted, Gated(Stability::Unstable,
757 "#[unwind] is experimental",
758 cfg_fn!(unwind_attributes))),
759 ("used", Whitelisted, Gated(
760 Stability::Unstable, "used",
761 "the `#[used]` attribute is an experimental feature",
765 ("prelude_import", Whitelisted, Gated(Stability::Unstable,
767 "`#[prelude_import]` is for use by rustc only",
768 cfg_fn!(prelude_import))),
770 // FIXME: #14407 these are only looked at on-demand so we can't
771 // guarantee they'll have already been checked
772 ("rustc_deprecated", Whitelisted, Ungated),
773 ("must_use", Whitelisted, Ungated),
774 ("stable", Whitelisted, Ungated),
775 ("unstable", Whitelisted, Ungated),
776 ("deprecated", Normal, Ungated),
778 ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
780 "unboxed_closures are still evolving",
781 cfg_fn!(unboxed_closures))),
783 ("windows_subsystem", Whitelisted, Ungated),
785 ("proc_macro_attribute", Normal, Gated(Stability::Unstable,
787 "attribute proc macros are currently unstable",
788 cfg_fn!(proc_macro))),
790 ("proc_macro", Normal, Gated(Stability::Unstable,
792 "function-like proc macros are currently unstable",
793 cfg_fn!(proc_macro))),
795 ("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
796 "rustc_derive_registrar",
797 "used internally by rustc",
798 cfg_fn!(rustc_attrs))),
800 // Crate level attributes
801 ("crate_name", CrateLevel, Ungated),
802 ("crate_type", CrateLevel, Ungated),
803 ("crate_id", CrateLevel, Ungated),
804 ("feature", CrateLevel, Ungated),
805 ("no_start", CrateLevel, Ungated),
806 ("no_main", CrateLevel, Ungated),
807 ("no_builtins", CrateLevel, Ungated),
808 ("recursion_limit", CrateLevel, Ungated),
809 ("type_length_limit", CrateLevel, Ungated),
812 // cfg(...)'s that are feature gated
813 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
814 // (name in cfg, feature, function to check if the feature is enabled)
815 ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
816 ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
817 ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
818 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
821 #[derive(Debug, Eq, PartialEq)]
822 pub struct GatedCfg {
828 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
829 let name = cfg.name().as_str();
831 .position(|info| info.0 == name)
840 pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
841 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
842 if !has_feature(features) && !self.span.allows_unstable() {
843 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
844 emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
850 features: &'a Features,
851 parse_sess: &'a ParseSess,
852 plugin_attributes: &'a [(String, AttributeType)],
855 macro_rules! gate_feature_fn {
856 ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
857 let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
858 let has_feature: bool = has_feature(&$cx.features);
859 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
860 if !has_feature && !span.allows_unstable() {
861 emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
866 macro_rules! gate_feature {
867 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
868 gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
872 impl<'a> Context<'a> {
873 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
874 debug!("check_attribute(attr = {:?})", attr);
875 let name = unwrap_or!(attr.name(), return).as_str();
876 for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
878 if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
879 gate_feature_fn!(self, has_feature, attr.span, name, desc);
881 debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
885 for &(ref n, ref ty) in self.plugin_attributes {
886 if attr.path == &**n {
887 // Plugins can't gate attributes, so we don't check for it
888 // unlike the code above; we only use this loop to
889 // short-circuit to avoid the checks below
890 debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty);
894 if name.starts_with("rustc_") {
895 gate_feature!(self, rustc_attrs, attr.span,
896 "unless otherwise specified, attributes \
897 with the prefix `rustc_` \
898 are reserved for internal compiler diagnostics");
899 } else if name.starts_with("derive_") {
900 gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
901 } else if !attr::is_known(attr) {
902 // Only run the custom attribute lint during regular
903 // feature gate checking. Macro gating runs
904 // before the plugin attributes are registered
905 // so we skip this then
907 gate_feature!(self, custom_attribute, attr.span,
908 &format!("The attribute `{}` is currently \
909 unknown to the compiler and \
911 added to it in the future",
918 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
919 let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] };
920 cx.check_attribute(attr, true);
923 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
924 ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
927 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
928 if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
930 // FIXME (#28244): enforce that active features have issue numbers
931 // assert!(issue.is_some())
934 // search in Accepted, Removed, or Stable Removed features
935 let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES)
936 .find(|t| t.0 == feature);
938 Some(&(_, _, issue)) => issue,
939 None => panic!("Feature `{}` is not declared anywhere", feature),
949 pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
951 feature_err(sess, feature, span, issue, explain).emit();
954 pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
955 explain: &str) -> DiagnosticBuilder<'a> {
956 let diag = &sess.span_diagnostic;
958 let issue = match issue {
959 GateIssue::Language => find_lang_feature_issue(feature),
960 GateIssue::Library(lib) => lib,
963 let mut err = if let Some(n) = issue {
964 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
966 diag.struct_span_err(span, explain)
969 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
970 if sess.unstable_features.is_nightly_build() {
971 err.help(&format!("add #![feature({})] to the \
972 crate attributes to enable",
979 const EXPLAIN_BOX_SYNTAX: &'static str =
980 "box expression syntax is experimental; you can call `Box::new` instead.";
982 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
983 "attributes on non-item statements and expressions are experimental.";
985 pub const EXPLAIN_ASM: &'static str =
986 "inline assembly is not stable enough for use and is subject to change";
988 pub const EXPLAIN_GLOBAL_ASM: &'static str =
989 "`global_asm!` is not stable enough for use and is subject to change";
991 pub const EXPLAIN_LOG_SYNTAX: &'static str =
992 "`log_syntax!` is not stable enough for use and is subject to change";
994 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
995 "`concat_idents` is not stable enough for use and is subject to change";
997 pub const EXPLAIN_TRACE_MACROS: &'static str =
998 "`trace_macros` is not stable enough for use and is subject to change";
999 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
1000 "allow_internal_unstable side-steps feature gating and stability checks";
1002 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
1003 "`#[derive]` for custom traits is deprecated and will be removed in the future.";
1005 pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
1006 "`#[derive]` for custom traits is deprecated and will be removed in the future. \
1007 Prefer using procedural macro custom derive.";
1009 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
1010 "attributes of the form `#[derive_*]` are reserved for the compiler";
1012 pub const EXPLAIN_PLACEMENT_IN: &'static str =
1013 "placement-in expression syntax is experimental and subject to change.";
1015 pub const CLOSURE_TO_FN_COERCION: &'static str =
1016 "non-capturing closure to fn coercion is experimental";
1018 struct PostExpansionVisitor<'a> {
1019 context: &'a Context<'a>,
1022 macro_rules! gate_feature_post {
1023 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
1024 let (cx, span) = ($cx, $span);
1025 if !span.allows_unstable() {
1026 gate_feature!(cx.context, $feature, span, $explain)
1031 impl<'a> PostExpansionVisitor<'a> {
1032 fn check_abi(&self, abi: Abi, span: Span) {
1034 Abi::RustIntrinsic => {
1035 gate_feature_post!(&self, intrinsics, span,
1036 "intrinsics are subject to change");
1038 Abi::PlatformIntrinsic => {
1039 gate_feature_post!(&self, platform_intrinsics, span,
1040 "platform intrinsics are experimental and possibly buggy");
1042 Abi::Vectorcall => {
1043 gate_feature_post!(&self, abi_vectorcall, span,
1044 "vectorcall is experimental and subject to change");
1047 gate_feature_post!(&self, unboxed_closures, span,
1048 "rust-call ABI is subject to change");
1051 gate_feature_post!(&self, abi_sysv64, span,
1052 "sysv64 ABI is experimental and subject to change");
1055 gate_feature_post!(&self, abi_ptx, span,
1056 "PTX ABIs are experimental and subject to change");
1058 Abi::Unadjusted => {
1059 gate_feature_post!(&self, abi_unadjusted, span,
1060 "unadjusted ABI is an implementation detail and perma-unstable");
1062 Abi::Msp430Interrupt => {
1063 gate_feature_post!(&self, abi_msp430_interrupt, span,
1064 "msp430-interrupt ABI is experimental and subject to change");
1066 Abi::X86Interrupt => {
1067 gate_feature_post!(&self, abi_x86_interrupt, span,
1068 "x86-interrupt ABI is experimental and subject to change");
1083 fn contains_novel_literal(item: &ast::MetaItem) -> bool {
1084 use ast::MetaItemKind::*;
1085 use ast::NestedMetaItemKind::*;
1089 NameValue(ref lit) => !lit.node.is_str(),
1090 List(ref list) => list.iter().any(|li| {
1092 MetaItem(ref mi) => contains_novel_literal(&mi),
1099 fn starts_with_digit(s: &str) -> bool {
1100 s.as_bytes().first().cloned().map_or(false, |b| b >= b'0' && b <= b'9')
1103 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1104 fn visit_attribute(&mut self, attr: &ast::Attribute) {
1105 if !attr.span.allows_unstable() {
1106 // check for gated attributes
1107 self.context.check_attribute(attr, false);
1110 if self.context.features.proc_macro && attr::is_known(attr) {
1114 let meta = panictry!(attr.parse_meta(&self.context.parse_sess));
1115 if contains_novel_literal(&meta) {
1116 gate_feature_post!(&self, attr_literals, attr.span,
1117 "non-string literals in attributes, or string \
1118 literals in top-level positions, are experimental");
1122 fn visit_name(&mut self, sp: Span, name: ast::Name) {
1123 if !name.as_str().is_ascii() {
1124 gate_feature_post!(&self, non_ascii_idents, sp,
1125 "non-ascii idents are not fully supported.");
1129 fn visit_item(&mut self, i: &'a ast::Item) {
1131 ast::ItemKind::ExternCrate(_) => {
1132 if attr::contains_name(&i.attrs[..], "macro_reexport") {
1133 gate_feature_post!(&self, macro_reexport, i.span,
1134 "macros reexports are experimental \
1135 and possibly buggy");
1139 ast::ItemKind::ForeignMod(ref foreign_module) => {
1140 if attr::contains_name(&i.attrs[..], "link_args") {
1141 gate_feature_post!(&self, link_args, i.span,
1142 "the `link_args` attribute is not portable \
1143 across platforms, it is recommended to \
1144 use `#[link(name = \"foo\")]` instead")
1146 self.check_abi(foreign_module.abi, i.span);
1149 ast::ItemKind::Fn(..) => {
1150 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1151 gate_feature_post!(&self, plugin_registrar, i.span,
1152 "compiler plugins are experimental and possibly buggy");
1154 if attr::contains_name(&i.attrs[..], "start") {
1155 gate_feature_post!(&self, start, i.span,
1156 "a #[start] function is an experimental \
1157 feature whose signature may change \
1160 if attr::contains_name(&i.attrs[..], "main") {
1161 gate_feature_post!(&self, main, i.span,
1162 "declaration of a nonstandard #[main] \
1163 function may change over time, for now \
1164 a top-level `fn main()` is required");
1168 ast::ItemKind::Struct(..) => {
1169 if attr::contains_name(&i.attrs[..], "simd") {
1170 gate_feature_post!(&self, simd, i.span,
1171 "SIMD types are experimental and possibly buggy");
1172 self.context.parse_sess.span_diagnostic.span_warn(i.span,
1173 "the `#[simd]` attribute \
1174 is deprecated, use \
1175 `#[repr(simd)]` instead");
1177 for attr in &i.attrs {
1178 if attr.path == "repr" {
1179 for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1180 if item.check_name("simd") {
1181 gate_feature_post!(&self, repr_simd, i.span,
1182 "SIMD types are experimental \
1183 and possibly buggy");
1191 ast::ItemKind::Union(..) => {
1192 gate_feature_post!(&self, untagged_unions,
1194 "unions are unstable and possibly buggy");
1197 ast::ItemKind::DefaultImpl(..) => {
1198 gate_feature_post!(&self, optin_builtin_traits,
1200 "default trait implementations are experimental \
1201 and possibly buggy");
1204 ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
1206 ast::ImplPolarity::Negative => {
1207 gate_feature_post!(&self, optin_builtin_traits,
1209 "negative trait bounds are not yet fully implemented; \
1210 use marker types for now");
1219 visit::walk_item(self, i);
1222 fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
1223 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
1224 Some(val) => val.as_str().starts_with("llvm."),
1228 gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1229 "linking to LLVM intrinsics is experimental");
1232 visit::walk_foreign_item(self, i)
1235 fn visit_ty(&mut self, ty: &'a ast::Ty) {
1237 ast::TyKind::BareFn(ref bare_fn_ty) => {
1238 self.check_abi(bare_fn_ty.abi, ty.span);
1240 ast::TyKind::ImplTrait(..) => {
1241 gate_feature_post!(&self, conservative_impl_trait, ty.span,
1242 "`impl Trait` is experimental");
1244 ast::TyKind::Never => {
1245 gate_feature_post!(&self, never_type, ty.span,
1246 "The `!` type is experimental");
1250 visit::walk_ty(self, ty)
1253 fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
1254 if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
1255 match output_ty.node {
1256 ast::TyKind::Never => return,
1259 self.visit_ty(output_ty)
1263 fn visit_expr(&mut self, e: &'a ast::Expr) {
1265 ast::ExprKind::Box(_) => {
1266 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1268 ast::ExprKind::Type(..) => {
1269 gate_feature_post!(&self, type_ascription, e.span,
1270 "type ascription is experimental");
1272 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1273 gate_feature_post!(&self, inclusive_range_syntax,
1275 "inclusive range syntax is experimental");
1277 ast::ExprKind::InPlace(..) => {
1278 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1280 ast::ExprKind::Struct(_, ref fields, _) => {
1281 for field in fields {
1282 if starts_with_digit(&field.ident.node.name.as_str()) {
1283 gate_feature_post!(&self, relaxed_adts,
1285 "numeric fields in struct expressions are unstable");
1289 ast::ExprKind::Break(_, Some(_)) => {
1290 gate_feature_post!(&self, loop_break_value, e.span,
1291 "`break` with a value is experimental");
1293 ast::ExprKind::Lit(ref lit) => {
1294 if let ast::LitKind::Int(_, ref ty) = lit.node {
1296 ast::LitIntType::Signed(ast::IntTy::I128) |
1297 ast::LitIntType::Unsigned(ast::UintTy::U128) => {
1298 gate_feature_post!(&self, i128_type, e.span,
1299 "128-bit integers are not stable");
1305 ast::ExprKind::Catch(_) => {
1306 gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
1310 visit::walk_expr(self, e);
1313 fn visit_pat(&mut self, pattern: &'a ast::Pat) {
1314 match pattern.node {
1315 PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
1316 gate_feature_post!(&self, advanced_slice_patterns,
1318 "multiple-element slice matches anywhere \
1319 but at the end of a slice (e.g. \
1320 `[0, ..xs, 0]`) are experimental")
1322 PatKind::Slice(..) => {
1323 gate_feature_post!(&self, slice_patterns,
1325 "slice pattern syntax is experimental");
1327 PatKind::Box(..) => {
1328 gate_feature_post!(&self, box_patterns,
1330 "box pattern syntax is experimental");
1332 PatKind::Struct(_, ref fields, _) => {
1333 for field in fields {
1334 if starts_with_digit(&field.node.ident.name.as_str()) {
1335 gate_feature_post!(&self, relaxed_adts,
1337 "numeric fields in struct patterns are unstable");
1341 PatKind::Range(_, _, RangeEnd::Excluded) => {
1342 gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
1343 "exclusive range pattern syntax is experimental");
1347 visit::walk_pat(self, pattern)
1350 fn visit_fn(&mut self,
1351 fn_kind: FnKind<'a>,
1352 fn_decl: &'a ast::FnDecl,
1355 // check for const fn declarations
1357 FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => {
1358 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1361 // stability of const fn methods are covered in
1362 // visit_trait_item and visit_impl_item below; this is
1363 // because default methods don't pass through this
1369 FnKind::ItemFn(_, _, _, _, abi, _, _) |
1370 FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
1371 self.check_abi(abi, span);
1375 visit::walk_fn(self, fn_kind, fn_decl, span);
1378 fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1380 ast::TraitItemKind::Const(..) => {
1381 gate_feature_post!(&self, associated_consts,
1383 "associated constants are experimental")
1385 ast::TraitItemKind::Method(ref sig, ref block) => {
1386 if block.is_none() {
1387 self.check_abi(sig.abi, ti.span);
1389 if sig.constness.node == ast::Constness::Const {
1390 gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1393 ast::TraitItemKind::Type(_, Some(_)) => {
1394 gate_feature_post!(&self, associated_type_defaults, ti.span,
1395 "associated type defaults are unstable");
1399 visit::walk_trait_item(self, ti);
1402 fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
1403 if ii.defaultness == ast::Defaultness::Default {
1404 gate_feature_post!(&self, specialization,
1406 "specialization is unstable");
1410 ast::ImplItemKind::Const(..) => {
1411 gate_feature_post!(&self, associated_consts,
1413 "associated constants are experimental")
1415 ast::ImplItemKind::Method(ref sig, _) => {
1416 if sig.constness.node == ast::Constness::Const {
1417 gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1422 visit::walk_impl_item(self, ii);
1425 fn visit_generics(&mut self, g: &'a ast::Generics) {
1426 for t in &g.ty_params {
1427 if !t.attrs.is_empty() {
1428 gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
1429 "attributes on type parameter bindings are experimental");
1432 visit::walk_generics(self, g)
1435 fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) {
1436 if !lifetime_def.attrs.is_empty() {
1437 gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
1438 "attributes on lifetime bindings are experimental");
1440 visit::walk_lifetime_def(self, lifetime_def)
1444 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1445 let mut features = Features::new();
1447 let mut feature_checker = MutexFeatureChecker::default();
1449 for attr in krate_attrs {
1450 if !attr.check_name("feature") {
1454 match attr.meta_item_list() {
1456 span_err!(span_handler, attr.span, E0555,
1457 "malformed feature attribute, expected #![feature(...)]");
1461 let name = if let Some(word) = mi.word() {
1464 span_err!(span_handler, mi.span, E0556,
1465 "malformed feature, expected just one word");
1469 if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1470 .find(|& &(n, _, _, _)| name == n) {
1471 *(setter(&mut features)) = true;
1472 feature_checker.collect(&features, mi.span);
1474 else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1475 .find(|& &(n, _, _)| name == n)
1476 .or_else(|| STABLE_REMOVED_FEATURES.iter()
1477 .find(|& &(n, _, _)| name == n)) {
1478 span_err!(span_handler, mi.span, E0557, "feature has been removed");
1480 else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1481 .find(|& &(n, _, _)| name == n) {
1482 features.declared_stable_lang_features.push((name, mi.span));
1484 features.declared_lib_features.push((name, mi.span));
1491 feature_checker.check(span_handler);
1496 // A collector for mutually-exclusive features and their flag spans
1498 struct MutexFeatureChecker {
1499 proc_macro: Option<Span>,
1500 custom_attribute: Option<Span>,
1503 impl MutexFeatureChecker {
1504 // If this method turns out to be a hotspot due to branching,
1505 // the branching can be eliminated by modifying `setter!()` to set these spans
1506 // only for the features that need to be checked for mutual exclusion.
1507 fn collect(&mut self, features: &Features, span: Span) {
1508 if features.proc_macro {
1509 // If self.proc_macro is None, set to Some(span)
1510 self.proc_macro = self.proc_macro.or(Some(span));
1513 if features.custom_attribute {
1514 self.custom_attribute = self.custom_attribute.or(Some(span));
1518 fn check(self, handler: &Handler) {
1519 if let (Some(pm_span), Some(ca_span)) = (self.proc_macro, self.custom_attribute) {
1520 handler.struct_span_err(pm_span, "Cannot use `#![feature(proc_macro)]` and \
1521 `#![feature(custom_attribute)] at the same time")
1522 .span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
1530 pub fn check_crate(krate: &ast::Crate,
1532 features: &Features,
1533 plugin_attributes: &[(String, AttributeType)],
1534 unstable: UnstableFeatures) {
1535 maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1539 plugin_attributes: plugin_attributes,
1541 visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1544 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1545 pub enum UnstableFeatures {
1546 /// Hard errors for unstable features are active, as on
1547 /// beta/stable channels.
1549 /// Allow features to be activated, as on nightly.
1551 /// Errors are bypassed for bootstrapping. This is required any time
1552 /// during the build that feature-related lints are set to warn or above
1553 /// because the build turns on warnings-as-errors and uses lots of unstable
1554 /// features. As a result, this is always required for building Rust itself.
1558 impl UnstableFeatures {
1559 pub fn from_environment() -> UnstableFeatures {
1560 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1561 let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1562 // Whether we should enable unstable features for bootstrapping
1563 let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
1564 match (disable_unstable_features, bootstrap) {
1565 (_, true) => UnstableFeatures::Cheat,
1566 (true, _) => UnstableFeatures::Disallow,
1567 (false, _) => UnstableFeatures::Allow
1571 pub fn is_nightly_build(&self) -> bool {
1573 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1579 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1580 unstable: UnstableFeatures) {
1581 let allow_features = match unstable {
1582 UnstableFeatures::Allow => true,
1583 UnstableFeatures::Disallow => false,
1584 UnstableFeatures::Cheat => true
1586 if !allow_features {
1587 for attr in &krate.attrs {
1588 if attr.check_name("feature") {
1589 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1590 span_err!(span_handler, attr.span, E0554,
1591 "#[feature] may not be used on the {} release channel",