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 // Allows module-level inline assembly by way of global_asm!()
348 (active, global_asm, "1.18.0", Some(35119)),
350 // Allows overlapping impls of marker traits
351 (active, overlapping_marker_traits, "1.18.0", Some(29864)),
353 // Allows use of the :vis macro fragment specifier
354 (active, macro_vis_matcher, "1.18.0", Some(41022)),
358 (removed, import_shadowing, "1.0.0", None),
359 (removed, managed_boxes, "1.0.0", None),
360 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
361 (removed, negate_unsigned, "1.0.0", Some(29645)),
362 (removed, reflect, "1.0.0", Some(27749)),
363 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
364 (removed, opt_out_copy, "1.0.0", None),
365 (removed, quad_precision_float, "1.0.0", None),
366 (removed, struct_inherit, "1.0.0", None),
367 (removed, test_removed_feature, "1.0.0", None),
368 (removed, visible_private_types, "1.0.0", None),
369 (removed, unsafe_no_drop_flag, "1.0.0", None),
370 // Allows using items which are missing stability attributes
372 (removed, unmarked_api, "1.0.0", None),
373 (removed, pushpop_unsafe, "1.2.0", None),
377 (stable_removed, no_stack_check, "1.0.0", None),
381 (accepted, associated_types, "1.0.0", None),
382 // allow overloading augmented assignment operations like `a += b`
383 (accepted, augmented_assignments, "1.8.0", Some(28235)),
384 // allow empty structs and enum variants with braces
385 (accepted, braced_empty_structs, "1.8.0", Some(29720)),
386 (accepted, default_type_params, "1.0.0", None),
387 (accepted, globs, "1.0.0", None),
388 (accepted, if_let, "1.0.0", None),
389 // A temporary feature gate used to enable parser extensions needed
390 // to bootstrap fix for #5723.
391 (accepted, issue_5723_bootstrap, "1.0.0", None),
392 (accepted, macro_rules, "1.0.0", None),
393 // Allows using #![no_std]
394 (accepted, no_std, "1.6.0", None),
395 (accepted, slicing_syntax, "1.0.0", None),
396 (accepted, struct_variant, "1.0.0", None),
397 // These are used to test this portion of the compiler, they don't actually
399 (accepted, test_accepted_feature, "1.0.0", None),
400 (accepted, tuple_indexing, "1.0.0", None),
401 // Allows macros to appear in the type position.
402 (accepted, type_macros, "1.13.0", Some(27245)),
403 (accepted, while_let, "1.0.0", None),
404 // Allows `#[deprecated]` attribute
405 (accepted, deprecated, "1.9.0", Some(29935)),
407 (accepted, question_mark, "1.13.0", Some(31436)),
408 // Allows `..` in tuple (struct) patterns
409 (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
410 (accepted, item_like_imports, "1.14.0", Some(35120)),
411 // Allows using `Self` and associated types in struct expressions and patterns.
412 (accepted, more_struct_aliases, "1.16.0", Some(37544)),
413 // elide `'static` lifetimes in `static`s and `const`s
414 (accepted, static_in_const, "1.17.0", Some(35897)),
415 // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
416 (accepted, field_init_shorthand, "1.17.0", Some(37340)),
417 // Allows the definition recursive static items.
418 (accepted, static_recursion, "1.17.0", Some(29719)),
419 // pub(restricted) visibilities (RFC 1422)
420 (accepted, pub_restricted, "1.18.0", Some(32409)),
421 // The #![windows_subsystem] attribute
422 (accepted, windows_subsystem, "1.18.0", Some(37499)),
424 // If you change this, please modify src/doc/unstable-book as well. You must
425 // move that documentation into the relevant place in the other docs, and
426 // remove the chapter on the flag.
428 #[derive(PartialEq, Copy, Clone, Debug)]
429 pub enum AttributeType {
430 /// Normal, builtin attribute that is consumed
431 /// by the compiler before the unused_attribute check
434 /// Builtin attribute that may not be consumed by the compiler
435 /// before the unused_attribute check. These attributes
436 /// will be ignored by the unused_attribute lint
439 /// Builtin attribute that is only allowed at the crate level
443 pub enum AttributeGate {
444 /// Is gated by a given feature gate, reason
445 /// and function to check if enabled
446 Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
448 /// Ungated attribute, can be used on all release channels
453 fn is_deprecated(&self) -> bool {
455 Gated(Stability::Deprecated(_), ..) => true,
461 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
464 // Argument is tracking issue link.
465 Deprecated(&'static str),
469 impl ::std::fmt::Debug for AttributeGate {
470 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
472 Gated(ref stab, ref name, ref expl, _) =>
473 write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
474 Ungated => write!(fmt, "Ungated")
479 macro_rules! cfg_fn {
480 ($field: ident) => {{
481 fn f(features: &Features) -> bool {
484 f as fn(&Features) -> bool
488 pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
489 BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
492 pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
493 BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name))
496 // Attributes that have a special meaning to rustc or rustdoc
497 pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
500 ("warn", Normal, Ungated),
501 ("allow", Normal, Ungated),
502 ("forbid", Normal, Ungated),
503 ("deny", Normal, Ungated),
505 ("macro_reexport", Normal, Ungated),
506 ("macro_use", Normal, Ungated),
507 ("macro_export", Normal, Ungated),
508 ("plugin_registrar", Normal, Ungated),
510 ("cfg", Normal, Ungated),
511 ("cfg_attr", Normal, Ungated),
512 ("main", Normal, Ungated),
513 ("start", Normal, Ungated),
514 ("test", Normal, Ungated),
515 ("bench", Normal, Ungated),
516 ("simd", Normal, Ungated),
517 ("repr", Normal, Ungated),
518 ("path", Normal, Ungated),
519 ("abi", Normal, Ungated),
520 ("automatically_derived", Normal, Ungated),
521 ("no_mangle", Normal, Ungated),
522 ("no_link", Normal, Ungated),
523 ("derive", Normal, Ungated),
524 ("should_panic", Normal, Ungated),
525 ("ignore", Normal, Ungated),
526 ("no_implicit_prelude", Normal, Ungated),
527 ("reexport_test_harness_main", Normal, Ungated),
528 ("link_args", Normal, Ungated),
529 ("macro_escape", Normal, Ungated),
532 ("structural_match", Whitelisted, Gated(Stability::Unstable,
534 "the semantics of constant patterns is \
536 cfg_fn!(structural_match))),
538 ("plugin", CrateLevel, Gated(Stability::Unstable,
540 "compiler plugins are experimental \
544 ("no_std", CrateLevel, Ungated),
545 ("no_core", CrateLevel, Gated(Stability::Unstable,
547 "no_core is experimental",
549 ("lang", Normal, Gated(Stability::Unstable,
551 "language items are subject to change",
552 cfg_fn!(lang_items))),
553 ("linkage", Whitelisted, Gated(Stability::Unstable,
555 "the `linkage` attribute is experimental \
556 and not portable across platforms",
558 ("thread_local", Whitelisted, Gated(Stability::Unstable,
560 "`#[thread_local]` is an experimental feature, and does \
561 not currently handle destructors. There is no \
562 corresponding `#[task_local]` mapping to the task \
564 cfg_fn!(thread_local))),
566 ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
568 "the `#[rustc_on_unimplemented]` attribute \
569 is an experimental feature",
570 cfg_fn!(on_unimplemented))),
571 ("allocator", Whitelisted, Gated(Stability::Unstable,
573 "the `#[allocator]` attribute is an experimental feature",
574 cfg_fn!(allocator))),
575 ("needs_allocator", Normal, Gated(Stability::Unstable,
577 "the `#[needs_allocator]` \
578 attribute is an experimental \
580 cfg_fn!(needs_allocator))),
581 ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
583 "the `#[panic_runtime]` attribute is \
584 an experimental feature",
585 cfg_fn!(panic_runtime))),
586 ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
587 "needs_panic_runtime",
588 "the `#[needs_panic_runtime]` \
589 attribute is an experimental \
591 cfg_fn!(needs_panic_runtime))),
592 ("rustc_variance", Normal, Gated(Stability::Unstable,
594 "the `#[rustc_variance]` attribute \
595 is just used for rustc unit tests \
596 and will never be stable",
597 cfg_fn!(rustc_attrs))),
598 ("rustc_error", Whitelisted, Gated(Stability::Unstable,
600 "the `#[rustc_error]` attribute \
601 is just used for rustc unit tests \
602 and will never be stable",
603 cfg_fn!(rustc_attrs))),
604 ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
606 "the `#[rustc_if_this_changed]` attribute \
607 is just used for rustc unit tests \
608 and will never be stable",
609 cfg_fn!(rustc_attrs))),
610 ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
612 "the `#[rustc_if_this_changed]` attribute \
613 is just used for rustc unit tests \
614 and will never be stable",
615 cfg_fn!(rustc_attrs))),
616 ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
618 "the `#[rustc_dirty]` attribute \
619 is just used for rustc unit tests \
620 and will never be stable",
621 cfg_fn!(rustc_attrs))),
622 ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
624 "the `#[rustc_clean]` attribute \
625 is just used for rustc unit tests \
626 and will never be stable",
627 cfg_fn!(rustc_attrs))),
628 ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
630 "the `#[rustc_metadata_dirty]` attribute \
631 is just used for rustc unit tests \
632 and will never be stable",
633 cfg_fn!(rustc_attrs))),
634 ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
636 "the `#[rustc_metadata_clean]` attribute \
637 is just used for rustc unit tests \
638 and will never be stable",
639 cfg_fn!(rustc_attrs))),
640 ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
643 is just used for rustc unit tests \
644 and will never be stable",
645 cfg_fn!(rustc_attrs))),
646 ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
649 is just used for rustc unit tests \
650 and will never be stable",
651 cfg_fn!(rustc_attrs))),
652 ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
654 "internal rustc attributes will never be stable",
655 cfg_fn!(rustc_attrs))),
656 ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
658 "internal rustc attributes will never be stable",
659 cfg_fn!(rustc_attrs))),
660 ("rustc_move_fragments", Normal, Gated(Stability::Unstable,
662 "the `#[rustc_move_fragments]` attribute \
663 is just used for rustc unit tests \
664 and will never be stable",
665 cfg_fn!(rustc_attrs))),
666 ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
668 "the `#[rustc_mir]` attribute \
669 is just used for rustc unit tests \
670 and will never be stable",
671 cfg_fn!(rustc_attrs))),
672 ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
674 "the `#[rustc_inherit_overflow_checks]` \
675 attribute is just used to control \
676 overflow checking behavior of several \
677 libcore functions that are inlined \
678 across crates and will never be stable",
679 cfg_fn!(rustc_attrs))),
680 ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
682 "the `#[compiler_builtins]` attribute is used to \
683 identify the `compiler_builtins` crate which \
684 contains compiler-rt intrinsics and will never be \
686 cfg_fn!(compiler_builtins))),
687 ("sanitizer_runtime", Whitelisted, Gated(Stability::Unstable,
689 "the `#[sanitizer_runtime]` attribute is used to \
690 identify crates that contain the runtime of a \
691 sanitizer and will never be stable",
692 cfg_fn!(sanitizer_runtime))),
694 ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
695 "allow_internal_unstable",
696 EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
697 cfg_fn!(allow_internal_unstable))),
699 ("fundamental", Whitelisted, Gated(Stability::Unstable,
701 "the `#[fundamental]` attribute \
702 is an experimental feature",
703 cfg_fn!(fundamental))),
705 ("proc_macro_derive", Normal, Ungated),
707 ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
709 "internal implementation detail",
710 cfg_fn!(rustc_attrs))),
712 // FIXME: #14408 whitelist docs since rustdoc looks at them
713 ("doc", Whitelisted, Ungated),
715 // FIXME: #14406 these are processed in trans, which happens after the
717 ("cold", Whitelisted, Ungated),
718 ("naked", Whitelisted, Gated(Stability::Unstable,
720 "the `#[naked]` attribute \
721 is an experimental feature",
722 cfg_fn!(naked_functions))),
723 ("target_feature", Whitelisted, Gated(
724 Stability::Unstable, "target_feature",
725 "the `#[target_feature]` attribute is an experimental feature",
726 cfg_fn!(target_feature))),
727 ("export_name", Whitelisted, Ungated),
728 ("inline", Whitelisted, Ungated),
729 ("link", Whitelisted, Ungated),
730 ("link_name", Whitelisted, Ungated),
731 ("link_section", Whitelisted, Ungated),
732 ("no_builtins", Whitelisted, Ungated),
733 ("no_mangle", Whitelisted, Ungated),
734 ("no_debug", Whitelisted, Gated(
735 Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
737 "the `#[no_debug]` attribute is an experimental feature",
739 ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
740 "omit_gdb_pretty_printer_section",
741 "the `#[omit_gdb_pretty_printer_section]` \
742 attribute is just used for the Rust test \
744 cfg_fn!(omit_gdb_pretty_printer_section))),
745 ("unsafe_destructor_blind_to_params",
747 Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761"),
748 "dropck_parametricity",
749 "unsafe_destructor_blind_to_params has been replaced by \
750 may_dangle and will be removed in the future",
751 cfg_fn!(dropck_parametricity))),
754 Gated(Stability::Unstable,
756 "may_dangle has unstable semantics and may be removed in the future",
757 cfg_fn!(dropck_eyepatch))),
758 ("unwind", Whitelisted, Gated(Stability::Unstable,
760 "#[unwind] is experimental",
761 cfg_fn!(unwind_attributes))),
762 ("used", Whitelisted, Gated(
763 Stability::Unstable, "used",
764 "the `#[used]` attribute is an experimental feature",
768 ("prelude_import", Whitelisted, Gated(Stability::Unstable,
770 "`#[prelude_import]` is for use by rustc only",
771 cfg_fn!(prelude_import))),
773 // FIXME: #14407 these are only looked at on-demand so we can't
774 // guarantee they'll have already been checked
775 ("rustc_deprecated", Whitelisted, Ungated),
776 ("must_use", Whitelisted, Ungated),
777 ("stable", Whitelisted, Ungated),
778 ("unstable", Whitelisted, Ungated),
779 ("deprecated", Normal, Ungated),
781 ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
783 "unboxed_closures are still evolving",
784 cfg_fn!(unboxed_closures))),
786 ("windows_subsystem", Whitelisted, Ungated),
788 ("proc_macro_attribute", Normal, Gated(Stability::Unstable,
790 "attribute proc macros are currently unstable",
791 cfg_fn!(proc_macro))),
793 ("proc_macro", Normal, Gated(Stability::Unstable,
795 "function-like proc macros are currently unstable",
796 cfg_fn!(proc_macro))),
798 ("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
799 "rustc_derive_registrar",
800 "used internally by rustc",
801 cfg_fn!(rustc_attrs))),
803 // Crate level attributes
804 ("crate_name", CrateLevel, Ungated),
805 ("crate_type", CrateLevel, Ungated),
806 ("crate_id", CrateLevel, Ungated),
807 ("feature", CrateLevel, Ungated),
808 ("no_start", CrateLevel, Ungated),
809 ("no_main", CrateLevel, Ungated),
810 ("no_builtins", CrateLevel, Ungated),
811 ("recursion_limit", CrateLevel, Ungated),
812 ("type_length_limit", CrateLevel, Ungated),
815 // cfg(...)'s that are feature gated
816 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
817 // (name in cfg, feature, function to check if the feature is enabled)
818 ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
819 ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
820 ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
821 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
824 #[derive(Debug, Eq, PartialEq)]
825 pub struct GatedCfg {
831 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
832 let name = cfg.name().as_str();
834 .position(|info| info.0 == name)
843 pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
844 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
845 if !has_feature(features) && !self.span.allows_unstable() {
846 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
847 emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
853 features: &'a Features,
854 parse_sess: &'a ParseSess,
855 plugin_attributes: &'a [(String, AttributeType)],
858 macro_rules! gate_feature_fn {
859 ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
860 let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
861 let has_feature: bool = has_feature(&$cx.features);
862 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
863 if !has_feature && !span.allows_unstable() {
864 emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
869 macro_rules! gate_feature {
870 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
871 gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
875 impl<'a> Context<'a> {
876 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
877 debug!("check_attribute(attr = {:?})", attr);
878 let name = unwrap_or!(attr.name(), return).as_str();
879 for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
881 if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
882 gate_feature_fn!(self, has_feature, attr.span, name, desc);
884 debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
888 for &(ref n, ref ty) in self.plugin_attributes {
889 if attr.path == &**n {
890 // Plugins can't gate attributes, so we don't check for it
891 // unlike the code above; we only use this loop to
892 // short-circuit to avoid the checks below
893 debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty);
897 if name.starts_with("rustc_") {
898 gate_feature!(self, rustc_attrs, attr.span,
899 "unless otherwise specified, attributes \
900 with the prefix `rustc_` \
901 are reserved for internal compiler diagnostics");
902 } else if name.starts_with("derive_") {
903 gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
904 } else if !attr::is_known(attr) {
905 // Only run the custom attribute lint during regular
906 // feature gate checking. Macro gating runs
907 // before the plugin attributes are registered
908 // so we skip this then
910 gate_feature!(self, custom_attribute, attr.span,
911 &format!("The attribute `{}` is currently \
912 unknown to the compiler and \
914 added to it in the future",
921 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
922 let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] };
923 cx.check_attribute(attr, true);
926 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
927 ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
930 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
931 if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
933 // FIXME (#28244): enforce that active features have issue numbers
934 // assert!(issue.is_some())
937 // search in Accepted, Removed, or Stable Removed features
938 let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES)
939 .find(|t| t.0 == feature);
941 Some(&(_, _, issue)) => issue,
942 None => panic!("Feature `{}` is not declared anywhere", feature),
952 pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
954 feature_err(sess, feature, span, issue, explain).emit();
957 pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
958 explain: &str) -> DiagnosticBuilder<'a> {
959 let diag = &sess.span_diagnostic;
961 let issue = match issue {
962 GateIssue::Language => find_lang_feature_issue(feature),
963 GateIssue::Library(lib) => lib,
966 let mut err = if let Some(n) = issue {
967 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
969 diag.struct_span_err(span, explain)
972 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
973 if sess.unstable_features.is_nightly_build() {
974 err.help(&format!("add #![feature({})] to the \
975 crate attributes to enable",
982 const EXPLAIN_BOX_SYNTAX: &'static str =
983 "box expression syntax is experimental; you can call `Box::new` instead.";
985 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
986 "attributes on non-item statements and expressions are experimental.";
988 pub const EXPLAIN_ASM: &'static str =
989 "inline assembly is not stable enough for use and is subject to change";
991 pub const EXPLAIN_GLOBAL_ASM: &'static str =
992 "`global_asm!` is not stable enough for use and is subject to change";
994 pub const EXPLAIN_LOG_SYNTAX: &'static str =
995 "`log_syntax!` is not stable enough for use and is subject to change";
997 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
998 "`concat_idents` is not stable enough for use and is subject to change";
1000 pub const EXPLAIN_TRACE_MACROS: &'static str =
1001 "`trace_macros` is not stable enough for use and is subject to change";
1002 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
1003 "allow_internal_unstable side-steps feature gating and stability checks";
1005 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
1006 "`#[derive]` for custom traits is deprecated and will be removed in the future.";
1008 pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
1009 "`#[derive]` for custom traits is deprecated and will be removed in the future. \
1010 Prefer using procedural macro custom derive.";
1012 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
1013 "attributes of the form `#[derive_*]` are reserved for the compiler";
1015 pub const EXPLAIN_VIS_MATCHER: &'static str =
1016 ":vis fragment specifier is experimental and subject to change";
1018 pub const EXPLAIN_PLACEMENT_IN: &'static str =
1019 "placement-in expression syntax is experimental and subject to change.";
1021 pub const CLOSURE_TO_FN_COERCION: &'static str =
1022 "non-capturing closure to fn coercion is experimental";
1024 struct PostExpansionVisitor<'a> {
1025 context: &'a Context<'a>,
1028 macro_rules! gate_feature_post {
1029 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
1030 let (cx, span) = ($cx, $span);
1031 if !span.allows_unstable() {
1032 gate_feature!(cx.context, $feature, span, $explain)
1037 impl<'a> PostExpansionVisitor<'a> {
1038 fn check_abi(&self, abi: Abi, span: Span) {
1040 Abi::RustIntrinsic => {
1041 gate_feature_post!(&self, intrinsics, span,
1042 "intrinsics are subject to change");
1044 Abi::PlatformIntrinsic => {
1045 gate_feature_post!(&self, platform_intrinsics, span,
1046 "platform intrinsics are experimental and possibly buggy");
1048 Abi::Vectorcall => {
1049 gate_feature_post!(&self, abi_vectorcall, span,
1050 "vectorcall is experimental and subject to change");
1053 gate_feature_post!(&self, unboxed_closures, span,
1054 "rust-call ABI is subject to change");
1057 gate_feature_post!(&self, abi_sysv64, span,
1058 "sysv64 ABI is experimental and subject to change");
1061 gate_feature_post!(&self, abi_ptx, span,
1062 "PTX ABIs are experimental and subject to change");
1064 Abi::Unadjusted => {
1065 gate_feature_post!(&self, abi_unadjusted, span,
1066 "unadjusted ABI is an implementation detail and perma-unstable");
1068 Abi::Msp430Interrupt => {
1069 gate_feature_post!(&self, abi_msp430_interrupt, span,
1070 "msp430-interrupt ABI is experimental and subject to change");
1072 Abi::X86Interrupt => {
1073 gate_feature_post!(&self, abi_x86_interrupt, span,
1074 "x86-interrupt ABI is experimental and subject to change");
1089 fn contains_novel_literal(item: &ast::MetaItem) -> bool {
1090 use ast::MetaItemKind::*;
1091 use ast::NestedMetaItemKind::*;
1095 NameValue(ref lit) => !lit.node.is_str(),
1096 List(ref list) => list.iter().any(|li| {
1098 MetaItem(ref mi) => contains_novel_literal(&mi),
1105 fn starts_with_digit(s: &str) -> bool {
1106 s.as_bytes().first().cloned().map_or(false, |b| b >= b'0' && b <= b'9')
1109 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1110 fn visit_attribute(&mut self, attr: &ast::Attribute) {
1111 if !attr.span.allows_unstable() {
1112 // check for gated attributes
1113 self.context.check_attribute(attr, false);
1116 if self.context.features.proc_macro && attr::is_known(attr) {
1120 let meta = panictry!(attr.parse_meta(&self.context.parse_sess));
1121 if contains_novel_literal(&meta) {
1122 gate_feature_post!(&self, attr_literals, attr.span,
1123 "non-string literals in attributes, or string \
1124 literals in top-level positions, are experimental");
1128 fn visit_name(&mut self, sp: Span, name: ast::Name) {
1129 if !name.as_str().is_ascii() {
1130 gate_feature_post!(&self, non_ascii_idents, sp,
1131 "non-ascii idents are not fully supported.");
1135 fn visit_item(&mut self, i: &'a ast::Item) {
1137 ast::ItemKind::ExternCrate(_) => {
1138 if attr::contains_name(&i.attrs[..], "macro_reexport") {
1139 gate_feature_post!(&self, macro_reexport, i.span,
1140 "macros reexports are experimental \
1141 and possibly buggy");
1145 ast::ItemKind::ForeignMod(ref foreign_module) => {
1146 if attr::contains_name(&i.attrs[..], "link_args") {
1147 gate_feature_post!(&self, link_args, i.span,
1148 "the `link_args` attribute is not portable \
1149 across platforms, it is recommended to \
1150 use `#[link(name = \"foo\")]` instead")
1152 self.check_abi(foreign_module.abi, i.span);
1155 ast::ItemKind::Fn(..) => {
1156 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1157 gate_feature_post!(&self, plugin_registrar, i.span,
1158 "compiler plugins are experimental and possibly buggy");
1160 if attr::contains_name(&i.attrs[..], "start") {
1161 gate_feature_post!(&self, start, i.span,
1162 "a #[start] function is an experimental \
1163 feature whose signature may change \
1166 if attr::contains_name(&i.attrs[..], "main") {
1167 gate_feature_post!(&self, main, i.span,
1168 "declaration of a nonstandard #[main] \
1169 function may change over time, for now \
1170 a top-level `fn main()` is required");
1174 ast::ItemKind::Struct(..) => {
1175 if attr::contains_name(&i.attrs[..], "simd") {
1176 gate_feature_post!(&self, simd, i.span,
1177 "SIMD types are experimental and possibly buggy");
1178 self.context.parse_sess.span_diagnostic.span_warn(i.span,
1179 "the `#[simd]` attribute \
1180 is deprecated, use \
1181 `#[repr(simd)]` instead");
1183 for attr in &i.attrs {
1184 if attr.path == "repr" {
1185 for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1186 if item.check_name("simd") {
1187 gate_feature_post!(&self, repr_simd, i.span,
1188 "SIMD types are experimental \
1189 and possibly buggy");
1197 ast::ItemKind::Union(..) => {
1198 gate_feature_post!(&self, untagged_unions,
1200 "unions are unstable and possibly buggy");
1203 ast::ItemKind::DefaultImpl(..) => {
1204 gate_feature_post!(&self, optin_builtin_traits,
1206 "default trait implementations are experimental \
1207 and possibly buggy");
1210 ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
1212 ast::ImplPolarity::Negative => {
1213 gate_feature_post!(&self, optin_builtin_traits,
1215 "negative trait bounds are not yet fully implemented; \
1216 use marker types for now");
1225 visit::walk_item(self, i);
1228 fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
1229 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
1230 Some(val) => val.as_str().starts_with("llvm."),
1234 gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1235 "linking to LLVM intrinsics is experimental");
1238 visit::walk_foreign_item(self, i)
1241 fn visit_ty(&mut self, ty: &'a ast::Ty) {
1243 ast::TyKind::BareFn(ref bare_fn_ty) => {
1244 self.check_abi(bare_fn_ty.abi, ty.span);
1246 ast::TyKind::ImplTrait(..) => {
1247 gate_feature_post!(&self, conservative_impl_trait, ty.span,
1248 "`impl Trait` is experimental");
1250 ast::TyKind::Never => {
1251 gate_feature_post!(&self, never_type, ty.span,
1252 "The `!` type is experimental");
1256 visit::walk_ty(self, ty)
1259 fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
1260 if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
1261 match output_ty.node {
1262 ast::TyKind::Never => return,
1265 self.visit_ty(output_ty)
1269 fn visit_expr(&mut self, e: &'a ast::Expr) {
1271 ast::ExprKind::Box(_) => {
1272 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1274 ast::ExprKind::Type(..) => {
1275 gate_feature_post!(&self, type_ascription, e.span,
1276 "type ascription is experimental");
1278 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1279 gate_feature_post!(&self, inclusive_range_syntax,
1281 "inclusive range syntax is experimental");
1283 ast::ExprKind::InPlace(..) => {
1284 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1286 ast::ExprKind::Struct(_, ref fields, _) => {
1287 for field in fields {
1288 if starts_with_digit(&field.ident.node.name.as_str()) {
1289 gate_feature_post!(&self, relaxed_adts,
1291 "numeric fields in struct expressions are unstable");
1295 ast::ExprKind::Break(_, Some(_)) => {
1296 gate_feature_post!(&self, loop_break_value, e.span,
1297 "`break` with a value is experimental");
1299 ast::ExprKind::Lit(ref lit) => {
1300 if let ast::LitKind::Int(_, ref ty) = lit.node {
1302 ast::LitIntType::Signed(ast::IntTy::I128) |
1303 ast::LitIntType::Unsigned(ast::UintTy::U128) => {
1304 gate_feature_post!(&self, i128_type, e.span,
1305 "128-bit integers are not stable");
1311 ast::ExprKind::Catch(_) => {
1312 gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
1316 visit::walk_expr(self, e);
1319 fn visit_pat(&mut self, pattern: &'a ast::Pat) {
1320 match pattern.node {
1321 PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
1322 gate_feature_post!(&self, advanced_slice_patterns,
1324 "multiple-element slice matches anywhere \
1325 but at the end of a slice (e.g. \
1326 `[0, ..xs, 0]`) are experimental")
1328 PatKind::Slice(..) => {
1329 gate_feature_post!(&self, slice_patterns,
1331 "slice pattern syntax is experimental");
1333 PatKind::Box(..) => {
1334 gate_feature_post!(&self, box_patterns,
1336 "box pattern syntax is experimental");
1338 PatKind::Struct(_, ref fields, _) => {
1339 for field in fields {
1340 if starts_with_digit(&field.node.ident.name.as_str()) {
1341 gate_feature_post!(&self, relaxed_adts,
1343 "numeric fields in struct patterns are unstable");
1347 PatKind::Range(_, _, RangeEnd::Excluded) => {
1348 gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
1349 "exclusive range pattern syntax is experimental");
1353 visit::walk_pat(self, pattern)
1356 fn visit_fn(&mut self,
1357 fn_kind: FnKind<'a>,
1358 fn_decl: &'a ast::FnDecl,
1361 // check for const fn declarations
1363 FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => {
1364 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1367 // stability of const fn methods are covered in
1368 // visit_trait_item and visit_impl_item below; this is
1369 // because default methods don't pass through this
1375 FnKind::ItemFn(_, _, _, _, abi, _, _) |
1376 FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
1377 self.check_abi(abi, span);
1381 visit::walk_fn(self, fn_kind, fn_decl, span);
1384 fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1386 ast::TraitItemKind::Const(..) => {
1387 gate_feature_post!(&self, associated_consts,
1389 "associated constants are experimental")
1391 ast::TraitItemKind::Method(ref sig, ref block) => {
1392 if block.is_none() {
1393 self.check_abi(sig.abi, ti.span);
1395 if sig.constness.node == ast::Constness::Const {
1396 gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1399 ast::TraitItemKind::Type(_, Some(_)) => {
1400 gate_feature_post!(&self, associated_type_defaults, ti.span,
1401 "associated type defaults are unstable");
1405 visit::walk_trait_item(self, ti);
1408 fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
1409 if ii.defaultness == ast::Defaultness::Default {
1410 gate_feature_post!(&self, specialization,
1412 "specialization is unstable");
1416 ast::ImplItemKind::Const(..) => {
1417 gate_feature_post!(&self, associated_consts,
1419 "associated constants are experimental")
1421 ast::ImplItemKind::Method(ref sig, _) => {
1422 if sig.constness.node == ast::Constness::Const {
1423 gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1428 visit::walk_impl_item(self, ii);
1431 fn visit_generics(&mut self, g: &'a ast::Generics) {
1432 for t in &g.ty_params {
1433 if !t.attrs.is_empty() {
1434 gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
1435 "attributes on type parameter bindings are experimental");
1438 visit::walk_generics(self, g)
1441 fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) {
1442 if !lifetime_def.attrs.is_empty() {
1443 gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
1444 "attributes on lifetime bindings are experimental");
1446 visit::walk_lifetime_def(self, lifetime_def)
1450 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1451 let mut features = Features::new();
1453 let mut feature_checker = MutexFeatureChecker::default();
1455 for attr in krate_attrs {
1456 if !attr.check_name("feature") {
1460 match attr.meta_item_list() {
1462 span_err!(span_handler, attr.span, E0555,
1463 "malformed feature attribute, expected #![feature(...)]");
1467 let name = if let Some(word) = mi.word() {
1470 span_err!(span_handler, mi.span, E0556,
1471 "malformed feature, expected just one word");
1475 if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1476 .find(|& &(n, _, _, _)| name == n) {
1477 *(setter(&mut features)) = true;
1478 feature_checker.collect(&features, mi.span);
1480 else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1481 .find(|& &(n, _, _)| name == n)
1482 .or_else(|| STABLE_REMOVED_FEATURES.iter()
1483 .find(|& &(n, _, _)| name == n)) {
1484 span_err!(span_handler, mi.span, E0557, "feature has been removed");
1486 else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1487 .find(|& &(n, _, _)| name == n) {
1488 features.declared_stable_lang_features.push((name, mi.span));
1490 features.declared_lib_features.push((name, mi.span));
1497 feature_checker.check(span_handler);
1502 // A collector for mutually-exclusive features and their flag spans
1504 struct MutexFeatureChecker {
1505 proc_macro: Option<Span>,
1506 custom_attribute: Option<Span>,
1509 impl MutexFeatureChecker {
1510 // If this method turns out to be a hotspot due to branching,
1511 // the branching can be eliminated by modifying `setter!()` to set these spans
1512 // only for the features that need to be checked for mutual exclusion.
1513 fn collect(&mut self, features: &Features, span: Span) {
1514 if features.proc_macro {
1515 // If self.proc_macro is None, set to Some(span)
1516 self.proc_macro = self.proc_macro.or(Some(span));
1519 if features.custom_attribute {
1520 self.custom_attribute = self.custom_attribute.or(Some(span));
1524 fn check(self, handler: &Handler) {
1525 if let (Some(pm_span), Some(ca_span)) = (self.proc_macro, self.custom_attribute) {
1526 handler.struct_span_err(pm_span, "Cannot use `#![feature(proc_macro)]` and \
1527 `#![feature(custom_attribute)] at the same time")
1528 .span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
1536 pub fn check_crate(krate: &ast::Crate,
1538 features: &Features,
1539 plugin_attributes: &[(String, AttributeType)],
1540 unstable: UnstableFeatures) {
1541 maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1545 plugin_attributes: plugin_attributes,
1547 visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1550 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1551 pub enum UnstableFeatures {
1552 /// Hard errors for unstable features are active, as on
1553 /// beta/stable channels.
1555 /// Allow features to be activated, as on nightly.
1557 /// Errors are bypassed for bootstrapping. This is required any time
1558 /// during the build that feature-related lints are set to warn or above
1559 /// because the build turns on warnings-as-errors and uses lots of unstable
1560 /// features. As a result, this is always required for building Rust itself.
1564 impl UnstableFeatures {
1565 pub fn from_environment() -> UnstableFeatures {
1566 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1567 let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1568 // Whether we should enable unstable features for bootstrapping
1569 let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
1570 match (disable_unstable_features, bootstrap) {
1571 (_, true) => UnstableFeatures::Cheat,
1572 (true, _) => UnstableFeatures::Disallow,
1573 (false, _) => UnstableFeatures::Allow
1577 pub fn is_nightly_build(&self) -> bool {
1579 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1585 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1586 unstable: UnstableFeatures) {
1587 let allow_features = match unstable {
1588 UnstableFeatures::Allow => true,
1589 UnstableFeatures::Disallow => false,
1590 UnstableFeatures::Cheat => true
1592 if !allow_features {
1593 for attr in &krate.attrs {
1594 if attr.check_name("feature") {
1595 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1596 span_err!(span_handler, attr.span, E0554,
1597 "#[feature] may not be used on the {} release channel",