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};
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", 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),
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 // allow using type ascription in expressions
238 ("type_ascription", "1.6.0", Some(23416), Active),
240 // Allows cfg(target_thread_local)
241 ("cfg_target_thread_local", "1.7.0", Some(29594), Active),
243 // (changing above list without updating src/doc/reference.md makes @cmr sad)
246 /// Represents an active feature that is currently being implemented or
247 /// currently being considered for addition/removal.
250 /// Represents a feature which has since been removed (it was once Active)
253 /// This language feature has since been Accepted (it was once Active)
257 // Attributes that have a special meaning to rustc or rustdoc
258 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
261 ("warn", Normal, Ungated),
262 ("allow", Normal, Ungated),
263 ("forbid", Normal, Ungated),
264 ("deny", Normal, Ungated),
266 ("macro_reexport", Normal, Ungated),
267 ("macro_use", Normal, Ungated),
268 ("macro_export", Normal, Ungated),
269 ("plugin_registrar", Normal, Ungated),
271 ("cfg", Normal, Ungated),
272 ("cfg_attr", Normal, Ungated),
273 ("main", Normal, Ungated),
274 ("start", Normal, Ungated),
275 ("test", Normal, Ungated),
276 ("bench", Normal, Ungated),
277 ("simd", Normal, Ungated),
278 ("repr", Normal, Ungated),
279 ("path", Normal, Ungated),
280 ("abi", Normal, Ungated),
281 ("automatically_derived", Normal, Ungated),
282 ("no_mangle", Normal, Ungated),
283 ("no_link", Normal, Ungated),
284 ("derive", Normal, Ungated),
285 ("should_panic", Normal, Ungated),
286 ("ignore", Normal, Ungated),
287 ("no_implicit_prelude", Normal, Ungated),
288 ("reexport_test_harness_main", Normal, Ungated),
289 ("link_args", Normal, Ungated),
290 ("macro_escape", Normal, Ungated),
292 // Not used any more, but we can't feature gate it
293 ("no_stack_check", Normal, Ungated),
295 ("plugin", CrateLevel, Gated("plugin",
296 "compiler plugins are experimental \
297 and possibly buggy")),
298 ("no_std", CrateLevel, Ungated),
299 ("no_core", CrateLevel, Gated("no_core",
300 "no_core is experimental")),
301 ("lang", Normal, Gated("lang_items",
302 "language items are subject to change")),
303 ("linkage", Whitelisted, Gated("linkage",
304 "the `linkage` attribute is experimental \
305 and not portable across platforms")),
306 ("thread_local", Whitelisted, Gated("thread_local",
307 "`#[thread_local]` is an experimental feature, and does \
308 not currently handle destructors. There is no \
309 corresponding `#[task_local]` mapping to the task \
312 ("rustc_on_unimplemented", Normal, Gated("on_unimplemented",
313 "the `#[rustc_on_unimplemented]` attribute \
314 is an experimental feature")),
315 ("allocator", Whitelisted, Gated("allocator",
316 "the `#[allocator]` attribute is an experimental feature")),
317 ("needs_allocator", Normal, Gated("needs_allocator",
318 "the `#[needs_allocator]` \
319 attribute is an experimental \
321 ("rustc_variance", Normal, Gated("rustc_attrs",
322 "the `#[rustc_variance]` attribute \
323 is just used for rustc unit tests \
324 and will never be stable")),
325 ("rustc_error", Whitelisted, Gated("rustc_attrs",
326 "the `#[rustc_error]` attribute \
327 is just used for rustc unit tests \
328 and will never be stable")),
329 ("rustc_move_fragments", Normal, Gated("rustc_attrs",
330 "the `#[rustc_move_fragments]` attribute \
331 is just used for rustc unit tests \
332 and will never be stable")),
333 ("rustc_mir", Normal, Gated("rustc_attrs",
334 "the `#[rustc_mir]` attribute \
335 is just used for rustc unit tests \
336 and will never be stable")),
338 ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
339 EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
341 ("fundamental", Whitelisted, Gated("fundamental",
342 "the `#[fundamental]` attribute \
343 is an experimental feature")),
345 ("linked_from", Normal, Gated("linked_from",
346 "the `#[linked_from]` attribute \
347 is an experimental feature")),
349 // FIXME: #14408 whitelist docs since rustdoc looks at them
350 ("doc", Whitelisted, Ungated),
352 // FIXME: #14406 these are processed in trans, which happens after the
354 ("cold", Whitelisted, Ungated),
355 ("export_name", Whitelisted, Ungated),
356 ("inline", Whitelisted, Ungated),
357 ("link", Whitelisted, Ungated),
358 ("link_name", Whitelisted, Ungated),
359 ("link_section", Whitelisted, Ungated),
360 ("no_builtins", Whitelisted, Ungated),
361 ("no_mangle", Whitelisted, Ungated),
362 ("no_debug", Whitelisted, Gated("no_debug",
363 "the `#[no_debug]` attribute \
364 is an experimental feature")),
365 ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
366 "the `#[omit_gdb_pretty_printer_section]` \
367 attribute is just used for the Rust test \
369 ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
370 "unsafe_no_drop_flag has unstable semantics \
371 and may be removed in the future")),
372 ("unsafe_destructor_blind_to_params",
374 Gated("dropck_parametricity",
375 "unsafe_destructor_blind_to_params has unstable semantics \
376 and may be removed in the future")),
377 ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental")),
380 ("prelude_import", Whitelisted, Gated("prelude_import",
381 "`#[prelude_import]` is for use by rustc only")),
383 // FIXME: #14407 these are only looked at on-demand so we can't
384 // guarantee they'll have already been checked
385 ("rustc_deprecated", Whitelisted, Ungated),
386 ("must_use", Whitelisted, Ungated),
387 ("stable", Whitelisted, Ungated),
388 ("unstable", Whitelisted, Ungated),
389 ("deprecated", Normal, Gated("deprecated", "`#[deprecated]` attribute is unstable")),
391 ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
392 "unboxed_closures are still evolving")),
393 ("rustc_reflect_like", Whitelisted, Gated("reflect",
394 "defining reflective traits is still evolving")),
396 // Crate level attributes
397 ("crate_name", CrateLevel, Ungated),
398 ("crate_type", CrateLevel, Ungated),
399 ("crate_id", CrateLevel, Ungated),
400 ("feature", CrateLevel, Ungated),
401 ("no_start", CrateLevel, Ungated),
402 ("no_main", CrateLevel, Ungated),
403 ("no_builtins", CrateLevel, Ungated),
404 ("recursion_limit", CrateLevel, Ungated),
407 macro_rules! cfg_fn {
408 (|$x: ident| $e: expr) => {{
409 fn f($x: &Features) -> bool {
412 f as fn(&Features) -> bool
415 // cfg(...)'s that are feature gated
416 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
417 // (name in cfg, feature, function to check if the feature is enabled)
418 ("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)),
419 ("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)),
420 ("target_thread_local", "cfg_target_thread_local",
421 cfg_fn!(|x| x.cfg_target_thread_local)),
424 #[derive(Debug, Eq, PartialEq)]
425 pub enum GatedCfgAttr {
430 #[derive(Debug, Eq, PartialEq)]
431 pub struct GatedCfg {
436 impl Ord for GatedCfgAttr {
437 fn cmp(&self, other: &GatedCfgAttr) -> cmp::Ordering {
438 let to_tup = |s: &GatedCfgAttr| match *s {
439 GatedCfgAttr::GatedCfg(ref gated_cfg) => {
440 (gated_cfg.span.lo.0, gated_cfg.span.hi.0, gated_cfg.index)
442 GatedCfgAttr::GatedAttr(ref span) => {
443 (span.lo.0, span.hi.0, GATED_CFGS.len())
446 to_tup(self).cmp(&to_tup(other))
450 impl PartialOrd for GatedCfgAttr {
451 fn partial_cmp(&self, other: &GatedCfgAttr) -> Option<cmp::Ordering> {
452 Some(self.cmp(other))
457 pub fn check_and_emit(&self,
458 diagnostic: &Handler,
462 GatedCfgAttr::GatedCfg(ref cfg) => {
463 cfg.check_and_emit(diagnostic, features, codemap);
465 GatedCfgAttr::GatedAttr(span) => {
466 if !features.stmt_expr_attributes {
467 emit_feature_err(diagnostic,
468 "stmt_expr_attributes",
471 EXPLAIN_STMT_ATTR_SYNTAX);
479 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
480 let name = cfg.name();
482 .position(|info| info.0 == name)
490 fn check_and_emit(&self,
491 diagnostic: &Handler,
494 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
495 if !has_feature(features) && !codemap.span_allows_unstable(self.span) {
496 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
497 emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
503 #[derive(PartialEq, Copy, Clone, Debug)]
504 pub enum AttributeType {
505 /// Normal, builtin attribute that is consumed
506 /// by the compiler before the unused_attribute check
509 /// Builtin attribute that may not be consumed by the compiler
510 /// before the unused_attribute check. These attributes
511 /// will be ignored by the unused_attribute lint
514 /// Builtin attribute that is only allowed at the crate level
518 #[derive(PartialEq, Copy, Clone, Debug)]
519 pub enum AttributeGate {
520 /// Is gated by a given feature gate and reason
521 Gated(&'static str, &'static str),
523 /// Ungated attribute, can be used on all release channels
527 /// A set of features to be used by later passes.
528 pub struct Features {
529 pub unboxed_closures: bool,
530 pub rustc_diagnostic_macros: bool,
531 pub allow_quote: bool,
533 pub allow_log_syntax: bool,
534 pub allow_concat_idents: bool,
535 pub allow_trace_macros: bool,
536 pub allow_internal_unstable: bool,
537 pub allow_custom_derive: bool,
538 pub allow_placement_in: bool,
540 pub allow_pushpop_unsafe: bool,
542 pub unmarked_api: bool,
543 pub negate_unsigned: bool,
544 /// spans of #![feature] attrs for stable language features. for error reporting
545 pub declared_stable_lang_features: Vec<Span>,
546 /// #![feature] attrs for non-language (library) features
547 pub declared_lib_features: Vec<(InternedString, Span)>,
549 pub const_indexing: bool,
550 pub static_recursion: bool,
551 pub default_type_parameter_fallback: bool,
552 pub type_macros: bool,
553 pub cfg_target_feature: bool,
554 pub cfg_target_vendor: bool,
555 pub cfg_target_thread_local: bool,
556 pub augmented_assignments: bool,
557 pub braced_empty_structs: bool,
558 pub staged_api: bool,
559 pub stmt_expr_attributes: bool,
560 pub deprecated: bool,
564 pub fn new() -> Features {
566 unboxed_closures: false,
567 rustc_diagnostic_macros: false,
570 allow_log_syntax: false,
571 allow_concat_idents: false,
572 allow_trace_macros: false,
573 allow_internal_unstable: false,
574 allow_custom_derive: false,
575 allow_placement_in: false,
577 allow_pushpop_unsafe: false,
580 negate_unsigned: false,
581 declared_stable_lang_features: Vec::new(),
582 declared_lib_features: Vec::new(),
584 const_indexing: false,
585 static_recursion: false,
586 default_type_parameter_fallback: false,
588 cfg_target_feature: false,
589 cfg_target_vendor: false,
590 cfg_target_thread_local: false,
591 augmented_assignments: false,
592 braced_empty_structs: false,
594 stmt_expr_attributes: false,
600 const EXPLAIN_BOX_SYNTAX: &'static str =
601 "box expression syntax is experimental; you can call `Box::new` instead.";
603 const EXPLAIN_PLACEMENT_IN: &'static str =
604 "placement-in expression syntax is experimental and subject to change.";
606 const EXPLAIN_PUSHPOP_UNSAFE: &'static str =
607 "push/pop_unsafe macros are experimental and subject to change.";
609 const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
610 "attributes on non-item statements and expressions are experimental.";
612 pub fn check_for_box_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
613 if let Some(&Features { allow_box: true, .. }) = f {
616 emit_feature_err(diag, "box_syntax", span, GateIssue::Language, EXPLAIN_BOX_SYNTAX);
619 pub fn check_for_placement_in(f: Option<&Features>, diag: &Handler, span: Span) {
620 if let Some(&Features { allow_placement_in: true, .. }) = f {
623 emit_feature_err(diag, "placement_in_syntax", span, GateIssue::Language, EXPLAIN_PLACEMENT_IN);
626 pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
627 if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f {
630 emit_feature_err(diag, "pushpop_unsafe", span, GateIssue::Language, EXPLAIN_PUSHPOP_UNSAFE);
634 features: Vec<&'static str>,
635 span_handler: &'a Handler,
637 plugin_attributes: &'a [(String, AttributeType)],
640 impl<'a> Context<'a> {
641 fn enable_feature(&mut self, feature: &'static str) {
642 debug!("enabling feature: {}", feature);
643 self.features.push(feature);
646 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
647 let has_feature = self.has_feature(feature);
648 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature);
650 emit_feature_err(self.span_handler, feature, span, GateIssue::Language, explain);
653 fn has_feature(&self, feature: &str) -> bool {
654 self.features.iter().any(|&n| n == feature)
657 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
658 debug!("check_attribute(attr = {:?})", attr);
659 let name = &*attr.name();
660 for &(n, ty, gateage) in KNOWN_ATTRIBUTES {
662 if let Gated(gate, desc) = gateage {
663 self.gate_feature(gate, attr.span, desc);
665 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
669 for &(ref n, ref ty) in self.plugin_attributes {
671 // Plugins can't gate attributes, so we don't check for it
672 // unlike the code above; we only use this loop to
673 // short-circuit to avoid the checks below
674 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
678 if name.starts_with("rustc_") {
679 self.gate_feature("rustc_attrs", attr.span,
680 "unless otherwise specified, attributes \
681 with the prefix `rustc_` \
682 are reserved for internal compiler diagnostics");
683 } else if name.starts_with("derive_") {
684 self.gate_feature("custom_derive", attr.span,
685 "attributes of the form `#[derive_*]` are reserved \
688 // Only run the custom attribute lint during regular
689 // feature gate checking. Macro gating runs
690 // before the plugin attributes are registered
691 // so we skip this then
693 self.gate_feature("custom_attribute", attr.span,
694 &format!("The attribute `{}` is currently \
695 unknown to the compiler and \
697 added to it in the future",
704 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
705 let info = KNOWN_FEATURES.iter()
706 .find(|t| t.0 == feature)
709 if let Active = info.3 {
710 // FIXME (#28244): enforce that active features have issue numbers
711 // assert!(issue.is_some())
721 pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
723 let issue = match issue {
724 GateIssue::Language => find_lang_feature_issue(feature),
725 GateIssue::Library(lib) => lib,
728 let mut err = if let Some(n) = issue {
729 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
731 diag.struct_span_err(span, explain)
734 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
735 if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
739 err.fileline_help(span, &format!("add #![feature({})] to the \
740 crate attributes to enable",
745 pub const EXPLAIN_ASM: &'static str =
746 "inline assembly is not stable enough for use and is subject to change";
748 pub const EXPLAIN_LOG_SYNTAX: &'static str =
749 "`log_syntax!` is not stable enough for use and is subject to change";
751 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
752 "`concat_idents` is not stable enough for use and is subject to change";
754 pub const EXPLAIN_TRACE_MACROS: &'static str =
755 "`trace_macros` is not stable enough for use and is subject to change";
756 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
757 "allow_internal_unstable side-steps feature gating and stability checks";
759 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
760 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
762 struct MacroVisitor<'a> {
763 context: &'a Context<'a>
766 impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
767 fn visit_mac(&mut self, mac: &ast::Mac) {
768 let path = &mac.node.path;
769 let name = path.segments.last().unwrap().identifier.name.as_str();
771 // Issue 22234: If you add a new case here, make sure to also
772 // add code to catch the macro during or after expansion.
774 // We still keep this MacroVisitor (rather than *solely*
775 // relying on catching cases during or after expansion) to
776 // catch uses of these macros within conditionally-compiled
777 // code, e.g. `#[cfg]`-guarded functions.
780 self.context.gate_feature("asm", path.span, EXPLAIN_ASM);
783 else if name == "log_syntax" {
784 self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX);
787 else if name == "trace_macros" {
788 self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS);
791 else if name == "concat_idents" {
792 self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS);
796 fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
797 self.context.check_attribute(attr, true);
800 fn visit_expr(&mut self, e: &ast::Expr) {
801 // Issue 22181: overloaded-`box` and placement-`in` are
802 // implemented via a desugaring expansion, so their feature
803 // gates go into MacroVisitor since that works pre-expansion.
805 // Issue 22234: we also check during expansion as well.
806 // But we keep these checks as a pre-expansion check to catch
807 // uses in e.g. conditionalized code.
809 if let ast::ExprBox(_) = e.node {
810 self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX);
813 if let ast::ExprInPlace(..) = e.node {
814 self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN);
817 visit::walk_expr(self, e);
821 struct PostExpansionVisitor<'a> {
822 context: &'a Context<'a>,
825 impl<'a> PostExpansionVisitor<'a> {
826 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
827 if !self.context.cm.span_allows_unstable(span) {
828 self.context.gate_feature(feature, span, explain)
833 impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
834 fn visit_attribute(&mut self, attr: &ast::Attribute) {
835 if !self.context.cm.span_allows_unstable(attr.span) {
836 self.context.check_attribute(attr, false);
840 fn visit_name(&mut self, sp: Span, name: ast::Name) {
841 if !name.as_str().is_ascii() {
842 self.gate_feature("non_ascii_idents", sp,
843 "non-ascii idents are not fully supported.");
847 fn visit_item(&mut self, i: &ast::Item) {
849 ast::ItemExternCrate(_) => {
850 if attr::contains_name(&i.attrs[..], "macro_reexport") {
851 self.gate_feature("macro_reexport", i.span,
852 "macros reexports are experimental \
853 and possibly buggy");
857 ast::ItemForeignMod(ref foreign_module) => {
858 if attr::contains_name(&i.attrs[..], "link_args") {
859 self.gate_feature("link_args", i.span,
860 "the `link_args` attribute is not portable \
861 across platforms, it is recommended to \
862 use `#[link(name = \"foo\")]` instead")
864 let maybe_feature = match foreign_module.abi {
865 Abi::RustIntrinsic => Some(("intrinsics", "intrinsics are subject to change")),
866 Abi::PlatformIntrinsic => {
867 Some(("platform_intrinsics",
868 "platform intrinsics are experimental and possibly buggy"))
872 if let Some((feature, msg)) = maybe_feature {
873 self.gate_feature(feature, i.span, msg)
878 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
879 self.gate_feature("plugin_registrar", i.span,
880 "compiler plugins are experimental and possibly buggy");
882 if attr::contains_name(&i.attrs[..], "start") {
883 self.gate_feature("start", i.span,
884 "a #[start] function is an experimental \
885 feature whose signature may change \
888 if attr::contains_name(&i.attrs[..], "main") {
889 self.gate_feature("main", i.span,
890 "declaration of a nonstandard #[main] \
891 function may change over time, for now \
892 a top-level `fn main()` is required");
896 ast::ItemStruct(..) => {
897 if attr::contains_name(&i.attrs[..], "simd") {
898 self.gate_feature("simd", i.span,
899 "SIMD types are experimental and possibly buggy");
900 self.context.span_handler.span_warn(i.span,
901 "the `#[simd]` attribute is deprecated, \
902 use `#[repr(simd)]` instead");
904 for attr in &i.attrs {
905 if attr.name() == "repr" {
906 for item in attr.meta_item_list().unwrap_or(&[]) {
907 if item.name() == "simd" {
908 self.gate_feature("repr_simd", i.span,
909 "SIMD types are experimental and possibly buggy");
917 ast::ItemDefaultImpl(..) => {
918 self.gate_feature("optin_builtin_traits",
920 "default trait implementations are experimental \
921 and possibly buggy");
924 ast::ItemImpl(_, polarity, _, _, _, _) => {
926 ast::ImplPolarity::Negative => {
927 self.gate_feature("optin_builtin_traits",
929 "negative trait bounds are not yet fully implemented; \
930 use marker types for now");
939 visit::walk_item(self, i);
942 fn visit_variant_data(&mut self, s: &'v ast::VariantData, _: ast::Ident,
943 _: &'v ast::Generics, _: ast::NodeId, span: Span) {
944 if s.fields().is_empty() {
946 self.gate_feature("braced_empty_structs", span,
947 "empty structs and enum variants with braces are unstable");
948 } else if s.is_tuple() {
949 self.context.span_handler.struct_span_err(span, "empty tuple structs and enum \
950 variants are not allowed, use \
951 unit structs and enum variants \
953 .span_help(span, "remove trailing `()` to make a unit \
954 struct or unit enum variant")
958 visit::walk_struct_def(self, s)
961 fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
962 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
964 Some(val) => val.starts_with("llvm."),
968 self.gate_feature("link_llvm_intrinsics", i.span,
969 "linking to LLVM intrinsics is experimental");
972 visit::walk_foreign_item(self, i)
975 fn visit_expr(&mut self, e: &ast::Expr) {
978 self.gate_feature("box_syntax",
980 "box expression syntax is experimental; \
981 you can call `Box::new` instead.");
983 ast::ExprType(..) => {
984 self.gate_feature("type_ascription", e.span,
985 "type ascription is experimental");
989 visit::walk_expr(self, e);
992 fn visit_pat(&mut self, pattern: &ast::Pat) {
994 ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
995 self.gate_feature("advanced_slice_patterns",
997 "multiple-element slice matches anywhere \
998 but at the end of a slice (e.g. \
999 `[0, ..xs, 0]`) are experimental")
1001 ast::PatVec(..) => {
1002 self.gate_feature("slice_patterns",
1004 "slice pattern syntax is experimental");
1006 ast::PatBox(..) => {
1007 self.gate_feature("box_patterns",
1009 "box pattern syntax is experimental");
1013 visit::walk_pat(self, pattern)
1016 fn visit_fn(&mut self,
1017 fn_kind: FnKind<'v>,
1018 fn_decl: &'v ast::FnDecl,
1019 block: &'v ast::Block,
1022 // check for const fn declarations
1024 FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1025 self.gate_feature("const_fn", span, "const fn is unstable");
1028 // stability of const fn methods are covered in
1029 // visit_trait_item and visit_impl_item below; this is
1030 // because default methods don't pass through this
1036 FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
1037 self.gate_feature("intrinsics",
1039 "intrinsics are subject to change")
1041 FnKind::ItemFn(_, _, _, _, abi, _) |
1042 FnKind::Method(_, &ast::MethodSig { abi, .. }, _) if abi == Abi::RustCall => {
1043 self.gate_feature("unboxed_closures",
1045 "rust-call ABI is subject to change")
1049 visit::walk_fn(self, fn_kind, fn_decl, block, span);
1052 fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
1054 ast::ConstTraitItem(..) => {
1055 self.gate_feature("associated_consts",
1057 "associated constants are experimental")
1059 ast::MethodTraitItem(ref sig, _) => {
1060 if sig.constness == ast::Constness::Const {
1061 self.gate_feature("const_fn", ti.span, "const fn is unstable");
1064 ast::TypeTraitItem(_, Some(_)) => {
1065 self.gate_feature("associated_type_defaults", ti.span,
1066 "associated type defaults are unstable");
1070 visit::walk_trait_item(self, ti);
1073 fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
1075 ast::ImplItemKind::Const(..) => {
1076 self.gate_feature("associated_consts",
1078 "associated constants are experimental")
1080 ast::ImplItemKind::Method(ref sig, _) => {
1081 if sig.constness == ast::Constness::Const {
1082 self.gate_feature("const_fn", ii.span, "const fn is unstable");
1087 visit::walk_impl_item(self, ii);
1091 fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
1093 plugin_attributes: &[(String, AttributeType)],
1096 where F: FnOnce(&mut Context, &ast::Crate)
1098 let mut cx = Context {
1099 features: Vec::new(),
1100 span_handler: span_handler,
1102 plugin_attributes: plugin_attributes,
1105 let mut accepted_features = Vec::new();
1106 let mut unknown_features = Vec::new();
1108 for attr in &krate.attrs {
1109 if !attr.check_name("feature") {
1113 match attr.meta_item_list() {
1115 span_handler.span_err(attr.span, "malformed feature attribute, \
1116 expected #![feature(...)]");
1120 let name = match mi.node {
1121 ast::MetaWord(ref word) => (*word).clone(),
1123 span_handler.span_err(mi.span,
1124 "malformed feature, expected just \
1129 match KNOWN_FEATURES.iter()
1130 .find(|& &(n, _, _, _)| name == n) {
1131 Some(&(name, _, _, Active)) => {
1132 cx.enable_feature(name);
1134 Some(&(_, _, _, Removed)) => {
1135 span_handler.span_err(mi.span, "feature has been removed");
1137 Some(&(_, _, _, Accepted)) => {
1138 accepted_features.push(mi.span);
1141 unknown_features.push((name, mi.span));
1149 check(&mut cx, krate);
1151 // FIXME (pnkfelix): Before adding the 99th entry below, change it
1152 // to a single-pass (instead of N calls to `.has_feature`).
1155 unboxed_closures: cx.has_feature("unboxed_closures"),
1156 rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
1157 allow_quote: cx.has_feature("quote"),
1158 allow_asm: cx.has_feature("asm"),
1159 allow_log_syntax: cx.has_feature("log_syntax"),
1160 allow_concat_idents: cx.has_feature("concat_idents"),
1161 allow_trace_macros: cx.has_feature("trace_macros"),
1162 allow_internal_unstable: cx.has_feature("allow_internal_unstable"),
1163 allow_custom_derive: cx.has_feature("custom_derive"),
1164 allow_placement_in: cx.has_feature("placement_in_syntax"),
1165 allow_box: cx.has_feature("box_syntax"),
1166 allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"),
1167 simd_ffi: cx.has_feature("simd_ffi"),
1168 unmarked_api: cx.has_feature("unmarked_api"),
1169 negate_unsigned: cx.has_feature("negate_unsigned"),
1170 declared_stable_lang_features: accepted_features,
1171 declared_lib_features: unknown_features,
1172 const_fn: cx.has_feature("const_fn"),
1173 const_indexing: cx.has_feature("const_indexing"),
1174 static_recursion: cx.has_feature("static_recursion"),
1175 default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"),
1176 type_macros: cx.has_feature("type_macros"),
1177 cfg_target_feature: cx.has_feature("cfg_target_feature"),
1178 cfg_target_vendor: cx.has_feature("cfg_target_vendor"),
1179 cfg_target_thread_local: cx.has_feature("cfg_target_thread_local"),
1180 augmented_assignments: cx.has_feature("augmented_assignments"),
1181 braced_empty_structs: cx.has_feature("braced_empty_structs"),
1182 staged_api: cx.has_feature("staged_api"),
1183 stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"),
1184 deprecated: cx.has_feature("deprecated"),
1188 pub fn check_crate_macros(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate)
1190 check_crate_inner(cm, span_handler, krate, &[] as &'static [_],
1191 |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate))
1194 pub fn check_crate(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate,
1195 plugin_attributes: &[(String, AttributeType)],
1196 unstable: UnstableFeatures) -> Features
1198 maybe_stage_features(span_handler, krate, unstable);
1200 check_crate_inner(cm, span_handler, krate, plugin_attributes,
1201 |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx },
1205 #[derive(Clone, Copy)]
1206 pub enum UnstableFeatures {
1207 /// Hard errors for unstable features are active, as on
1208 /// beta/stable channels.
1210 /// Allow features to me activated, as on nightly.
1212 /// Errors are bypassed for bootstrapping. This is required any time
1213 /// during the build that feature-related lints are set to warn or above
1214 /// because the build turns on warnings-as-errors and uses lots of unstable
1215 /// features. As a result, this is always required for building Rust itself.
1219 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1220 unstable: UnstableFeatures) {
1221 let allow_features = match unstable {
1222 UnstableFeatures::Allow => true,
1223 UnstableFeatures::Disallow => false,
1224 UnstableFeatures::Cheat => true
1226 if !allow_features {
1227 for attr in &krate.attrs {
1228 if attr.check_name("feature") {
1229 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1230 let ref msg = format!("#[feature] may not be used on the {} release channel",
1232 span_handler.span_err(attr.span, msg);