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, RangeSyntax};
33 use errors::{DiagnosticBuilder, Handler, FatalError};
34 use visit::{self, FnKind, Visitor};
38 use std::ascii::AsciiExt;
43 fn f(features: &mut Features, span: Span) {
44 features.declared_lib_features.push((Symbol::intern("proc_macro"), span));
45 features.proc_macro = true;
47 f as fn(&mut Features, Span)
50 fn f(features: &mut Features, _: Span) {
51 features.$field = true;
53 f as fn(&mut Features, Span)
57 macro_rules! declare_features {
58 ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => {
59 /// Represents active features that are currently being implemented or
60 /// currently being considered for addition/removal.
61 const ACTIVE_FEATURES:
62 &'static [(&'static str, &'static str, Option<u32>, fn(&mut Features, Span))] =
63 &[$((stringify!($feature), $ver, $issue, set!($feature))),+];
65 /// A set of features to be used by later passes.
67 /// #![feature] attrs for stable language features, for error reporting
68 pub declared_stable_lang_features: Vec<(Symbol, Span)>,
69 /// #![feature] attrs for non-language (library) features
70 pub declared_lib_features: Vec<(Symbol, Span)>,
71 $(pub $feature: bool),+
75 pub fn new() -> Features {
77 declared_stable_lang_features: Vec::new(),
78 declared_lib_features: Vec::new(),
85 ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
86 /// Represents unstable features which have since been removed (it was once Active)
87 const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
88 $((stringify!($feature), $ver, $issue)),+
92 ($((stable_removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
93 /// Represents stable features which have since been removed (it was once Accepted)
94 const STABLE_REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
95 $((stringify!($feature), $ver, $issue)),+
99 ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => {
100 /// Those language feature has since been Accepted (it was once Active)
101 const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
102 $((stringify!($feature), $ver, $issue)),+
107 // If you change this, please modify src/doc/unstable-book as well.
109 // Don't ever remove anything from this list; set them to 'Removed'.
111 // The version numbers here correspond to the version in which the current status
112 // was set. This is most important for knowing when a particular feature became
115 // NB: tools/tidy/src/features.rs parses this information directly out of the
116 // source, so take care when modifying it.
119 (active, asm, "1.0.0", Some(29722)),
120 (active, concat_idents, "1.0.0", Some(29599)),
121 (active, link_args, "1.0.0", Some(29596)),
122 (active, log_syntax, "1.0.0", Some(29598)),
123 (active, non_ascii_idents, "1.0.0", Some(28979)),
124 (active, plugin_registrar, "1.0.0", Some(29597)),
125 (active, thread_local, "1.0.0", Some(29594)),
126 (active, trace_macros, "1.0.0", Some(29598)),
128 // rustc internal, for now:
129 (active, intrinsics, "1.0.0", None),
130 (active, lang_items, "1.0.0", None),
132 (active, link_llvm_intrinsics, "1.0.0", Some(29602)),
133 (active, linkage, "1.0.0", Some(29603)),
134 (active, quote, "1.0.0", Some(29601)),
135 (active, simd, "1.0.0", Some(27731)),
139 (active, rustc_diagnostic_macros, "1.0.0", None),
140 (active, rustc_const_unstable, "1.0.0", None),
141 (active, advanced_slice_patterns, "1.0.0", Some(23121)),
142 (active, box_syntax, "1.0.0", Some(27779)),
143 (active, placement_in_syntax, "1.0.0", Some(27779)),
144 (active, unboxed_closures, "1.0.0", Some(29625)),
146 (active, fundamental, "1.0.0", Some(29635)),
147 (active, main, "1.0.0", Some(29634)),
148 (active, needs_allocator, "1.4.0", Some(27389)),
149 (active, on_unimplemented, "1.0.0", Some(29628)),
150 (active, plugin, "1.0.0", Some(29597)),
151 (active, simd_ffi, "1.0.0", Some(27731)),
152 (active, start, "1.0.0", Some(29633)),
153 (active, structural_match, "1.8.0", Some(31434)),
154 (active, panic_runtime, "1.10.0", Some(32837)),
155 (active, needs_panic_runtime, "1.10.0", Some(32837)),
157 // OIBIT specific features
158 (active, optin_builtin_traits, "1.0.0", Some(13231)),
160 // macro reexport needs more discussion and stabilization
161 (active, macro_reexport, "1.0.0", Some(29638)),
163 // Allows use of #[staged_api]
165 (active, staged_api, "1.0.0", None),
167 // Allows using #![no_core]
168 (active, no_core, "1.3.0", Some(29639)),
170 // Allows using `box` in patterns; RFC 469
171 (active, box_patterns, "1.0.0", Some(29641)),
173 // Allows using the unsafe_destructor_blind_to_params attribute;
175 (active, dropck_parametricity, "1.3.0", Some(28498)),
177 // Allows using the may_dangle attribute; RFC 1327
178 (active, dropck_eyepatch, "1.10.0", Some(34761)),
180 // Allows the use of custom attributes; RFC 572
181 (active, custom_attribute, "1.0.0", Some(29642)),
183 // Allows the use of #[derive(Anything)] as sugar for
184 // #[derive_Anything].
185 (active, custom_derive, "1.0.0", Some(29644)),
187 // Allows the use of rustc_* attributes; RFC 572
188 (active, rustc_attrs, "1.0.0", Some(29642)),
190 // Allows the use of #[allow_internal_unstable]. This is an
191 // attribute on macro_rules! and can't use the attribute handling
192 // below (it has to be checked before expansion possibly makes
193 // macros disappear).
196 (active, allow_internal_unstable, "1.0.0", None),
198 // Allows the use of #[allow_internal_unsafe]. This is an
199 // attribute on macro_rules! and can't use the attribute handling
200 // below (it has to be checked before expansion possibly makes
201 // macros disappear).
204 (active, allow_internal_unsafe, "1.0.0", None),
206 // #23121. Array patterns have some hazards yet.
207 (active, slice_patterns, "1.0.0", Some(23121)),
209 // Allows the definition of `const fn` functions.
210 (active, const_fn, "1.2.0", Some(24111)),
212 // Allows indexing into constant arrays.
213 (active, const_indexing, "1.4.0", Some(29947)),
215 // Allows using #[prelude_import] on glob `use` items.
218 (active, prelude_import, "1.2.0", None),
220 // Allows default type parameters to influence type inference.
221 (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
223 // Allows associated type defaults
224 (active, associated_type_defaults, "1.2.0", Some(29661)),
226 // allow `repr(simd)`, and importing the various simd intrinsics
227 (active, repr_simd, "1.4.0", Some(27731)),
229 // Allows cfg(target_feature = "...").
230 (active, cfg_target_feature, "1.4.0", Some(29717)),
232 // allow `extern "platform-intrinsic" { ... }`
233 (active, platform_intrinsics, "1.4.0", Some(27731)),
236 // rust runtime internal
237 (active, unwind_attributes, "1.4.0", None),
239 // allow the use of `#[naked]` on functions.
240 (active, naked_functions, "1.9.0", Some(32408)),
242 // allow `#[no_debug]`
243 (active, no_debug, "1.5.0", Some(29721)),
245 // allow `#[omit_gdb_pretty_printer_section]`
247 (active, omit_gdb_pretty_printer_section, "1.5.0", None),
249 // Allows cfg(target_vendor = "...").
250 (active, cfg_target_vendor, "1.5.0", Some(29718)),
252 // Allow attributes on expressions and non-item statements
253 (active, stmt_expr_attributes, "1.6.0", Some(15701)),
255 // allow using type ascription in expressions
256 (active, type_ascription, "1.6.0", Some(23416)),
258 // Allows cfg(target_thread_local)
259 (active, cfg_target_thread_local, "1.7.0", Some(29594)),
262 (active, abi_vectorcall, "1.7.0", None),
265 (active, inclusive_range_syntax, "1.7.0", Some(28237)),
268 (active, exclusive_range_pattern, "1.11.0", Some(37854)),
270 // impl specialization (RFC 1210)
271 (active, specialization, "1.7.0", Some(31844)),
273 // Allows cfg(target_has_atomic = "...").
274 (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
276 // Allows `impl Trait` in function return types.
277 (active, conservative_impl_trait, "1.12.0", Some(34511)),
280 (active, never_type, "1.13.0", Some(35121)),
282 // Allows all literals in attribute lists and values of key-value pairs.
283 (active, attr_literals, "1.13.0", Some(34981)),
285 // Allows the sysV64 ABI to be specified on all platforms
286 // instead of just the platforms on which it is the C ABI
287 (active, abi_sysv64, "1.13.0", Some(36167)),
289 // Allows untagged unions `union U { ... }`
290 (active, untagged_unions, "1.13.0", Some(32836)),
292 // Used to identify the `compiler_builtins` crate
294 (active, compiler_builtins, "1.13.0", None),
296 // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
297 (active, generic_param_attrs, "1.11.0", Some(34761)),
299 // Allows #[link(..., cfg(..))]
300 (active, link_cfg, "1.14.0", Some(37406)),
302 (active, use_extern_macros, "1.15.0", Some(35896)),
304 // Allows #[target_feature(...)]
305 (active, target_feature, "1.15.0", None),
307 // `extern "ptx-*" fn()`
308 (active, abi_ptx, "1.15.0", None),
311 (active, i128_type, "1.16.0", Some(35118)),
313 // The `repr(i128)` annotation for enums
314 (active, repr128, "1.16.0", Some(35118)),
316 // The `unadjusted` ABI. Perma unstable.
317 (active, abi_unadjusted, "1.16.0", None),
319 // Procedural macros 2.0.
320 (active, proc_macro, "1.16.0", Some(38356)),
322 // Declarative macros 2.0 (`macro`).
323 (active, decl_macro, "1.17.0", Some(39412)),
325 // Allows #[link(kind="static-nobundle"...]
326 (active, static_nobundle, "1.16.0", Some(37403)),
328 // `extern "msp430-interrupt" fn()`
329 (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
331 // Used to identify crates that contain sanitizer runtimes
333 (active, sanitizer_runtime, "1.17.0", None),
335 // Used to identify crates that contain the profiler runtime
337 (active, profiler_runtime, "1.18.0", None),
339 // `extern "x86-interrupt" fn()`
340 (active, abi_x86_interrupt, "1.17.0", Some(40180)),
343 // Allows the `catch {...}` expression
344 (active, catch_expr, "1.17.0", Some(31436)),
346 // Allows `repr(align(u16))` struct attribute (RFC 1358)
347 (active, repr_align, "1.17.0", Some(33626)),
349 // Used to preserve symbols (see llvm.used)
350 (active, used, "1.18.0", Some(40289)),
352 // Allows module-level inline assembly by way of global_asm!()
353 (active, global_asm, "1.18.0", Some(35119)),
355 // Allows overlapping impls of marker traits
356 (active, overlapping_marker_traits, "1.18.0", Some(29864)),
358 // Allows use of the :vis macro fragment specifier
359 (active, macro_vis_matcher, "1.18.0", Some(41022)),
362 (active, abi_thiscall, "1.19.0", None),
364 // Allows a test to fail without failing the whole suite
365 (active, allow_fail, "1.19.0", Some(42219)),
367 // Allows unsized tuple coercion.
368 (active, unsized_tuple_coercion, "1.20.0", Some(42877)),
371 (active, generators, "1.21.0", None),
374 // global allocators and their internals
375 (active, global_allocator, "1.20.0", None),
376 (active, allocator_internals, "1.20.0", None),
379 (active, doc_cfg, "1.21.0", Some(43781)),
381 (active, doc_masked, "1.21.0", None),
383 // allow `#[must_use]` on functions (RFC 1940)
384 (active, fn_must_use, "1.21.0", Some(43302)),
386 // allow '|' at beginning of match arms (RFC 1925)
387 (active, match_beginning_vert, "1.21.0", Some(44101)),
389 // Copy/Clone closures (RFC 2132)
390 (active, clone_closures, "1.22.0", Some(44490)),
391 (active, copy_closures, "1.22.0", Some(44490)),
393 // allow `'_` placeholder lifetimes
394 (active, underscore_lifetimes, "1.22.0", Some(44524)),
396 // allow `..=` in patterns (RFC 1192)
397 (active, dotdoteq_in_patterns, "1.22.0", Some(28237)),
401 (removed, import_shadowing, "1.0.0", None),
402 (removed, managed_boxes, "1.0.0", None),
403 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
404 (removed, negate_unsigned, "1.0.0", Some(29645)),
405 (removed, reflect, "1.0.0", Some(27749)),
406 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
407 (removed, opt_out_copy, "1.0.0", None),
408 (removed, quad_precision_float, "1.0.0", None),
409 (removed, struct_inherit, "1.0.0", None),
410 (removed, test_removed_feature, "1.0.0", None),
411 (removed, visible_private_types, "1.0.0", None),
412 (removed, unsafe_no_drop_flag, "1.0.0", None),
413 // Allows using items which are missing stability attributes
415 (removed, unmarked_api, "1.0.0", None),
416 (removed, pushpop_unsafe, "1.2.0", None),
417 (removed, allocator, "1.0.0", None),
421 (stable_removed, no_stack_check, "1.0.0", None),
425 (accepted, associated_types, "1.0.0", None),
426 // allow overloading augmented assignment operations like `a += b`
427 (accepted, augmented_assignments, "1.8.0", Some(28235)),
428 // allow empty structs and enum variants with braces
429 (accepted, braced_empty_structs, "1.8.0", Some(29720)),
430 (accepted, default_type_params, "1.0.0", None),
431 (accepted, globs, "1.0.0", None),
432 (accepted, if_let, "1.0.0", None),
433 // A temporary feature gate used to enable parser extensions needed
434 // to bootstrap fix for #5723.
435 (accepted, issue_5723_bootstrap, "1.0.0", None),
436 (accepted, macro_rules, "1.0.0", None),
437 // Allows using #![no_std]
438 (accepted, no_std, "1.6.0", None),
439 (accepted, slicing_syntax, "1.0.0", None),
440 (accepted, struct_variant, "1.0.0", None),
441 // These are used to test this portion of the compiler, they don't actually
443 (accepted, test_accepted_feature, "1.0.0", None),
444 (accepted, tuple_indexing, "1.0.0", None),
445 // Allows macros to appear in the type position.
446 (accepted, type_macros, "1.13.0", Some(27245)),
447 (accepted, while_let, "1.0.0", None),
448 // Allows `#[deprecated]` attribute
449 (accepted, deprecated, "1.9.0", Some(29935)),
451 (accepted, question_mark, "1.13.0", Some(31436)),
452 // Allows `..` in tuple (struct) patterns
453 (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
454 (accepted, item_like_imports, "1.15.0", Some(35120)),
455 // Allows using `Self` and associated types in struct expressions and patterns.
456 (accepted, more_struct_aliases, "1.16.0", Some(37544)),
457 // elide `'static` lifetimes in `static`s and `const`s
458 (accepted, static_in_const, "1.17.0", Some(35897)),
459 // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
460 (accepted, field_init_shorthand, "1.17.0", Some(37340)),
461 // Allows the definition recursive static items.
462 (accepted, static_recursion, "1.17.0", Some(29719)),
463 // pub(restricted) visibilities (RFC 1422)
464 (accepted, pub_restricted, "1.18.0", Some(32409)),
465 // The #![windows_subsystem] attribute
466 (accepted, windows_subsystem, "1.18.0", Some(37499)),
467 // Allows `break {expr}` with a value inside `loop`s.
468 (accepted, loop_break_value, "1.19.0", Some(37339)),
469 // Permits numeric fields in struct expressions and patterns.
470 (accepted, relaxed_adts, "1.19.0", Some(35626)),
471 // Coerces non capturing closures to function pointers
472 (accepted, closure_to_fn_coercion, "1.19.0", Some(39817)),
473 // Allows attributes on struct literal fields.
474 (accepted, struct_field_attributes, "1.20.0", Some(38814)),
475 // Allows the definition of associated constants in `trait` or `impl`
477 (accepted, associated_consts, "1.20.0", Some(29646)),
478 // Usage of the `compile_error!` macro
479 (accepted, compile_error, "1.20.0", Some(40872)),
480 // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
481 (accepted, rvalue_static_promotion, "1.21.0", Some(38865)),
482 // Allow Drop types in constants (RFC 1440)
483 (accepted, drop_types_in_const, "1.22.0", Some(33156)),
486 // If you change this, please modify src/doc/unstable-book as well. You must
487 // move that documentation into the relevant place in the other docs, and
488 // remove the chapter on the flag.
490 #[derive(PartialEq, Copy, Clone, Debug)]
491 pub enum AttributeType {
492 /// Normal, builtin attribute that is consumed
493 /// by the compiler before the unused_attribute check
496 /// Builtin attribute that may not be consumed by the compiler
497 /// before the unused_attribute check. These attributes
498 /// will be ignored by the unused_attribute lint
501 /// Builtin attribute that is only allowed at the crate level
505 pub enum AttributeGate {
506 /// Is gated by a given feature gate, reason
507 /// and function to check if enabled
508 Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
510 /// Ungated attribute, can be used on all release channels
515 fn is_deprecated(&self) -> bool {
517 Gated(Stability::Deprecated(_), ..) => true,
523 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
526 // Argument is tracking issue link.
527 Deprecated(&'static str),
531 impl ::std::fmt::Debug for AttributeGate {
532 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
534 Gated(ref stab, name, expl, _) =>
535 write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
536 Ungated => write!(fmt, "Ungated")
541 macro_rules! cfg_fn {
542 ($field: ident) => {{
543 fn f(features: &Features) -> bool {
546 f as fn(&Features) -> bool
550 pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
551 BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
554 pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
555 BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name))
558 // Attributes that have a special meaning to rustc or rustdoc
559 pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
562 ("warn", Normal, Ungated),
563 ("allow", Normal, Ungated),
564 ("forbid", Normal, Ungated),
565 ("deny", Normal, Ungated),
567 ("macro_reexport", Normal, Ungated),
568 ("macro_use", Normal, Ungated),
569 ("macro_export", Normal, Ungated),
570 ("plugin_registrar", Normal, Ungated),
572 ("cfg", Normal, Ungated),
573 ("cfg_attr", Normal, Ungated),
574 ("main", Normal, Ungated),
575 ("start", Normal, Ungated),
576 ("test", Normal, Ungated),
577 ("bench", Normal, Ungated),
578 ("simd", Normal, Ungated),
579 ("repr", Normal, Ungated),
580 ("path", Normal, Ungated),
581 ("abi", Normal, Ungated),
582 ("automatically_derived", Normal, Ungated),
583 ("no_mangle", Normal, Ungated),
584 ("no_link", Normal, Ungated),
585 ("derive", Normal, Ungated),
586 ("should_panic", Normal, Ungated),
587 ("ignore", Normal, Ungated),
588 ("no_implicit_prelude", Normal, Ungated),
589 ("reexport_test_harness_main", Normal, Ungated),
590 ("link_args", Normal, Gated(Stability::Unstable,
592 "the `link_args` attribute is experimental and not \
593 portable across platforms, it is recommended to \
594 use `#[link(name = \"foo\")] instead",
595 cfg_fn!(link_args))),
596 ("macro_escape", Normal, Ungated),
599 ("structural_match", Whitelisted, Gated(Stability::Unstable,
601 "the semantics of constant patterns is \
603 cfg_fn!(structural_match))),
605 ("plugin", CrateLevel, Gated(Stability::Unstable,
607 "compiler plugins are experimental \
611 ("no_std", CrateLevel, Ungated),
612 ("no_core", CrateLevel, Gated(Stability::Unstable,
614 "no_core is experimental",
616 ("lang", Normal, Gated(Stability::Unstable,
618 "language items are subject to change",
619 cfg_fn!(lang_items))),
620 ("linkage", Whitelisted, Gated(Stability::Unstable,
622 "the `linkage` attribute is experimental \
623 and not portable across platforms",
625 ("thread_local", Whitelisted, Gated(Stability::Unstable,
627 "`#[thread_local]` is an experimental feature, and does \
628 not currently handle destructors. There is no \
629 corresponding `#[task_local]` mapping to the task \
631 cfg_fn!(thread_local))),
633 ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
635 "the `#[rustc_on_unimplemented]` attribute \
636 is an experimental feature",
637 cfg_fn!(on_unimplemented))),
638 ("rustc_const_unstable", Normal, Gated(Stability::Unstable,
639 "rustc_const_unstable",
640 "the `#[rustc_const_unstable]` attribute \
641 is an internal feature",
642 cfg_fn!(rustc_const_unstable))),
643 ("global_allocator", Normal, Gated(Stability::Unstable,
645 "the `#[global_allocator]` attribute is \
646 an experimental feature",
647 cfg_fn!(global_allocator))),
648 ("default_lib_allocator", Whitelisted, Gated(Stability::Unstable,
649 "allocator_internals",
650 "the `#[default_lib_allocator]` \
651 attribute is an experimental feature",
652 cfg_fn!(allocator_internals))),
653 ("needs_allocator", Normal, Gated(Stability::Unstable,
654 "allocator_internals",
655 "the `#[needs_allocator]` \
656 attribute is an experimental \
658 cfg_fn!(allocator_internals))),
659 ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
661 "the `#[panic_runtime]` attribute is \
662 an experimental feature",
663 cfg_fn!(panic_runtime))),
664 ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
665 "needs_panic_runtime",
666 "the `#[needs_panic_runtime]` \
667 attribute is an experimental \
669 cfg_fn!(needs_panic_runtime))),
670 ("rustc_variance", Normal, Gated(Stability::Unstable,
672 "the `#[rustc_variance]` attribute \
673 is just used for rustc unit tests \
674 and will never be stable",
675 cfg_fn!(rustc_attrs))),
676 ("rustc_error", Whitelisted, Gated(Stability::Unstable,
678 "the `#[rustc_error]` attribute \
679 is just used for rustc unit tests \
680 and will never be stable",
681 cfg_fn!(rustc_attrs))),
682 ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
684 "the `#[rustc_if_this_changed]` attribute \
685 is just used for rustc unit tests \
686 and will never be stable",
687 cfg_fn!(rustc_attrs))),
688 ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
690 "the `#[rustc_if_this_changed]` attribute \
691 is just used for rustc unit tests \
692 and will never be stable",
693 cfg_fn!(rustc_attrs))),
694 ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
696 "the `#[rustc_dirty]` attribute \
697 is just used for rustc unit tests \
698 and will never be stable",
699 cfg_fn!(rustc_attrs))),
700 ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
702 "the `#[rustc_clean]` attribute \
703 is just used for rustc unit tests \
704 and will never be stable",
705 cfg_fn!(rustc_attrs))),
706 ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
708 "the `#[rustc_metadata_dirty]` attribute \
709 is just used for rustc unit tests \
710 and will never be stable",
711 cfg_fn!(rustc_attrs))),
712 ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
714 "the `#[rustc_metadata_clean]` attribute \
715 is just used for rustc unit tests \
716 and will never be stable",
717 cfg_fn!(rustc_attrs))),
718 ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
721 is just used for rustc unit tests \
722 and will never be stable",
723 cfg_fn!(rustc_attrs))),
724 ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
727 is just used for rustc unit tests \
728 and will never be stable",
729 cfg_fn!(rustc_attrs))),
730 ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
732 "internal rustc attributes will never be stable",
733 cfg_fn!(rustc_attrs))),
734 ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
736 "internal rustc attributes will never be stable",
737 cfg_fn!(rustc_attrs))),
738 ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
740 "the `#[rustc_mir]` attribute \
741 is just used for rustc unit tests \
742 and will never be stable",
743 cfg_fn!(rustc_attrs))),
744 ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
746 "the `#[rustc_inherit_overflow_checks]` \
747 attribute is just used to control \
748 overflow checking behavior of several \
749 libcore functions that are inlined \
750 across crates and will never be stable",
751 cfg_fn!(rustc_attrs))),
752 ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
754 "the `#[compiler_builtins]` attribute is used to \
755 identify the `compiler_builtins` crate which \
756 contains compiler-rt intrinsics and will never be \
758 cfg_fn!(compiler_builtins))),
759 ("sanitizer_runtime", Whitelisted, Gated(Stability::Unstable,
761 "the `#[sanitizer_runtime]` attribute is used to \
762 identify crates that contain the runtime of a \
763 sanitizer and will never be stable",
764 cfg_fn!(sanitizer_runtime))),
765 ("profiler_runtime", Whitelisted, Gated(Stability::Unstable,
767 "the `#[profiler_runtime]` attribute is used to \
768 identify the `profiler_builtins` crate which \
769 contains the profiler runtime and will never be \
771 cfg_fn!(profiler_runtime))),
773 ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
774 "allow_internal_unstable",
775 EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
776 cfg_fn!(allow_internal_unstable))),
778 ("allow_internal_unsafe", Normal, Gated(Stability::Unstable,
779 "allow_internal_unsafe",
780 EXPLAIN_ALLOW_INTERNAL_UNSAFE,
781 cfg_fn!(allow_internal_unsafe))),
783 ("fundamental", Whitelisted, Gated(Stability::Unstable,
785 "the `#[fundamental]` attribute \
786 is an experimental feature",
787 cfg_fn!(fundamental))),
789 ("proc_macro_derive", Normal, Ungated),
791 ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
793 "internal implementation detail",
794 cfg_fn!(rustc_attrs))),
796 // FIXME: #14408 whitelist docs since rustdoc looks at them
797 ("doc", Whitelisted, Ungated),
799 // FIXME: #14406 these are processed in trans, which happens after the
801 ("cold", Whitelisted, Ungated),
802 ("naked", Whitelisted, Gated(Stability::Unstable,
804 "the `#[naked]` attribute \
805 is an experimental feature",
806 cfg_fn!(naked_functions))),
807 ("target_feature", Whitelisted, Gated(
808 Stability::Unstable, "target_feature",
809 "the `#[target_feature]` attribute is an experimental feature",
810 cfg_fn!(target_feature))),
811 ("export_name", Whitelisted, Ungated),
812 ("inline", Whitelisted, Ungated),
813 ("link", Whitelisted, Ungated),
814 ("link_name", Whitelisted, Ungated),
815 ("link_section", Whitelisted, Ungated),
816 ("no_builtins", Whitelisted, Ungated),
817 ("no_mangle", Whitelisted, Ungated),
818 ("no_debug", Whitelisted, Gated(
819 Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
821 "the `#[no_debug]` attribute is an experimental feature",
823 ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
824 "omit_gdb_pretty_printer_section",
825 "the `#[omit_gdb_pretty_printer_section]` \
826 attribute is just used for the Rust test \
828 cfg_fn!(omit_gdb_pretty_printer_section))),
829 ("unsafe_destructor_blind_to_params",
831 Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761"),
832 "dropck_parametricity",
833 "unsafe_destructor_blind_to_params has been replaced by \
834 may_dangle and will be removed in the future",
835 cfg_fn!(dropck_parametricity))),
838 Gated(Stability::Unstable,
840 "may_dangle has unstable semantics and may be removed in the future",
841 cfg_fn!(dropck_eyepatch))),
842 ("unwind", Whitelisted, Gated(Stability::Unstable,
844 "#[unwind] is experimental",
845 cfg_fn!(unwind_attributes))),
846 ("used", Whitelisted, Gated(
847 Stability::Unstable, "used",
848 "the `#[used]` attribute is an experimental feature",
852 ("prelude_import", Whitelisted, Gated(Stability::Unstable,
854 "`#[prelude_import]` is for use by rustc only",
855 cfg_fn!(prelude_import))),
857 // FIXME: #14407 these are only looked at on-demand so we can't
858 // guarantee they'll have already been checked
859 ("rustc_deprecated", Whitelisted, Ungated),
860 ("must_use", Whitelisted, Ungated),
861 ("stable", Whitelisted, Ungated),
862 ("unstable", Whitelisted, Ungated),
863 ("deprecated", Normal, Ungated),
865 ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
867 "unboxed_closures are still evolving",
868 cfg_fn!(unboxed_closures))),
870 ("windows_subsystem", Whitelisted, Ungated),
872 ("proc_macro_attribute", Normal, Gated(Stability::Unstable,
874 "attribute proc macros are currently unstable",
875 cfg_fn!(proc_macro))),
877 ("proc_macro", Normal, Gated(Stability::Unstable,
879 "function-like proc macros are currently unstable",
880 cfg_fn!(proc_macro))),
882 ("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
883 "rustc_derive_registrar",
884 "used internally by rustc",
885 cfg_fn!(rustc_attrs))),
887 ("allow_fail", Normal, Gated(Stability::Unstable,
889 "allow_fail attribute is currently unstable",
890 cfg_fn!(allow_fail))),
892 // Crate level attributes
893 ("crate_name", CrateLevel, Ungated),
894 ("crate_type", CrateLevel, Ungated),
895 ("crate_id", CrateLevel, Ungated),
896 ("feature", CrateLevel, Ungated),
897 ("no_start", CrateLevel, Ungated),
898 ("no_main", CrateLevel, Ungated),
899 ("no_builtins", CrateLevel, Ungated),
900 ("recursion_limit", CrateLevel, Ungated),
901 ("type_length_limit", CrateLevel, Ungated),
904 // cfg(...)'s that are feature gated
905 const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[
906 // (name in cfg, feature, function to check if the feature is enabled)
907 ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
908 ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
909 ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
910 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
913 #[derive(Debug, Eq, PartialEq)]
914 pub struct GatedCfg {
920 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
921 let name = cfg.name().as_str();
923 .position(|info| info.0 == name)
932 pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
933 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
934 if !has_feature(features) && !self.span.allows_unstable() {
935 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
936 emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
942 features: &'a Features,
943 parse_sess: &'a ParseSess,
944 plugin_attributes: &'a [(String, AttributeType)],
947 macro_rules! gate_feature_fn {
948 ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
949 let (cx, has_feature, span,
950 name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level);
951 let has_feature: bool = has_feature(&$cx.features);
952 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
953 if !has_feature && !span.allows_unstable() {
954 leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
960 macro_rules! gate_feature {
961 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
962 gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
963 stringify!($feature), $explain, GateStrength::Hard)
965 ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {
966 gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
967 stringify!($feature), $explain, $level)
971 impl<'a> Context<'a> {
972 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
973 debug!("check_attribute(attr = {:?})", attr);
974 let name = unwrap_or!(attr.name(), return).as_str();
975 for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
977 if let Gated(_, name, desc, ref has_feature) = *gateage {
978 gate_feature_fn!(self, has_feature, attr.span, name, desc, GateStrength::Hard);
980 debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
984 for &(ref n, ref ty) in self.plugin_attributes {
985 if attr.path == &**n {
986 // Plugins can't gate attributes, so we don't check for it
987 // unlike the code above; we only use this loop to
988 // short-circuit to avoid the checks below
989 debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty);
993 if name.starts_with("rustc_") {
994 gate_feature!(self, rustc_attrs, attr.span,
995 "unless otherwise specified, attributes \
996 with the prefix `rustc_` \
997 are reserved for internal compiler diagnostics");
998 } else if name.starts_with("derive_") {
999 gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
1000 } else if !attr::is_known(attr) {
1001 // Only run the custom attribute lint during regular
1002 // feature gate checking. Macro gating runs
1003 // before the plugin attributes are registered
1004 // so we skip this then
1006 gate_feature!(self, custom_attribute, attr.span,
1007 &format!("The attribute `{}` is currently \
1008 unknown to the compiler and \
1010 added to it in the future",
1017 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
1018 let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] };
1019 cx.check_attribute(attr, true);
1022 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
1023 ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
1026 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
1027 if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
1029 // FIXME (#28244): enforce that active features have issue numbers
1030 // assert!(issue.is_some())
1033 // search in Accepted, Removed, or Stable Removed features
1034 let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES)
1035 .find(|t| t.0 == feature);
1037 Some(&(_, _, issue)) => issue,
1038 None => panic!("Feature `{}` is not declared anywhere", feature),
1043 pub enum GateIssue {
1045 Library(Option<u32>)
1048 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
1049 pub enum GateStrength {
1050 /// A hard error. (Most feature gates should use this.)
1052 /// Only a warning. (Use this only as backwards-compatibility demands.)
1056 pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
1058 feature_err(sess, feature, span, issue, explain).emit();
1061 pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
1062 explain: &str) -> DiagnosticBuilder<'a> {
1063 leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
1066 fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
1067 explain: &str, level: GateStrength) -> DiagnosticBuilder<'a> {
1068 let diag = &sess.span_diagnostic;
1070 let issue = match issue {
1071 GateIssue::Language => find_lang_feature_issue(feature),
1072 GateIssue::Library(lib) => lib,
1075 let explanation = if let Some(n) = issue {
1076 format!("{} (see issue #{})", explain, n)
1081 let mut err = match level {
1082 GateStrength::Hard => diag.struct_span_err(span, &explanation),
1083 GateStrength::Soft => diag.struct_span_warn(span, &explanation),
1086 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
1087 if sess.unstable_features.is_nightly_build() {
1088 err.help(&format!("add #![feature({})] to the \
1089 crate attributes to enable",
1093 // If we're on stable and only emitting a "soft" warning, add a note to
1094 // clarify that the feature isn't "on" (rather than being on but
1096 if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft {
1097 err.help("a nightly build of the compiler is required to enable this feature");
1104 const EXPLAIN_BOX_SYNTAX: &'static str =
1105 "box expression syntax is experimental; you can call `Box::new` instead.";
1107 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
1108 "attributes on non-item statements and expressions are experimental.";
1110 pub const EXPLAIN_ASM: &'static str =
1111 "inline assembly is not stable enough for use and is subject to change";
1113 pub const EXPLAIN_GLOBAL_ASM: &'static str =
1114 "`global_asm!` is not stable enough for use and is subject to change";
1116 pub const EXPLAIN_LOG_SYNTAX: &'static str =
1117 "`log_syntax!` is not stable enough for use and is subject to change";
1119 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
1120 "`concat_idents` is not stable enough for use and is subject to change";
1122 pub const EXPLAIN_TRACE_MACROS: &'static str =
1123 "`trace_macros` is not stable enough for use and is subject to change";
1124 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
1125 "allow_internal_unstable side-steps feature gating and stability checks";
1126 pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &'static str =
1127 "allow_internal_unsafe side-steps the unsafe_code lint";
1129 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
1130 "`#[derive]` for custom traits is deprecated and will be removed in the future.";
1132 pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
1133 "`#[derive]` for custom traits is deprecated and will be removed in the future. \
1134 Prefer using procedural macro custom derive.";
1136 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
1137 "attributes of the form `#[derive_*]` are reserved for the compiler";
1139 pub const EXPLAIN_VIS_MATCHER: &'static str =
1140 ":vis fragment specifier is experimental and subject to change";
1142 pub const EXPLAIN_PLACEMENT_IN: &'static str =
1143 "placement-in expression syntax is experimental and subject to change.";
1145 pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
1146 "Unsized tuple coercion is not stable enough for use and is subject to change";
1148 struct PostExpansionVisitor<'a> {
1149 context: &'a Context<'a>,
1152 macro_rules! gate_feature_post {
1153 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
1154 let (cx, span) = ($cx, $span);
1155 if !span.allows_unstable() {
1156 gate_feature!(cx.context, $feature, span, $explain)
1159 ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
1160 let (cx, span) = ($cx, $span);
1161 if !span.allows_unstable() {
1162 gate_feature!(cx.context, $feature, span, $explain, $level)
1167 impl<'a> PostExpansionVisitor<'a> {
1168 fn check_abi(&self, abi: Abi, span: Span) {
1170 Abi::RustIntrinsic => {
1171 gate_feature_post!(&self, intrinsics, span,
1172 "intrinsics are subject to change");
1174 Abi::PlatformIntrinsic => {
1175 gate_feature_post!(&self, platform_intrinsics, span,
1176 "platform intrinsics are experimental and possibly buggy");
1178 Abi::Vectorcall => {
1179 gate_feature_post!(&self, abi_vectorcall, span,
1180 "vectorcall is experimental and subject to change");
1183 gate_feature_post!(&self, abi_thiscall, span,
1184 "thiscall is experimental and subject to change");
1187 gate_feature_post!(&self, unboxed_closures, span,
1188 "rust-call ABI is subject to change");
1191 gate_feature_post!(&self, abi_sysv64, span,
1192 "sysv64 ABI is experimental and subject to change");
1195 gate_feature_post!(&self, abi_ptx, span,
1196 "PTX ABIs are experimental and subject to change");
1198 Abi::Unadjusted => {
1199 gate_feature_post!(&self, abi_unadjusted, span,
1200 "unadjusted ABI is an implementation detail and perma-unstable");
1202 Abi::Msp430Interrupt => {
1203 gate_feature_post!(&self, abi_msp430_interrupt, span,
1204 "msp430-interrupt ABI is experimental and subject to change");
1206 Abi::X86Interrupt => {
1207 gate_feature_post!(&self, abi_x86_interrupt, span,
1208 "x86-interrupt ABI is experimental and subject to change");
1223 fn contains_novel_literal(item: &ast::MetaItem) -> bool {
1224 use ast::MetaItemKind::*;
1225 use ast::NestedMetaItemKind::*;
1229 NameValue(ref lit) => !lit.node.is_str(),
1230 List(ref list) => list.iter().any(|li| {
1232 MetaItem(ref mi) => contains_novel_literal(mi),
1239 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1240 fn visit_attribute(&mut self, attr: &ast::Attribute) {
1241 if !attr.span.allows_unstable() {
1242 // check for gated attributes
1243 self.context.check_attribute(attr, false);
1246 if attr.check_name("doc") {
1247 if let Some(content) = attr.meta_item_list() {
1248 if content.len() == 1 && content[0].check_name("cfg") {
1249 gate_feature_post!(&self, doc_cfg, attr.span,
1250 "#[doc(cfg(...))] is experimental"
1252 } else if content.iter().any(|c| c.check_name("masked")) {
1253 gate_feature_post!(&self, doc_masked, attr.span,
1254 "#[doc(masked)] is experimental"
1260 if self.context.features.proc_macro && attr::is_known(attr) {
1264 let meta = panictry!(attr.parse_meta(self.context.parse_sess));
1265 if contains_novel_literal(&meta) {
1266 gate_feature_post!(&self, attr_literals, attr.span,
1267 "non-string literals in attributes, or string \
1268 literals in top-level positions, are experimental");
1272 fn visit_name(&mut self, sp: Span, name: ast::Name) {
1273 if !name.as_str().is_ascii() {
1274 gate_feature_post!(&self, non_ascii_idents, sp,
1275 "non-ascii idents are not fully supported.");
1279 fn visit_item(&mut self, i: &'a ast::Item) {
1281 ast::ItemKind::ExternCrate(_) => {
1282 if let Some(attr) = attr::find_by_name(&i.attrs[..], "macro_reexport") {
1283 gate_feature_post!(&self, macro_reexport, attr.span,
1284 "macros reexports are experimental \
1285 and possibly buggy");
1289 ast::ItemKind::ForeignMod(ref foreign_module) => {
1290 self.check_abi(foreign_module.abi, i.span);
1293 ast::ItemKind::Fn(..) => {
1294 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1295 gate_feature_post!(&self, plugin_registrar, i.span,
1296 "compiler plugins are experimental and possibly buggy");
1298 if attr::contains_name(&i.attrs[..], "start") {
1299 gate_feature_post!(&self, start, i.span,
1300 "a #[start] function is an experimental \
1301 feature whose signature may change \
1304 if attr::contains_name(&i.attrs[..], "main") {
1305 gate_feature_post!(&self, main, i.span,
1306 "declaration of a nonstandard #[main] \
1307 function may change over time, for now \
1308 a top-level `fn main()` is required");
1310 if let Some(attr) = attr::find_by_name(&i.attrs[..], "must_use") {
1311 gate_feature_post!(&self, fn_must_use, attr.span,
1312 "`#[must_use]` on functions is experimental",
1313 GateStrength::Soft);
1317 ast::ItemKind::Struct(..) => {
1318 if let Some(attr) = attr::find_by_name(&i.attrs[..], "simd") {
1319 gate_feature_post!(&self, simd, attr.span,
1320 "SIMD types are experimental and possibly buggy");
1321 self.context.parse_sess.span_diagnostic.span_warn(attr.span,
1322 "the `#[simd]` attribute \
1323 is deprecated, use \
1324 `#[repr(simd)]` instead");
1326 if let Some(attr) = attr::find_by_name(&i.attrs[..], "repr") {
1327 for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1328 if item.check_name("simd") {
1329 gate_feature_post!(&self, repr_simd, attr.span,
1330 "SIMD types are experimental and possibly buggy");
1332 if item.check_name("align") {
1333 gate_feature_post!(&self, repr_align, attr.span,
1334 "the struct `#[repr(align(u16))]` attribute \
1341 ast::ItemKind::DefaultImpl(..) => {
1342 gate_feature_post!(&self, optin_builtin_traits,
1344 "default trait implementations are experimental \
1345 and possibly buggy");
1348 ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, ref impl_items) => {
1349 if polarity == ast::ImplPolarity::Negative {
1350 gate_feature_post!(&self, optin_builtin_traits,
1352 "negative trait bounds are not yet fully implemented; \
1353 use marker types for now");
1356 if let ast::Defaultness::Default = defaultness {
1357 gate_feature_post!(&self, specialization,
1359 "specialization is unstable");
1362 for impl_item in impl_items {
1363 if let ast::ImplItemKind::Method(..) = impl_item.node {
1364 if let Some(attr) = attr::find_by_name(&impl_item.attrs[..], "must_use") {
1365 gate_feature_post!(&self, fn_must_use, attr.span,
1366 "`#[must_use]` on methods is experimental",
1367 GateStrength::Soft);
1373 ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
1374 let msg = "`macro` is experimental";
1375 gate_feature_post!(&self, decl_macro, i.span, msg);
1381 visit::walk_item(self, i);
1384 fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
1385 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
1386 Some(val) => val.as_str().starts_with("llvm."),
1390 gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1391 "linking to LLVM intrinsics is experimental");
1394 visit::walk_foreign_item(self, i)
1397 fn visit_ty(&mut self, ty: &'a ast::Ty) {
1399 ast::TyKind::BareFn(ref bare_fn_ty) => {
1400 self.check_abi(bare_fn_ty.abi, ty.span);
1402 ast::TyKind::ImplTrait(..) => {
1403 gate_feature_post!(&self, conservative_impl_trait, ty.span,
1404 "`impl Trait` is experimental");
1406 ast::TyKind::Never => {
1407 gate_feature_post!(&self, never_type, ty.span,
1408 "The `!` type is experimental");
1412 visit::walk_ty(self, ty)
1415 fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
1416 if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
1417 if output_ty.node != ast::TyKind::Never {
1418 self.visit_ty(output_ty)
1423 fn visit_expr(&mut self, e: &'a ast::Expr) {
1425 ast::ExprKind::Box(_) => {
1426 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1428 ast::ExprKind::Type(..) => {
1429 gate_feature_post!(&self, type_ascription, e.span,
1430 "type ascription is experimental");
1432 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1433 gate_feature_post!(&self, inclusive_range_syntax,
1435 "inclusive range syntax is experimental");
1437 ast::ExprKind::InPlace(..) => {
1438 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1440 ast::ExprKind::Yield(..) => {
1441 gate_feature_post!(&self, generators,
1443 "yield syntax is experimental");
1445 ast::ExprKind::Lit(ref lit) => {
1446 if let ast::LitKind::Int(_, ref ty) = lit.node {
1448 ast::LitIntType::Signed(ast::IntTy::I128) |
1449 ast::LitIntType::Unsigned(ast::UintTy::U128) => {
1450 gate_feature_post!(&self, i128_type, e.span,
1451 "128-bit integers are not stable");
1457 ast::ExprKind::Catch(_) => {
1458 gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
1462 visit::walk_expr(self, e);
1465 fn visit_arm(&mut self, arm: &'a ast::Arm) {
1466 if let Some(span) = arm.beginning_vert {
1467 gate_feature_post!(&self, match_beginning_vert,
1469 "Use of a '|' at the beginning of a match arm is experimental")
1471 visit::walk_arm(self, arm)
1474 fn visit_pat(&mut self, pattern: &'a ast::Pat) {
1475 match pattern.node {
1476 PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
1477 gate_feature_post!(&self, advanced_slice_patterns,
1479 "multiple-element slice matches anywhere \
1480 but at the end of a slice (e.g. \
1481 `[0, ..xs, 0]`) are experimental")
1483 PatKind::Slice(..) => {
1484 gate_feature_post!(&self, slice_patterns,
1486 "slice pattern syntax is experimental");
1488 PatKind::Box(..) => {
1489 gate_feature_post!(&self, box_patterns,
1491 "box pattern syntax is experimental");
1493 PatKind::Range(_, _, RangeEnd::Excluded) => {
1494 gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
1495 "exclusive range pattern syntax is experimental");
1497 PatKind::Range(_, _, RangeEnd::Included(RangeSyntax::DotDotEq)) => {
1498 gate_feature_post!(&self, dotdoteq_in_patterns, pattern.span,
1499 "`..=` syntax in patterns is experimental");
1503 visit::walk_pat(self, pattern)
1506 fn visit_fn(&mut self,
1507 fn_kind: FnKind<'a>,
1508 fn_decl: &'a ast::FnDecl,
1511 // check for const fn declarations
1512 if let FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) =
1514 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1516 // stability of const fn methods are covered in
1517 // visit_trait_item and visit_impl_item below; this is
1518 // because default methods don't pass through this
1522 FnKind::ItemFn(_, _, _, _, abi, _, _) |
1523 FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
1524 self.check_abi(abi, span);
1528 visit::walk_fn(self, fn_kind, fn_decl, span);
1531 fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1533 ast::TraitItemKind::Method(ref sig, ref block) => {
1534 if block.is_none() {
1535 self.check_abi(sig.abi, ti.span);
1537 if sig.constness.node == ast::Constness::Const {
1538 gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1541 ast::TraitItemKind::Type(_, Some(_)) => {
1542 gate_feature_post!(&self, associated_type_defaults, ti.span,
1543 "associated type defaults are unstable");
1547 visit::walk_trait_item(self, ti);
1550 fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
1551 if ii.defaultness == ast::Defaultness::Default {
1552 gate_feature_post!(&self, specialization,
1554 "specialization is unstable");
1558 ast::ImplItemKind::Method(ref sig, _) => {
1559 if sig.constness.node == ast::Constness::Const {
1560 gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1565 visit::walk_impl_item(self, ii);
1568 fn visit_generics(&mut self, g: &'a ast::Generics) {
1569 for t in &g.ty_params {
1570 if !t.attrs.is_empty() {
1571 gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
1572 "attributes on type parameter bindings are experimental");
1575 visit::walk_generics(self, g)
1578 fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) {
1579 if !lifetime_def.attrs.is_empty() {
1580 gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
1581 "attributes on lifetime bindings are experimental");
1583 visit::walk_lifetime_def(self, lifetime_def)
1586 fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
1587 if lt.ident.name == "'_" {
1588 gate_feature_post!(&self, underscore_lifetimes, lt.span,
1589 "underscore lifetimes are unstable");
1591 visit::walk_lifetime(self, lt)
1595 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1596 let mut features = Features::new();
1598 let mut feature_checker = FeatureChecker::default();
1600 for attr in krate_attrs {
1601 if !attr.check_name("feature") {
1605 match attr.meta_item_list() {
1607 span_err!(span_handler, attr.span, E0555,
1608 "malformed feature attribute, expected #![feature(...)]");
1612 let name = if let Some(word) = mi.word() {
1615 span_err!(span_handler, mi.span, E0556,
1616 "malformed feature, expected just one word");
1620 if let Some(&(_, _, _, set)) = ACTIVE_FEATURES.iter()
1621 .find(|& &(n, _, _, _)| name == n) {
1622 set(&mut features, mi.span);
1623 feature_checker.collect(&features, mi.span);
1625 else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1626 .find(|& &(n, _, _)| name == n)
1627 .or_else(|| STABLE_REMOVED_FEATURES.iter()
1628 .find(|& &(n, _, _)| name == n)) {
1629 span_err!(span_handler, mi.span, E0557, "feature has been removed");
1631 else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1632 .find(|& &(n, _, _)| name == n) {
1633 features.declared_stable_lang_features.push((name, mi.span));
1635 features.declared_lib_features.push((name, mi.span));
1642 feature_checker.check(span_handler);
1647 /// A collector for mutually exclusive and interdependent features and their flag spans.
1649 struct FeatureChecker {
1650 proc_macro: Option<Span>,
1651 custom_attribute: Option<Span>,
1652 copy_closures: Option<Span>,
1653 clone_closures: Option<Span>,
1656 impl FeatureChecker {
1657 // If this method turns out to be a hotspot due to branching,
1658 // the branching can be eliminated by modifying `set!()` to set these spans
1659 // only for the features that need to be checked for mutual exclusion.
1660 fn collect(&mut self, features: &Features, span: Span) {
1661 if features.proc_macro {
1662 // If self.proc_macro is None, set to Some(span)
1663 self.proc_macro = self.proc_macro.or(Some(span));
1666 if features.custom_attribute {
1667 self.custom_attribute = self.custom_attribute.or(Some(span));
1670 if features.copy_closures {
1671 self.copy_closures = self.copy_closures.or(Some(span));
1674 if features.clone_closures {
1675 self.clone_closures = self.clone_closures.or(Some(span));
1679 fn check(self, handler: &Handler) {
1680 if let (Some(pm_span), Some(ca_span)) = (self.proc_macro, self.custom_attribute) {
1681 handler.struct_span_err(pm_span, "Cannot use `#![feature(proc_macro)]` and \
1682 `#![feature(custom_attribute)] at the same time")
1683 .span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
1689 if let (Some(span), None) = (self.copy_closures, self.clone_closures) {
1690 handler.struct_span_err(span, "`#![feature(copy_closures)]` can only be used with \
1691 `#![feature(clone_closures)]`")
1692 .span_note(span, "`#![feature(copy_closures)]` declared here")
1700 pub fn check_crate(krate: &ast::Crate,
1702 features: &Features,
1703 plugin_attributes: &[(String, AttributeType)],
1704 unstable: UnstableFeatures) {
1705 maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1711 visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1714 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1715 pub enum UnstableFeatures {
1716 /// Hard errors for unstable features are active, as on
1717 /// beta/stable channels.
1719 /// Allow features to be activated, as on nightly.
1721 /// Errors are bypassed for bootstrapping. This is required any time
1722 /// during the build that feature-related lints are set to warn or above
1723 /// because the build turns on warnings-as-errors and uses lots of unstable
1724 /// features. As a result, this is always required for building Rust itself.
1728 impl UnstableFeatures {
1729 pub fn from_environment() -> UnstableFeatures {
1730 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1731 let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1732 // Whether we should enable unstable features for bootstrapping
1733 let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
1734 match (disable_unstable_features, bootstrap) {
1735 (_, true) => UnstableFeatures::Cheat,
1736 (true, _) => UnstableFeatures::Disallow,
1737 (false, _) => UnstableFeatures::Allow
1741 pub fn is_nightly_build(&self) -> bool {
1743 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1749 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1750 unstable: UnstableFeatures) {
1751 let allow_features = match unstable {
1752 UnstableFeatures::Allow => true,
1753 UnstableFeatures::Disallow => false,
1754 UnstableFeatures::Cheat => true
1756 if !allow_features {
1757 for attr in &krate.attrs {
1758 if attr.check_name("feature") {
1759 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1760 span_err!(span_handler, attr.span, E0554,
1761 "#![feature] may not be used on the {} release channel",