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