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