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