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