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),
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_move_fragments", Normal, Gated("rustc_attrs",
333 "the `#[rustc_move_fragments]` attribute \
334 is just used for rustc unit tests \
335 and will never be stable")),
336 ("rustc_mir", Normal, Gated("rustc_attrs",
337 "the `#[rustc_mir]` attribute \
338 is just used for rustc unit tests \
339 and will never be stable")),
341 ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
342 EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
344 ("fundamental", Whitelisted, Gated("fundamental",
345 "the `#[fundamental]` attribute \
346 is an experimental feature")),
348 ("linked_from", Normal, Gated("linked_from",
349 "the `#[linked_from]` attribute \
350 is an experimental feature")),
352 // FIXME: #14408 whitelist docs since rustdoc looks at them
353 ("doc", Whitelisted, Ungated),
355 // FIXME: #14406 these are processed in trans, which happens after the
357 ("cold", Whitelisted, Ungated),
358 ("export_name", Whitelisted, Ungated),
359 ("inline", Whitelisted, Ungated),
360 ("link", Whitelisted, Ungated),
361 ("link_name", Whitelisted, Ungated),
362 ("link_section", Whitelisted, Ungated),
363 ("no_builtins", Whitelisted, Ungated),
364 ("no_mangle", Whitelisted, Ungated),
365 ("no_debug", Whitelisted, Gated("no_debug",
366 "the `#[no_debug]` attribute \
367 is an experimental feature")),
368 ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
369 "the `#[omit_gdb_pretty_printer_section]` \
370 attribute is just used for the Rust test \
372 ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
373 "unsafe_no_drop_flag has unstable semantics \
374 and may be removed in the future")),
375 ("unsafe_destructor_blind_to_params",
377 Gated("dropck_parametricity",
378 "unsafe_destructor_blind_to_params has unstable semantics \
379 and may be removed in the future")),
380 ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental")),
383 ("prelude_import", Whitelisted, Gated("prelude_import",
384 "`#[prelude_import]` is for use by rustc only")),
386 // FIXME: #14407 these are only looked at on-demand so we can't
387 // guarantee they'll have already been checked
388 ("rustc_deprecated", Whitelisted, Ungated),
389 ("must_use", Whitelisted, Ungated),
390 ("stable", Whitelisted, Ungated),
391 ("unstable", Whitelisted, Ungated),
392 ("deprecated", Normal, Gated("deprecated", "`#[deprecated]` attribute is unstable")),
394 ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
395 "unboxed_closures are still evolving")),
396 ("rustc_reflect_like", Whitelisted, Gated("reflect",
397 "defining reflective traits is still evolving")),
399 // Crate level attributes
400 ("crate_name", CrateLevel, Ungated),
401 ("crate_type", CrateLevel, Ungated),
402 ("crate_id", CrateLevel, Ungated),
403 ("feature", CrateLevel, Ungated),
404 ("no_start", CrateLevel, Ungated),
405 ("no_main", CrateLevel, Ungated),
406 ("no_builtins", CrateLevel, Ungated),
407 ("recursion_limit", CrateLevel, Ungated),
410 macro_rules! cfg_fn {
411 (|$x: ident| $e: expr) => {{
412 fn f($x: &Features) -> bool {
415 f as fn(&Features) -> bool
418 // cfg(...)'s that are feature gated
419 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
420 // (name in cfg, feature, function to check if the feature is enabled)
421 ("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)),
422 ("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)),
423 ("target_thread_local", "cfg_target_thread_local",
424 cfg_fn!(|x| x.cfg_target_thread_local)),
427 #[derive(Debug, Eq, PartialEq)]
428 pub enum GatedCfgAttr {
433 #[derive(Debug, Eq, PartialEq)]
434 pub struct GatedCfg {
439 impl Ord for GatedCfgAttr {
440 fn cmp(&self, other: &GatedCfgAttr) -> cmp::Ordering {
441 let to_tup = |s: &GatedCfgAttr| match *s {
442 GatedCfgAttr::GatedCfg(ref gated_cfg) => {
443 (gated_cfg.span.lo.0, gated_cfg.span.hi.0, gated_cfg.index)
445 GatedCfgAttr::GatedAttr(ref span) => {
446 (span.lo.0, span.hi.0, GATED_CFGS.len())
449 to_tup(self).cmp(&to_tup(other))
453 impl PartialOrd for GatedCfgAttr {
454 fn partial_cmp(&self, other: &GatedCfgAttr) -> Option<cmp::Ordering> {
455 Some(self.cmp(other))
460 pub fn check_and_emit(&self,
461 diagnostic: &Handler,
465 GatedCfgAttr::GatedCfg(ref cfg) => {
466 cfg.check_and_emit(diagnostic, features, codemap);
468 GatedCfgAttr::GatedAttr(span) => {
469 if !features.stmt_expr_attributes {
470 emit_feature_err(diagnostic,
471 "stmt_expr_attributes",
474 EXPLAIN_STMT_ATTR_SYNTAX);
482 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
483 let name = cfg.name();
485 .position(|info| info.0 == name)
493 fn check_and_emit(&self,
494 diagnostic: &Handler,
497 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
498 if !has_feature(features) && !codemap.span_allows_unstable(self.span) {
499 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
500 emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
506 #[derive(PartialEq, Copy, Clone, Debug)]
507 pub enum AttributeType {
508 /// Normal, builtin attribute that is consumed
509 /// by the compiler before the unused_attribute check
512 /// Builtin attribute that may not be consumed by the compiler
513 /// before the unused_attribute check. These attributes
514 /// will be ignored by the unused_attribute lint
517 /// Builtin attribute that is only allowed at the crate level
521 #[derive(PartialEq, Copy, Clone, Debug)]
522 pub enum AttributeGate {
523 /// Is gated by a given feature gate and reason
524 Gated(&'static str, &'static str),
526 /// Ungated attribute, can be used on all release channels
530 /// A set of features to be used by later passes.
531 pub struct Features {
532 pub unboxed_closures: bool,
533 pub rustc_diagnostic_macros: bool,
534 pub allow_quote: bool,
536 pub allow_log_syntax: bool,
537 pub allow_concat_idents: bool,
538 pub allow_trace_macros: bool,
539 pub allow_internal_unstable: bool,
540 pub allow_custom_derive: bool,
541 pub allow_placement_in: bool,
543 pub allow_pushpop_unsafe: bool,
545 pub unmarked_api: bool,
546 pub negate_unsigned: bool,
547 /// spans of #![feature] attrs for stable language features. for error reporting
548 pub declared_stable_lang_features: Vec<Span>,
549 /// #![feature] attrs for non-language (library) features
550 pub declared_lib_features: Vec<(InternedString, Span)>,
552 pub const_indexing: bool,
553 pub static_recursion: bool,
554 pub default_type_parameter_fallback: bool,
555 pub type_macros: bool,
556 pub cfg_target_feature: bool,
557 pub cfg_target_vendor: bool,
558 pub cfg_target_thread_local: bool,
559 pub augmented_assignments: bool,
560 pub braced_empty_structs: bool,
561 pub staged_api: bool,
562 pub stmt_expr_attributes: bool,
563 pub deprecated: bool,
567 pub fn new() -> Features {
569 unboxed_closures: false,
570 rustc_diagnostic_macros: false,
573 allow_log_syntax: false,
574 allow_concat_idents: false,
575 allow_trace_macros: false,
576 allow_internal_unstable: false,
577 allow_custom_derive: false,
578 allow_placement_in: false,
580 allow_pushpop_unsafe: false,
583 negate_unsigned: false,
584 declared_stable_lang_features: Vec::new(),
585 declared_lib_features: Vec::new(),
587 const_indexing: false,
588 static_recursion: false,
589 default_type_parameter_fallback: false,
591 cfg_target_feature: false,
592 cfg_target_vendor: false,
593 cfg_target_thread_local: false,
594 augmented_assignments: false,
595 braced_empty_structs: false,
597 stmt_expr_attributes: false,
603 const EXPLAIN_BOX_SYNTAX: &'static str =
604 "box expression syntax is experimental; you can call `Box::new` instead.";
606 const EXPLAIN_PLACEMENT_IN: &'static str =
607 "placement-in expression syntax is experimental and subject to change.";
609 const EXPLAIN_PUSHPOP_UNSAFE: &'static str =
610 "push/pop_unsafe macros are experimental and subject to change.";
612 const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
613 "attributes on non-item statements and expressions are experimental.";
615 pub fn check_for_box_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
616 if let Some(&Features { allow_box: true, .. }) = f {
619 emit_feature_err(diag, "box_syntax", span, GateIssue::Language, EXPLAIN_BOX_SYNTAX);
622 pub fn check_for_placement_in(f: Option<&Features>, diag: &Handler, span: Span) {
623 if let Some(&Features { allow_placement_in: true, .. }) = f {
626 emit_feature_err(diag, "placement_in_syntax", span, GateIssue::Language, EXPLAIN_PLACEMENT_IN);
629 pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
630 if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f {
633 emit_feature_err(diag, "pushpop_unsafe", span, GateIssue::Language, EXPLAIN_PUSHPOP_UNSAFE);
637 features: Vec<&'static str>,
638 span_handler: &'a Handler,
640 plugin_attributes: &'a [(String, AttributeType)],
643 impl<'a> Context<'a> {
644 fn enable_feature(&mut self, feature: &'static str) {
645 debug!("enabling feature: {}", feature);
646 self.features.push(feature);
649 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
650 let has_feature = self.has_feature(feature);
651 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature);
653 emit_feature_err(self.span_handler, feature, span, GateIssue::Language, explain);
656 fn has_feature(&self, feature: &str) -> bool {
657 self.features.iter().any(|&n| n == feature)
660 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
661 debug!("check_attribute(attr = {:?})", attr);
662 let name = &*attr.name();
663 for &(n, ty, gateage) in KNOWN_ATTRIBUTES {
665 if let Gated(gate, desc) = gateage {
666 self.gate_feature(gate, attr.span, desc);
668 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
672 for &(ref n, ref ty) in self.plugin_attributes {
674 // Plugins can't gate attributes, so we don't check for it
675 // unlike the code above; we only use this loop to
676 // short-circuit to avoid the checks below
677 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
681 if name.starts_with("rustc_") {
682 self.gate_feature("rustc_attrs", attr.span,
683 "unless otherwise specified, attributes \
684 with the prefix `rustc_` \
685 are reserved for internal compiler diagnostics");
686 } else if name.starts_with("derive_") {
687 self.gate_feature("custom_derive", attr.span,
688 "attributes of the form `#[derive_*]` are reserved \
691 // Only run the custom attribute lint during regular
692 // feature gate checking. Macro gating runs
693 // before the plugin attributes are registered
694 // so we skip this then
696 self.gate_feature("custom_attribute", attr.span,
697 &format!("The attribute `{}` is currently \
698 unknown to the compiler and \
700 added to it in the future",
707 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
708 let info = KNOWN_FEATURES.iter()
709 .find(|t| t.0 == feature)
712 if let Active = info.3 {
713 // FIXME (#28244): enforce that active features have issue numbers
714 // assert!(issue.is_some())
724 pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
726 let issue = match issue {
727 GateIssue::Language => find_lang_feature_issue(feature),
728 GateIssue::Library(lib) => lib,
731 if let Some(n) = issue {
732 diag.span_err(span, &format!("{} (see issue #{})", explain, n));
734 diag.span_err(span, explain);
737 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
738 if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; }
739 diag.fileline_help(span, &format!("add #![feature({})] to the \
740 crate attributes to enable",
744 pub const EXPLAIN_ASM: &'static str =
745 "inline assembly is not stable enough for use and is subject to change";
747 pub const EXPLAIN_LOG_SYNTAX: &'static str =
748 "`log_syntax!` is not stable enough for use and is subject to change";
750 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
751 "`concat_idents` is not stable enough for use and is subject to change";
753 pub const EXPLAIN_TRACE_MACROS: &'static str =
754 "`trace_macros` is not stable enough for use and is subject to change";
755 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
756 "allow_internal_unstable side-steps feature gating and stability checks";
758 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
759 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
761 struct MacroVisitor<'a> {
762 context: &'a Context<'a>
765 impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
766 fn visit_mac(&mut self, mac: &ast::Mac) {
767 let path = &mac.node.path;
768 let name = path.segments.last().unwrap().identifier.name.as_str();
770 // Issue 22234: If you add a new case here, make sure to also
771 // add code to catch the macro during or after expansion.
773 // We still keep this MacroVisitor (rather than *solely*
774 // relying on catching cases during or after expansion) to
775 // catch uses of these macros within conditionally-compiled
776 // code, e.g. `#[cfg]`-guarded functions.
779 self.context.gate_feature("asm", path.span, EXPLAIN_ASM);
782 else if name == "log_syntax" {
783 self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX);
786 else if name == "trace_macros" {
787 self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS);
790 else if name == "concat_idents" {
791 self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS);
795 fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
796 self.context.check_attribute(attr, true);
799 fn visit_expr(&mut self, e: &ast::Expr) {
800 // Issue 22181: overloaded-`box` and placement-`in` are
801 // implemented via a desugaring expansion, so their feature
802 // gates go into MacroVisitor since that works pre-expansion.
804 // Issue 22234: we also check during expansion as well.
805 // But we keep these checks as a pre-expansion check to catch
806 // uses in e.g. conditionalized code.
808 if let ast::ExprBox(_) = e.node {
809 self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX);
812 if let ast::ExprInPlace(..) = e.node {
813 self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN);
816 visit::walk_expr(self, e);
820 struct PostExpansionVisitor<'a> {
821 context: &'a Context<'a>,
824 impl<'a> PostExpansionVisitor<'a> {
825 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
826 if !self.context.cm.span_allows_unstable(span) {
827 self.context.gate_feature(feature, span, explain)
832 impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
833 fn visit_attribute(&mut self, attr: &ast::Attribute) {
834 if !self.context.cm.span_allows_unstable(attr.span) {
835 self.context.check_attribute(attr, false);
839 fn visit_name(&mut self, sp: Span, name: ast::Name) {
840 if !name.as_str().is_ascii() {
841 self.gate_feature("non_ascii_idents", sp,
842 "non-ascii idents are not fully supported.");
846 fn visit_item(&mut self, i: &ast::Item) {
848 ast::ItemExternCrate(_) => {
849 if attr::contains_name(&i.attrs[..], "macro_reexport") {
850 self.gate_feature("macro_reexport", i.span,
851 "macros reexports are experimental \
852 and possibly buggy");
856 ast::ItemForeignMod(ref foreign_module) => {
857 if attr::contains_name(&i.attrs[..], "link_args") {
858 self.gate_feature("link_args", i.span,
859 "the `link_args` attribute is not portable \
860 across platforms, it is recommended to \
861 use `#[link(name = \"foo\")]` instead")
863 let maybe_feature = match foreign_module.abi {
864 Abi::RustIntrinsic => Some(("intrinsics", "intrinsics are subject to change")),
865 Abi::PlatformIntrinsic => {
866 Some(("platform_intrinsics",
867 "platform intrinsics are experimental and possibly buggy"))
870 Some(("abi_vectorcall",
871 "vectorcall is experimental and subject to change"
876 if let Some((feature, msg)) = maybe_feature {
877 self.gate_feature(feature, i.span, msg)
882 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
883 self.gate_feature("plugin_registrar", i.span,
884 "compiler plugins are experimental and possibly buggy");
886 if attr::contains_name(&i.attrs[..], "start") {
887 self.gate_feature("start", i.span,
888 "a #[start] function is an experimental \
889 feature whose signature may change \
892 if attr::contains_name(&i.attrs[..], "main") {
893 self.gate_feature("main", i.span,
894 "declaration of a nonstandard #[main] \
895 function may change over time, for now \
896 a top-level `fn main()` is required");
900 ast::ItemStruct(..) => {
901 if attr::contains_name(&i.attrs[..], "simd") {
902 self.gate_feature("simd", i.span,
903 "SIMD types are experimental and possibly buggy");
904 self.context.span_handler.span_warn(i.span,
905 "the `#[simd]` attribute is deprecated, \
906 use `#[repr(simd)]` instead");
908 for attr in &i.attrs {
909 if attr.name() == "repr" {
910 for item in attr.meta_item_list().unwrap_or(&[]) {
911 if item.name() == "simd" {
912 self.gate_feature("repr_simd", i.span,
913 "SIMD types are experimental and possibly buggy");
921 ast::ItemDefaultImpl(..) => {
922 self.gate_feature("optin_builtin_traits",
924 "default trait implementations are experimental \
925 and possibly buggy");
928 ast::ItemImpl(_, polarity, _, _, _, _) => {
930 ast::ImplPolarity::Negative => {
931 self.gate_feature("optin_builtin_traits",
933 "negative trait bounds are not yet fully implemented; \
934 use marker types for now");
943 visit::walk_item(self, i);
946 fn visit_variant_data(&mut self, s: &'v ast::VariantData, _: ast::Ident,
947 _: &'v ast::Generics, _: ast::NodeId, span: Span) {
948 if s.fields().is_empty() {
950 self.gate_feature("braced_empty_structs", span,
951 "empty structs and enum variants with braces are unstable");
952 } else if s.is_tuple() {
953 self.context.span_handler.span_err(span, "empty tuple structs and enum variants \
954 are not allowed, use unit structs and \
955 enum variants instead");
956 self.context.span_handler.span_help(span, "remove trailing `()` to make a unit \
957 struct or unit enum variant");
960 visit::walk_struct_def(self, s)
963 fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
964 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
966 Some(val) => val.starts_with("llvm."),
970 self.gate_feature("link_llvm_intrinsics", i.span,
971 "linking to LLVM intrinsics is experimental");
974 visit::walk_foreign_item(self, i)
977 fn visit_expr(&mut self, e: &ast::Expr) {
980 self.gate_feature("box_syntax",
982 "box expression syntax is experimental; \
983 you can call `Box::new` instead.");
985 ast::ExprType(..) => {
986 self.gate_feature("type_ascription", e.span,
987 "type ascription is experimental");
991 visit::walk_expr(self, e);
994 fn visit_pat(&mut self, pattern: &ast::Pat) {
996 ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
997 self.gate_feature("advanced_slice_patterns",
999 "multiple-element slice matches anywhere \
1000 but at the end of a slice (e.g. \
1001 `[0, ..xs, 0]`) are experimental")
1003 ast::PatVec(..) => {
1004 self.gate_feature("slice_patterns",
1006 "slice pattern syntax is experimental");
1008 ast::PatBox(..) => {
1009 self.gate_feature("box_patterns",
1011 "box pattern syntax is experimental");
1015 visit::walk_pat(self, pattern)
1018 fn visit_fn(&mut self,
1019 fn_kind: FnKind<'v>,
1020 fn_decl: &'v ast::FnDecl,
1021 block: &'v ast::Block,
1024 // check for const fn declarations
1026 FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1027 self.gate_feature("const_fn", span, "const fn is unstable");
1030 // stability of const fn methods are covered in
1031 // visit_trait_item and visit_impl_item below; this is
1032 // because default methods don't pass through this
1038 FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
1039 self.gate_feature("intrinsics",
1041 "intrinsics are subject to change")
1043 FnKind::ItemFn(_, _, _, _, abi, _) |
1044 FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => match abi {
1046 self.gate_feature("unboxed_closures", span,
1047 "rust-call ABI is subject to change");
1049 Abi::Vectorcall => {
1050 self.gate_feature("abi_vectorcall", span,
1051 "vectorcall is experimental and subject to change");
1057 visit::walk_fn(self, fn_kind, fn_decl, block, span);
1060 fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
1062 ast::ConstTraitItem(..) => {
1063 self.gate_feature("associated_consts",
1065 "associated constants are experimental")
1067 ast::MethodTraitItem(ref sig, _) => {
1068 if sig.constness == ast::Constness::Const {
1069 self.gate_feature("const_fn", ti.span, "const fn is unstable");
1072 ast::TypeTraitItem(_, Some(_)) => {
1073 self.gate_feature("associated_type_defaults", ti.span,
1074 "associated type defaults are unstable");
1078 visit::walk_trait_item(self, ti);
1081 fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
1083 ast::ImplItemKind::Const(..) => {
1084 self.gate_feature("associated_consts",
1086 "associated constants are experimental")
1088 ast::ImplItemKind::Method(ref sig, _) => {
1089 if sig.constness == ast::Constness::Const {
1090 self.gate_feature("const_fn", ii.span, "const fn is unstable");
1095 visit::walk_impl_item(self, ii);
1099 fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
1101 plugin_attributes: &[(String, AttributeType)],
1104 where F: FnOnce(&mut Context, &ast::Crate)
1106 let mut cx = Context {
1107 features: Vec::new(),
1108 span_handler: span_handler,
1110 plugin_attributes: plugin_attributes,
1113 let mut accepted_features = Vec::new();
1114 let mut unknown_features = Vec::new();
1116 for attr in &krate.attrs {
1117 if !attr.check_name("feature") {
1121 match attr.meta_item_list() {
1123 span_handler.span_err(attr.span, "malformed feature attribute, \
1124 expected #![feature(...)]");
1128 let name = match mi.node {
1129 ast::MetaWord(ref word) => (*word).clone(),
1131 span_handler.span_err(mi.span,
1132 "malformed feature, expected just \
1137 match KNOWN_FEATURES.iter()
1138 .find(|& &(n, _, _, _)| name == n) {
1139 Some(&(name, _, _, Active)) => {
1140 cx.enable_feature(name);
1142 Some(&(_, _, _, Removed)) => {
1143 span_handler.span_err(mi.span, "feature has been removed");
1145 Some(&(_, _, _, Accepted)) => {
1146 accepted_features.push(mi.span);
1149 unknown_features.push((name, mi.span));
1157 check(&mut cx, krate);
1159 // FIXME (pnkfelix): Before adding the 99th entry below, change it
1160 // to a single-pass (instead of N calls to `.has_feature`).
1163 unboxed_closures: cx.has_feature("unboxed_closures"),
1164 rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
1165 allow_quote: cx.has_feature("quote"),
1166 allow_asm: cx.has_feature("asm"),
1167 allow_log_syntax: cx.has_feature("log_syntax"),
1168 allow_concat_idents: cx.has_feature("concat_idents"),
1169 allow_trace_macros: cx.has_feature("trace_macros"),
1170 allow_internal_unstable: cx.has_feature("allow_internal_unstable"),
1171 allow_custom_derive: cx.has_feature("custom_derive"),
1172 allow_placement_in: cx.has_feature("placement_in_syntax"),
1173 allow_box: cx.has_feature("box_syntax"),
1174 allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"),
1175 simd_ffi: cx.has_feature("simd_ffi"),
1176 unmarked_api: cx.has_feature("unmarked_api"),
1177 negate_unsigned: cx.has_feature("negate_unsigned"),
1178 declared_stable_lang_features: accepted_features,
1179 declared_lib_features: unknown_features,
1180 const_fn: cx.has_feature("const_fn"),
1181 const_indexing: cx.has_feature("const_indexing"),
1182 static_recursion: cx.has_feature("static_recursion"),
1183 default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"),
1184 type_macros: cx.has_feature("type_macros"),
1185 cfg_target_feature: cx.has_feature("cfg_target_feature"),
1186 cfg_target_vendor: cx.has_feature("cfg_target_vendor"),
1187 cfg_target_thread_local: cx.has_feature("cfg_target_thread_local"),
1188 augmented_assignments: cx.has_feature("augmented_assignments"),
1189 braced_empty_structs: cx.has_feature("braced_empty_structs"),
1190 staged_api: cx.has_feature("staged_api"),
1191 stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"),
1192 deprecated: cx.has_feature("deprecated"),
1196 pub fn check_crate_macros(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate)
1198 check_crate_inner(cm, span_handler, krate, &[] as &'static [_],
1199 |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate))
1202 pub fn check_crate(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate,
1203 plugin_attributes: &[(String, AttributeType)],
1204 unstable: UnstableFeatures) -> Features
1206 maybe_stage_features(span_handler, krate, unstable);
1208 check_crate_inner(cm, span_handler, krate, plugin_attributes,
1209 |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx },
1213 #[derive(Clone, Copy)]
1214 pub enum UnstableFeatures {
1215 /// Hard errors for unstable features are active, as on
1216 /// beta/stable channels.
1218 /// Allow features to me activated, as on nightly.
1220 /// Errors are bypassed for bootstrapping. This is required any time
1221 /// during the build that feature-related lints are set to warn or above
1222 /// because the build turns on warnings-as-errors and uses lots of unstable
1223 /// features. As a result, this is always required for building Rust itself.
1227 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1228 unstable: UnstableFeatures) {
1229 let allow_features = match unstable {
1230 UnstableFeatures::Allow => true,
1231 UnstableFeatures::Disallow => false,
1232 UnstableFeatures::Cheat => true
1234 if !allow_features {
1235 for attr in &krate.attrs {
1236 if attr.check_name("feature") {
1237 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1238 let ref msg = format!("#[feature] may not be used on the {} release channel",
1240 span_handler.span_err(attr.span, msg);