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