1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 //! This module implements the gating necessary for preventing certain compiler
14 //! features from being used by default. This module will crawl a pre-expanded
15 //! AST to ensure that there are no features which are used that are not
18 //! Features are enabled in programs via the crate-level attributes of
19 //! `#![feature(...)]` with a comma-separated list of features.
21 //! For the purpose of future feature-tracking, once code for detection of feature
22 //! gate usage is added, *do not remove it again* even once the feature
25 use self::AttributeType::*;
26 use self::AttributeGate::*;
29 use ast::{self, NodeId, PatKind, RangeEnd};
31 use codemap::{CodeMap, Spanned};
33 use errors::{DiagnosticBuilder, Handler, FatalError};
34 use visit::{self, FnKind, Visitor};
38 use std::ascii::AsciiExt;
43 fn f(features: &mut Features) -> &mut bool {
46 f as fn(&mut Features) -> &mut bool
50 macro_rules! declare_features {
51 ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => {
52 /// Represents active features that are currently being implemented or
53 /// currently being considered for addition/removal.
54 const ACTIVE_FEATURES: &'static [(&'static str, &'static str,
55 Option<u32>, fn(&mut Features) -> &mut bool)] = &[
56 $((stringify!($feature), $ver, $issue, setter!($feature))),+
59 /// A set of features to be used by later passes.
61 /// #![feature] attrs for stable language features, for error reporting
62 pub declared_stable_lang_features: Vec<(Symbol, Span)>,
63 /// #![feature] attrs for non-language (library) features
64 pub declared_lib_features: Vec<(Symbol, Span)>,
65 $(pub $feature: bool),+
69 pub fn new() -> Features {
71 declared_stable_lang_features: Vec::new(),
72 declared_lib_features: Vec::new(),
79 ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
80 /// Represents features which has since been removed (it was once Active)
81 const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
82 $((stringify!($feature), $ver, $issue)),+
86 ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => {
87 /// Those language feature has since been Accepted (it was once Active)
88 const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
89 $((stringify!($feature), $ver, $issue)),+
94 // If you change this list without updating src/doc/reference.md, @cmr will be sad
95 // Don't ever remove anything from this list; set them to 'Removed'.
96 // The version numbers here correspond to the version in which the current status
97 // was set. This is most important for knowing when a particular feature became
99 // NB: The featureck.py script parses this information directly out of the source
100 // so take care when modifying it.
103 (active, asm, "1.0.0", Some(29722)),
104 (active, concat_idents, "1.0.0", Some(29599)),
105 (active, link_args, "1.0.0", Some(29596)),
106 (active, log_syntax, "1.0.0", Some(29598)),
107 (active, non_ascii_idents, "1.0.0", Some(28979)),
108 (active, plugin_registrar, "1.0.0", Some(29597)),
109 (active, thread_local, "1.0.0", Some(29594)),
110 (active, trace_macros, "1.0.0", Some(29598)),
112 // rustc internal, for now:
113 (active, intrinsics, "1.0.0", None),
114 (active, lang_items, "1.0.0", None),
116 (active, link_llvm_intrinsics, "1.0.0", Some(29602)),
117 (active, linkage, "1.0.0", Some(29603)),
118 (active, quote, "1.0.0", Some(29601)),
119 (active, simd, "1.0.0", Some(27731)),
123 (active, rustc_diagnostic_macros, "1.0.0", None),
124 (active, advanced_slice_patterns, "1.0.0", Some(23121)),
125 (active, box_syntax, "1.0.0", Some(27779)),
126 (active, placement_in_syntax, "1.0.0", Some(27779)),
127 (active, unboxed_closures, "1.0.0", Some(29625)),
129 (active, allocator, "1.0.0", Some(27389)),
130 (active, fundamental, "1.0.0", Some(29635)),
131 (active, main, "1.0.0", Some(29634)),
132 (active, needs_allocator, "1.4.0", Some(27389)),
133 (active, on_unimplemented, "1.0.0", Some(29628)),
134 (active, plugin, "1.0.0", Some(29597)),
135 (active, simd_ffi, "1.0.0", Some(27731)),
136 (active, start, "1.0.0", Some(29633)),
137 (active, structural_match, "1.8.0", Some(31434)),
138 (active, panic_runtime, "1.10.0", Some(32837)),
139 (active, needs_panic_runtime, "1.10.0", Some(32837)),
141 // OIBIT specific features
142 (active, optin_builtin_traits, "1.0.0", Some(13231)),
144 // macro reexport needs more discussion and stabilization
145 (active, macro_reexport, "1.0.0", Some(29638)),
147 // Allows use of #[staged_api]
149 (active, staged_api, "1.0.0", None),
151 // Allows using #![no_core]
152 (active, no_core, "1.3.0", Some(29639)),
154 // Allows using `box` in patterns; RFC 469
155 (active, box_patterns, "1.0.0", Some(29641)),
157 // Allows using the unsafe_destructor_blind_to_params attribute;
159 (active, dropck_parametricity, "1.3.0", Some(28498)),
161 // Allows using the may_dangle attribute; RFC 1327
162 (active, dropck_eyepatch, "1.10.0", Some(34761)),
164 // Allows the use of custom attributes; RFC 572
165 (active, custom_attribute, "1.0.0", Some(29642)),
167 // Allows the use of #[derive(Anything)] as sugar for
168 // #[derive_Anything].
169 (active, custom_derive, "1.0.0", Some(29644)),
171 // Allows the use of rustc_* attributes; RFC 572
172 (active, rustc_attrs, "1.0.0", Some(29642)),
174 // Allows the use of #[allow_internal_unstable]. This is an
175 // attribute on macro_rules! and can't use the attribute handling
176 // below (it has to be checked before expansion possibly makes
177 // macros disappear).
180 (active, allow_internal_unstable, "1.0.0", None),
182 // #23121. Array patterns have some hazards yet.
183 (active, slice_patterns, "1.0.0", Some(23121)),
185 // Allows the definition of associated constants in `trait` or `impl`
187 (active, associated_consts, "1.0.0", Some(29646)),
189 // Allows the definition of `const fn` functions.
190 (active, const_fn, "1.2.0", Some(24111)),
192 // Allows indexing into constant arrays.
193 (active, const_indexing, "1.4.0", Some(29947)),
195 // Allows using #[prelude_import] on glob `use` items.
198 (active, prelude_import, "1.2.0", None),
200 // Allows the definition recursive static items.
201 (active, static_recursion, "1.3.0", Some(29719)),
203 // Allows default type parameters to influence type inference.
204 (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
206 // Allows associated type defaults
207 (active, associated_type_defaults, "1.2.0", Some(29661)),
209 // allow `repr(simd)`, and importing the various simd intrinsics
210 (active, repr_simd, "1.4.0", Some(27731)),
212 // Allows cfg(target_feature = "...").
213 (active, cfg_target_feature, "1.4.0", Some(29717)),
215 // allow `extern "platform-intrinsic" { ... }`
216 (active, platform_intrinsics, "1.4.0", Some(27731)),
219 // rust runtime internal
220 (active, unwind_attributes, "1.4.0", None),
222 // allow the use of `#[naked]` on functions.
223 (active, naked_functions, "1.9.0", Some(32408)),
225 // allow `#[no_debug]`
226 (active, no_debug, "1.5.0", Some(29721)),
228 // allow `#[omit_gdb_pretty_printer_section]`
230 (active, omit_gdb_pretty_printer_section, "1.5.0", None),
232 // Allows cfg(target_vendor = "...").
233 (active, cfg_target_vendor, "1.5.0", Some(29718)),
235 // Allow attributes on expressions and non-item statements
236 (active, stmt_expr_attributes, "1.6.0", Some(15701)),
238 // allow using type ascription in expressions
239 (active, type_ascription, "1.6.0", Some(23416)),
241 // Allows cfg(target_thread_local)
242 (active, cfg_target_thread_local, "1.7.0", Some(29594)),
245 (active, abi_vectorcall, "1.7.0", None),
248 (active, inclusive_range_syntax, "1.7.0", Some(28237)),
251 (active, exclusive_range_pattern, "1.11.0", Some(37854)),
253 // impl specialization (RFC 1210)
254 (active, specialization, "1.7.0", Some(31844)),
256 // pub(restricted) visibilities (RFC 1422)
257 (active, pub_restricted, "1.9.0", Some(32409)),
259 // Allow Drop types in statics/const functions (RFC 1440)
260 (active, drop_types_in_const, "1.9.0", Some(33156)),
262 // Allows cfg(target_has_atomic = "...").
263 (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
265 // Allows `impl Trait` in function return types.
266 (active, conservative_impl_trait, "1.12.0", Some(34511)),
268 // Permits numeric fields in struct expressions and patterns.
269 (active, relaxed_adts, "1.12.0", Some(35626)),
272 (active, never_type, "1.13.0", Some(35121)),
274 // Allows all literals in attribute lists and values of key-value pairs.
275 (active, attr_literals, "1.13.0", Some(34981)),
277 // Allows the sysV64 ABI to be specified on all platforms
278 // instead of just the platforms on which it is the C ABI
279 (active, abi_sysv64, "1.13.0", Some(36167)),
281 // Allows untagged unions `union U { ... }`
282 (active, untagged_unions, "1.13.0", Some(32836)),
284 // elide `'static` lifetimes in `static`s and `const`s
285 (active, static_in_const, "1.13.0", Some(35897)),
287 // Used to identify the `compiler_builtins` crate
289 (active, compiler_builtins, "1.13.0", None),
291 // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
292 (active, generic_param_attrs, "1.11.0", Some(34761)),
294 // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
295 (active, field_init_shorthand, "1.14.0", Some(37340)),
297 // The #![windows_subsystem] attribute
298 (active, windows_subsystem, "1.14.0", Some(37499)),
300 // Allows #[link(..., cfg(..))]
301 (active, link_cfg, "1.14.0", Some(37406)),
303 (active, use_extern_macros, "1.15.0", Some(35896)),
305 // Allows `break {expr}` with a value inside `loop`s.
306 (active, loop_break_value, "1.14.0", Some(37339)),
308 // Allows #[target_feature(...)]
309 (active, target_feature, "1.15.0", None),
311 // `extern "ptx-*" fn()`
312 (active, abi_ptx, "1.15.0", None),
315 (active, i128_type, "1.16.0", Some(35118)),
317 // The `unadjusted` ABI. Perma unstable.
318 (active, abi_unadjusted, "1.16.0", None),
321 (active, proc_macro, "1.16.0", Some(38356)),
323 // Allows attributes on struct literal fields.
324 (active, struct_field_attributes, "1.16.0", Some(38814)),
326 // Allows #[link(kind="static-nobundle"...]
327 (active, static_nobundle, "1.16.0", Some(37403)),
329 // `extern "msp430-interrupt" fn()`
330 (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
334 (removed, import_shadowing, "1.0.0", None),
335 (removed, managed_boxes, "1.0.0", None),
336 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
337 (removed, negate_unsigned, "1.0.0", Some(29645)),
338 (removed, reflect, "1.0.0", Some(27749)),
339 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
340 (removed, opt_out_copy, "1.0.0", None),
341 (removed, quad_precision_float, "1.0.0", None),
342 (removed, struct_inherit, "1.0.0", None),
343 (removed, test_removed_feature, "1.0.0", None),
344 (removed, visible_private_types, "1.0.0", None),
345 (removed, unsafe_no_drop_flag, "1.0.0", None),
346 // Allows using items which are missing stability attributes
348 (removed, unmarked_api, "1.0.0", None),
349 (removed, pushpop_unsafe, "1.2.0", None),
353 (accepted, associated_types, "1.0.0", None),
354 // allow overloading augmented assignment operations like `a += b`
355 (accepted, augmented_assignments, "1.8.0", Some(28235)),
356 // allow empty structs and enum variants with braces
357 (accepted, braced_empty_structs, "1.8.0", Some(29720)),
358 (accepted, default_type_params, "1.0.0", None),
359 (accepted, globs, "1.0.0", None),
360 (accepted, if_let, "1.0.0", None),
361 // A temporary feature gate used to enable parser extensions needed
362 // to bootstrap fix for #5723.
363 (accepted, issue_5723_bootstrap, "1.0.0", None),
364 (accepted, macro_rules, "1.0.0", None),
365 // Allows using #![no_std]
366 (accepted, no_std, "1.6.0", None),
367 (accepted, slicing_syntax, "1.0.0", None),
368 (accepted, struct_variant, "1.0.0", None),
369 // These are used to test this portion of the compiler, they don't actually
371 (accepted, test_accepted_feature, "1.0.0", None),
372 (accepted, tuple_indexing, "1.0.0", None),
373 // Allows macros to appear in the type position.
374 (accepted, type_macros, "1.13.0", Some(27245)),
375 (accepted, while_let, "1.0.0", None),
376 // Allows `#[deprecated]` attribute
377 (accepted, deprecated, "1.9.0", Some(29935)),
379 (accepted, question_mark, "1.13.0", Some(31436)),
380 // Allows `..` in tuple (struct) patterns
381 (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
382 (accepted, item_like_imports, "1.14.0", Some(35120)),
383 // Allows using `Self` and associated types in struct expressions and patterns.
384 (accepted, more_struct_aliases, "1.16.0", Some(37544)),
386 // (changing above list without updating src/doc/reference.md makes @cmr sad)
388 #[derive(PartialEq, Copy, Clone, Debug)]
389 pub enum AttributeType {
390 /// Normal, builtin attribute that is consumed
391 /// by the compiler before the unused_attribute check
394 /// Builtin attribute that may not be consumed by the compiler
395 /// before the unused_attribute check. These attributes
396 /// will be ignored by the unused_attribute lint
399 /// Builtin attribute that is only allowed at the crate level
403 pub enum AttributeGate {
404 /// Is gated by a given feature gate, reason
405 /// and function to check if enabled
406 Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
408 /// Ungated attribute, can be used on all release channels
413 fn is_deprecated(&self) -> bool {
415 Gated(Stability::Deprecated(_), ..) => true,
421 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
424 // Argument is tracking issue link.
425 Deprecated(&'static str),
429 impl ::std::fmt::Debug for AttributeGate {
430 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
432 Gated(ref stab, ref name, ref expl, _) =>
433 write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
434 Ungated => write!(fmt, "Ungated")
439 macro_rules! cfg_fn {
440 ($field: ident) => {{
441 fn f(features: &Features) -> bool {
444 f as fn(&Features) -> bool
448 pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
449 BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
452 pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
453 BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name))
456 // Attributes that have a special meaning to rustc or rustdoc
457 pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
460 ("warn", Normal, Ungated),
461 ("allow", Normal, Ungated),
462 ("forbid", Normal, Ungated),
463 ("deny", Normal, Ungated),
465 ("macro_reexport", Normal, Ungated),
466 ("macro_use", Normal, Ungated),
467 ("macro_export", Normal, Ungated),
468 ("plugin_registrar", Normal, Ungated),
470 ("cfg", Normal, Ungated),
471 ("cfg_attr", Normal, Ungated),
472 ("main", Normal, Ungated),
473 ("start", Normal, Ungated),
474 ("test", Normal, Ungated),
475 ("bench", Normal, Ungated),
476 ("simd", Normal, Ungated),
477 ("repr", Normal, Ungated),
478 ("path", Normal, Ungated),
479 ("abi", Normal, Ungated),
480 ("automatically_derived", Normal, Ungated),
481 ("no_mangle", Normal, Ungated),
482 ("no_link", Normal, Ungated),
483 ("derive", Normal, Ungated),
484 ("should_panic", Normal, Ungated),
485 ("ignore", Normal, Ungated),
486 ("no_implicit_prelude", Normal, Ungated),
487 ("reexport_test_harness_main", Normal, Ungated),
488 ("link_args", Normal, Ungated),
489 ("macro_escape", Normal, Ungated),
492 ("structural_match", Whitelisted, Gated(Stability::Unstable,
494 "the semantics of constant patterns is \
496 cfg_fn!(structural_match))),
498 // Not used any more, but we can't feature gate it
499 ("no_stack_check", Normal, Ungated),
501 ("plugin", CrateLevel, Gated(Stability::Unstable,
503 "compiler plugins are experimental \
507 ("no_std", CrateLevel, Ungated),
508 ("no_core", CrateLevel, Gated(Stability::Unstable,
510 "no_core is experimental",
512 ("lang", Normal, Gated(Stability::Unstable,
514 "language items are subject to change",
515 cfg_fn!(lang_items))),
516 ("linkage", Whitelisted, Gated(Stability::Unstable,
518 "the `linkage` attribute is experimental \
519 and not portable across platforms",
521 ("thread_local", Whitelisted, Gated(Stability::Unstable,
523 "`#[thread_local]` is an experimental feature, and does \
524 not currently handle destructors. There is no \
525 corresponding `#[task_local]` mapping to the task \
527 cfg_fn!(thread_local))),
529 ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
531 "the `#[rustc_on_unimplemented]` attribute \
532 is an experimental feature",
533 cfg_fn!(on_unimplemented))),
534 ("allocator", Whitelisted, Gated(Stability::Unstable,
536 "the `#[allocator]` attribute is an experimental feature",
537 cfg_fn!(allocator))),
538 ("needs_allocator", Normal, Gated(Stability::Unstable,
540 "the `#[needs_allocator]` \
541 attribute is an experimental \
543 cfg_fn!(needs_allocator))),
544 ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
546 "the `#[panic_runtime]` attribute is \
547 an experimental feature",
548 cfg_fn!(panic_runtime))),
549 ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
550 "needs_panic_runtime",
551 "the `#[needs_panic_runtime]` \
552 attribute is an experimental \
554 cfg_fn!(needs_panic_runtime))),
555 ("rustc_variance", Normal, Gated(Stability::Unstable,
557 "the `#[rustc_variance]` attribute \
558 is just used for rustc unit tests \
559 and will never be stable",
560 cfg_fn!(rustc_attrs))),
561 ("rustc_error", Whitelisted, Gated(Stability::Unstable,
563 "the `#[rustc_error]` attribute \
564 is just used for rustc unit tests \
565 and will never be stable",
566 cfg_fn!(rustc_attrs))),
567 ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
569 "the `#[rustc_if_this_changed]` attribute \
570 is just used for rustc unit tests \
571 and will never be stable",
572 cfg_fn!(rustc_attrs))),
573 ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
575 "the `#[rustc_if_this_changed]` attribute \
576 is just used for rustc unit tests \
577 and will never be stable",
578 cfg_fn!(rustc_attrs))),
579 ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
581 "the `#[rustc_dirty]` attribute \
582 is just used for rustc unit tests \
583 and will never be stable",
584 cfg_fn!(rustc_attrs))),
585 ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
587 "the `#[rustc_clean]` attribute \
588 is just used for rustc unit tests \
589 and will never be stable",
590 cfg_fn!(rustc_attrs))),
591 ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
593 "the `#[rustc_metadata_dirty]` attribute \
594 is just used for rustc unit tests \
595 and will never be stable",
596 cfg_fn!(rustc_attrs))),
597 ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
599 "the `#[rustc_metadata_clean]` attribute \
600 is just used for rustc unit tests \
601 and will never be stable",
602 cfg_fn!(rustc_attrs))),
603 ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
606 is just used for rustc unit tests \
607 and will never be stable",
608 cfg_fn!(rustc_attrs))),
609 ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
612 is just used for rustc unit tests \
613 and will never be stable",
614 cfg_fn!(rustc_attrs))),
615 ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
617 "internal rustc attributes will never be stable",
618 cfg_fn!(rustc_attrs))),
619 ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
621 "internal rustc attributes will never be stable",
622 cfg_fn!(rustc_attrs))),
623 ("rustc_move_fragments", Normal, Gated(Stability::Unstable,
625 "the `#[rustc_move_fragments]` attribute \
626 is just used for rustc unit tests \
627 and will never be stable",
628 cfg_fn!(rustc_attrs))),
629 ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
631 "the `#[rustc_mir]` attribute \
632 is just used for rustc unit tests \
633 and will never be stable",
634 cfg_fn!(rustc_attrs))),
635 ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
637 "the `#[rustc_inherit_overflow_checks]` \
638 attribute is just used to control \
639 overflow checking behavior of several \
640 libcore functions that are inlined \
641 across crates and will never be stable",
642 cfg_fn!(rustc_attrs))),
643 ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
645 "the `#[compiler_builtins]` attribute is used to \
646 identify the `compiler_builtins` crate which \
647 contains compiler-rt intrinsics and will never be \
649 cfg_fn!(compiler_builtins))),
651 ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
652 "allow_internal_unstable",
653 EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
654 cfg_fn!(allow_internal_unstable))),
656 ("fundamental", Whitelisted, Gated(Stability::Unstable,
658 "the `#[fundamental]` attribute \
659 is an experimental feature",
660 cfg_fn!(fundamental))),
662 ("proc_macro_derive", Normal, Ungated),
664 ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
666 "internal implementation detail",
667 cfg_fn!(rustc_attrs))),
669 // FIXME: #14408 whitelist docs since rustdoc looks at them
670 ("doc", Whitelisted, Ungated),
672 // FIXME: #14406 these are processed in trans, which happens after the
674 ("cold", Whitelisted, Ungated),
675 ("naked", Whitelisted, Gated(Stability::Unstable,
677 "the `#[naked]` attribute \
678 is an experimental feature",
679 cfg_fn!(naked_functions))),
680 ("target_feature", Whitelisted, Gated(
681 Stability::Unstable, "target_feature",
682 "the `#[target_feature]` attribute is an experimental feature",
683 cfg_fn!(target_feature))),
684 ("export_name", Whitelisted, Ungated),
685 ("inline", Whitelisted, Ungated),
686 ("link", Whitelisted, Ungated),
687 ("link_name", Whitelisted, Ungated),
688 ("link_section", Whitelisted, Ungated),
689 ("no_builtins", Whitelisted, Ungated),
690 ("no_mangle", Whitelisted, Ungated),
691 ("no_debug", Whitelisted, Gated(
692 Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
694 "the `#[no_debug]` attribute is an experimental feature",
696 ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
697 "omit_gdb_pretty_printer_section",
698 "the `#[omit_gdb_pretty_printer_section]` \
699 attribute is just used for the Rust test \
701 cfg_fn!(omit_gdb_pretty_printer_section))),
702 ("unsafe_destructor_blind_to_params",
704 Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761"),
705 "dropck_parametricity",
706 "unsafe_destructor_blind_to_params has been replaced by \
707 may_dangle and will be removed in the future",
708 cfg_fn!(dropck_parametricity))),
711 Gated(Stability::Unstable,
713 "may_dangle has unstable semantics and may be removed in the future",
714 cfg_fn!(dropck_eyepatch))),
715 ("unwind", Whitelisted, Gated(Stability::Unstable,
717 "#[unwind] is experimental",
718 cfg_fn!(unwind_attributes))),
721 ("prelude_import", Whitelisted, Gated(Stability::Unstable,
723 "`#[prelude_import]` is for use by rustc only",
724 cfg_fn!(prelude_import))),
726 // FIXME: #14407 these are only looked at on-demand so we can't
727 // guarantee they'll have already been checked
728 ("rustc_deprecated", Whitelisted, Ungated),
729 ("must_use", Whitelisted, Ungated),
730 ("stable", Whitelisted, Ungated),
731 ("unstable", Whitelisted, Ungated),
732 ("deprecated", Normal, Ungated),
734 ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
736 "unboxed_closures are still evolving",
737 cfg_fn!(unboxed_closures))),
739 ("windows_subsystem", Whitelisted, Gated(Stability::Unstable,
741 "the windows subsystem attribute \
742 is currently unstable",
743 cfg_fn!(windows_subsystem))),
745 ("proc_macro_attribute", Normal, Gated(Stability::Unstable,
747 "attribute proc macros are currently unstable",
748 cfg_fn!(proc_macro))),
750 ("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
751 "rustc_derive_registrar",
752 "used internally by rustc",
753 cfg_fn!(rustc_attrs))),
755 // Crate level attributes
756 ("crate_name", CrateLevel, Ungated),
757 ("crate_type", CrateLevel, Ungated),
758 ("crate_id", CrateLevel, Ungated),
759 ("feature", CrateLevel, Ungated),
760 ("no_start", CrateLevel, Ungated),
761 ("no_main", CrateLevel, Ungated),
762 ("no_builtins", CrateLevel, Ungated),
763 ("recursion_limit", CrateLevel, Ungated),
764 ("type_length_limit", CrateLevel, Ungated),
767 // cfg(...)'s that are feature gated
768 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
769 // (name in cfg, feature, function to check if the feature is enabled)
770 ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
771 ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
772 ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
773 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
776 #[derive(Debug, Eq, PartialEq)]
777 pub struct GatedCfg {
783 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
784 let name = &*cfg.name().as_str();
786 .position(|info| info.0 == name)
795 pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
796 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
797 if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
798 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
799 emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
805 features: &'a Features,
806 parse_sess: &'a ParseSess,
808 plugin_attributes: &'a [(String, AttributeType)],
811 macro_rules! gate_feature_fn {
812 ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
813 let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
814 let has_feature: bool = has_feature(&$cx.features);
815 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
816 if !has_feature && !cx.cm.span_allows_unstable(span) {
817 emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
822 macro_rules! gate_feature {
823 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
824 gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
828 impl<'a> Context<'a> {
829 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
830 debug!("check_attribute(attr = {:?})", attr);
831 let name = &*attr.name().as_str();
832 for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
834 if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
835 gate_feature_fn!(self, has_feature, attr.span, name, desc);
837 debug!("check_attribute: {:?} is builtin, {:?}, {:?}", name, ty, gateage);
841 for &(ref n, ref ty) in self.plugin_attributes {
843 // Plugins can't gate attributes, so we don't check for it
844 // unlike the code above; we only use this loop to
845 // short-circuit to avoid the checks below
846 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
850 if name.starts_with("rustc_") {
851 gate_feature!(self, rustc_attrs, attr.span,
852 "unless otherwise specified, attributes \
853 with the prefix `rustc_` \
854 are reserved for internal compiler diagnostics");
855 } else if name.starts_with("derive_") {
856 gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
857 } else if attr::is_known(attr) {
858 debug!("check_attribute: {:?} is known", name);
860 // Only run the custom attribute lint during regular
861 // feature gate checking. Macro gating runs
862 // before the plugin attributes are registered
863 // so we skip this then
865 gate_feature!(self, custom_attribute, attr.span,
866 &format!("The attribute `{}` is currently \
867 unknown to the compiler and \
869 added to it in the future",
876 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
877 cm: &CodeMap, features: &Features) {
879 features: features, parse_sess: parse_sess,
880 cm: cm, plugin_attributes: &[]
882 cx.check_attribute(attr, true);
885 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
886 ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
889 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
890 if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
892 // FIXME (#28244): enforce that active features have issue numbers
893 // assert!(issue.is_some())
896 // search in Accepted or Removed features
897 match ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).find(|t| t.0 == feature) {
898 Some(&(_, _, issue)) => issue,
899 None => panic!("Feature `{}` is not declared anywhere", feature),
909 pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
911 feature_err(sess, feature, span, issue, explain).emit();
914 pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
915 explain: &str) -> DiagnosticBuilder<'a> {
916 let diag = &sess.span_diagnostic;
918 let issue = match issue {
919 GateIssue::Language => find_lang_feature_issue(feature),
920 GateIssue::Library(lib) => lib,
923 let mut err = if let Some(n) = issue {
924 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
926 diag.struct_span_err(span, explain)
929 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
930 if sess.unstable_features.is_nightly_build() {
931 err.help(&format!("add #![feature({})] to the \
932 crate attributes to enable",
939 const EXPLAIN_BOX_SYNTAX: &'static str =
940 "box expression syntax is experimental; you can call `Box::new` instead.";
942 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
943 "attributes on non-item statements and expressions are experimental.";
945 pub const EXPLAIN_ASM: &'static str =
946 "inline assembly is not stable enough for use and is subject to change";
948 pub const EXPLAIN_LOG_SYNTAX: &'static str =
949 "`log_syntax!` is not stable enough for use and is subject to change";
951 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
952 "`concat_idents` is not stable enough for use and is subject to change";
954 pub const EXPLAIN_TRACE_MACROS: &'static str =
955 "`trace_macros` is not stable enough for use and is subject to change";
956 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
957 "allow_internal_unstable side-steps feature gating and stability checks";
959 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
960 "`#[derive]` for custom traits is not stable enough for use. It is deprecated and will \
961 be removed in v1.15";
963 pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
964 "`#[derive]` for custom traits is deprecated and will be removed in v1.15. Prefer using \
965 procedural macro custom derive";
967 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
968 "attributes of the form `#[derive_*]` are reserved for the compiler";
970 pub const EXPLAIN_PLACEMENT_IN: &'static str =
971 "placement-in expression syntax is experimental and subject to change.";
973 struct PostExpansionVisitor<'a> {
974 context: &'a Context<'a>,
977 macro_rules! gate_feature_post {
978 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
979 let (cx, span) = ($cx, $span);
980 if !cx.context.cm.span_allows_unstable(span) {
981 gate_feature!(cx.context, $feature, span, $explain)
986 impl<'a> PostExpansionVisitor<'a> {
987 fn check_abi(&self, abi: Abi, span: Span) {
989 Abi::RustIntrinsic => {
990 gate_feature_post!(&self, intrinsics, span,
991 "intrinsics are subject to change");
993 Abi::PlatformIntrinsic => {
994 gate_feature_post!(&self, platform_intrinsics, span,
995 "platform intrinsics are experimental and possibly buggy");
998 gate_feature_post!(&self, abi_vectorcall, span,
999 "vectorcall is experimental and subject to change");
1002 gate_feature_post!(&self, unboxed_closures, span,
1003 "rust-call ABI is subject to change");
1006 gate_feature_post!(&self, abi_sysv64, span,
1007 "sysv64 ABI is experimental and subject to change");
1010 gate_feature_post!(&self, abi_ptx, span,
1011 "PTX ABIs are experimental and subject to change");
1013 Abi::Unadjusted => {
1014 gate_feature_post!(&self, abi_unadjusted, span,
1015 "unadjusted ABI is an implementation detail and perma-unstable");
1017 Abi::Msp430Interrupt => {
1018 gate_feature_post!(&self, abi_msp430_interrupt, span,
1019 "msp430-interrupt ABI is experimental and subject to change");
1034 fn contains_novel_literal(item: &ast::MetaItem) -> bool {
1035 use ast::MetaItemKind::*;
1036 use ast::NestedMetaItemKind::*;
1040 NameValue(ref lit) => !lit.node.is_str(),
1041 List(ref list) => list.iter().any(|li| {
1043 MetaItem(ref mi) => contains_novel_literal(&mi),
1050 fn starts_with_digit(s: &str) -> bool {
1051 s.as_bytes().first().cloned().map_or(false, |b| b >= b'0' && b <= b'9')
1054 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1055 fn visit_attribute(&mut self, attr: &ast::Attribute) {
1056 if !self.context.cm.span_allows_unstable(attr.span) {
1057 // check for gated attributes
1058 self.context.check_attribute(attr, false);
1061 if contains_novel_literal(&attr.value) {
1062 gate_feature_post!(&self, attr_literals, attr.span,
1063 "non-string literals in attributes, or string \
1064 literals in top-level positions, are experimental");
1068 fn visit_name(&mut self, sp: Span, name: ast::Name) {
1069 if !name.as_str().is_ascii() {
1070 gate_feature_post!(&self, non_ascii_idents, sp,
1071 "non-ascii idents are not fully supported.");
1075 fn visit_item(&mut self, i: &'a ast::Item) {
1077 ast::ItemKind::ExternCrate(_) => {
1078 if attr::contains_name(&i.attrs[..], "macro_reexport") {
1079 gate_feature_post!(&self, macro_reexport, i.span,
1080 "macros reexports are experimental \
1081 and possibly buggy");
1085 ast::ItemKind::ForeignMod(ref foreign_module) => {
1086 if attr::contains_name(&i.attrs[..], "link_args") {
1087 gate_feature_post!(&self, link_args, i.span,
1088 "the `link_args` attribute is not portable \
1089 across platforms, it is recommended to \
1090 use `#[link(name = \"foo\")]` instead")
1092 self.check_abi(foreign_module.abi, i.span);
1095 ast::ItemKind::Fn(..) => {
1096 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1097 gate_feature_post!(&self, plugin_registrar, i.span,
1098 "compiler plugins are experimental and possibly buggy");
1100 if attr::contains_name(&i.attrs[..], "start") {
1101 gate_feature_post!(&self, start, i.span,
1102 "a #[start] function is an experimental \
1103 feature whose signature may change \
1106 if attr::contains_name(&i.attrs[..], "main") {
1107 gate_feature_post!(&self, main, i.span,
1108 "declaration of a nonstandard #[main] \
1109 function may change over time, for now \
1110 a top-level `fn main()` is required");
1114 ast::ItemKind::Struct(..) => {
1115 if attr::contains_name(&i.attrs[..], "simd") {
1116 gate_feature_post!(&self, simd, i.span,
1117 "SIMD types are experimental and possibly buggy");
1118 self.context.parse_sess.span_diagnostic.span_warn(i.span,
1119 "the `#[simd]` attribute \
1120 is deprecated, use \
1121 `#[repr(simd)]` instead");
1123 for attr in &i.attrs {
1124 if attr.name() == "repr" {
1125 for item in attr.meta_item_list().unwrap_or(&[]) {
1126 if item.check_name("simd") {
1127 gate_feature_post!(&self, repr_simd, i.span,
1128 "SIMD types are experimental \
1129 and possibly buggy");
1137 ast::ItemKind::Union(..) => {
1138 gate_feature_post!(&self, untagged_unions,
1140 "unions are unstable and possibly buggy");
1143 ast::ItemKind::DefaultImpl(..) => {
1144 gate_feature_post!(&self, optin_builtin_traits,
1146 "default trait implementations are experimental \
1147 and possibly buggy");
1150 ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
1152 ast::ImplPolarity::Negative => {
1153 gate_feature_post!(&self, optin_builtin_traits,
1155 "negative trait bounds are not yet fully implemented; \
1156 use marker types for now");
1165 visit::walk_item(self, i);
1168 fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
1169 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
1170 Some(val) => val.as_str().starts_with("llvm."),
1174 gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1175 "linking to LLVM intrinsics is experimental");
1178 visit::walk_foreign_item(self, i)
1181 fn visit_ty(&mut self, ty: &'a ast::Ty) {
1183 ast::TyKind::BareFn(ref bare_fn_ty) => {
1184 self.check_abi(bare_fn_ty.abi, ty.span);
1186 ast::TyKind::ImplTrait(..) => {
1187 gate_feature_post!(&self, conservative_impl_trait, ty.span,
1188 "`impl Trait` is experimental");
1190 ast::TyKind::Never => {
1191 gate_feature_post!(&self, never_type, ty.span,
1192 "The `!` type is experimental");
1196 visit::walk_ty(self, ty)
1199 fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
1200 if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
1201 match output_ty.node {
1202 ast::TyKind::Never => return,
1205 self.visit_ty(output_ty)
1209 fn visit_expr(&mut self, e: &'a ast::Expr) {
1211 ast::ExprKind::Box(_) => {
1212 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1214 ast::ExprKind::Type(..) => {
1215 gate_feature_post!(&self, type_ascription, e.span,
1216 "type ascription is experimental");
1218 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1219 gate_feature_post!(&self, inclusive_range_syntax,
1221 "inclusive range syntax is experimental");
1223 ast::ExprKind::InPlace(..) => {
1224 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1226 ast::ExprKind::Struct(_, ref fields, _) => {
1227 for field in fields {
1228 if field.is_shorthand {
1229 gate_feature_post!(&self, field_init_shorthand, field.span,
1230 "struct field shorthands are unstable");
1232 if starts_with_digit(&field.ident.node.name.as_str()) {
1233 gate_feature_post!(&self, relaxed_adts,
1235 "numeric fields in struct expressions are unstable");
1239 ast::ExprKind::Break(_, Some(_)) => {
1240 gate_feature_post!(&self, loop_break_value, e.span,
1241 "`break` with a value is experimental");
1243 ast::ExprKind::Lit(ref lit) => {
1244 if let ast::LitKind::Int(_, ref ty) = lit.node {
1246 ast::LitIntType::Signed(ast::IntTy::I128) |
1247 ast::LitIntType::Unsigned(ast::UintTy::U128) => {
1248 gate_feature_post!(&self, i128_type, e.span,
1249 "128-bit integers are not stable");
1257 visit::walk_expr(self, e);
1260 fn visit_pat(&mut self, pattern: &'a ast::Pat) {
1261 match pattern.node {
1262 PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
1263 gate_feature_post!(&self, advanced_slice_patterns,
1265 "multiple-element slice matches anywhere \
1266 but at the end of a slice (e.g. \
1267 `[0, ..xs, 0]`) are experimental")
1269 PatKind::Slice(..) => {
1270 gate_feature_post!(&self, slice_patterns,
1272 "slice pattern syntax is experimental");
1274 PatKind::Box(..) => {
1275 gate_feature_post!(&self, box_patterns,
1277 "box pattern syntax is experimental");
1279 PatKind::Struct(_, ref fields, _) => {
1280 for field in fields {
1281 if starts_with_digit(&field.node.ident.name.as_str()) {
1282 gate_feature_post!(&self, relaxed_adts,
1284 "numeric fields in struct patterns are unstable");
1288 PatKind::Range(_, _, RangeEnd::Excluded) => {
1289 gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
1290 "exclusive range pattern syntax is experimental");
1294 visit::walk_pat(self, pattern)
1297 fn visit_fn(&mut self,
1298 fn_kind: FnKind<'a>,
1299 fn_decl: &'a ast::FnDecl,
1302 // check for const fn declarations
1304 FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => {
1305 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1308 // stability of const fn methods are covered in
1309 // visit_trait_item and visit_impl_item below; this is
1310 // because default methods don't pass through this
1316 FnKind::ItemFn(_, _, _, _, abi, _, _) |
1317 FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
1318 self.check_abi(abi, span);
1322 visit::walk_fn(self, fn_kind, fn_decl, span);
1325 fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1327 ast::TraitItemKind::Const(..) => {
1328 gate_feature_post!(&self, associated_consts,
1330 "associated constants are experimental")
1332 ast::TraitItemKind::Method(ref sig, ref block) => {
1333 if block.is_none() {
1334 self.check_abi(sig.abi, ti.span);
1336 if sig.constness.node == ast::Constness::Const {
1337 gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1340 ast::TraitItemKind::Type(_, Some(_)) => {
1341 gate_feature_post!(&self, associated_type_defaults, ti.span,
1342 "associated type defaults are unstable");
1346 visit::walk_trait_item(self, ti);
1349 fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
1350 if ii.defaultness == ast::Defaultness::Default {
1351 gate_feature_post!(&self, specialization,
1353 "specialization is unstable");
1357 ast::ImplItemKind::Const(..) => {
1358 gate_feature_post!(&self, associated_consts,
1360 "associated constants are experimental")
1362 ast::ImplItemKind::Method(ref sig, _) => {
1363 if sig.constness.node == ast::Constness::Const {
1364 gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1369 visit::walk_impl_item(self, ii);
1372 fn visit_vis(&mut self, vis: &'a ast::Visibility) {
1373 let span = match *vis {
1374 ast::Visibility::Crate(span) => span,
1375 ast::Visibility::Restricted { ref path, .. } => path.span,
1378 gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental");
1380 visit::walk_vis(self, vis)
1383 fn visit_generics(&mut self, g: &'a ast::Generics) {
1384 for t in &g.ty_params {
1385 if !t.attrs.is_empty() {
1386 gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
1387 "attributes on type parameter bindings are experimental");
1390 visit::walk_generics(self, g)
1393 fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) {
1394 if !lifetime_def.attrs.is_empty() {
1395 gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
1396 "attributes on lifetime bindings are experimental");
1398 visit::walk_lifetime_def(self, lifetime_def)
1402 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1403 let mut features = Features::new();
1405 let mut feature_checker = MutexFeatureChecker::default();
1407 for attr in krate_attrs {
1408 if !attr.check_name("feature") {
1412 match attr.meta_item_list() {
1414 span_err!(span_handler, attr.span, E0555,
1415 "malformed feature attribute, expected #![feature(...)]");
1419 let name = if let Some(word) = mi.word() {
1422 span_err!(span_handler, mi.span, E0556,
1423 "malformed feature, expected just one word");
1427 if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1428 .find(|& &(n, _, _, _)| name == n) {
1429 *(setter(&mut features)) = true;
1430 feature_checker.collect(&features, mi.span);
1432 else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1433 .find(|& &(n, _, _)| name == n) {
1434 span_err!(span_handler, mi.span, E0557, "feature has been removed");
1436 else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1437 .find(|& &(n, _, _)| name == n) {
1438 features.declared_stable_lang_features.push((name, mi.span));
1440 features.declared_lib_features.push((name, mi.span));
1447 feature_checker.check(span_handler);
1452 // A collector for mutually-exclusive features and their flag spans
1454 struct MutexFeatureChecker {
1455 proc_macro: Option<Span>,
1456 custom_attribute: Option<Span>,
1459 impl MutexFeatureChecker {
1460 // If this method turns out to be a hotspot due to branching,
1461 // the branching can be eliminated by modifying `setter!()` to set these spans
1462 // only for the features that need to be checked for mutual exclusion.
1463 fn collect(&mut self, features: &Features, span: Span) {
1464 if features.proc_macro {
1465 // If self.proc_macro is None, set to Some(span)
1466 self.proc_macro = self.proc_macro.or(Some(span));
1469 if features.custom_attribute {
1470 self.custom_attribute = self.custom_attribute.or(Some(span));
1474 fn check(self, handler: &Handler) {
1475 if let (Some(pm_span), Some(ca_span)) = (self.proc_macro, self.custom_attribute) {
1476 handler.struct_span_err(pm_span, "Cannot use `#![feature(proc_macro)]` and \
1477 `#![feature(custom_attribute)] at the same time")
1478 .span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
1486 pub fn check_crate(krate: &ast::Crate,
1488 features: &Features,
1489 plugin_attributes: &[(String, AttributeType)],
1490 unstable: UnstableFeatures) {
1491 maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1496 plugin_attributes: plugin_attributes,
1498 visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1501 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1502 pub enum UnstableFeatures {
1503 /// Hard errors for unstable features are active, as on
1504 /// beta/stable channels.
1506 /// Allow features to be activated, as on nightly.
1508 /// Errors are bypassed for bootstrapping. This is required any time
1509 /// during the build that feature-related lints are set to warn or above
1510 /// because the build turns on warnings-as-errors and uses lots of unstable
1511 /// features. As a result, this is always required for building Rust itself.
1515 impl UnstableFeatures {
1516 pub fn from_environment() -> UnstableFeatures {
1517 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1518 let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1519 // Whether we should enable unstable features for bootstrapping
1520 let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
1521 match (disable_unstable_features, bootstrap) {
1522 (_, true) => UnstableFeatures::Cheat,
1523 (true, _) => UnstableFeatures::Disallow,
1524 (false, _) => UnstableFeatures::Allow
1528 pub fn is_nightly_build(&self) -> bool {
1530 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1536 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1537 unstable: UnstableFeatures) {
1538 let allow_features = match unstable {
1539 UnstableFeatures::Allow => true,
1540 UnstableFeatures::Disallow => false,
1541 UnstableFeatures::Cheat => true
1543 if !allow_features {
1544 for attr in &krate.attrs {
1545 if attr.check_name("feature") {
1546 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1547 span_err!(span_handler, attr.span, E0554,
1548 "#[feature] may not be used on the {} release channel",