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