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