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