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};
42 fn f(features: &mut Features, span: Span) {
43 features.declared_lib_features.push((Symbol::intern("proc_macro"), span));
44 features.proc_macro = true;
46 f as fn(&mut Features, Span)
49 fn f(features: &mut Features, _: Span) {
50 features.$field = true;
52 f as fn(&mut Features, Span)
56 macro_rules! declare_features {
57 ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => {
58 /// Represents active features that are currently being implemented or
59 /// currently being considered for addition/removal.
60 const ACTIVE_FEATURES:
61 &'static [(&'static str, &'static str, Option<u32>, fn(&mut Features, Span))] =
62 &[$((stringify!($feature), $ver, $issue, set!($feature))),+];
64 /// A set of features to be used by later passes.
66 /// #![feature] attrs for stable language features, for error reporting
67 pub declared_stable_lang_features: Vec<(Symbol, Span)>,
68 /// #![feature] attrs for non-language (library) features
69 pub declared_lib_features: Vec<(Symbol, Span)>,
70 $(pub $feature: bool),+
74 pub fn new() -> Features {
76 declared_stable_lang_features: Vec::new(),
77 declared_lib_features: Vec::new(),
84 ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
85 /// Represents unstable features which have since been removed (it was once Active)
86 const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
87 $((stringify!($feature), $ver, $issue)),+
91 ($((stable_removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
92 /// Represents stable features which have since been removed (it was once Accepted)
93 const STABLE_REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
94 $((stringify!($feature), $ver, $issue)),+
98 ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => {
99 /// Those language feature has since been Accepted (it was once Active)
100 const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
101 $((stringify!($feature), $ver, $issue)),+
106 // If you change this, please modify src/doc/unstable-book as well.
108 // Don't ever remove anything from this list; set them to 'Removed'.
110 // The version numbers here correspond to the version in which the current status
111 // was set. This is most important for knowing when a particular feature became
114 // NB: tools/tidy/src/features.rs parses this information directly out of the
115 // source, so take care when modifying it.
118 (active, asm, "1.0.0", Some(29722)),
119 (active, concat_idents, "1.0.0", Some(29599)),
120 (active, link_args, "1.0.0", Some(29596)),
121 (active, log_syntax, "1.0.0", Some(29598)),
122 (active, non_ascii_idents, "1.0.0", Some(28979)),
123 (active, plugin_registrar, "1.0.0", Some(29597)),
124 (active, thread_local, "1.0.0", Some(29594)),
125 (active, trace_macros, "1.0.0", Some(29598)),
127 // rustc internal, for now:
128 (active, intrinsics, "1.0.0", None),
129 (active, lang_items, "1.0.0", None),
131 (active, link_llvm_intrinsics, "1.0.0", Some(29602)),
132 (active, linkage, "1.0.0", Some(29603)),
133 (active, quote, "1.0.0", Some(29601)),
134 (active, simd, "1.0.0", Some(27731)),
138 (active, rustc_diagnostic_macros, "1.0.0", None),
139 (active, rustc_const_unstable, "1.0.0", None),
140 (active, advanced_slice_patterns, "1.0.0", Some(23121)),
141 (active, box_syntax, "1.0.0", Some(27779)),
142 (active, placement_in_syntax, "1.0.0", Some(27779)),
143 (active, unboxed_closures, "1.0.0", Some(29625)),
145 (active, fundamental, "1.0.0", Some(29635)),
146 (active, main, "1.0.0", Some(29634)),
147 (active, needs_allocator, "1.4.0", Some(27389)),
148 (active, on_unimplemented, "1.0.0", Some(29628)),
149 (active, plugin, "1.0.0", Some(29597)),
150 (active, simd_ffi, "1.0.0", Some(27731)),
151 (active, start, "1.0.0", Some(29633)),
152 (active, structural_match, "1.8.0", Some(31434)),
153 (active, panic_runtime, "1.10.0", Some(32837)),
154 (active, needs_panic_runtime, "1.10.0", Some(32837)),
156 // OIBIT specific features
157 (active, optin_builtin_traits, "1.0.0", Some(13231)),
159 // macro reexport needs more discussion and stabilization
160 (active, macro_reexport, "1.0.0", Some(29638)),
162 // Allows use of #[staged_api]
164 (active, staged_api, "1.0.0", None),
166 // Allows using #![no_core]
167 (active, no_core, "1.3.0", Some(29639)),
169 // Allows using `box` in patterns; RFC 469
170 (active, box_patterns, "1.0.0", Some(29641)),
172 // Allows using the unsafe_destructor_blind_to_params attribute;
174 (active, dropck_parametricity, "1.3.0", Some(28498)),
176 // Allows using the may_dangle attribute; RFC 1327
177 (active, dropck_eyepatch, "1.10.0", Some(34761)),
179 // Allows the use of custom attributes; RFC 572
180 (active, custom_attribute, "1.0.0", Some(29642)),
182 // Allows the use of #[derive(Anything)] as sugar for
183 // #[derive_Anything].
184 (active, custom_derive, "1.0.0", Some(29644)),
186 // Allows the use of rustc_* attributes; RFC 572
187 (active, rustc_attrs, "1.0.0", Some(29642)),
189 // Allows the use of #[allow_internal_unstable]. This is an
190 // attribute on macro_rules! and can't use the attribute handling
191 // below (it has to be checked before expansion possibly makes
192 // macros disappear).
195 (active, allow_internal_unstable, "1.0.0", None),
197 // Allows the use of #[allow_internal_unsafe]. This is an
198 // attribute on macro_rules! and can't use the attribute handling
199 // below (it has to be checked before expansion possibly makes
200 // macros disappear).
203 (active, allow_internal_unsafe, "1.0.0", None),
205 // #23121. Array patterns have some hazards yet.
206 (active, slice_patterns, "1.0.0", Some(23121)),
208 // Allows the definition of `const fn` functions.
209 (active, const_fn, "1.2.0", Some(24111)),
211 // Allows indexing into constant arrays.
212 (active, const_indexing, "1.4.0", Some(29947)),
214 // Allows using #[prelude_import] on glob `use` items.
217 (active, prelude_import, "1.2.0", None),
219 // Allows default type parameters to influence type inference.
220 (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
222 // Allows associated type defaults
223 (active, associated_type_defaults, "1.2.0", Some(29661)),
225 // allow `repr(simd)`, and importing the various simd intrinsics
226 (active, repr_simd, "1.4.0", Some(27731)),
228 // Allows cfg(target_feature = "...").
229 (active, cfg_target_feature, "1.4.0", Some(29717)),
231 // allow `extern "platform-intrinsic" { ... }`
232 (active, platform_intrinsics, "1.4.0", Some(27731)),
235 // rust runtime internal
236 (active, unwind_attributes, "1.4.0", None),
238 // allow the use of `#[naked]` on functions.
239 (active, naked_functions, "1.9.0", Some(32408)),
241 // allow `#[no_debug]`
242 (active, no_debug, "1.5.0", Some(29721)),
244 // allow `#[omit_gdb_pretty_printer_section]`
246 (active, omit_gdb_pretty_printer_section, "1.5.0", None),
248 // Allows cfg(target_vendor = "...").
249 (active, cfg_target_vendor, "1.5.0", Some(29718)),
251 // Allow attributes on expressions and non-item statements
252 (active, stmt_expr_attributes, "1.6.0", Some(15701)),
254 // allow using type ascription in expressions
255 (active, type_ascription, "1.6.0", Some(23416)),
257 // Allows cfg(target_thread_local)
258 (active, cfg_target_thread_local, "1.7.0", Some(29594)),
261 (active, abi_vectorcall, "1.7.0", None),
264 (active, inclusive_range_syntax, "1.7.0", Some(28237)),
267 (active, exclusive_range_pattern, "1.11.0", Some(37854)),
269 // impl specialization (RFC 1210)
270 (active, specialization, "1.7.0", Some(31844)),
272 // Allows cfg(target_has_atomic = "...").
273 (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
275 // Allows `impl Trait` in function return types.
276 (active, conservative_impl_trait, "1.12.0", Some(34511)),
278 // Allows `impl Trait` in function arguments.
279 (active, universal_impl_trait, "1.23.0", Some(34511)),
282 (active, never_type, "1.13.0", Some(35121)),
284 // Allows all literals in attribute lists and values of key-value pairs.
285 (active, attr_literals, "1.13.0", Some(34981)),
287 // Allows the sysV64 ABI to be specified on all platforms
288 // instead of just the platforms on which it is the C ABI
289 (active, abi_sysv64, "1.13.0", Some(36167)),
291 // Allows untagged unions `union U { ... }`
292 (active, untagged_unions, "1.13.0", Some(32836)),
294 // Used to identify the `compiler_builtins` crate
296 (active, compiler_builtins, "1.13.0", None),
298 // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
299 (active, generic_param_attrs, "1.11.0", Some(34761)),
301 // Allows #[link(..., cfg(..))]
302 (active, link_cfg, "1.14.0", Some(37406)),
304 (active, use_extern_macros, "1.15.0", Some(35896)),
306 // Allows #[target_feature(...)]
307 (active, target_feature, "1.15.0", None),
309 // `extern "ptx-*" fn()`
310 (active, abi_ptx, "1.15.0", None),
313 (active, i128_type, "1.16.0", Some(35118)),
315 // The `repr(i128)` annotation for enums
316 (active, repr128, "1.16.0", Some(35118)),
318 // The `unadjusted` ABI. Perma unstable.
319 (active, abi_unadjusted, "1.16.0", None),
321 // Procedural macros 2.0.
322 (active, proc_macro, "1.16.0", Some(38356)),
324 // Declarative macros 2.0 (`macro`).
325 (active, decl_macro, "1.17.0", Some(39412)),
327 // Allows #[link(kind="static-nobundle"...]
328 (active, static_nobundle, "1.16.0", Some(37403)),
330 // `extern "msp430-interrupt" fn()`
331 (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
333 // Used to identify crates that contain sanitizer runtimes
335 (active, sanitizer_runtime, "1.17.0", None),
337 // Used to identify crates that contain the profiler runtime
339 (active, profiler_runtime, "1.18.0", None),
341 // `extern "x86-interrupt" fn()`
342 (active, abi_x86_interrupt, "1.17.0", Some(40180)),
345 // Allows the `catch {...}` expression
346 (active, catch_expr, "1.17.0", Some(31436)),
348 // Allows `repr(align(u16))` struct attribute (RFC 1358)
349 (active, repr_align, "1.17.0", Some(33626)),
351 // Used to preserve symbols (see llvm.used)
352 (active, used, "1.18.0", Some(40289)),
354 // Allows module-level inline assembly by way of global_asm!()
355 (active, global_asm, "1.18.0", Some(35119)),
357 // Allows overlapping impls of marker traits
358 (active, overlapping_marker_traits, "1.18.0", Some(29864)),
360 // Allows use of the :vis macro fragment specifier
361 (active, macro_vis_matcher, "1.18.0", Some(41022)),
364 (active, abi_thiscall, "1.19.0", None),
366 // Allows a test to fail without failing the whole suite
367 (active, allow_fail, "1.19.0", Some(42219)),
369 // Allows unsized tuple coercion.
370 (active, unsized_tuple_coercion, "1.20.0", Some(42877)),
373 (active, generators, "1.21.0", None),
376 // global allocators and their internals
377 (active, global_allocator, "1.20.0", None),
378 (active, allocator_internals, "1.20.0", None),
381 (active, doc_cfg, "1.21.0", Some(43781)),
383 (active, doc_masked, "1.21.0", Some(44027)),
385 // allow `#[must_use]` on functions and comparison operators (RFC 1940)
386 (active, fn_must_use, "1.21.0", Some(43302)),
388 // allow '|' at beginning of match arms (RFC 1925)
389 (active, match_beginning_vert, "1.21.0", Some(44101)),
391 // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008)
392 (active, non_exhaustive, "1.22.0", Some(44109)),
394 // Copy/Clone closures (RFC 2132)
395 (active, clone_closures, "1.22.0", Some(44490)),
396 (active, copy_closures, "1.22.0", Some(44490)),
398 // allow `'_` placeholder lifetimes
399 (active, underscore_lifetimes, "1.22.0", Some(44524)),
401 // allow `..=` in patterns (RFC 1192)
402 (active, dotdoteq_in_patterns, "1.22.0", Some(28237)),
404 // Default match binding modes (RFC 2005)
405 (active, match_default_bindings, "1.22.0", Some(42640)),
407 // Trait object syntax with `dyn` prefix
408 (active, dyn_trait, "1.22.0", Some(44662)),
410 // `crate` as visibility modifier, synonymous to `pub(crate)`
411 (active, crate_visibility_modifier, "1.23.0", Some(45388)),
414 (active, extern_types, "1.23.0", Some(43467)),
416 // Allow trait methods with arbitrary self types
417 (active, arbitrary_self_types, "1.23.0", Some(44874)),
421 (removed, import_shadowing, "1.0.0", None),
422 (removed, managed_boxes, "1.0.0", None),
423 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
424 (removed, negate_unsigned, "1.0.0", Some(29645)),
425 (removed, reflect, "1.0.0", Some(27749)),
426 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
427 (removed, opt_out_copy, "1.0.0", None),
428 (removed, quad_precision_float, "1.0.0", None),
429 (removed, struct_inherit, "1.0.0", None),
430 (removed, test_removed_feature, "1.0.0", None),
431 (removed, visible_private_types, "1.0.0", None),
432 (removed, unsafe_no_drop_flag, "1.0.0", None),
433 // Allows using items which are missing stability attributes
435 (removed, unmarked_api, "1.0.0", None),
436 (removed, pushpop_unsafe, "1.2.0", None),
437 (removed, allocator, "1.0.0", None),
441 (stable_removed, no_stack_check, "1.0.0", None),
445 (accepted, associated_types, "1.0.0", None),
446 // allow overloading augmented assignment operations like `a += b`
447 (accepted, augmented_assignments, "1.8.0", Some(28235)),
448 // allow empty structs and enum variants with braces
449 (accepted, braced_empty_structs, "1.8.0", Some(29720)),
450 (accepted, default_type_params, "1.0.0", None),
451 (accepted, globs, "1.0.0", None),
452 (accepted, if_let, "1.0.0", None),
453 // A temporary feature gate used to enable parser extensions needed
454 // to bootstrap fix for #5723.
455 (accepted, issue_5723_bootstrap, "1.0.0", None),
456 (accepted, macro_rules, "1.0.0", None),
457 // Allows using #![no_std]
458 (accepted, no_std, "1.6.0", None),
459 (accepted, slicing_syntax, "1.0.0", None),
460 (accepted, struct_variant, "1.0.0", None),
461 // These are used to test this portion of the compiler, they don't actually
463 (accepted, test_accepted_feature, "1.0.0", None),
464 (accepted, tuple_indexing, "1.0.0", None),
465 // Allows macros to appear in the type position.
466 (accepted, type_macros, "1.13.0", Some(27245)),
467 (accepted, while_let, "1.0.0", None),
468 // Allows `#[deprecated]` attribute
469 (accepted, deprecated, "1.9.0", Some(29935)),
471 (accepted, question_mark, "1.13.0", Some(31436)),
472 // Allows `..` in tuple (struct) patterns
473 (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
474 (accepted, item_like_imports, "1.15.0", Some(35120)),
475 // Allows using `Self` and associated types in struct expressions and patterns.
476 (accepted, more_struct_aliases, "1.16.0", Some(37544)),
477 // elide `'static` lifetimes in `static`s and `const`s
478 (accepted, static_in_const, "1.17.0", Some(35897)),
479 // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
480 (accepted, field_init_shorthand, "1.17.0", Some(37340)),
481 // Allows the definition recursive static items.
482 (accepted, static_recursion, "1.17.0", Some(29719)),
483 // pub(restricted) visibilities (RFC 1422)
484 (accepted, pub_restricted, "1.18.0", Some(32409)),
485 // The #![windows_subsystem] attribute
486 (accepted, windows_subsystem, "1.18.0", Some(37499)),
487 // Allows `break {expr}` with a value inside `loop`s.
488 (accepted, loop_break_value, "1.19.0", Some(37339)),
489 // Permits numeric fields in struct expressions and patterns.
490 (accepted, relaxed_adts, "1.19.0", Some(35626)),
491 // Coerces non capturing closures to function pointers
492 (accepted, closure_to_fn_coercion, "1.19.0", Some(39817)),
493 // Allows attributes on struct literal fields.
494 (accepted, struct_field_attributes, "1.20.0", Some(38814)),
495 // Allows the definition of associated constants in `trait` or `impl`
497 (accepted, associated_consts, "1.20.0", Some(29646)),
498 // Usage of the `compile_error!` macro
499 (accepted, compile_error, "1.20.0", Some(40872)),
500 // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
501 (accepted, rvalue_static_promotion, "1.21.0", Some(38865)),
502 // Allow Drop types in constants (RFC 1440)
503 (accepted, drop_types_in_const, "1.22.0", Some(33156)),
506 // If you change this, please modify src/doc/unstable-book as well. You must
507 // move that documentation into the relevant place in the other docs, and
508 // remove the chapter on the flag.
510 #[derive(PartialEq, Copy, Clone, Debug)]
511 pub enum AttributeType {
512 /// Normal, builtin attribute that is consumed
513 /// by the compiler before the unused_attribute check
516 /// Builtin attribute that may not be consumed by the compiler
517 /// before the unused_attribute check. These attributes
518 /// will be ignored by the unused_attribute lint
521 /// Builtin attribute that is only allowed at the crate level
525 pub enum AttributeGate {
526 /// Is gated by a given feature gate, reason
527 /// and function to check if enabled
528 Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
530 /// Ungated attribute, can be used on all release channels
535 fn is_deprecated(&self) -> bool {
537 Gated(Stability::Deprecated(_), ..) => true,
543 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
546 // Argument is tracking issue link.
547 Deprecated(&'static str),
551 impl ::std::fmt::Debug for AttributeGate {
552 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
554 Gated(ref stab, name, expl, _) =>
555 write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
556 Ungated => write!(fmt, "Ungated")
561 macro_rules! cfg_fn {
562 ($field: ident) => {{
563 fn f(features: &Features) -> bool {
566 f as fn(&Features) -> bool
570 pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
571 BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
574 pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
575 BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name))
578 // Attributes that have a special meaning to rustc or rustdoc
579 pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
582 ("warn", Normal, Ungated),
583 ("allow", Normal, Ungated),
584 ("forbid", Normal, Ungated),
585 ("deny", Normal, Ungated),
587 ("macro_reexport", Normal, Ungated),
588 ("macro_use", Normal, Ungated),
589 ("macro_export", Normal, Ungated),
590 ("plugin_registrar", Normal, Ungated),
592 ("cfg", Normal, Ungated),
593 ("cfg_attr", Normal, Ungated),
594 ("main", Normal, Ungated),
595 ("start", Normal, Ungated),
596 ("test", Normal, Ungated),
597 ("bench", Normal, Ungated),
598 ("simd", Normal, Ungated),
599 ("repr", Normal, Ungated),
600 ("path", Normal, Ungated),
601 ("abi", Normal, Ungated),
602 ("automatically_derived", Normal, Ungated),
603 ("no_mangle", Normal, Ungated),
604 ("no_link", Normal, Ungated),
605 ("derive", Normal, Ungated),
606 ("should_panic", Normal, Ungated),
607 ("ignore", Normal, Ungated),
608 ("no_implicit_prelude", Normal, Ungated),
609 ("reexport_test_harness_main", Normal, Ungated),
610 ("link_args", Normal, Gated(Stability::Unstable,
612 "the `link_args` attribute is experimental and not \
613 portable across platforms, it is recommended to \
614 use `#[link(name = \"foo\")] instead",
615 cfg_fn!(link_args))),
616 ("macro_escape", Normal, Ungated),
619 ("structural_match", Whitelisted, Gated(Stability::Unstable,
621 "the semantics of constant patterns is \
623 cfg_fn!(structural_match))),
626 ("non_exhaustive", Whitelisted, Gated(Stability::Unstable,
628 "non exhaustive is an experimental feature",
629 cfg_fn!(non_exhaustive))),
631 ("plugin", CrateLevel, Gated(Stability::Unstable,
633 "compiler plugins are experimental \
637 ("no_std", CrateLevel, Ungated),
638 ("no_core", CrateLevel, Gated(Stability::Unstable,
640 "no_core is experimental",
642 ("lang", Normal, Gated(Stability::Unstable,
644 "language items are subject to change",
645 cfg_fn!(lang_items))),
646 ("linkage", Whitelisted, Gated(Stability::Unstable,
648 "the `linkage` attribute is experimental \
649 and not portable across platforms",
651 ("thread_local", Whitelisted, Gated(Stability::Unstable,
653 "`#[thread_local]` is an experimental feature, and does \
654 not currently handle destructors. There is no \
655 corresponding `#[task_local]` mapping to the task \
657 cfg_fn!(thread_local))),
659 ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
661 "the `#[rustc_on_unimplemented]` attribute \
662 is an experimental feature",
663 cfg_fn!(on_unimplemented))),
664 ("rustc_const_unstable", Normal, Gated(Stability::Unstable,
665 "rustc_const_unstable",
666 "the `#[rustc_const_unstable]` attribute \
667 is an internal feature",
668 cfg_fn!(rustc_const_unstable))),
669 ("global_allocator", Normal, Gated(Stability::Unstable,
671 "the `#[global_allocator]` attribute is \
672 an experimental feature",
673 cfg_fn!(global_allocator))),
674 ("default_lib_allocator", Whitelisted, Gated(Stability::Unstable,
675 "allocator_internals",
676 "the `#[default_lib_allocator]` \
677 attribute is an experimental feature",
678 cfg_fn!(allocator_internals))),
679 ("needs_allocator", Normal, Gated(Stability::Unstable,
680 "allocator_internals",
681 "the `#[needs_allocator]` \
682 attribute is an experimental \
684 cfg_fn!(allocator_internals))),
685 ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
687 "the `#[panic_runtime]` attribute is \
688 an experimental feature",
689 cfg_fn!(panic_runtime))),
690 ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
691 "needs_panic_runtime",
692 "the `#[needs_panic_runtime]` \
693 attribute is an experimental \
695 cfg_fn!(needs_panic_runtime))),
696 ("rustc_variance", Normal, Gated(Stability::Unstable,
698 "the `#[rustc_variance]` attribute \
699 is just used for rustc unit tests \
700 and will never be stable",
701 cfg_fn!(rustc_attrs))),
702 ("rustc_error", Whitelisted, Gated(Stability::Unstable,
704 "the `#[rustc_error]` attribute \
705 is just used for rustc unit tests \
706 and will never be stable",
707 cfg_fn!(rustc_attrs))),
708 ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
710 "the `#[rustc_if_this_changed]` attribute \
711 is just used for rustc unit tests \
712 and will never be stable",
713 cfg_fn!(rustc_attrs))),
714 ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
716 "the `#[rustc_if_this_changed]` attribute \
717 is just used for rustc unit tests \
718 and will never be stable",
719 cfg_fn!(rustc_attrs))),
720 ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
722 "the `#[rustc_dirty]` attribute \
723 is just used for rustc unit tests \
724 and will never be stable",
725 cfg_fn!(rustc_attrs))),
726 ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
728 "the `#[rustc_clean]` attribute \
729 is just used for rustc unit tests \
730 and will never be stable",
731 cfg_fn!(rustc_attrs))),
732 ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
734 "the `#[rustc_metadata_dirty]` attribute \
735 is just used for rustc unit tests \
736 and will never be stable",
737 cfg_fn!(rustc_attrs))),
738 ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
740 "the `#[rustc_metadata_clean]` attribute \
741 is just used for rustc unit tests \
742 and will never be stable",
743 cfg_fn!(rustc_attrs))),
744 ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
747 is just used for rustc unit tests \
748 and will never be stable",
749 cfg_fn!(rustc_attrs))),
750 ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
753 is just used for rustc unit tests \
754 and will never be stable",
755 cfg_fn!(rustc_attrs))),
756 ("rustc_synthetic", Whitelisted, Gated(Stability::Unstable,
759 is just used for rustc unit tests \
760 and will never be stable",
761 cfg_fn!(rustc_attrs))),
762 ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
764 "internal rustc attributes will never be stable",
765 cfg_fn!(rustc_attrs))),
766 ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
768 "internal rustc attributes will never be stable",
769 cfg_fn!(rustc_attrs))),
770 ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
772 "the `#[rustc_mir]` attribute \
773 is just used for rustc unit tests \
774 and will never be stable",
775 cfg_fn!(rustc_attrs))),
776 ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
778 "the `#[rustc_inherit_overflow_checks]` \
779 attribute is just used to control \
780 overflow checking behavior of several \
781 libcore functions that are inlined \
782 across crates and will never be stable",
783 cfg_fn!(rustc_attrs))),
784 ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
786 "the `#[compiler_builtins]` attribute is used to \
787 identify the `compiler_builtins` crate which \
788 contains compiler-rt intrinsics and will never be \
790 cfg_fn!(compiler_builtins))),
791 ("sanitizer_runtime", Whitelisted, Gated(Stability::Unstable,
793 "the `#[sanitizer_runtime]` attribute is used to \
794 identify crates that contain the runtime of a \
795 sanitizer and will never be stable",
796 cfg_fn!(sanitizer_runtime))),
797 ("profiler_runtime", Whitelisted, Gated(Stability::Unstable,
799 "the `#[profiler_runtime]` attribute is used to \
800 identify the `profiler_builtins` crate which \
801 contains the profiler runtime and will never be \
803 cfg_fn!(profiler_runtime))),
805 ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
806 "allow_internal_unstable",
807 EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
808 cfg_fn!(allow_internal_unstable))),
810 ("allow_internal_unsafe", Normal, Gated(Stability::Unstable,
811 "allow_internal_unsafe",
812 EXPLAIN_ALLOW_INTERNAL_UNSAFE,
813 cfg_fn!(allow_internal_unsafe))),
815 ("fundamental", Whitelisted, Gated(Stability::Unstable,
817 "the `#[fundamental]` attribute \
818 is an experimental feature",
819 cfg_fn!(fundamental))),
821 ("proc_macro_derive", Normal, Ungated),
823 ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
825 "internal implementation detail",
826 cfg_fn!(rustc_attrs))),
828 // FIXME: #14408 whitelist docs since rustdoc looks at them
829 ("doc", Whitelisted, Ungated),
831 // FIXME: #14406 these are processed in trans, which happens after the
833 ("cold", Whitelisted, Ungated),
834 ("naked", Whitelisted, Gated(Stability::Unstable,
836 "the `#[naked]` attribute \
837 is an experimental feature",
838 cfg_fn!(naked_functions))),
839 ("target_feature", Whitelisted, Gated(
840 Stability::Unstable, "target_feature",
841 "the `#[target_feature]` attribute is an experimental feature",
842 cfg_fn!(target_feature))),
843 ("export_name", Whitelisted, Ungated),
844 ("inline", Whitelisted, Ungated),
845 ("link", Whitelisted, Ungated),
846 ("link_name", Whitelisted, Ungated),
847 ("link_section", Whitelisted, Ungated),
848 ("no_builtins", Whitelisted, Ungated),
849 ("no_mangle", Whitelisted, Ungated),
850 ("no_debug", Whitelisted, Gated(
851 Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
853 "the `#[no_debug]` attribute was an experimental feature that has been \
854 deprecated due to lack of demand",
856 ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
857 "omit_gdb_pretty_printer_section",
858 "the `#[omit_gdb_pretty_printer_section]` \
859 attribute is just used for the Rust test \
861 cfg_fn!(omit_gdb_pretty_printer_section))),
862 ("unsafe_destructor_blind_to_params",
864 Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761"),
865 "dropck_parametricity",
866 "unsafe_destructor_blind_to_params has been replaced by \
867 may_dangle and will be removed in the future",
868 cfg_fn!(dropck_parametricity))),
871 Gated(Stability::Unstable,
873 "may_dangle has unstable semantics and may be removed in the future",
874 cfg_fn!(dropck_eyepatch))),
875 ("unwind", Whitelisted, Gated(Stability::Unstable,
877 "#[unwind] is experimental",
878 cfg_fn!(unwind_attributes))),
879 ("used", Whitelisted, Gated(
880 Stability::Unstable, "used",
881 "the `#[used]` attribute is an experimental feature",
885 ("prelude_import", Whitelisted, Gated(Stability::Unstable,
887 "`#[prelude_import]` is for use by rustc only",
888 cfg_fn!(prelude_import))),
890 // FIXME: #14407 these are only looked at on-demand so we can't
891 // guarantee they'll have already been checked
892 ("rustc_deprecated", Whitelisted, Ungated),
893 ("must_use", Whitelisted, Ungated),
894 ("stable", Whitelisted, Ungated),
895 ("unstable", Whitelisted, Ungated),
896 ("deprecated", Normal, Ungated),
898 ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
900 "unboxed_closures are still evolving",
901 cfg_fn!(unboxed_closures))),
903 ("windows_subsystem", Whitelisted, Ungated),
905 ("proc_macro_attribute", Normal, Gated(Stability::Unstable,
907 "attribute proc macros are currently unstable",
908 cfg_fn!(proc_macro))),
910 ("proc_macro", Normal, Gated(Stability::Unstable,
912 "function-like proc macros are currently unstable",
913 cfg_fn!(proc_macro))),
915 ("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
916 "rustc_derive_registrar",
917 "used internally by rustc",
918 cfg_fn!(rustc_attrs))),
920 ("allow_fail", Normal, Gated(Stability::Unstable,
922 "allow_fail attribute is currently unstable",
923 cfg_fn!(allow_fail))),
925 ("rustc_std_internal_symbol", Whitelisted, Gated(Stability::Unstable,
927 "this is an internal attribute that will \
929 cfg_fn!(rustc_attrs))),
931 // Crate level attributes
932 ("crate_name", CrateLevel, Ungated),
933 ("crate_type", CrateLevel, Ungated),
934 ("crate_id", CrateLevel, Ungated),
935 ("feature", CrateLevel, Ungated),
936 ("no_start", CrateLevel, Ungated),
937 ("no_main", CrateLevel, Ungated),
938 ("no_builtins", CrateLevel, Ungated),
939 ("recursion_limit", CrateLevel, Ungated),
940 ("type_length_limit", CrateLevel, Ungated),
943 // cfg(...)'s that are feature gated
944 const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[
945 // (name in cfg, feature, function to check if the feature is enabled)
946 ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
947 ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
948 ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
949 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
952 #[derive(Debug, Eq, PartialEq)]
953 pub struct GatedCfg {
959 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
960 let name = cfg.name().as_str();
962 .position(|info| info.0 == name)
971 pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
972 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
973 if !has_feature(features) && !self.span.allows_unstable() {
974 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
975 emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
981 features: &'a Features,
982 parse_sess: &'a ParseSess,
983 plugin_attributes: &'a [(String, AttributeType)],
986 macro_rules! gate_feature_fn {
987 ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
988 let (cx, has_feature, span,
989 name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level);
990 let has_feature: bool = has_feature(&$cx.features);
991 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
992 if !has_feature && !span.allows_unstable() {
993 leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
999 macro_rules! gate_feature {
1000 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
1001 gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
1002 stringify!($feature), $explain, GateStrength::Hard)
1004 ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {
1005 gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
1006 stringify!($feature), $explain, $level)
1010 impl<'a> Context<'a> {
1011 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
1012 debug!("check_attribute(attr = {:?})", attr);
1013 let name = unwrap_or!(attr.name(), return).as_str();
1014 for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
1016 if let Gated(_, name, desc, ref has_feature) = *gateage {
1017 gate_feature_fn!(self, has_feature, attr.span, name, desc, GateStrength::Hard);
1019 debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
1023 for &(ref n, ref ty) in self.plugin_attributes {
1024 if attr.path == &**n {
1025 // Plugins can't gate attributes, so we don't check for it
1026 // unlike the code above; we only use this loop to
1027 // short-circuit to avoid the checks below
1028 debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty);
1032 if name.starts_with("rustc_") {
1033 gate_feature!(self, rustc_attrs, attr.span,
1034 "unless otherwise specified, attributes \
1035 with the prefix `rustc_` \
1036 are reserved for internal compiler diagnostics");
1037 } else if name.starts_with("derive_") {
1038 gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
1039 } else if !attr::is_known(attr) {
1040 // Only run the custom attribute lint during regular
1041 // feature gate checking. Macro gating runs
1042 // before the plugin attributes are registered
1043 // so we skip this then
1045 gate_feature!(self, custom_attribute, attr.span,
1046 &format!("The attribute `{}` is currently \
1047 unknown to the compiler and \
1049 added to it in the future",
1056 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
1057 let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] };
1058 cx.check_attribute(attr, true);
1061 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
1062 ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
1065 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
1066 if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
1068 // FIXME (#28244): enforce that active features have issue numbers
1069 // assert!(issue.is_some())
1072 // search in Accepted, Removed, or Stable Removed features
1073 let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES)
1074 .find(|t| t.0 == feature);
1076 Some(&(_, _, issue)) => issue,
1077 None => panic!("Feature `{}` is not declared anywhere", feature),
1082 pub enum GateIssue {
1084 Library(Option<u32>)
1087 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
1088 pub enum GateStrength {
1089 /// A hard error. (Most feature gates should use this.)
1091 /// Only a warning. (Use this only as backwards-compatibility demands.)
1095 pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
1097 feature_err(sess, feature, span, issue, explain).emit();
1100 pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
1101 explain: &str) -> DiagnosticBuilder<'a> {
1102 leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
1105 fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
1106 explain: &str, level: GateStrength) -> DiagnosticBuilder<'a> {
1107 let diag = &sess.span_diagnostic;
1109 let issue = match issue {
1110 GateIssue::Language => find_lang_feature_issue(feature),
1111 GateIssue::Library(lib) => lib,
1114 let explanation = if let Some(n) = issue {
1115 format!("{} (see issue #{})", explain, n)
1120 let mut err = match level {
1121 GateStrength::Hard => diag.struct_span_err(span, &explanation),
1122 GateStrength::Soft => diag.struct_span_warn(span, &explanation),
1125 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
1126 if sess.unstable_features.is_nightly_build() {
1127 err.help(&format!("add #![feature({})] to the \
1128 crate attributes to enable",
1132 // If we're on stable and only emitting a "soft" warning, add a note to
1133 // clarify that the feature isn't "on" (rather than being on but
1135 if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft {
1136 err.help("a nightly build of the compiler is required to enable this feature");
1143 const EXPLAIN_BOX_SYNTAX: &'static str =
1144 "box expression syntax is experimental; you can call `Box::new` instead.";
1146 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
1147 "attributes on non-item statements and expressions are experimental.";
1149 pub const EXPLAIN_ASM: &'static str =
1150 "inline assembly is not stable enough for use and is subject to change";
1152 pub const EXPLAIN_GLOBAL_ASM: &'static str =
1153 "`global_asm!` is not stable enough for use and is subject to change";
1155 pub const EXPLAIN_LOG_SYNTAX: &'static str =
1156 "`log_syntax!` is not stable enough for use and is subject to change";
1158 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
1159 "`concat_idents` is not stable enough for use and is subject to change";
1161 pub const EXPLAIN_TRACE_MACROS: &'static str =
1162 "`trace_macros` is not stable enough for use and is subject to change";
1163 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
1164 "allow_internal_unstable side-steps feature gating and stability checks";
1165 pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &'static str =
1166 "allow_internal_unsafe side-steps the unsafe_code lint";
1168 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
1169 "`#[derive]` for custom traits is deprecated and will be removed in the future.";
1171 pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
1172 "`#[derive]` for custom traits is deprecated and will be removed in the future. \
1173 Prefer using procedural macro custom derive.";
1175 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
1176 "attributes of the form `#[derive_*]` are reserved for the compiler";
1178 pub const EXPLAIN_VIS_MATCHER: &'static str =
1179 ":vis fragment specifier is experimental and subject to change";
1181 pub const EXPLAIN_PLACEMENT_IN: &'static str =
1182 "placement-in expression syntax is experimental and subject to change.";
1184 pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
1185 "Unsized tuple coercion is not stable enough for use and is subject to change";
1187 struct PostExpansionVisitor<'a> {
1188 context: &'a Context<'a>,
1191 macro_rules! gate_feature_post {
1192 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
1193 let (cx, span) = ($cx, $span);
1194 if !span.allows_unstable() {
1195 gate_feature!(cx.context, $feature, span, $explain)
1198 ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
1199 let (cx, span) = ($cx, $span);
1200 if !span.allows_unstable() {
1201 gate_feature!(cx.context, $feature, span, $explain, $level)
1206 impl<'a> PostExpansionVisitor<'a> {
1207 fn check_abi(&self, abi: Abi, span: Span) {
1209 Abi::RustIntrinsic => {
1210 gate_feature_post!(&self, intrinsics, span,
1211 "intrinsics are subject to change");
1213 Abi::PlatformIntrinsic => {
1214 gate_feature_post!(&self, platform_intrinsics, span,
1215 "platform intrinsics are experimental and possibly buggy");
1217 Abi::Vectorcall => {
1218 gate_feature_post!(&self, abi_vectorcall, span,
1219 "vectorcall is experimental and subject to change");
1222 gate_feature_post!(&self, abi_thiscall, span,
1223 "thiscall is experimental and subject to change");
1226 gate_feature_post!(&self, unboxed_closures, span,
1227 "rust-call ABI is subject to change");
1230 gate_feature_post!(&self, abi_sysv64, span,
1231 "sysv64 ABI is experimental and subject to change");
1234 gate_feature_post!(&self, abi_ptx, span,
1235 "PTX ABIs are experimental and subject to change");
1237 Abi::Unadjusted => {
1238 gate_feature_post!(&self, abi_unadjusted, span,
1239 "unadjusted ABI is an implementation detail and perma-unstable");
1241 Abi::Msp430Interrupt => {
1242 gate_feature_post!(&self, abi_msp430_interrupt, span,
1243 "msp430-interrupt ABI is experimental and subject to change");
1245 Abi::X86Interrupt => {
1246 gate_feature_post!(&self, abi_x86_interrupt, span,
1247 "x86-interrupt ABI is experimental and subject to change");
1262 fn contains_novel_literal(item: &ast::MetaItem) -> bool {
1263 use ast::MetaItemKind::*;
1264 use ast::NestedMetaItemKind::*;
1268 NameValue(ref lit) => !lit.node.is_str(),
1269 List(ref list) => list.iter().any(|li| {
1271 MetaItem(ref mi) => contains_novel_literal(mi),
1278 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1279 fn visit_attribute(&mut self, attr: &ast::Attribute) {
1280 if !attr.span.allows_unstable() {
1281 // check for gated attributes
1282 self.context.check_attribute(attr, false);
1285 if attr.check_name("doc") {
1286 if let Some(content) = attr.meta_item_list() {
1287 if content.len() == 1 && content[0].check_name("cfg") {
1288 gate_feature_post!(&self, doc_cfg, attr.span,
1289 "#[doc(cfg(...))] is experimental"
1291 } else if content.iter().any(|c| c.check_name("masked")) {
1292 gate_feature_post!(&self, doc_masked, attr.span,
1293 "#[doc(masked)] is experimental"
1299 if self.context.features.proc_macro && attr::is_known(attr) {
1303 let meta = panictry!(attr.parse_meta(self.context.parse_sess));
1304 if contains_novel_literal(&meta) {
1305 gate_feature_post!(&self, attr_literals, attr.span,
1306 "non-string literals in attributes, or string \
1307 literals in top-level positions, are experimental");
1311 fn visit_name(&mut self, sp: Span, name: ast::Name) {
1312 if !name.as_str().is_ascii() {
1313 gate_feature_post!(&self, non_ascii_idents, sp,
1314 "non-ascii idents are not fully supported.");
1318 fn visit_item(&mut self, i: &'a ast::Item) {
1320 ast::ItemKind::ExternCrate(_) => {
1321 if let Some(attr) = attr::find_by_name(&i.attrs[..], "macro_reexport") {
1322 gate_feature_post!(&self, macro_reexport, attr.span,
1323 "macros reexports are experimental \
1324 and possibly buggy");
1328 ast::ItemKind::ForeignMod(ref foreign_module) => {
1329 self.check_abi(foreign_module.abi, i.span);
1332 ast::ItemKind::Fn(..) => {
1333 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1334 gate_feature_post!(&self, plugin_registrar, i.span,
1335 "compiler plugins are experimental and possibly buggy");
1337 if attr::contains_name(&i.attrs[..], "start") {
1338 gate_feature_post!(&self, start, i.span,
1339 "a #[start] function is an experimental \
1340 feature whose signature may change \
1343 if attr::contains_name(&i.attrs[..], "main") {
1344 gate_feature_post!(&self, main, i.span,
1345 "declaration of a nonstandard #[main] \
1346 function may change over time, for now \
1347 a top-level `fn main()` is required");
1349 if let Some(attr) = attr::find_by_name(&i.attrs[..], "must_use") {
1350 gate_feature_post!(&self, fn_must_use, attr.span,
1351 "`#[must_use]` on functions is experimental",
1352 GateStrength::Soft);
1356 ast::ItemKind::Struct(..) => {
1357 if let Some(attr) = attr::find_by_name(&i.attrs[..], "simd") {
1358 gate_feature_post!(&self, simd, attr.span,
1359 "SIMD types are experimental and possibly buggy");
1360 self.context.parse_sess.span_diagnostic.span_warn(attr.span,
1361 "the `#[simd]` attribute \
1362 is deprecated, use \
1363 `#[repr(simd)]` instead");
1365 if let Some(attr) = attr::find_by_name(&i.attrs[..], "repr") {
1366 for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1367 if item.check_name("simd") {
1368 gate_feature_post!(&self, repr_simd, attr.span,
1369 "SIMD types are experimental and possibly buggy");
1371 if item.check_name("align") {
1372 gate_feature_post!(&self, repr_align, attr.span,
1373 "the struct `#[repr(align(u16))]` attribute \
1380 ast::ItemKind::AutoImpl(..) => {
1381 gate_feature_post!(&self, optin_builtin_traits,
1383 "auto trait implementations are experimental \
1384 and possibly buggy");
1387 ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, ref impl_items) => {
1388 if polarity == ast::ImplPolarity::Negative {
1389 gate_feature_post!(&self, optin_builtin_traits,
1391 "negative trait bounds are not yet fully implemented; \
1392 use marker types for now");
1395 if let ast::Defaultness::Default = defaultness {
1396 gate_feature_post!(&self, specialization,
1398 "specialization is unstable");
1401 for impl_item in impl_items {
1402 if let ast::ImplItemKind::Method(..) = impl_item.node {
1403 if let Some(attr) = attr::find_by_name(&impl_item.attrs[..], "must_use") {
1404 gate_feature_post!(&self, fn_must_use, attr.span,
1405 "`#[must_use]` on methods is experimental",
1406 GateStrength::Soft);
1412 ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => {
1413 gate_feature_post!(&self, optin_builtin_traits,
1415 "auto traits are experimental and possibly buggy");
1418 ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
1419 let msg = "`macro` is experimental";
1420 gate_feature_post!(&self, decl_macro, i.span, msg);
1426 visit::walk_item(self, i);
1429 fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
1431 ast::ForeignItemKind::Fn(..) |
1432 ast::ForeignItemKind::Static(..) => {
1433 let link_name = attr::first_attr_value_str_by_name(&i.attrs, "link_name");
1434 let links_to_llvm = match link_name {
1435 Some(val) => val.as_str().starts_with("llvm."),
1439 gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1440 "linking to LLVM intrinsics is experimental");
1443 ast::ForeignItemKind::Ty => {
1444 gate_feature_post!(&self, extern_types, i.span,
1445 "extern types are experimental");
1449 visit::walk_foreign_item(self, i)
1452 fn visit_ty(&mut self, ty: &'a ast::Ty) {
1454 ast::TyKind::BareFn(ref bare_fn_ty) => {
1455 self.check_abi(bare_fn_ty.abi, ty.span);
1457 ast::TyKind::Never => {
1458 gate_feature_post!(&self, never_type, ty.span,
1459 "The `!` type is experimental");
1461 ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => {
1462 gate_feature_post!(&self, dyn_trait, ty.span,
1463 "`dyn Trait` syntax is unstable");
1467 visit::walk_ty(self, ty)
1470 fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
1471 if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
1472 if output_ty.node != ast::TyKind::Never {
1473 self.visit_ty(output_ty)
1478 fn visit_expr(&mut self, e: &'a ast::Expr) {
1480 ast::ExprKind::Box(_) => {
1481 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1483 ast::ExprKind::Type(..) => {
1484 gate_feature_post!(&self, type_ascription, e.span,
1485 "type ascription is experimental");
1487 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1488 gate_feature_post!(&self, inclusive_range_syntax,
1490 "inclusive range syntax is experimental");
1492 ast::ExprKind::InPlace(..) => {
1493 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1495 ast::ExprKind::Yield(..) => {
1496 gate_feature_post!(&self, generators,
1498 "yield syntax is experimental");
1500 ast::ExprKind::Lit(ref lit) => {
1501 if let ast::LitKind::Int(_, ref ty) = lit.node {
1503 ast::LitIntType::Signed(ast::IntTy::I128) |
1504 ast::LitIntType::Unsigned(ast::UintTy::U128) => {
1505 gate_feature_post!(&self, i128_type, e.span,
1506 "128-bit integers are not stable");
1512 ast::ExprKind::Catch(_) => {
1513 gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
1517 visit::walk_expr(self, e);
1520 fn visit_arm(&mut self, arm: &'a ast::Arm) {
1521 if let Some(span) = arm.beginning_vert {
1522 gate_feature_post!(&self, match_beginning_vert,
1524 "Use of a '|' at the beginning of a match arm is experimental")
1526 visit::walk_arm(self, arm)
1529 fn visit_pat(&mut self, pattern: &'a ast::Pat) {
1530 match pattern.node {
1531 PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
1532 gate_feature_post!(&self, advanced_slice_patterns,
1534 "multiple-element slice matches anywhere \
1535 but at the end of a slice (e.g. \
1536 `[0, ..xs, 0]`) are experimental")
1538 PatKind::Slice(..) => {
1539 gate_feature_post!(&self, slice_patterns,
1541 "slice pattern syntax is experimental");
1543 PatKind::Box(..) => {
1544 gate_feature_post!(&self, box_patterns,
1546 "box pattern syntax is experimental");
1548 PatKind::Range(_, _, RangeEnd::Excluded) => {
1549 gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
1550 "exclusive range pattern syntax is experimental");
1552 PatKind::Range(_, _, RangeEnd::Included(RangeSyntax::DotDotEq)) => {
1553 gate_feature_post!(&self, dotdoteq_in_patterns, pattern.span,
1554 "`..=` syntax in patterns is experimental");
1558 visit::walk_pat(self, pattern)
1561 fn visit_fn(&mut self,
1562 fn_kind: FnKind<'a>,
1563 fn_decl: &'a ast::FnDecl,
1566 // check for const fn declarations
1567 if let FnKind::ItemFn(_, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) =
1569 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1571 // stability of const fn methods are covered in
1572 // visit_trait_item and visit_impl_item below; this is
1573 // because default methods don't pass through this
1577 FnKind::ItemFn(_, _, _, abi, _, _) |
1578 FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
1579 self.check_abi(abi, span);
1583 visit::walk_fn(self, fn_kind, fn_decl, span);
1586 fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1588 ast::TraitItemKind::Method(ref sig, ref block) => {
1589 if block.is_none() {
1590 self.check_abi(sig.abi, ti.span);
1592 if sig.constness.node == ast::Constness::Const {
1593 gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1596 ast::TraitItemKind::Type(_, Some(_)) => {
1597 gate_feature_post!(&self, associated_type_defaults, ti.span,
1598 "associated type defaults are unstable");
1602 visit::walk_trait_item(self, ti);
1605 fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
1606 if ii.defaultness == ast::Defaultness::Default {
1607 gate_feature_post!(&self, specialization,
1609 "specialization is unstable");
1613 ast::ImplItemKind::Method(ref sig, _) => {
1614 if sig.constness.node == ast::Constness::Const {
1615 gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1620 visit::walk_impl_item(self, ii);
1623 fn visit_vis(&mut self, vis: &'a ast::Visibility) {
1624 if let ast::Visibility::Crate(span, ast::CrateSugar::JustCrate) = *vis {
1625 gate_feature_post!(&self, crate_visibility_modifier, span,
1626 "`crate` visibility modifier is experimental");
1628 visit::walk_vis(self, vis);
1631 fn visit_generics(&mut self, g: &'a ast::Generics) {
1632 for t in &g.ty_params {
1633 if !t.attrs.is_empty() {
1634 gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
1635 "attributes on type parameter bindings are experimental");
1638 visit::walk_generics(self, g)
1641 fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) {
1642 if !lifetime_def.attrs.is_empty() {
1643 gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
1644 "attributes on lifetime bindings are experimental");
1646 visit::walk_lifetime_def(self, lifetime_def)
1649 fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
1650 if lt.ident.name == "'_" {
1651 gate_feature_post!(&self, underscore_lifetimes, lt.span,
1652 "underscore lifetimes are unstable");
1654 visit::walk_lifetime(self, lt)
1658 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1659 let mut features = Features::new();
1661 let mut feature_checker = FeatureChecker::default();
1663 for attr in krate_attrs {
1664 if !attr.check_name("feature") {
1668 match attr.meta_item_list() {
1670 span_err!(span_handler, attr.span, E0555,
1671 "malformed feature attribute, expected #![feature(...)]");
1675 let name = if let Some(word) = mi.word() {
1678 span_err!(span_handler, mi.span, E0556,
1679 "malformed feature, expected just one word");
1683 if let Some(&(_, _, _, set)) = ACTIVE_FEATURES.iter()
1684 .find(|& &(n, _, _, _)| name == n) {
1685 set(&mut features, mi.span);
1686 feature_checker.collect(&features, mi.span);
1688 else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1689 .find(|& &(n, _, _)| name == n)
1690 .or_else(|| STABLE_REMOVED_FEATURES.iter()
1691 .find(|& &(n, _, _)| name == n)) {
1692 span_err!(span_handler, mi.span, E0557, "feature has been removed");
1694 else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1695 .find(|& &(n, _, _)| name == n) {
1696 features.declared_stable_lang_features.push((name, mi.span));
1698 features.declared_lib_features.push((name, mi.span));
1705 feature_checker.check(span_handler);
1710 /// A collector for mutually exclusive and interdependent features and their flag spans.
1712 struct FeatureChecker {
1713 proc_macro: Option<Span>,
1714 custom_attribute: Option<Span>,
1715 copy_closures: Option<Span>,
1716 clone_closures: Option<Span>,
1719 impl FeatureChecker {
1720 // If this method turns out to be a hotspot due to branching,
1721 // the branching can be eliminated by modifying `set!()` to set these spans
1722 // only for the features that need to be checked for mutual exclusion.
1723 fn collect(&mut self, features: &Features, span: Span) {
1724 if features.proc_macro {
1725 // If self.proc_macro is None, set to Some(span)
1726 self.proc_macro = self.proc_macro.or(Some(span));
1729 if features.custom_attribute {
1730 self.custom_attribute = self.custom_attribute.or(Some(span));
1733 if features.copy_closures {
1734 self.copy_closures = self.copy_closures.or(Some(span));
1737 if features.clone_closures {
1738 self.clone_closures = self.clone_closures.or(Some(span));
1742 fn check(self, handler: &Handler) {
1743 if let (Some(pm_span), Some(ca_span)) = (self.proc_macro, self.custom_attribute) {
1744 handler.struct_span_err(pm_span, "Cannot use `#![feature(proc_macro)]` and \
1745 `#![feature(custom_attribute)] at the same time")
1746 .span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
1752 if let (Some(span), None) = (self.copy_closures, self.clone_closures) {
1753 handler.struct_span_err(span, "`#![feature(copy_closures)]` can only be used with \
1754 `#![feature(clone_closures)]`")
1755 .span_note(span, "`#![feature(copy_closures)]` declared here")
1763 pub fn check_crate(krate: &ast::Crate,
1765 features: &Features,
1766 plugin_attributes: &[(String, AttributeType)],
1767 unstable: UnstableFeatures) {
1768 maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1774 visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1777 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1778 pub enum UnstableFeatures {
1779 /// Hard errors for unstable features are active, as on
1780 /// beta/stable channels.
1782 /// Allow features to be activated, as on nightly.
1784 /// Errors are bypassed for bootstrapping. This is required any time
1785 /// during the build that feature-related lints are set to warn or above
1786 /// because the build turns on warnings-as-errors and uses lots of unstable
1787 /// features. As a result, this is always required for building Rust itself.
1791 impl UnstableFeatures {
1792 pub fn from_environment() -> UnstableFeatures {
1793 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1794 let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1795 // Whether we should enable unstable features for bootstrapping
1796 let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
1797 match (disable_unstable_features, bootstrap) {
1798 (_, true) => UnstableFeatures::Cheat,
1799 (true, _) => UnstableFeatures::Disallow,
1800 (false, _) => UnstableFeatures::Allow
1804 pub fn is_nightly_build(&self) -> bool {
1806 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1812 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1813 unstable: UnstableFeatures) {
1814 let allow_features = match unstable {
1815 UnstableFeatures::Allow => true,
1816 UnstableFeatures::Disallow => false,
1817 UnstableFeatures::Cheat => true
1819 if !allow_features {
1820 for attr in &krate.attrs {
1821 if attr.check_name("feature") {
1822 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1823 span_err!(span_handler, attr.span, E0554,
1824 "#![feature] may not be used on the {} release channel",