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),
243 // (changing above list without updating src/doc/reference.md makes @cmr sad)
246 /// Represents an active feature that is currently being implemented or
247 /// currently being considered for addition/removal.
250 /// Represents a feature which has since been removed (it was once Active)
253 /// This language feature has since been Accepted (it was once Active)
257 // Attributes that have a special meaning to rustc or rustdoc
258 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
261 ("warn", Normal, Ungated),
262 ("allow", Normal, Ungated),
263 ("forbid", Normal, Ungated),
264 ("deny", Normal, Ungated),
266 ("macro_reexport", Normal, Ungated),
267 ("macro_use", Normal, Ungated),
268 ("macro_export", Normal, Ungated),
269 ("plugin_registrar", Normal, Ungated),
271 ("cfg", Normal, Ungated),
272 ("cfg_attr", Normal, Ungated),
273 ("main", Normal, Ungated),
274 ("start", Normal, Ungated),
275 ("test", Normal, Ungated),
276 ("bench", Normal, Ungated),
277 ("simd", Normal, Ungated),
278 ("repr", Normal, Ungated),
279 ("path", Normal, Ungated),
280 ("abi", Normal, Ungated),
281 ("automatically_derived", Normal, Ungated),
282 ("no_mangle", Normal, Ungated),
283 ("no_link", Normal, Ungated),
284 ("derive", Normal, Ungated),
285 ("should_panic", Normal, Ungated),
286 ("ignore", Normal, Ungated),
287 ("no_implicit_prelude", Normal, Ungated),
288 ("reexport_test_harness_main", Normal, Ungated),
289 ("link_args", Normal, Ungated),
290 ("macro_escape", Normal, Ungated),
292 // Not used any more, but we can't feature gate it
293 ("no_stack_check", Normal, Ungated),
295 ("plugin", CrateLevel, Gated("plugin",
296 "compiler plugins are experimental \
297 and possibly buggy")),
298 ("no_std", CrateLevel, Ungated),
299 ("no_core", CrateLevel, Gated("no_core",
300 "no_core is experimental")),
301 ("lang", Normal, Gated("lang_items",
302 "language items are subject to change")),
303 ("linkage", Whitelisted, Gated("linkage",
304 "the `linkage` attribute is experimental \
305 and not portable across platforms")),
306 ("thread_local", Whitelisted, Gated("thread_local",
307 "`#[thread_local]` is an experimental feature, and does \
308 not currently handle destructors. There is no \
309 corresponding `#[task_local]` mapping to the task \
312 ("rustc_on_unimplemented", Normal, Gated("on_unimplemented",
313 "the `#[rustc_on_unimplemented]` attribute \
314 is an experimental feature")),
315 ("allocator", Whitelisted, Gated("allocator",
316 "the `#[allocator]` attribute is an experimental feature")),
317 ("needs_allocator", Normal, Gated("needs_allocator",
318 "the `#[needs_allocator]` \
319 attribute is an experimental \
321 ("rustc_variance", Normal, Gated("rustc_attrs",
322 "the `#[rustc_variance]` attribute \
323 is just used for rustc unit tests \
324 and will never be stable")),
325 ("rustc_error", Whitelisted, Gated("rustc_attrs",
326 "the `#[rustc_error]` attribute \
327 is just used for rustc unit tests \
328 and will never be stable")),
329 ("rustc_if_this_changed", Whitelisted, Gated("rustc_attrs",
330 "the `#[rustc_if_this_changed]` attribute \
331 is just used for rustc unit tests \
332 and will never be stable")),
333 ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs",
334 "the `#[rustc_if_this_changed]` attribute \
335 is just used for rustc unit tests \
336 and will never be stable")),
337 ("rustc_move_fragments", Normal, Gated("rustc_attrs",
338 "the `#[rustc_move_fragments]` attribute \
339 is just used for rustc unit tests \
340 and will never be stable")),
341 ("rustc_mir", Normal, Gated("rustc_attrs",
342 "the `#[rustc_mir]` attribute \
343 is just used for rustc unit tests \
344 and will never be stable")),
346 ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
347 EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),
349 ("fundamental", Whitelisted, Gated("fundamental",
350 "the `#[fundamental]` attribute \
351 is an experimental feature")),
353 ("linked_from", Normal, Gated("linked_from",
354 "the `#[linked_from]` attribute \
355 is an experimental feature")),
357 // FIXME: #14408 whitelist docs since rustdoc looks at them
358 ("doc", Whitelisted, Ungated),
360 // FIXME: #14406 these are processed in trans, which happens after the
362 ("cold", Whitelisted, Ungated),
363 ("export_name", Whitelisted, Ungated),
364 ("inline", Whitelisted, Ungated),
365 ("link", Whitelisted, Ungated),
366 ("link_name", Whitelisted, Ungated),
367 ("link_section", Whitelisted, Ungated),
368 ("no_builtins", Whitelisted, Ungated),
369 ("no_mangle", Whitelisted, Ungated),
370 ("no_debug", Whitelisted, Gated("no_debug",
371 "the `#[no_debug]` attribute \
372 is an experimental feature")),
373 ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
374 "the `#[omit_gdb_pretty_printer_section]` \
375 attribute is just used for the Rust test \
377 ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
378 "unsafe_no_drop_flag has unstable semantics \
379 and may be removed in the future")),
380 ("unsafe_destructor_blind_to_params",
382 Gated("dropck_parametricity",
383 "unsafe_destructor_blind_to_params has unstable semantics \
384 and may be removed in the future")),
385 ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental")),
388 ("prelude_import", Whitelisted, Gated("prelude_import",
389 "`#[prelude_import]` is for use by rustc only")),
391 // FIXME: #14407 these are only looked at on-demand so we can't
392 // guarantee they'll have already been checked
393 ("rustc_deprecated", Whitelisted, Ungated),
394 ("must_use", Whitelisted, Ungated),
395 ("stable", Whitelisted, Ungated),
396 ("unstable", Whitelisted, Ungated),
397 ("deprecated", Normal, Gated("deprecated", "`#[deprecated]` attribute is unstable")),
399 ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
400 "unboxed_closures are still evolving")),
401 ("rustc_reflect_like", Whitelisted, Gated("reflect",
402 "defining reflective traits is still evolving")),
404 // Crate level attributes
405 ("crate_name", CrateLevel, Ungated),
406 ("crate_type", CrateLevel, Ungated),
407 ("crate_id", CrateLevel, Ungated),
408 ("feature", CrateLevel, Ungated),
409 ("no_start", CrateLevel, Ungated),
410 ("no_main", CrateLevel, Ungated),
411 ("no_builtins", CrateLevel, Ungated),
412 ("recursion_limit", CrateLevel, Ungated),
415 macro_rules! cfg_fn {
416 (|$x: ident| $e: expr) => {{
417 fn f($x: &Features) -> bool {
420 f as fn(&Features) -> bool
423 // cfg(...)'s that are feature gated
424 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
425 // (name in cfg, feature, function to check if the feature is enabled)
426 ("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)),
427 ("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)),
428 ("target_thread_local", "cfg_target_thread_local",
429 cfg_fn!(|x| x.cfg_target_thread_local)),
432 #[derive(Debug, Eq, PartialEq)]
433 pub enum GatedCfgAttr {
438 #[derive(Debug, Eq, PartialEq)]
439 pub struct GatedCfg {
444 impl Ord for GatedCfgAttr {
445 fn cmp(&self, other: &GatedCfgAttr) -> cmp::Ordering {
446 let to_tup = |s: &GatedCfgAttr| match *s {
447 GatedCfgAttr::GatedCfg(ref gated_cfg) => {
448 (gated_cfg.span.lo.0, gated_cfg.span.hi.0, gated_cfg.index)
450 GatedCfgAttr::GatedAttr(ref span) => {
451 (span.lo.0, span.hi.0, GATED_CFGS.len())
454 to_tup(self).cmp(&to_tup(other))
458 impl PartialOrd for GatedCfgAttr {
459 fn partial_cmp(&self, other: &GatedCfgAttr) -> Option<cmp::Ordering> {
460 Some(self.cmp(other))
465 pub fn check_and_emit(&self,
466 diagnostic: &Handler,
470 GatedCfgAttr::GatedCfg(ref cfg) => {
471 cfg.check_and_emit(diagnostic, features, codemap);
473 GatedCfgAttr::GatedAttr(span) => {
474 if !features.stmt_expr_attributes {
475 emit_feature_err(diagnostic,
476 "stmt_expr_attributes",
479 EXPLAIN_STMT_ATTR_SYNTAX);
487 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
488 let name = cfg.name();
490 .position(|info| info.0 == name)
498 fn check_and_emit(&self,
499 diagnostic: &Handler,
502 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
503 if !has_feature(features) && !codemap.span_allows_unstable(self.span) {
504 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
505 emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
511 #[derive(PartialEq, Copy, Clone, Debug)]
512 pub enum AttributeType {
513 /// Normal, builtin attribute that is consumed
514 /// by the compiler before the unused_attribute check
517 /// Builtin attribute that may not be consumed by the compiler
518 /// before the unused_attribute check. These attributes
519 /// will be ignored by the unused_attribute lint
522 /// Builtin attribute that is only allowed at the crate level
526 #[derive(PartialEq, Copy, Clone, Debug)]
527 pub enum AttributeGate {
528 /// Is gated by a given feature gate and reason
529 Gated(&'static str, &'static str),
531 /// Ungated attribute, can be used on all release channels
535 /// A set of features to be used by later passes.
536 pub struct Features {
537 pub unboxed_closures: bool,
538 pub rustc_diagnostic_macros: bool,
539 pub allow_quote: bool,
541 pub allow_log_syntax: bool,
542 pub allow_concat_idents: bool,
543 pub allow_trace_macros: bool,
544 pub allow_internal_unstable: bool,
545 pub allow_custom_derive: bool,
546 pub allow_placement_in: bool,
548 pub allow_pushpop_unsafe: bool,
550 pub unmarked_api: bool,
551 /// spans of #![feature] attrs for stable language features. for error reporting
552 pub declared_stable_lang_features: Vec<Span>,
553 /// #![feature] attrs for non-language (library) features
554 pub declared_lib_features: Vec<(InternedString, Span)>,
556 pub const_indexing: bool,
557 pub static_recursion: bool,
558 pub default_type_parameter_fallback: bool,
559 pub type_macros: bool,
560 pub cfg_target_feature: bool,
561 pub cfg_target_vendor: bool,
562 pub cfg_target_thread_local: bool,
563 pub augmented_assignments: bool,
564 pub braced_empty_structs: bool,
565 pub staged_api: bool,
566 pub stmt_expr_attributes: bool,
567 pub deprecated: bool,
571 pub fn new() -> Features {
573 unboxed_closures: false,
574 rustc_diagnostic_macros: false,
577 allow_log_syntax: false,
578 allow_concat_idents: false,
579 allow_trace_macros: false,
580 allow_internal_unstable: false,
581 allow_custom_derive: false,
582 allow_placement_in: false,
584 allow_pushpop_unsafe: false,
587 declared_stable_lang_features: Vec::new(),
588 declared_lib_features: Vec::new(),
590 const_indexing: false,
591 static_recursion: false,
592 default_type_parameter_fallback: false,
594 cfg_target_feature: false,
595 cfg_target_vendor: false,
596 cfg_target_thread_local: false,
597 augmented_assignments: false,
598 braced_empty_structs: false,
600 stmt_expr_attributes: false,
606 const EXPLAIN_BOX_SYNTAX: &'static str =
607 "box expression syntax is experimental; you can call `Box::new` instead.";
609 const EXPLAIN_PLACEMENT_IN: &'static str =
610 "placement-in expression syntax is experimental and subject to change.";
612 const EXPLAIN_PUSHPOP_UNSAFE: &'static str =
613 "push/pop_unsafe macros are experimental and subject to change.";
615 const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
616 "attributes on non-item statements and expressions are experimental.";
618 pub fn check_for_box_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
619 if let Some(&Features { allow_box: true, .. }) = f {
622 emit_feature_err(diag, "box_syntax", span, GateIssue::Language, EXPLAIN_BOX_SYNTAX);
625 pub fn check_for_placement_in(f: Option<&Features>, diag: &Handler, span: Span) {
626 if let Some(&Features { allow_placement_in: true, .. }) = f {
629 emit_feature_err(diag, "placement_in_syntax", span, GateIssue::Language, EXPLAIN_PLACEMENT_IN);
632 pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &Handler, span: Span) {
633 if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f {
636 emit_feature_err(diag, "pushpop_unsafe", span, GateIssue::Language, EXPLAIN_PUSHPOP_UNSAFE);
640 features: Vec<&'static str>,
641 span_handler: &'a Handler,
643 plugin_attributes: &'a [(String, AttributeType)],
646 impl<'a> Context<'a> {
647 fn enable_feature(&mut self, feature: &'static str) {
648 debug!("enabling feature: {}", feature);
649 self.features.push(feature);
652 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
653 let has_feature = self.has_feature(feature);
654 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature);
656 emit_feature_err(self.span_handler, feature, span, GateIssue::Language, explain);
659 fn has_feature(&self, feature: &str) -> bool {
660 self.features.iter().any(|&n| n == feature)
663 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
664 debug!("check_attribute(attr = {:?})", attr);
665 let name = &*attr.name();
666 for &(n, ty, gateage) in KNOWN_ATTRIBUTES {
668 if let Gated(gate, desc) = gateage {
669 self.gate_feature(gate, attr.span, desc);
671 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
675 for &(ref n, ref ty) in self.plugin_attributes {
677 // Plugins can't gate attributes, so we don't check for it
678 // unlike the code above; we only use this loop to
679 // short-circuit to avoid the checks below
680 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
684 if name.starts_with("rustc_") {
685 self.gate_feature("rustc_attrs", attr.span,
686 "unless otherwise specified, attributes \
687 with the prefix `rustc_` \
688 are reserved for internal compiler diagnostics");
689 } else if name.starts_with("derive_") {
690 self.gate_feature("custom_derive", attr.span,
691 "attributes of the form `#[derive_*]` are reserved \
694 // Only run the custom attribute lint during regular
695 // feature gate checking. Macro gating runs
696 // before the plugin attributes are registered
697 // so we skip this then
699 self.gate_feature("custom_attribute", attr.span,
700 &format!("The attribute `{}` is currently \
701 unknown to the compiler and \
703 added to it in the future",
710 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
711 let info = KNOWN_FEATURES.iter()
712 .find(|t| t.0 == feature)
715 if let Active = info.3 {
716 // FIXME (#28244): enforce that active features have issue numbers
717 // assert!(issue.is_some())
727 pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
729 let issue = match issue {
730 GateIssue::Language => find_lang_feature_issue(feature),
731 GateIssue::Library(lib) => lib,
734 let mut err = if let Some(n) = issue {
735 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
737 diag.struct_span_err(span, explain)
740 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
741 if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
745 err.fileline_help(span, &format!("add #![feature({})] to the \
746 crate attributes to enable",
751 pub const EXPLAIN_ASM: &'static str =
752 "inline assembly is not stable enough for use and is subject to change";
754 pub const EXPLAIN_LOG_SYNTAX: &'static str =
755 "`log_syntax!` is not stable enough for use and is subject to change";
757 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
758 "`concat_idents` is not stable enough for use and is subject to change";
760 pub const EXPLAIN_TRACE_MACROS: &'static str =
761 "`trace_macros` is not stable enough for use and is subject to change";
762 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
763 "allow_internal_unstable side-steps feature gating and stability checks";
765 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
766 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
768 struct MacroVisitor<'a> {
769 context: &'a Context<'a>
772 impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
773 fn visit_mac(&mut self, mac: &ast::Mac) {
774 let path = &mac.node.path;
775 let name = path.segments.last().unwrap().identifier.name.as_str();
777 // Issue 22234: If you add a new case here, make sure to also
778 // add code to catch the macro during or after expansion.
780 // We still keep this MacroVisitor (rather than *solely*
781 // relying on catching cases during or after expansion) to
782 // catch uses of these macros within conditionally-compiled
783 // code, e.g. `#[cfg]`-guarded functions.
786 self.context.gate_feature("asm", path.span, EXPLAIN_ASM);
789 else if name == "log_syntax" {
790 self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX);
793 else if name == "trace_macros" {
794 self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS);
797 else if name == "concat_idents" {
798 self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS);
802 fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
803 self.context.check_attribute(attr, true);
806 fn visit_expr(&mut self, e: &ast::Expr) {
807 // Issue 22181: overloaded-`box` and placement-`in` are
808 // implemented via a desugaring expansion, so their feature
809 // gates go into MacroVisitor since that works pre-expansion.
811 // Issue 22234: we also check during expansion as well.
812 // But we keep these checks as a pre-expansion check to catch
813 // uses in e.g. conditionalized code.
815 if let ast::ExprBox(_) = e.node {
816 self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX);
819 if let ast::ExprInPlace(..) = e.node {
820 self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN);
823 visit::walk_expr(self, e);
827 struct PostExpansionVisitor<'a> {
828 context: &'a Context<'a>,
831 impl<'a> PostExpansionVisitor<'a> {
832 fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
833 if !self.context.cm.span_allows_unstable(span) {
834 self.context.gate_feature(feature, span, explain)
839 impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
840 fn visit_attribute(&mut self, attr: &ast::Attribute) {
841 if !self.context.cm.span_allows_unstable(attr.span) {
842 self.context.check_attribute(attr, false);
846 fn visit_name(&mut self, sp: Span, name: ast::Name) {
847 if !name.as_str().is_ascii() {
848 self.gate_feature("non_ascii_idents", sp,
849 "non-ascii idents are not fully supported.");
853 fn visit_item(&mut self, i: &ast::Item) {
855 ast::ItemExternCrate(_) => {
856 if attr::contains_name(&i.attrs[..], "macro_reexport") {
857 self.gate_feature("macro_reexport", i.span,
858 "macros reexports are experimental \
859 and possibly buggy");
863 ast::ItemForeignMod(ref foreign_module) => {
864 if attr::contains_name(&i.attrs[..], "link_args") {
865 self.gate_feature("link_args", i.span,
866 "the `link_args` attribute is not portable \
867 across platforms, it is recommended to \
868 use `#[link(name = \"foo\")]` instead")
870 let maybe_feature = match foreign_module.abi {
871 Abi::RustIntrinsic => Some(("intrinsics", "intrinsics are subject to change")),
872 Abi::PlatformIntrinsic => {
873 Some(("platform_intrinsics",
874 "platform intrinsics are experimental and possibly buggy"))
878 if let Some((feature, msg)) = maybe_feature {
879 self.gate_feature(feature, i.span, msg)
884 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
885 self.gate_feature("plugin_registrar", i.span,
886 "compiler plugins are experimental and possibly buggy");
888 if attr::contains_name(&i.attrs[..], "start") {
889 self.gate_feature("start", i.span,
890 "a #[start] function is an experimental \
891 feature whose signature may change \
894 if attr::contains_name(&i.attrs[..], "main") {
895 self.gate_feature("main", i.span,
896 "declaration of a nonstandard #[main] \
897 function may change over time, for now \
898 a top-level `fn main()` is required");
902 ast::ItemStruct(..) => {
903 if attr::contains_name(&i.attrs[..], "simd") {
904 self.gate_feature("simd", i.span,
905 "SIMD types are experimental and possibly buggy");
906 self.context.span_handler.span_warn(i.span,
907 "the `#[simd]` attribute is deprecated, \
908 use `#[repr(simd)]` instead");
910 for attr in &i.attrs {
911 if attr.name() == "repr" {
912 for item in attr.meta_item_list().unwrap_or(&[]) {
913 if item.name() == "simd" {
914 self.gate_feature("repr_simd", i.span,
915 "SIMD types are experimental and possibly buggy");
923 ast::ItemDefaultImpl(..) => {
924 self.gate_feature("optin_builtin_traits",
926 "default trait implementations are experimental \
927 and possibly buggy");
930 ast::ItemImpl(_, polarity, _, _, _, _) => {
932 ast::ImplPolarity::Negative => {
933 self.gate_feature("optin_builtin_traits",
935 "negative trait bounds are not yet fully implemented; \
936 use marker types for now");
945 visit::walk_item(self, i);
948 fn visit_variant_data(&mut self, s: &'v ast::VariantData, _: ast::Ident,
949 _: &'v ast::Generics, _: ast::NodeId, span: Span) {
950 if s.fields().is_empty() {
952 self.gate_feature("braced_empty_structs", span,
953 "empty structs and enum variants with braces are unstable");
954 } else if s.is_tuple() {
955 self.context.span_handler.struct_span_err(span, "empty tuple structs and enum \
956 variants are not allowed, use \
957 unit structs and enum variants \
959 .span_help(span, "remove trailing `()` to make a unit \
960 struct or unit enum variant")
964 visit::walk_struct_def(self, s)
967 fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
968 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
970 Some(val) => val.starts_with("llvm."),
974 self.gate_feature("link_llvm_intrinsics", i.span,
975 "linking to LLVM intrinsics is experimental");
978 visit::walk_foreign_item(self, i)
981 fn visit_expr(&mut self, e: &ast::Expr) {
984 self.gate_feature("box_syntax",
986 "box expression syntax is experimental; \
987 you can call `Box::new` instead.");
989 ast::ExprType(..) => {
990 self.gate_feature("type_ascription", e.span,
991 "type ascription is experimental");
995 visit::walk_expr(self, e);
998 fn visit_pat(&mut self, pattern: &ast::Pat) {
1000 ast::PatVec(_, Some(_), ref last) if !last.is_empty() => {
1001 self.gate_feature("advanced_slice_patterns",
1003 "multiple-element slice matches anywhere \
1004 but at the end of a slice (e.g. \
1005 `[0, ..xs, 0]`) are experimental")
1007 ast::PatVec(..) => {
1008 self.gate_feature("slice_patterns",
1010 "slice pattern syntax is experimental");
1012 ast::PatBox(..) => {
1013 self.gate_feature("box_patterns",
1015 "box pattern syntax is experimental");
1019 visit::walk_pat(self, pattern)
1022 fn visit_fn(&mut self,
1023 fn_kind: FnKind<'v>,
1024 fn_decl: &'v ast::FnDecl,
1025 block: &'v ast::Block,
1028 // check for const fn declarations
1030 FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1031 self.gate_feature("const_fn", span, "const fn is unstable");
1034 // stability of const fn methods are covered in
1035 // visit_trait_item and visit_impl_item below; this is
1036 // because default methods don't pass through this
1042 FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
1043 self.gate_feature("intrinsics",
1045 "intrinsics are subject to change")
1047 FnKind::ItemFn(_, _, _, _, abi, _) |
1048 FnKind::Method(_, &ast::MethodSig { abi, .. }, _) if abi == Abi::RustCall => {
1049 self.gate_feature("unboxed_closures",
1051 "rust-call ABI is subject to change")
1055 visit::walk_fn(self, fn_kind, fn_decl, block, span);
1058 fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
1060 ast::ConstTraitItem(..) => {
1061 self.gate_feature("associated_consts",
1063 "associated constants are experimental")
1065 ast::MethodTraitItem(ref sig, _) => {
1066 if sig.constness == ast::Constness::Const {
1067 self.gate_feature("const_fn", ti.span, "const fn is unstable");
1070 ast::TypeTraitItem(_, Some(_)) => {
1071 self.gate_feature("associated_type_defaults", ti.span,
1072 "associated type defaults are unstable");
1076 visit::walk_trait_item(self, ti);
1079 fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
1081 ast::ImplItemKind::Const(..) => {
1082 self.gate_feature("associated_consts",
1084 "associated constants are experimental")
1086 ast::ImplItemKind::Method(ref sig, _) => {
1087 if sig.constness == ast::Constness::Const {
1088 self.gate_feature("const_fn", ii.span, "const fn is unstable");
1093 visit::walk_impl_item(self, ii);
1097 fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
1099 plugin_attributes: &[(String, AttributeType)],
1102 where F: FnOnce(&mut Context, &ast::Crate)
1104 let mut cx = Context {
1105 features: Vec::new(),
1106 span_handler: span_handler,
1108 plugin_attributes: plugin_attributes,
1111 let mut accepted_features = Vec::new();
1112 let mut unknown_features = Vec::new();
1114 for attr in &krate.attrs {
1115 if !attr.check_name("feature") {
1119 match attr.meta_item_list() {
1121 span_handler.span_err(attr.span, "malformed feature attribute, \
1122 expected #![feature(...)]");
1126 let name = match mi.node {
1127 ast::MetaWord(ref word) => (*word).clone(),
1129 span_handler.span_err(mi.span,
1130 "malformed feature, expected just \
1135 match KNOWN_FEATURES.iter()
1136 .find(|& &(n, _, _, _)| name == n) {
1137 Some(&(name, _, _, Active)) => {
1138 cx.enable_feature(name);
1140 Some(&(_, _, _, Removed)) => {
1141 span_handler.span_err(mi.span, "feature has been removed");
1143 Some(&(_, _, _, Accepted)) => {
1144 accepted_features.push(mi.span);
1147 unknown_features.push((name, mi.span));
1155 check(&mut cx, krate);
1157 // FIXME (pnkfelix): Before adding the 99th entry below, change it
1158 // to a single-pass (instead of N calls to `.has_feature`).
1161 unboxed_closures: cx.has_feature("unboxed_closures"),
1162 rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
1163 allow_quote: cx.has_feature("quote"),
1164 allow_asm: cx.has_feature("asm"),
1165 allow_log_syntax: cx.has_feature("log_syntax"),
1166 allow_concat_idents: cx.has_feature("concat_idents"),
1167 allow_trace_macros: cx.has_feature("trace_macros"),
1168 allow_internal_unstable: cx.has_feature("allow_internal_unstable"),
1169 allow_custom_derive: cx.has_feature("custom_derive"),
1170 allow_placement_in: cx.has_feature("placement_in_syntax"),
1171 allow_box: cx.has_feature("box_syntax"),
1172 allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"),
1173 simd_ffi: cx.has_feature("simd_ffi"),
1174 unmarked_api: cx.has_feature("unmarked_api"),
1175 declared_stable_lang_features: accepted_features,
1176 declared_lib_features: unknown_features,
1177 const_fn: cx.has_feature("const_fn"),
1178 const_indexing: cx.has_feature("const_indexing"),
1179 static_recursion: cx.has_feature("static_recursion"),
1180 default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"),
1181 type_macros: cx.has_feature("type_macros"),
1182 cfg_target_feature: cx.has_feature("cfg_target_feature"),
1183 cfg_target_vendor: cx.has_feature("cfg_target_vendor"),
1184 cfg_target_thread_local: cx.has_feature("cfg_target_thread_local"),
1185 augmented_assignments: cx.has_feature("augmented_assignments"),
1186 braced_empty_structs: cx.has_feature("braced_empty_structs"),
1187 staged_api: cx.has_feature("staged_api"),
1188 stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"),
1189 deprecated: cx.has_feature("deprecated"),
1193 pub fn check_crate_macros(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate)
1195 check_crate_inner(cm, span_handler, krate, &[] as &'static [_],
1196 |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate))
1199 pub fn check_crate(cm: &CodeMap, span_handler: &Handler, krate: &ast::Crate,
1200 plugin_attributes: &[(String, AttributeType)],
1201 unstable: UnstableFeatures) -> Features
1203 maybe_stage_features(span_handler, krate, unstable);
1205 check_crate_inner(cm, span_handler, krate, plugin_attributes,
1206 |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx },
1210 #[derive(Clone, Copy)]
1211 pub enum UnstableFeatures {
1212 /// Hard errors for unstable features are active, as on
1213 /// beta/stable channels.
1215 /// Allow features to me activated, as on nightly.
1217 /// Errors are bypassed for bootstrapping. This is required any time
1218 /// during the build that feature-related lints are set to warn or above
1219 /// because the build turns on warnings-as-errors and uses lots of unstable
1220 /// features. As a result, this is always required for building Rust itself.
1224 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1225 unstable: UnstableFeatures) {
1226 let allow_features = match unstable {
1227 UnstableFeatures::Allow => true,
1228 UnstableFeatures::Disallow => false,
1229 UnstableFeatures::Cheat => true
1231 if !allow_features {
1232 for attr in &krate.attrs {
1233 if attr.check_name("feature") {
1234 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1235 let ref msg = format!("#[feature] may not be used on the {} release channel",
1237 span_handler.span_err(attr.span, msg);