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