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};
31 use codemap::{CodeMap, Spanned};
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 // The #![windows_subsystem] attribute
296 (active, windows_subsystem, "1.14.0", Some(37499)),
298 // Allows #[link(..., cfg(..))]
299 (active, link_cfg, "1.14.0", Some(37406)),
301 (active, use_extern_macros, "1.15.0", Some(35896)),
303 // Allows `break {expr}` with a value inside `loop`s.
304 (active, loop_break_value, "1.14.0", Some(37339)),
306 // Allows #[target_feature(...)]
307 (active, target_feature, "1.15.0", None),
309 // `extern "ptx-*" fn()`
310 (active, abi_ptx, "1.15.0", None),
313 (active, i128_type, "1.16.0", Some(35118)),
315 // The `unadjusted` ABI. Perma unstable.
316 (active, abi_unadjusted, "1.16.0", None),
319 (active, proc_macro, "1.16.0", Some(38356)),
321 // Allows attributes on struct literal fields.
322 (active, struct_field_attributes, "1.16.0", Some(38814)),
324 // Allows #[link(kind="static-nobundle"...]
325 (active, static_nobundle, "1.16.0", Some(37403)),
327 // `extern "msp430-interrupt" fn()`
328 (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
330 // Coerces non capturing closures to function pointers
331 (active, closure_to_fn_coercion, "1.17.0", Some(39817)),
333 // Used to identify crates that contain sanitizer runtimes
335 (active, sanitizer_runtime, "1.17.0", None),
337 // `extern "x86-interrupt" fn()`
338 (active, abi_x86_interrupt, "1.17.0", Some(40180)),
340 // Allows the `catch {...}` expression
341 (active, catch_expr, "1.17.0", Some(31436)),
343 // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
344 (active, rvalue_static_promotion, "1.15.1", Some(38865)),
348 (removed, import_shadowing, "1.0.0", None),
349 (removed, managed_boxes, "1.0.0", None),
350 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
351 (removed, negate_unsigned, "1.0.0", Some(29645)),
352 (removed, reflect, "1.0.0", Some(27749)),
353 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
354 (removed, opt_out_copy, "1.0.0", None),
355 (removed, quad_precision_float, "1.0.0", None),
356 (removed, struct_inherit, "1.0.0", None),
357 (removed, test_removed_feature, "1.0.0", None),
358 (removed, visible_private_types, "1.0.0", None),
359 (removed, unsafe_no_drop_flag, "1.0.0", None),
360 // Allows using items which are missing stability attributes
362 (removed, unmarked_api, "1.0.0", None),
363 (removed, pushpop_unsafe, "1.2.0", None),
367 (stable_removed, no_stack_check, "1.0.0", None),
371 (accepted, associated_types, "1.0.0", None),
372 // allow overloading augmented assignment operations like `a += b`
373 (accepted, augmented_assignments, "1.8.0", Some(28235)),
374 // allow empty structs and enum variants with braces
375 (accepted, braced_empty_structs, "1.8.0", Some(29720)),
376 (accepted, default_type_params, "1.0.0", None),
377 (accepted, globs, "1.0.0", None),
378 (accepted, if_let, "1.0.0", None),
379 // A temporary feature gate used to enable parser extensions needed
380 // to bootstrap fix for #5723.
381 (accepted, issue_5723_bootstrap, "1.0.0", None),
382 (accepted, macro_rules, "1.0.0", None),
383 // Allows using #![no_std]
384 (accepted, no_std, "1.6.0", None),
385 (accepted, slicing_syntax, "1.0.0", None),
386 (accepted, struct_variant, "1.0.0", None),
387 // These are used to test this portion of the compiler, they don't actually
389 (accepted, test_accepted_feature, "1.0.0", None),
390 (accepted, tuple_indexing, "1.0.0", None),
391 // Allows macros to appear in the type position.
392 (accepted, type_macros, "1.13.0", Some(27245)),
393 (accepted, while_let, "1.0.0", None),
394 // Allows `#[deprecated]` attribute
395 (accepted, deprecated, "1.9.0", Some(29935)),
397 (accepted, question_mark, "1.13.0", Some(31436)),
398 // Allows `..` in tuple (struct) patterns
399 (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
400 (accepted, item_like_imports, "1.14.0", Some(35120)),
401 // Allows using `Self` and associated types in struct expressions and patterns.
402 (accepted, more_struct_aliases, "1.16.0", Some(37544)),
403 // elide `'static` lifetimes in `static`s and `const`s
404 (accepted, static_in_const, "1.17.0", Some(35897)),
405 // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
406 (accepted, field_init_shorthand, "1.17.0", Some(37340)),
407 // Allows the definition recursive static items.
408 (accepted, static_recursion, "1.17.0", Some(29719)),
409 // pub(restricted) visibilities (RFC 1422)
410 (accepted, pub_restricted, "1.17.0", Some(32409)),
413 // If you change this, please modify src/doc/unstable-book as well. You must
414 // move that documentation into the relevant place in the other docs, and
415 // remove the chapter on the flag.
417 #[derive(PartialEq, Copy, Clone, Debug)]
418 pub enum AttributeType {
419 /// Normal, builtin attribute that is consumed
420 /// by the compiler before the unused_attribute check
423 /// Builtin attribute that may not be consumed by the compiler
424 /// before the unused_attribute check. These attributes
425 /// will be ignored by the unused_attribute lint
428 /// Builtin attribute that is only allowed at the crate level
432 pub enum AttributeGate {
433 /// Is gated by a given feature gate, reason
434 /// and function to check if enabled
435 Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
437 /// Ungated attribute, can be used on all release channels
442 fn is_deprecated(&self) -> bool {
444 Gated(Stability::Deprecated(_), ..) => true,
450 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
453 // Argument is tracking issue link.
454 Deprecated(&'static str),
458 impl ::std::fmt::Debug for AttributeGate {
459 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
461 Gated(ref stab, ref name, ref expl, _) =>
462 write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
463 Ungated => write!(fmt, "Ungated")
468 macro_rules! cfg_fn {
469 ($field: ident) => {{
470 fn f(features: &Features) -> bool {
473 f as fn(&Features) -> bool
477 pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
478 BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
481 pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
482 BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name))
485 // Attributes that have a special meaning to rustc or rustdoc
486 pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
489 ("warn", Normal, Ungated),
490 ("allow", Normal, Ungated),
491 ("forbid", Normal, Ungated),
492 ("deny", Normal, Ungated),
494 ("macro_reexport", Normal, Ungated),
495 ("macro_use", Normal, Ungated),
496 ("macro_export", Normal, Ungated),
497 ("plugin_registrar", Normal, Ungated),
499 ("cfg", Normal, Ungated),
500 ("cfg_attr", Normal, Ungated),
501 ("main", Normal, Ungated),
502 ("start", Normal, Ungated),
503 ("test", Normal, Ungated),
504 ("bench", Normal, Ungated),
505 ("simd", Normal, Ungated),
506 ("repr", Normal, Ungated),
507 ("path", Normal, Ungated),
508 ("abi", Normal, Ungated),
509 ("automatically_derived", Normal, Ungated),
510 ("no_mangle", Normal, Ungated),
511 ("no_link", Normal, Ungated),
512 ("derive", Normal, Ungated),
513 ("should_panic", Normal, Ungated),
514 ("ignore", Normal, Ungated),
515 ("no_implicit_prelude", Normal, Ungated),
516 ("reexport_test_harness_main", Normal, Ungated),
517 ("link_args", Normal, Ungated),
518 ("macro_escape", Normal, Ungated),
521 ("structural_match", Whitelisted, Gated(Stability::Unstable,
523 "the semantics of constant patterns is \
525 cfg_fn!(structural_match))),
527 ("plugin", CrateLevel, Gated(Stability::Unstable,
529 "compiler plugins are experimental \
533 ("no_std", CrateLevel, Ungated),
534 ("no_core", CrateLevel, Gated(Stability::Unstable,
536 "no_core is experimental",
538 ("lang", Normal, Gated(Stability::Unstable,
540 "language items are subject to change",
541 cfg_fn!(lang_items))),
542 ("linkage", Whitelisted, Gated(Stability::Unstable,
544 "the `linkage` attribute is experimental \
545 and not portable across platforms",
547 ("thread_local", Whitelisted, Gated(Stability::Unstable,
549 "`#[thread_local]` is an experimental feature, and does \
550 not currently handle destructors. There is no \
551 corresponding `#[task_local]` mapping to the task \
553 cfg_fn!(thread_local))),
555 ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
557 "the `#[rustc_on_unimplemented]` attribute \
558 is an experimental feature",
559 cfg_fn!(on_unimplemented))),
560 ("allocator", Whitelisted, Gated(Stability::Unstable,
562 "the `#[allocator]` attribute is an experimental feature",
563 cfg_fn!(allocator))),
564 ("needs_allocator", Normal, Gated(Stability::Unstable,
566 "the `#[needs_allocator]` \
567 attribute is an experimental \
569 cfg_fn!(needs_allocator))),
570 ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
572 "the `#[panic_runtime]` attribute is \
573 an experimental feature",
574 cfg_fn!(panic_runtime))),
575 ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
576 "needs_panic_runtime",
577 "the `#[needs_panic_runtime]` \
578 attribute is an experimental \
580 cfg_fn!(needs_panic_runtime))),
581 ("rustc_variance", Normal, Gated(Stability::Unstable,
583 "the `#[rustc_variance]` attribute \
584 is just used for rustc unit tests \
585 and will never be stable",
586 cfg_fn!(rustc_attrs))),
587 ("rustc_error", Whitelisted, Gated(Stability::Unstable,
589 "the `#[rustc_error]` attribute \
590 is just used for rustc unit tests \
591 and will never be stable",
592 cfg_fn!(rustc_attrs))),
593 ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
595 "the `#[rustc_if_this_changed]` attribute \
596 is just used for rustc unit tests \
597 and will never be stable",
598 cfg_fn!(rustc_attrs))),
599 ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
601 "the `#[rustc_if_this_changed]` attribute \
602 is just used for rustc unit tests \
603 and will never be stable",
604 cfg_fn!(rustc_attrs))),
605 ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
607 "the `#[rustc_dirty]` attribute \
608 is just used for rustc unit tests \
609 and will never be stable",
610 cfg_fn!(rustc_attrs))),
611 ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
613 "the `#[rustc_clean]` attribute \
614 is just used for rustc unit tests \
615 and will never be stable",
616 cfg_fn!(rustc_attrs))),
617 ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
619 "the `#[rustc_metadata_dirty]` attribute \
620 is just used for rustc unit tests \
621 and will never be stable",
622 cfg_fn!(rustc_attrs))),
623 ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
625 "the `#[rustc_metadata_clean]` attribute \
626 is just used for rustc unit tests \
627 and will never be stable",
628 cfg_fn!(rustc_attrs))),
629 ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
632 is just used for rustc unit tests \
633 and will never be stable",
634 cfg_fn!(rustc_attrs))),
635 ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
638 is just used for rustc unit tests \
639 and will never be stable",
640 cfg_fn!(rustc_attrs))),
641 ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
643 "internal rustc attributes will never be stable",
644 cfg_fn!(rustc_attrs))),
645 ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
647 "internal rustc attributes will never be stable",
648 cfg_fn!(rustc_attrs))),
649 ("rustc_move_fragments", Normal, Gated(Stability::Unstable,
651 "the `#[rustc_move_fragments]` attribute \
652 is just used for rustc unit tests \
653 and will never be stable",
654 cfg_fn!(rustc_attrs))),
655 ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
657 "the `#[rustc_mir]` attribute \
658 is just used for rustc unit tests \
659 and will never be stable",
660 cfg_fn!(rustc_attrs))),
661 ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
663 "the `#[rustc_inherit_overflow_checks]` \
664 attribute is just used to control \
665 overflow checking behavior of several \
666 libcore functions that are inlined \
667 across crates and will never be stable",
668 cfg_fn!(rustc_attrs))),
669 ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
671 "the `#[compiler_builtins]` attribute is used to \
672 identify the `compiler_builtins` crate which \
673 contains compiler-rt intrinsics and will never be \
675 cfg_fn!(compiler_builtins))),
676 ("sanitizer_runtime", Whitelisted, Gated(Stability::Unstable,
678 "the `#[sanitizer_runtime]` attribute is used to \
679 identify crates that contain the runtime of a \
680 sanitizer and will never be stable",
681 cfg_fn!(sanitizer_runtime))),
683 ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
684 "allow_internal_unstable",
685 EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
686 cfg_fn!(allow_internal_unstable))),
688 ("fundamental", Whitelisted, Gated(Stability::Unstable,
690 "the `#[fundamental]` attribute \
691 is an experimental feature",
692 cfg_fn!(fundamental))),
694 ("proc_macro_derive", Normal, Ungated),
696 ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
698 "internal implementation detail",
699 cfg_fn!(rustc_attrs))),
701 // FIXME: #14408 whitelist docs since rustdoc looks at them
702 ("doc", Whitelisted, Ungated),
704 // FIXME: #14406 these are processed in trans, which happens after the
706 ("cold", Whitelisted, Ungated),
707 ("naked", Whitelisted, Gated(Stability::Unstable,
709 "the `#[naked]` attribute \
710 is an experimental feature",
711 cfg_fn!(naked_functions))),
712 ("target_feature", Whitelisted, Gated(
713 Stability::Unstable, "target_feature",
714 "the `#[target_feature]` attribute is an experimental feature",
715 cfg_fn!(target_feature))),
716 ("export_name", Whitelisted, Ungated),
717 ("inline", Whitelisted, Ungated),
718 ("link", Whitelisted, Ungated),
719 ("link_name", Whitelisted, Ungated),
720 ("link_section", Whitelisted, Ungated),
721 ("no_builtins", Whitelisted, Ungated),
722 ("no_mangle", Whitelisted, Ungated),
723 ("no_debug", Whitelisted, Gated(
724 Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
726 "the `#[no_debug]` attribute is an experimental feature",
728 ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
729 "omit_gdb_pretty_printer_section",
730 "the `#[omit_gdb_pretty_printer_section]` \
731 attribute is just used for the Rust test \
733 cfg_fn!(omit_gdb_pretty_printer_section))),
734 ("unsafe_destructor_blind_to_params",
736 Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761"),
737 "dropck_parametricity",
738 "unsafe_destructor_blind_to_params has been replaced by \
739 may_dangle and will be removed in the future",
740 cfg_fn!(dropck_parametricity))),
743 Gated(Stability::Unstable,
745 "may_dangle has unstable semantics and may be removed in the future",
746 cfg_fn!(dropck_eyepatch))),
747 ("unwind", Whitelisted, Gated(Stability::Unstable,
749 "#[unwind] is experimental",
750 cfg_fn!(unwind_attributes))),
753 ("prelude_import", Whitelisted, Gated(Stability::Unstable,
755 "`#[prelude_import]` is for use by rustc only",
756 cfg_fn!(prelude_import))),
758 // FIXME: #14407 these are only looked at on-demand so we can't
759 // guarantee they'll have already been checked
760 ("rustc_deprecated", Whitelisted, Ungated),
761 ("must_use", Whitelisted, Ungated),
762 ("stable", Whitelisted, Ungated),
763 ("unstable", Whitelisted, Ungated),
764 ("deprecated", Normal, Ungated),
766 ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
768 "unboxed_closures are still evolving",
769 cfg_fn!(unboxed_closures))),
771 ("windows_subsystem", Whitelisted, Gated(Stability::Unstable,
773 "the windows subsystem attribute \
774 is currently unstable",
775 cfg_fn!(windows_subsystem))),
777 ("proc_macro_attribute", Normal, Gated(Stability::Unstable,
779 "attribute proc macros are currently unstable",
780 cfg_fn!(proc_macro))),
782 ("proc_macro", Normal, Gated(Stability::Unstable,
784 "function-like proc macros are currently unstable",
785 cfg_fn!(proc_macro))),
787 ("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
788 "rustc_derive_registrar",
789 "used internally by rustc",
790 cfg_fn!(rustc_attrs))),
792 // Crate level attributes
793 ("crate_name", CrateLevel, Ungated),
794 ("crate_type", CrateLevel, Ungated),
795 ("crate_id", CrateLevel, Ungated),
796 ("feature", CrateLevel, Ungated),
797 ("no_start", CrateLevel, Ungated),
798 ("no_main", CrateLevel, Ungated),
799 ("no_builtins", CrateLevel, Ungated),
800 ("recursion_limit", CrateLevel, Ungated),
801 ("type_length_limit", CrateLevel, Ungated),
804 // cfg(...)'s that are feature gated
805 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
806 // (name in cfg, feature, function to check if the feature is enabled)
807 ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
808 ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
809 ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
810 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
813 #[derive(Debug, Eq, PartialEq)]
814 pub struct GatedCfg {
820 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
821 let name = cfg.name().as_str();
823 .position(|info| info.0 == name)
832 pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
833 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
834 if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
835 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
836 emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
842 features: &'a Features,
843 parse_sess: &'a ParseSess,
845 plugin_attributes: &'a [(String, AttributeType)],
848 macro_rules! gate_feature_fn {
849 ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
850 let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
851 let has_feature: bool = has_feature(&$cx.features);
852 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
853 if !has_feature && !cx.cm.span_allows_unstable(span) {
854 emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
859 macro_rules! gate_feature {
860 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
861 gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
865 impl<'a> Context<'a> {
866 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
867 debug!("check_attribute(attr = {:?})", attr);
868 let name = unwrap_or!(attr.name(), return).as_str();
869 for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
871 if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
872 gate_feature_fn!(self, has_feature, attr.span, name, desc);
874 debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
878 for &(ref n, ref ty) in self.plugin_attributes {
879 if attr.path == &**n {
880 // Plugins can't gate attributes, so we don't check for it
881 // unlike the code above; we only use this loop to
882 // short-circuit to avoid the checks below
883 debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty);
887 if name.starts_with("rustc_") {
888 gate_feature!(self, rustc_attrs, attr.span,
889 "unless otherwise specified, attributes \
890 with the prefix `rustc_` \
891 are reserved for internal compiler diagnostics");
892 } else if name.starts_with("derive_") {
893 gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
894 } else if !attr::is_known(attr) {
895 // Only run the custom attribute lint during regular
896 // feature gate checking. Macro gating runs
897 // before the plugin attributes are registered
898 // so we skip this then
900 gate_feature!(self, custom_attribute, attr.span,
901 &format!("The attribute `{}` is currently \
902 unknown to the compiler and \
904 added to it in the future",
911 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
912 cm: &CodeMap, features: &Features) {
914 features: features, parse_sess: parse_sess,
915 cm: cm, plugin_attributes: &[]
917 cx.check_attribute(attr, true);
920 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
921 ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
924 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
925 if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
927 // FIXME (#28244): enforce that active features have issue numbers
928 // assert!(issue.is_some())
931 // search in Accepted, Removed, or Stable Removed features
932 let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES)
933 .find(|t| t.0 == feature);
935 Some(&(_, _, issue)) => issue,
936 None => panic!("Feature `{}` is not declared anywhere", feature),
946 pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
948 feature_err(sess, feature, span, issue, explain).emit();
951 pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
952 explain: &str) -> DiagnosticBuilder<'a> {
953 let diag = &sess.span_diagnostic;
955 let issue = match issue {
956 GateIssue::Language => find_lang_feature_issue(feature),
957 GateIssue::Library(lib) => lib,
960 let mut err = if let Some(n) = issue {
961 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
963 diag.struct_span_err(span, explain)
966 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
967 if sess.unstable_features.is_nightly_build() {
968 err.help(&format!("add #![feature({})] to the \
969 crate attributes to enable",
976 const EXPLAIN_BOX_SYNTAX: &'static str =
977 "box expression syntax is experimental; you can call `Box::new` instead.";
979 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
980 "attributes on non-item statements and expressions are experimental.";
982 pub const EXPLAIN_ASM: &'static str =
983 "inline assembly is not stable enough for use and is subject to change";
985 pub const EXPLAIN_LOG_SYNTAX: &'static str =
986 "`log_syntax!` is not stable enough for use and is subject to change";
988 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
989 "`concat_idents` is not stable enough for use and is subject to change";
991 pub const EXPLAIN_TRACE_MACROS: &'static str =
992 "`trace_macros` is not stable enough for use and is subject to change";
993 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
994 "allow_internal_unstable side-steps feature gating and stability checks";
996 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
997 "`#[derive]` for custom traits is deprecated and will be removed in the future.";
999 pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
1000 "`#[derive]` for custom traits is deprecated and will be removed in the future. \
1001 Prefer using procedural macro custom derive.";
1003 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
1004 "attributes of the form `#[derive_*]` are reserved for the compiler";
1006 pub const EXPLAIN_PLACEMENT_IN: &'static str =
1007 "placement-in expression syntax is experimental and subject to change.";
1009 pub const CLOSURE_TO_FN_COERCION: &'static str =
1010 "non-capturing closure to fn coercion is experimental";
1012 struct PostExpansionVisitor<'a> {
1013 context: &'a Context<'a>,
1016 macro_rules! gate_feature_post {
1017 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
1018 let (cx, span) = ($cx, $span);
1019 if !cx.context.cm.span_allows_unstable(span) {
1020 gate_feature!(cx.context, $feature, span, $explain)
1025 impl<'a> PostExpansionVisitor<'a> {
1026 fn check_abi(&self, abi: Abi, span: Span) {
1028 Abi::RustIntrinsic => {
1029 gate_feature_post!(&self, intrinsics, span,
1030 "intrinsics are subject to change");
1032 Abi::PlatformIntrinsic => {
1033 gate_feature_post!(&self, platform_intrinsics, span,
1034 "platform intrinsics are experimental and possibly buggy");
1036 Abi::Vectorcall => {
1037 gate_feature_post!(&self, abi_vectorcall, span,
1038 "vectorcall is experimental and subject to change");
1041 gate_feature_post!(&self, unboxed_closures, span,
1042 "rust-call ABI is subject to change");
1045 gate_feature_post!(&self, abi_sysv64, span,
1046 "sysv64 ABI is experimental and subject to change");
1049 gate_feature_post!(&self, abi_ptx, span,
1050 "PTX ABIs are experimental and subject to change");
1052 Abi::Unadjusted => {
1053 gate_feature_post!(&self, abi_unadjusted, span,
1054 "unadjusted ABI is an implementation detail and perma-unstable");
1056 Abi::Msp430Interrupt => {
1057 gate_feature_post!(&self, abi_msp430_interrupt, span,
1058 "msp430-interrupt ABI is experimental and subject to change");
1060 Abi::X86Interrupt => {
1061 gate_feature_post!(&self, abi_x86_interrupt, span,
1062 "x86-interrupt ABI is experimental and subject to change");
1077 fn contains_novel_literal(item: &ast::MetaItem) -> bool {
1078 use ast::MetaItemKind::*;
1079 use ast::NestedMetaItemKind::*;
1083 NameValue(ref lit) => !lit.node.is_str(),
1084 List(ref list) => list.iter().any(|li| {
1086 MetaItem(ref mi) => contains_novel_literal(&mi),
1093 fn starts_with_digit(s: &str) -> bool {
1094 s.as_bytes().first().cloned().map_or(false, |b| b >= b'0' && b <= b'9')
1097 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1098 fn visit_attribute(&mut self, attr: &ast::Attribute) {
1099 if !self.context.cm.span_allows_unstable(attr.span) {
1100 // check for gated attributes
1101 self.context.check_attribute(attr, false);
1104 if self.context.features.proc_macro && attr::is_known(attr) {
1108 let meta = panictry!(attr.parse_meta(&self.context.parse_sess));
1109 if contains_novel_literal(&meta) {
1110 gate_feature_post!(&self, attr_literals, attr.span,
1111 "non-string literals in attributes, or string \
1112 literals in top-level positions, are experimental");
1116 fn visit_name(&mut self, sp: Span, name: ast::Name) {
1117 if !name.as_str().is_ascii() {
1118 gate_feature_post!(&self, non_ascii_idents, sp,
1119 "non-ascii idents are not fully supported.");
1123 fn visit_item(&mut self, i: &'a ast::Item) {
1125 ast::ItemKind::ExternCrate(_) => {
1126 if attr::contains_name(&i.attrs[..], "macro_reexport") {
1127 gate_feature_post!(&self, macro_reexport, i.span,
1128 "macros reexports are experimental \
1129 and possibly buggy");
1133 ast::ItemKind::ForeignMod(ref foreign_module) => {
1134 if attr::contains_name(&i.attrs[..], "link_args") {
1135 gate_feature_post!(&self, link_args, i.span,
1136 "the `link_args` attribute is not portable \
1137 across platforms, it is recommended to \
1138 use `#[link(name = \"foo\")]` instead")
1140 self.check_abi(foreign_module.abi, i.span);
1143 ast::ItemKind::Fn(..) => {
1144 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1145 gate_feature_post!(&self, plugin_registrar, i.span,
1146 "compiler plugins are experimental and possibly buggy");
1148 if attr::contains_name(&i.attrs[..], "start") {
1149 gate_feature_post!(&self, start, i.span,
1150 "a #[start] function is an experimental \
1151 feature whose signature may change \
1154 if attr::contains_name(&i.attrs[..], "main") {
1155 gate_feature_post!(&self, main, i.span,
1156 "declaration of a nonstandard #[main] \
1157 function may change over time, for now \
1158 a top-level `fn main()` is required");
1162 ast::ItemKind::Struct(..) => {
1163 if attr::contains_name(&i.attrs[..], "simd") {
1164 gate_feature_post!(&self, simd, i.span,
1165 "SIMD types are experimental and possibly buggy");
1166 self.context.parse_sess.span_diagnostic.span_warn(i.span,
1167 "the `#[simd]` attribute \
1168 is deprecated, use \
1169 `#[repr(simd)]` instead");
1171 for attr in &i.attrs {
1172 if attr.path == "repr" {
1173 for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1174 if item.check_name("simd") {
1175 gate_feature_post!(&self, repr_simd, i.span,
1176 "SIMD types are experimental \
1177 and possibly buggy");
1185 ast::ItemKind::Union(..) => {
1186 gate_feature_post!(&self, untagged_unions,
1188 "unions are unstable and possibly buggy");
1191 ast::ItemKind::DefaultImpl(..) => {
1192 gate_feature_post!(&self, optin_builtin_traits,
1194 "default trait implementations are experimental \
1195 and possibly buggy");
1198 ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
1200 ast::ImplPolarity::Negative => {
1201 gate_feature_post!(&self, optin_builtin_traits,
1203 "negative trait bounds are not yet fully implemented; \
1204 use marker types for now");
1213 visit::walk_item(self, i);
1216 fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
1217 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
1218 Some(val) => val.as_str().starts_with("llvm."),
1222 gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1223 "linking to LLVM intrinsics is experimental");
1226 visit::walk_foreign_item(self, i)
1229 fn visit_ty(&mut self, ty: &'a ast::Ty) {
1231 ast::TyKind::BareFn(ref bare_fn_ty) => {
1232 self.check_abi(bare_fn_ty.abi, ty.span);
1234 ast::TyKind::ImplTrait(..) => {
1235 gate_feature_post!(&self, conservative_impl_trait, ty.span,
1236 "`impl Trait` is experimental");
1238 ast::TyKind::Never => {
1239 gate_feature_post!(&self, never_type, ty.span,
1240 "The `!` type is experimental");
1244 visit::walk_ty(self, ty)
1247 fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
1248 if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
1249 match output_ty.node {
1250 ast::TyKind::Never => return,
1253 self.visit_ty(output_ty)
1257 fn visit_expr(&mut self, e: &'a ast::Expr) {
1259 ast::ExprKind::Box(_) => {
1260 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1262 ast::ExprKind::Type(..) => {
1263 gate_feature_post!(&self, type_ascription, e.span,
1264 "type ascription is experimental");
1266 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1267 gate_feature_post!(&self, inclusive_range_syntax,
1269 "inclusive range syntax is experimental");
1271 ast::ExprKind::InPlace(..) => {
1272 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1274 ast::ExprKind::Struct(_, ref fields, _) => {
1275 for field in fields {
1276 if starts_with_digit(&field.ident.node.name.as_str()) {
1277 gate_feature_post!(&self, relaxed_adts,
1279 "numeric fields in struct expressions are unstable");
1283 ast::ExprKind::Break(_, Some(_)) => {
1284 gate_feature_post!(&self, loop_break_value, e.span,
1285 "`break` with a value is experimental");
1287 ast::ExprKind::Lit(ref lit) => {
1288 if let ast::LitKind::Int(_, ref ty) = lit.node {
1290 ast::LitIntType::Signed(ast::IntTy::I128) |
1291 ast::LitIntType::Unsigned(ast::UintTy::U128) => {
1292 gate_feature_post!(&self, i128_type, e.span,
1293 "128-bit integers are not stable");
1299 ast::ExprKind::Catch(_) => {
1300 gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
1304 visit::walk_expr(self, e);
1307 fn visit_pat(&mut self, pattern: &'a ast::Pat) {
1308 match pattern.node {
1309 PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
1310 gate_feature_post!(&self, advanced_slice_patterns,
1312 "multiple-element slice matches anywhere \
1313 but at the end of a slice (e.g. \
1314 `[0, ..xs, 0]`) are experimental")
1316 PatKind::Slice(..) => {
1317 gate_feature_post!(&self, slice_patterns,
1319 "slice pattern syntax is experimental");
1321 PatKind::Box(..) => {
1322 gate_feature_post!(&self, box_patterns,
1324 "box pattern syntax is experimental");
1326 PatKind::Struct(_, ref fields, _) => {
1327 for field in fields {
1328 if starts_with_digit(&field.node.ident.name.as_str()) {
1329 gate_feature_post!(&self, relaxed_adts,
1331 "numeric fields in struct patterns are unstable");
1335 PatKind::Range(_, _, RangeEnd::Excluded) => {
1336 gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
1337 "exclusive range pattern syntax is experimental");
1341 visit::walk_pat(self, pattern)
1344 fn visit_fn(&mut self,
1345 fn_kind: FnKind<'a>,
1346 fn_decl: &'a ast::FnDecl,
1349 // check for const fn declarations
1351 FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => {
1352 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1355 // stability of const fn methods are covered in
1356 // visit_trait_item and visit_impl_item below; this is
1357 // because default methods don't pass through this
1363 FnKind::ItemFn(_, _, _, _, abi, _, _) |
1364 FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
1365 self.check_abi(abi, span);
1369 visit::walk_fn(self, fn_kind, fn_decl, span);
1372 fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1374 ast::TraitItemKind::Const(..) => {
1375 gate_feature_post!(&self, associated_consts,
1377 "associated constants are experimental")
1379 ast::TraitItemKind::Method(ref sig, ref block) => {
1380 if block.is_none() {
1381 self.check_abi(sig.abi, ti.span);
1383 if sig.constness.node == ast::Constness::Const {
1384 gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1387 ast::TraitItemKind::Type(_, Some(_)) => {
1388 gate_feature_post!(&self, associated_type_defaults, ti.span,
1389 "associated type defaults are unstable");
1393 visit::walk_trait_item(self, ti);
1396 fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
1397 if ii.defaultness == ast::Defaultness::Default {
1398 gate_feature_post!(&self, specialization,
1400 "specialization is unstable");
1404 ast::ImplItemKind::Const(..) => {
1405 gate_feature_post!(&self, associated_consts,
1407 "associated constants are experimental")
1409 ast::ImplItemKind::Method(ref sig, _) => {
1410 if sig.constness.node == ast::Constness::Const {
1411 gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1416 visit::walk_impl_item(self, ii);
1419 fn visit_generics(&mut self, g: &'a ast::Generics) {
1420 for t in &g.ty_params {
1421 if !t.attrs.is_empty() {
1422 gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
1423 "attributes on type parameter bindings are experimental");
1426 visit::walk_generics(self, g)
1429 fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) {
1430 if !lifetime_def.attrs.is_empty() {
1431 gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
1432 "attributes on lifetime bindings are experimental");
1434 visit::walk_lifetime_def(self, lifetime_def)
1438 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1439 let mut features = Features::new();
1441 let mut feature_checker = MutexFeatureChecker::default();
1443 for attr in krate_attrs {
1444 if !attr.check_name("feature") {
1448 match attr.meta_item_list() {
1450 span_err!(span_handler, attr.span, E0555,
1451 "malformed feature attribute, expected #![feature(...)]");
1455 let name = if let Some(word) = mi.word() {
1458 span_err!(span_handler, mi.span, E0556,
1459 "malformed feature, expected just one word");
1463 if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1464 .find(|& &(n, _, _, _)| name == n) {
1465 *(setter(&mut features)) = true;
1466 feature_checker.collect(&features, mi.span);
1468 else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1469 .find(|& &(n, _, _)| name == n)
1470 .or_else(|| STABLE_REMOVED_FEATURES.iter()
1471 .find(|& &(n, _, _)| name == n)) {
1472 span_err!(span_handler, mi.span, E0557, "feature has been removed");
1474 else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1475 .find(|& &(n, _, _)| name == n) {
1476 features.declared_stable_lang_features.push((name, mi.span));
1478 features.declared_lib_features.push((name, mi.span));
1485 feature_checker.check(span_handler);
1490 // A collector for mutually-exclusive features and their flag spans
1492 struct MutexFeatureChecker {
1493 proc_macro: Option<Span>,
1494 custom_attribute: Option<Span>,
1497 impl MutexFeatureChecker {
1498 // If this method turns out to be a hotspot due to branching,
1499 // the branching can be eliminated by modifying `setter!()` to set these spans
1500 // only for the features that need to be checked for mutual exclusion.
1501 fn collect(&mut self, features: &Features, span: Span) {
1502 if features.proc_macro {
1503 // If self.proc_macro is None, set to Some(span)
1504 self.proc_macro = self.proc_macro.or(Some(span));
1507 if features.custom_attribute {
1508 self.custom_attribute = self.custom_attribute.or(Some(span));
1512 fn check(self, handler: &Handler) {
1513 if let (Some(pm_span), Some(ca_span)) = (self.proc_macro, self.custom_attribute) {
1514 handler.struct_span_err(pm_span, "Cannot use `#![feature(proc_macro)]` and \
1515 `#![feature(custom_attribute)] at the same time")
1516 .span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
1524 pub fn check_crate(krate: &ast::Crate,
1526 features: &Features,
1527 plugin_attributes: &[(String, AttributeType)],
1528 unstable: UnstableFeatures) {
1529 maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1534 plugin_attributes: plugin_attributes,
1536 visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1539 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1540 pub enum UnstableFeatures {
1541 /// Hard errors for unstable features are active, as on
1542 /// beta/stable channels.
1544 /// Allow features to be activated, as on nightly.
1546 /// Errors are bypassed for bootstrapping. This is required any time
1547 /// during the build that feature-related lints are set to warn or above
1548 /// because the build turns on warnings-as-errors and uses lots of unstable
1549 /// features. As a result, this is always required for building Rust itself.
1553 impl UnstableFeatures {
1554 pub fn from_environment() -> UnstableFeatures {
1555 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1556 let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1557 // Whether we should enable unstable features for bootstrapping
1558 let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
1559 match (disable_unstable_features, bootstrap) {
1560 (_, true) => UnstableFeatures::Cheat,
1561 (true, _) => UnstableFeatures::Disallow,
1562 (false, _) => UnstableFeatures::Allow
1566 pub fn is_nightly_build(&self) -> bool {
1568 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1574 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1575 unstable: UnstableFeatures) {
1576 let allow_features = match unstable {
1577 UnstableFeatures::Allow => true,
1578 UnstableFeatures::Disallow => false,
1579 UnstableFeatures::Cheat => true
1581 if !allow_features {
1582 for attr in &krate.attrs {
1583 if attr.check_name("feature") {
1584 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1585 span_err!(span_handler, attr.span, E0554,
1586 "#[feature] may not be used on the {} release channel",