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