]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/feature_gate.rs
Rollup merge of #39604 - est31:i128_tests, r=alexcrichton
[rust.git] / src / libsyntax / feature_gate.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Feature gating
12 //!
13 //! This module implements the gating necessary for preventing certain compiler
14 //! features from being used by default. This module will crawl a pre-expanded
15 //! AST to ensure that there are no features which are used that are not
16 //! enabled.
17 //!
18 //! Features are enabled in programs via the crate-level attributes of
19 //! `#![feature(...)]` with a comma-separated list of features.
20 //!
21 //! For the purpose of future feature-tracking, once code for detection of feature
22 //! gate usage is added, *do not remove it again* even once the feature
23 //! becomes stable.
24
25 use self::AttributeType::*;
26 use self::AttributeGate::*;
27
28 use abi::Abi;
29 use ast::{self, NodeId, PatKind, RangeEnd};
30 use attr;
31 use codemap::{CodeMap, Spanned};
32 use syntax_pos::Span;
33 use errors::{DiagnosticBuilder, Handler, FatalError};
34 use visit::{self, FnKind, Visitor};
35 use parse::ParseSess;
36 use symbol::Symbol;
37
38 use std::ascii::AsciiExt;
39 use std::env;
40
41 macro_rules! setter {
42     ($field: ident) => {{
43         fn f(features: &mut Features) -> &mut bool {
44             &mut features.$field
45         }
46         f as fn(&mut Features) -> &mut bool
47     }}
48 }
49
50 macro_rules! declare_features {
51     ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => {
52         /// Represents active features that are currently being implemented or
53         /// currently being considered for addition/removal.
54         const ACTIVE_FEATURES: &'static [(&'static str, &'static str,
55                                           Option<u32>, fn(&mut Features) -> &mut bool)] = &[
56             $((stringify!($feature), $ver, $issue, setter!($feature))),+
57         ];
58
59         /// A set of features to be used by later passes.
60         pub struct Features {
61             /// #![feature] attrs for stable language features, for error reporting
62             pub declared_stable_lang_features: Vec<(Symbol, Span)>,
63             /// #![feature] attrs for non-language (library) features
64             pub declared_lib_features: Vec<(Symbol, Span)>,
65             $(pub $feature: bool),+
66         }
67
68         impl Features {
69             pub fn new() -> Features {
70                 Features {
71                     declared_stable_lang_features: Vec::new(),
72                     declared_lib_features: Vec::new(),
73                     $($feature: false),+
74                 }
75             }
76         }
77     };
78
79     ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
80         /// Represents features which has since been removed (it was once Active)
81         const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
82             $((stringify!($feature), $ver, $issue)),+
83         ];
84     };
85
86     ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => {
87         /// Those language feature has since been Accepted (it was once Active)
88         const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
89             $((stringify!($feature), $ver, $issue)),+
90         ];
91     }
92 }
93
94 // If you change this list without updating src/doc/reference.md, @cmr will be sad
95 // Don't ever remove anything from this list; set them to 'Removed'.
96 // The version numbers here correspond to the version in which the current status
97 // was set. This is most important for knowing when a particular feature became
98 // stable (active).
99 // NB: The featureck.py script parses this information directly out of the source
100 // so take care when modifying it.
101
102 declare_features! (
103     (active, asm, "1.0.0", Some(29722)),
104     (active, concat_idents, "1.0.0", Some(29599)),
105     (active, link_args, "1.0.0", Some(29596)),
106     (active, log_syntax, "1.0.0", Some(29598)),
107     (active, non_ascii_idents, "1.0.0", Some(28979)),
108     (active, plugin_registrar, "1.0.0", Some(29597)),
109     (active, thread_local, "1.0.0", Some(29594)),
110     (active, trace_macros, "1.0.0", Some(29598)),
111
112     // rustc internal, for now:
113     (active, intrinsics, "1.0.0", None),
114     (active, lang_items, "1.0.0", None),
115
116     (active, link_llvm_intrinsics, "1.0.0", Some(29602)),
117     (active, linkage, "1.0.0", Some(29603)),
118     (active, quote, "1.0.0", Some(29601)),
119     (active, simd, "1.0.0", Some(27731)),
120
121
122     // rustc internal
123     (active, rustc_diagnostic_macros, "1.0.0", None),
124     (active, advanced_slice_patterns, "1.0.0", Some(23121)),
125     (active, box_syntax, "1.0.0", Some(27779)),
126     (active, placement_in_syntax, "1.0.0", Some(27779)),
127     (active, unboxed_closures, "1.0.0", Some(29625)),
128
129     (active, allocator, "1.0.0", Some(27389)),
130     (active, fundamental, "1.0.0", Some(29635)),
131     (active, main, "1.0.0", Some(29634)),
132     (active, needs_allocator, "1.4.0", Some(27389)),
133     (active, on_unimplemented, "1.0.0", Some(29628)),
134     (active, plugin, "1.0.0", Some(29597)),
135     (active, simd_ffi, "1.0.0", Some(27731)),
136     (active, start, "1.0.0", Some(29633)),
137     (active, structural_match, "1.8.0", Some(31434)),
138     (active, panic_runtime, "1.10.0", Some(32837)),
139     (active, needs_panic_runtime, "1.10.0", Some(32837)),
140
141     // OIBIT specific features
142     (active, optin_builtin_traits, "1.0.0", Some(13231)),
143
144     // macro reexport needs more discussion and stabilization
145     (active, macro_reexport, "1.0.0", Some(29638)),
146
147     // Allows use of #[staged_api]
148     // rustc internal
149     (active, staged_api, "1.0.0", None),
150
151     // Allows using #![no_core]
152     (active, no_core, "1.3.0", Some(29639)),
153
154     // Allows using `box` in patterns; RFC 469
155     (active, box_patterns, "1.0.0", Some(29641)),
156
157     // Allows using the unsafe_destructor_blind_to_params attribute;
158     // RFC 1238
159     (active, dropck_parametricity, "1.3.0", Some(28498)),
160
161     // Allows using the may_dangle attribute; RFC 1327
162     (active, dropck_eyepatch, "1.10.0", Some(34761)),
163
164     // Allows the use of custom attributes; RFC 572
165     (active, custom_attribute, "1.0.0", Some(29642)),
166
167     // Allows the use of #[derive(Anything)] as sugar for
168     // #[derive_Anything].
169     (active, custom_derive, "1.0.0", Some(29644)),
170
171     // Allows the use of rustc_* attributes; RFC 572
172     (active, rustc_attrs, "1.0.0", Some(29642)),
173
174     // Allows the use of #[allow_internal_unstable]. This is an
175     // attribute on macro_rules! and can't use the attribute handling
176     // below (it has to be checked before expansion possibly makes
177     // macros disappear).
178     //
179     // rustc internal
180     (active, allow_internal_unstable, "1.0.0", None),
181
182     // #23121. Array patterns have some hazards yet.
183     (active, slice_patterns, "1.0.0", Some(23121)),
184
185     // Allows the definition of associated constants in `trait` or `impl`
186     // blocks.
187     (active, associated_consts, "1.0.0", Some(29646)),
188
189     // Allows the definition of `const fn` functions.
190     (active, const_fn, "1.2.0", Some(24111)),
191
192     // Allows indexing into constant arrays.
193     (active, const_indexing, "1.4.0", Some(29947)),
194
195     // Allows using #[prelude_import] on glob `use` items.
196     //
197     // rustc internal
198     (active, prelude_import, "1.2.0", None),
199
200     // Allows the definition recursive static items.
201     (active, static_recursion, "1.3.0", Some(29719)),
202
203     // Allows default type parameters to influence type inference.
204     (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
205
206     // Allows associated type defaults
207     (active, associated_type_defaults, "1.2.0", Some(29661)),
208
209     // allow `repr(simd)`, and importing the various simd intrinsics
210     (active, repr_simd, "1.4.0", Some(27731)),
211
212     // Allows cfg(target_feature = "...").
213     (active, cfg_target_feature, "1.4.0", Some(29717)),
214
215     // allow `extern "platform-intrinsic" { ... }`
216     (active, platform_intrinsics, "1.4.0", Some(27731)),
217
218     // allow `#[unwind]`
219     // rust runtime internal
220     (active, unwind_attributes, "1.4.0", None),
221
222     // allow the use of `#[naked]` on functions.
223     (active, naked_functions, "1.9.0", Some(32408)),
224
225     // allow `#[no_debug]`
226     (active, no_debug, "1.5.0", Some(29721)),
227
228     // allow `#[omit_gdb_pretty_printer_section]`
229     // rustc internal.
230     (active, omit_gdb_pretty_printer_section, "1.5.0", None),
231
232     // Allows cfg(target_vendor = "...").
233     (active, cfg_target_vendor, "1.5.0", Some(29718)),
234
235     // Allow attributes on expressions and non-item statements
236     (active, stmt_expr_attributes, "1.6.0", Some(15701)),
237
238     // allow using type ascription in expressions
239     (active, type_ascription, "1.6.0", Some(23416)),
240
241     // Allows cfg(target_thread_local)
242     (active, cfg_target_thread_local, "1.7.0", Some(29594)),
243
244     // rustc internal
245     (active, abi_vectorcall, "1.7.0", None),
246
247     // a...b and ...b
248     (active, inclusive_range_syntax, "1.7.0", Some(28237)),
249
250     // X..Y patterns
251     (active, exclusive_range_pattern, "1.11.0", Some(37854)),
252
253     // impl specialization (RFC 1210)
254     (active, specialization, "1.7.0", Some(31844)),
255
256     // pub(restricted) visibilities (RFC 1422)
257     (active, pub_restricted, "1.9.0", Some(32409)),
258
259     // Allow Drop types in statics/const functions (RFC 1440)
260     (active, drop_types_in_const, "1.9.0", Some(33156)),
261
262     // Allows cfg(target_has_atomic = "...").
263     (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
264
265     // Allows `impl Trait` in function return types.
266     (active, conservative_impl_trait, "1.12.0", Some(34511)),
267
268     // Permits numeric fields in struct expressions and patterns.
269     (active, relaxed_adts, "1.12.0", Some(35626)),
270
271     // The `!` type
272     (active, never_type, "1.13.0", Some(35121)),
273
274     // Allows all literals in attribute lists and values of key-value pairs.
275     (active, attr_literals, "1.13.0", Some(34981)),
276
277     // Allows the sysV64 ABI to be specified on all platforms
278     // instead of just the platforms on which it is the C ABI
279     (active, abi_sysv64, "1.13.0", Some(36167)),
280
281     // Allows untagged unions `union U { ... }`
282     (active, untagged_unions, "1.13.0", Some(32836)),
283
284     // Used to identify the `compiler_builtins` crate
285     // rustc internal
286     (active, compiler_builtins, "1.13.0", None),
287
288     // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
289     (active, generic_param_attrs, "1.11.0", Some(34761)),
290
291     // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
292     (active, field_init_shorthand, "1.14.0", Some(37340)),
293
294     // The #![windows_subsystem] attribute
295     (active, windows_subsystem, "1.14.0", Some(37499)),
296
297     // Allows #[link(..., cfg(..))]
298     (active, link_cfg, "1.14.0", Some(37406)),
299
300     (active, use_extern_macros, "1.15.0", Some(35896)),
301
302     // Allows `break {expr}` with a value inside `loop`s.
303     (active, loop_break_value, "1.14.0", Some(37339)),
304
305     // Allows #[target_feature(...)]
306     (active, target_feature, "1.15.0", None),
307
308     // `extern "ptx-*" fn()`
309     (active, abi_ptx, "1.15.0", None),
310
311     // The `i128` type
312     (active, i128_type, "1.16.0", Some(35118)),
313
314     // The `unadjusted` ABI. Perma unstable.
315     (active, abi_unadjusted, "1.16.0", None),
316
317     // Macros 1.1
318     (active, proc_macro, "1.16.0", Some(38356)),
319
320     // Allows attributes on struct literal fields.
321     (active, struct_field_attributes, "1.16.0", Some(38814)),
322
323     // Allows #[link(kind="static-nobundle"...]
324     (active, static_nobundle, "1.16.0", Some(37403)),
325
326     // `extern "msp430-interrupt" fn()`
327     (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
328
329     // Used to identify crates that contain sanitizer runtimes
330     // rustc internal
331     (active, sanitizer_runtime, "1.17.0", None),
332 );
333
334 declare_features! (
335     (removed, import_shadowing, "1.0.0", None),
336     (removed, managed_boxes, "1.0.0", None),
337     // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
338     (removed, negate_unsigned, "1.0.0", Some(29645)),
339     (removed, reflect, "1.0.0", Some(27749)),
340     // A way to temporarily opt out of opt in copy. This will *never* be accepted.
341     (removed, opt_out_copy, "1.0.0", None),
342     (removed, quad_precision_float, "1.0.0", None),
343     (removed, struct_inherit, "1.0.0", None),
344     (removed, test_removed_feature, "1.0.0", None),
345     (removed, visible_private_types, "1.0.0", None),
346     (removed, unsafe_no_drop_flag, "1.0.0", None),
347     // Allows using items which are missing stability attributes
348     // rustc internal
349     (removed, unmarked_api, "1.0.0", None),
350     (removed, pushpop_unsafe, "1.2.0", None),
351 );
352
353 declare_features! (
354     (accepted, associated_types, "1.0.0", None),
355     // allow overloading augmented assignment operations like `a += b`
356     (accepted, augmented_assignments, "1.8.0", Some(28235)),
357     // allow empty structs and enum variants with braces
358     (accepted, braced_empty_structs, "1.8.0", Some(29720)),
359     (accepted, default_type_params, "1.0.0", None),
360     (accepted, globs, "1.0.0", None),
361     (accepted, if_let, "1.0.0", None),
362     // A temporary feature gate used to enable parser extensions needed
363     // to bootstrap fix for #5723.
364     (accepted, issue_5723_bootstrap, "1.0.0", None),
365     (accepted, macro_rules, "1.0.0", None),
366     // Allows using #![no_std]
367     (accepted, no_std, "1.6.0", None),
368     (accepted, slicing_syntax, "1.0.0", None),
369     (accepted, struct_variant, "1.0.0", None),
370     // These are used to test this portion of the compiler, they don't actually
371     // mean anything
372     (accepted, test_accepted_feature, "1.0.0", None),
373     (accepted, tuple_indexing, "1.0.0", None),
374     // Allows macros to appear in the type position.
375     (accepted, type_macros, "1.13.0", Some(27245)),
376     (accepted, while_let, "1.0.0", None),
377     // Allows `#[deprecated]` attribute
378     (accepted, deprecated, "1.9.0", Some(29935)),
379     // `expr?`
380     (accepted, question_mark, "1.13.0", Some(31436)),
381     // Allows `..` in tuple (struct) patterns
382     (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
383     (accepted, item_like_imports, "1.14.0", Some(35120)),
384     // Allows using `Self` and associated types in struct expressions and patterns.
385     (accepted, more_struct_aliases, "1.16.0", Some(37544)),
386     // elide `'static` lifetimes in `static`s and `const`s
387     (accepted, static_in_const, "1.17.0", Some(35897)),
388 );
389 // (changing above list without updating src/doc/reference.md makes @cmr sad)
390
391 #[derive(PartialEq, Copy, Clone, Debug)]
392 pub enum AttributeType {
393     /// Normal, builtin attribute that is consumed
394     /// by the compiler before the unused_attribute check
395     Normal,
396
397     /// Builtin attribute that may not be consumed by the compiler
398     /// before the unused_attribute check. These attributes
399     /// will be ignored by the unused_attribute lint
400     Whitelisted,
401
402     /// Builtin attribute that is only allowed at the crate level
403     CrateLevel,
404 }
405
406 pub enum AttributeGate {
407     /// Is gated by a given feature gate, reason
408     /// and function to check if enabled
409     Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
410
411     /// Ungated attribute, can be used on all release channels
412     Ungated,
413 }
414
415 impl AttributeGate {
416     fn is_deprecated(&self) -> bool {
417         match *self {
418             Gated(Stability::Deprecated(_), ..) => true,
419             _ => false,
420         }
421     }
422 }
423
424 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
425 pub enum Stability {
426     Unstable,
427     // Argument is tracking issue link.
428     Deprecated(&'static str),
429 }
430
431 // fn() is not Debug
432 impl ::std::fmt::Debug for AttributeGate {
433     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
434         match *self {
435             Gated(ref stab, ref name, ref expl, _) =>
436                 write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
437             Ungated => write!(fmt, "Ungated")
438         }
439     }
440 }
441
442 macro_rules! cfg_fn {
443     ($field: ident) => {{
444         fn f(features: &Features) -> bool {
445             features.$field
446         }
447         f as fn(&Features) -> bool
448     }}
449 }
450
451 pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
452     BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
453 }
454
455 pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
456     BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name))
457 }
458
459 // Attributes that have a special meaning to rustc or rustdoc
460 pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
461     // Normal attributes
462
463     ("warn", Normal, Ungated),
464     ("allow", Normal, Ungated),
465     ("forbid", Normal, Ungated),
466     ("deny", Normal, Ungated),
467
468     ("macro_reexport", Normal, Ungated),
469     ("macro_use", Normal, Ungated),
470     ("macro_export", Normal, Ungated),
471     ("plugin_registrar", Normal, Ungated),
472
473     ("cfg", Normal, Ungated),
474     ("cfg_attr", Normal, Ungated),
475     ("main", Normal, Ungated),
476     ("start", Normal, Ungated),
477     ("test", Normal, Ungated),
478     ("bench", Normal, Ungated),
479     ("simd", Normal, Ungated),
480     ("repr", Normal, Ungated),
481     ("path", Normal, Ungated),
482     ("abi", Normal, Ungated),
483     ("automatically_derived", Normal, Ungated),
484     ("no_mangle", Normal, Ungated),
485     ("no_link", Normal, Ungated),
486     ("derive", Normal, Ungated),
487     ("should_panic", Normal, Ungated),
488     ("ignore", Normal, Ungated),
489     ("no_implicit_prelude", Normal, Ungated),
490     ("reexport_test_harness_main", Normal, Ungated),
491     ("link_args", Normal, Ungated),
492     ("macro_escape", Normal, Ungated),
493
494     // RFC #1445.
495     ("structural_match", Whitelisted, Gated(Stability::Unstable,
496                                             "structural_match",
497                                             "the semantics of constant patterns is \
498                                              not yet settled",
499                                             cfg_fn!(structural_match))),
500
501     // Not used any more, but we can't feature gate it
502     ("no_stack_check", Normal, Ungated),
503
504     ("plugin", CrateLevel, Gated(Stability::Unstable,
505                                  "plugin",
506                                  "compiler plugins are experimental \
507                                   and possibly buggy",
508                                  cfg_fn!(plugin))),
509
510     ("no_std", CrateLevel, Ungated),
511     ("no_core", CrateLevel, Gated(Stability::Unstable,
512                                   "no_core",
513                                   "no_core is experimental",
514                                   cfg_fn!(no_core))),
515     ("lang", Normal, Gated(Stability::Unstable,
516                            "lang_items",
517                            "language items are subject to change",
518                            cfg_fn!(lang_items))),
519     ("linkage", Whitelisted, Gated(Stability::Unstable,
520                                    "linkage",
521                                    "the `linkage` attribute is experimental \
522                                     and not portable across platforms",
523                                    cfg_fn!(linkage))),
524     ("thread_local", Whitelisted, Gated(Stability::Unstable,
525                                         "thread_local",
526                                         "`#[thread_local]` is an experimental feature, and does \
527                                          not currently handle destructors. There is no \
528                                          corresponding `#[task_local]` mapping to the task \
529                                          model",
530                                         cfg_fn!(thread_local))),
531
532     ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
533                                              "on_unimplemented",
534                                              "the `#[rustc_on_unimplemented]` attribute \
535                                               is an experimental feature",
536                                              cfg_fn!(on_unimplemented))),
537     ("allocator", Whitelisted, Gated(Stability::Unstable,
538                                      "allocator",
539                                      "the `#[allocator]` attribute is an experimental feature",
540                                      cfg_fn!(allocator))),
541     ("needs_allocator", Normal, Gated(Stability::Unstable,
542                                       "needs_allocator",
543                                       "the `#[needs_allocator]` \
544                                        attribute is an experimental \
545                                        feature",
546                                       cfg_fn!(needs_allocator))),
547     ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
548                                          "panic_runtime",
549                                          "the `#[panic_runtime]` attribute is \
550                                           an experimental feature",
551                                          cfg_fn!(panic_runtime))),
552     ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
553                                                "needs_panic_runtime",
554                                                "the `#[needs_panic_runtime]` \
555                                                 attribute is an experimental \
556                                                 feature",
557                                                cfg_fn!(needs_panic_runtime))),
558     ("rustc_variance", Normal, Gated(Stability::Unstable,
559                                      "rustc_attrs",
560                                      "the `#[rustc_variance]` attribute \
561                                       is just used for rustc unit tests \
562                                       and will never be stable",
563                                      cfg_fn!(rustc_attrs))),
564     ("rustc_error", Whitelisted, Gated(Stability::Unstable,
565                                        "rustc_attrs",
566                                        "the `#[rustc_error]` attribute \
567                                         is just used for rustc unit tests \
568                                         and will never be stable",
569                                        cfg_fn!(rustc_attrs))),
570     ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
571                                                  "rustc_attrs",
572                                                  "the `#[rustc_if_this_changed]` attribute \
573                                                   is just used for rustc unit tests \
574                                                   and will never be stable",
575                                                  cfg_fn!(rustc_attrs))),
576     ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
577                                                       "rustc_attrs",
578                                                       "the `#[rustc_if_this_changed]` attribute \
579                                                        is just used for rustc unit tests \
580                                                        and will never be stable",
581                                                       cfg_fn!(rustc_attrs))),
582     ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
583                                        "rustc_attrs",
584                                        "the `#[rustc_dirty]` attribute \
585                                         is just used for rustc unit tests \
586                                         and will never be stable",
587                                        cfg_fn!(rustc_attrs))),
588     ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
589                                        "rustc_attrs",
590                                        "the `#[rustc_clean]` attribute \
591                                         is just used for rustc unit tests \
592                                         and will never be stable",
593                                        cfg_fn!(rustc_attrs))),
594     ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
595                                                 "rustc_attrs",
596                                                 "the `#[rustc_metadata_dirty]` attribute \
597                                                  is just used for rustc unit tests \
598                                                  and will never be stable",
599                                                  cfg_fn!(rustc_attrs))),
600     ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
601                                                 "rustc_attrs",
602                                                 "the `#[rustc_metadata_clean]` attribute \
603                                                  is just used for rustc unit tests \
604                                                  and will never be stable",
605                                                  cfg_fn!(rustc_attrs))),
606     ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
607                                                   "rustc_attrs",
608                                                   "this attribute \
609                                                    is just used for rustc unit tests \
610                                                    and will never be stable",
611                                                   cfg_fn!(rustc_attrs))),
612     ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
613                                                       "rustc_attrs",
614                                                       "this attribute \
615                                                        is just used for rustc unit tests \
616                                                        and will never be stable",
617                                                       cfg_fn!(rustc_attrs))),
618     ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
619                                              "rustc_attrs",
620                                              "internal rustc attributes will never be stable",
621                                              cfg_fn!(rustc_attrs))),
622     ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
623                                            "rustc_attrs",
624                                            "internal rustc attributes will never be stable",
625                                            cfg_fn!(rustc_attrs))),
626     ("rustc_move_fragments", Normal, Gated(Stability::Unstable,
627                                            "rustc_attrs",
628                                            "the `#[rustc_move_fragments]` attribute \
629                                             is just used for rustc unit tests \
630                                             and will never be stable",
631                                            cfg_fn!(rustc_attrs))),
632     ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
633                                      "rustc_attrs",
634                                      "the `#[rustc_mir]` attribute \
635                                       is just used for rustc unit tests \
636                                       and will never be stable",
637                                      cfg_fn!(rustc_attrs))),
638     ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
639                                                          "rustc_attrs",
640                                                          "the `#[rustc_inherit_overflow_checks]` \
641                                                           attribute is just used to control \
642                                                           overflow checking behavior of several \
643                                                           libcore functions that are inlined \
644                                                           across crates and will never be stable",
645                                                           cfg_fn!(rustc_attrs))),
646     ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
647                                              "compiler_builtins",
648                                              "the `#[compiler_builtins]` attribute is used to \
649                                               identify the `compiler_builtins` crate which \
650                                               contains compiler-rt intrinsics and will never be \
651                                               stable",
652                                           cfg_fn!(compiler_builtins))),
653     ("sanitizer_runtime", Whitelisted, Gated(Stability::Unstable,
654                                              "sanitizer_runtime",
655                                              "the `#[sanitizer_runtime]` attribute is used to \
656                                               identify crates that contain the runtime of a \
657                                               sanitizer and will never be stable",
658                                              cfg_fn!(sanitizer_runtime))),
659
660     ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
661                                               "allow_internal_unstable",
662                                               EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
663                                               cfg_fn!(allow_internal_unstable))),
664
665     ("fundamental", Whitelisted, Gated(Stability::Unstable,
666                                        "fundamental",
667                                        "the `#[fundamental]` attribute \
668                                         is an experimental feature",
669                                        cfg_fn!(fundamental))),
670
671     ("proc_macro_derive", Normal, Ungated),
672
673     ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
674                                                    "rustc_attrs",
675                                                    "internal implementation detail",
676                                                    cfg_fn!(rustc_attrs))),
677
678     // FIXME: #14408 whitelist docs since rustdoc looks at them
679     ("doc", Whitelisted, Ungated),
680
681     // FIXME: #14406 these are processed in trans, which happens after the
682     // lint pass
683     ("cold", Whitelisted, Ungated),
684     ("naked", Whitelisted, Gated(Stability::Unstable,
685                                  "naked_functions",
686                                  "the `#[naked]` attribute \
687                                   is an experimental feature",
688                                  cfg_fn!(naked_functions))),
689     ("target_feature", Whitelisted, Gated(
690         Stability::Unstable, "target_feature",
691         "the `#[target_feature]` attribute is an experimental feature",
692         cfg_fn!(target_feature))),
693     ("export_name", Whitelisted, Ungated),
694     ("inline", Whitelisted, Ungated),
695     ("link", Whitelisted, Ungated),
696     ("link_name", Whitelisted, Ungated),
697     ("link_section", Whitelisted, Ungated),
698     ("no_builtins", Whitelisted, Ungated),
699     ("no_mangle", Whitelisted, Ungated),
700     ("no_debug", Whitelisted, Gated(
701         Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
702         "no_debug",
703         "the `#[no_debug]` attribute is an experimental feature",
704         cfg_fn!(no_debug))),
705     ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
706                                                        "omit_gdb_pretty_printer_section",
707                                                        "the `#[omit_gdb_pretty_printer_section]` \
708                                                         attribute is just used for the Rust test \
709                                                         suite",
710                                                        cfg_fn!(omit_gdb_pretty_printer_section))),
711     ("unsafe_destructor_blind_to_params",
712      Normal,
713      Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761"),
714            "dropck_parametricity",
715            "unsafe_destructor_blind_to_params has been replaced by \
716             may_dangle and will be removed in the future",
717            cfg_fn!(dropck_parametricity))),
718     ("may_dangle",
719      Normal,
720      Gated(Stability::Unstable,
721            "dropck_eyepatch",
722            "may_dangle has unstable semantics and may be removed in the future",
723            cfg_fn!(dropck_eyepatch))),
724     ("unwind", Whitelisted, Gated(Stability::Unstable,
725                                   "unwind_attributes",
726                                   "#[unwind] is experimental",
727                                   cfg_fn!(unwind_attributes))),
728
729     // used in resolve
730     ("prelude_import", Whitelisted, Gated(Stability::Unstable,
731                                           "prelude_import",
732                                           "`#[prelude_import]` is for use by rustc only",
733                                           cfg_fn!(prelude_import))),
734
735     // FIXME: #14407 these are only looked at on-demand so we can't
736     // guarantee they'll have already been checked
737     ("rustc_deprecated", Whitelisted, Ungated),
738     ("must_use", Whitelisted, Ungated),
739     ("stable", Whitelisted, Ungated),
740     ("unstable", Whitelisted, Ungated),
741     ("deprecated", Normal, Ungated),
742
743     ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
744                                         "unboxed_closures",
745                                         "unboxed_closures are still evolving",
746                                         cfg_fn!(unboxed_closures))),
747
748     ("windows_subsystem", Whitelisted, Gated(Stability::Unstable,
749                                              "windows_subsystem",
750                                              "the windows subsystem attribute \
751                                               is currently unstable",
752                                              cfg_fn!(windows_subsystem))),
753
754     ("proc_macro_attribute", Normal, Gated(Stability::Unstable,
755                                            "proc_macro",
756                                            "attribute proc macros are currently unstable",
757                                            cfg_fn!(proc_macro))),
758
759     ("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
760                                              "rustc_derive_registrar",
761                                              "used internally by rustc",
762                                              cfg_fn!(rustc_attrs))),
763
764     // Crate level attributes
765     ("crate_name", CrateLevel, Ungated),
766     ("crate_type", CrateLevel, Ungated),
767     ("crate_id", CrateLevel, Ungated),
768     ("feature", CrateLevel, Ungated),
769     ("no_start", CrateLevel, Ungated),
770     ("no_main", CrateLevel, Ungated),
771     ("no_builtins", CrateLevel, Ungated),
772     ("recursion_limit", CrateLevel, Ungated),
773     ("type_length_limit", CrateLevel, Ungated),
774 ];
775
776 // cfg(...)'s that are feature gated
777 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
778     // (name in cfg, feature, function to check if the feature is enabled)
779     ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
780     ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
781     ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
782     ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
783 ];
784
785 #[derive(Debug, Eq, PartialEq)]
786 pub struct GatedCfg {
787     span: Span,
788     index: usize,
789 }
790
791 impl GatedCfg {
792     pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
793         let name = &*cfg.name().as_str();
794         GATED_CFGS.iter()
795                   .position(|info| info.0 == name)
796                   .map(|idx| {
797                       GatedCfg {
798                           span: cfg.span,
799                           index: idx
800                       }
801                   })
802     }
803
804     pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
805         let (cfg, feature, has_feature) = GATED_CFGS[self.index];
806         if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
807             let explain = format!("`cfg({})` is experimental and subject to change", cfg);
808             emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
809         }
810     }
811 }
812
813 struct Context<'a> {
814     features: &'a Features,
815     parse_sess: &'a ParseSess,
816     cm: &'a CodeMap,
817     plugin_attributes: &'a [(String, AttributeType)],
818 }
819
820 macro_rules! gate_feature_fn {
821     ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
822         let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
823         let has_feature: bool = has_feature(&$cx.features);
824         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
825         if !has_feature && !cx.cm.span_allows_unstable(span) {
826             emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
827         }
828     }}
829 }
830
831 macro_rules! gate_feature {
832     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
833         gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
834     }
835 }
836
837 impl<'a> Context<'a> {
838     fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
839         debug!("check_attribute(attr = {:?})", attr);
840         let name = &*attr.name().as_str();
841         for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
842             if n == name {
843                 if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
844                     gate_feature_fn!(self, has_feature, attr.span, name, desc);
845                 }
846                 debug!("check_attribute: {:?} is builtin, {:?}, {:?}", name, ty, gateage);
847                 return;
848             }
849         }
850         for &(ref n, ref ty) in self.plugin_attributes {
851             if n == name {
852                 // Plugins can't gate attributes, so we don't check for it
853                 // unlike the code above; we only use this loop to
854                 // short-circuit to avoid the checks below
855                 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
856                 return;
857             }
858         }
859         if name.starts_with("rustc_") {
860             gate_feature!(self, rustc_attrs, attr.span,
861                           "unless otherwise specified, attributes \
862                            with the prefix `rustc_` \
863                            are reserved for internal compiler diagnostics");
864         } else if name.starts_with("derive_") {
865             gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
866         } else if attr::is_known(attr) {
867             debug!("check_attribute: {:?} is known", name);
868         } else {
869             // Only run the custom attribute lint during regular
870             // feature gate checking. Macro gating runs
871             // before the plugin attributes are registered
872             // so we skip this then
873             if !is_macro {
874                 gate_feature!(self, custom_attribute, attr.span,
875                               &format!("The attribute `{}` is currently \
876                                         unknown to the compiler and \
877                                         may have meaning \
878                                         added to it in the future",
879                                        name));
880             }
881         }
882     }
883 }
884
885 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
886                        cm: &CodeMap, features: &Features) {
887     let cx = Context {
888         features: features, parse_sess: parse_sess,
889         cm: cm, plugin_attributes: &[]
890     };
891     cx.check_attribute(attr, true);
892 }
893
894 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
895     ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
896 }
897
898 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
899     if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
900         let issue = info.2;
901         // FIXME (#28244): enforce that active features have issue numbers
902         // assert!(issue.is_some())
903         issue
904     } else {
905         // search in Accepted or Removed features
906         match ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).find(|t| t.0 == feature) {
907             Some(&(_, _, issue)) => issue,
908             None => panic!("Feature `{}` is not declared anywhere", feature),
909         }
910     }
911 }
912
913 pub enum GateIssue {
914     Language,
915     Library(Option<u32>)
916 }
917
918 pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
919                         explain: &str) {
920     feature_err(sess, feature, span, issue, explain).emit();
921 }
922
923 pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
924                    explain: &str) -> DiagnosticBuilder<'a> {
925     let diag = &sess.span_diagnostic;
926
927     let issue = match issue {
928         GateIssue::Language => find_lang_feature_issue(feature),
929         GateIssue::Library(lib) => lib,
930     };
931
932     let mut err = if let Some(n) = issue {
933         diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
934     } else {
935         diag.struct_span_err(span, explain)
936     };
937
938     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
939     if sess.unstable_features.is_nightly_build() {
940         err.help(&format!("add #![feature({})] to the \
941                            crate attributes to enable",
942                           feature));
943     }
944
945     err
946 }
947
948 const EXPLAIN_BOX_SYNTAX: &'static str =
949     "box expression syntax is experimental; you can call `Box::new` instead.";
950
951 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
952     "attributes on non-item statements and expressions are experimental.";
953
954 pub const EXPLAIN_ASM: &'static str =
955     "inline assembly is not stable enough for use and is subject to change";
956
957 pub const EXPLAIN_LOG_SYNTAX: &'static str =
958     "`log_syntax!` is not stable enough for use and is subject to change";
959
960 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
961     "`concat_idents` is not stable enough for use and is subject to change";
962
963 pub const EXPLAIN_TRACE_MACROS: &'static str =
964     "`trace_macros` is not stable enough for use and is subject to change";
965 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
966     "allow_internal_unstable side-steps feature gating and stability checks";
967
968 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
969     "`#[derive]` for custom traits is deprecated and will be removed in the future.";
970
971 pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
972     "`#[derive]` for custom traits is deprecated and will be removed in the future. \
973     Prefer using procedural macro custom derive.";
974
975 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
976     "attributes of the form `#[derive_*]` are reserved for the compiler";
977
978 pub const EXPLAIN_PLACEMENT_IN: &'static str =
979     "placement-in expression syntax is experimental and subject to change.";
980
981 struct PostExpansionVisitor<'a> {
982     context: &'a Context<'a>,
983 }
984
985 macro_rules! gate_feature_post {
986     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
987         let (cx, span) = ($cx, $span);
988         if !cx.context.cm.span_allows_unstable(span) {
989             gate_feature!(cx.context, $feature, span, $explain)
990         }
991     }}
992 }
993
994 impl<'a> PostExpansionVisitor<'a> {
995     fn check_abi(&self, abi: Abi, span: Span) {
996         match abi {
997             Abi::RustIntrinsic => {
998                 gate_feature_post!(&self, intrinsics, span,
999                                    "intrinsics are subject to change");
1000             },
1001             Abi::PlatformIntrinsic => {
1002                 gate_feature_post!(&self, platform_intrinsics, span,
1003                                    "platform intrinsics are experimental and possibly buggy");
1004             },
1005             Abi::Vectorcall => {
1006                 gate_feature_post!(&self, abi_vectorcall, span,
1007                                    "vectorcall is experimental and subject to change");
1008             },
1009             Abi::RustCall => {
1010                 gate_feature_post!(&self, unboxed_closures, span,
1011                                    "rust-call ABI is subject to change");
1012             },
1013             Abi::SysV64 => {
1014                 gate_feature_post!(&self, abi_sysv64, span,
1015                                    "sysv64 ABI is experimental and subject to change");
1016             },
1017             Abi::PtxKernel => {
1018                 gate_feature_post!(&self, abi_ptx, span,
1019                                    "PTX ABIs are experimental and subject to change");
1020             },
1021             Abi::Unadjusted => {
1022                 gate_feature_post!(&self, abi_unadjusted, span,
1023                                    "unadjusted ABI is an implementation detail and perma-unstable");
1024             },
1025             Abi::Msp430Interrupt => {
1026                 gate_feature_post!(&self, abi_msp430_interrupt, span,
1027                                    "msp430-interrupt ABI is experimental and subject to change");
1028             },
1029             // Stable
1030             Abi::Cdecl |
1031             Abi::Stdcall |
1032             Abi::Fastcall |
1033             Abi::Aapcs |
1034             Abi::Win64 |
1035             Abi::Rust |
1036             Abi::C |
1037             Abi::System => {}
1038         }
1039     }
1040 }
1041
1042 fn contains_novel_literal(item: &ast::MetaItem) -> bool {
1043     use ast::MetaItemKind::*;
1044     use ast::NestedMetaItemKind::*;
1045
1046     match item.node {
1047         Word => false,
1048         NameValue(ref lit) => !lit.node.is_str(),
1049         List(ref list) => list.iter().any(|li| {
1050             match li.node {
1051                 MetaItem(ref mi) => contains_novel_literal(&mi),
1052                 Literal(_) => true,
1053             }
1054         }),
1055     }
1056 }
1057
1058 fn starts_with_digit(s: &str) -> bool {
1059     s.as_bytes().first().cloned().map_or(false, |b| b >= b'0' && b <= b'9')
1060 }
1061
1062 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1063     fn visit_attribute(&mut self, attr: &ast::Attribute) {
1064         if !self.context.cm.span_allows_unstable(attr.span) {
1065             // check for gated attributes
1066             self.context.check_attribute(attr, false);
1067         }
1068
1069         if contains_novel_literal(&attr.value) {
1070             gate_feature_post!(&self, attr_literals, attr.span,
1071                                "non-string literals in attributes, or string \
1072                                literals in top-level positions, are experimental");
1073         }
1074     }
1075
1076     fn visit_name(&mut self, sp: Span, name: ast::Name) {
1077         if !name.as_str().is_ascii() {
1078             gate_feature_post!(&self, non_ascii_idents, sp,
1079                                "non-ascii idents are not fully supported.");
1080         }
1081     }
1082
1083     fn visit_item(&mut self, i: &'a ast::Item) {
1084         match i.node {
1085             ast::ItemKind::ExternCrate(_) => {
1086                 if attr::contains_name(&i.attrs[..], "macro_reexport") {
1087                     gate_feature_post!(&self, macro_reexport, i.span,
1088                                        "macros reexports are experimental \
1089                                         and possibly buggy");
1090                 }
1091             }
1092
1093             ast::ItemKind::ForeignMod(ref foreign_module) => {
1094                 if attr::contains_name(&i.attrs[..], "link_args") {
1095                     gate_feature_post!(&self, link_args, i.span,
1096                                       "the `link_args` attribute is not portable \
1097                                        across platforms, it is recommended to \
1098                                        use `#[link(name = \"foo\")]` instead")
1099                 }
1100                 self.check_abi(foreign_module.abi, i.span);
1101             }
1102
1103             ast::ItemKind::Fn(..) => {
1104                 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1105                     gate_feature_post!(&self, plugin_registrar, i.span,
1106                                        "compiler plugins are experimental and possibly buggy");
1107                 }
1108                 if attr::contains_name(&i.attrs[..], "start") {
1109                     gate_feature_post!(&self, start, i.span,
1110                                       "a #[start] function is an experimental \
1111                                        feature whose signature may change \
1112                                        over time");
1113                 }
1114                 if attr::contains_name(&i.attrs[..], "main") {
1115                     gate_feature_post!(&self, main, i.span,
1116                                        "declaration of a nonstandard #[main] \
1117                                         function may change over time, for now \
1118                                         a top-level `fn main()` is required");
1119                 }
1120             }
1121
1122             ast::ItemKind::Struct(..) => {
1123                 if attr::contains_name(&i.attrs[..], "simd") {
1124                     gate_feature_post!(&self, simd, i.span,
1125                                        "SIMD types are experimental and possibly buggy");
1126                     self.context.parse_sess.span_diagnostic.span_warn(i.span,
1127                                                                       "the `#[simd]` attribute \
1128                                                                        is deprecated, use \
1129                                                                        `#[repr(simd)]` instead");
1130                 }
1131                 for attr in &i.attrs {
1132                     if attr.name() == "repr" {
1133                         for item in attr.meta_item_list().unwrap_or(&[]) {
1134                             if item.check_name("simd") {
1135                                 gate_feature_post!(&self, repr_simd, i.span,
1136                                                    "SIMD types are experimental \
1137                                                     and possibly buggy");
1138
1139                             }
1140                         }
1141                     }
1142                 }
1143             }
1144
1145             ast::ItemKind::Union(..) => {
1146                 gate_feature_post!(&self, untagged_unions,
1147                                    i.span,
1148                                    "unions are unstable and possibly buggy");
1149             }
1150
1151             ast::ItemKind::DefaultImpl(..) => {
1152                 gate_feature_post!(&self, optin_builtin_traits,
1153                                    i.span,
1154                                    "default trait implementations are experimental \
1155                                     and possibly buggy");
1156             }
1157
1158             ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
1159                 match polarity {
1160                     ast::ImplPolarity::Negative => {
1161                         gate_feature_post!(&self, optin_builtin_traits,
1162                                            i.span,
1163                                            "negative trait bounds are not yet fully implemented; \
1164                                             use marker types for now");
1165                     },
1166                     _ => {}
1167                 }
1168             }
1169
1170             _ => {}
1171         }
1172
1173         visit::walk_item(self, i);
1174     }
1175
1176     fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
1177         let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
1178             Some(val) => val.as_str().starts_with("llvm."),
1179             _ => false
1180         };
1181         if links_to_llvm {
1182             gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1183                               "linking to LLVM intrinsics is experimental");
1184         }
1185
1186         visit::walk_foreign_item(self, i)
1187     }
1188
1189     fn visit_ty(&mut self, ty: &'a ast::Ty) {
1190         match ty.node {
1191             ast::TyKind::BareFn(ref bare_fn_ty) => {
1192                 self.check_abi(bare_fn_ty.abi, ty.span);
1193             }
1194             ast::TyKind::ImplTrait(..) => {
1195                 gate_feature_post!(&self, conservative_impl_trait, ty.span,
1196                                    "`impl Trait` is experimental");
1197             }
1198             ast::TyKind::Never => {
1199                 gate_feature_post!(&self, never_type, ty.span,
1200                                    "The `!` type is experimental");
1201             },
1202             _ => {}
1203         }
1204         visit::walk_ty(self, ty)
1205     }
1206
1207     fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
1208         if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
1209             match output_ty.node {
1210                 ast::TyKind::Never => return,
1211                 _ => (),
1212             };
1213             self.visit_ty(output_ty)
1214         }
1215     }
1216
1217     fn visit_expr(&mut self, e: &'a ast::Expr) {
1218         match e.node {
1219             ast::ExprKind::Box(_) => {
1220                 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1221             }
1222             ast::ExprKind::Type(..) => {
1223                 gate_feature_post!(&self, type_ascription, e.span,
1224                                   "type ascription is experimental");
1225             }
1226             ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1227                 gate_feature_post!(&self, inclusive_range_syntax,
1228                                   e.span,
1229                                   "inclusive range syntax is experimental");
1230             }
1231             ast::ExprKind::InPlace(..) => {
1232                 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1233             }
1234             ast::ExprKind::Struct(_, ref fields, _) => {
1235                 for field in fields {
1236                     if field.is_shorthand {
1237                         gate_feature_post!(&self, field_init_shorthand, field.span,
1238                                            "struct field shorthands are unstable");
1239                     }
1240                     if starts_with_digit(&field.ident.node.name.as_str()) {
1241                         gate_feature_post!(&self, relaxed_adts,
1242                                           field.span,
1243                                           "numeric fields in struct expressions are unstable");
1244                     }
1245                 }
1246             }
1247             ast::ExprKind::Break(_, Some(_)) => {
1248                 gate_feature_post!(&self, loop_break_value, e.span,
1249                                    "`break` with a value is experimental");
1250             }
1251             ast::ExprKind::Lit(ref lit) => {
1252                 if let ast::LitKind::Int(_, ref ty) = lit.node {
1253                     match *ty {
1254                         ast::LitIntType::Signed(ast::IntTy::I128) |
1255                         ast::LitIntType::Unsigned(ast::UintTy::U128) => {
1256                             gate_feature_post!(&self, i128_type, e.span,
1257                                                "128-bit integers are not stable");
1258                         }
1259                         _ => {}
1260                     }
1261                 }
1262             }
1263             _ => {}
1264         }
1265         visit::walk_expr(self, e);
1266     }
1267
1268     fn visit_pat(&mut self, pattern: &'a ast::Pat) {
1269         match pattern.node {
1270             PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
1271                 gate_feature_post!(&self, advanced_slice_patterns,
1272                                   pattern.span,
1273                                   "multiple-element slice matches anywhere \
1274                                    but at the end of a slice (e.g. \
1275                                    `[0, ..xs, 0]`) are experimental")
1276             }
1277             PatKind::Slice(..) => {
1278                 gate_feature_post!(&self, slice_patterns,
1279                                   pattern.span,
1280                                   "slice pattern syntax is experimental");
1281             }
1282             PatKind::Box(..) => {
1283                 gate_feature_post!(&self, box_patterns,
1284                                   pattern.span,
1285                                   "box pattern syntax is experimental");
1286             }
1287             PatKind::Struct(_, ref fields, _) => {
1288                 for field in fields {
1289                     if starts_with_digit(&field.node.ident.name.as_str()) {
1290                         gate_feature_post!(&self, relaxed_adts,
1291                                           field.span,
1292                                           "numeric fields in struct patterns are unstable");
1293                     }
1294                 }
1295             }
1296             PatKind::Range(_, _, RangeEnd::Excluded) => {
1297                 gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
1298                                    "exclusive range pattern syntax is experimental");
1299             }
1300             _ => {}
1301         }
1302         visit::walk_pat(self, pattern)
1303     }
1304
1305     fn visit_fn(&mut self,
1306                 fn_kind: FnKind<'a>,
1307                 fn_decl: &'a ast::FnDecl,
1308                 span: Span,
1309                 _node_id: NodeId) {
1310         // check for const fn declarations
1311         match fn_kind {
1312             FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => {
1313                 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1314             }
1315             _ => {
1316                 // stability of const fn methods are covered in
1317                 // visit_trait_item and visit_impl_item below; this is
1318                 // because default methods don't pass through this
1319                 // point.
1320             }
1321         }
1322
1323         match fn_kind {
1324             FnKind::ItemFn(_, _, _, _, abi, _, _) |
1325             FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
1326                 self.check_abi(abi, span);
1327             }
1328             _ => {}
1329         }
1330         visit::walk_fn(self, fn_kind, fn_decl, span);
1331     }
1332
1333     fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1334         match ti.node {
1335             ast::TraitItemKind::Const(..) => {
1336                 gate_feature_post!(&self, associated_consts,
1337                                   ti.span,
1338                                   "associated constants are experimental")
1339             }
1340             ast::TraitItemKind::Method(ref sig, ref block) => {
1341                 if block.is_none() {
1342                     self.check_abi(sig.abi, ti.span);
1343                 }
1344                 if sig.constness.node == ast::Constness::Const {
1345                     gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1346                 }
1347             }
1348             ast::TraitItemKind::Type(_, Some(_)) => {
1349                 gate_feature_post!(&self, associated_type_defaults, ti.span,
1350                                   "associated type defaults are unstable");
1351             }
1352             _ => {}
1353         }
1354         visit::walk_trait_item(self, ti);
1355     }
1356
1357     fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
1358         if ii.defaultness == ast::Defaultness::Default {
1359             gate_feature_post!(&self, specialization,
1360                               ii.span,
1361                               "specialization is unstable");
1362         }
1363
1364         match ii.node {
1365             ast::ImplItemKind::Const(..) => {
1366                 gate_feature_post!(&self, associated_consts,
1367                                   ii.span,
1368                                   "associated constants are experimental")
1369             }
1370             ast::ImplItemKind::Method(ref sig, _) => {
1371                 if sig.constness.node == ast::Constness::Const {
1372                     gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1373                 }
1374             }
1375             _ => {}
1376         }
1377         visit::walk_impl_item(self, ii);
1378     }
1379
1380     fn visit_vis(&mut self, vis: &'a ast::Visibility) {
1381         let span = match *vis {
1382             ast::Visibility::Crate(span) => span,
1383             ast::Visibility::Restricted { ref path, .. } => path.span,
1384             _ => return,
1385         };
1386         gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental");
1387
1388         visit::walk_vis(self, vis)
1389     }
1390
1391     fn visit_generics(&mut self, g: &'a ast::Generics) {
1392         for t in &g.ty_params {
1393             if !t.attrs.is_empty() {
1394                 gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
1395                                    "attributes on type parameter bindings are experimental");
1396             }
1397         }
1398         visit::walk_generics(self, g)
1399     }
1400
1401     fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) {
1402         if !lifetime_def.attrs.is_empty() {
1403             gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
1404                                "attributes on lifetime bindings are experimental");
1405         }
1406         visit::walk_lifetime_def(self, lifetime_def)
1407     }
1408 }
1409
1410 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1411     let mut features = Features::new();
1412
1413     let mut feature_checker = MutexFeatureChecker::default();
1414
1415     for attr in krate_attrs {
1416         if !attr.check_name("feature") {
1417             continue
1418         }
1419
1420         match attr.meta_item_list() {
1421             None => {
1422                 span_err!(span_handler, attr.span, E0555,
1423                           "malformed feature attribute, expected #![feature(...)]");
1424             }
1425             Some(list) => {
1426                 for mi in list {
1427                     let name = if let Some(word) = mi.word() {
1428                         word.name()
1429                     } else {
1430                         span_err!(span_handler, mi.span, E0556,
1431                                   "malformed feature, expected just one word");
1432                         continue
1433                     };
1434
1435                     if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1436                         .find(|& &(n, _, _, _)| name == n) {
1437                         *(setter(&mut features)) = true;
1438                         feature_checker.collect(&features, mi.span);
1439                     }
1440                     else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1441                         .find(|& &(n, _, _)| name == n) {
1442                         span_err!(span_handler, mi.span, E0557, "feature has been removed");
1443                     }
1444                     else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1445                         .find(|& &(n, _, _)| name == n) {
1446                         features.declared_stable_lang_features.push((name, mi.span));
1447                     } else {
1448                         features.declared_lib_features.push((name, mi.span));
1449                     }
1450                 }
1451             }
1452         }
1453     }
1454
1455     feature_checker.check(span_handler);
1456
1457     features
1458 }
1459
1460 // A collector for mutually-exclusive features and their flag spans
1461 #[derive(Default)]
1462 struct MutexFeatureChecker {
1463     proc_macro: Option<Span>,
1464     custom_attribute: Option<Span>,
1465 }
1466
1467 impl MutexFeatureChecker {
1468     // If this method turns out to be a hotspot due to branching,
1469     // the branching can be eliminated by modifying `setter!()` to set these spans
1470     // only for the features that need to be checked for mutual exclusion.
1471     fn collect(&mut self, features: &Features, span: Span) {
1472         if features.proc_macro {
1473             // If self.proc_macro is None, set to Some(span)
1474             self.proc_macro = self.proc_macro.or(Some(span));
1475         }
1476
1477         if features.custom_attribute {
1478             self.custom_attribute = self.custom_attribute.or(Some(span));
1479         }
1480     }
1481
1482     fn check(self, handler: &Handler) {
1483         if let (Some(pm_span), Some(ca_span)) = (self.proc_macro, self.custom_attribute) {
1484             handler.struct_span_err(pm_span, "Cannot use `#![feature(proc_macro)]` and \
1485                                               `#![feature(custom_attribute)] at the same time")
1486                 .span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
1487                 .emit();
1488
1489             panic!(FatalError);
1490         }
1491     }
1492 }
1493
1494 pub fn check_crate(krate: &ast::Crate,
1495                    sess: &ParseSess,
1496                    features: &Features,
1497                    plugin_attributes: &[(String, AttributeType)],
1498                    unstable: UnstableFeatures) {
1499     maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1500     let ctx = Context {
1501         features: features,
1502         parse_sess: sess,
1503         cm: sess.codemap(),
1504         plugin_attributes: plugin_attributes,
1505     };
1506     visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1507 }
1508
1509 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1510 pub enum UnstableFeatures {
1511     /// Hard errors for unstable features are active, as on
1512     /// beta/stable channels.
1513     Disallow,
1514     /// Allow features to be activated, as on nightly.
1515     Allow,
1516     /// Errors are bypassed for bootstrapping. This is required any time
1517     /// during the build that feature-related lints are set to warn or above
1518     /// because the build turns on warnings-as-errors and uses lots of unstable
1519     /// features. As a result, this is always required for building Rust itself.
1520     Cheat
1521 }
1522
1523 impl UnstableFeatures {
1524     pub fn from_environment() -> UnstableFeatures {
1525         // Whether this is a feature-staged build, i.e. on the beta or stable channel
1526         let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1527         // Whether we should enable unstable features for bootstrapping
1528         let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
1529         match (disable_unstable_features, bootstrap) {
1530             (_, true) => UnstableFeatures::Cheat,
1531             (true, _) => UnstableFeatures::Disallow,
1532             (false, _) => UnstableFeatures::Allow
1533         }
1534     }
1535
1536     pub fn is_nightly_build(&self) -> bool {
1537         match *self {
1538             UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1539             _ => false,
1540         }
1541     }
1542 }
1543
1544 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1545                         unstable: UnstableFeatures) {
1546     let allow_features = match unstable {
1547         UnstableFeatures::Allow => true,
1548         UnstableFeatures::Disallow => false,
1549         UnstableFeatures::Cheat => true
1550     };
1551     if !allow_features {
1552         for attr in &krate.attrs {
1553             if attr.check_name("feature") {
1554                 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1555                 span_err!(span_handler, attr.span, E0554,
1556                           "#[feature] may not be used on the {} release channel",
1557                           release_channel);
1558             }
1559         }
1560     }
1561 }