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