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