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.
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.
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
18 //! Features are enabled in programs via the crate-level attributes of
19 //! `#![feature(...)]` with a comma-separated list of features.
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
26 use self::AttributeType::*;
27 use self::AttributeGate::*;
33 use attr::AttrMetaMethods;
34 use codemap::{CodeMap, Span};
35 use diagnostic::SpanHandler;
37 use visit::{FnKind, Visitor};
38 use parse::token::InternedString;
40 use std::ascii::AsciiExt;
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
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),
64 // rustc internal, for now:
65 ("intrinsics", "1.0.0", None, Active),
66 ("lang_items", "1.0.0", None, Active),
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),
75 ("quad_precision_float", "1.0.0", None, Removed),
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),
91 ("pushpop_unsafe", "1.2.0", None, Active),
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),
99 ("if_let", "1.0.0", None, Accepted),
100 ("while_let", "1.0.0", None, Accepted),
102 ("plugin", "1.0.0", Some(29597), Active),
103 ("start", "1.0.0", Some(29633), Active),
104 ("main", "1.0.0", Some(29634), Active),
106 ("fundamental", "1.0.0", Some(29635), Active),
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),
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),
115 // OIBIT specific features
116 ("optin_builtin_traits", "1.0.0", Some(13231), Active),
118 // macro reexport needs more discussion and stabilization
119 ("macro_reexport", "1.0.0", Some(29638), Active),
121 // These are used to test this portion of the compiler, they don't actually
123 ("test_accepted_feature", "1.0.0", None, Accepted),
124 ("test_removed_feature", "1.0.0", None, Removed),
126 // Allows use of #[staged_api]
128 ("staged_api", "1.0.0", None, Active),
130 // Allows using items which are missing stability attributes
132 ("unmarked_api", "1.0.0", None, Active),
134 // Allows using #![no_std]
135 ("no_std", "1.0.0", None, Accepted),
137 // Allows using #![no_core]
138 ("no_core", "1.3.0", Some(29639), Active),
140 // Allows using `box` in patterns; RFC 469
141 ("box_patterns", "1.0.0", Some(29641), Active),
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),
147 // Allows using the unsafe_destructor_blind_to_params attribute;
149 ("dropck_parametricity", "1.3.0", Some(28498), Active),
151 // Allows the use of custom attributes; RFC 572
152 ("custom_attribute", "1.0.0", Some(29642), Active),
154 // Allows the use of #[derive(Anything)] as sugar for
155 // #[derive_Anything].
156 ("custom_derive", "1.0.0", Some(29644), Active),
158 // Allows the use of rustc_* attributes; RFC 572
159 ("rustc_attrs", "1.0.0", Some(29642), Active),
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).
167 ("allow_internal_unstable", "1.0.0", None, Active),
169 // #23121. Array patterns have some hazards yet.
170 ("slice_patterns", "1.0.0", Some(23121), Active),
172 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
173 ("negate_unsigned", "1.0.0", Some(29645), Active),
175 // Allows the definition of associated constants in `trait` or `impl`
177 ("associated_consts", "1.0.0", Some(29646), Active),
179 // Allows the definition of `const fn` functions.
180 ("const_fn", "1.2.0", Some(24111), Active),
182 // Allows indexing into constant arrays.
183 ("const_indexing", "1.4.0", Some(29947), Active),
185 // Allows using #[prelude_import] on glob `use` items.
188 ("prelude_import", "1.2.0", None, Active),
190 // Allows the definition recursive static items.
191 ("static_recursion", "1.3.0", Some(29719), Active),
193 // Allows default type parameters to influence type inference.
194 ("default_type_parameter_fallback", "1.3.0", Some(27336), Active),
196 // Allows associated type defaults
197 ("associated_type_defaults", "1.2.0", Some(29661), Active),
199 // Allows macros to appear in the type position.
200 ("type_macros", "1.3.0", Some(27336), Active),
202 // allow `repr(simd)`, and importing the various simd intrinsics
203 ("repr_simd", "1.4.0", Some(27731), Active),
205 // Allows cfg(target_feature = "...").
206 ("cfg_target_feature", "1.4.0", Some(29717), Active),
208 // allow `extern "platform-intrinsic" { ... }`
209 ("platform_intrinsics", "1.4.0", Some(27731), Active),
212 // rust runtime internal
213 ("unwind_attributes", "1.4.0", None, Active),
215 // allow empty structs and enum variants with braces
216 ("braced_empty_structs", "1.5.0", Some(29720), Active),
218 // allow overloading augmented assignment operations like `a += b`
219 ("augmented_assignments", "1.5.0", Some(28235), Active),
221 // allow `#[no_debug]`
222 ("no_debug", "1.5.0", Some(29721), Active),
224 // allow `#[omit_gdb_pretty_printer_section]`
226 ("omit_gdb_pretty_printer_section", "1.5.0", None, Active),
228 // Allows cfg(target_vendor = "...").
229 ("cfg_target_vendor", "1.5.0", Some(29718), Active),
231 // Allow attributes on expressions and non-item statements
232 ("stmt_expr_attributes", "1.6.0", Some(15701), Active),
234 // Allows `#[deprecated]` attribute
235 ("deprecated", "1.6.0", Some(29935), Active),
237 // (changing above list without updating src/doc/reference.md makes @cmr sad)
240 /// Represents an active feature that is currently being implemented or
241 /// currently being considered for addition/removal.
244 /// Represents a feature which has since been removed (it was once Active)
247 /// This language feature has since been Accepted (it was once Active)
251 // Attributes that have a special meaning to rustc or rustdoc
252 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
255 ("warn", Normal, Ungated),
256 ("allow", Normal, Ungated),
257 ("forbid", Normal, Ungated),
258 ("deny", Normal, Ungated),
260 ("macro_reexport", Normal, Ungated),
261 ("macro_use", Normal, Ungated),
262 ("macro_export", Normal, Ungated),
263 ("plugin_registrar", Normal, Ungated),
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),
286 // Not used any more, but we can't feature gate it
287 ("no_stack_check", Normal, Ungated),
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 \
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 \
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")),
332 ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
333 EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
335 ("fundamental", Whitelisted, Gated("fundamental",
336 "the `#[fundamental]` attribute \
337 is an experimental feature")),
339 ("linked_from", Normal, Gated("linked_from",
340 "the `#[linked_from]` attribute \
341 is an experimental feature")),
343 // FIXME: #14408 whitelist docs since rustdoc looks at them
344 ("doc", Whitelisted, Ungated),
346 // FIXME: #14406 these are processed in trans, which happens after the
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 \
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",
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")),
374 ("prelude_import", Whitelisted, Gated("prelude_import",
375 "`#[prelude_import]` is for use by rustc only")),
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")),
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")),
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),
401 macro_rules! cfg_fn {
402 (|$x: ident| $e: expr) => {{
403 fn f($x: &Features) -> bool {
406 f as fn(&Features) -> bool
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)),
416 #[derive(Debug, Eq, PartialEq)]
417 pub enum GatedCfgAttr {
422 #[derive(Debug, Eq, PartialEq)]
423 pub struct GatedCfg {
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)
434 GatedCfgAttr::GatedAttr(ref span) => {
435 (span.lo.0, span.hi.0, GATED_CFGS.len())
438 to_tup(self).cmp(&to_tup(other))
442 impl PartialOrd for GatedCfgAttr {
443 fn partial_cmp(&self, other: &GatedCfgAttr) -> Option<cmp::Ordering> {
444 Some(self.cmp(other))
449 pub fn check_and_emit(&self, diagnostic: &SpanHandler, features: &Features) {
451 GatedCfgAttr::GatedCfg(ref cfg) => {
452 cfg.check_and_emit(diagnostic, features);
454 GatedCfgAttr::GatedAttr(span) => {
455 if !features.stmt_expr_attributes {
456 emit_feature_err(diagnostic,
457 "stmt_expr_attributes",
460 EXPLAIN_STMT_ATTR_SYNTAX);
468 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
469 let name = cfg.name();
471 .position(|info| info.0 == name)
479 fn check_and_emit(&self, diagnostic: &SpanHandler, 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);
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
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
500 /// Builtin attribute that is only allowed at the crate level
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),
509 /// Ungated attribute, can be used on all release channels
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,
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,
527 pub allow_pushpop_unsafe: 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)>,
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,
550 pub fn new() -> Features {
552 unboxed_closures: false,
553 rustc_diagnostic_macros: false,
554 visible_private_types: 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,
564 allow_pushpop_unsafe: false,
567 negate_unsigned: false,
568 declared_stable_lang_features: Vec::new(),
569 declared_lib_features: Vec::new(),
571 const_indexing: false,
572 static_recursion: false,
573 default_type_parameter_fallback: false,
575 cfg_target_feature: false,
576 cfg_target_vendor: false,
577 augmented_assignments: false,
578 braced_empty_structs: false,
580 stmt_expr_attributes: false,
586 const EXPLAIN_BOX_SYNTAX: &'static str =
587 "box expression syntax is experimental; you can call `Box::new` instead.";
589 const EXPLAIN_PLACEMENT_IN: &'static str =
590 "placement-in expression syntax is experimental and subject to change.";
592 const EXPLAIN_PUSHPOP_UNSAFE: &'static str =
593 "push/pop_unsafe macros are experimental and subject to change.";
595 const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
596 "attributes on non-item statements and expressions are experimental.";
598 pub fn check_for_box_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) {
599 if let Some(&Features { allow_box: true, .. }) = f {
602 emit_feature_err(diag, "box_syntax", span, GateIssue::Language, EXPLAIN_BOX_SYNTAX);
605 pub fn check_for_placement_in(f: Option<&Features>, diag: &SpanHandler, span: Span) {
606 if let Some(&Features { allow_placement_in: true, .. }) = f {
609 emit_feature_err(diag, "placement_in_syntax", span, GateIssue::Language, EXPLAIN_PLACEMENT_IN);
612 pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) {
613 if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f {
616 emit_feature_err(diag, "pushpop_unsafe", span, GateIssue::Language, EXPLAIN_PUSHPOP_UNSAFE);
620 features: Vec<&'static str>,
621 span_handler: &'a SpanHandler,
623 plugin_attributes: &'a [(String, AttributeType)],
626 impl<'a> Context<'a> {
627 fn enable_feature(&mut self, feature: &'static str) {
628 debug!("enabling feature: {}", feature);
629 self.features.push(feature);
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);
636 emit_feature_err(self.span_handler, feature, span, GateIssue::Language, explain);
639 fn has_feature(&self, feature: &str) -> bool {
640 self.features.iter().any(|&n| n == feature)
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 {
648 if let Gated(gate, desc) = gateage {
649 self.gate_feature(gate, attr.span, desc);
651 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
655 for &(ref n, ref ty) in self.plugin_attributes {
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);
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 \
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
679 self.gate_feature("custom_attribute", attr.span,
680 &format!("The attribute `{}` is currently \
681 unknown to the compiler and \
683 added to it in the future",
690 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
691 let info = KNOWN_FEATURES.iter()
692 .find(|t| t.0 == feature)
695 if let Active = info.3 {
696 // FIXME (#28244): enforce that active features have issue numbers
697 // assert!(issue.is_some())
707 pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, issue: GateIssue,
709 let issue = match issue {
710 GateIssue::Language => find_lang_feature_issue(feature),
711 GateIssue::Library(lib) => lib,
714 if let Some(n) = issue {
715 diag.span_err(span, &format!("{} (see issue #{})", explain, n));
717 diag.span_err(span, explain);
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",
727 pub const EXPLAIN_ASM: &'static str =
728 "inline assembly is not stable enough for use and is subject to change";
730 pub const EXPLAIN_LOG_SYNTAX: &'static str =
731 "`log_syntax!` is not stable enough for use and is subject to change";
733 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
734 "`concat_idents` is not stable enough for use and is subject to change";
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";
741 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
742 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
744 struct MacroVisitor<'a> {
745 context: &'a Context<'a>
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();
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.
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.
762 self.context.gate_feature("asm", path.span, EXPLAIN_ASM);
765 else if name == "log_syntax" {
766 self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX);
769 else if name == "trace_macros" {
770 self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS);
773 else if name == "concat_idents" {
774 self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS);
778 fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
779 self.context.check_attribute(attr, true);
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.
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.
791 if let ast::ExprBox(_) = e.node {
792 self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX);
795 if let ast::ExprInPlace(..) = e.node {
796 self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN);
799 visit::walk_expr(self, e);
803 struct PostExpansionVisitor<'a> {
804 context: &'a Context<'a>,
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)
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);
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.");
829 fn visit_item(&mut self, i: &ast::Item) {
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");
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")
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"))
854 if let Some((feature, msg)) = maybe_feature {
855 self.gate_feature(feature, i.span, msg)
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");
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 \
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");
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");
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");
899 ast::ItemDefaultImpl(..) => {
900 self.gate_feature("optin_builtin_traits",
902 "default trait implementations are experimental \
903 and possibly buggy");
906 ast::ItemImpl(_, polarity, _, _, _, _) => {
908 ast::ImplPolarity::Negative => {
909 self.gate_feature("optin_builtin_traits",
911 "negative trait bounds are not yet fully implemented; \
912 use marker types for now");
921 visit::walk_item(self, i);
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() {
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");
938 visit::walk_struct_def(self, s)
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,
944 Some(val) => val.starts_with("llvm."),
948 self.gate_feature("link_llvm_intrinsics", i.span,
949 "linking to LLVM intrinsics is experimental");
952 visit::walk_foreign_item(self, i)
955 fn visit_expr(&mut self, e: &ast::Expr) {
958 self.gate_feature("box_syntax",
960 "box expression syntax is experimental; \
961 you can call `Box::new` instead.");
965 visit::walk_expr(self, e);
968 fn visit_pat(&mut self, pattern: &ast::Pat) {
970 ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
971 self.gate_feature("advanced_slice_patterns",
973 "multiple-element slice matches anywhere \
974 but at the end of a slice (e.g. \
975 `[0, ..xs, 0]`) are experimental")
978 self.gate_feature("slice_patterns",
980 "slice pattern syntax is experimental");
983 self.gate_feature("box_patterns",
985 "box pattern syntax is experimental");
989 visit::walk_pat(self, pattern)
992 fn visit_fn(&mut self,
994 fn_decl: &'v ast::FnDecl,
995 block: &'v ast::Block,
998 // check for const fn declarations
1000 FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1001 self.gate_feature("const_fn", span, "const fn is unstable");
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
1012 FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
1013 self.gate_feature("intrinsics",
1015 "intrinsics are subject to change")
1017 FnKind::ItemFn(_, _, _, _, abi, _) |
1018 FnKind::Method(_, &ast::MethodSig { abi, .. }, _) if abi == Abi::RustCall => {
1019 self.gate_feature("unboxed_closures",
1021 "rust-call ABI is subject to change")
1025 visit::walk_fn(self, fn_kind, fn_decl, block, span);
1028 fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
1030 ast::ConstTraitItem(..) => {
1031 self.gate_feature("associated_consts",
1033 "associated constants are experimental")
1035 ast::MethodTraitItem(ref sig, _) => {
1036 if sig.constness == ast::Constness::Const {
1037 self.gate_feature("const_fn", ti.span, "const fn is unstable");
1040 ast::TypeTraitItem(_, Some(_)) => {
1041 self.gate_feature("associated_type_defaults", ti.span,
1042 "associated type defaults are unstable");
1046 visit::walk_trait_item(self, ti);
1049 fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
1051 ast::ImplItemKind::Const(..) => {
1052 self.gate_feature("associated_consts",
1054 "associated constants are experimental")
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");
1063 visit::walk_impl_item(self, ii);
1067 fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
1069 plugin_attributes: &[(String, AttributeType)],
1072 where F: FnOnce(&mut Context, &ast::Crate)
1074 let mut cx = Context {
1075 features: Vec::new(),
1076 span_handler: span_handler,
1078 plugin_attributes: plugin_attributes,
1081 let mut accepted_features = Vec::new();
1082 let mut unknown_features = Vec::new();
1084 for attr in &krate.attrs {
1085 if !attr.check_name("feature") {
1089 match attr.meta_item_list() {
1091 span_handler.span_err(attr.span, "malformed feature attribute, \
1092 expected #![feature(...)]");
1096 let name = match mi.node {
1097 ast::MetaWord(ref word) => (*word).clone(),
1099 span_handler.span_err(mi.span,
1100 "malformed feature, expected just \
1105 match KNOWN_FEATURES.iter()
1106 .find(|& &(n, _, _, _)| name == n) {
1107 Some(&(name, _, _, Active)) => {
1108 cx.enable_feature(name);
1110 Some(&(_, _, _, Removed)) => {
1111 span_handler.span_err(mi.span, "feature has been removed");
1113 Some(&(_, _, _, Accepted)) => {
1114 accepted_features.push(mi.span);
1117 unknown_features.push((name, mi.span));
1125 check(&mut cx, krate);
1127 // FIXME (pnkfelix): Before adding the 99th entry below, change it
1128 // to a single-pass (instead of N calls to `.has_feature`).
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"),
1164 pub fn check_crate_macros(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate)
1166 check_crate_inner(cm, span_handler, krate, &[] as &'static [_],
1167 |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate))
1170 pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate,
1171 plugin_attributes: &[(String, AttributeType)],
1172 unstable: UnstableFeatures) -> Features
1174 maybe_stage_features(span_handler, krate, unstable);
1176 check_crate_inner(cm, span_handler, krate, plugin_attributes,
1177 |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx },
1181 #[derive(Clone, Copy)]
1182 pub enum UnstableFeatures {
1183 /// Hard errors for unstable features are active, as on
1184 /// beta/stable channels.
1186 /// Allow features to me activated, as on nightly.
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.
1195 fn maybe_stage_features(span_handler: &SpanHandler, krate: &ast::Crate,
1196 unstable: UnstableFeatures) {
1197 let allow_features = match unstable {
1198 UnstableFeatures::Allow => true,
1199 UnstableFeatures::Disallow => false,
1200 UnstableFeatures::Cheat => true
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",
1208 span_handler.span_err(attr.span, msg);