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