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