]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/feature_gate.rs
efedc7229e64c951e3536bd2b36cec1a7d207449
[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::{NodeId, PatKind};
30 use ast;
31 use attr;
32 use attr::AttrMetaMethods;
33 use codemap::CodeMap;
34 use syntax_pos::Span;
35 use errors::Handler;
36 use visit::{self, FnKind, Visitor};
37 use parse::ParseSess;
38 use parse::token::InternedString;
39
40 use std::ascii::AsciiExt;
41
42 macro_rules! setter {
43     ($field: ident) => {{
44         fn f(features: &mut Features) -> &mut bool {
45             &mut features.$field
46         }
47         f as fn(&mut Features) -> &mut bool
48     }}
49 }
50
51 macro_rules! declare_features {
52     ($((active, $feature: ident, $ver: expr, $issue: expr)),+) => {
53         /// Represents active features that are currently being implemented or
54         /// currently being considered for addition/removal.
55         const ACTIVE_FEATURES: &'static [(&'static str, &'static str,
56                                           Option<u32>, fn(&mut Features) -> &mut bool)] = &[
57             $((stringify!($feature), $ver, $issue, setter!($feature))),+
58         ];
59
60         /// A set of features to be used by later passes.
61         pub struct Features {
62             /// #![feature] attrs for stable language features, for error reporting
63             pub declared_stable_lang_features: Vec<(InternedString, Span)>,
64             /// #![feature] attrs for non-language (library) features
65             pub declared_lib_features: Vec<(InternedString, Span)>,
66             $(pub $feature: bool),+
67         }
68
69         impl Features {
70             pub fn new() -> Features {
71                 Features {
72                     declared_stable_lang_features: Vec::new(),
73                     declared_lib_features: Vec::new(),
74                     $($feature: false),+
75                 }
76             }
77         }
78     };
79
80     ($((removed, $feature: ident, $ver: expr, $issue: expr)),+) => {
81         /// Represents features which has since been removed (it was once Active)
82         const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
83             $((stringify!($feature), $ver, $issue)),+
84         ];
85     };
86
87     ($((accepted, $feature: ident, $ver: expr, $issue: expr)),+) => {
88         /// Those language feature has since been Accepted (it was once Active)
89         const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
90             $((stringify!($feature), $ver, $issue)),+
91         ];
92     }
93 }
94
95 // If you change this list without updating src/doc/reference.md, @cmr will be sad
96 // Don't ever remove anything from this list; set them to 'Removed'.
97 // The version numbers here correspond to the version in which the current status
98 // was set. This is most important for knowing when a particular feature became
99 // stable (active).
100 // NB: The featureck.py script parses this information directly out of the source
101 // so take care when modifying it.
102
103 declare_features! (
104     (active, asm, "1.0.0", Some(29722)),
105     (active, concat_idents, "1.0.0", Some(29599)),
106     (active, link_args, "1.0.0", Some(29596)),
107     (active, log_syntax, "1.0.0", Some(29598)),
108     (active, non_ascii_idents, "1.0.0", Some(28979)),
109     (active, plugin_registrar, "1.0.0", Some(29597)),
110     (active, thread_local, "1.0.0", Some(29594)),
111     (active, trace_macros, "1.0.0", Some(29598)),
112
113     // rustc internal, for now:
114     (active, intrinsics, "1.0.0", None),
115     (active, lang_items, "1.0.0", None),
116
117     (active, link_llvm_intrinsics, "1.0.0", Some(29602)),
118     (active, linkage, "1.0.0", Some(29603)),
119     (active, quote, "1.0.0", Some(29601)),
120     (active, simd, "1.0.0", Some(27731)),
121
122
123     // rustc internal
124     (active, rustc_diagnostic_macros, "1.0.0", None),
125     (active, advanced_slice_patterns, "1.0.0", Some(23121)),
126     (active, box_syntax, "1.0.0", Some(27779)),
127     (active, placement_in_syntax, "1.0.0", Some(27779)),
128     (active, reflect, "1.0.0", Some(27749)),
129     (active, unboxed_closures, "1.0.0", Some(29625)),
130
131     // rustc internal.
132     (active, pushpop_unsafe, "1.2.0", None),
133
134     (active, allocator, "1.0.0", Some(27389)),
135     (active, fundamental, "1.0.0", Some(29635)),
136     (active, linked_from, "1.3.0", Some(29629)),
137     (active, main, "1.0.0", Some(29634)),
138     (active, needs_allocator, "1.4.0", Some(27389)),
139     (active, on_unimplemented, "1.0.0", Some(29628)),
140     (active, plugin, "1.0.0", Some(29597)),
141     (active, simd_ffi, "1.0.0", Some(27731)),
142     (active, start, "1.0.0", Some(29633)),
143     (active, structural_match, "1.8.0", Some(31434)),
144     (active, panic_runtime, "1.10.0", Some(32837)),
145     (active, needs_panic_runtime, "1.10.0", Some(32837)),
146
147     // OIBIT specific features
148     (active, optin_builtin_traits, "1.0.0", Some(13231)),
149
150     // macro reexport needs more discussion and stabilization
151     (active, macro_reexport, "1.0.0", Some(29638)),
152
153     // Allows use of #[staged_api]
154     // rustc internal
155     (active, staged_api, "1.0.0", None),
156
157     // Allows using items which are missing stability attributes
158     // rustc internal
159     (active, unmarked_api, "1.0.0", None),
160
161     // Allows using #![no_core]
162     (active, no_core, "1.3.0", Some(29639)),
163
164     // Allows using `box` in patterns; RFC 469
165     (active, box_patterns, "1.0.0", Some(29641)),
166
167     // Allows using the unsafe_no_drop_flag attribute (unlikely to
168     // switch to Accepted; see RFC 320)
169     (active, unsafe_no_drop_flag, "1.0.0", None),
170
171     // Allows using the unsafe_destructor_blind_to_params attribute;
172     // RFC 1238
173     (active, dropck_parametricity, "1.3.0", Some(28498)),
174
175     // Allows the use of custom attributes; RFC 572
176     (active, custom_attribute, "1.0.0", Some(29642)),
177
178     // Allows the use of #[derive(Anything)] as sugar for
179     // #[derive_Anything].
180     (active, custom_derive, "1.0.0", Some(29644)),
181
182     // Allows the use of rustc_* attributes; RFC 572
183     (active, rustc_attrs, "1.0.0", Some(29642)),
184
185     // Allows the use of #[allow_internal_unstable]. This is an
186     // attribute on macro_rules! and can't use the attribute handling
187     // below (it has to be checked before expansion possibly makes
188     // macros disappear).
189     //
190     // rustc internal
191     (active, allow_internal_unstable, "1.0.0", None),
192
193     // #23121. Array patterns have some hazards yet.
194     (active, slice_patterns, "1.0.0", Some(23121)),
195
196     // Allows the definition of associated constants in `trait` or `impl`
197     // blocks.
198     (active, associated_consts, "1.0.0", Some(29646)),
199
200     // Allows the definition of `const fn` functions.
201     (active, const_fn, "1.2.0", Some(24111)),
202
203     // Allows indexing into constant arrays.
204     (active, const_indexing, "1.4.0", Some(29947)),
205
206     // Allows using #[prelude_import] on glob `use` items.
207     //
208     // rustc internal
209     (active, prelude_import, "1.2.0", None),
210
211     // Allows the definition recursive static items.
212     (active, static_recursion, "1.3.0", Some(29719)),
213
214     // Allows default type parameters to influence type inference.
215     (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
216
217     // Allows associated type defaults
218     (active, associated_type_defaults, "1.2.0", Some(29661)),
219
220     // Allows macros to appear in the type position.
221     (active, type_macros, "1.3.0", Some(27245)),
222
223     // allow `repr(simd)`, and importing the various simd intrinsics
224     (active, repr_simd, "1.4.0", Some(27731)),
225
226     // Allows cfg(target_feature = "...").
227     (active, cfg_target_feature, "1.4.0", Some(29717)),
228
229     // allow `extern "platform-intrinsic" { ... }`
230     (active, platform_intrinsics, "1.4.0", Some(27731)),
231
232     // allow `#[unwind]`
233     // rust runtime internal
234     (active, unwind_attributes, "1.4.0", None),
235
236     // allow the use of `#[naked]` on functions.
237     (active, naked_functions, "1.9.0", Some(32408)),
238
239     // allow `#[no_debug]`
240     (active, no_debug, "1.5.0", Some(29721)),
241
242     // allow `#[omit_gdb_pretty_printer_section]`
243     // rustc internal.
244     (active, omit_gdb_pretty_printer_section, "1.5.0", None),
245
246     // Allows cfg(target_vendor = "...").
247     (active, cfg_target_vendor, "1.5.0", Some(29718)),
248
249     // Allow attributes on expressions and non-item statements
250     (active, stmt_expr_attributes, "1.6.0", Some(15701)),
251
252     // allow using type ascription in expressions
253     (active, type_ascription, "1.6.0", Some(23416)),
254
255     // Allows cfg(target_thread_local)
256     (active, cfg_target_thread_local, "1.7.0", Some(29594)),
257
258     // rustc internal
259     (active, abi_vectorcall, "1.7.0", None),
260
261     // a...b and ...b
262     (active, inclusive_range_syntax, "1.7.0", Some(28237)),
263
264     // `expr?`
265     (active, question_mark, "1.9.0", Some(31436)),
266
267     // impl specialization (RFC 1210)
268     (active, specialization, "1.7.0", Some(31844)),
269
270     // pub(restricted) visibilities (RFC 1422)
271     (active, pub_restricted, "1.9.0", Some(32409)),
272
273     // Allow Drop types in statics/const functions (RFC 1440)
274     (active, drop_types_in_const, "1.9.0", Some(33156)),
275
276     // Allows cfg(target_has_atomic = "...").
277     (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
278
279     // Allows `..` in tuple (struct) patterns
280     (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627)),
281
282     // Allows `impl Trait` in function return types.
283     (active, conservative_impl_trait, "1.12.0", Some(34511)),
284
285     // Allows tuple structs and variants in more contexts,
286     // Permits numeric fields in struct expressions and patterns.
287     (active, relaxed_adts, "1.12.0", Some(35626)),
288
289     // The `!` type
290     (active, bang_type, "1.13.0", Some(35121))
291 );
292
293 declare_features! (
294     (removed, import_shadowing, "1.0.0", None),
295     (removed, managed_boxes, "1.0.0", None),
296     // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
297     (removed, negate_unsigned, "1.0.0", Some(29645)),
298     // A way to temporarily opt out of opt in copy. This will *never* be accepted.
299     (removed, opt_out_copy, "1.0.0", None),
300     (removed, quad_precision_float, "1.0.0", None),
301     (removed, struct_inherit, "1.0.0", None),
302     (removed, test_removed_feature, "1.0.0", None),
303     (removed, visible_private_types, "1.0.0", None)
304 );
305
306 declare_features! (
307     (accepted, associated_types, "1.0.0", None),
308     // allow overloading augmented assignment operations like `a += b`
309     (accepted, augmented_assignments, "1.8.0", Some(28235)),
310     // allow empty structs and enum variants with braces
311     (accepted, braced_empty_structs, "1.8.0", Some(29720)),
312     (accepted, default_type_params, "1.0.0", None),
313     (accepted, globs, "1.0.0", None),
314     (accepted, if_let, "1.0.0", None),
315     // A temporary feature gate used to enable parser extensions needed
316     // to bootstrap fix for #5723.
317     (accepted, issue_5723_bootstrap, "1.0.0", None),
318     (accepted, macro_rules, "1.0.0", None),
319     // Allows using #![no_std]
320     (accepted, no_std, "1.0.0", None),
321     (accepted, slicing_syntax, "1.0.0", None),
322     (accepted, struct_variant, "1.0.0", None),
323     // These are used to test this portion of the compiler, they don't actually
324     // mean anything
325     (accepted, test_accepted_feature, "1.0.0", None),
326     (accepted, tuple_indexing, "1.0.0", None),
327     (accepted, while_let, "1.0.0", None),
328     // Allows `#[deprecated]` attribute
329     (accepted, deprecated, "1.9.0", Some(29935))
330 );
331 // (changing above list without updating src/doc/reference.md makes @cmr sad)
332
333 #[derive(PartialEq, Copy, Clone, Debug)]
334 pub enum AttributeType {
335     /// Normal, builtin attribute that is consumed
336     /// by the compiler before the unused_attribute check
337     Normal,
338
339     /// Builtin attribute that may not be consumed by the compiler
340     /// before the unused_attribute check. These attributes
341     /// will be ignored by the unused_attribute lint
342     Whitelisted,
343
344     /// Builtin attribute that is only allowed at the crate level
345     CrateLevel,
346 }
347
348 pub enum AttributeGate {
349     /// Is gated by a given feature gate, reason
350     /// and function to check if enabled
351     Gated(&'static str, &'static str, fn(&Features) -> bool),
352
353     /// Ungated attribute, can be used on all release channels
354     Ungated,
355 }
356
357 // fn() is not Debug
358 impl ::std::fmt::Debug for AttributeGate {
359     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
360         match *self {
361             Gated(ref name, ref expl, _) => write!(fmt, "Gated({}, {})", name, expl),
362             Ungated => write!(fmt, "Ungated")
363         }
364     }
365 }
366
367 macro_rules! cfg_fn {
368     ($field: ident) => {{
369         fn f(features: &Features) -> bool {
370             features.$field
371         }
372         f as fn(&Features) -> bool
373     }}
374 }
375
376 // Attributes that have a special meaning to rustc or rustdoc
377 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
378     // Normal attributes
379
380     ("warn", Normal, Ungated),
381     ("allow", Normal, Ungated),
382     ("forbid", Normal, Ungated),
383     ("deny", Normal, Ungated),
384
385     ("macro_reexport", Normal, Ungated),
386     ("macro_use", Normal, Ungated),
387     ("macro_export", Normal, Ungated),
388     ("plugin_registrar", Normal, Ungated),
389
390     ("cfg", Normal, Ungated),
391     ("cfg_attr", Normal, Ungated),
392     ("main", Normal, Ungated),
393     ("start", Normal, Ungated),
394     ("test", Normal, Ungated),
395     ("bench", Normal, Ungated),
396     ("simd", Normal, Ungated),
397     ("repr", Normal, Ungated),
398     ("path", Normal, Ungated),
399     ("abi", Normal, Ungated),
400     ("automatically_derived", Normal, Ungated),
401     ("no_mangle", Normal, Ungated),
402     ("no_link", Normal, Ungated),
403     ("derive", Normal, Ungated),
404     ("should_panic", Normal, Ungated),
405     ("ignore", Normal, Ungated),
406     ("no_implicit_prelude", Normal, Ungated),
407     ("reexport_test_harness_main", Normal, Ungated),
408     ("link_args", Normal, Ungated),
409     ("macro_escape", Normal, Ungated),
410
411     // RFC #1445.
412     ("structural_match", Whitelisted, Gated("structural_match",
413                                             "the semantics of constant patterns is \
414                                              not yet settled",
415                                             cfg_fn!(structural_match))),
416
417     // Not used any more, but we can't feature gate it
418     ("no_stack_check", Normal, Ungated),
419
420     ("plugin", CrateLevel, Gated("plugin",
421                                  "compiler plugins are experimental \
422                                   and possibly buggy",
423                                  cfg_fn!(plugin))),
424
425     ("no_std", CrateLevel, Ungated),
426     ("no_core", CrateLevel, Gated("no_core",
427                                   "no_core is experimental",
428                                   cfg_fn!(no_core))),
429     ("lang", Normal, Gated("lang_items",
430                            "language items are subject to change",
431                            cfg_fn!(lang_items))),
432     ("linkage", Whitelisted, Gated("linkage",
433                                    "the `linkage` attribute is experimental \
434                                     and not portable across platforms",
435                                    cfg_fn!(linkage))),
436     ("thread_local", Whitelisted, Gated("thread_local",
437                                         "`#[thread_local]` is an experimental feature, and does \
438                                          not currently handle destructors. There is no \
439                                          corresponding `#[task_local]` mapping to the task \
440                                          model",
441                                         cfg_fn!(thread_local))),
442
443     ("rustc_on_unimplemented", Normal, Gated("on_unimplemented",
444                                              "the `#[rustc_on_unimplemented]` attribute \
445                                               is an experimental feature",
446                                              cfg_fn!(on_unimplemented))),
447     ("allocator", Whitelisted, Gated("allocator",
448                                      "the `#[allocator]` attribute is an experimental feature",
449                                      cfg_fn!(allocator))),
450     ("needs_allocator", Normal, Gated("needs_allocator",
451                                       "the `#[needs_allocator]` \
452                                        attribute is an experimental \
453                                        feature",
454                                       cfg_fn!(needs_allocator))),
455     ("panic_runtime", Whitelisted, Gated("panic_runtime",
456                                          "the `#[panic_runtime]` attribute is \
457                                           an experimental feature",
458                                          cfg_fn!(panic_runtime))),
459     ("needs_panic_runtime", Whitelisted, Gated("needs_panic_runtime",
460                                                "the `#[needs_panic_runtime]` \
461                                                 attribute is an experimental \
462                                                 feature",
463                                                cfg_fn!(needs_panic_runtime))),
464     ("rustc_variance", Normal, Gated("rustc_attrs",
465                                      "the `#[rustc_variance]` attribute \
466                                       is just used for rustc unit tests \
467                                       and will never be stable",
468                                      cfg_fn!(rustc_attrs))),
469     ("rustc_error", Whitelisted, Gated("rustc_attrs",
470                                        "the `#[rustc_error]` attribute \
471                                         is just used for rustc unit tests \
472                                         and will never be stable",
473                                        cfg_fn!(rustc_attrs))),
474     ("rustc_if_this_changed", Whitelisted, Gated("rustc_attrs",
475                                                  "the `#[rustc_if_this_changed]` attribute \
476                                                   is just used for rustc unit tests \
477                                                   and will never be stable",
478                                                  cfg_fn!(rustc_attrs))),
479     ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs",
480                                                       "the `#[rustc_if_this_changed]` attribute \
481                                                        is just used for rustc unit tests \
482                                                        and will never be stable",
483                                                       cfg_fn!(rustc_attrs))),
484     ("rustc_dirty", Whitelisted, Gated("rustc_attrs",
485                                        "the `#[rustc_dirty]` attribute \
486                                         is just used for rustc unit tests \
487                                         and will never be stable",
488                                        cfg_fn!(rustc_attrs))),
489     ("rustc_clean", Whitelisted, Gated("rustc_attrs",
490                                        "the `#[rustc_clean]` attribute \
491                                         is just used for rustc unit tests \
492                                         and will never be stable",
493                                        cfg_fn!(rustc_attrs))),
494     ("rustc_partition_reused", Whitelisted, Gated("rustc_attrs",
495                                                   "this attribute \
496                                                    is just used for rustc unit tests \
497                                                    and will never be stable",
498                                                   cfg_fn!(rustc_attrs))),
499     ("rustc_partition_translated", Whitelisted, Gated("rustc_attrs",
500                                                       "this attribute \
501                                                        is just used for rustc unit tests \
502                                                        and will never be stable",
503                                                       cfg_fn!(rustc_attrs))),
504     ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs",
505                                              "internal rustc attributes will never be stable",
506                                              cfg_fn!(rustc_attrs))),
507     ("rustc_item_path", Whitelisted, Gated("rustc_attrs",
508                                            "internal rustc attributes will never be stable",
509                                            cfg_fn!(rustc_attrs))),
510     ("rustc_move_fragments", Normal, Gated("rustc_attrs",
511                                            "the `#[rustc_move_fragments]` attribute \
512                                             is just used for rustc unit tests \
513                                             and will never be stable",
514                                            cfg_fn!(rustc_attrs))),
515     ("rustc_mir", Whitelisted, Gated("rustc_attrs",
516                                      "the `#[rustc_mir]` attribute \
517                                       is just used for rustc unit tests \
518                                       and will never be stable",
519                                      cfg_fn!(rustc_attrs))),
520     ("rustc_no_mir", Whitelisted, Gated("rustc_attrs",
521                                         "the `#[rustc_no_mir]` attribute \
522                                          is just used to make tests pass \
523                                          and will never be stable",
524                                         cfg_fn!(rustc_attrs))),
525     ("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs",
526                                                          "the `#[rustc_inherit_overflow_checks]` \
527                                                           attribute is just used to control \
528                                                           overflow checking behavior of several \
529                                                           libcore functions that are inlined \
530                                                           across crates and will never be stable",
531                                                           cfg_fn!(rustc_attrs))),
532
533     ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
534                                               EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
535                                               cfg_fn!(allow_internal_unstable))),
536
537     ("fundamental", Whitelisted, Gated("fundamental",
538                                        "the `#[fundamental]` attribute \
539                                         is an experimental feature",
540                                        cfg_fn!(fundamental))),
541
542     ("linked_from", Normal, Gated("linked_from",
543                                   "the `#[linked_from]` attribute \
544                                    is an experimental feature",
545                                   cfg_fn!(linked_from))),
546
547     // FIXME: #14408 whitelist docs since rustdoc looks at them
548     ("doc", Whitelisted, Ungated),
549
550     // FIXME: #14406 these are processed in trans, which happens after the
551     // lint pass
552     ("cold", Whitelisted, Ungated),
553     ("naked", Whitelisted, Gated("naked_functions",
554                                  "the `#[naked]` attribute \
555                                   is an experimental feature",
556                                  cfg_fn!(naked_functions))),
557     ("export_name", Whitelisted, Ungated),
558     ("inline", Whitelisted, Ungated),
559     ("link", Whitelisted, Ungated),
560     ("link_name", Whitelisted, Ungated),
561     ("link_section", Whitelisted, Ungated),
562     ("no_builtins", Whitelisted, Ungated),
563     ("no_mangle", Whitelisted, Ungated),
564     ("no_debug", Whitelisted, Gated("no_debug",
565                                     "the `#[no_debug]` attribute \
566                                      is an experimental feature",
567                                     cfg_fn!(no_debug))),
568     ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
569                                                        "the `#[omit_gdb_pretty_printer_section]` \
570                                                         attribute is just used for the Rust test \
571                                                         suite",
572                                                        cfg_fn!(omit_gdb_pretty_printer_section))),
573     ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
574                                                "unsafe_no_drop_flag has unstable semantics \
575                                                 and may be removed in the future",
576                                                cfg_fn!(unsafe_no_drop_flag))),
577     ("unsafe_destructor_blind_to_params",
578      Normal,
579      Gated("dropck_parametricity",
580            "unsafe_destructor_blind_to_params has unstable semantics \
581             and may be removed in the future",
582            cfg_fn!(dropck_parametricity))),
583     ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental",
584                                   cfg_fn!(unwind_attributes))),
585
586     // used in resolve
587     ("prelude_import", Whitelisted, Gated("prelude_import",
588                                           "`#[prelude_import]` is for use by rustc only",
589                                           cfg_fn!(prelude_import))),
590
591     // FIXME: #14407 these are only looked at on-demand so we can't
592     // guarantee they'll have already been checked
593     ("rustc_deprecated", Whitelisted, Ungated),
594     ("must_use", Whitelisted, Ungated),
595     ("stable", Whitelisted, Ungated),
596     ("unstable", Whitelisted, Ungated),
597     ("deprecated", Normal, Ungated),
598
599     ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
600                                         "unboxed_closures are still evolving",
601                                         cfg_fn!(unboxed_closures))),
602     ("rustc_reflect_like", Whitelisted, Gated("reflect",
603                                               "defining reflective traits is still evolving",
604                                               cfg_fn!(reflect))),
605
606     // Crate level attributes
607     ("crate_name", CrateLevel, Ungated),
608     ("crate_type", CrateLevel, Ungated),
609     ("crate_id", CrateLevel, Ungated),
610     ("feature", CrateLevel, Ungated),
611     ("no_start", CrateLevel, Ungated),
612     ("no_main", CrateLevel, Ungated),
613     ("no_builtins", CrateLevel, Ungated),
614     ("recursion_limit", CrateLevel, Ungated),
615 ];
616
617 // cfg(...)'s that are feature gated
618 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
619     // (name in cfg, feature, function to check if the feature is enabled)
620     ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
621     ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
622     ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
623     ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
624 ];
625
626 #[derive(Debug, Eq, PartialEq)]
627 pub struct GatedCfg {
628     span: Span,
629     index: usize,
630 }
631
632 impl GatedCfg {
633     pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
634         let name = cfg.name();
635         GATED_CFGS.iter()
636                   .position(|info| info.0 == name)
637                   .map(|idx| {
638                       GatedCfg {
639                           span: cfg.span,
640                           index: idx
641                       }
642                   })
643     }
644
645     pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
646         let (cfg, feature, has_feature) = GATED_CFGS[self.index];
647         if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
648             let diagnostic = &sess.span_diagnostic;
649             let explain = format!("`cfg({})` is experimental and subject to change", cfg);
650             emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
651         }
652     }
653 }
654
655 struct Context<'a> {
656     features: &'a Features,
657     span_handler: &'a Handler,
658     cm: &'a CodeMap,
659     plugin_attributes: &'a [(String, AttributeType)],
660 }
661
662 macro_rules! gate_feature_fn {
663     ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
664         let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
665         let has_feature: bool = has_feature(&$cx.features);
666         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
667         if !has_feature && !cx.cm.span_allows_unstable(span) {
668             emit_feature_err(cx.span_handler, name, span, GateIssue::Language, explain);
669         }
670     }}
671 }
672
673 macro_rules! gate_feature {
674     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
675         gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
676     }
677 }
678
679 impl<'a> Context<'a> {
680     fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
681         debug!("check_attribute(attr = {:?})", attr);
682         let name = &*attr.name();
683         for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES {
684             if n == name {
685                 if let &Gated(ref name, ref desc, ref has_feature) = gateage {
686                     gate_feature_fn!(self, has_feature, attr.span, name, desc);
687                 }
688                 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
689                 return;
690             }
691         }
692         for &(ref n, ref ty) in self.plugin_attributes {
693             if n == name {
694                 // Plugins can't gate attributes, so we don't check for it
695                 // unlike the code above; we only use this loop to
696                 // short-circuit to avoid the checks below
697                 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
698                 return;
699             }
700         }
701         if name.starts_with("rustc_") {
702             gate_feature!(self, rustc_attrs, attr.span,
703                           "unless otherwise specified, attributes \
704                            with the prefix `rustc_` \
705                            are reserved for internal compiler diagnostics");
706         } else if name.starts_with("derive_") {
707             gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
708         } else {
709             // Only run the custom attribute lint during regular
710             // feature gate checking. Macro gating runs
711             // before the plugin attributes are registered
712             // so we skip this then
713             if !is_macro {
714                 gate_feature!(self, custom_attribute, attr.span,
715                               &format!("The attribute `{}` is currently \
716                                         unknown to the compiler and \
717                                         may have meaning \
718                                         added to it in the future",
719                                        name));
720             }
721         }
722     }
723 }
724
725 pub fn check_attribute(attr: &ast::Attribute, handler: &Handler,
726                        cm: &CodeMap, features: &Features) {
727     let cx = Context {
728         features: features, span_handler: handler,
729         cm: cm, plugin_attributes: &[]
730     };
731     cx.check_attribute(attr, true);
732 }
733
734 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
735     ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
736 }
737
738 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
739     if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
740         let issue = info.2;
741         // FIXME (#28244): enforce that active features have issue numbers
742         // assert!(issue.is_some())
743         issue
744     } else {
745         // search in Accepted or Removed features
746         ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES.iter())
747             .find(|t| t.0 == feature)
748             .unwrap().2
749     }
750 }
751
752 pub enum GateIssue {
753     Language,
754     Library(Option<u32>)
755 }
756
757 pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
758                         explain: &str) {
759     let issue = match issue {
760         GateIssue::Language => find_lang_feature_issue(feature),
761         GateIssue::Library(lib) => lib,
762     };
763
764     let mut err = if let Some(n) = issue {
765         diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
766     } else {
767         diag.struct_span_err(span, explain)
768     };
769
770     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
771     if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
772         err.emit();
773         return;
774     }
775     err.help(&format!("add #![feature({})] to the \
776                        crate attributes to enable",
777                       feature));
778     err.emit();
779 }
780
781 const EXPLAIN_BOX_SYNTAX: &'static str =
782     "box expression syntax is experimental; you can call `Box::new` instead.";
783
784 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
785     "attributes on non-item statements and expressions are experimental.";
786
787 pub const EXPLAIN_ASM: &'static str =
788     "inline assembly is not stable enough for use and is subject to change";
789
790 pub const EXPLAIN_LOG_SYNTAX: &'static str =
791     "`log_syntax!` is not stable enough for use and is subject to change";
792
793 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
794     "`concat_idents` is not stable enough for use and is subject to change";
795
796 pub const EXPLAIN_TRACE_MACROS: &'static str =
797     "`trace_macros` is not stable enough for use and is subject to change";
798 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
799     "allow_internal_unstable side-steps feature gating and stability checks";
800
801 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
802     "`#[derive]` for custom traits is not stable enough for use and is subject to change";
803
804 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
805     "attributes of the form `#[derive_*]` are reserved for the compiler";
806
807 pub const EXPLAIN_PLACEMENT_IN: &'static str =
808     "placement-in expression syntax is experimental and subject to change.";
809
810 struct PostExpansionVisitor<'a> {
811     context: &'a Context<'a>,
812 }
813
814 macro_rules! gate_feature_post {
815     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
816         let (cx, span) = ($cx, $span);
817         if !cx.context.cm.span_allows_unstable(span) {
818             gate_feature!(cx.context, $feature, span, $explain)
819         }
820     }}
821 }
822
823 impl<'a> PostExpansionVisitor<'a> {
824     fn check_abi(&self, abi: Abi, span: Span) {
825         match abi {
826             Abi::RustIntrinsic =>
827                 gate_feature_post!(&self, intrinsics, span,
828                                    "intrinsics are subject to change"),
829             Abi::PlatformIntrinsic => {
830                 gate_feature_post!(&self, platform_intrinsics, span,
831                                    "platform intrinsics are experimental and possibly buggy")
832             },
833             Abi::Vectorcall => {
834                 gate_feature_post!(&self, abi_vectorcall, span,
835                                    "vectorcall is experimental and subject to change")
836             }
837             Abi::RustCall => {
838                 gate_feature_post!(&self, unboxed_closures, span,
839                                    "rust-call ABI is subject to change");
840             }
841             _ => {}
842         }
843     }
844 }
845
846 impl<'a> Visitor for PostExpansionVisitor<'a> {
847     fn visit_attribute(&mut self, attr: &ast::Attribute) {
848         if !self.context.cm.span_allows_unstable(attr.span) {
849             self.context.check_attribute(attr, false);
850         }
851     }
852
853     fn visit_name(&mut self, sp: Span, name: ast::Name) {
854         if !name.as_str().is_ascii() {
855             gate_feature_post!(&self, non_ascii_idents, sp,
856                                "non-ascii idents are not fully supported.");
857         }
858     }
859
860     fn visit_item(&mut self, i: &ast::Item) {
861         match i.node {
862             ast::ItemKind::ExternCrate(_) => {
863                 if attr::contains_name(&i.attrs[..], "macro_reexport") {
864                     gate_feature_post!(&self, macro_reexport, i.span,
865                                        "macros reexports are experimental \
866                                         and possibly buggy");
867                 }
868             }
869
870             ast::ItemKind::ForeignMod(ref foreign_module) => {
871                 if attr::contains_name(&i.attrs[..], "link_args") {
872                     gate_feature_post!(&self, link_args, i.span,
873                                       "the `link_args` attribute is not portable \
874                                        across platforms, it is recommended to \
875                                        use `#[link(name = \"foo\")]` instead")
876                 }
877                 self.check_abi(foreign_module.abi, i.span);
878             }
879
880             ast::ItemKind::Fn(..) => {
881                 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
882                     gate_feature_post!(&self, plugin_registrar, i.span,
883                                        "compiler plugins are experimental and possibly buggy");
884                 }
885                 if attr::contains_name(&i.attrs[..], "start") {
886                     gate_feature_post!(&self, start, i.span,
887                                       "a #[start] function is an experimental \
888                                        feature whose signature may change \
889                                        over time");
890                 }
891                 if attr::contains_name(&i.attrs[..], "main") {
892                     gate_feature_post!(&self, main, i.span,
893                                        "declaration of a nonstandard #[main] \
894                                         function may change over time, for now \
895                                         a top-level `fn main()` is required");
896                 }
897             }
898
899             ast::ItemKind::Struct(..) => {
900                 if attr::contains_name(&i.attrs[..], "simd") {
901                     gate_feature_post!(&self, simd, i.span,
902                                        "SIMD types are experimental and possibly buggy");
903                     self.context.span_handler.span_warn(i.span,
904                                                         "the `#[simd]` attribute is deprecated, \
905                                                          use `#[repr(simd)]` instead");
906                 }
907                 for attr in &i.attrs {
908                     if attr.name() == "repr" {
909                         for item in attr.meta_item_list().unwrap_or(&[]) {
910                             if item.name() == "simd" {
911                                 gate_feature_post!(&self, repr_simd, i.span,
912                                                    "SIMD types are experimental \
913                                                     and possibly buggy");
914
915                             }
916                         }
917                     }
918                 }
919             }
920
921             ast::ItemKind::DefaultImpl(..) => {
922                 gate_feature_post!(&self, optin_builtin_traits,
923                                    i.span,
924                                    "default trait implementations are experimental \
925                                     and possibly buggy");
926             }
927
928             ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
929                 match polarity {
930                     ast::ImplPolarity::Negative => {
931                         gate_feature_post!(&self, optin_builtin_traits,
932                                            i.span,
933                                            "negative trait bounds are not yet fully implemented; \
934                                             use marker types for now");
935                     },
936                     _ => {}
937                 }
938             }
939
940             _ => {}
941         }
942
943         visit::walk_item(self, i);
944     }
945
946     fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
947         let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
948                                                                      "link_name") {
949             Some(val) => val.starts_with("llvm."),
950             _ => false
951         };
952         if links_to_llvm {
953             gate_feature_post!(&self, link_llvm_intrinsics, i.span,
954                               "linking to LLVM intrinsics is experimental");
955         }
956
957         visit::walk_foreign_item(self, i)
958     }
959
960     fn visit_ty(&mut self, ty: &ast::Ty) {
961         match ty.node {
962             ast::TyKind::BareFn(ref bare_fn_ty) => {
963                 self.check_abi(bare_fn_ty.abi, ty.span);
964             }
965             ast::TyKind::ImplTrait(..) => {
966                 gate_feature_post!(&self, conservative_impl_trait, ty.span,
967                                    "`impl Trait` is experimental");
968             }
969             ast::TyKind::Empty => {
970                 gate_feature_post!(&self, bang_type, ty.span,
971                                    "The `!` type is experimental");
972             },
973             _ => {}
974         }
975         visit::walk_ty(self, ty)
976     }
977
978     fn visit_fn_ret_ty(&mut self, ret_ty: &ast::FunctionRetTy) {
979         if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
980             match output_ty.node {
981                 ast::TyKind::Empty => return,
982                 _ => (),
983             };
984             visit::walk_ty(self, output_ty)
985         }
986     }
987
988     fn visit_expr(&mut self, e: &ast::Expr) {
989         match e.node {
990             ast::ExprKind::Box(_) => {
991                 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
992             }
993             ast::ExprKind::Type(..) => {
994                 gate_feature_post!(&self, type_ascription, e.span,
995                                   "type ascription is experimental");
996             }
997             ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
998                 gate_feature_post!(&self, inclusive_range_syntax,
999                                   e.span,
1000                                   "inclusive range syntax is experimental");
1001             }
1002             ast::ExprKind::Try(..) => {
1003                 gate_feature_post!(&self, question_mark, e.span, "the `?` operator is not stable");
1004             }
1005             ast::ExprKind::InPlace(..) => {
1006                 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1007             }
1008             _ => {}
1009         }
1010         visit::walk_expr(self, e);
1011     }
1012
1013     fn visit_pat(&mut self, pattern: &ast::Pat) {
1014         match pattern.node {
1015             PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => {
1016                 gate_feature_post!(&self, advanced_slice_patterns,
1017                                   pattern.span,
1018                                   "multiple-element slice matches anywhere \
1019                                    but at the end of a slice (e.g. \
1020                                    `[0, ..xs, 0]`) are experimental")
1021             }
1022             PatKind::Vec(..) => {
1023                 gate_feature_post!(&self, slice_patterns,
1024                                   pattern.span,
1025                                   "slice pattern syntax is experimental");
1026             }
1027             PatKind::Box(..) => {
1028                 gate_feature_post!(&self, box_patterns,
1029                                   pattern.span,
1030                                   "box pattern syntax is experimental");
1031             }
1032             PatKind::Tuple(_, ddpos)
1033                     if ddpos.is_some() => {
1034                 gate_feature_post!(&self, dotdot_in_tuple_patterns,
1035                                   pattern.span,
1036                                   "`..` in tuple patterns is experimental");
1037             }
1038             PatKind::TupleStruct(_, ref fields, ddpos)
1039                     if ddpos.is_some() && !fields.is_empty() => {
1040                 gate_feature_post!(&self, dotdot_in_tuple_patterns,
1041                                   pattern.span,
1042                                   "`..` in tuple struct patterns is experimental");
1043             }
1044             PatKind::TupleStruct(_, ref fields, ddpos)
1045                     if ddpos.is_none() && fields.is_empty() => {
1046                 gate_feature_post!(&self, relaxed_adts, pattern.span,
1047                                    "empty tuple structs patterns are unstable");
1048             }
1049             _ => {}
1050         }
1051         visit::walk_pat(self, pattern)
1052     }
1053
1054     fn visit_fn(&mut self,
1055                 fn_kind: FnKind,
1056                 fn_decl: &ast::FnDecl,
1057                 block: &ast::Block,
1058                 span: Span,
1059                 _node_id: NodeId) {
1060         // check for const fn declarations
1061         match fn_kind {
1062             FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1063                 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1064             }
1065             _ => {
1066                 // stability of const fn methods are covered in
1067                 // visit_trait_item and visit_impl_item below; this is
1068                 // because default methods don't pass through this
1069                 // point.
1070             }
1071         }
1072
1073         match fn_kind {
1074             FnKind::ItemFn(_, _, _, _, abi, _) |
1075             FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => {
1076                 self.check_abi(abi, span);
1077             }
1078             _ => {}
1079         }
1080         visit::walk_fn(self, fn_kind, fn_decl, block, span);
1081     }
1082
1083     fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
1084         match ti.node {
1085             ast::TraitItemKind::Const(..) => {
1086                 gate_feature_post!(&self, associated_consts,
1087                                   ti.span,
1088                                   "associated constants are experimental")
1089             }
1090             ast::TraitItemKind::Method(ref sig, ref block) => {
1091                 if block.is_none() {
1092                     self.check_abi(sig.abi, ti.span);
1093                 }
1094                 if sig.constness == ast::Constness::Const {
1095                     gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1096                 }
1097             }
1098             ast::TraitItemKind::Type(_, Some(_)) => {
1099                 gate_feature_post!(&self, associated_type_defaults, ti.span,
1100                                   "associated type defaults are unstable");
1101             }
1102             _ => {}
1103         }
1104         visit::walk_trait_item(self, ti);
1105     }
1106
1107     fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
1108         if ii.defaultness == ast::Defaultness::Default {
1109             gate_feature_post!(&self, specialization,
1110                               ii.span,
1111                               "specialization is unstable");
1112         }
1113
1114         match ii.node {
1115             ast::ImplItemKind::Const(..) => {
1116                 gate_feature_post!(&self, associated_consts,
1117                                   ii.span,
1118                                   "associated constants are experimental")
1119             }
1120             ast::ImplItemKind::Method(ref sig, _) => {
1121                 if sig.constness == ast::Constness::Const {
1122                     gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1123                 }
1124             }
1125             _ => {}
1126         }
1127         visit::walk_impl_item(self, ii);
1128     }
1129
1130     fn visit_variant_data(&mut self, vdata: &ast::VariantData, _: ast::Ident,
1131                           _: &ast::Generics, _: NodeId, span: Span) {
1132         if vdata.fields().is_empty() {
1133             if vdata.is_tuple() {
1134                 gate_feature_post!(&self, relaxed_adts, span,
1135                                    "empty tuple structs and enum variants are unstable, \
1136                                     use unit structs and enum variants instead");
1137             }
1138         }
1139
1140         visit::walk_struct_def(self, vdata)
1141     }
1142
1143     fn visit_vis(&mut self, vis: &ast::Visibility) {
1144         let span = match *vis {
1145             ast::Visibility::Crate(span) => span,
1146             ast::Visibility::Restricted { ref path, .. } => path.span,
1147             _ => return,
1148         };
1149         gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental");
1150
1151         visit::walk_vis(self, vis)
1152     }
1153 }
1154
1155 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1156     let mut features = Features::new();
1157
1158     for attr in krate_attrs {
1159         if !attr.check_name("feature") {
1160             continue
1161         }
1162
1163         match attr.meta_item_list() {
1164             None => {
1165                 span_err!(span_handler, attr.span, E0555,
1166                           "malformed feature attribute, expected #![feature(...)]");
1167             }
1168             Some(list) => {
1169                 for mi in list {
1170                     let name = if mi.is_word() {
1171                                    mi.name()
1172                                } else {
1173                                    span_err!(span_handler, mi.span, E0556,
1174                                              "malformed feature, expected just one word");
1175                                    continue
1176                                };
1177                     if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1178                         .find(|& &(n, _, _, _)| name == n) {
1179                         *(setter(&mut features)) = true;
1180                     }
1181                     else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1182                         .find(|& &(n, _, _)| name == n) {
1183                         span_err!(span_handler, mi.span, E0557, "feature has been removed");
1184                     }
1185                     else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1186                         .find(|& &(n, _, _)| name == n) {
1187                         features.declared_stable_lang_features.push((name, mi.span));
1188                     } else {
1189                         features.declared_lib_features.push((name, mi.span));
1190                     }
1191                 }
1192             }
1193         }
1194     }
1195
1196     features
1197 }
1198
1199 pub fn check_crate(krate: &ast::Crate,
1200                    sess: &ParseSess,
1201                    features: &Features,
1202                    plugin_attributes: &[(String, AttributeType)],
1203                    unstable: UnstableFeatures) {
1204     maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1205     let ctx = Context {
1206         features: features,
1207         span_handler: &sess.span_diagnostic,
1208         cm: sess.codemap(),
1209         plugin_attributes: plugin_attributes,
1210     };
1211     visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1212 }
1213
1214 #[derive(Clone, Copy)]
1215 pub enum UnstableFeatures {
1216     /// Hard errors for unstable features are active, as on
1217     /// beta/stable channels.
1218     Disallow,
1219     /// Allow features to me activated, as on nightly.
1220     Allow,
1221     /// Errors are bypassed for bootstrapping. This is required any time
1222     /// during the build that feature-related lints are set to warn or above
1223     /// because the build turns on warnings-as-errors and uses lots of unstable
1224     /// features. As a result, this is always required for building Rust itself.
1225     Cheat
1226 }
1227
1228 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1229                         unstable: UnstableFeatures) {
1230     let allow_features = match unstable {
1231         UnstableFeatures::Allow => true,
1232         UnstableFeatures::Disallow => false,
1233         UnstableFeatures::Cheat => true
1234     };
1235     if !allow_features {
1236         for attr in &krate.attrs {
1237             if attr.check_name("feature") {
1238                 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1239                 span_err!(span_handler, attr.span, E0554,
1240                           "#[feature] may not be used on the {} release channel",
1241                           release_channel);
1242             }
1243         }
1244     }
1245 }