]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/feature_gate.rs
ad52184a6dcb0cd658cb607b31fc5a97352ad3b6
[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
290 declare_features! (
291     (removed, import_shadowing, "1.0.0", None),
292     (removed, managed_boxes, "1.0.0", None),
293     // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
294     (removed, negate_unsigned, "1.0.0", Some(29645)),
295     // A way to temporarily opt out of opt in copy. This will *never* be accepted.
296     (removed, opt_out_copy, "1.0.0", None),
297     (removed, quad_precision_float, "1.0.0", None),
298     (removed, struct_inherit, "1.0.0", None),
299     (removed, test_removed_feature, "1.0.0", None),
300     (removed, visible_private_types, "1.0.0", None)
301 );
302
303 declare_features! (
304     (accepted, associated_types, "1.0.0", None),
305     // allow overloading augmented assignment operations like `a += b`
306     (accepted, augmented_assignments, "1.8.0", Some(28235)),
307     // allow empty structs and enum variants with braces
308     (accepted, braced_empty_structs, "1.8.0", Some(29720)),
309     (accepted, default_type_params, "1.0.0", None),
310     (accepted, globs, "1.0.0", None),
311     (accepted, if_let, "1.0.0", None),
312     // A temporary feature gate used to enable parser extensions needed
313     // to bootstrap fix for #5723.
314     (accepted, issue_5723_bootstrap, "1.0.0", None),
315     (accepted, macro_rules, "1.0.0", None),
316     // Allows using #![no_std]
317     (accepted, no_std, "1.0.0", None),
318     (accepted, slicing_syntax, "1.0.0", None),
319     (accepted, struct_variant, "1.0.0", None),
320     // These are used to test this portion of the compiler, they don't actually
321     // mean anything
322     (accepted, test_accepted_feature, "1.0.0", None),
323     (accepted, tuple_indexing, "1.0.0", None),
324     (accepted, while_let, "1.0.0", None),
325     // Allows `#[deprecated]` attribute
326     (accepted, deprecated, "1.9.0", Some(29935))
327 );
328 // (changing above list without updating src/doc/reference.md makes @cmr sad)
329
330 #[derive(PartialEq, Copy, Clone, Debug)]
331 pub enum AttributeType {
332     /// Normal, builtin attribute that is consumed
333     /// by the compiler before the unused_attribute check
334     Normal,
335
336     /// Builtin attribute that may not be consumed by the compiler
337     /// before the unused_attribute check. These attributes
338     /// will be ignored by the unused_attribute lint
339     Whitelisted,
340
341     /// Builtin attribute that is only allowed at the crate level
342     CrateLevel,
343 }
344
345 pub enum AttributeGate {
346     /// Is gated by a given feature gate, reason
347     /// and function to check if enabled
348     Gated(&'static str, &'static str, fn(&Features) -> bool),
349
350     /// Ungated attribute, can be used on all release channels
351     Ungated,
352 }
353
354 // fn() is not Debug
355 impl ::std::fmt::Debug for AttributeGate {
356     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
357         match *self {
358             Gated(ref name, ref expl, _) => write!(fmt, "Gated({}, {})", name, expl),
359             Ungated => write!(fmt, "Ungated")
360         }
361     }
362 }
363
364 macro_rules! cfg_fn {
365     ($field: ident) => {{
366         fn f(features: &Features) -> bool {
367             features.$field
368         }
369         f as fn(&Features) -> bool
370     }}
371 }
372
373 // Attributes that have a special meaning to rustc or rustdoc
374 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
375     // Normal attributes
376
377     ("warn", Normal, Ungated),
378     ("allow", Normal, Ungated),
379     ("forbid", Normal, Ungated),
380     ("deny", Normal, Ungated),
381
382     ("macro_reexport", Normal, Ungated),
383     ("macro_use", Normal, Ungated),
384     ("macro_export", Normal, Ungated),
385     ("plugin_registrar", Normal, Ungated),
386
387     ("cfg", Normal, Ungated),
388     ("cfg_attr", Normal, Ungated),
389     ("main", Normal, Ungated),
390     ("start", Normal, Ungated),
391     ("test", Normal, Ungated),
392     ("bench", Normal, Ungated),
393     ("simd", Normal, Ungated),
394     ("repr", Normal, Ungated),
395     ("path", Normal, Ungated),
396     ("abi", Normal, Ungated),
397     ("automatically_derived", Normal, Ungated),
398     ("no_mangle", Normal, Ungated),
399     ("no_link", Normal, Ungated),
400     ("derive", Normal, Ungated),
401     ("should_panic", Normal, Ungated),
402     ("ignore", Normal, Ungated),
403     ("no_implicit_prelude", Normal, Ungated),
404     ("reexport_test_harness_main", Normal, Ungated),
405     ("link_args", Normal, Ungated),
406     ("macro_escape", Normal, Ungated),
407
408     // RFC #1445.
409     ("structural_match", Whitelisted, Gated("structural_match",
410                                             "the semantics of constant patterns is \
411                                              not yet settled",
412                                             cfg_fn!(structural_match))),
413
414     // Not used any more, but we can't feature gate it
415     ("no_stack_check", Normal, Ungated),
416
417     ("plugin", CrateLevel, Gated("plugin",
418                                  "compiler plugins are experimental \
419                                   and possibly buggy",
420                                  cfg_fn!(plugin))),
421
422     ("no_std", CrateLevel, Ungated),
423     ("no_core", CrateLevel, Gated("no_core",
424                                   "no_core is experimental",
425                                   cfg_fn!(no_core))),
426     ("lang", Normal, Gated("lang_items",
427                            "language items are subject to change",
428                            cfg_fn!(lang_items))),
429     ("linkage", Whitelisted, Gated("linkage",
430                                    "the `linkage` attribute is experimental \
431                                     and not portable across platforms",
432                                    cfg_fn!(linkage))),
433     ("thread_local", Whitelisted, Gated("thread_local",
434                                         "`#[thread_local]` is an experimental feature, and does \
435                                          not currently handle destructors. There is no \
436                                          corresponding `#[task_local]` mapping to the task \
437                                          model",
438                                         cfg_fn!(thread_local))),
439
440     ("rustc_on_unimplemented", Normal, Gated("on_unimplemented",
441                                              "the `#[rustc_on_unimplemented]` attribute \
442                                               is an experimental feature",
443                                              cfg_fn!(on_unimplemented))),
444     ("allocator", Whitelisted, Gated("allocator",
445                                      "the `#[allocator]` attribute is an experimental feature",
446                                      cfg_fn!(allocator))),
447     ("needs_allocator", Normal, Gated("needs_allocator",
448                                       "the `#[needs_allocator]` \
449                                        attribute is an experimental \
450                                        feature",
451                                       cfg_fn!(needs_allocator))),
452     ("panic_runtime", Whitelisted, Gated("panic_runtime",
453                                          "the `#[panic_runtime]` attribute is \
454                                           an experimental feature",
455                                          cfg_fn!(panic_runtime))),
456     ("needs_panic_runtime", Whitelisted, Gated("needs_panic_runtime",
457                                                "the `#[needs_panic_runtime]` \
458                                                 attribute is an experimental \
459                                                 feature",
460                                                cfg_fn!(needs_panic_runtime))),
461     ("rustc_variance", Normal, Gated("rustc_attrs",
462                                      "the `#[rustc_variance]` attribute \
463                                       is just used for rustc unit tests \
464                                       and will never be stable",
465                                      cfg_fn!(rustc_attrs))),
466     ("rustc_error", Whitelisted, Gated("rustc_attrs",
467                                        "the `#[rustc_error]` attribute \
468                                         is just used for rustc unit tests \
469                                         and will never be stable",
470                                        cfg_fn!(rustc_attrs))),
471     ("rustc_if_this_changed", Whitelisted, Gated("rustc_attrs",
472                                                  "the `#[rustc_if_this_changed]` attribute \
473                                                   is just used for rustc unit tests \
474                                                   and will never be stable",
475                                                  cfg_fn!(rustc_attrs))),
476     ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs",
477                                                       "the `#[rustc_if_this_changed]` attribute \
478                                                        is just used for rustc unit tests \
479                                                        and will never be stable",
480                                                       cfg_fn!(rustc_attrs))),
481     ("rustc_dirty", Whitelisted, Gated("rustc_attrs",
482                                        "the `#[rustc_dirty]` attribute \
483                                         is just used for rustc unit tests \
484                                         and will never be stable",
485                                        cfg_fn!(rustc_attrs))),
486     ("rustc_clean", Whitelisted, Gated("rustc_attrs",
487                                        "the `#[rustc_clean]` attribute \
488                                         is just used for rustc unit tests \
489                                         and will never be stable",
490                                        cfg_fn!(rustc_attrs))),
491     ("rustc_partition_reused", Whitelisted, Gated("rustc_attrs",
492                                                   "this attribute \
493                                                    is just used for rustc unit tests \
494                                                    and will never be stable",
495                                                   cfg_fn!(rustc_attrs))),
496     ("rustc_partition_translated", Whitelisted, Gated("rustc_attrs",
497                                                       "this attribute \
498                                                        is just used for rustc unit tests \
499                                                        and will never be stable",
500                                                       cfg_fn!(rustc_attrs))),
501     ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs",
502                                              "internal rustc attributes will never be stable",
503                                              cfg_fn!(rustc_attrs))),
504     ("rustc_item_path", Whitelisted, Gated("rustc_attrs",
505                                            "internal rustc attributes will never be stable",
506                                            cfg_fn!(rustc_attrs))),
507     ("rustc_move_fragments", Normal, Gated("rustc_attrs",
508                                            "the `#[rustc_move_fragments]` attribute \
509                                             is just used for rustc unit tests \
510                                             and will never be stable",
511                                            cfg_fn!(rustc_attrs))),
512     ("rustc_mir", Whitelisted, Gated("rustc_attrs",
513                                      "the `#[rustc_mir]` attribute \
514                                       is just used for rustc unit tests \
515                                       and will never be stable",
516                                      cfg_fn!(rustc_attrs))),
517     ("rustc_no_mir", Whitelisted, Gated("rustc_attrs",
518                                         "the `#[rustc_no_mir]` attribute \
519                                          is just used to make tests pass \
520                                          and will never be stable",
521                                         cfg_fn!(rustc_attrs))),
522     ("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs",
523                                                          "the `#[rustc_inherit_overflow_checks]` \
524                                                           attribute is just used to control \
525                                                           overflow checking behavior of several \
526                                                           libcore functions that are inlined \
527                                                           across crates and will never be stable",
528                                                           cfg_fn!(rustc_attrs))),
529
530     ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
531                                               EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
532                                               cfg_fn!(allow_internal_unstable))),
533
534     ("fundamental", Whitelisted, Gated("fundamental",
535                                        "the `#[fundamental]` attribute \
536                                         is an experimental feature",
537                                        cfg_fn!(fundamental))),
538
539     ("linked_from", Normal, Gated("linked_from",
540                                   "the `#[linked_from]` attribute \
541                                    is an experimental feature",
542                                   cfg_fn!(linked_from))),
543
544     // FIXME: #14408 whitelist docs since rustdoc looks at them
545     ("doc", Whitelisted, Ungated),
546
547     // FIXME: #14406 these are processed in trans, which happens after the
548     // lint pass
549     ("cold", Whitelisted, Ungated),
550     ("naked", Whitelisted, Gated("naked_functions",
551                                  "the `#[naked]` attribute \
552                                   is an experimental feature",
553                                  cfg_fn!(naked_functions))),
554     ("export_name", Whitelisted, Ungated),
555     ("inline", Whitelisted, Ungated),
556     ("link", Whitelisted, Ungated),
557     ("link_name", Whitelisted, Ungated),
558     ("link_section", Whitelisted, Ungated),
559     ("no_builtins", Whitelisted, Ungated),
560     ("no_mangle", Whitelisted, Ungated),
561     ("no_debug", Whitelisted, Gated("no_debug",
562                                     "the `#[no_debug]` attribute \
563                                      is an experimental feature",
564                                     cfg_fn!(no_debug))),
565     ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
566                                                        "the `#[omit_gdb_pretty_printer_section]` \
567                                                         attribute is just used for the Rust test \
568                                                         suite",
569                                                        cfg_fn!(omit_gdb_pretty_printer_section))),
570     ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
571                                                "unsafe_no_drop_flag has unstable semantics \
572                                                 and may be removed in the future",
573                                                cfg_fn!(unsafe_no_drop_flag))),
574     ("unsafe_destructor_blind_to_params",
575      Normal,
576      Gated("dropck_parametricity",
577            "unsafe_destructor_blind_to_params has unstable semantics \
578             and may be removed in the future",
579            cfg_fn!(dropck_parametricity))),
580     ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental",
581                                   cfg_fn!(unwind_attributes))),
582
583     // used in resolve
584     ("prelude_import", Whitelisted, Gated("prelude_import",
585                                           "`#[prelude_import]` is for use by rustc only",
586                                           cfg_fn!(prelude_import))),
587
588     // FIXME: #14407 these are only looked at on-demand so we can't
589     // guarantee they'll have already been checked
590     ("rustc_deprecated", Whitelisted, Ungated),
591     ("must_use", Whitelisted, Ungated),
592     ("stable", Whitelisted, Ungated),
593     ("unstable", Whitelisted, Ungated),
594     ("deprecated", Normal, Ungated),
595
596     ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
597                                         "unboxed_closures are still evolving",
598                                         cfg_fn!(unboxed_closures))),
599     ("rustc_reflect_like", Whitelisted, Gated("reflect",
600                                               "defining reflective traits is still evolving",
601                                               cfg_fn!(reflect))),
602
603     // Crate level attributes
604     ("crate_name", CrateLevel, Ungated),
605     ("crate_type", CrateLevel, Ungated),
606     ("crate_id", CrateLevel, Ungated),
607     ("feature", CrateLevel, Ungated),
608     ("no_start", CrateLevel, Ungated),
609     ("no_main", CrateLevel, Ungated),
610     ("no_builtins", CrateLevel, Ungated),
611     ("recursion_limit", CrateLevel, Ungated),
612 ];
613
614 // cfg(...)'s that are feature gated
615 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
616     // (name in cfg, feature, function to check if the feature is enabled)
617     ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
618     ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
619     ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
620     ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
621 ];
622
623 #[derive(Debug, Eq, PartialEq)]
624 pub struct GatedCfg {
625     span: Span,
626     index: usize,
627 }
628
629 impl GatedCfg {
630     pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
631         let name = cfg.name();
632         GATED_CFGS.iter()
633                   .position(|info| info.0 == name)
634                   .map(|idx| {
635                       GatedCfg {
636                           span: cfg.span,
637                           index: idx
638                       }
639                   })
640     }
641
642     pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
643         let (cfg, feature, has_feature) = GATED_CFGS[self.index];
644         if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
645             let diagnostic = &sess.span_diagnostic;
646             let explain = format!("`cfg({})` is experimental and subject to change", cfg);
647             emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
648         }
649     }
650 }
651
652 struct Context<'a> {
653     features: &'a Features,
654     span_handler: &'a Handler,
655     cm: &'a CodeMap,
656     plugin_attributes: &'a [(String, AttributeType)],
657 }
658
659 macro_rules! gate_feature_fn {
660     ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
661         let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
662         let has_feature: bool = has_feature(&$cx.features);
663         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
664         if !has_feature && !cx.cm.span_allows_unstable(span) {
665             emit_feature_err(cx.span_handler, name, span, GateIssue::Language, explain);
666         }
667     }}
668 }
669
670 macro_rules! gate_feature {
671     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
672         gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
673     }
674 }
675
676 impl<'a> Context<'a> {
677     fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
678         debug!("check_attribute(attr = {:?})", attr);
679         let name = &*attr.name();
680         for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES {
681             if n == name {
682                 if let &Gated(ref name, ref desc, ref has_feature) = gateage {
683                     gate_feature_fn!(self, has_feature, attr.span, name, desc);
684                 }
685                 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
686                 return;
687             }
688         }
689         for &(ref n, ref ty) in self.plugin_attributes {
690             if n == name {
691                 // Plugins can't gate attributes, so we don't check for it
692                 // unlike the code above; we only use this loop to
693                 // short-circuit to avoid the checks below
694                 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
695                 return;
696             }
697         }
698         if name.starts_with("rustc_") {
699             gate_feature!(self, rustc_attrs, attr.span,
700                           "unless otherwise specified, attributes \
701                            with the prefix `rustc_` \
702                            are reserved for internal compiler diagnostics");
703         } else if name.starts_with("derive_") {
704             gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
705         } else {
706             // Only run the custom attribute lint during regular
707             // feature gate checking. Macro gating runs
708             // before the plugin attributes are registered
709             // so we skip this then
710             if !is_macro {
711                 gate_feature!(self, custom_attribute, attr.span,
712                               &format!("The attribute `{}` is currently \
713                                         unknown to the compiler and \
714                                         may have meaning \
715                                         added to it in the future",
716                                        name));
717             }
718         }
719     }
720 }
721
722 pub fn check_attribute(attr: &ast::Attribute, handler: &Handler,
723                        cm: &CodeMap, features: &Features) {
724     let cx = Context {
725         features: features, span_handler: handler,
726         cm: cm, plugin_attributes: &[]
727     };
728     cx.check_attribute(attr, true);
729 }
730
731 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
732     ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
733 }
734
735 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
736     if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
737         let issue = info.2;
738         // FIXME (#28244): enforce that active features have issue numbers
739         // assert!(issue.is_some())
740         issue
741     } else {
742         // search in Accepted or Removed features
743         ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES.iter())
744             .find(|t| t.0 == feature)
745             .unwrap().2
746     }
747 }
748
749 pub enum GateIssue {
750     Language,
751     Library(Option<u32>)
752 }
753
754 pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
755                         explain: &str) {
756     let issue = match issue {
757         GateIssue::Language => find_lang_feature_issue(feature),
758         GateIssue::Library(lib) => lib,
759     };
760
761     let mut err = if let Some(n) = issue {
762         diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
763     } else {
764         diag.struct_span_err(span, explain)
765     };
766
767     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
768     if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
769         err.emit();
770         return;
771     }
772     err.help(&format!("add #![feature({})] to the \
773                        crate attributes to enable",
774                       feature));
775     err.emit();
776 }
777
778 const EXPLAIN_BOX_SYNTAX: &'static str =
779     "box expression syntax is experimental; you can call `Box::new` instead.";
780
781 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
782     "attributes on non-item statements and expressions are experimental.";
783
784 pub const EXPLAIN_ASM: &'static str =
785     "inline assembly is not stable enough for use and is subject to change";
786
787 pub const EXPLAIN_LOG_SYNTAX: &'static str =
788     "`log_syntax!` is not stable enough for use and is subject to change";
789
790 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
791     "`concat_idents` is not stable enough for use and is subject to change";
792
793 pub const EXPLAIN_TRACE_MACROS: &'static str =
794     "`trace_macros` is not stable enough for use and is subject to change";
795 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
796     "allow_internal_unstable side-steps feature gating and stability checks";
797
798 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
799     "`#[derive]` for custom traits is not stable enough for use and is subject to change";
800
801 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
802     "attributes of the form `#[derive_*]` are reserved for the compiler";
803
804 pub const EXPLAIN_PLACEMENT_IN: &'static str =
805     "placement-in expression syntax is experimental and subject to change.";
806
807 struct PostExpansionVisitor<'a> {
808     context: &'a Context<'a>,
809 }
810
811 macro_rules! gate_feature_post {
812     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
813         let (cx, span) = ($cx, $span);
814         if !cx.context.cm.span_allows_unstable(span) {
815             gate_feature!(cx.context, $feature, span, $explain)
816         }
817     }}
818 }
819
820 impl<'a> PostExpansionVisitor<'a> {
821     fn check_abi(&self, abi: Abi, span: Span) {
822         match abi {
823             Abi::RustIntrinsic =>
824                 gate_feature_post!(&self, intrinsics, span,
825                                    "intrinsics are subject to change"),
826             Abi::PlatformIntrinsic => {
827                 gate_feature_post!(&self, platform_intrinsics, span,
828                                    "platform intrinsics are experimental and possibly buggy")
829             },
830             Abi::Vectorcall => {
831                 gate_feature_post!(&self, abi_vectorcall, span,
832                                    "vectorcall is experimental and subject to change")
833             }
834             Abi::RustCall => {
835                 gate_feature_post!(&self, unboxed_closures, span,
836                                    "rust-call ABI is subject to change");
837             }
838             _ => {}
839         }
840     }
841 }
842
843 impl<'a> Visitor for PostExpansionVisitor<'a> {
844     fn visit_attribute(&mut self, attr: &ast::Attribute) {
845         if !self.context.cm.span_allows_unstable(attr.span) {
846             self.context.check_attribute(attr, false);
847         }
848     }
849
850     fn visit_name(&mut self, sp: Span, name: ast::Name) {
851         if !name.as_str().is_ascii() {
852             gate_feature_post!(&self, non_ascii_idents, sp,
853                                "non-ascii idents are not fully supported.");
854         }
855     }
856
857     fn visit_item(&mut self, i: &ast::Item) {
858         match i.node {
859             ast::ItemKind::ExternCrate(_) => {
860                 if attr::contains_name(&i.attrs[..], "macro_reexport") {
861                     gate_feature_post!(&self, macro_reexport, i.span,
862                                        "macros reexports are experimental \
863                                         and possibly buggy");
864                 }
865             }
866
867             ast::ItemKind::ForeignMod(ref foreign_module) => {
868                 if attr::contains_name(&i.attrs[..], "link_args") {
869                     gate_feature_post!(&self, link_args, i.span,
870                                       "the `link_args` attribute is not portable \
871                                        across platforms, it is recommended to \
872                                        use `#[link(name = \"foo\")]` instead")
873                 }
874                 self.check_abi(foreign_module.abi, i.span);
875             }
876
877             ast::ItemKind::Fn(..) => {
878                 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
879                     gate_feature_post!(&self, plugin_registrar, i.span,
880                                        "compiler plugins are experimental and possibly buggy");
881                 }
882                 if attr::contains_name(&i.attrs[..], "start") {
883                     gate_feature_post!(&self, start, i.span,
884                                       "a #[start] function is an experimental \
885                                        feature whose signature may change \
886                                        over time");
887                 }
888                 if attr::contains_name(&i.attrs[..], "main") {
889                     gate_feature_post!(&self, main, i.span,
890                                        "declaration of a nonstandard #[main] \
891                                         function may change over time, for now \
892                                         a top-level `fn main()` is required");
893                 }
894             }
895
896             ast::ItemKind::Struct(..) => {
897                 if attr::contains_name(&i.attrs[..], "simd") {
898                     gate_feature_post!(&self, simd, i.span,
899                                        "SIMD types are experimental and possibly buggy");
900                     self.context.span_handler.span_warn(i.span,
901                                                         "the `#[simd]` attribute is deprecated, \
902                                                          use `#[repr(simd)]` instead");
903                 }
904                 for attr in &i.attrs {
905                     if attr.name() == "repr" {
906                         for item in attr.meta_item_list().unwrap_or(&[]) {
907                             if item.name() == "simd" {
908                                 gate_feature_post!(&self, repr_simd, i.span,
909                                                    "SIMD types are experimental \
910                                                     and possibly buggy");
911
912                             }
913                         }
914                     }
915                 }
916             }
917
918             ast::ItemKind::DefaultImpl(..) => {
919                 gate_feature_post!(&self, optin_builtin_traits,
920                                    i.span,
921                                    "default trait implementations are experimental \
922                                     and possibly buggy");
923             }
924
925             ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
926                 match polarity {
927                     ast::ImplPolarity::Negative => {
928                         gate_feature_post!(&self, optin_builtin_traits,
929                                            i.span,
930                                            "negative trait bounds are not yet fully implemented; \
931                                             use marker types for now");
932                     },
933                     _ => {}
934                 }
935             }
936
937             _ => {}
938         }
939
940         visit::walk_item(self, i);
941     }
942
943     fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
944         let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
945                                                                      "link_name") {
946             Some(val) => val.starts_with("llvm."),
947             _ => false
948         };
949         if links_to_llvm {
950             gate_feature_post!(&self, link_llvm_intrinsics, i.span,
951                               "linking to LLVM intrinsics is experimental");
952         }
953
954         visit::walk_foreign_item(self, i)
955     }
956
957     fn visit_ty(&mut self, ty: &ast::Ty) {
958         match ty.node {
959             ast::TyKind::BareFn(ref bare_fn_ty) => {
960                 self.check_abi(bare_fn_ty.abi, ty.span);
961             }
962             ast::TyKind::ImplTrait(..) => {
963                 gate_feature_post!(&self, conservative_impl_trait, ty.span,
964                                    "`impl Trait` is experimental");
965             }
966             _ => {}
967         }
968         visit::walk_ty(self, ty)
969     }
970
971     fn visit_expr(&mut self, e: &ast::Expr) {
972         match e.node {
973             ast::ExprKind::Box(_) => {
974                 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
975             }
976             ast::ExprKind::Type(..) => {
977                 gate_feature_post!(&self, type_ascription, e.span,
978                                   "type ascription is experimental");
979             }
980             ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
981                 gate_feature_post!(&self, inclusive_range_syntax,
982                                   e.span,
983                                   "inclusive range syntax is experimental");
984             }
985             ast::ExprKind::Try(..) => {
986                 gate_feature_post!(&self, question_mark, e.span, "the `?` operator is not stable");
987             }
988             ast::ExprKind::InPlace(..) => {
989                 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
990             }
991             _ => {}
992         }
993         visit::walk_expr(self, e);
994     }
995
996     fn visit_pat(&mut self, pattern: &ast::Pat) {
997         match pattern.node {
998             PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => {
999                 gate_feature_post!(&self, advanced_slice_patterns,
1000                                   pattern.span,
1001                                   "multiple-element slice matches anywhere \
1002                                    but at the end of a slice (e.g. \
1003                                    `[0, ..xs, 0]`) are experimental")
1004             }
1005             PatKind::Vec(..) => {
1006                 gate_feature_post!(&self, slice_patterns,
1007                                   pattern.span,
1008                                   "slice pattern syntax is experimental");
1009             }
1010             PatKind::Box(..) => {
1011                 gate_feature_post!(&self, box_patterns,
1012                                   pattern.span,
1013                                   "box pattern syntax is experimental");
1014             }
1015             PatKind::Tuple(_, ddpos)
1016                     if ddpos.is_some() => {
1017                 gate_feature_post!(&self, dotdot_in_tuple_patterns,
1018                                   pattern.span,
1019                                   "`..` in tuple patterns is experimental");
1020             }
1021             PatKind::TupleStruct(_, ref fields, ddpos)
1022                     if ddpos.is_some() && !fields.is_empty() => {
1023                 gate_feature_post!(&self, dotdot_in_tuple_patterns,
1024                                   pattern.span,
1025                                   "`..` in tuple struct patterns is experimental");
1026             }
1027             PatKind::TupleStruct(_, ref fields, ddpos)
1028                     if ddpos.is_none() && fields.is_empty() => {
1029                 gate_feature_post!(&self, relaxed_adts, pattern.span,
1030                                    "empty tuple structs patterns are unstable");
1031             }
1032             _ => {}
1033         }
1034         visit::walk_pat(self, pattern)
1035     }
1036
1037     fn visit_fn(&mut self,
1038                 fn_kind: FnKind,
1039                 fn_decl: &ast::FnDecl,
1040                 block: &ast::Block,
1041                 span: Span,
1042                 _node_id: NodeId) {
1043         // check for const fn declarations
1044         match fn_kind {
1045             FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1046                 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1047             }
1048             _ => {
1049                 // stability of const fn methods are covered in
1050                 // visit_trait_item and visit_impl_item below; this is
1051                 // because default methods don't pass through this
1052                 // point.
1053             }
1054         }
1055
1056         match fn_kind {
1057             FnKind::ItemFn(_, _, _, _, abi, _) |
1058             FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => {
1059                 self.check_abi(abi, span);
1060             }
1061             _ => {}
1062         }
1063         visit::walk_fn(self, fn_kind, fn_decl, block, span);
1064     }
1065
1066     fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
1067         match ti.node {
1068             ast::TraitItemKind::Const(..) => {
1069                 gate_feature_post!(&self, associated_consts,
1070                                   ti.span,
1071                                   "associated constants are experimental")
1072             }
1073             ast::TraitItemKind::Method(ref sig, ref block) => {
1074                 if block.is_none() {
1075                     self.check_abi(sig.abi, ti.span);
1076                 }
1077                 if sig.constness == ast::Constness::Const {
1078                     gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1079                 }
1080             }
1081             ast::TraitItemKind::Type(_, Some(_)) => {
1082                 gate_feature_post!(&self, associated_type_defaults, ti.span,
1083                                   "associated type defaults are unstable");
1084             }
1085             _ => {}
1086         }
1087         visit::walk_trait_item(self, ti);
1088     }
1089
1090     fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
1091         if ii.defaultness == ast::Defaultness::Default {
1092             gate_feature_post!(&self, specialization,
1093                               ii.span,
1094                               "specialization is unstable");
1095         }
1096
1097         match ii.node {
1098             ast::ImplItemKind::Const(..) => {
1099                 gate_feature_post!(&self, associated_consts,
1100                                   ii.span,
1101                                   "associated constants are experimental")
1102             }
1103             ast::ImplItemKind::Method(ref sig, _) => {
1104                 if sig.constness == ast::Constness::Const {
1105                     gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1106                 }
1107             }
1108             _ => {}
1109         }
1110         visit::walk_impl_item(self, ii);
1111     }
1112
1113     fn visit_variant_data(&mut self, vdata: &ast::VariantData, _: ast::Ident,
1114                           _: &ast::Generics, _: NodeId, span: Span) {
1115         if vdata.fields().is_empty() {
1116             if vdata.is_tuple() {
1117                 gate_feature_post!(&self, relaxed_adts, span,
1118                                    "empty tuple structs and enum variants are unstable, \
1119                                     use unit structs and enum variants instead");
1120             }
1121         }
1122
1123         visit::walk_struct_def(self, vdata)
1124     }
1125
1126     fn visit_vis(&mut self, vis: &ast::Visibility) {
1127         let span = match *vis {
1128             ast::Visibility::Crate(span) => span,
1129             ast::Visibility::Restricted { ref path, .. } => path.span,
1130             _ => return,
1131         };
1132         gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental");
1133
1134         visit::walk_vis(self, vis)
1135     }
1136 }
1137
1138 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1139     let mut features = Features::new();
1140
1141     for attr in krate_attrs {
1142         if !attr.check_name("feature") {
1143             continue
1144         }
1145
1146         match attr.meta_item_list() {
1147             None => {
1148                 span_err!(span_handler, attr.span, E0555,
1149                           "malformed feature attribute, expected #![feature(...)]");
1150             }
1151             Some(list) => {
1152                 for mi in list {
1153                     let name = if mi.is_word() {
1154                                    mi.name()
1155                                } else {
1156                                    span_err!(span_handler, mi.span, E0556,
1157                                              "malformed feature, expected just one word");
1158                                    continue
1159                                };
1160                     if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1161                         .find(|& &(n, _, _, _)| name == n) {
1162                         *(setter(&mut features)) = true;
1163                     }
1164                     else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1165                         .find(|& &(n, _, _)| name == n) {
1166                         span_err!(span_handler, mi.span, E0557, "feature has been removed");
1167                     }
1168                     else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1169                         .find(|& &(n, _, _)| name == n) {
1170                         features.declared_stable_lang_features.push((name, mi.span));
1171                     } else {
1172                         features.declared_lib_features.push((name, mi.span));
1173                     }
1174                 }
1175             }
1176         }
1177     }
1178
1179     features
1180 }
1181
1182 pub fn check_crate(krate: &ast::Crate,
1183                    sess: &ParseSess,
1184                    features: &Features,
1185                    plugin_attributes: &[(String, AttributeType)],
1186                    unstable: UnstableFeatures) {
1187     maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1188     let ctx = Context {
1189         features: features,
1190         span_handler: &sess.span_diagnostic,
1191         cm: sess.codemap(),
1192         plugin_attributes: plugin_attributes,
1193     };
1194     visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1195 }
1196
1197 #[derive(Clone, Copy)]
1198 pub enum UnstableFeatures {
1199     /// Hard errors for unstable features are active, as on
1200     /// beta/stable channels.
1201     Disallow,
1202     /// Allow features to me activated, as on nightly.
1203     Allow,
1204     /// Errors are bypassed for bootstrapping. This is required any time
1205     /// during the build that feature-related lints are set to warn or above
1206     /// because the build turns on warnings-as-errors and uses lots of unstable
1207     /// features. As a result, this is always required for building Rust itself.
1208     Cheat
1209 }
1210
1211 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1212                         unstable: UnstableFeatures) {
1213     let allow_features = match unstable {
1214         UnstableFeatures::Allow => true,
1215         UnstableFeatures::Disallow => false,
1216         UnstableFeatures::Cheat => true
1217     };
1218     if !allow_features {
1219         for attr in &krate.attrs {
1220             if attr.check_name("feature") {
1221                 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1222                 span_err!(span_handler, attr.span, E0554,
1223                           "#[feature] may not be used on the {} release channel",
1224                           release_channel);
1225             }
1226         }
1227     }
1228 }