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