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