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