]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/feature_gate.rs
97eec3a21e9d16629d8cb28890761e2fa4da68bc
[rust.git] / src / libsyntax / feature_gate.rs
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.
4 //
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.
10
11 //! Feature gating
12 //!
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
16 //! enabled.
17 //!
18 //! Features are enabled in programs via the crate-level attributes of
19 //! `#![feature(...)]` with a comma-separated list of features.
20 //!
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
23 //! becomes stable.
24
25 use self::AttributeType::*;
26 use self::AttributeGate::*;
27
28 use abi::Abi;
29 use ast::{self, NodeId, PatKind, RangeEnd, RangeSyntax};
30 use attr;
31 use codemap::Spanned;
32 use syntax_pos::Span;
33 use errors::{DiagnosticBuilder, Handler, FatalError};
34 use visit::{self, FnKind, Visitor};
35 use parse::ParseSess;
36 use symbol::Symbol;
37
38 use std::env;
39
40 macro_rules! set {
41     (proc_macro) => {{
42         fn f(features: &mut Features, span: Span) {
43             features.declared_lib_features.push((Symbol::intern("proc_macro"), span));
44             features.proc_macro = true;
45         }
46         f as fn(&mut Features, Span)
47     }};
48     ($field: ident) => {{
49         fn f(features: &mut Features, _: Span) {
50             features.$field = true;
51         }
52         f as fn(&mut Features, Span)
53     }}
54 }
55
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))),+];
63
64         /// A set of features to be used by later passes.
65         pub struct Features {
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),+
71         }
72
73         impl Features {
74             pub fn new() -> Features {
75                 Features {
76                     declared_stable_lang_features: Vec::new(),
77                     declared_lib_features: Vec::new(),
78                     $($feature: false),+
79                 }
80             }
81         }
82     };
83
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)),+
88         ];
89     };
90
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)),+
95         ];
96     };
97
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)),+
102         ];
103     }
104 }
105
106 // If you change this, please modify src/doc/unstable-book as well.
107 //
108 // Don't ever remove anything from this list; set them to 'Removed'.
109 //
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
112 // stable (active).
113 //
114 // NB: tools/tidy/src/features.rs parses this information directly out of the
115 // source, so take care when modifying it.
116
117 declare_features! (
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)),
126
127     // rustc internal, for now:
128     (active, intrinsics, "1.0.0", None),
129     (active, lang_items, "1.0.0", None),
130
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)),
135
136
137     // rustc internal
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)),
144
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)),
155
156     // OIBIT specific features
157     (active, optin_builtin_traits, "1.0.0", Some(13231)),
158
159     // macro reexport needs more discussion and stabilization
160     (active, macro_reexport, "1.0.0", Some(29638)),
161
162     // Allows use of #[staged_api]
163     // rustc internal
164     (active, staged_api, "1.0.0", None),
165
166     // Allows using #![no_core]
167     (active, no_core, "1.3.0", Some(29639)),
168
169     // Allows using `box` in patterns; RFC 469
170     (active, box_patterns, "1.0.0", Some(29641)),
171
172     // Allows using the unsafe_destructor_blind_to_params attribute;
173     // RFC 1238
174     (active, dropck_parametricity, "1.3.0", Some(28498)),
175
176     // Allows using the may_dangle attribute; RFC 1327
177     (active, dropck_eyepatch, "1.10.0", Some(34761)),
178
179     // Allows the use of custom attributes; RFC 572
180     (active, custom_attribute, "1.0.0", Some(29642)),
181
182     // Allows the use of #[derive(Anything)] as sugar for
183     // #[derive_Anything].
184     (active, custom_derive, "1.0.0", Some(29644)),
185
186     // Allows the use of rustc_* attributes; RFC 572
187     (active, rustc_attrs, "1.0.0", Some(29642)),
188
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).
193     //
194     // rustc internal
195     (active, allow_internal_unstable, "1.0.0", None),
196
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).
201     //
202     // rustc internal
203     (active, allow_internal_unsafe, "1.0.0", None),
204
205     // #23121. Array patterns have some hazards yet.
206     (active, slice_patterns, "1.0.0", Some(23121)),
207
208     // Allows the definition of `const fn` functions.
209     (active, const_fn, "1.2.0", Some(24111)),
210
211     // Allows indexing into constant arrays.
212     (active, const_indexing, "1.4.0", Some(29947)),
213
214     // Allows using #[prelude_import] on glob `use` items.
215     //
216     // rustc internal
217     (active, prelude_import, "1.2.0", None),
218
219     // Allows default type parameters to influence type inference.
220     (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
221
222     // Allows associated type defaults
223     (active, associated_type_defaults, "1.2.0", Some(29661)),
224
225     // allow `repr(simd)`, and importing the various simd intrinsics
226     (active, repr_simd, "1.4.0", Some(27731)),
227
228     // Allows cfg(target_feature = "...").
229     (active, cfg_target_feature, "1.4.0", Some(29717)),
230
231     // allow `extern "platform-intrinsic" { ... }`
232     (active, platform_intrinsics, "1.4.0", Some(27731)),
233
234     // allow `#[unwind]`
235     // rust runtime internal
236     (active, unwind_attributes, "1.4.0", None),
237
238     // allow the use of `#[naked]` on functions.
239     (active, naked_functions, "1.9.0", Some(32408)),
240
241     // allow `#[no_debug]`
242     (active, no_debug, "1.5.0", Some(29721)),
243
244     // allow `#[omit_gdb_pretty_printer_section]`
245     // rustc internal.
246     (active, omit_gdb_pretty_printer_section, "1.5.0", None),
247
248     // Allows cfg(target_vendor = "...").
249     (active, cfg_target_vendor, "1.5.0", Some(29718)),
250
251     // Allow attributes on expressions and non-item statements
252     (active, stmt_expr_attributes, "1.6.0", Some(15701)),
253
254     // allow using type ascription in expressions
255     (active, type_ascription, "1.6.0", Some(23416)),
256
257     // Allows cfg(target_thread_local)
258     (active, cfg_target_thread_local, "1.7.0", Some(29594)),
259
260     // rustc internal
261     (active, abi_vectorcall, "1.7.0", None),
262
263     // a..=b and ..=b
264     (active, inclusive_range_syntax, "1.7.0", Some(28237)),
265
266     // X..Y patterns
267     (active, exclusive_range_pattern, "1.11.0", Some(37854)),
268
269     // impl specialization (RFC 1210)
270     (active, specialization, "1.7.0", Some(31844)),
271
272     // Allows cfg(target_has_atomic = "...").
273     (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
274
275     // Allows `impl Trait` in function return types.
276     (active, conservative_impl_trait, "1.12.0", Some(34511)),
277
278     // Allows `impl Trait` in function arguments.
279     (active, universal_impl_trait, "1.23.0", Some(34511)),
280
281     // The `!` type
282     (active, never_type, "1.13.0", Some(35121)),
283
284     // Allows all literals in attribute lists and values of key-value pairs.
285     (active, attr_literals, "1.13.0", Some(34981)),
286
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)),
290
291     // Allows untagged unions `union U { ... }`
292     (active, untagged_unions, "1.13.0", Some(32836)),
293
294     // Used to identify the `compiler_builtins` crate
295     // rustc internal
296     (active, compiler_builtins, "1.13.0", None),
297
298     // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
299     (active, generic_param_attrs, "1.11.0", Some(34761)),
300
301     // Allows #[link(..., cfg(..))]
302     (active, link_cfg, "1.14.0", Some(37406)),
303
304     (active, use_extern_macros, "1.15.0", Some(35896)),
305
306     // Allows #[target_feature(...)]
307     (active, target_feature, "1.15.0", None),
308
309     // `extern "ptx-*" fn()`
310     (active, abi_ptx, "1.15.0", None),
311
312     // The `i128` type
313     (active, i128_type, "1.16.0", Some(35118)),
314
315     // The `repr(i128)` annotation for enums
316     (active, repr128, "1.16.0", Some(35118)),
317
318     // The `unadjusted` ABI. Perma unstable.
319     (active, abi_unadjusted, "1.16.0", None),
320
321     // Procedural macros 2.0.
322     (active, proc_macro, "1.16.0", Some(38356)),
323
324     // Declarative macros 2.0 (`macro`).
325     (active, decl_macro, "1.17.0", Some(39412)),
326
327     // Allows #[link(kind="static-nobundle"...]
328     (active, static_nobundle, "1.16.0", Some(37403)),
329
330     // `extern "msp430-interrupt" fn()`
331     (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
332
333     // Used to identify crates that contain sanitizer runtimes
334     // rustc internal
335     (active, sanitizer_runtime, "1.17.0", None),
336
337     // Used to identify crates that contain the profiler runtime
338     // rustc internal
339     (active, profiler_runtime, "1.18.0", None),
340
341     // `extern "x86-interrupt" fn()`
342     (active, abi_x86_interrupt, "1.17.0", Some(40180)),
343
344
345     // Allows the `catch {...}` expression
346     (active, catch_expr, "1.17.0", Some(31436)),
347
348     // Allows `repr(align(u16))` struct attribute (RFC 1358)
349     (active, repr_align, "1.17.0", Some(33626)),
350
351     // Used to preserve symbols (see llvm.used)
352     (active, used, "1.18.0", Some(40289)),
353
354     // Allows module-level inline assembly by way of global_asm!()
355     (active, global_asm, "1.18.0", Some(35119)),
356
357     // Allows overlapping impls of marker traits
358     (active, overlapping_marker_traits, "1.18.0", Some(29864)),
359
360     // Allows use of the :vis macro fragment specifier
361     (active, macro_vis_matcher, "1.18.0", Some(41022)),
362
363     // rustc internal
364     (active, abi_thiscall, "1.19.0", None),
365
366     // Allows a test to fail without failing the whole suite
367     (active, allow_fail, "1.19.0", Some(42219)),
368
369     // Allows unsized tuple coercion.
370     (active, unsized_tuple_coercion, "1.20.0", Some(42877)),
371
372     // Generators
373     (active, generators, "1.21.0", None),
374
375
376     // global allocators and their internals
377     (active, global_allocator, "1.20.0", None),
378     (active, allocator_internals, "1.20.0", None),
379
380     // #[doc(cfg(...))]
381     (active, doc_cfg, "1.21.0", Some(43781)),
382     // #[doc(masked)]
383     (active, doc_masked, "1.21.0", Some(44027)),
384
385     // allow `#[must_use]` on functions and comparison operators (RFC 1940)
386     (active, fn_must_use, "1.21.0", Some(43302)),
387
388     // allow '|' at beginning of match arms (RFC 1925)
389     (active, match_beginning_vert, "1.21.0", Some(44101)),
390
391     // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008)
392     (active, non_exhaustive, "1.22.0", Some(44109)),
393
394     // Copy/Clone closures (RFC 2132)
395     (active, clone_closures, "1.22.0", Some(44490)),
396     (active, copy_closures, "1.22.0", Some(44490)),
397
398     // allow `'_` placeholder lifetimes
399     (active, underscore_lifetimes, "1.22.0", Some(44524)),
400
401     // allow `..=` in patterns (RFC 1192)
402     (active, dotdoteq_in_patterns, "1.22.0", Some(28237)),
403
404     // Default match binding modes (RFC 2005)
405     (active, match_default_bindings, "1.22.0", Some(42640)),
406
407     // Trait object syntax with `dyn` prefix
408     (active, dyn_trait, "1.22.0", Some(44662)),
409
410     // `crate` as visibility modifier, synonymous to `pub(crate)`
411     (active, crate_visibility_modifier, "1.23.0", Some(45388)),
412
413     // extern types
414     (active, extern_types, "1.23.0", Some(43467)),
415
416     // Allow trait methods with arbitrary self types
417     (active, arbitrary_self_types, "1.23.0", Some(44874)),
418 );
419
420 declare_features! (
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
434     // rustc internal
435     (removed, unmarked_api, "1.0.0", None),
436     (removed, pushpop_unsafe, "1.2.0", None),
437     (removed, allocator, "1.0.0", None),
438 );
439
440 declare_features! (
441     (stable_removed, no_stack_check, "1.0.0", None),
442 );
443
444 declare_features! (
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
462     // mean anything
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)),
470     // `expr?`
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`
496     // blocks.
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)),
504 );
505
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.
509
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
514     Normal,
515
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
519     Whitelisted,
520
521     /// Builtin attribute that is only allowed at the crate level
522     CrateLevel,
523 }
524
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),
529
530     /// Ungated attribute, can be used on all release channels
531     Ungated,
532 }
533
534 impl AttributeGate {
535     fn is_deprecated(&self) -> bool {
536         match *self {
537             Gated(Stability::Deprecated(_), ..) => true,
538             _ => false,
539         }
540     }
541 }
542
543 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
544 pub enum Stability {
545     Unstable,
546     // Argument is tracking issue link.
547     Deprecated(&'static str),
548 }
549
550 // fn() is not Debug
551 impl ::std::fmt::Debug for AttributeGate {
552     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
553         match *self {
554             Gated(ref stab, name, expl, _) =>
555                 write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
556             Ungated => write!(fmt, "Ungated")
557         }
558     }
559 }
560
561 macro_rules! cfg_fn {
562     ($field: ident) => {{
563         fn f(features: &Features) -> bool {
564             features.$field
565         }
566         f as fn(&Features) -> bool
567     }}
568 }
569
570 pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
571     BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
572 }
573
574 pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
575     BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name))
576 }
577
578 // Attributes that have a special meaning to rustc or rustdoc
579 pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
580     // Normal attributes
581
582     ("warn", Normal, Ungated),
583     ("allow", Normal, Ungated),
584     ("forbid", Normal, Ungated),
585     ("deny", Normal, Ungated),
586
587     ("macro_reexport", Normal, Ungated),
588     ("macro_use", Normal, Ungated),
589     ("macro_export", Normal, Ungated),
590     ("plugin_registrar", Normal, Ungated),
591
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,
611                                 "link_args",
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),
617
618     // RFC #1445.
619     ("structural_match", Whitelisted, Gated(Stability::Unstable,
620                                             "structural_match",
621                                             "the semantics of constant patterns is \
622                                              not yet settled",
623                                             cfg_fn!(structural_match))),
624
625     // RFC #2008
626     ("non_exhaustive", Whitelisted, Gated(Stability::Unstable,
627                                           "non_exhaustive",
628                                           "non exhaustive is an experimental feature",
629                                           cfg_fn!(non_exhaustive))),
630
631     ("plugin", CrateLevel, Gated(Stability::Unstable,
632                                  "plugin",
633                                  "compiler plugins are experimental \
634                                   and possibly buggy",
635                                  cfg_fn!(plugin))),
636
637     ("no_std", CrateLevel, Ungated),
638     ("no_core", CrateLevel, Gated(Stability::Unstable,
639                                   "no_core",
640                                   "no_core is experimental",
641                                   cfg_fn!(no_core))),
642     ("lang", Normal, Gated(Stability::Unstable,
643                            "lang_items",
644                            "language items are subject to change",
645                            cfg_fn!(lang_items))),
646     ("linkage", Whitelisted, Gated(Stability::Unstable,
647                                    "linkage",
648                                    "the `linkage` attribute is experimental \
649                                     and not portable across platforms",
650                                    cfg_fn!(linkage))),
651     ("thread_local", Whitelisted, Gated(Stability::Unstable,
652                                         "thread_local",
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 \
656                                          model",
657                                         cfg_fn!(thread_local))),
658
659     ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
660                                              "on_unimplemented",
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,
670                                        "global_allocator",
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 \
683                                        feature",
684                                       cfg_fn!(allocator_internals))),
685     ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
686                                          "panic_runtime",
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 \
694                                                 feature",
695                                                cfg_fn!(needs_panic_runtime))),
696     ("rustc_variance", Normal, Gated(Stability::Unstable,
697                                      "rustc_attrs",
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,
703                                        "rustc_attrs",
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,
709                                                  "rustc_attrs",
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,
715                                                       "rustc_attrs",
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,
721                                        "rustc_attrs",
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,
727                                        "rustc_attrs",
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,
733                                                 "rustc_attrs",
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,
739                                                 "rustc_attrs",
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,
745                                                   "rustc_attrs",
746                                                   "this attribute \
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,
751                                                       "rustc_attrs",
752                                                       "this attribute \
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,
757                                                       "rustc_attrs",
758                                                       "this attribute \
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,
763                                              "rustc_attrs",
764                                              "internal rustc attributes will never be stable",
765                                              cfg_fn!(rustc_attrs))),
766     ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
767                                            "rustc_attrs",
768                                            "internal rustc attributes will never be stable",
769                                            cfg_fn!(rustc_attrs))),
770     ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
771                                      "rustc_attrs",
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,
777                                                          "rustc_attrs",
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,
785                                              "compiler_builtins",
786                                              "the `#[compiler_builtins]` attribute is used to \
787                                               identify the `compiler_builtins` crate which \
788                                               contains compiler-rt intrinsics and will never be \
789                                               stable",
790                                           cfg_fn!(compiler_builtins))),
791     ("sanitizer_runtime", Whitelisted, Gated(Stability::Unstable,
792                                              "sanitizer_runtime",
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,
798                                              "profiler_runtime",
799                                              "the `#[profiler_runtime]` attribute is used to \
800                                               identify the `profiler_builtins` crate which \
801                                               contains the profiler runtime and will never be \
802                                               stable",
803                                              cfg_fn!(profiler_runtime))),
804
805     ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
806                                               "allow_internal_unstable",
807                                               EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
808                                               cfg_fn!(allow_internal_unstable))),
809
810     ("allow_internal_unsafe", Normal, Gated(Stability::Unstable,
811                                             "allow_internal_unsafe",
812                                             EXPLAIN_ALLOW_INTERNAL_UNSAFE,
813                                             cfg_fn!(allow_internal_unsafe))),
814
815     ("fundamental", Whitelisted, Gated(Stability::Unstable,
816                                        "fundamental",
817                                        "the `#[fundamental]` attribute \
818                                         is an experimental feature",
819                                        cfg_fn!(fundamental))),
820
821     ("proc_macro_derive", Normal, Ungated),
822
823     ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
824                                                    "rustc_attrs",
825                                                    "internal implementation detail",
826                                                    cfg_fn!(rustc_attrs))),
827
828     // FIXME: #14408 whitelist docs since rustdoc looks at them
829     ("doc", Whitelisted, Ungated),
830
831     // FIXME: #14406 these are processed in trans, which happens after the
832     // lint pass
833     ("cold", Whitelisted, Ungated),
834     ("naked", Whitelisted, Gated(Stability::Unstable,
835                                  "naked_functions",
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"),
852         "no_debug",
853         "the `#[no_debug]` attribute was an experimental feature that has been \
854          deprecated due to lack of demand",
855         cfg_fn!(no_debug))),
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 \
860                                                         suite",
861                                                        cfg_fn!(omit_gdb_pretty_printer_section))),
862     ("unsafe_destructor_blind_to_params",
863      Normal,
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))),
869     ("may_dangle",
870      Normal,
871      Gated(Stability::Unstable,
872            "dropck_eyepatch",
873            "may_dangle has unstable semantics and may be removed in the future",
874            cfg_fn!(dropck_eyepatch))),
875     ("unwind", Whitelisted, Gated(Stability::Unstable,
876                                   "unwind_attributes",
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",
882         cfg_fn!(used))),
883
884     // used in resolve
885     ("prelude_import", Whitelisted, Gated(Stability::Unstable,
886                                           "prelude_import",
887                                           "`#[prelude_import]` is for use by rustc only",
888                                           cfg_fn!(prelude_import))),
889
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),
897
898     ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
899                                         "unboxed_closures",
900                                         "unboxed_closures are still evolving",
901                                         cfg_fn!(unboxed_closures))),
902
903     ("windows_subsystem", Whitelisted, Ungated),
904
905     ("proc_macro_attribute", Normal, Gated(Stability::Unstable,
906                                            "proc_macro",
907                                            "attribute proc macros are currently unstable",
908                                            cfg_fn!(proc_macro))),
909
910     ("proc_macro", Normal, Gated(Stability::Unstable,
911                                  "proc_macro",
912                                  "function-like proc macros are currently unstable",
913                                  cfg_fn!(proc_macro))),
914
915     ("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
916                                              "rustc_derive_registrar",
917                                              "used internally by rustc",
918                                              cfg_fn!(rustc_attrs))),
919
920     ("allow_fail", Normal, Gated(Stability::Unstable,
921                                  "allow_fail",
922                                  "allow_fail attribute is currently unstable",
923                                  cfg_fn!(allow_fail))),
924
925     ("rustc_std_internal_symbol", Whitelisted, Gated(Stability::Unstable,
926                                      "rustc_attrs",
927                                      "this is an internal attribute that will \
928                                       never be stable",
929                                      cfg_fn!(rustc_attrs))),
930
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),
941 ];
942
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)),
950 ];
951
952 #[derive(Debug, Eq, PartialEq)]
953 pub struct GatedCfg {
954     span: Span,
955     index: usize,
956 }
957
958 impl GatedCfg {
959     pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
960         let name = cfg.name().as_str();
961         GATED_CFGS.iter()
962                   .position(|info| info.0 == name)
963                   .map(|idx| {
964                       GatedCfg {
965                           span: cfg.span,
966                           index: idx
967                       }
968                   })
969     }
970
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);
976         }
977     }
978 }
979
980 struct Context<'a> {
981     features: &'a Features,
982     parse_sess: &'a ParseSess,
983     plugin_attributes: &'a [(String, AttributeType)],
984 }
985
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)
994                 .emit();
995         }
996     }}
997 }
998
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)
1003     };
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)
1007     };
1008 }
1009
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 {
1015             if name == n {
1016                 if let Gated(_, name, desc, ref has_feature) = *gateage {
1017                     gate_feature_fn!(self, has_feature, attr.span, name, desc, GateStrength::Hard);
1018                 }
1019                 debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
1020                 return;
1021             }
1022         }
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);
1029                 return;
1030             }
1031         }
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
1044             if !is_macro {
1045                 gate_feature!(self, custom_attribute, attr.span,
1046                               &format!("The attribute `{}` is currently \
1047                                         unknown to the compiler and \
1048                                         may have meaning \
1049                                         added to it in the future",
1050                                        attr.path));
1051             }
1052         }
1053     }
1054 }
1055
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);
1059 }
1060
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)
1063 }
1064
1065 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
1066     if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
1067         let issue = info.2;
1068         // FIXME (#28244): enforce that active features have issue numbers
1069         // assert!(issue.is_some())
1070         issue
1071     } else {
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);
1075         match found {
1076             Some(&(_, _, issue)) => issue,
1077             None => panic!("Feature `{}` is not declared anywhere", feature),
1078         }
1079     }
1080 }
1081
1082 pub enum GateIssue {
1083     Language,
1084     Library(Option<u32>)
1085 }
1086
1087 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
1088 pub enum GateStrength {
1089     /// A hard error. (Most feature gates should use this.)
1090     Hard,
1091     /// Only a warning. (Use this only as backwards-compatibility demands.)
1092     Soft,
1093 }
1094
1095 pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
1096                         explain: &str) {
1097     feature_err(sess, feature, span, issue, explain).emit();
1098 }
1099
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)
1103 }
1104
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;
1108
1109     let issue = match issue {
1110         GateIssue::Language => find_lang_feature_issue(feature),
1111         GateIssue::Library(lib) => lib,
1112     };
1113
1114     let explanation = if let Some(n) = issue {
1115         format!("{} (see issue #{})", explain, n)
1116     } else {
1117         explain.to_owned()
1118     };
1119
1120     let mut err = match level {
1121         GateStrength::Hard => diag.struct_span_err(span, &explanation),
1122         GateStrength::Soft => diag.struct_span_warn(span, &explanation),
1123     };
1124
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",
1129                           feature));
1130     }
1131
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
1134     // warning-worthy).
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");
1137     }
1138
1139     err
1140
1141 }
1142
1143 const EXPLAIN_BOX_SYNTAX: &'static str =
1144     "box expression syntax is experimental; you can call `Box::new` instead.";
1145
1146 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
1147     "attributes on non-item statements and expressions are experimental.";
1148
1149 pub const EXPLAIN_ASM: &'static str =
1150     "inline assembly is not stable enough for use and is subject to change";
1151
1152 pub const EXPLAIN_GLOBAL_ASM: &'static str =
1153     "`global_asm!` is not stable enough for use and is subject to change";
1154
1155 pub const EXPLAIN_LOG_SYNTAX: &'static str =
1156     "`log_syntax!` is not stable enough for use and is subject to change";
1157
1158 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
1159     "`concat_idents` is not stable enough for use and is subject to change";
1160
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";
1167
1168 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
1169     "`#[derive]` for custom traits is deprecated and will be removed in the future.";
1170
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.";
1174
1175 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
1176     "attributes of the form `#[derive_*]` are reserved for the compiler";
1177
1178 pub const EXPLAIN_VIS_MATCHER: &'static str =
1179     ":vis fragment specifier is experimental and subject to change";
1180
1181 pub const EXPLAIN_PLACEMENT_IN: &'static str =
1182     "placement-in expression syntax is experimental and subject to change.";
1183
1184 pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
1185     "Unsized tuple coercion is not stable enough for use and is subject to change";
1186
1187 struct PostExpansionVisitor<'a> {
1188     context: &'a Context<'a>,
1189 }
1190
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)
1196         }
1197     }};
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)
1202         }
1203     }}
1204 }
1205
1206 impl<'a> PostExpansionVisitor<'a> {
1207     fn check_abi(&self, abi: Abi, span: Span) {
1208         match abi {
1209             Abi::RustIntrinsic => {
1210                 gate_feature_post!(&self, intrinsics, span,
1211                                    "intrinsics are subject to change");
1212             },
1213             Abi::PlatformIntrinsic => {
1214                 gate_feature_post!(&self, platform_intrinsics, span,
1215                                    "platform intrinsics are experimental and possibly buggy");
1216             },
1217             Abi::Vectorcall => {
1218                 gate_feature_post!(&self, abi_vectorcall, span,
1219                                    "vectorcall is experimental and subject to change");
1220             },
1221             Abi::Thiscall => {
1222                 gate_feature_post!(&self, abi_thiscall, span,
1223                                    "thiscall is experimental and subject to change");
1224             },
1225             Abi::RustCall => {
1226                 gate_feature_post!(&self, unboxed_closures, span,
1227                                    "rust-call ABI is subject to change");
1228             },
1229             Abi::SysV64 => {
1230                 gate_feature_post!(&self, abi_sysv64, span,
1231                                    "sysv64 ABI is experimental and subject to change");
1232             },
1233             Abi::PtxKernel => {
1234                 gate_feature_post!(&self, abi_ptx, span,
1235                                    "PTX ABIs are experimental and subject to change");
1236             },
1237             Abi::Unadjusted => {
1238                 gate_feature_post!(&self, abi_unadjusted, span,
1239                                    "unadjusted ABI is an implementation detail and perma-unstable");
1240             },
1241             Abi::Msp430Interrupt => {
1242                 gate_feature_post!(&self, abi_msp430_interrupt, span,
1243                                    "msp430-interrupt ABI is experimental and subject to change");
1244             },
1245             Abi::X86Interrupt => {
1246                 gate_feature_post!(&self, abi_x86_interrupt, span,
1247                                    "x86-interrupt ABI is experimental and subject to change");
1248             },
1249             // Stable
1250             Abi::Cdecl |
1251             Abi::Stdcall |
1252             Abi::Fastcall |
1253             Abi::Aapcs |
1254             Abi::Win64 |
1255             Abi::Rust |
1256             Abi::C |
1257             Abi::System => {}
1258         }
1259     }
1260 }
1261
1262 fn contains_novel_literal(item: &ast::MetaItem) -> bool {
1263     use ast::MetaItemKind::*;
1264     use ast::NestedMetaItemKind::*;
1265
1266     match item.node {
1267         Word => false,
1268         NameValue(ref lit) => !lit.node.is_str(),
1269         List(ref list) => list.iter().any(|li| {
1270             match li.node {
1271                 MetaItem(ref mi) => contains_novel_literal(mi),
1272                 Literal(_) => true,
1273             }
1274         }),
1275     }
1276 }
1277
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);
1283         }
1284
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"
1290                     );
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"
1294                     );
1295                 }
1296             }
1297         }
1298
1299         if self.context.features.proc_macro && attr::is_known(attr) {
1300             return
1301         }
1302
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");
1308         }
1309     }
1310
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.");
1315         }
1316     }
1317
1318     fn visit_item(&mut self, i: &'a ast::Item) {
1319         match i.node {
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");
1325                 }
1326             }
1327
1328             ast::ItemKind::ForeignMod(ref foreign_module) => {
1329                 self.check_abi(foreign_module.abi, i.span);
1330             }
1331
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");
1336                 }
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 \
1341                                        over time");
1342                 }
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");
1348                 }
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);
1353                 }
1354             }
1355
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");
1364                 }
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");
1370                         }
1371                         if item.check_name("align") {
1372                             gate_feature_post!(&self, repr_align, attr.span,
1373                                                "the struct `#[repr(align(u16))]` attribute \
1374                                                 is experimental");
1375                         }
1376                     }
1377                 }
1378             }
1379
1380             ast::ItemKind::AutoImpl(..) => {
1381                 gate_feature_post!(&self, optin_builtin_traits,
1382                                    i.span,
1383                                    "auto trait implementations are experimental \
1384                                     and possibly buggy");
1385             }
1386
1387             ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, ref impl_items) => {
1388                 if polarity == ast::ImplPolarity::Negative {
1389                     gate_feature_post!(&self, optin_builtin_traits,
1390                                        i.span,
1391                                        "negative trait bounds are not yet fully implemented; \
1392                                         use marker types for now");
1393                 }
1394
1395                 if let ast::Defaultness::Default = defaultness {
1396                     gate_feature_post!(&self, specialization,
1397                                        i.span,
1398                                        "specialization is unstable");
1399                 }
1400
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);
1407                         }
1408                     }
1409                 }
1410             }
1411
1412             ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => {
1413                 gate_feature_post!(&self, optin_builtin_traits,
1414                                    i.span,
1415                                    "auto traits are experimental and possibly buggy");
1416             }
1417
1418             ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
1419                 let msg = "`macro` is experimental";
1420                 gate_feature_post!(&self, decl_macro, i.span, msg);
1421             }
1422
1423             _ => {}
1424         }
1425
1426         visit::walk_item(self, i);
1427     }
1428
1429     fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
1430         match i.node {
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."),
1436                     _ => false
1437                 };
1438                 if links_to_llvm {
1439                     gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1440                                        "linking to LLVM intrinsics is experimental");
1441                 }
1442             }
1443             ast::ForeignItemKind::Ty => {
1444                     gate_feature_post!(&self, extern_types, i.span,
1445                                        "extern types are experimental");
1446             }
1447         }
1448
1449         visit::walk_foreign_item(self, i)
1450     }
1451
1452     fn visit_ty(&mut self, ty: &'a ast::Ty) {
1453         match ty.node {
1454             ast::TyKind::BareFn(ref bare_fn_ty) => {
1455                 self.check_abi(bare_fn_ty.abi, ty.span);
1456             }
1457             ast::TyKind::Never => {
1458                 gate_feature_post!(&self, never_type, ty.span,
1459                                    "The `!` type is experimental");
1460             },
1461             ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => {
1462                 gate_feature_post!(&self, dyn_trait, ty.span,
1463                                    "`dyn Trait` syntax is unstable");
1464             }
1465             _ => {}
1466         }
1467         visit::walk_ty(self, ty)
1468     }
1469
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)
1474             }
1475         }
1476     }
1477
1478     fn visit_expr(&mut self, e: &'a ast::Expr) {
1479         match e.node {
1480             ast::ExprKind::Box(_) => {
1481                 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1482             }
1483             ast::ExprKind::Type(..) => {
1484                 gate_feature_post!(&self, type_ascription, e.span,
1485                                   "type ascription is experimental");
1486             }
1487             ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1488                 gate_feature_post!(&self, inclusive_range_syntax,
1489                                   e.span,
1490                                   "inclusive range syntax is experimental");
1491             }
1492             ast::ExprKind::InPlace(..) => {
1493                 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1494             }
1495             ast::ExprKind::Yield(..) => {
1496                 gate_feature_post!(&self, generators,
1497                                   e.span,
1498                                   "yield syntax is experimental");
1499             }
1500             ast::ExprKind::Lit(ref lit) => {
1501                 if let ast::LitKind::Int(_, ref ty) = lit.node {
1502                     match *ty {
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");
1507                         }
1508                         _ => {}
1509                     }
1510                 }
1511             }
1512             ast::ExprKind::Catch(_) => {
1513                 gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
1514             }
1515             _ => {}
1516         }
1517         visit::walk_expr(self, e);
1518     }
1519
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,
1523                                span,
1524                                "Use of a '|' at the beginning of a match arm is experimental")
1525         }
1526         visit::walk_arm(self, arm)
1527     }
1528
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,
1533                                   pattern.span,
1534                                   "multiple-element slice matches anywhere \
1535                                    but at the end of a slice (e.g. \
1536                                    `[0, ..xs, 0]`) are experimental")
1537             }
1538             PatKind::Slice(..) => {
1539                 gate_feature_post!(&self, slice_patterns,
1540                                   pattern.span,
1541                                   "slice pattern syntax is experimental");
1542             }
1543             PatKind::Box(..) => {
1544                 gate_feature_post!(&self, box_patterns,
1545                                   pattern.span,
1546                                   "box pattern syntax is experimental");
1547             }
1548             PatKind::Range(_, _, RangeEnd::Excluded) => {
1549                 gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
1550                                    "exclusive range pattern syntax is experimental");
1551             }
1552             PatKind::Range(_, _, RangeEnd::Included(RangeSyntax::DotDotEq)) => {
1553                 gate_feature_post!(&self, dotdoteq_in_patterns, pattern.span,
1554                                    "`..=` syntax in patterns is experimental");
1555             }
1556             _ => {}
1557         }
1558         visit::walk_pat(self, pattern)
1559     }
1560
1561     fn visit_fn(&mut self,
1562                 fn_kind: FnKind<'a>,
1563                 fn_decl: &'a ast::FnDecl,
1564                 span: Span,
1565                 _node_id: NodeId) {
1566         // check for const fn declarations
1567         if let FnKind::ItemFn(_, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) =
1568             fn_kind {
1569             gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1570         }
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
1574         // point.
1575
1576         match fn_kind {
1577             FnKind::ItemFn(_, _, _, abi, _, _) |
1578             FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
1579                 self.check_abi(abi, span);
1580             }
1581             _ => {}
1582         }
1583         visit::walk_fn(self, fn_kind, fn_decl, span);
1584     }
1585
1586     fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1587         match ti.node {
1588             ast::TraitItemKind::Method(ref sig, ref block) => {
1589                 if block.is_none() {
1590                     self.check_abi(sig.abi, ti.span);
1591                 }
1592                 if sig.constness.node == ast::Constness::Const {
1593                     gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1594                 }
1595             }
1596             ast::TraitItemKind::Type(_, Some(_)) => {
1597                 gate_feature_post!(&self, associated_type_defaults, ti.span,
1598                                   "associated type defaults are unstable");
1599             }
1600             _ => {}
1601         }
1602         visit::walk_trait_item(self, ti);
1603     }
1604
1605     fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
1606         if ii.defaultness == ast::Defaultness::Default {
1607             gate_feature_post!(&self, specialization,
1608                               ii.span,
1609                               "specialization is unstable");
1610         }
1611
1612         match ii.node {
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");
1616                 }
1617             }
1618             _ => {}
1619         }
1620         visit::walk_impl_item(self, ii);
1621     }
1622
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");
1627         }
1628         visit::walk_vis(self, vis);
1629     }
1630
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");
1636             }
1637         }
1638         visit::walk_generics(self, g)
1639     }
1640
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");
1645         }
1646         visit::walk_lifetime_def(self, lifetime_def)
1647     }
1648
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");
1653         }
1654         visit::walk_lifetime(self, lt)
1655     }
1656 }
1657
1658 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1659     let mut features = Features::new();
1660
1661     let mut feature_checker = FeatureChecker::default();
1662
1663     for attr in krate_attrs {
1664         if !attr.check_name("feature") {
1665             continue
1666         }
1667
1668         match attr.meta_item_list() {
1669             None => {
1670                 span_err!(span_handler, attr.span, E0555,
1671                           "malformed feature attribute, expected #![feature(...)]");
1672             }
1673             Some(list) => {
1674                 for mi in list {
1675                     let name = if let Some(word) = mi.word() {
1676                         word.name()
1677                     } else {
1678                         span_err!(span_handler, mi.span, E0556,
1679                                   "malformed feature, expected just one word");
1680                         continue
1681                     };
1682
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);
1687                     }
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");
1693                     }
1694                     else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1695                         .find(|& &(n, _, _)| name == n) {
1696                         features.declared_stable_lang_features.push((name, mi.span));
1697                     } else {
1698                         features.declared_lib_features.push((name, mi.span));
1699                     }
1700                 }
1701             }
1702         }
1703     }
1704
1705     feature_checker.check(span_handler);
1706
1707     features
1708 }
1709
1710 /// A collector for mutually exclusive and interdependent features and their flag spans.
1711 #[derive(Default)]
1712 struct FeatureChecker {
1713     proc_macro: Option<Span>,
1714     custom_attribute: Option<Span>,
1715     copy_closures: Option<Span>,
1716     clone_closures: Option<Span>,
1717 }
1718
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));
1727         }
1728
1729         if features.custom_attribute {
1730             self.custom_attribute = self.custom_attribute.or(Some(span));
1731         }
1732
1733         if features.copy_closures {
1734             self.copy_closures = self.copy_closures.or(Some(span));
1735         }
1736
1737         if features.clone_closures {
1738             self.clone_closures = self.clone_closures.or(Some(span));
1739         }
1740     }
1741
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")
1747                 .emit();
1748
1749             panic!(FatalError);
1750         }
1751
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")
1756                   .emit();
1757
1758             panic!(FatalError);
1759         }
1760     }
1761 }
1762
1763 pub fn check_crate(krate: &ast::Crate,
1764                    sess: &ParseSess,
1765                    features: &Features,
1766                    plugin_attributes: &[(String, AttributeType)],
1767                    unstable: UnstableFeatures) {
1768     maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1769     let ctx = Context {
1770         features,
1771         parse_sess: sess,
1772         plugin_attributes,
1773     };
1774     visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1775 }
1776
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.
1781     Disallow,
1782     /// Allow features to be activated, as on nightly.
1783     Allow,
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.
1788     Cheat
1789 }
1790
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
1801         }
1802     }
1803
1804     pub fn is_nightly_build(&self) -> bool {
1805         match *self {
1806             UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1807             _ => false,
1808         }
1809     }
1810 }
1811
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
1818     };
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",
1825                           release_channel);
1826             }
1827         }
1828     }
1829 }