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