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), Removed),
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),
244 ("abi_vectorcall", "1.7.0", None, Active)
246 // (changing above list without updating src/doc/reference.md makes @cmr sad)
249 /// Represents an active feature that is currently being implemented or
250 /// currently being considered for addition/removal.
253 /// Represents a feature which has since been removed (it was once Active)
256 /// This language feature has since been Accepted (it was once Active)
260 // Attributes that have a special meaning to rustc or rustdoc
261 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
264 ("warn", Normal, Ungated),
265 ("allow", Normal, Ungated),
266 ("forbid", Normal, Ungated),
267 ("deny", Normal, Ungated),
269 ("macro_reexport", Normal, Ungated),
270 ("macro_use", Normal, Ungated),
271 ("macro_export", Normal, Ungated),
272 ("plugin_registrar", Normal, Ungated),
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),
295 // Not used any more, but we can't feature gate it
296 ("no_stack_check", Normal, Ungated),
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 \
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 \
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_if_this_changed", Whitelisted, Gated("rustc_attrs",
333 "the `#[rustc_if_this_changed]` attribute \
334 is just used for rustc unit tests \
335 and will never be stable")),
336 ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs",
337 "the `#[rustc_if_this_changed]` attribute \
338 is just used for rustc unit tests \
339 and will never be stable")),
340 ("rustc_move_fragments", Normal, Gated("rustc_attrs",
341 "the `#[rustc_move_fragments]` attribute \
342 is just used for rustc unit tests \
343 and will never be stable")),
344 ("rustc_mir", Normal, Gated("rustc_attrs",
345 "the `#[rustc_mir]` attribute \
346 is just used for rustc unit tests \
347 and will never be stable")),
349 ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
350 EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
352 ("fundamental", Whitelisted, Gated("fundamental",
353 "the `#[fundamental]` attribute \
354 is an experimental feature")),
356 ("linked_from", Normal, Gated("linked_from",
357 "the `#[linked_from]` attribute \
358 is an experimental feature")),
360 // FIXME: #14408 whitelist docs since rustdoc looks at them
361 ("doc", Whitelisted, Ungated),
363 // FIXME: #14406 these are processed in trans, which happens after the
365 ("cold", Whitelisted, Ungated),
366 ("export_name", Whitelisted, Ungated),
367 ("inline", Whitelisted, Ungated),
368 ("link", Whitelisted, Ungated),
369 ("link_name", Whitelisted, Ungated),
370 ("link_section", Whitelisted, Ungated),
371 ("no_builtins", Whitelisted, Ungated),
372 ("no_mangle", Whitelisted, Ungated),
373 ("no_debug", Whitelisted, Gated("no_debug",
374 "the `#[no_debug]` attribute \
375 is an experimental feature")),
376 ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
377 "the `#[omit_gdb_pretty_printer_section]` \
378 attribute is just used for the Rust test \
380 ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
381 "unsafe_no_drop_flag has unstable semantics \
382 and may be removed in the future")),
383 ("unsafe_destructor_blind_to_params",
385 Gated("dropck_parametricity",
386 "unsafe_destructor_blind_to_params has unstable semantics \
387 and may be removed in the future")),
388 ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental")),
391 ("prelude_import", Whitelisted, Gated("prelude_import",
392 "`#[prelude_import]` is for use by rustc only")),
394 // FIXME: #14407 these are only looked at on-demand so we can't
395 // guarantee they'll have already been checked
396 ("rustc_deprecated", Whitelisted, Ungated),
397 ("must_use", Whitelisted, Ungated),
398 ("stable", Whitelisted, Ungated),
399 ("unstable", Whitelisted, Ungated),
400 ("deprecated", Normal, Gated("deprecated", "`#[deprecated]` attribute is unstable")),
402 ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
403 "unboxed_closures are still evolving")),
404 ("rustc_reflect_like", Whitelisted, Gated("reflect",
405 "defining reflective traits is still evolving")),
407 // Crate level attributes
408 ("crate_name", CrateLevel, Ungated),
409 ("crate_type", CrateLevel, Ungated),
410 ("crate_id", CrateLevel, Ungated),
411 ("feature", CrateLevel, Ungated),
412 ("no_start", CrateLevel, Ungated),
413 ("no_main", CrateLevel, Ungated),
414 ("no_builtins", CrateLevel, Ungated),
415 ("recursion_limit", CrateLevel, Ungated),
418 macro_rules! cfg_fn {
419 (|$x: ident| $e: expr) => {{
420 fn f($x: &Features) -> bool {
423 f as fn(&Features) -> bool
426 // cfg(...)'s that are feature gated
427 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
428 // (name in cfg, feature, function to check if the feature is enabled)
429 ("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)),
430 ("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)),
431 ("target_thread_local", "cfg_target_thread_local",
432 cfg_fn!(|x| x.cfg_target_thread_local)),
435 #[derive(Debug, Eq, PartialEq)]
436 pub enum GatedCfgAttr {
441 #[derive(Debug, Eq, PartialEq)]
442 pub struct GatedCfg {
447 impl Ord for GatedCfgAttr {
448 fn cmp(&self, other: &GatedCfgAttr) -> cmp::Ordering {
449 let to_tup = |s: &GatedCfgAttr| match *s {
450 GatedCfgAttr::GatedCfg(ref gated_cfg) => {
451 (gated_cfg.span.lo.0, gated_cfg.span.hi.0, gated_cfg.index)
453 GatedCfgAttr::GatedAttr(ref span) => {
454 (span.lo.0, span.hi.0, GATED_CFGS.len())
457 to_tup(self).cmp(&to_tup(other))
461 impl PartialOrd for GatedCfgAttr {
462 fn partial_cmp(&self, other: &GatedCfgAttr) -> Option<cmp::Ordering> {
463 Some(self.cmp(other))
468 pub fn check_and_emit(&self,
469 diagnostic: &Handler,
473 GatedCfgAttr::GatedCfg(ref cfg) => {
474 cfg.check_and_emit(diagnostic, features, codemap);
476 GatedCfgAttr::GatedAttr(span) => {
477 if !features.stmt_expr_attributes {
478 emit_feature_err(diagnostic,
479 "stmt_expr_attributes",
482 EXPLAIN_STMT_ATTR_SYNTAX);
490 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
491 let name = cfg.name();
493 .position(|info| info.0 == name)
501 fn check_and_emit(&self,
502 diagnostic: &Handler,
505 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
506 if !has_feature(features) && !codemap.span_allows_unstable(self.span) {
507 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
508 emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
514 #[derive(PartialEq, Copy, Clone, Debug)]
515 pub enum AttributeType {
516 /// Normal, builtin attribute that is consumed
517 /// by the compiler before the unused_attribute check
520 /// Builtin attribute that may not be consumed by the compiler
521 /// before the unused_attribute check. These attributes
522 /// will be ignored by the unused_attribute lint
525 /// Builtin attribute that is only allowed at the crate level
529 #[derive(PartialEq, Copy, Clone, Debug)]
530 pub enum AttributeGate {
531 /// Is gated by a given feature gate and reason
532 Gated(&'static str, &'static str),
534 /// Ungated attribute, can be used on all release channels
538 /// A set of features to be used by later passes.
539 pub struct Features {
540 pub unboxed_closures: bool,
541 pub rustc_diagnostic_macros: bool,
542 pub allow_quote: bool,
544 pub allow_log_syntax: bool,
545 pub allow_concat_idents: bool,
546 pub allow_trace_macros: bool,
547 pub allow_internal_unstable: bool,
548 pub allow_custom_derive: bool,
549 pub allow_placement_in: bool,
551 pub allow_pushpop_unsafe: bool,
553 pub unmarked_api: bool,
554 /// spans of #![feature] attrs for stable language features. for error reporting
555 pub declared_stable_lang_features: Vec<Span>,
556 /// #![feature] attrs for non-language (library) features
557 pub declared_lib_features: Vec<(InternedString, Span)>,
559 pub const_indexing: bool,
560 pub static_recursion: bool,
561 pub default_type_parameter_fallback: bool,
562 pub type_macros: bool,
563 pub cfg_target_feature: bool,
564 pub cfg_target_vendor: bool,
565 pub cfg_target_thread_local: bool,
566 pub augmented_assignments: bool,
567 pub braced_empty_structs: bool,
568 pub staged_api: bool,
569 pub stmt_expr_attributes: bool,
570 pub deprecated: bool,
574 pub fn new() -> Features {
576 unboxed_closures: false,
577 rustc_diagnostic_macros: false,
580 allow_log_syntax: false,
581 allow_concat_idents: false,
582 allow_trace_macros: false,
583 allow_internal_unstable: false,
584 allow_custom_derive: false,
585 allow_placement_in: false,
587 allow_pushpop_unsafe: false,
590 declared_stable_lang_features: Vec::new(),
591 declared_lib_features: Vec::new(),
593 const_indexing: false,
594 static_recursion: false,
595 default_type_parameter_fallback: false,
597 cfg_target_feature: false,
598 cfg_target_vendor: false,
599 cfg_target_thread_local: false,
600 augmented_assignments: false,
601 braced_empty_structs: false,
603 stmt_expr_attributes: false,
609 const EXPLAIN_BOX_SYNTAX: &'static str =
610 "box expression syntax is experimental; you can call `Box::new` instead.";
612 const EXPLAIN_PLACEMENT_IN: &'static str =
613 "placement-in expression syntax is experimental and subject to change.";
615 const EXPLAIN_PUSHPOP_UNSAFE: &'static str =
616 "push/pop_unsafe macros are experimental and subject to change.";
618 const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
619 "attributes on non-item statements and expressions are experimental.";
621 pub fn check_for_box_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
622 if let Some(&Features { allow_box: true, .. }) = f {
625 emit_feature_err(diag, "box_syntax", span, GateIssue::Language, EXPLAIN_BOX_SYNTAX);
628 pub fn check_for_placement_in(f: Option<&Features>, diag: &Handler, span: Span) {
629 if let Some(&Features { allow_placement_in: true, .. }) = f {
632 emit_feature_err(diag, "placement_in_syntax", span, GateIssue::Language, EXPLAIN_PLACEMENT_IN);
635 pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
636 if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f {
639 emit_feature_err(diag, "pushpop_unsafe", span, GateIssue::Language, EXPLAIN_PUSHPOP_UNSAFE);
643 features: Vec<&'static str>,
644 span_handler: &'a Handler,
646 plugin_attributes: &'a [(String, AttributeType)],
649 impl<'a> Context<'a> {
650 fn enable_feature(&mut self, feature: &'static str) {
651 debug!("enabling feature: {}", feature);
652 self.features.push(feature);
655 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
656 let has_feature = self.has_feature(feature);
657 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature);
659 emit_feature_err(self.span_handler, feature, span, GateIssue::Language, explain);
662 fn has_feature(&self, feature: &str) -> bool {
663 self.features.iter().any(|&n| n == feature)
666 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
667 debug!("check_attribute(attr = {:?})", attr);
668 let name = &*attr.name();
669 for &(n, ty, gateage) in KNOWN_ATTRIBUTES {
671 if let Gated(gate, desc) = gateage {
672 self.gate_feature(gate, attr.span, desc);
674 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
678 for &(ref n, ref ty) in self.plugin_attributes {
680 // Plugins can't gate attributes, so we don't check for it
681 // unlike the code above; we only use this loop to
682 // short-circuit to avoid the checks below
683 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
687 if name.starts_with("rustc_") {
688 self.gate_feature("rustc_attrs", attr.span,
689 "unless otherwise specified, attributes \
690 with the prefix `rustc_` \
691 are reserved for internal compiler diagnostics");
692 } else if name.starts_with("derive_") {
693 self.gate_feature("custom_derive", attr.span,
694 "attributes of the form `#[derive_*]` are reserved \
697 // Only run the custom attribute lint during regular
698 // feature gate checking. Macro gating runs
699 // before the plugin attributes are registered
700 // so we skip this then
702 self.gate_feature("custom_attribute", attr.span,
703 &format!("The attribute `{}` is currently \
704 unknown to the compiler and \
706 added to it in the future",
713 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
714 let info = KNOWN_FEATURES.iter()
715 .find(|t| t.0 == feature)
718 if let Active = info.3 {
719 // FIXME (#28244): enforce that active features have issue numbers
720 // assert!(issue.is_some())
730 pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
732 let issue = match issue {
733 GateIssue::Language => find_lang_feature_issue(feature),
734 GateIssue::Library(lib) => lib,
737 let mut err = if let Some(n) = issue {
738 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
740 diag.struct_span_err(span, explain)
743 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
744 if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
748 err.fileline_help(span, &format!("add #![feature({})] to the \
749 crate attributes to enable",
754 pub const EXPLAIN_ASM: &'static str =
755 "inline assembly is not stable enough for use and is subject to change";
757 pub const EXPLAIN_LOG_SYNTAX: &'static str =
758 "`log_syntax!` is not stable enough for use and is subject to change";
760 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
761 "`concat_idents` is not stable enough for use and is subject to change";
763 pub const EXPLAIN_TRACE_MACROS: &'static str =
764 "`trace_macros` is not stable enough for use and is subject to change";
765 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
766 "allow_internal_unstable side-steps feature gating and stability checks";
768 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
769 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
771 struct MacroVisitor<'a> {
772 context: &'a Context<'a>
775 impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
776 fn visit_mac(&mut self, mac: &ast::Mac) {
777 let path = &mac.node.path;
778 let name = path.segments.last().unwrap().identifier.name.as_str();
780 // Issue 22234: If you add a new case here, make sure to also
781 // add code to catch the macro during or after expansion.
783 // We still keep this MacroVisitor (rather than *solely*
784 // relying on catching cases during or after expansion) to
785 // catch uses of these macros within conditionally-compiled
786 // code, e.g. `#[cfg]`-guarded functions.
789 self.context.gate_feature("asm", path.span, EXPLAIN_ASM);
792 else if name == "log_syntax" {
793 self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX);
796 else if name == "trace_macros" {
797 self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS);
800 else if name == "concat_idents" {
801 self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS);
805 fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
806 self.context.check_attribute(attr, true);
809 fn visit_expr(&mut self, e: &ast::Expr) {
810 // Issue 22181: overloaded-`box` and placement-`in` are
811 // implemented via a desugaring expansion, so their feature
812 // gates go into MacroVisitor since that works pre-expansion.
814 // Issue 22234: we also check during expansion as well.
815 // But we keep these checks as a pre-expansion check to catch
816 // uses in e.g. conditionalized code.
818 if let ast::ExprBox(_) = e.node {
819 self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX);
822 if let ast::ExprInPlace(..) = e.node {
823 self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN);
826 visit::walk_expr(self, e);
830 struct PostExpansionVisitor<'a> {
831 context: &'a Context<'a>,
834 impl<'a> PostExpansionVisitor<'a> {
835 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
836 if !self.context.cm.span_allows_unstable(span) {
837 self.context.gate_feature(feature, span, explain)
842 impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
843 fn visit_attribute(&mut self, attr: &ast::Attribute) {
844 if !self.context.cm.span_allows_unstable(attr.span) {
845 self.context.check_attribute(attr, false);
849 fn visit_name(&mut self, sp: Span, name: ast::Name) {
850 if !name.as_str().is_ascii() {
851 self.gate_feature("non_ascii_idents", sp,
852 "non-ascii idents are not fully supported.");
856 fn visit_item(&mut self, i: &ast::Item) {
858 ast::ItemExternCrate(_) => {
859 if attr::contains_name(&i.attrs[..], "macro_reexport") {
860 self.gate_feature("macro_reexport", i.span,
861 "macros reexports are experimental \
862 and possibly buggy");
866 ast::ItemForeignMod(ref foreign_module) => {
867 if attr::contains_name(&i.attrs[..], "link_args") {
868 self.gate_feature("link_args", i.span,
869 "the `link_args` attribute is not portable \
870 across platforms, it is recommended to \
871 use `#[link(name = \"foo\")]` instead")
873 let maybe_feature = match foreign_module.abi {
874 Abi::RustIntrinsic => Some(("intrinsics", "intrinsics are subject to change")),
875 Abi::PlatformIntrinsic => {
876 Some(("platform_intrinsics",
877 "platform intrinsics are experimental and possibly buggy"))
880 Some(("abi_vectorcall",
881 "vectorcall is experimental and subject to change"
886 if let Some((feature, msg)) = maybe_feature {
887 self.gate_feature(feature, i.span, msg)
892 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
893 self.gate_feature("plugin_registrar", i.span,
894 "compiler plugins are experimental and possibly buggy");
896 if attr::contains_name(&i.attrs[..], "start") {
897 self.gate_feature("start", i.span,
898 "a #[start] function is an experimental \
899 feature whose signature may change \
902 if attr::contains_name(&i.attrs[..], "main") {
903 self.gate_feature("main", i.span,
904 "declaration of a nonstandard #[main] \
905 function may change over time, for now \
906 a top-level `fn main()` is required");
910 ast::ItemStruct(..) => {
911 if attr::contains_name(&i.attrs[..], "simd") {
912 self.gate_feature("simd", i.span,
913 "SIMD types are experimental and possibly buggy");
914 self.context.span_handler.span_warn(i.span,
915 "the `#[simd]` attribute is deprecated, \
916 use `#[repr(simd)]` instead");
918 for attr in &i.attrs {
919 if attr.name() == "repr" {
920 for item in attr.meta_item_list().unwrap_or(&[]) {
921 if item.name() == "simd" {
922 self.gate_feature("repr_simd", i.span,
923 "SIMD types are experimental and possibly buggy");
931 ast::ItemDefaultImpl(..) => {
932 self.gate_feature("optin_builtin_traits",
934 "default trait implementations are experimental \
935 and possibly buggy");
938 ast::ItemImpl(_, polarity, _, _, _, _) => {
940 ast::ImplPolarity::Negative => {
941 self.gate_feature("optin_builtin_traits",
943 "negative trait bounds are not yet fully implemented; \
944 use marker types for now");
953 visit::walk_item(self, i);
956 fn visit_variant_data(&mut self, s: &'v ast::VariantData, _: ast::Ident,
957 _: &'v ast::Generics, _: ast::NodeId, span: Span) {
958 if s.fields().is_empty() {
960 self.gate_feature("braced_empty_structs", span,
961 "empty structs and enum variants with braces are unstable");
962 } else if s.is_tuple() {
963 self.context.span_handler.struct_span_err(span, "empty tuple structs and enum \
964 variants are not allowed, use \
965 unit structs and enum variants \
967 .span_help(span, "remove trailing `()` to make a unit \
968 struct or unit enum variant")
972 visit::walk_struct_def(self, s)
975 fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
976 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
978 Some(val) => val.starts_with("llvm."),
982 self.gate_feature("link_llvm_intrinsics", i.span,
983 "linking to LLVM intrinsics is experimental");
986 visit::walk_foreign_item(self, i)
989 fn visit_expr(&mut self, e: &ast::Expr) {
992 self.gate_feature("box_syntax",
994 "box expression syntax is experimental; \
995 you can call `Box::new` instead.");
997 ast::ExprType(..) => {
998 self.gate_feature("type_ascription", e.span,
999 "type ascription is experimental");
1003 visit::walk_expr(self, e);
1006 fn visit_pat(&mut self, pattern: &ast::Pat) {
1007 match pattern.node {
1008 ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
1009 self.gate_feature("advanced_slice_patterns",
1011 "multiple-element slice matches anywhere \
1012 but at the end of a slice (e.g. \
1013 `[0, ..xs, 0]`) are experimental")
1015 ast::PatVec(..) => {
1016 self.gate_feature("slice_patterns",
1018 "slice pattern syntax is experimental");
1020 ast::PatBox(..) => {
1021 self.gate_feature("box_patterns",
1023 "box pattern syntax is experimental");
1027 visit::walk_pat(self, pattern)
1030 fn visit_fn(&mut self,
1031 fn_kind: FnKind<'v>,
1032 fn_decl: &'v ast::FnDecl,
1033 block: &'v ast::Block,
1036 // check for const fn declarations
1038 FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1039 self.gate_feature("const_fn", span, "const fn is unstable");
1042 // stability of const fn methods are covered in
1043 // visit_trait_item and visit_impl_item below; this is
1044 // because default methods don't pass through this
1050 FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
1051 self.gate_feature("intrinsics",
1053 "intrinsics are subject to change")
1055 FnKind::ItemFn(_, _, _, _, abi, _) |
1056 FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => match abi {
1058 self.gate_feature("unboxed_closures", span,
1059 "rust-call ABI is subject to change");
1061 Abi::Vectorcall => {
1062 self.gate_feature("abi_vectorcall", span,
1063 "vectorcall is experimental and subject to change");
1069 visit::walk_fn(self, fn_kind, fn_decl, block, span);
1072 fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
1074 ast::ConstTraitItem(..) => {
1075 self.gate_feature("associated_consts",
1077 "associated constants are experimental")
1079 ast::MethodTraitItem(ref sig, _) => {
1080 if sig.constness == ast::Constness::Const {
1081 self.gate_feature("const_fn", ti.span, "const fn is unstable");
1084 ast::TypeTraitItem(_, Some(_)) => {
1085 self.gate_feature("associated_type_defaults", ti.span,
1086 "associated type defaults are unstable");
1090 visit::walk_trait_item(self, ti);
1093 fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
1095 ast::ImplItemKind::Const(..) => {
1096 self.gate_feature("associated_consts",
1098 "associated constants are experimental")
1100 ast::ImplItemKind::Method(ref sig, _) => {
1101 if sig.constness == ast::Constness::Const {
1102 self.gate_feature("const_fn", ii.span, "const fn is unstable");
1107 visit::walk_impl_item(self, ii);
1111 fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
1113 plugin_attributes: &[(String, AttributeType)],
1116 where F: FnOnce(&mut Context, &ast::Crate)
1118 let mut cx = Context {
1119 features: Vec::new(),
1120 span_handler: span_handler,
1122 plugin_attributes: plugin_attributes,
1125 let mut accepted_features = Vec::new();
1126 let mut unknown_features = Vec::new();
1128 for attr in &krate.attrs {
1129 if !attr.check_name("feature") {
1133 match attr.meta_item_list() {
1135 span_handler.span_err(attr.span, "malformed feature attribute, \
1136 expected #![feature(...)]");
1140 let name = match mi.node {
1141 ast::MetaWord(ref word) => (*word).clone(),
1143 span_handler.span_err(mi.span,
1144 "malformed feature, expected just \
1149 match KNOWN_FEATURES.iter()
1150 .find(|& &(n, _, _, _)| name == n) {
1151 Some(&(name, _, _, Active)) => {
1152 cx.enable_feature(name);
1154 Some(&(_, _, _, Removed)) => {
1155 span_handler.span_err(mi.span, "feature has been removed");
1157 Some(&(_, _, _, Accepted)) => {
1158 accepted_features.push(mi.span);
1161 unknown_features.push((name, mi.span));
1169 check(&mut cx, krate);
1171 // FIXME (pnkfelix): Before adding the 99th entry below, change it
1172 // to a single-pass (instead of N calls to `.has_feature`).
1175 unboxed_closures: cx.has_feature("unboxed_closures"),
1176 rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
1177 allow_quote: cx.has_feature("quote"),
1178 allow_asm: cx.has_feature("asm"),
1179 allow_log_syntax: cx.has_feature("log_syntax"),
1180 allow_concat_idents: cx.has_feature("concat_idents"),
1181 allow_trace_macros: cx.has_feature("trace_macros"),
1182 allow_internal_unstable: cx.has_feature("allow_internal_unstable"),
1183 allow_custom_derive: cx.has_feature("custom_derive"),
1184 allow_placement_in: cx.has_feature("placement_in_syntax"),
1185 allow_box: cx.has_feature("box_syntax"),
1186 allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"),
1187 simd_ffi: cx.has_feature("simd_ffi"),
1188 unmarked_api: cx.has_feature("unmarked_api"),
1189 declared_stable_lang_features: accepted_features,
1190 declared_lib_features: unknown_features,
1191 const_fn: cx.has_feature("const_fn"),
1192 const_indexing: cx.has_feature("const_indexing"),
1193 static_recursion: cx.has_feature("static_recursion"),
1194 default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"),
1195 type_macros: cx.has_feature("type_macros"),
1196 cfg_target_feature: cx.has_feature("cfg_target_feature"),
1197 cfg_target_vendor: cx.has_feature("cfg_target_vendor"),
1198 cfg_target_thread_local: cx.has_feature("cfg_target_thread_local"),
1199 augmented_assignments: cx.has_feature("augmented_assignments"),
1200 braced_empty_structs: cx.has_feature("braced_empty_structs"),
1201 staged_api: cx.has_feature("staged_api"),
1202 stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"),
1203 deprecated: cx.has_feature("deprecated"),
1207 pub fn check_crate_macros(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate)
1209 check_crate_inner(cm, span_handler, krate, &[] as &'static [_],
1210 |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate))
1213 pub fn check_crate(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate,
1214 plugin_attributes: &[(String, AttributeType)],
1215 unstable: UnstableFeatures) -> Features
1217 maybe_stage_features(span_handler, krate, unstable);
1219 check_crate_inner(cm, span_handler, krate, plugin_attributes,
1220 |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx },
1224 #[derive(Clone, Copy)]
1225 pub enum UnstableFeatures {
1226 /// Hard errors for unstable features are active, as on
1227 /// beta/stable channels.
1229 /// Allow features to me activated, as on nightly.
1231 /// Errors are bypassed for bootstrapping. This is required any time
1232 /// during the build that feature-related lints are set to warn or above
1233 /// because the build turns on warnings-as-errors and uses lots of unstable
1234 /// features. As a result, this is always required for building Rust itself.
1238 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1239 unstable: UnstableFeatures) {
1240 let allow_features = match unstable {
1241 UnstableFeatures::Allow => true,
1242 UnstableFeatures::Disallow => false,
1243 UnstableFeatures::Cheat => true
1245 if !allow_features {
1246 for attr in &krate.attrs {
1247 if attr.check_name("feature") {
1248 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1249 let ref msg = format!("#[feature] may not be used on the {} release channel",
1251 span_handler.span_err(attr.span, msg);