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