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::*;
30 use ast::{NodeId, PatKind};
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 the use of `#[naked]` on functions.
216 ("naked_functions", "1.9.0", Some(32408), Active),
218 // allow empty structs and enum variants with braces
219 ("braced_empty_structs", "1.5.0", Some(29720), Accepted),
221 // allow overloading augmented assignment operations like `a += b`
222 ("augmented_assignments", "1.5.0", Some(28235), Accepted),
224 // allow `#[no_debug]`
225 ("no_debug", "1.5.0", Some(29721), Active),
227 // allow `#[omit_gdb_pretty_printer_section]`
229 ("omit_gdb_pretty_printer_section", "1.5.0", None, Active),
231 // Allows cfg(target_vendor = "...").
232 ("cfg_target_vendor", "1.5.0", Some(29718), Active),
234 // Allow attributes on expressions and non-item statements
235 ("stmt_expr_attributes", "1.6.0", Some(15701), Active),
237 // Allows `#[deprecated]` attribute
238 ("deprecated", "1.6.0", Some(29935), Active),
240 // allow using type ascription in expressions
241 ("type_ascription", "1.6.0", Some(23416), Active),
243 // Allows cfg(target_thread_local)
244 ("cfg_target_thread_local", "1.7.0", Some(29594), Active),
247 ("abi_vectorcall", "1.7.0", None, Active),
250 ("inclusive_range_syntax", "1.7.0", Some(28237), Active),
253 ("question_mark", "1.9.0", Some(31436), Active),
255 // impl specialization (RFC 1210)
256 ("specialization", "1.7.0", Some(31844), Active),
258 // (changing above list without updating src/doc/reference.md makes @cmr sad)
261 /// Represents an active feature that is currently being implemented or
262 /// currently being considered for addition/removal.
265 /// Represents a feature which has since been removed (it was once Active)
268 /// This language feature has since been Accepted (it was once Active)
272 // Attributes that have a special meaning to rustc or rustdoc
273 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
276 ("warn", Normal, Ungated),
277 ("allow", Normal, Ungated),
278 ("forbid", Normal, Ungated),
279 ("deny", Normal, Ungated),
281 ("macro_reexport", Normal, Ungated),
282 ("macro_use", Normal, Ungated),
283 ("macro_export", Normal, Ungated),
284 ("plugin_registrar", Normal, Ungated),
286 ("cfg", Normal, Ungated),
287 ("cfg_attr", Normal, Ungated),
288 ("main", Normal, Ungated),
289 ("start", Normal, Ungated),
290 ("test", Normal, Ungated),
291 ("bench", Normal, Ungated),
292 ("simd", Normal, Ungated),
293 ("repr", Normal, Ungated),
294 ("path", Normal, Ungated),
295 ("abi", Normal, Ungated),
296 ("automatically_derived", Normal, Ungated),
297 ("no_mangle", Normal, Ungated),
298 ("no_link", Normal, Ungated),
299 ("derive", Normal, Ungated),
300 ("should_panic", Normal, Ungated),
301 ("ignore", Normal, Ungated),
302 ("no_implicit_prelude", Normal, Ungated),
303 ("reexport_test_harness_main", Normal, Ungated),
304 ("link_args", Normal, Ungated),
305 ("macro_escape", Normal, Ungated),
307 // Not used any more, but we can't feature gate it
308 ("no_stack_check", Normal, Ungated),
310 ("plugin", CrateLevel, Gated("plugin",
311 "compiler plugins are experimental \
312 and possibly buggy")),
313 ("no_std", CrateLevel, Ungated),
314 ("no_core", CrateLevel, Gated("no_core",
315 "no_core is experimental")),
316 ("lang", Normal, Gated("lang_items",
317 "language items are subject to change")),
318 ("linkage", Whitelisted, Gated("linkage",
319 "the `linkage` attribute is experimental \
320 and not portable across platforms")),
321 ("thread_local", Whitelisted, Gated("thread_local",
322 "`#[thread_local]` is an experimental feature, and does \
323 not currently handle destructors. There is no \
324 corresponding `#[task_local]` mapping to the task \
327 ("rustc_on_unimplemented", Normal, Gated("on_unimplemented",
328 "the `#[rustc_on_unimplemented]` attribute \
329 is an experimental feature")),
330 ("allocator", Whitelisted, Gated("allocator",
331 "the `#[allocator]` attribute is an experimental feature")),
332 ("needs_allocator", Normal, Gated("needs_allocator",
333 "the `#[needs_allocator]` \
334 attribute is an experimental \
336 ("rustc_variance", Normal, Gated("rustc_attrs",
337 "the `#[rustc_variance]` attribute \
338 is just used for rustc unit tests \
339 and will never be stable")),
340 ("rustc_error", Whitelisted, Gated("rustc_attrs",
341 "the `#[rustc_error]` attribute \
342 is just used for rustc unit tests \
343 and will never be stable")),
344 ("rustc_if_this_changed", Whitelisted, Gated("rustc_attrs",
345 "the `#[rustc_if_this_changed]` attribute \
346 is just used for rustc unit tests \
347 and will never be stable")),
348 ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs",
349 "the `#[rustc_if_this_changed]` attribute \
350 is just used for rustc unit tests \
351 and will never be stable")),
352 ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs",
353 "internal rustc attributes will never be stable")),
354 ("rustc_item_path", Whitelisted, Gated("rustc_attrs",
355 "internal rustc attributes will never be stable")),
356 ("rustc_move_fragments", Normal, Gated("rustc_attrs",
357 "the `#[rustc_move_fragments]` attribute \
358 is just used for rustc unit tests \
359 and will never be stable")),
360 ("rustc_mir", Whitelisted, Gated("rustc_attrs",
361 "the `#[rustc_mir]` attribute \
362 is just used for rustc unit tests \
363 and will never be stable")),
364 ("rustc_no_mir", Whitelisted, Gated("rustc_attrs",
365 "the `#[rustc_no_mir]` attribute \
366 is just used to make tests pass \
367 and will never be stable")),
369 ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
370 EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
372 ("fundamental", Whitelisted, Gated("fundamental",
373 "the `#[fundamental]` attribute \
374 is an experimental feature")),
376 ("linked_from", Normal, Gated("linked_from",
377 "the `#[linked_from]` attribute \
378 is an experimental feature")),
380 // FIXME: #14408 whitelist docs since rustdoc looks at them
381 ("doc", Whitelisted, Ungated),
383 // FIXME: #14406 these are processed in trans, which happens after the
385 ("cold", Whitelisted, Ungated),
386 ("naked", Whitelisted, Gated("naked_functions",
387 "the `#[naked]` attribute \
388 is an experimental feature")),
389 ("export_name", Whitelisted, Ungated),
390 ("inline", Whitelisted, Ungated),
391 ("link", Whitelisted, Ungated),
392 ("link_name", Whitelisted, Ungated),
393 ("link_section", Whitelisted, Ungated),
394 ("no_builtins", Whitelisted, Ungated),
395 ("no_mangle", Whitelisted, Ungated),
396 ("no_debug", Whitelisted, Gated("no_debug",
397 "the `#[no_debug]` attribute \
398 is an experimental feature")),
399 ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
400 "the `#[omit_gdb_pretty_printer_section]` \
401 attribute is just used for the Rust test \
403 ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
404 "unsafe_no_drop_flag has unstable semantics \
405 and may be removed in the future")),
406 ("unsafe_destructor_blind_to_params",
408 Gated("dropck_parametricity",
409 "unsafe_destructor_blind_to_params has unstable semantics \
410 and may be removed in the future")),
411 ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental")),
414 ("prelude_import", Whitelisted, Gated("prelude_import",
415 "`#[prelude_import]` is for use by rustc only")),
417 // FIXME: #14407 these are only looked at on-demand so we can't
418 // guarantee they'll have already been checked
419 ("rustc_deprecated", Whitelisted, Ungated),
420 ("must_use", Whitelisted, Ungated),
421 ("stable", Whitelisted, Ungated),
422 ("unstable", Whitelisted, Ungated),
423 ("deprecated", Normal, Gated("deprecated", "`#[deprecated]` attribute is unstable")),
425 ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
426 "unboxed_closures are still evolving")),
427 ("rustc_reflect_like", Whitelisted, Gated("reflect",
428 "defining reflective traits is still evolving")),
430 // Crate level attributes
431 ("crate_name", CrateLevel, Ungated),
432 ("crate_type", CrateLevel, Ungated),
433 ("crate_id", CrateLevel, Ungated),
434 ("feature", CrateLevel, Ungated),
435 ("no_start", CrateLevel, Ungated),
436 ("no_main", CrateLevel, Ungated),
437 ("no_builtins", CrateLevel, Ungated),
438 ("recursion_limit", CrateLevel, Ungated),
441 macro_rules! cfg_fn {
442 (|$x: ident| $e: expr) => {{
443 fn f($x: &Features) -> bool {
446 f as fn(&Features) -> bool
449 // cfg(...)'s that are feature gated
450 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
451 // (name in cfg, feature, function to check if the feature is enabled)
452 ("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)),
453 ("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)),
454 ("target_thread_local", "cfg_target_thread_local",
455 cfg_fn!(|x| x.cfg_target_thread_local)),
458 #[derive(Debug, Eq, PartialEq)]
459 pub enum GatedCfgAttr {
464 #[derive(Debug, Eq, PartialEq)]
465 pub struct GatedCfg {
470 impl Ord for GatedCfgAttr {
471 fn cmp(&self, other: &GatedCfgAttr) -> cmp::Ordering {
472 let to_tup = |s: &GatedCfgAttr| match *s {
473 GatedCfgAttr::GatedCfg(ref gated_cfg) => {
474 (gated_cfg.span.lo.0, gated_cfg.span.hi.0, gated_cfg.index)
476 GatedCfgAttr::GatedAttr(ref span) => {
477 (span.lo.0, span.hi.0, GATED_CFGS.len())
480 to_tup(self).cmp(&to_tup(other))
484 impl PartialOrd for GatedCfgAttr {
485 fn partial_cmp(&self, other: &GatedCfgAttr) -> Option<cmp::Ordering> {
486 Some(self.cmp(other))
491 pub fn check_and_emit(&self,
492 diagnostic: &Handler,
496 GatedCfgAttr::GatedCfg(ref cfg) => {
497 cfg.check_and_emit(diagnostic, features, codemap);
499 GatedCfgAttr::GatedAttr(span) => {
500 if !features.stmt_expr_attributes {
501 emit_feature_err(diagnostic,
502 "stmt_expr_attributes",
505 EXPLAIN_STMT_ATTR_SYNTAX);
513 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
514 let name = cfg.name();
516 .position(|info| info.0 == name)
524 fn check_and_emit(&self,
525 diagnostic: &Handler,
528 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
529 if !has_feature(features) && !codemap.span_allows_unstable(self.span) {
530 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
531 emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
537 #[derive(PartialEq, Copy, Clone, Debug)]
538 pub enum AttributeType {
539 /// Normal, builtin attribute that is consumed
540 /// by the compiler before the unused_attribute check
543 /// Builtin attribute that may not be consumed by the compiler
544 /// before the unused_attribute check. These attributes
545 /// will be ignored by the unused_attribute lint
548 /// Builtin attribute that is only allowed at the crate level
552 #[derive(PartialEq, Copy, Clone, Debug)]
553 pub enum AttributeGate {
554 /// Is gated by a given feature gate and reason
555 Gated(&'static str, &'static str),
557 /// Ungated attribute, can be used on all release channels
561 /// A set of features to be used by later passes.
562 pub struct Features {
563 pub unboxed_closures: bool,
564 pub rustc_diagnostic_macros: bool,
565 pub allow_quote: bool,
567 pub allow_log_syntax: bool,
568 pub allow_concat_idents: bool,
569 pub allow_trace_macros: bool,
570 pub allow_internal_unstable: bool,
571 pub allow_custom_derive: bool,
572 pub allow_placement_in: bool,
574 pub allow_pushpop_unsafe: bool,
575 pub allow_inclusive_range: bool,
577 pub unmarked_api: bool,
578 /// spans of #![feature] attrs for stable language features. for error reporting
579 pub declared_stable_lang_features: Vec<Span>,
580 /// #![feature] attrs for non-language (library) features
581 pub declared_lib_features: Vec<(InternedString, Span)>,
583 pub const_indexing: bool,
584 pub static_recursion: bool,
585 pub default_type_parameter_fallback: bool,
586 pub rustc_attrs: bool,
587 pub type_macros: bool,
588 pub cfg_target_feature: bool,
589 pub cfg_target_vendor: bool,
590 pub cfg_target_thread_local: bool,
591 pub staged_api: bool,
592 pub stmt_expr_attributes: bool,
593 pub deprecated: bool,
594 pub question_mark: bool,
595 pub specialization: bool,
599 pub fn new() -> Features {
601 unboxed_closures: false,
602 rustc_diagnostic_macros: false,
605 allow_log_syntax: false,
606 allow_concat_idents: false,
607 allow_trace_macros: false,
608 allow_internal_unstable: false,
609 allow_custom_derive: false,
610 allow_placement_in: false,
612 allow_pushpop_unsafe: false,
613 allow_inclusive_range: false,
616 declared_stable_lang_features: Vec::new(),
617 declared_lib_features: Vec::new(),
619 const_indexing: false,
620 static_recursion: false,
621 default_type_parameter_fallback: false,
624 cfg_target_feature: false,
625 cfg_target_vendor: false,
626 cfg_target_thread_local: false,
628 stmt_expr_attributes: false,
630 question_mark: false,
631 specialization: false,
636 const EXPLAIN_BOX_SYNTAX: &'static str =
637 "box expression syntax is experimental; you can call `Box::new` instead.";
639 const EXPLAIN_PLACEMENT_IN: &'static str =
640 "placement-in expression syntax is experimental and subject to change.";
642 const EXPLAIN_PUSHPOP_UNSAFE: &'static str =
643 "push/pop_unsafe macros are experimental and subject to change.";
645 const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
646 "attributes on non-item statements and expressions are experimental.";
648 pub fn check_for_box_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
649 if let Some(&Features { allow_box: true, .. }) = f {
652 emit_feature_err(diag, "box_syntax", span, GateIssue::Language, EXPLAIN_BOX_SYNTAX);
655 pub fn check_for_placement_in(f: Option<&Features>, diag: &Handler, span: Span) {
656 if let Some(&Features { allow_placement_in: true, .. }) = f {
659 emit_feature_err(diag, "placement_in_syntax", span, GateIssue::Language, EXPLAIN_PLACEMENT_IN);
662 pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
663 if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f {
666 emit_feature_err(diag, "pushpop_unsafe", span, GateIssue::Language, EXPLAIN_PUSHPOP_UNSAFE);
670 features: Vec<&'static str>,
671 span_handler: &'a Handler,
673 plugin_attributes: &'a [(String, AttributeType)],
676 impl<'a> Context<'a> {
677 fn enable_feature(&mut self, feature: &'static str) {
678 debug!("enabling feature: {}", feature);
679 self.features.push(feature);
682 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
683 let has_feature = self.has_feature(feature);
684 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature);
686 emit_feature_err(self.span_handler, feature, span, GateIssue::Language, explain);
689 fn has_feature(&self, feature: &str) -> bool {
690 self.features.iter().any(|&n| n == feature)
693 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
694 debug!("check_attribute(attr = {:?})", attr);
695 let name = &*attr.name();
696 for &(n, ty, gateage) in KNOWN_ATTRIBUTES {
698 if let Gated(gate, desc) = gateage {
699 self.gate_feature(gate, attr.span, desc);
701 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
705 for &(ref n, ref ty) in self.plugin_attributes {
707 // Plugins can't gate attributes, so we don't check for it
708 // unlike the code above; we only use this loop to
709 // short-circuit to avoid the checks below
710 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
714 if name.starts_with("rustc_") {
715 self.gate_feature("rustc_attrs", attr.span,
716 "unless otherwise specified, attributes \
717 with the prefix `rustc_` \
718 are reserved for internal compiler diagnostics");
719 } else if name.starts_with("derive_") {
720 self.gate_feature("custom_derive", attr.span,
721 "attributes of the form `#[derive_*]` are reserved \
724 // Only run the custom attribute lint during regular
725 // feature gate checking. Macro gating runs
726 // before the plugin attributes are registered
727 // so we skip this then
729 self.gate_feature("custom_attribute", attr.span,
730 &format!("The attribute `{}` is currently \
731 unknown to the compiler and \
733 added to it in the future",
740 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
741 let info = KNOWN_FEATURES.iter()
742 .find(|t| t.0 == feature)
745 if let Active = info.3 {
746 // FIXME (#28244): enforce that active features have issue numbers
747 // assert!(issue.is_some())
757 pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
759 let issue = match issue {
760 GateIssue::Language => find_lang_feature_issue(feature),
761 GateIssue::Library(lib) => lib,
764 let mut err = if let Some(n) = issue {
765 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
767 diag.struct_span_err(span, explain)
770 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
771 if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
775 err.fileline_help(span, &format!("add #![feature({})] to the \
776 crate attributes to enable",
781 pub const EXPLAIN_ASM: &'static str =
782 "inline assembly is not stable enough for use and is subject to change";
784 pub const EXPLAIN_LOG_SYNTAX: &'static str =
785 "`log_syntax!` is not stable enough for use and is subject to change";
787 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
788 "`concat_idents` is not stable enough for use and is subject to change";
790 pub const EXPLAIN_TRACE_MACROS: &'static str =
791 "`trace_macros` is not stable enough for use and is subject to change";
792 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
793 "allow_internal_unstable side-steps feature gating and stability checks";
795 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
796 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
798 struct MacroVisitor<'a> {
799 context: &'a Context<'a>
802 impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
803 fn visit_mac(&mut self, mac: &ast::Mac) {
804 let path = &mac.node.path;
805 let name = path.segments.last().unwrap().identifier.name.as_str();
807 // Issue 22234: If you add a new case here, make sure to also
808 // add code to catch the macro during or after expansion.
810 // We still keep this MacroVisitor (rather than *solely*
811 // relying on catching cases during or after expansion) to
812 // catch uses of these macros within conditionally-compiled
813 // code, e.g. `#[cfg]`-guarded functions.
816 self.context.gate_feature("asm", path.span, EXPLAIN_ASM);
819 else if name == "log_syntax" {
820 self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX);
823 else if name == "trace_macros" {
824 self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS);
827 else if name == "concat_idents" {
828 self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS);
832 fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
833 self.context.check_attribute(attr, true);
836 fn visit_expr(&mut self, e: &ast::Expr) {
837 // Issue 22181: overloaded-`box` and placement-`in` are
838 // implemented via a desugaring expansion, so their feature
839 // gates go into MacroVisitor since that works pre-expansion.
841 // Issue 22234: we also check during expansion as well.
842 // But we keep these checks as a pre-expansion check to catch
843 // uses in e.g. conditionalized code.
845 if let ast::ExprKind::Box(_) = e.node {
846 self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX);
849 if let ast::ExprKind::InPlace(..) = e.node {
850 self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN);
853 visit::walk_expr(self, e);
857 struct PostExpansionVisitor<'a> {
858 context: &'a Context<'a>,
861 impl<'a> PostExpansionVisitor<'a> {
862 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
863 if !self.context.cm.span_allows_unstable(span) {
864 self.context.gate_feature(feature, span, explain)
869 impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
870 fn visit_attribute(&mut self, attr: &ast::Attribute) {
871 if !self.context.cm.span_allows_unstable(attr.span) {
872 self.context.check_attribute(attr, false);
876 fn visit_name(&mut self, sp: Span, name: ast::Name) {
877 if !name.as_str().is_ascii() {
878 self.gate_feature("non_ascii_idents", sp,
879 "non-ascii idents are not fully supported.");
883 fn visit_item(&mut self, i: &ast::Item) {
885 ast::ItemKind::ExternCrate(_) => {
886 if attr::contains_name(&i.attrs[..], "macro_reexport") {
887 self.gate_feature("macro_reexport", i.span,
888 "macros reexports are experimental \
889 and possibly buggy");
893 ast::ItemKind::ForeignMod(ref foreign_module) => {
894 if attr::contains_name(&i.attrs[..], "link_args") {
895 self.gate_feature("link_args", i.span,
896 "the `link_args` attribute is not portable \
897 across platforms, it is recommended to \
898 use `#[link(name = \"foo\")]` instead")
900 let maybe_feature = match foreign_module.abi {
901 Abi::RustIntrinsic => Some(("intrinsics", "intrinsics are subject to change")),
902 Abi::PlatformIntrinsic => {
903 Some(("platform_intrinsics",
904 "platform intrinsics are experimental and possibly buggy"))
907 Some(("abi_vectorcall",
908 "vectorcall is experimental and subject to change"
913 if let Some((feature, msg)) = maybe_feature {
914 self.gate_feature(feature, i.span, msg)
918 ast::ItemKind::Fn(..) => {
919 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
920 self.gate_feature("plugin_registrar", i.span,
921 "compiler plugins are experimental and possibly buggy");
923 if attr::contains_name(&i.attrs[..], "start") {
924 self.gate_feature("start", i.span,
925 "a #[start] function is an experimental \
926 feature whose signature may change \
929 if attr::contains_name(&i.attrs[..], "main") {
930 self.gate_feature("main", i.span,
931 "declaration of a nonstandard #[main] \
932 function may change over time, for now \
933 a top-level `fn main()` is required");
937 ast::ItemKind::Struct(..) => {
938 if attr::contains_name(&i.attrs[..], "simd") {
939 self.gate_feature("simd", i.span,
940 "SIMD types are experimental and possibly buggy");
941 self.context.span_handler.span_warn(i.span,
942 "the `#[simd]` attribute is deprecated, \
943 use `#[repr(simd)]` instead");
945 for attr in &i.attrs {
946 if attr.name() == "repr" {
947 for item in attr.meta_item_list().unwrap_or(&[]) {
948 if item.name() == "simd" {
949 self.gate_feature("repr_simd", i.span,
950 "SIMD types are experimental and possibly buggy");
958 ast::ItemKind::DefaultImpl(..) => {
959 self.gate_feature("optin_builtin_traits",
961 "default trait implementations are experimental \
962 and possibly buggy");
965 ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
967 ast::ImplPolarity::Negative => {
968 self.gate_feature("optin_builtin_traits",
970 "negative trait bounds are not yet fully implemented; \
971 use marker types for now");
980 visit::walk_item(self, i);
983 fn visit_variant_data(&mut self, s: &'v ast::VariantData, _: ast::Ident,
984 _: &'v ast::Generics, _: ast::NodeId, span: Span) {
985 if s.fields().is_empty() {
987 self.context.span_handler.struct_span_err(span, "empty tuple structs and enum \
988 variants are not allowed, use \
989 unit structs and enum variants \
991 .span_help(span, "remove trailing `()` to make a unit \
992 struct or unit enum variant")
996 visit::walk_struct_def(self, s)
999 fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
1000 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
1002 Some(val) => val.starts_with("llvm."),
1006 self.gate_feature("link_llvm_intrinsics", i.span,
1007 "linking to LLVM intrinsics is experimental");
1010 visit::walk_foreign_item(self, i)
1013 fn visit_expr(&mut self, e: &ast::Expr) {
1015 ast::ExprKind::Box(_) => {
1016 self.gate_feature("box_syntax",
1018 "box expression syntax is experimental; \
1019 you can call `Box::new` instead.");
1021 ast::ExprKind::Type(..) => {
1022 self.gate_feature("type_ascription", e.span,
1023 "type ascription is experimental");
1025 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1026 self.gate_feature("inclusive_range_syntax",
1028 "inclusive range syntax is experimental");
1030 ast::ExprKind::Try(..) => {
1031 self.gate_feature("question_mark", e.span, "the `?` operator is not stable");
1035 visit::walk_expr(self, e);
1038 fn visit_pat(&mut self, pattern: &ast::Pat) {
1039 match pattern.node {
1040 PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => {
1041 self.gate_feature("advanced_slice_patterns",
1043 "multiple-element slice matches anywhere \
1044 but at the end of a slice (e.g. \
1045 `[0, ..xs, 0]`) are experimental")
1047 PatKind::Vec(..) => {
1048 self.gate_feature("slice_patterns",
1050 "slice pattern syntax is experimental");
1052 PatKind::Box(..) => {
1053 self.gate_feature("box_patterns",
1055 "box pattern syntax is experimental");
1059 visit::walk_pat(self, pattern)
1062 fn visit_fn(&mut self,
1063 fn_kind: FnKind<'v>,
1064 fn_decl: &'v ast::FnDecl,
1065 block: &'v ast::Block,
1068 // check for const fn declarations
1070 FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1071 self.gate_feature("const_fn", span, "const fn is unstable");
1074 // stability of const fn methods are covered in
1075 // visit_trait_item and visit_impl_item below; this is
1076 // because default methods don't pass through this
1082 FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
1083 self.gate_feature("intrinsics",
1085 "intrinsics are subject to change")
1087 FnKind::ItemFn(_, _, _, _, abi, _) |
1088 FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => match abi {
1090 self.gate_feature("unboxed_closures", span,
1091 "rust-call ABI is subject to change");
1093 Abi::Vectorcall => {
1094 self.gate_feature("abi_vectorcall", span,
1095 "vectorcall is experimental and subject to change");
1101 visit::walk_fn(self, fn_kind, fn_decl, block, span);
1104 fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
1106 ast::TraitItemKind::Const(..) => {
1107 self.gate_feature("associated_consts",
1109 "associated constants are experimental")
1111 ast::TraitItemKind::Method(ref sig, _) => {
1112 if sig.constness == ast::Constness::Const {
1113 self.gate_feature("const_fn", ti.span, "const fn is unstable");
1116 ast::TraitItemKind::Type(_, Some(_)) => {
1117 self.gate_feature("associated_type_defaults", ti.span,
1118 "associated type defaults are unstable");
1122 visit::walk_trait_item(self, ti);
1125 fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
1126 if ii.defaultness == ast::Defaultness::Default {
1127 self.gate_feature("specialization",
1129 "specialization is unstable");
1133 ast::ImplItemKind::Const(..) => {
1134 self.gate_feature("associated_consts",
1136 "associated constants are experimental")
1138 ast::ImplItemKind::Method(ref sig, _) => {
1139 if sig.constness == ast::Constness::Const {
1140 self.gate_feature("const_fn", ii.span, "const fn is unstable");
1145 visit::walk_impl_item(self, ii);
1149 fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
1151 plugin_attributes: &[(String, AttributeType)],
1154 where F: FnOnce(&mut Context, &ast::Crate)
1156 let mut cx = Context {
1157 features: Vec::new(),
1158 span_handler: span_handler,
1160 plugin_attributes: plugin_attributes,
1163 let mut accepted_features = Vec::new();
1164 let mut unknown_features = Vec::new();
1166 for attr in &krate.attrs {
1167 if !attr.check_name("feature") {
1171 match attr.meta_item_list() {
1173 span_handler.span_err(attr.span, "malformed feature attribute, \
1174 expected #![feature(...)]");
1178 let name = match mi.node {
1179 ast::MetaItemKind::Word(ref word) => (*word).clone(),
1181 span_handler.span_err(mi.span,
1182 "malformed feature, expected just \
1187 match KNOWN_FEATURES.iter()
1188 .find(|& &(n, _, _, _)| name == n) {
1189 Some(&(name, _, _, Active)) => {
1190 cx.enable_feature(name);
1192 Some(&(_, _, _, Removed)) => {
1193 span_handler.span_err(mi.span, "feature has been removed");
1195 Some(&(_, _, _, Accepted)) => {
1196 accepted_features.push(mi.span);
1199 unknown_features.push((name, mi.span));
1207 check(&mut cx, krate);
1209 // FIXME (pnkfelix): Before adding the 99th entry below, change it
1210 // to a single-pass (instead of N calls to `.has_feature`).
1213 unboxed_closures: cx.has_feature("unboxed_closures"),
1214 rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
1215 allow_quote: cx.has_feature("quote"),
1216 allow_asm: cx.has_feature("asm"),
1217 allow_log_syntax: cx.has_feature("log_syntax"),
1218 allow_concat_idents: cx.has_feature("concat_idents"),
1219 allow_trace_macros: cx.has_feature("trace_macros"),
1220 allow_internal_unstable: cx.has_feature("allow_internal_unstable"),
1221 allow_custom_derive: cx.has_feature("custom_derive"),
1222 allow_placement_in: cx.has_feature("placement_in_syntax"),
1223 allow_box: cx.has_feature("box_syntax"),
1224 allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"),
1225 allow_inclusive_range: cx.has_feature("inclusive_range_syntax"),
1226 simd_ffi: cx.has_feature("simd_ffi"),
1227 unmarked_api: cx.has_feature("unmarked_api"),
1228 declared_stable_lang_features: accepted_features,
1229 declared_lib_features: unknown_features,
1230 const_fn: cx.has_feature("const_fn"),
1231 const_indexing: cx.has_feature("const_indexing"),
1232 static_recursion: cx.has_feature("static_recursion"),
1233 default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"),
1234 rustc_attrs: cx.has_feature("rustc_attrs"),
1235 type_macros: cx.has_feature("type_macros"),
1236 cfg_target_feature: cx.has_feature("cfg_target_feature"),
1237 cfg_target_vendor: cx.has_feature("cfg_target_vendor"),
1238 cfg_target_thread_local: cx.has_feature("cfg_target_thread_local"),
1239 staged_api: cx.has_feature("staged_api"),
1240 stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"),
1241 deprecated: cx.has_feature("deprecated"),
1242 question_mark: cx.has_feature("question_mark"),
1243 specialization: cx.has_feature("specialization"),
1247 pub fn check_crate_macros(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate)
1249 check_crate_inner(cm, span_handler, krate, &[] as &'static [_],
1250 |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate))
1253 pub fn check_crate(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate,
1254 plugin_attributes: &[(String, AttributeType)],
1255 unstable: UnstableFeatures) -> Features
1257 maybe_stage_features(span_handler, krate, unstable);
1259 check_crate_inner(cm, span_handler, krate, plugin_attributes,
1260 |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx },
1264 #[derive(Clone, Copy)]
1265 pub enum UnstableFeatures {
1266 /// Hard errors for unstable features are active, as on
1267 /// beta/stable channels.
1269 /// Allow features to me activated, as on nightly.
1271 /// Errors are bypassed for bootstrapping. This is required any time
1272 /// during the build that feature-related lints are set to warn or above
1273 /// because the build turns on warnings-as-errors and uses lots of unstable
1274 /// features. As a result, this is always required for building Rust itself.
1278 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1279 unstable: UnstableFeatures) {
1280 let allow_features = match unstable {
1281 UnstableFeatures::Allow => true,
1282 UnstableFeatures::Disallow => false,
1283 UnstableFeatures::Cheat => true
1285 if !allow_features {
1286 for attr in &krate.attrs {
1287 if attr.check_name("feature") {
1288 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1289 let ref msg = format!("#[feature] may not be used on the {} release channel",
1291 span_handler.span_err(attr.span, msg);