]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/feature_gate.rs
Auto merge of #43648 - RalfJung:jemalloc-debug, r=alexcrichton
[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! set {
42     (proc_macro) => {{
43         fn f(features: &mut Features, span: Span) {
44             features.declared_lib_features.push((Symbol::intern("proc_macro"), span));
45             features.proc_macro = true;
46         }
47         f as fn(&mut Features, Span)
48     }};
49     ($field: ident) => {{
50         fn f(features: &mut Features, _: Span) {
51             features.$field = true;
52         }
53         f as fn(&mut Features, Span)
54     }}
55 }
56
57 macro_rules! declare_features {
58     ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => {
59         /// Represents active features that are currently being implemented or
60         /// currently being considered for addition/removal.
61         const ACTIVE_FEATURES:
62                 &'static [(&'static str, &'static str, Option<u32>, fn(&mut Features, Span))] =
63             &[$((stringify!($feature), $ver, $issue, set!($feature))),+];
64
65         /// A set of features to be used by later passes.
66         pub struct Features {
67             /// #![feature] attrs for stable language features, for error reporting
68             pub declared_stable_lang_features: Vec<(Symbol, Span)>,
69             /// #![feature] attrs for non-language (library) features
70             pub declared_lib_features: Vec<(Symbol, Span)>,
71             $(pub $feature: bool),+
72         }
73
74         impl Features {
75             pub fn new() -> Features {
76                 Features {
77                     declared_stable_lang_features: Vec::new(),
78                     declared_lib_features: Vec::new(),
79                     $($feature: false),+
80                 }
81             }
82         }
83     };
84
85     ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
86         /// Represents unstable features which have since been removed (it was once Active)
87         const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
88             $((stringify!($feature), $ver, $issue)),+
89         ];
90     };
91
92     ($((stable_removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
93         /// Represents stable features which have since been removed (it was once Accepted)
94         const STABLE_REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
95             $((stringify!($feature), $ver, $issue)),+
96         ];
97     };
98
99     ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => {
100         /// Those language feature has since been Accepted (it was once Active)
101         const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
102             $((stringify!($feature), $ver, $issue)),+
103         ];
104     }
105 }
106
107 // If you change this, please modify src/doc/unstable-book as well.
108 //
109 // Don't ever remove anything from this list; set them to 'Removed'.
110 //
111 // The version numbers here correspond to the version in which the current status
112 // was set. This is most important for knowing when a particular feature became
113 // stable (active).
114 //
115 // NB: tools/tidy/src/features.rs parses this information directly out of the
116 // source, so take care when modifying it.
117
118 declare_features! (
119     (active, asm, "1.0.0", Some(29722)),
120     (active, concat_idents, "1.0.0", Some(29599)),
121     (active, link_args, "1.0.0", Some(29596)),
122     (active, log_syntax, "1.0.0", Some(29598)),
123     (active, non_ascii_idents, "1.0.0", Some(28979)),
124     (active, plugin_registrar, "1.0.0", Some(29597)),
125     (active, thread_local, "1.0.0", Some(29594)),
126     (active, trace_macros, "1.0.0", Some(29598)),
127
128     // rustc internal, for now:
129     (active, intrinsics, "1.0.0", None),
130     (active, lang_items, "1.0.0", None),
131
132     (active, link_llvm_intrinsics, "1.0.0", Some(29602)),
133     (active, linkage, "1.0.0", Some(29603)),
134     (active, quote, "1.0.0", Some(29601)),
135     (active, simd, "1.0.0", Some(27731)),
136
137
138     // rustc internal
139     (active, rustc_diagnostic_macros, "1.0.0", None),
140     (active, advanced_slice_patterns, "1.0.0", Some(23121)),
141     (active, box_syntax, "1.0.0", Some(27779)),
142     (active, placement_in_syntax, "1.0.0", Some(27779)),
143     (active, unboxed_closures, "1.0.0", Some(29625)),
144
145     (active, fundamental, "1.0.0", Some(29635)),
146     (active, main, "1.0.0", Some(29634)),
147     (active, needs_allocator, "1.4.0", Some(27389)),
148     (active, on_unimplemented, "1.0.0", Some(29628)),
149     (active, plugin, "1.0.0", Some(29597)),
150     (active, simd_ffi, "1.0.0", Some(27731)),
151     (active, start, "1.0.0", Some(29633)),
152     (active, structural_match, "1.8.0", Some(31434)),
153     (active, panic_runtime, "1.10.0", Some(32837)),
154     (active, needs_panic_runtime, "1.10.0", Some(32837)),
155
156     // OIBIT specific features
157     (active, optin_builtin_traits, "1.0.0", Some(13231)),
158
159     // macro reexport needs more discussion and stabilization
160     (active, macro_reexport, "1.0.0", Some(29638)),
161
162     // Allows use of #[staged_api]
163     // rustc internal
164     (active, staged_api, "1.0.0", None),
165
166     // Allows using #![no_core]
167     (active, no_core, "1.3.0", Some(29639)),
168
169     // Allows using `box` in patterns; RFC 469
170     (active, box_patterns, "1.0.0", Some(29641)),
171
172     // Allows using the unsafe_destructor_blind_to_params attribute;
173     // RFC 1238
174     (active, dropck_parametricity, "1.3.0", Some(28498)),
175
176     // Allows using the may_dangle attribute; RFC 1327
177     (active, dropck_eyepatch, "1.10.0", Some(34761)),
178
179     // Allows the use of custom attributes; RFC 572
180     (active, custom_attribute, "1.0.0", Some(29642)),
181
182     // Allows the use of #[derive(Anything)] as sugar for
183     // #[derive_Anything].
184     (active, custom_derive, "1.0.0", Some(29644)),
185
186     // Allows the use of rustc_* attributes; RFC 572
187     (active, rustc_attrs, "1.0.0", Some(29642)),
188
189     // Allows the use of #[allow_internal_unstable]. This is an
190     // attribute on macro_rules! and can't use the attribute handling
191     // below (it has to be checked before expansion possibly makes
192     // macros disappear).
193     //
194     // rustc internal
195     (active, allow_internal_unstable, "1.0.0", None),
196
197     // Allows the use of #[allow_internal_unsafe]. This is an
198     // attribute on macro_rules! and can't use the attribute handling
199     // below (it has to be checked before expansion possibly makes
200     // macros disappear).
201     //
202     // rustc internal
203     (active, allow_internal_unsafe, "1.0.0", None),
204
205     // #23121. Array patterns have some hazards yet.
206     (active, slice_patterns, "1.0.0", Some(23121)),
207
208     // Allows the definition of `const fn` functions.
209     (active, const_fn, "1.2.0", Some(24111)),
210
211     // Allows indexing into constant arrays.
212     (active, const_indexing, "1.4.0", Some(29947)),
213
214     // Allows using #[prelude_import] on glob `use` items.
215     //
216     // rustc internal
217     (active, prelude_import, "1.2.0", None),
218
219     // Allows default type parameters to influence type inference.
220     (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
221
222     // Allows associated type defaults
223     (active, associated_type_defaults, "1.2.0", Some(29661)),
224
225     // allow `repr(simd)`, and importing the various simd intrinsics
226     (active, repr_simd, "1.4.0", Some(27731)),
227
228     // Allows cfg(target_feature = "...").
229     (active, cfg_target_feature, "1.4.0", Some(29717)),
230
231     // allow `extern "platform-intrinsic" { ... }`
232     (active, platform_intrinsics, "1.4.0", Some(27731)),
233
234     // allow `#[unwind]`
235     // rust runtime internal
236     (active, unwind_attributes, "1.4.0", None),
237
238     // allow the use of `#[naked]` on functions.
239     (active, naked_functions, "1.9.0", Some(32408)),
240
241     // allow `#[no_debug]`
242     (active, no_debug, "1.5.0", Some(29721)),
243
244     // allow `#[omit_gdb_pretty_printer_section]`
245     // rustc internal.
246     (active, omit_gdb_pretty_printer_section, "1.5.0", None),
247
248     // Allows cfg(target_vendor = "...").
249     (active, cfg_target_vendor, "1.5.0", Some(29718)),
250
251     // Allow attributes on expressions and non-item statements
252     (active, stmt_expr_attributes, "1.6.0", Some(15701)),
253
254     // allow using type ascription in expressions
255     (active, type_ascription, "1.6.0", Some(23416)),
256
257     // Allows cfg(target_thread_local)
258     (active, cfg_target_thread_local, "1.7.0", Some(29594)),
259
260     // rustc internal
261     (active, abi_vectorcall, "1.7.0", None),
262
263     // a...b and ...b
264     (active, inclusive_range_syntax, "1.7.0", Some(28237)),
265
266     // X..Y patterns
267     (active, exclusive_range_pattern, "1.11.0", Some(37854)),
268
269     // impl specialization (RFC 1210)
270     (active, specialization, "1.7.0", Some(31844)),
271
272     // Allow Drop types in statics/const functions (RFC 1440)
273     (active, drop_types_in_const, "1.9.0", Some(33156)),
274
275     // Allows cfg(target_has_atomic = "...").
276     (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
277
278     // Allows `impl Trait` in function return types.
279     (active, conservative_impl_trait, "1.12.0", Some(34511)),
280
281     // The `!` type
282     (active, never_type, "1.13.0", Some(35121)),
283
284     // Allows all literals in attribute lists and values of key-value pairs.
285     (active, attr_literals, "1.13.0", Some(34981)),
286
287     // Allows the sysV64 ABI to be specified on all platforms
288     // instead of just the platforms on which it is the C ABI
289     (active, abi_sysv64, "1.13.0", Some(36167)),
290
291     // Allows untagged unions `union U { ... }`
292     (active, untagged_unions, "1.13.0", Some(32836)),
293
294     // Used to identify the `compiler_builtins` crate
295     // rustc internal
296     (active, compiler_builtins, "1.13.0", None),
297
298     // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
299     (active, generic_param_attrs, "1.11.0", Some(34761)),
300
301     // Allows #[link(..., cfg(..))]
302     (active, link_cfg, "1.14.0", Some(37406)),
303
304     (active, use_extern_macros, "1.15.0", Some(35896)),
305
306     // Allows #[target_feature(...)]
307     (active, target_feature, "1.15.0", None),
308
309     // `extern "ptx-*" fn()`
310     (active, abi_ptx, "1.15.0", None),
311
312     // The `i128` type
313     (active, i128_type, "1.16.0", Some(35118)),
314
315     // The `unadjusted` ABI. Perma unstable.
316     (active, abi_unadjusted, "1.16.0", None),
317
318     // Procedural macros 2.0.
319     (active, proc_macro, "1.16.0", Some(38356)),
320
321     // Declarative macros 2.0 (`macro`).
322     (active, decl_macro, "1.17.0", Some(39412)),
323
324     // Allows #[link(kind="static-nobundle"...]
325     (active, static_nobundle, "1.16.0", Some(37403)),
326
327     // `extern "msp430-interrupt" fn()`
328     (active, abi_msp430_interrupt, "1.16.0", Some(38487)),
329
330     // Used to identify crates that contain sanitizer runtimes
331     // rustc internal
332     (active, sanitizer_runtime, "1.17.0", None),
333
334     // Used to identify crates that contain the profiler runtime
335     // rustc internal
336     (active, profiler_runtime, "1.18.0", None),
337
338     // `extern "x86-interrupt" fn()`
339     (active, abi_x86_interrupt, "1.17.0", Some(40180)),
340
341
342     // Allows the `catch {...}` expression
343     (active, catch_expr, "1.17.0", Some(31436)),
344
345     // Allows `repr(align(u16))` struct attribute (RFC 1358)
346     (active, repr_align, "1.17.0", Some(33626)),
347
348     // Used to preserve symbols (see llvm.used)
349     (active, used, "1.18.0", Some(40289)),
350
351     // Allows module-level inline assembly by way of global_asm!()
352     (active, global_asm, "1.18.0", Some(35119)),
353
354     // Allows overlapping impls of marker traits
355     (active, overlapping_marker_traits, "1.18.0", Some(29864)),
356
357     // Allows use of the :vis macro fragment specifier
358     (active, macro_vis_matcher, "1.18.0", Some(41022)),
359
360     // rustc internal
361     (active, abi_thiscall, "1.19.0", None),
362
363     // Allows a test to fail without failing the whole suite
364     (active, allow_fail, "1.19.0", Some(42219)),
365
366     // Allows unsized tuple coercion.
367     (active, unsized_tuple_coercion, "1.20.0", Some(42877)),
368
369     // Generators
370     (active, generators, "1.21.0", None),
371
372
373     // global allocators and their internals
374     (active, global_allocator, "1.20.0", None),
375     (active, allocator_internals, "1.20.0", None),
376
377     // #[doc(cfg(...))]
378     (active, doc_cfg, "1.21.0", Some(43781)),
379
380     // allow `#[must_use]` on functions (RFC 1940)
381     (active, fn_must_use, "1.21.0", Some(43302)),
382 );
383
384 declare_features! (
385     (removed, import_shadowing, "1.0.0", None),
386     (removed, managed_boxes, "1.0.0", None),
387     // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
388     (removed, negate_unsigned, "1.0.0", Some(29645)),
389     (removed, reflect, "1.0.0", Some(27749)),
390     // A way to temporarily opt out of opt in copy. This will *never* be accepted.
391     (removed, opt_out_copy, "1.0.0", None),
392     (removed, quad_precision_float, "1.0.0", None),
393     (removed, struct_inherit, "1.0.0", None),
394     (removed, test_removed_feature, "1.0.0", None),
395     (removed, visible_private_types, "1.0.0", None),
396     (removed, unsafe_no_drop_flag, "1.0.0", None),
397     // Allows using items which are missing stability attributes
398     // rustc internal
399     (removed, unmarked_api, "1.0.0", None),
400     (removed, pushpop_unsafe, "1.2.0", None),
401     (removed, allocator, "1.0.0", None),
402 );
403
404 declare_features! (
405     (stable_removed, no_stack_check, "1.0.0", None),
406 );
407
408 declare_features! (
409     (accepted, associated_types, "1.0.0", None),
410     // allow overloading augmented assignment operations like `a += b`
411     (accepted, augmented_assignments, "1.8.0", Some(28235)),
412     // allow empty structs and enum variants with braces
413     (accepted, braced_empty_structs, "1.8.0", Some(29720)),
414     (accepted, default_type_params, "1.0.0", None),
415     (accepted, globs, "1.0.0", None),
416     (accepted, if_let, "1.0.0", None),
417     // A temporary feature gate used to enable parser extensions needed
418     // to bootstrap fix for #5723.
419     (accepted, issue_5723_bootstrap, "1.0.0", None),
420     (accepted, macro_rules, "1.0.0", None),
421     // Allows using #![no_std]
422     (accepted, no_std, "1.6.0", None),
423     (accepted, slicing_syntax, "1.0.0", None),
424     (accepted, struct_variant, "1.0.0", None),
425     // These are used to test this portion of the compiler, they don't actually
426     // mean anything
427     (accepted, test_accepted_feature, "1.0.0", None),
428     (accepted, tuple_indexing, "1.0.0", None),
429     // Allows macros to appear in the type position.
430     (accepted, type_macros, "1.13.0", Some(27245)),
431     (accepted, while_let, "1.0.0", None),
432     // Allows `#[deprecated]` attribute
433     (accepted, deprecated, "1.9.0", Some(29935)),
434     // `expr?`
435     (accepted, question_mark, "1.13.0", Some(31436)),
436     // Allows `..` in tuple (struct) patterns
437     (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
438     (accepted, item_like_imports, "1.15.0", Some(35120)),
439     // Allows using `Self` and associated types in struct expressions and patterns.
440     (accepted, more_struct_aliases, "1.16.0", Some(37544)),
441     // elide `'static` lifetimes in `static`s and `const`s
442     (accepted, static_in_const, "1.17.0", Some(35897)),
443     // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
444     (accepted, field_init_shorthand, "1.17.0", Some(37340)),
445     // Allows the definition recursive static items.
446     (accepted, static_recursion, "1.17.0", Some(29719)),
447     // pub(restricted) visibilities (RFC 1422)
448     (accepted, pub_restricted, "1.18.0", Some(32409)),
449     // The #![windows_subsystem] attribute
450     (accepted, windows_subsystem, "1.18.0", Some(37499)),
451     // Allows `break {expr}` with a value inside `loop`s.
452     (accepted, loop_break_value, "1.19.0", Some(37339)),
453     // Permits numeric fields in struct expressions and patterns.
454     (accepted, relaxed_adts, "1.19.0", Some(35626)),
455     // Coerces non capturing closures to function pointers
456     (accepted, closure_to_fn_coercion, "1.19.0", Some(39817)),
457     // Allows attributes on struct literal fields.
458     (accepted, struct_field_attributes, "1.20.0", Some(38814)),
459     // Allows the definition of associated constants in `trait` or `impl`
460     // blocks.
461     (accepted, associated_consts, "1.20.0", Some(29646)),
462     // Usage of the `compile_error!` macro
463     (accepted, compile_error, "1.20.0", Some(40872)),
464     // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
465     (accepted, rvalue_static_promotion, "1.21.0", Some(38865)),
466 );
467
468 // If you change this, please modify src/doc/unstable-book as well. You must
469 // move that documentation into the relevant place in the other docs, and
470 // remove the chapter on the flag.
471
472 #[derive(PartialEq, Copy, Clone, Debug)]
473 pub enum AttributeType {
474     /// Normal, builtin attribute that is consumed
475     /// by the compiler before the unused_attribute check
476     Normal,
477
478     /// Builtin attribute that may not be consumed by the compiler
479     /// before the unused_attribute check. These attributes
480     /// will be ignored by the unused_attribute lint
481     Whitelisted,
482
483     /// Builtin attribute that is only allowed at the crate level
484     CrateLevel,
485 }
486
487 pub enum AttributeGate {
488     /// Is gated by a given feature gate, reason
489     /// and function to check if enabled
490     Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
491
492     /// Ungated attribute, can be used on all release channels
493     Ungated,
494 }
495
496 impl AttributeGate {
497     fn is_deprecated(&self) -> bool {
498         match *self {
499             Gated(Stability::Deprecated(_), ..) => true,
500             _ => false,
501         }
502     }
503 }
504
505 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
506 pub enum Stability {
507     Unstable,
508     // Argument is tracking issue link.
509     Deprecated(&'static str),
510 }
511
512 // fn() is not Debug
513 impl ::std::fmt::Debug for AttributeGate {
514     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
515         match *self {
516             Gated(ref stab, name, expl, _) =>
517                 write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
518             Ungated => write!(fmt, "Ungated")
519         }
520     }
521 }
522
523 macro_rules! cfg_fn {
524     ($field: ident) => {{
525         fn f(features: &Features) -> bool {
526             features.$field
527         }
528         f as fn(&Features) -> bool
529     }}
530 }
531
532 pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
533     BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
534 }
535
536 pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
537     BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name))
538 }
539
540 // Attributes that have a special meaning to rustc or rustdoc
541 pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
542     // Normal attributes
543
544     ("warn", Normal, Ungated),
545     ("allow", Normal, Ungated),
546     ("forbid", Normal, Ungated),
547     ("deny", Normal, Ungated),
548
549     ("macro_reexport", Normal, Ungated),
550     ("macro_use", Normal, Ungated),
551     ("macro_export", Normal, Ungated),
552     ("plugin_registrar", Normal, Ungated),
553
554     ("cfg", Normal, Ungated),
555     ("cfg_attr", Normal, Ungated),
556     ("main", Normal, Ungated),
557     ("start", Normal, Ungated),
558     ("test", Normal, Ungated),
559     ("bench", Normal, Ungated),
560     ("simd", Normal, Ungated),
561     ("repr", Normal, Ungated),
562     ("path", Normal, Ungated),
563     ("abi", Normal, Ungated),
564     ("automatically_derived", Normal, Ungated),
565     ("no_mangle", Normal, Ungated),
566     ("no_link", Normal, Ungated),
567     ("derive", Normal, Ungated),
568     ("should_panic", Normal, Ungated),
569     ("ignore", Normal, Ungated),
570     ("no_implicit_prelude", Normal, Ungated),
571     ("reexport_test_harness_main", Normal, Ungated),
572     ("link_args", Normal, Gated(Stability::Unstable,
573                                 "link_args",
574                                 "the `link_args` attribute is experimental and not \
575                                  portable across platforms, it is recommended to \
576                                  use `#[link(name = \"foo\")] instead",
577                                 cfg_fn!(link_args))),
578     ("macro_escape", Normal, Ungated),
579
580     // RFC #1445.
581     ("structural_match", Whitelisted, Gated(Stability::Unstable,
582                                             "structural_match",
583                                             "the semantics of constant patterns is \
584                                              not yet settled",
585                                             cfg_fn!(structural_match))),
586
587     ("plugin", CrateLevel, Gated(Stability::Unstable,
588                                  "plugin",
589                                  "compiler plugins are experimental \
590                                   and possibly buggy",
591                                  cfg_fn!(plugin))),
592
593     ("no_std", CrateLevel, Ungated),
594     ("no_core", CrateLevel, Gated(Stability::Unstable,
595                                   "no_core",
596                                   "no_core is experimental",
597                                   cfg_fn!(no_core))),
598     ("lang", Normal, Gated(Stability::Unstable,
599                            "lang_items",
600                            "language items are subject to change",
601                            cfg_fn!(lang_items))),
602     ("linkage", Whitelisted, Gated(Stability::Unstable,
603                                    "linkage",
604                                    "the `linkage` attribute is experimental \
605                                     and not portable across platforms",
606                                    cfg_fn!(linkage))),
607     ("thread_local", Whitelisted, Gated(Stability::Unstable,
608                                         "thread_local",
609                                         "`#[thread_local]` is an experimental feature, and does \
610                                          not currently handle destructors. There is no \
611                                          corresponding `#[task_local]` mapping to the task \
612                                          model",
613                                         cfg_fn!(thread_local))),
614
615     ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
616                                              "on_unimplemented",
617                                              "the `#[rustc_on_unimplemented]` attribute \
618                                               is an experimental feature",
619                                              cfg_fn!(on_unimplemented))),
620     ("global_allocator", Normal, Gated(Stability::Unstable,
621                                        "global_allocator",
622                                        "the `#[global_allocator]` attribute is \
623                                         an experimental feature",
624                                        cfg_fn!(global_allocator))),
625     ("default_lib_allocator", Whitelisted, Gated(Stability::Unstable,
626                                             "allocator_internals",
627                                             "the `#[default_lib_allocator]` \
628                                              attribute is an experimental feature",
629                                             cfg_fn!(allocator_internals))),
630     ("needs_allocator", Normal, Gated(Stability::Unstable,
631                                       "allocator_internals",
632                                       "the `#[needs_allocator]` \
633                                        attribute is an experimental \
634                                        feature",
635                                       cfg_fn!(allocator_internals))),
636     ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
637                                          "panic_runtime",
638                                          "the `#[panic_runtime]` attribute is \
639                                           an experimental feature",
640                                          cfg_fn!(panic_runtime))),
641     ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
642                                                "needs_panic_runtime",
643                                                "the `#[needs_panic_runtime]` \
644                                                 attribute is an experimental \
645                                                 feature",
646                                                cfg_fn!(needs_panic_runtime))),
647     ("rustc_variance", Normal, Gated(Stability::Unstable,
648                                      "rustc_attrs",
649                                      "the `#[rustc_variance]` attribute \
650                                       is just used for rustc unit tests \
651                                       and will never be stable",
652                                      cfg_fn!(rustc_attrs))),
653     ("rustc_error", Whitelisted, Gated(Stability::Unstable,
654                                        "rustc_attrs",
655                                        "the `#[rustc_error]` attribute \
656                                         is just used for rustc unit tests \
657                                         and will never be stable",
658                                        cfg_fn!(rustc_attrs))),
659     ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
660                                                  "rustc_attrs",
661                                                  "the `#[rustc_if_this_changed]` attribute \
662                                                   is just used for rustc unit tests \
663                                                   and will never be stable",
664                                                  cfg_fn!(rustc_attrs))),
665     ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
666                                                       "rustc_attrs",
667                                                       "the `#[rustc_if_this_changed]` attribute \
668                                                        is just used for rustc unit tests \
669                                                        and will never be stable",
670                                                       cfg_fn!(rustc_attrs))),
671     ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
672                                        "rustc_attrs",
673                                        "the `#[rustc_dirty]` attribute \
674                                         is just used for rustc unit tests \
675                                         and will never be stable",
676                                        cfg_fn!(rustc_attrs))),
677     ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
678                                        "rustc_attrs",
679                                        "the `#[rustc_clean]` attribute \
680                                         is just used for rustc unit tests \
681                                         and will never be stable",
682                                        cfg_fn!(rustc_attrs))),
683     ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
684                                                 "rustc_attrs",
685                                                 "the `#[rustc_metadata_dirty]` attribute \
686                                                  is just used for rustc unit tests \
687                                                  and will never be stable",
688                                                  cfg_fn!(rustc_attrs))),
689     ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
690                                                 "rustc_attrs",
691                                                 "the `#[rustc_metadata_clean]` attribute \
692                                                  is just used for rustc unit tests \
693                                                  and will never be stable",
694                                                  cfg_fn!(rustc_attrs))),
695     ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
696                                                   "rustc_attrs",
697                                                   "this attribute \
698                                                    is just used for rustc unit tests \
699                                                    and will never be stable",
700                                                   cfg_fn!(rustc_attrs))),
701     ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
702                                                       "rustc_attrs",
703                                                       "this attribute \
704                                                        is just used for rustc unit tests \
705                                                        and will never be stable",
706                                                       cfg_fn!(rustc_attrs))),
707     ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
708                                              "rustc_attrs",
709                                              "internal rustc attributes will never be stable",
710                                              cfg_fn!(rustc_attrs))),
711     ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
712                                            "rustc_attrs",
713                                            "internal rustc attributes will never be stable",
714                                            cfg_fn!(rustc_attrs))),
715     ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
716                                      "rustc_attrs",
717                                      "the `#[rustc_mir]` attribute \
718                                       is just used for rustc unit tests \
719                                       and will never be stable",
720                                      cfg_fn!(rustc_attrs))),
721     ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
722                                                          "rustc_attrs",
723                                                          "the `#[rustc_inherit_overflow_checks]` \
724                                                           attribute is just used to control \
725                                                           overflow checking behavior of several \
726                                                           libcore functions that are inlined \
727                                                           across crates and will never be stable",
728                                                           cfg_fn!(rustc_attrs))),
729     ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
730                                              "compiler_builtins",
731                                              "the `#[compiler_builtins]` attribute is used to \
732                                               identify the `compiler_builtins` crate which \
733                                               contains compiler-rt intrinsics and will never be \
734                                               stable",
735                                           cfg_fn!(compiler_builtins))),
736     ("sanitizer_runtime", Whitelisted, Gated(Stability::Unstable,
737                                              "sanitizer_runtime",
738                                              "the `#[sanitizer_runtime]` attribute is used to \
739                                               identify crates that contain the runtime of a \
740                                               sanitizer and will never be stable",
741                                              cfg_fn!(sanitizer_runtime))),
742     ("profiler_runtime", Whitelisted, Gated(Stability::Unstable,
743                                              "profiler_runtime",
744                                              "the `#[profiler_runtime]` attribute is used to \
745                                               identify the `profiler_builtins` crate which \
746                                               contains the profiler runtime and will never be \
747                                               stable",
748                                              cfg_fn!(profiler_runtime))),
749
750     ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
751                                               "allow_internal_unstable",
752                                               EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
753                                               cfg_fn!(allow_internal_unstable))),
754
755     ("allow_internal_unsafe", Normal, Gated(Stability::Unstable,
756                                             "allow_internal_unsafe",
757                                             EXPLAIN_ALLOW_INTERNAL_UNSAFE,
758                                             cfg_fn!(allow_internal_unsafe))),
759
760     ("fundamental", Whitelisted, Gated(Stability::Unstable,
761                                        "fundamental",
762                                        "the `#[fundamental]` attribute \
763                                         is an experimental feature",
764                                        cfg_fn!(fundamental))),
765
766     ("proc_macro_derive", Normal, Ungated),
767
768     ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
769                                                    "rustc_attrs",
770                                                    "internal implementation detail",
771                                                    cfg_fn!(rustc_attrs))),
772
773     // FIXME: #14408 whitelist docs since rustdoc looks at them
774     ("doc", Whitelisted, Ungated),
775
776     // FIXME: #14406 these are processed in trans, which happens after the
777     // lint pass
778     ("cold", Whitelisted, Ungated),
779     ("naked", Whitelisted, Gated(Stability::Unstable,
780                                  "naked_functions",
781                                  "the `#[naked]` attribute \
782                                   is an experimental feature",
783                                  cfg_fn!(naked_functions))),
784     ("target_feature", Whitelisted, Gated(
785         Stability::Unstable, "target_feature",
786         "the `#[target_feature]` attribute is an experimental feature",
787         cfg_fn!(target_feature))),
788     ("export_name", Whitelisted, Ungated),
789     ("inline", Whitelisted, Ungated),
790     ("link", Whitelisted, Ungated),
791     ("link_name", Whitelisted, Ungated),
792     ("link_section", Whitelisted, Ungated),
793     ("no_builtins", Whitelisted, Ungated),
794     ("no_mangle", Whitelisted, Ungated),
795     ("no_debug", Whitelisted, Gated(
796         Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
797         "no_debug",
798         "the `#[no_debug]` attribute is an experimental feature",
799         cfg_fn!(no_debug))),
800     ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
801                                                        "omit_gdb_pretty_printer_section",
802                                                        "the `#[omit_gdb_pretty_printer_section]` \
803                                                         attribute is just used for the Rust test \
804                                                         suite",
805                                                        cfg_fn!(omit_gdb_pretty_printer_section))),
806     ("unsafe_destructor_blind_to_params",
807      Normal,
808      Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761"),
809            "dropck_parametricity",
810            "unsafe_destructor_blind_to_params has been replaced by \
811             may_dangle and will be removed in the future",
812            cfg_fn!(dropck_parametricity))),
813     ("may_dangle",
814      Normal,
815      Gated(Stability::Unstable,
816            "dropck_eyepatch",
817            "may_dangle has unstable semantics and may be removed in the future",
818            cfg_fn!(dropck_eyepatch))),
819     ("unwind", Whitelisted, Gated(Stability::Unstable,
820                                   "unwind_attributes",
821                                   "#[unwind] is experimental",
822                                   cfg_fn!(unwind_attributes))),
823     ("used", Whitelisted, Gated(
824         Stability::Unstable, "used",
825         "the `#[used]` attribute is an experimental feature",
826         cfg_fn!(used))),
827
828     // used in resolve
829     ("prelude_import", Whitelisted, Gated(Stability::Unstable,
830                                           "prelude_import",
831                                           "`#[prelude_import]` is for use by rustc only",
832                                           cfg_fn!(prelude_import))),
833
834     // FIXME: #14407 these are only looked at on-demand so we can't
835     // guarantee they'll have already been checked
836     ("rustc_deprecated", Whitelisted, Ungated),
837     ("must_use", Whitelisted, Ungated),
838     ("stable", Whitelisted, Ungated),
839     ("unstable", Whitelisted, Ungated),
840     ("deprecated", Normal, Ungated),
841
842     ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
843                                         "unboxed_closures",
844                                         "unboxed_closures are still evolving",
845                                         cfg_fn!(unboxed_closures))),
846
847     ("windows_subsystem", Whitelisted, Ungated),
848
849     ("proc_macro_attribute", Normal, Gated(Stability::Unstable,
850                                            "proc_macro",
851                                            "attribute proc macros are currently unstable",
852                                            cfg_fn!(proc_macro))),
853
854     ("proc_macro", Normal, Gated(Stability::Unstable,
855                                  "proc_macro",
856                                  "function-like proc macros are currently unstable",
857                                  cfg_fn!(proc_macro))),
858
859     ("rustc_derive_registrar", Normal, Gated(Stability::Unstable,
860                                              "rustc_derive_registrar",
861                                              "used internally by rustc",
862                                              cfg_fn!(rustc_attrs))),
863
864     ("allow_fail", Normal, Gated(Stability::Unstable,
865                                  "allow_fail",
866                                  "allow_fail attribute is currently unstable",
867                                  cfg_fn!(allow_fail))),
868
869     // Crate level attributes
870     ("crate_name", CrateLevel, Ungated),
871     ("crate_type", CrateLevel, Ungated),
872     ("crate_id", CrateLevel, Ungated),
873     ("feature", CrateLevel, Ungated),
874     ("no_start", CrateLevel, Ungated),
875     ("no_main", CrateLevel, Ungated),
876     ("no_builtins", CrateLevel, Ungated),
877     ("recursion_limit", CrateLevel, Ungated),
878     ("type_length_limit", CrateLevel, Ungated),
879 ];
880
881 // cfg(...)'s that are feature gated
882 const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[
883     // (name in cfg, feature, function to check if the feature is enabled)
884     ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
885     ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
886     ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
887     ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
888 ];
889
890 #[derive(Debug, Eq, PartialEq)]
891 pub struct GatedCfg {
892     span: Span,
893     index: usize,
894 }
895
896 impl GatedCfg {
897     pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
898         let name = cfg.name().as_str();
899         GATED_CFGS.iter()
900                   .position(|info| info.0 == name)
901                   .map(|idx| {
902                       GatedCfg {
903                           span: cfg.span,
904                           index: idx
905                       }
906                   })
907     }
908
909     pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
910         let (cfg, feature, has_feature) = GATED_CFGS[self.index];
911         if !has_feature(features) && !self.span.allows_unstable() {
912             let explain = format!("`cfg({})` is experimental and subject to change", cfg);
913             emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
914         }
915     }
916 }
917
918 struct Context<'a> {
919     features: &'a Features,
920     parse_sess: &'a ParseSess,
921     plugin_attributes: &'a [(String, AttributeType)],
922 }
923
924 macro_rules! gate_feature_fn {
925     ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
926         let (cx, has_feature, span,
927              name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level);
928         let has_feature: bool = has_feature(&$cx.features);
929         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
930         if !has_feature && !span.allows_unstable() {
931             leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
932                 .emit();
933         }
934     }}
935 }
936
937 macro_rules! gate_feature {
938     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
939         gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
940                          stringify!($feature), $explain, GateStrength::Hard)
941     };
942     ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {
943         gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
944                          stringify!($feature), $explain, $level)
945     };
946 }
947
948 impl<'a> Context<'a> {
949     fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
950         debug!("check_attribute(attr = {:?})", attr);
951         let name = unwrap_or!(attr.name(), return).as_str();
952         for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
953             if name == n {
954                 if let Gated(_, name, desc, ref has_feature) = *gateage {
955                     gate_feature_fn!(self, has_feature, attr.span, name, desc, GateStrength::Hard);
956                 }
957                 debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
958                 return;
959             }
960         }
961         for &(ref n, ref ty) in self.plugin_attributes {
962             if attr.path == &**n {
963                 // Plugins can't gate attributes, so we don't check for it
964                 // unlike the code above; we only use this loop to
965                 // short-circuit to avoid the checks below
966                 debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty);
967                 return;
968             }
969         }
970         if name.starts_with("rustc_") {
971             gate_feature!(self, rustc_attrs, attr.span,
972                           "unless otherwise specified, attributes \
973                            with the prefix `rustc_` \
974                            are reserved for internal compiler diagnostics");
975         } else if name.starts_with("derive_") {
976             gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
977         } else if !attr::is_known(attr) {
978             // Only run the custom attribute lint during regular
979             // feature gate checking. Macro gating runs
980             // before the plugin attributes are registered
981             // so we skip this then
982             if !is_macro {
983                 gate_feature!(self, custom_attribute, attr.span,
984                               &format!("The attribute `{}` is currently \
985                                         unknown to the compiler and \
986                                         may have meaning \
987                                         added to it in the future",
988                                        attr.path));
989             }
990         }
991     }
992 }
993
994 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
995     let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] };
996     cx.check_attribute(attr, true);
997 }
998
999 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
1000     ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
1001 }
1002
1003 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
1004     if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
1005         let issue = info.2;
1006         // FIXME (#28244): enforce that active features have issue numbers
1007         // assert!(issue.is_some())
1008         issue
1009     } else {
1010         // search in Accepted, Removed, or Stable Removed features
1011         let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES)
1012             .find(|t| t.0 == feature);
1013         match found {
1014             Some(&(_, _, issue)) => issue,
1015             None => panic!("Feature `{}` is not declared anywhere", feature),
1016         }
1017     }
1018 }
1019
1020 pub enum GateIssue {
1021     Language,
1022     Library(Option<u32>)
1023 }
1024
1025 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
1026 pub enum GateStrength {
1027     /// A hard error. (Most feature gates should use this.)
1028     Hard,
1029     /// Only a warning. (Use this only as backwards-compatibility demands.)
1030     Soft,
1031 }
1032
1033 pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
1034                         explain: &str) {
1035     feature_err(sess, feature, span, issue, explain).emit();
1036 }
1037
1038 pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
1039                        explain: &str) -> DiagnosticBuilder<'a> {
1040     leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
1041 }
1042
1043 fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
1044                            explain: &str, level: GateStrength) -> DiagnosticBuilder<'a> {
1045     let diag = &sess.span_diagnostic;
1046
1047     let issue = match issue {
1048         GateIssue::Language => find_lang_feature_issue(feature),
1049         GateIssue::Library(lib) => lib,
1050     };
1051
1052     let explanation = if let Some(n) = issue {
1053         format!("{} (see issue #{})", explain, n)
1054     } else {
1055         explain.to_owned()
1056     };
1057
1058     let mut err = match level {
1059         GateStrength::Hard => diag.struct_span_err(span, &explanation),
1060         GateStrength::Soft => diag.struct_span_warn(span, &explanation),
1061     };
1062
1063     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
1064     if sess.unstable_features.is_nightly_build() {
1065         err.help(&format!("add #![feature({})] to the \
1066                            crate attributes to enable",
1067                           feature));
1068     }
1069
1070     // If we're on stable and only emitting a "soft" warning, add a note to
1071     // clarify that the feature isn't "on" (rather than being on but
1072     // warning-worthy).
1073     if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft {
1074         err.help("a nightly build of the compiler is required to enable this feature");
1075     }
1076
1077     err
1078
1079 }
1080
1081 const EXPLAIN_BOX_SYNTAX: &'static str =
1082     "box expression syntax is experimental; you can call `Box::new` instead.";
1083
1084 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
1085     "attributes on non-item statements and expressions are experimental.";
1086
1087 pub const EXPLAIN_ASM: &'static str =
1088     "inline assembly is not stable enough for use and is subject to change";
1089
1090 pub const EXPLAIN_GLOBAL_ASM: &'static str =
1091     "`global_asm!` is not stable enough for use and is subject to change";
1092
1093 pub const EXPLAIN_LOG_SYNTAX: &'static str =
1094     "`log_syntax!` is not stable enough for use and is subject to change";
1095
1096 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
1097     "`concat_idents` is not stable enough for use and is subject to change";
1098
1099 pub const EXPLAIN_TRACE_MACROS: &'static str =
1100     "`trace_macros` is not stable enough for use and is subject to change";
1101 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
1102     "allow_internal_unstable side-steps feature gating and stability checks";
1103 pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &'static str =
1104     "allow_internal_unsafe side-steps the unsafe_code lint";
1105
1106 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
1107     "`#[derive]` for custom traits is deprecated and will be removed in the future.";
1108
1109 pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
1110     "`#[derive]` for custom traits is deprecated and will be removed in the future. \
1111     Prefer using procedural macro custom derive.";
1112
1113 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
1114     "attributes of the form `#[derive_*]` are reserved for the compiler";
1115
1116 pub const EXPLAIN_VIS_MATCHER: &'static str =
1117     ":vis fragment specifier is experimental and subject to change";
1118
1119 pub const EXPLAIN_PLACEMENT_IN: &'static str =
1120     "placement-in expression syntax is experimental and subject to change.";
1121
1122 pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
1123     "Unsized tuple coercion is not stable enough for use and is subject to change";
1124
1125 struct PostExpansionVisitor<'a> {
1126     context: &'a Context<'a>,
1127 }
1128
1129 macro_rules! gate_feature_post {
1130     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
1131         let (cx, span) = ($cx, $span);
1132         if !span.allows_unstable() {
1133             gate_feature!(cx.context, $feature, span, $explain)
1134         }
1135     }};
1136     ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
1137         let (cx, span) = ($cx, $span);
1138         if !span.allows_unstable() {
1139             gate_feature!(cx.context, $feature, span, $explain, $level)
1140         }
1141     }}
1142 }
1143
1144 impl<'a> PostExpansionVisitor<'a> {
1145     fn check_abi(&self, abi: Abi, span: Span) {
1146         match abi {
1147             Abi::RustIntrinsic => {
1148                 gate_feature_post!(&self, intrinsics, span,
1149                                    "intrinsics are subject to change");
1150             },
1151             Abi::PlatformIntrinsic => {
1152                 gate_feature_post!(&self, platform_intrinsics, span,
1153                                    "platform intrinsics are experimental and possibly buggy");
1154             },
1155             Abi::Vectorcall => {
1156                 gate_feature_post!(&self, abi_vectorcall, span,
1157                                    "vectorcall is experimental and subject to change");
1158             },
1159             Abi::Thiscall => {
1160                 gate_feature_post!(&self, abi_thiscall, span,
1161                                    "thiscall is experimental and subject to change");
1162             },
1163             Abi::RustCall => {
1164                 gate_feature_post!(&self, unboxed_closures, span,
1165                                    "rust-call ABI is subject to change");
1166             },
1167             Abi::SysV64 => {
1168                 gate_feature_post!(&self, abi_sysv64, span,
1169                                    "sysv64 ABI is experimental and subject to change");
1170             },
1171             Abi::PtxKernel => {
1172                 gate_feature_post!(&self, abi_ptx, span,
1173                                    "PTX ABIs are experimental and subject to change");
1174             },
1175             Abi::Unadjusted => {
1176                 gate_feature_post!(&self, abi_unadjusted, span,
1177                                    "unadjusted ABI is an implementation detail and perma-unstable");
1178             },
1179             Abi::Msp430Interrupt => {
1180                 gate_feature_post!(&self, abi_msp430_interrupt, span,
1181                                    "msp430-interrupt ABI is experimental and subject to change");
1182             },
1183             Abi::X86Interrupt => {
1184                 gate_feature_post!(&self, abi_x86_interrupt, span,
1185                                    "x86-interrupt ABI is experimental and subject to change");
1186             },
1187             // Stable
1188             Abi::Cdecl |
1189             Abi::Stdcall |
1190             Abi::Fastcall |
1191             Abi::Aapcs |
1192             Abi::Win64 |
1193             Abi::Rust |
1194             Abi::C |
1195             Abi::System => {}
1196         }
1197     }
1198 }
1199
1200 fn contains_novel_literal(item: &ast::MetaItem) -> bool {
1201     use ast::MetaItemKind::*;
1202     use ast::NestedMetaItemKind::*;
1203
1204     match item.node {
1205         Word => false,
1206         NameValue(ref lit) => !lit.node.is_str(),
1207         List(ref list) => list.iter().any(|li| {
1208             match li.node {
1209                 MetaItem(ref mi) => contains_novel_literal(mi),
1210                 Literal(_) => true,
1211             }
1212         }),
1213     }
1214 }
1215
1216 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1217     fn visit_attribute(&mut self, attr: &ast::Attribute) {
1218         if !attr.span.allows_unstable() {
1219             // check for gated attributes
1220             self.context.check_attribute(attr, false);
1221         }
1222
1223         if attr.check_name("doc") {
1224             if let Some(content) = attr.meta_item_list() {
1225                 if content.len() == 1 && content[0].check_name("cfg") {
1226                     gate_feature_post!(&self, doc_cfg, attr.span,
1227                         "#[doc(cfg(...))] is experimental"
1228                     );
1229                 }
1230             }
1231         }
1232
1233         if self.context.features.proc_macro && attr::is_known(attr) {
1234             return
1235         }
1236
1237         let meta = panictry!(attr.parse_meta(self.context.parse_sess));
1238         if contains_novel_literal(&meta) {
1239             gate_feature_post!(&self, attr_literals, attr.span,
1240                                "non-string literals in attributes, or string \
1241                                literals in top-level positions, are experimental");
1242         }
1243     }
1244
1245     fn visit_name(&mut self, sp: Span, name: ast::Name) {
1246         if !name.as_str().is_ascii() {
1247             gate_feature_post!(&self, non_ascii_idents, sp,
1248                                "non-ascii idents are not fully supported.");
1249         }
1250     }
1251
1252     fn visit_item(&mut self, i: &'a ast::Item) {
1253         match i.node {
1254             ast::ItemKind::ExternCrate(_) => {
1255                 if let Some(attr) = attr::find_by_name(&i.attrs[..], "macro_reexport") {
1256                     gate_feature_post!(&self, macro_reexport, attr.span,
1257                                        "macros reexports are experimental \
1258                                         and possibly buggy");
1259                 }
1260             }
1261
1262             ast::ItemKind::ForeignMod(ref foreign_module) => {
1263                 self.check_abi(foreign_module.abi, i.span);
1264             }
1265
1266             ast::ItemKind::Fn(..) => {
1267                 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1268                     gate_feature_post!(&self, plugin_registrar, i.span,
1269                                        "compiler plugins are experimental and possibly buggy");
1270                 }
1271                 if attr::contains_name(&i.attrs[..], "start") {
1272                     gate_feature_post!(&self, start, i.span,
1273                                       "a #[start] function is an experimental \
1274                                        feature whose signature may change \
1275                                        over time");
1276                 }
1277                 if attr::contains_name(&i.attrs[..], "main") {
1278                     gate_feature_post!(&self, main, i.span,
1279                                        "declaration of a nonstandard #[main] \
1280                                         function may change over time, for now \
1281                                         a top-level `fn main()` is required");
1282                 }
1283                 if let Some(attr) = attr::find_by_name(&i.attrs[..], "must_use") {
1284                     gate_feature_post!(&self, fn_must_use, attr.span,
1285                                        "`#[must_use]` on functions is experimental",
1286                                        GateStrength::Soft);
1287                 }
1288             }
1289
1290             ast::ItemKind::Struct(..) => {
1291                 if let Some(attr) = attr::find_by_name(&i.attrs[..], "simd") {
1292                     gate_feature_post!(&self, simd, attr.span,
1293                                        "SIMD types are experimental and possibly buggy");
1294                     self.context.parse_sess.span_diagnostic.span_warn(attr.span,
1295                                                                       "the `#[simd]` attribute \
1296                                                                        is deprecated, use \
1297                                                                        `#[repr(simd)]` instead");
1298                 }
1299                 if let Some(attr) = attr::find_by_name(&i.attrs[..], "repr") {
1300                     for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1301                         if item.check_name("simd") {
1302                             gate_feature_post!(&self, repr_simd, attr.span,
1303                                                "SIMD types are experimental and possibly buggy");
1304                         }
1305                         if item.check_name("align") {
1306                             gate_feature_post!(&self, repr_align, attr.span,
1307                                                "the struct `#[repr(align(u16))]` attribute \
1308                                                 is experimental");
1309                         }
1310                     }
1311                 }
1312             }
1313
1314             ast::ItemKind::DefaultImpl(..) => {
1315                 gate_feature_post!(&self, optin_builtin_traits,
1316                                    i.span,
1317                                    "default trait implementations are experimental \
1318                                     and possibly buggy");
1319             }
1320
1321             ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, ref impl_items) => {
1322                 if polarity == ast::ImplPolarity::Negative {
1323                     gate_feature_post!(&self, optin_builtin_traits,
1324                                        i.span,
1325                                        "negative trait bounds are not yet fully implemented; \
1326                                         use marker types for now");
1327                 }
1328
1329                 if let ast::Defaultness::Default = defaultness {
1330                     gate_feature_post!(&self, specialization,
1331                                        i.span,
1332                                        "specialization is unstable");
1333                 }
1334
1335                 for impl_item in impl_items {
1336                     if let ast::ImplItemKind::Method(..) = impl_item.node {
1337                         if let Some(attr) = attr::find_by_name(&impl_item.attrs[..], "must_use") {
1338                             gate_feature_post!(&self, fn_must_use, attr.span,
1339                                                "`#[must_use]` on methods is experimental",
1340                                                GateStrength::Soft);
1341                         }
1342                     }
1343                 }
1344             }
1345
1346             ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
1347                 let msg = "`macro` is experimental";
1348                 gate_feature_post!(&self, decl_macro, i.span, msg);
1349             }
1350
1351             _ => {}
1352         }
1353
1354         visit::walk_item(self, i);
1355     }
1356
1357     fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
1358         let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
1359             Some(val) => val.as_str().starts_with("llvm."),
1360             _ => false
1361         };
1362         if links_to_llvm {
1363             gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1364                               "linking to LLVM intrinsics is experimental");
1365         }
1366
1367         visit::walk_foreign_item(self, i)
1368     }
1369
1370     fn visit_ty(&mut self, ty: &'a ast::Ty) {
1371         match ty.node {
1372             ast::TyKind::BareFn(ref bare_fn_ty) => {
1373                 self.check_abi(bare_fn_ty.abi, ty.span);
1374             }
1375             ast::TyKind::ImplTrait(..) => {
1376                 gate_feature_post!(&self, conservative_impl_trait, ty.span,
1377                                    "`impl Trait` is experimental");
1378             }
1379             ast::TyKind::Never => {
1380                 gate_feature_post!(&self, never_type, ty.span,
1381                                    "The `!` type is experimental");
1382             },
1383             _ => {}
1384         }
1385         visit::walk_ty(self, ty)
1386     }
1387
1388     fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
1389         if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
1390             if output_ty.node != ast::TyKind::Never {
1391                 self.visit_ty(output_ty)
1392             }
1393         }
1394     }
1395
1396     fn visit_expr(&mut self, e: &'a ast::Expr) {
1397         match e.node {
1398             ast::ExprKind::Box(_) => {
1399                 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1400             }
1401             ast::ExprKind::Type(..) => {
1402                 gate_feature_post!(&self, type_ascription, e.span,
1403                                   "type ascription is experimental");
1404             }
1405             ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1406                 gate_feature_post!(&self, inclusive_range_syntax,
1407                                   e.span,
1408                                   "inclusive range syntax is experimental");
1409             }
1410             ast::ExprKind::InPlace(..) => {
1411                 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1412             }
1413             ast::ExprKind::Yield(..) => {
1414                 gate_feature_post!(&self, generators,
1415                                   e.span,
1416                                   "yield syntax is experimental");
1417             }
1418             ast::ExprKind::Lit(ref lit) => {
1419                 if let ast::LitKind::Int(_, ref ty) = lit.node {
1420                     match *ty {
1421                         ast::LitIntType::Signed(ast::IntTy::I128) |
1422                         ast::LitIntType::Unsigned(ast::UintTy::U128) => {
1423                             gate_feature_post!(&self, i128_type, e.span,
1424                                                "128-bit integers are not stable");
1425                         }
1426                         _ => {}
1427                     }
1428                 }
1429             }
1430             ast::ExprKind::Catch(_) => {
1431                 gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
1432             }
1433             _ => {}
1434         }
1435         visit::walk_expr(self, e);
1436     }
1437
1438     fn visit_pat(&mut self, pattern: &'a ast::Pat) {
1439         match pattern.node {
1440             PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
1441                 gate_feature_post!(&self, advanced_slice_patterns,
1442                                   pattern.span,
1443                                   "multiple-element slice matches anywhere \
1444                                    but at the end of a slice (e.g. \
1445                                    `[0, ..xs, 0]`) are experimental")
1446             }
1447             PatKind::Slice(..) => {
1448                 gate_feature_post!(&self, slice_patterns,
1449                                   pattern.span,
1450                                   "slice pattern syntax is experimental");
1451             }
1452             PatKind::Box(..) => {
1453                 gate_feature_post!(&self, box_patterns,
1454                                   pattern.span,
1455                                   "box pattern syntax is experimental");
1456             }
1457             PatKind::Range(_, _, RangeEnd::Excluded) => {
1458                 gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
1459                                    "exclusive range pattern syntax is experimental");
1460             }
1461             _ => {}
1462         }
1463         visit::walk_pat(self, pattern)
1464     }
1465
1466     fn visit_fn(&mut self,
1467                 fn_kind: FnKind<'a>,
1468                 fn_decl: &'a ast::FnDecl,
1469                 span: Span,
1470                 _node_id: NodeId) {
1471         // check for const fn declarations
1472         if let FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) =
1473             fn_kind {
1474             gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1475         }
1476         // stability of const fn methods are covered in
1477         // visit_trait_item and visit_impl_item below; this is
1478         // because default methods don't pass through this
1479         // point.
1480
1481         match fn_kind {
1482             FnKind::ItemFn(_, _, _, _, abi, _, _) |
1483             FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
1484                 self.check_abi(abi, span);
1485             }
1486             _ => {}
1487         }
1488         visit::walk_fn(self, fn_kind, fn_decl, span);
1489     }
1490
1491     fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1492         match ti.node {
1493             ast::TraitItemKind::Method(ref sig, ref block) => {
1494                 if block.is_none() {
1495                     self.check_abi(sig.abi, ti.span);
1496                 }
1497                 if sig.constness.node == ast::Constness::Const {
1498                     gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1499                 }
1500             }
1501             ast::TraitItemKind::Type(_, Some(_)) => {
1502                 gate_feature_post!(&self, associated_type_defaults, ti.span,
1503                                   "associated type defaults are unstable");
1504             }
1505             _ => {}
1506         }
1507         visit::walk_trait_item(self, ti);
1508     }
1509
1510     fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
1511         if ii.defaultness == ast::Defaultness::Default {
1512             gate_feature_post!(&self, specialization,
1513                               ii.span,
1514                               "specialization is unstable");
1515         }
1516
1517         match ii.node {
1518             ast::ImplItemKind::Method(ref sig, _) => {
1519                 if sig.constness.node == ast::Constness::Const {
1520                     gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1521                 }
1522             }
1523             _ => {}
1524         }
1525         visit::walk_impl_item(self, ii);
1526     }
1527
1528     fn visit_generics(&mut self, g: &'a ast::Generics) {
1529         for t in &g.ty_params {
1530             if !t.attrs.is_empty() {
1531                 gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
1532                                    "attributes on type parameter bindings are experimental");
1533             }
1534         }
1535         visit::walk_generics(self, g)
1536     }
1537
1538     fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) {
1539         if !lifetime_def.attrs.is_empty() {
1540             gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
1541                                "attributes on lifetime bindings are experimental");
1542         }
1543         visit::walk_lifetime_def(self, lifetime_def)
1544     }
1545 }
1546
1547 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1548     let mut features = Features::new();
1549
1550     let mut feature_checker = MutexFeatureChecker::default();
1551
1552     for attr in krate_attrs {
1553         if !attr.check_name("feature") {
1554             continue
1555         }
1556
1557         match attr.meta_item_list() {
1558             None => {
1559                 span_err!(span_handler, attr.span, E0555,
1560                           "malformed feature attribute, expected #![feature(...)]");
1561             }
1562             Some(list) => {
1563                 for mi in list {
1564                     let name = if let Some(word) = mi.word() {
1565                         word.name()
1566                     } else {
1567                         span_err!(span_handler, mi.span, E0556,
1568                                   "malformed feature, expected just one word");
1569                         continue
1570                     };
1571
1572                     if let Some(&(_, _, _, set)) = ACTIVE_FEATURES.iter()
1573                         .find(|& &(n, _, _, _)| name == n) {
1574                         set(&mut features, mi.span);
1575                         feature_checker.collect(&features, mi.span);
1576                     }
1577                     else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1578                             .find(|& &(n, _, _)| name == n)
1579                         .or_else(|| STABLE_REMOVED_FEATURES.iter()
1580                             .find(|& &(n, _, _)| name == n)) {
1581                         span_err!(span_handler, mi.span, E0557, "feature has been removed");
1582                     }
1583                     else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1584                         .find(|& &(n, _, _)| name == n) {
1585                         features.declared_stable_lang_features.push((name, mi.span));
1586                     } else {
1587                         features.declared_lib_features.push((name, mi.span));
1588                     }
1589                 }
1590             }
1591         }
1592     }
1593
1594     feature_checker.check(span_handler);
1595
1596     features
1597 }
1598
1599 // A collector for mutually-exclusive features and their flag spans
1600 #[derive(Default)]
1601 struct MutexFeatureChecker {
1602     proc_macro: Option<Span>,
1603     custom_attribute: Option<Span>,
1604 }
1605
1606 impl MutexFeatureChecker {
1607     // If this method turns out to be a hotspot due to branching,
1608     // the branching can be eliminated by modifying `set!()` to set these spans
1609     // only for the features that need to be checked for mutual exclusion.
1610     fn collect(&mut self, features: &Features, span: Span) {
1611         if features.proc_macro {
1612             // If self.proc_macro is None, set to Some(span)
1613             self.proc_macro = self.proc_macro.or(Some(span));
1614         }
1615
1616         if features.custom_attribute {
1617             self.custom_attribute = self.custom_attribute.or(Some(span));
1618         }
1619     }
1620
1621     fn check(self, handler: &Handler) {
1622         if let (Some(pm_span), Some(ca_span)) = (self.proc_macro, self.custom_attribute) {
1623             handler.struct_span_err(pm_span, "Cannot use `#![feature(proc_macro)]` and \
1624                                               `#![feature(custom_attribute)] at the same time")
1625                 .span_note(ca_span, "`#![feature(custom_attribute)]` declared here")
1626                 .emit();
1627
1628             panic!(FatalError);
1629         }
1630     }
1631 }
1632
1633 pub fn check_crate(krate: &ast::Crate,
1634                    sess: &ParseSess,
1635                    features: &Features,
1636                    plugin_attributes: &[(String, AttributeType)],
1637                    unstable: UnstableFeatures) {
1638     maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1639     let ctx = Context {
1640         features,
1641         parse_sess: sess,
1642         plugin_attributes,
1643     };
1644     visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1645 }
1646
1647 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1648 pub enum UnstableFeatures {
1649     /// Hard errors for unstable features are active, as on
1650     /// beta/stable channels.
1651     Disallow,
1652     /// Allow features to be activated, as on nightly.
1653     Allow,
1654     /// Errors are bypassed for bootstrapping. This is required any time
1655     /// during the build that feature-related lints are set to warn or above
1656     /// because the build turns on warnings-as-errors and uses lots of unstable
1657     /// features. As a result, this is always required for building Rust itself.
1658     Cheat
1659 }
1660
1661 impl UnstableFeatures {
1662     pub fn from_environment() -> UnstableFeatures {
1663         // Whether this is a feature-staged build, i.e. on the beta or stable channel
1664         let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1665         // Whether we should enable unstable features for bootstrapping
1666         let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
1667         match (disable_unstable_features, bootstrap) {
1668             (_, true) => UnstableFeatures::Cheat,
1669             (true, _) => UnstableFeatures::Disallow,
1670             (false, _) => UnstableFeatures::Allow
1671         }
1672     }
1673
1674     pub fn is_nightly_build(&self) -> bool {
1675         match *self {
1676             UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1677             _ => false,
1678         }
1679     }
1680 }
1681
1682 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1683                         unstable: UnstableFeatures) {
1684     let allow_features = match unstable {
1685         UnstableFeatures::Allow => true,
1686         UnstableFeatures::Disallow => false,
1687         UnstableFeatures::Cheat => true
1688     };
1689     if !allow_features {
1690         for attr in &krate.attrs {
1691             if attr.check_name("feature") {
1692                 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1693                 span_err!(span_handler, attr.span, E0554,
1694                           "#![feature] may not be used on the {} release channel",
1695                           release_channel);
1696             }
1697         }
1698     }
1699 }