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