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