]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/feature_gate.rs
move error handling from libsyntax/diagnostics.rs to libsyntax/errors/*
[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::Status::*;
26 use self::AttributeType::*;
27 use self::AttributeGate::*;
28
29 use abi::Abi;
30 use ast::NodeId;
31 use ast;
32 use attr;
33 use attr::AttrMetaMethods;
34 use codemap::{CodeMap, Span};
35 use errors::Handler;
36 use visit;
37 use visit::{FnKind, Visitor};
38 use parse::token::InternedString;
39
40 use std::ascii::AsciiExt;
41 use std::cmp;
42
43 // If you change this list without updating src/doc/reference.md, @cmr will be sad
44 // Don't ever remove anything from this list; set them to 'Removed'.
45 // The version numbers here correspond to the version in which the current status
46 // was set. This is most important for knowing when a particular feature became
47 // stable (active).
48 // NB: The featureck.py script parses this information directly out of the source
49 // so take care when modifying it.
50 const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status)] = &[
51     ("globs", "1.0.0", None, Accepted),
52     ("macro_rules", "1.0.0", None, Accepted),
53     ("struct_variant", "1.0.0", None, Accepted),
54     ("asm", "1.0.0", Some(29722), Active),
55     ("managed_boxes", "1.0.0", None, Removed),
56     ("non_ascii_idents", "1.0.0", Some(28979), Active),
57     ("thread_local", "1.0.0", Some(29594), Active),
58     ("link_args", "1.0.0", Some(29596), Active),
59     ("plugin_registrar", "1.0.0", Some(29597), Active),
60     ("log_syntax", "1.0.0", Some(29598), Active),
61     ("trace_macros", "1.0.0", Some(29598), Active),
62     ("concat_idents", "1.0.0", Some(29599), Active),
63
64     // rustc internal, for now:
65     ("intrinsics", "1.0.0", None, Active),
66     ("lang_items", "1.0.0", None, Active),
67
68     ("simd", "1.0.0", Some(27731), Active),
69     ("default_type_params", "1.0.0", None, Accepted),
70     ("quote", "1.0.0", Some(29601), Active),
71     ("link_llvm_intrinsics", "1.0.0", Some(29602), Active),
72     ("linkage", "1.0.0", Some(29603), Active),
73     ("struct_inherit", "1.0.0", None, Removed),
74
75     ("quad_precision_float", "1.0.0", None, Removed),
76
77     // rustc internal
78     ("rustc_diagnostic_macros", "1.0.0", None, Active),
79     ("unboxed_closures", "1.0.0", Some(29625), Active),
80     ("reflect", "1.0.0", Some(27749), Active),
81     ("import_shadowing", "1.0.0", None, Removed),
82     ("advanced_slice_patterns", "1.0.0", Some(23121), Active),
83     ("tuple_indexing", "1.0.0", None, Accepted),
84     ("associated_types", "1.0.0", None, Accepted),
85     ("visible_private_types", "1.0.0", Some(29627), Active),
86     ("slicing_syntax", "1.0.0", None, Accepted),
87     ("box_syntax", "1.0.0", Some(27779), Active),
88     ("placement_in_syntax", "1.0.0", Some(27779), Active),
89
90     // rustc internal.
91     ("pushpop_unsafe", "1.2.0", None, Active),
92
93     ("on_unimplemented", "1.0.0", Some(29628), Active),
94     ("simd_ffi", "1.0.0", Some(27731), Active),
95     ("allocator", "1.0.0", Some(27389), Active),
96     ("needs_allocator", "1.4.0", Some(27389), Active),
97     ("linked_from", "1.3.0", Some(29629), Active),
98
99     ("if_let", "1.0.0", None, Accepted),
100     ("while_let", "1.0.0", None, Accepted),
101
102     ("plugin", "1.0.0", Some(29597), Active),
103     ("start", "1.0.0", Some(29633), Active),
104     ("main", "1.0.0", Some(29634), Active),
105
106     ("fundamental", "1.0.0", Some(29635), Active),
107
108     // A temporary feature gate used to enable parser extensions needed
109     // to bootstrap fix for #5723.
110     ("issue_5723_bootstrap", "1.0.0", None, Accepted),
111
112     // A way to temporarily opt out of opt in copy. This will *never* be accepted.
113     ("opt_out_copy", "1.0.0", None, Removed),
114
115     // OIBIT specific features
116     ("optin_builtin_traits", "1.0.0", Some(13231), Active),
117
118     // macro reexport needs more discussion and stabilization
119     ("macro_reexport", "1.0.0", Some(29638), Active),
120
121     // These are used to test this portion of the compiler, they don't actually
122     // mean anything
123     ("test_accepted_feature", "1.0.0", None, Accepted),
124     ("test_removed_feature", "1.0.0", None, Removed),
125
126     // Allows use of #[staged_api]
127     // rustc internal
128     ("staged_api", "1.0.0", None, Active),
129
130     // Allows using items which are missing stability attributes
131     // rustc internal
132     ("unmarked_api", "1.0.0", None, Active),
133
134     // Allows using #![no_std]
135     ("no_std", "1.0.0", None, Accepted),
136
137     // Allows using #![no_core]
138     ("no_core", "1.3.0", Some(29639), Active),
139
140     // Allows using `box` in patterns; RFC 469
141     ("box_patterns", "1.0.0", Some(29641), Active),
142
143     // Allows using the unsafe_no_drop_flag attribute (unlikely to
144     // switch to Accepted; see RFC 320)
145     ("unsafe_no_drop_flag", "1.0.0", None, Active),
146
147     // Allows using the unsafe_destructor_blind_to_params attribute;
148     // RFC 1238
149     ("dropck_parametricity", "1.3.0", Some(28498), Active),
150
151     // Allows the use of custom attributes; RFC 572
152     ("custom_attribute", "1.0.0", Some(29642), Active),
153
154     // Allows the use of #[derive(Anything)] as sugar for
155     // #[derive_Anything].
156     ("custom_derive", "1.0.0", Some(29644), Active),
157
158     // Allows the use of rustc_* attributes; RFC 572
159     ("rustc_attrs", "1.0.0", Some(29642), Active),
160
161     // Allows the use of #[allow_internal_unstable]. This is an
162     // attribute on macro_rules! and can't use the attribute handling
163     // below (it has to be checked before expansion possibly makes
164     // macros disappear).
165     //
166     // rustc internal
167     ("allow_internal_unstable", "1.0.0", None, Active),
168
169     // #23121. Array patterns have some hazards yet.
170     ("slice_patterns", "1.0.0", Some(23121), Active),
171
172     // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
173     ("negate_unsigned", "1.0.0", Some(29645), Active),
174
175     // Allows the definition of associated constants in `trait` or `impl`
176     // blocks.
177     ("associated_consts", "1.0.0", Some(29646), Active),
178
179     // Allows the definition of `const fn` functions.
180     ("const_fn", "1.2.0", Some(24111), Active),
181
182     // Allows indexing into constant arrays.
183     ("const_indexing", "1.4.0", Some(29947), Active),
184
185     // Allows using #[prelude_import] on glob `use` items.
186     //
187     // rustc internal
188     ("prelude_import", "1.2.0", None, Active),
189
190     // Allows the definition recursive static items.
191     ("static_recursion", "1.3.0", Some(29719), Active),
192
193     // Allows default type parameters to influence type inference.
194     ("default_type_parameter_fallback", "1.3.0", Some(27336), Active),
195
196     // Allows associated type defaults
197     ("associated_type_defaults", "1.2.0", Some(29661), Active),
198
199     // Allows macros to appear in the type position.
200     ("type_macros", "1.3.0", Some(27336), Active),
201
202     // allow `repr(simd)`, and importing the various simd intrinsics
203     ("repr_simd", "1.4.0", Some(27731), Active),
204
205     // Allows cfg(target_feature = "...").
206     ("cfg_target_feature", "1.4.0", Some(29717), Active),
207
208     // allow `extern "platform-intrinsic" { ... }`
209     ("platform_intrinsics", "1.4.0", Some(27731), Active),
210
211     // allow `#[unwind]`
212     // rust runtime internal
213     ("unwind_attributes", "1.4.0", None, Active),
214
215     // allow empty structs and enum variants with braces
216     ("braced_empty_structs", "1.5.0", Some(29720), Active),
217
218     // allow overloading augmented assignment operations like `a += b`
219     ("augmented_assignments", "1.5.0", Some(28235), Active),
220
221     // allow `#[no_debug]`
222     ("no_debug", "1.5.0", Some(29721), Active),
223
224     // allow `#[omit_gdb_pretty_printer_section]`
225     // rustc internal.
226     ("omit_gdb_pretty_printer_section", "1.5.0", None, Active),
227
228     // Allows cfg(target_vendor = "...").
229     ("cfg_target_vendor", "1.5.0", Some(29718), Active),
230
231     // Allow attributes on expressions and non-item statements
232     ("stmt_expr_attributes", "1.6.0", Some(15701), Active),
233
234     // Allows `#[deprecated]` attribute
235     ("deprecated", "1.6.0", Some(29935), Active),
236 ];
237 // (changing above list without updating src/doc/reference.md makes @cmr sad)
238
239 enum Status {
240     /// Represents an active feature that is currently being implemented or
241     /// currently being considered for addition/removal.
242     Active,
243
244     /// Represents a feature which has since been removed (it was once Active)
245     Removed,
246
247     /// This language feature has since been Accepted (it was once Active)
248     Accepted,
249 }
250
251 // Attributes that have a special meaning to rustc or rustdoc
252 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
253     // Normal attributes
254
255     ("warn", Normal, Ungated),
256     ("allow", Normal, Ungated),
257     ("forbid", Normal, Ungated),
258     ("deny", Normal, Ungated),
259
260     ("macro_reexport", Normal, Ungated),
261     ("macro_use", Normal, Ungated),
262     ("macro_export", Normal, Ungated),
263     ("plugin_registrar", Normal, Ungated),
264
265     ("cfg", Normal, Ungated),
266     ("cfg_attr", Normal, Ungated),
267     ("main", Normal, Ungated),
268     ("start", Normal, Ungated),
269     ("test", Normal, Ungated),
270     ("bench", Normal, Ungated),
271     ("simd", Normal, Ungated),
272     ("repr", Normal, Ungated),
273     ("path", Normal, Ungated),
274     ("abi", Normal, Ungated),
275     ("automatically_derived", Normal, Ungated),
276     ("no_mangle", Normal, Ungated),
277     ("no_link", Normal, Ungated),
278     ("derive", Normal, Ungated),
279     ("should_panic", Normal, Ungated),
280     ("ignore", Normal, Ungated),
281     ("no_implicit_prelude", Normal, Ungated),
282     ("reexport_test_harness_main", Normal, Ungated),
283     ("link_args", Normal, Ungated),
284     ("macro_escape", Normal, Ungated),
285
286     // Not used any more, but we can't feature gate it
287     ("no_stack_check", Normal, Ungated),
288
289     ("plugin", CrateLevel, Gated("plugin",
290                                  "compiler plugins are experimental \
291                                   and possibly buggy")),
292     ("no_std", CrateLevel, Ungated),
293     ("no_core", CrateLevel, Gated("no_core",
294                                   "no_core is experimental")),
295     ("lang", Normal, Gated("lang_items",
296                            "language items are subject to change")),
297     ("linkage", Whitelisted, Gated("linkage",
298                                    "the `linkage` attribute is experimental \
299                                     and not portable across platforms")),
300     ("thread_local", Whitelisted, Gated("thread_local",
301                                         "`#[thread_local]` is an experimental feature, and does \
302                                          not currently handle destructors. There is no \
303                                          corresponding `#[task_local]` mapping to the task \
304                                          model")),
305
306     ("rustc_on_unimplemented", Normal, Gated("on_unimplemented",
307                                              "the `#[rustc_on_unimplemented]` attribute \
308                                               is an experimental feature")),
309     ("allocator", Whitelisted, Gated("allocator",
310                                      "the `#[allocator]` attribute is an experimental feature")),
311     ("needs_allocator", Normal, Gated("needs_allocator",
312                                       "the `#[needs_allocator]` \
313                                        attribute is an experimental \
314                                        feature")),
315     ("rustc_variance", Normal, Gated("rustc_attrs",
316                                      "the `#[rustc_variance]` attribute \
317                                       is just used for rustc unit tests \
318                                       and will never be stable")),
319     ("rustc_error", Whitelisted, Gated("rustc_attrs",
320                                        "the `#[rustc_error]` attribute \
321                                         is just used for rustc unit tests \
322                                         and will never be stable")),
323     ("rustc_move_fragments", Normal, Gated("rustc_attrs",
324                                            "the `#[rustc_move_fragments]` attribute \
325                                             is just used for rustc unit tests \
326                                             and will never be stable")),
327     ("rustc_mir", Normal, Gated("rustc_attrs",
328                                 "the `#[rustc_mir]` attribute \
329                                  is just used for rustc unit tests \
330                                  and will never be stable")),
331
332     ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
333                                               EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
334
335     ("fundamental", Whitelisted, Gated("fundamental",
336                                        "the `#[fundamental]` attribute \
337                                         is an experimental feature")),
338
339     ("linked_from", Normal, Gated("linked_from",
340                                   "the `#[linked_from]` attribute \
341                                    is an experimental feature")),
342
343     // FIXME: #14408 whitelist docs since rustdoc looks at them
344     ("doc", Whitelisted, Ungated),
345
346     // FIXME: #14406 these are processed in trans, which happens after the
347     // lint pass
348     ("cold", Whitelisted, Ungated),
349     ("export_name", Whitelisted, Ungated),
350     ("inline", Whitelisted, Ungated),
351     ("link", Whitelisted, Ungated),
352     ("link_name", Whitelisted, Ungated),
353     ("link_section", Whitelisted, Ungated),
354     ("no_builtins", Whitelisted, Ungated),
355     ("no_mangle", Whitelisted, Ungated),
356     ("no_debug", Whitelisted, Gated("no_debug",
357                                     "the `#[no_debug]` attribute \
358                                      is an experimental feature")),
359     ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
360                                                        "the `#[omit_gdb_pretty_printer_section]` \
361                                                         attribute is just used for the Rust test \
362                                                         suite")),
363     ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
364                                                "unsafe_no_drop_flag has unstable semantics \
365                                                 and may be removed in the future")),
366     ("unsafe_destructor_blind_to_params",
367      Normal,
368      Gated("dropck_parametricity",
369            "unsafe_destructor_blind_to_params has unstable semantics \
370             and may be removed in the future")),
371     ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental")),
372
373     // used in resolve
374     ("prelude_import", Whitelisted, Gated("prelude_import",
375                                           "`#[prelude_import]` is for use by rustc only")),
376
377     // FIXME: #14407 these are only looked at on-demand so we can't
378     // guarantee they'll have already been checked
379     ("rustc_deprecated", Whitelisted, Ungated),
380     ("must_use", Whitelisted, Ungated),
381     ("stable", Whitelisted, Ungated),
382     ("unstable", Whitelisted, Ungated),
383     ("deprecated", Normal, Gated("deprecated", "`#[deprecated]` attribute is unstable")),
384
385     ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
386                                         "unboxed_closures are still evolving")),
387     ("rustc_reflect_like", Whitelisted, Gated("reflect",
388                                               "defining reflective traits is still evolving")),
389
390     // Crate level attributes
391     ("crate_name", CrateLevel, Ungated),
392     ("crate_type", CrateLevel, Ungated),
393     ("crate_id", CrateLevel, Ungated),
394     ("feature", CrateLevel, Ungated),
395     ("no_start", CrateLevel, Ungated),
396     ("no_main", CrateLevel, Ungated),
397     ("no_builtins", CrateLevel, Ungated),
398     ("recursion_limit", CrateLevel, Ungated),
399 ];
400
401 macro_rules! cfg_fn {
402     (|$x: ident| $e: expr) => {{
403         fn f($x: &Features) -> bool {
404             $e
405         }
406         f as fn(&Features) -> bool
407     }}
408 }
409 // cfg(...)'s that are feature gated
410 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
411     // (name in cfg, feature, function to check if the feature is enabled)
412     ("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)),
413     ("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)),
414 ];
415
416 #[derive(Debug, Eq, PartialEq)]
417 pub enum GatedCfgAttr {
418     GatedCfg(GatedCfg),
419     GatedAttr(Span),
420 }
421
422 #[derive(Debug, Eq, PartialEq)]
423 pub struct GatedCfg {
424     span: Span,
425     index: usize,
426 }
427
428 impl Ord for GatedCfgAttr {
429     fn cmp(&self, other: &GatedCfgAttr) -> cmp::Ordering {
430         let to_tup = |s: &GatedCfgAttr| match *s {
431             GatedCfgAttr::GatedCfg(ref gated_cfg) => {
432                 (gated_cfg.span.lo.0, gated_cfg.span.hi.0, gated_cfg.index)
433             }
434             GatedCfgAttr::GatedAttr(ref span) => {
435                 (span.lo.0, span.hi.0, GATED_CFGS.len())
436             }
437         };
438         to_tup(self).cmp(&to_tup(other))
439     }
440 }
441
442 impl PartialOrd for GatedCfgAttr {
443     fn partial_cmp(&self, other: &GatedCfgAttr) -> Option<cmp::Ordering> {
444         Some(self.cmp(other))
445     }
446 }
447
448 impl GatedCfgAttr {
449     pub fn check_and_emit(&self, diagnostic: &Handler, features: &Features) {
450         match *self {
451             GatedCfgAttr::GatedCfg(ref cfg) => {
452                 cfg.check_and_emit(diagnostic, features);
453             }
454             GatedCfgAttr::GatedAttr(span) => {
455                 if !features.stmt_expr_attributes {
456                     emit_feature_err(diagnostic,
457                                      "stmt_expr_attributes",
458                                      span,
459                                      GateIssue::Language,
460                                      EXPLAIN_STMT_ATTR_SYNTAX);
461                 }
462             }
463         }
464     }
465 }
466
467 impl GatedCfg {
468     pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
469         let name = cfg.name();
470         GATED_CFGS.iter()
471                   .position(|info| info.0 == name)
472                   .map(|idx| {
473                       GatedCfg {
474                           span: cfg.span,
475                           index: idx
476                       }
477                   })
478     }
479     fn check_and_emit(&self, diagnostic: &Handler, features: &Features) {
480         let (cfg, feature, has_feature) = GATED_CFGS[self.index];
481         if !has_feature(features) {
482             let explain = format!("`cfg({})` is experimental and subject to change", cfg);
483             emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
484         }
485     }
486 }
487
488
489 #[derive(PartialEq, Copy, Clone, Debug)]
490 pub enum AttributeType {
491     /// Normal, builtin attribute that is consumed
492     /// by the compiler before the unused_attribute check
493     Normal,
494
495     /// Builtin attribute that may not be consumed by the compiler
496     /// before the unused_attribute check. These attributes
497     /// will be ignored by the unused_attribute lint
498     Whitelisted,
499
500     /// Builtin attribute that is only allowed at the crate level
501     CrateLevel,
502 }
503
504 #[derive(PartialEq, Copy, Clone, Debug)]
505 pub enum AttributeGate {
506     /// Is gated by a given feature gate and reason
507     Gated(&'static str, &'static str),
508
509     /// Ungated attribute, can be used on all release channels
510     Ungated,
511 }
512
513 /// A set of features to be used by later passes.
514 pub struct Features {
515     pub unboxed_closures: bool,
516     pub rustc_diagnostic_macros: bool,
517     pub visible_private_types: bool,
518     pub allow_quote: bool,
519     pub allow_asm: bool,
520     pub allow_log_syntax: bool,
521     pub allow_concat_idents: bool,
522     pub allow_trace_macros: bool,
523     pub allow_internal_unstable: bool,
524     pub allow_custom_derive: bool,
525     pub allow_placement_in: bool,
526     pub allow_box: bool,
527     pub allow_pushpop_unsafe: bool,
528     pub simd_ffi: bool,
529     pub unmarked_api: bool,
530     pub negate_unsigned: bool,
531     /// spans of #![feature] attrs for stable language features. for error reporting
532     pub declared_stable_lang_features: Vec<Span>,
533     /// #![feature] attrs for non-language (library) features
534     pub declared_lib_features: Vec<(InternedString, Span)>,
535     pub const_fn: bool,
536     pub const_indexing: bool,
537     pub static_recursion: bool,
538     pub default_type_parameter_fallback: bool,
539     pub type_macros: bool,
540     pub cfg_target_feature: bool,
541     pub cfg_target_vendor: bool,
542     pub augmented_assignments: bool,
543     pub braced_empty_structs: bool,
544     pub staged_api: bool,
545     pub stmt_expr_attributes: bool,
546     pub deprecated: bool,
547 }
548
549 impl Features {
550     pub fn new() -> Features {
551         Features {
552             unboxed_closures: false,
553             rustc_diagnostic_macros: false,
554             visible_private_types: false,
555             allow_quote: false,
556             allow_asm: false,
557             allow_log_syntax: false,
558             allow_concat_idents: false,
559             allow_trace_macros: false,
560             allow_internal_unstable: false,
561             allow_custom_derive: false,
562             allow_placement_in: false,
563             allow_box: false,
564             allow_pushpop_unsafe: false,
565             simd_ffi: false,
566             unmarked_api: false,
567             negate_unsigned: false,
568             declared_stable_lang_features: Vec::new(),
569             declared_lib_features: Vec::new(),
570             const_fn: false,
571             const_indexing: false,
572             static_recursion: false,
573             default_type_parameter_fallback: false,
574             type_macros: false,
575             cfg_target_feature: false,
576             cfg_target_vendor: false,
577             augmented_assignments: false,
578             braced_empty_structs: false,
579             staged_api: false,
580             stmt_expr_attributes: false,
581             deprecated: false,
582         }
583     }
584 }
585
586 const EXPLAIN_BOX_SYNTAX: &'static str =
587     "box expression syntax is experimental; you can call `Box::new` instead.";
588
589 const EXPLAIN_PLACEMENT_IN: &'static str =
590     "placement-in expression syntax is experimental and subject to change.";
591
592 const EXPLAIN_PUSHPOP_UNSAFE: &'static str =
593     "push/pop_unsafe macros are experimental and subject to change.";
594
595 const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
596     "attributes on non-item statements and expressions are experimental.";
597
598 pub fn check_for_box_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
599     if let Some(&Features { allow_box: true, .. }) = f {
600         return;
601     }
602     emit_feature_err(diag, "box_syntax", span, GateIssue::Language, EXPLAIN_BOX_SYNTAX);
603 }
604
605 pub fn check_for_placement_in(f: Option<&Features>, diag: &Handler, span: Span) {
606     if let Some(&Features { allow_placement_in: true, .. }) = f {
607         return;
608     }
609     emit_feature_err(diag, "placement_in_syntax", span, GateIssue::Language, EXPLAIN_PLACEMENT_IN);
610 }
611
612 pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
613     if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f {
614         return;
615     }
616     emit_feature_err(diag, "pushpop_unsafe", span, GateIssue::Language, EXPLAIN_PUSHPOP_UNSAFE);
617 }
618
619 struct Context<'a> {
620     features: Vec<&'static str>,
621     span_handler: &'a Handler,
622     cm: &'a CodeMap,
623     plugin_attributes: &'a [(String, AttributeType)],
624 }
625
626 impl<'a> Context<'a> {
627     fn enable_feature(&mut self, feature: &'static str) {
628         debug!("enabling feature: {}", feature);
629         self.features.push(feature);
630     }
631
632     fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
633         let has_feature = self.has_feature(feature);
634         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature);
635         if !has_feature {
636             emit_feature_err(self.span_handler, feature, span, GateIssue::Language, explain);
637         }
638     }
639     fn has_feature(&self, feature: &str) -> bool {
640         self.features.iter().any(|&n| n == feature)
641     }
642
643     fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
644         debug!("check_attribute(attr = {:?})", attr);
645         let name = &*attr.name();
646         for &(n, ty, gateage) in KNOWN_ATTRIBUTES {
647             if n == name {
648                 if let Gated(gate, desc) = gateage {
649                     self.gate_feature(gate, attr.span, desc);
650                 }
651                 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
652                 return;
653             }
654         }
655         for &(ref n, ref ty) in self.plugin_attributes {
656             if &*n == name {
657                 // Plugins can't gate attributes, so we don't check for it
658                 // unlike the code above; we only use this loop to
659                 // short-circuit to avoid the checks below
660                 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
661                 return;
662             }
663         }
664         if name.starts_with("rustc_") {
665             self.gate_feature("rustc_attrs", attr.span,
666                               "unless otherwise specified, attributes \
667                                with the prefix `rustc_` \
668                                are reserved for internal compiler diagnostics");
669         } else if name.starts_with("derive_") {
670             self.gate_feature("custom_derive", attr.span,
671                               "attributes of the form `#[derive_*]` are reserved \
672                                for the compiler");
673         } else {
674             // Only run the custom attribute lint during regular
675             // feature gate checking. Macro gating runs
676             // before the plugin attributes are registered
677             // so we skip this then
678             if !is_macro {
679                 self.gate_feature("custom_attribute", attr.span,
680                            &format!("The attribute `{}` is currently \
681                                     unknown to the compiler and \
682                                     may have meaning \
683                                     added to it in the future",
684                                     name));
685             }
686         }
687     }
688 }
689
690 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
691     let info = KNOWN_FEATURES.iter()
692                               .find(|t| t.0 == feature)
693                               .unwrap();
694     let issue = info.2;
695     if let Active = info.3 {
696         // FIXME (#28244): enforce that active features have issue numbers
697         // assert!(issue.is_some())
698     }
699     issue
700 }
701
702 pub enum GateIssue {
703     Language,
704     Library(Option<u32>)
705 }
706
707 pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
708                         explain: &str) {
709     let issue = match issue {
710         GateIssue::Language => find_lang_feature_issue(feature),
711         GateIssue::Library(lib) => lib,
712     };
713
714     if let Some(n) = issue {
715         diag.span_err(span, &format!("{} (see issue #{})", explain, n));
716     } else {
717         diag.span_err(span, explain);
718     }
719
720     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
721     if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; }
722     diag.fileline_help(span, &format!("add #![feature({})] to the \
723                                    crate attributes to enable",
724                                   feature));
725 }
726
727 pub const EXPLAIN_ASM: &'static str =
728     "inline assembly is not stable enough for use and is subject to change";
729
730 pub const EXPLAIN_LOG_SYNTAX: &'static str =
731     "`log_syntax!` is not stable enough for use and is subject to change";
732
733 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
734     "`concat_idents` is not stable enough for use and is subject to change";
735
736 pub const EXPLAIN_TRACE_MACROS: &'static str =
737     "`trace_macros` is not stable enough for use and is subject to change";
738 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
739     "allow_internal_unstable side-steps feature gating and stability checks";
740
741 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
742     "`#[derive]` for custom traits is not stable enough for use and is subject to change";
743
744 struct MacroVisitor<'a> {
745     context: &'a Context<'a>
746 }
747
748 impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
749     fn visit_mac(&mut self, mac: &ast::Mac) {
750         let path = &mac.node.path;
751         let name = path.segments.last().unwrap().identifier.name.as_str();
752
753         // Issue 22234: If you add a new case here, make sure to also
754         // add code to catch the macro during or after expansion.
755         //
756         // We still keep this MacroVisitor (rather than *solely*
757         // relying on catching cases during or after expansion) to
758         // catch uses of these macros within conditionally-compiled
759         // code, e.g. `#[cfg]`-guarded functions.
760
761         if name == "asm" {
762             self.context.gate_feature("asm", path.span, EXPLAIN_ASM);
763         }
764
765         else if name == "log_syntax" {
766             self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX);
767         }
768
769         else if name == "trace_macros" {
770             self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS);
771         }
772
773         else if name == "concat_idents" {
774             self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS);
775         }
776     }
777
778     fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
779         self.context.check_attribute(attr, true);
780     }
781
782     fn visit_expr(&mut self, e: &ast::Expr) {
783         // Issue 22181: overloaded-`box` and placement-`in` are
784         // implemented via a desugaring expansion, so their feature
785         // gates go into MacroVisitor since that works pre-expansion.
786         //
787         // Issue 22234: we also check during expansion as well.
788         // But we keep these checks as a pre-expansion check to catch
789         // uses in e.g. conditionalized code.
790
791         if let ast::ExprBox(_) = e.node {
792             self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX);
793         }
794
795         if let ast::ExprInPlace(..) = e.node {
796             self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN);
797         }
798
799         visit::walk_expr(self, e);
800     }
801 }
802
803 struct PostExpansionVisitor<'a> {
804     context: &'a Context<'a>,
805 }
806
807 impl<'a> PostExpansionVisitor<'a> {
808     fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
809         if !self.context.cm.span_allows_unstable(span) {
810             self.context.gate_feature(feature, span, explain)
811         }
812     }
813 }
814
815 impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
816     fn visit_attribute(&mut self, attr: &ast::Attribute) {
817         if !self.context.cm.span_allows_unstable(attr.span) {
818             self.context.check_attribute(attr, false);
819         }
820     }
821
822     fn visit_name(&mut self, sp: Span, name: ast::Name) {
823         if !name.as_str().is_ascii() {
824             self.gate_feature("non_ascii_idents", sp,
825                               "non-ascii idents are not fully supported.");
826         }
827     }
828
829     fn visit_item(&mut self, i: &ast::Item) {
830         match i.node {
831             ast::ItemExternCrate(_) => {
832                 if attr::contains_name(&i.attrs[..], "macro_reexport") {
833                     self.gate_feature("macro_reexport", i.span,
834                                       "macros reexports are experimental \
835                                        and possibly buggy");
836                 }
837             }
838
839             ast::ItemForeignMod(ref foreign_module) => {
840                 if attr::contains_name(&i.attrs[..], "link_args") {
841                     self.gate_feature("link_args", i.span,
842                                       "the `link_args` attribute is not portable \
843                                        across platforms, it is recommended to \
844                                        use `#[link(name = \"foo\")]` instead")
845                 }
846                 let maybe_feature = match foreign_module.abi {
847                     Abi::RustIntrinsic => Some(("intrinsics", "intrinsics are subject to change")),
848                     Abi::PlatformIntrinsic => {
849                         Some(("platform_intrinsics",
850                               "platform intrinsics are experimental and possibly buggy"))
851                     }
852                     _ => None
853                 };
854                 if let Some((feature, msg)) = maybe_feature {
855                     self.gate_feature(feature, i.span, msg)
856                 }
857             }
858
859             ast::ItemFn(..) => {
860                 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
861                     self.gate_feature("plugin_registrar", i.span,
862                                       "compiler plugins are experimental and possibly buggy");
863                 }
864                 if attr::contains_name(&i.attrs[..], "start") {
865                     self.gate_feature("start", i.span,
866                                       "a #[start] function is an experimental \
867                                        feature whose signature may change \
868                                        over time");
869                 }
870                 if attr::contains_name(&i.attrs[..], "main") {
871                     self.gate_feature("main", i.span,
872                                       "declaration of a nonstandard #[main] \
873                                        function may change over time, for now \
874                                        a top-level `fn main()` is required");
875                 }
876             }
877
878             ast::ItemStruct(..) => {
879                 if attr::contains_name(&i.attrs[..], "simd") {
880                     self.gate_feature("simd", i.span,
881                                       "SIMD types are experimental and possibly buggy");
882                     self.context.span_handler.span_warn(i.span,
883                                                         "the `#[simd]` attribute is deprecated, \
884                                                          use `#[repr(simd)]` instead");
885                 }
886                 for attr in &i.attrs {
887                     if attr.name() == "repr" {
888                         for item in attr.meta_item_list().unwrap_or(&[]) {
889                             if item.name() == "simd" {
890                                 self.gate_feature("repr_simd", i.span,
891                                                   "SIMD types are experimental and possibly buggy");
892
893                             }
894                         }
895                     }
896                 }
897             }
898
899             ast::ItemDefaultImpl(..) => {
900                 self.gate_feature("optin_builtin_traits",
901                                   i.span,
902                                   "default trait implementations are experimental \
903                                    and possibly buggy");
904             }
905
906             ast::ItemImpl(_, polarity, _, _, _, _) => {
907                 match polarity {
908                     ast::ImplPolarity::Negative => {
909                         self.gate_feature("optin_builtin_traits",
910                                           i.span,
911                                           "negative trait bounds are not yet fully implemented; \
912                                           use marker types for now");
913                     },
914                     _ => {}
915                 }
916             }
917
918             _ => {}
919         }
920
921         visit::walk_item(self, i);
922     }
923
924     fn visit_variant_data(&mut self, s: &'v ast::VariantData, _: ast::Ident,
925                         _: &'v ast::Generics, _: ast::NodeId, span: Span) {
926         if s.fields().is_empty() {
927             if s.is_struct() {
928                 self.gate_feature("braced_empty_structs", span,
929                                   "empty structs and enum variants with braces are unstable");
930             } else if s.is_tuple() {
931                 self.context.span_handler.span_err(span, "empty tuple structs and enum variants \
932                                                           are not allowed, use unit structs and \
933                                                           enum variants instead");
934                 self.context.span_handler.span_help(span, "remove trailing `()` to make a unit \
935                                                            struct or unit enum variant");
936             }
937         }
938         visit::walk_struct_def(self, s)
939     }
940
941     fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
942         let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
943                                                                      "link_name") {
944             Some(val) => val.starts_with("llvm."),
945             _ => false
946         };
947         if links_to_llvm {
948             self.gate_feature("link_llvm_intrinsics", i.span,
949                               "linking to LLVM intrinsics is experimental");
950         }
951
952         visit::walk_foreign_item(self, i)
953     }
954
955     fn visit_expr(&mut self, e: &ast::Expr) {
956         match e.node {
957             ast::ExprBox(_) => {
958                 self.gate_feature("box_syntax",
959                                   e.span,
960                                   "box expression syntax is experimental; \
961                                    you can call `Box::new` instead.");
962             }
963             _ => {}
964         }
965         visit::walk_expr(self, e);
966     }
967
968     fn visit_pat(&mut self, pattern: &ast::Pat) {
969         match pattern.node {
970             ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
971                 self.gate_feature("advanced_slice_patterns",
972                                   pattern.span,
973                                   "multiple-element slice matches anywhere \
974                                    but at the end of a slice (e.g. \
975                                    `[0, ..xs, 0]`) are experimental")
976             }
977             ast::PatVec(..) => {
978                 self.gate_feature("slice_patterns",
979                                   pattern.span,
980                                   "slice pattern syntax is experimental");
981             }
982             ast::PatBox(..) => {
983                 self.gate_feature("box_patterns",
984                                   pattern.span,
985                                   "box pattern syntax is experimental");
986             }
987             _ => {}
988         }
989         visit::walk_pat(self, pattern)
990     }
991
992     fn visit_fn(&mut self,
993                 fn_kind: FnKind<'v>,
994                 fn_decl: &'v ast::FnDecl,
995                 block: &'v ast::Block,
996                 span: Span,
997                 _node_id: NodeId) {
998         // check for const fn declarations
999         match fn_kind {
1000             FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1001                 self.gate_feature("const_fn", span, "const fn is unstable");
1002             }
1003             _ => {
1004                 // stability of const fn methods are covered in
1005                 // visit_trait_item and visit_impl_item below; this is
1006                 // because default methods don't pass through this
1007                 // point.
1008             }
1009         }
1010
1011         match fn_kind {
1012             FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
1013                 self.gate_feature("intrinsics",
1014                                   span,
1015                                   "intrinsics are subject to change")
1016             }
1017             FnKind::ItemFn(_, _, _, _, abi, _) |
1018             FnKind::Method(_, &ast::MethodSig { abi, .. }, _) if abi == Abi::RustCall => {
1019                 self.gate_feature("unboxed_closures",
1020                                   span,
1021                                   "rust-call ABI is subject to change")
1022             }
1023             _ => {}
1024         }
1025         visit::walk_fn(self, fn_kind, fn_decl, block, span);
1026     }
1027
1028     fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
1029         match ti.node {
1030             ast::ConstTraitItem(..) => {
1031                 self.gate_feature("associated_consts",
1032                                   ti.span,
1033                                   "associated constants are experimental")
1034             }
1035             ast::MethodTraitItem(ref sig, _) => {
1036                 if sig.constness == ast::Constness::Const {
1037                     self.gate_feature("const_fn", ti.span, "const fn is unstable");
1038                 }
1039             }
1040             ast::TypeTraitItem(_, Some(_)) => {
1041                 self.gate_feature("associated_type_defaults", ti.span,
1042                                   "associated type defaults are unstable");
1043             }
1044             _ => {}
1045         }
1046         visit::walk_trait_item(self, ti);
1047     }
1048
1049     fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
1050         match ii.node {
1051             ast::ImplItemKind::Const(..) => {
1052                 self.gate_feature("associated_consts",
1053                                   ii.span,
1054                                   "associated constants are experimental")
1055             }
1056             ast::ImplItemKind::Method(ref sig, _) => {
1057                 if sig.constness == ast::Constness::Const {
1058                     self.gate_feature("const_fn", ii.span, "const fn is unstable");
1059                 }
1060             }
1061             _ => {}
1062         }
1063         visit::walk_impl_item(self, ii);
1064     }
1065 }
1066
1067 fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
1068                         krate: &ast::Crate,
1069                         plugin_attributes: &[(String, AttributeType)],
1070                         check: F)
1071                        -> Features
1072     where F: FnOnce(&mut Context, &ast::Crate)
1073 {
1074     let mut cx = Context {
1075         features: Vec::new(),
1076         span_handler: span_handler,
1077         cm: cm,
1078         plugin_attributes: plugin_attributes,
1079     };
1080
1081     let mut accepted_features = Vec::new();
1082     let mut unknown_features = Vec::new();
1083
1084     for attr in &krate.attrs {
1085         if !attr.check_name("feature") {
1086             continue
1087         }
1088
1089         match attr.meta_item_list() {
1090             None => {
1091                 span_handler.span_err(attr.span, "malformed feature attribute, \
1092                                                   expected #![feature(...)]");
1093             }
1094             Some(list) => {
1095                 for mi in list {
1096                     let name = match mi.node {
1097                         ast::MetaWord(ref word) => (*word).clone(),
1098                         _ => {
1099                             span_handler.span_err(mi.span,
1100                                                   "malformed feature, expected just \
1101                                                    one word");
1102                             continue
1103                         }
1104                     };
1105                     match KNOWN_FEATURES.iter()
1106                                         .find(|& &(n, _, _, _)| name == n) {
1107                         Some(&(name, _, _, Active)) => {
1108                             cx.enable_feature(name);
1109                         }
1110                         Some(&(_, _, _, Removed)) => {
1111                             span_handler.span_err(mi.span, "feature has been removed");
1112                         }
1113                         Some(&(_, _, _, Accepted)) => {
1114                             accepted_features.push(mi.span);
1115                         }
1116                         None => {
1117                             unknown_features.push((name, mi.span));
1118                         }
1119                     }
1120                 }
1121             }
1122         }
1123     }
1124
1125     check(&mut cx, krate);
1126
1127     // FIXME (pnkfelix): Before adding the 99th entry below, change it
1128     // to a single-pass (instead of N calls to `.has_feature`).
1129
1130     Features {
1131         unboxed_closures: cx.has_feature("unboxed_closures"),
1132         rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
1133         visible_private_types: cx.has_feature("visible_private_types"),
1134         allow_quote: cx.has_feature("quote"),
1135         allow_asm: cx.has_feature("asm"),
1136         allow_log_syntax: cx.has_feature("log_syntax"),
1137         allow_concat_idents: cx.has_feature("concat_idents"),
1138         allow_trace_macros: cx.has_feature("trace_macros"),
1139         allow_internal_unstable: cx.has_feature("allow_internal_unstable"),
1140         allow_custom_derive: cx.has_feature("custom_derive"),
1141         allow_placement_in: cx.has_feature("placement_in_syntax"),
1142         allow_box: cx.has_feature("box_syntax"),
1143         allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"),
1144         simd_ffi: cx.has_feature("simd_ffi"),
1145         unmarked_api: cx.has_feature("unmarked_api"),
1146         negate_unsigned: cx.has_feature("negate_unsigned"),
1147         declared_stable_lang_features: accepted_features,
1148         declared_lib_features: unknown_features,
1149         const_fn: cx.has_feature("const_fn"),
1150         const_indexing: cx.has_feature("const_indexing"),
1151         static_recursion: cx.has_feature("static_recursion"),
1152         default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"),
1153         type_macros: cx.has_feature("type_macros"),
1154         cfg_target_feature: cx.has_feature("cfg_target_feature"),
1155         cfg_target_vendor: cx.has_feature("cfg_target_vendor"),
1156         augmented_assignments: cx.has_feature("augmented_assignments"),
1157         braced_empty_structs: cx.has_feature("braced_empty_structs"),
1158         staged_api: cx.has_feature("staged_api"),
1159         stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"),
1160         deprecated: cx.has_feature("deprecated"),
1161     }
1162 }
1163
1164 pub fn check_crate_macros(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate)
1165 -> Features {
1166     check_crate_inner(cm, span_handler, krate, &[] as &'static [_],
1167                       |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate))
1168 }
1169
1170 pub fn check_crate(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate,
1171                    plugin_attributes: &[(String, AttributeType)],
1172                    unstable: UnstableFeatures) -> Features
1173 {
1174     maybe_stage_features(span_handler, krate, unstable);
1175
1176     check_crate_inner(cm, span_handler, krate, plugin_attributes,
1177                       |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx },
1178                                                      krate))
1179 }
1180
1181 #[derive(Clone, Copy)]
1182 pub enum UnstableFeatures {
1183     /// Hard errors for unstable features are active, as on
1184     /// beta/stable channels.
1185     Disallow,
1186     /// Allow features to me activated, as on nightly.
1187     Allow,
1188     /// Errors are bypassed for bootstrapping. This is required any time
1189     /// during the build that feature-related lints are set to warn or above
1190     /// because the build turns on warnings-as-errors and uses lots of unstable
1191     /// features. As a result, this is always required for building Rust itself.
1192     Cheat
1193 }
1194
1195 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1196                         unstable: UnstableFeatures) {
1197     let allow_features = match unstable {
1198         UnstableFeatures::Allow => true,
1199         UnstableFeatures::Disallow => false,
1200         UnstableFeatures::Cheat => true
1201     };
1202     if !allow_features {
1203         for attr in &krate.attrs {
1204             if attr.check_name("feature") {
1205                 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1206                 let ref msg = format!("#[feature] may not be used on the {} release channel",
1207                                       release_channel);
1208                 span_handler.span_err(attr.span, msg);
1209             }
1210         }
1211     }
1212 }