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