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
25 use self::AttributeType::*;
26 use self::AttributeGate::*;
29 use ast::{NodeId, PatKind};
32 use attr::AttrMetaMethods;
36 use visit::{self, FnKind, Visitor};
38 use parse::token::InternedString;
40 use std::ascii::AsciiExt;
44 fn f(features: &mut Features) -> &mut bool {
47 f as fn(&mut Features) -> &mut bool
51 macro_rules! declare_features {
52 ($((active, $feature: ident, $ver: expr, $issue: expr)),+) => {
53 /// Represents active features that are currently being implemented or
54 /// currently being considered for addition/removal.
55 const ACTIVE_FEATURES: &'static [(&'static str, &'static str,
56 Option<u32>, fn(&mut Features) -> &mut bool)] = &[
57 $((stringify!($feature), $ver, $issue, setter!($feature))),+
60 /// A set of features to be used by later passes.
62 /// #![feature] attrs for stable language features, for error reporting
63 pub declared_stable_lang_features: Vec<(InternedString, Span)>,
64 /// #![feature] attrs for non-language (library) features
65 pub declared_lib_features: Vec<(InternedString, Span)>,
66 $(pub $feature: bool),+
70 pub fn new() -> Features {
72 declared_stable_lang_features: Vec::new(),
73 declared_lib_features: Vec::new(),
80 ($((removed, $feature: ident, $ver: expr, $issue: expr)),+) => {
81 /// Represents features which has since been removed (it was once Active)
82 const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
83 $((stringify!($feature), $ver, $issue)),+
87 ($((accepted, $feature: ident, $ver: expr, $issue: expr)),+) => {
88 /// Those language feature has since been Accepted (it was once Active)
89 const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
90 $((stringify!($feature), $ver, $issue)),+
95 // If you change this list without updating src/doc/reference.md, @cmr will be sad
96 // Don't ever remove anything from this list; set them to 'Removed'.
97 // The version numbers here correspond to the version in which the current status
98 // was set. This is most important for knowing when a particular feature became
100 // NB: The featureck.py script parses this information directly out of the source
101 // so take care when modifying it.
104 (active, asm, "1.0.0", Some(29722)),
105 (active, concat_idents, "1.0.0", Some(29599)),
106 (active, link_args, "1.0.0", Some(29596)),
107 (active, log_syntax, "1.0.0", Some(29598)),
108 (active, non_ascii_idents, "1.0.0", Some(28979)),
109 (active, plugin_registrar, "1.0.0", Some(29597)),
110 (active, thread_local, "1.0.0", Some(29594)),
111 (active, trace_macros, "1.0.0", Some(29598)),
113 // rustc internal, for now:
114 (active, intrinsics, "1.0.0", None),
115 (active, lang_items, "1.0.0", None),
117 (active, link_llvm_intrinsics, "1.0.0", Some(29602)),
118 (active, linkage, "1.0.0", Some(29603)),
119 (active, quote, "1.0.0", Some(29601)),
120 (active, simd, "1.0.0", Some(27731)),
124 (active, rustc_diagnostic_macros, "1.0.0", None),
125 (active, advanced_slice_patterns, "1.0.0", Some(23121)),
126 (active, box_syntax, "1.0.0", Some(27779)),
127 (active, placement_in_syntax, "1.0.0", Some(27779)),
128 (active, reflect, "1.0.0", Some(27749)),
129 (active, unboxed_closures, "1.0.0", Some(29625)),
132 (active, pushpop_unsafe, "1.2.0", None),
134 (active, allocator, "1.0.0", Some(27389)),
135 (active, fundamental, "1.0.0", Some(29635)),
136 (active, linked_from, "1.3.0", Some(29629)),
137 (active, main, "1.0.0", Some(29634)),
138 (active, needs_allocator, "1.4.0", Some(27389)),
139 (active, on_unimplemented, "1.0.0", Some(29628)),
140 (active, plugin, "1.0.0", Some(29597)),
141 (active, simd_ffi, "1.0.0", Some(27731)),
142 (active, start, "1.0.0", Some(29633)),
143 (active, structural_match, "1.8.0", Some(31434)),
144 (active, panic_runtime, "1.10.0", Some(32837)),
145 (active, needs_panic_runtime, "1.10.0", Some(32837)),
147 // OIBIT specific features
148 (active, optin_builtin_traits, "1.0.0", Some(13231)),
150 // macro reexport needs more discussion and stabilization
151 (active, macro_reexport, "1.0.0", Some(29638)),
153 // Allows use of #[staged_api]
155 (active, staged_api, "1.0.0", None),
157 // Allows using items which are missing stability attributes
159 (active, unmarked_api, "1.0.0", None),
161 // Allows using #![no_core]
162 (active, no_core, "1.3.0", Some(29639)),
164 // Allows using `box` in patterns; RFC 469
165 (active, box_patterns, "1.0.0", Some(29641)),
167 // Allows using the unsafe_no_drop_flag attribute (unlikely to
168 // switch to Accepted; see RFC 320)
169 (active, unsafe_no_drop_flag, "1.0.0", None),
171 // Allows using the unsafe_destructor_blind_to_params attribute;
173 (active, dropck_parametricity, "1.3.0", Some(28498)),
175 // Allows the use of custom attributes; RFC 572
176 (active, custom_attribute, "1.0.0", Some(29642)),
178 // Allows the use of #[derive(Anything)] as sugar for
179 // #[derive_Anything].
180 (active, custom_derive, "1.0.0", Some(29644)),
182 // Allows the use of rustc_* attributes; RFC 572
183 (active, rustc_attrs, "1.0.0", Some(29642)),
185 // Allows the use of #[allow_internal_unstable]. This is an
186 // attribute on macro_rules! and can't use the attribute handling
187 // below (it has to be checked before expansion possibly makes
188 // macros disappear).
191 (active, allow_internal_unstable, "1.0.0", None),
193 // #23121. Array patterns have some hazards yet.
194 (active, slice_patterns, "1.0.0", Some(23121)),
196 // Allows the definition of associated constants in `trait` or `impl`
198 (active, associated_consts, "1.0.0", Some(29646)),
200 // Allows the definition of `const fn` functions.
201 (active, const_fn, "1.2.0", Some(24111)),
203 // Allows indexing into constant arrays.
204 (active, const_indexing, "1.4.0", Some(29947)),
206 // Allows using #[prelude_import] on glob `use` items.
209 (active, prelude_import, "1.2.0", None),
211 // Allows the definition recursive static items.
212 (active, static_recursion, "1.3.0", Some(29719)),
214 // Allows default type parameters to influence type inference.
215 (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
217 // Allows associated type defaults
218 (active, associated_type_defaults, "1.2.0", Some(29661)),
220 // Allows macros to appear in the type position.
221 (active, type_macros, "1.3.0", Some(27245)),
223 // allow `repr(simd)`, and importing the various simd intrinsics
224 (active, repr_simd, "1.4.0", Some(27731)),
226 // Allows cfg(target_feature = "...").
227 (active, cfg_target_feature, "1.4.0", Some(29717)),
229 // allow `extern "platform-intrinsic" { ... }`
230 (active, platform_intrinsics, "1.4.0", Some(27731)),
233 // rust runtime internal
234 (active, unwind_attributes, "1.4.0", None),
236 // allow the use of `#[naked]` on functions.
237 (active, naked_functions, "1.9.0", Some(32408)),
239 // allow `#[no_debug]`
240 (active, no_debug, "1.5.0", Some(29721)),
242 // allow `#[omit_gdb_pretty_printer_section]`
244 (active, omit_gdb_pretty_printer_section, "1.5.0", None),
246 // Allows cfg(target_vendor = "...").
247 (active, cfg_target_vendor, "1.5.0", Some(29718)),
249 // Allow attributes on expressions and non-item statements
250 (active, stmt_expr_attributes, "1.6.0", Some(15701)),
252 // allow using type ascription in expressions
253 (active, type_ascription, "1.6.0", Some(23416)),
255 // Allows cfg(target_thread_local)
256 (active, cfg_target_thread_local, "1.7.0", Some(29594)),
259 (active, abi_vectorcall, "1.7.0", None),
262 (active, inclusive_range_syntax, "1.7.0", Some(28237)),
265 (active, question_mark, "1.9.0", Some(31436)),
267 // impl specialization (RFC 1210)
268 (active, specialization, "1.7.0", Some(31844)),
270 // pub(restricted) visibilities (RFC 1422)
271 (active, pub_restricted, "1.9.0", Some(32409)),
273 // Allow Drop types in statics/const functions (RFC 1440)
274 (active, drop_types_in_const, "1.9.0", Some(33156)),
276 // Allows cfg(target_has_atomic = "...").
277 (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
279 // Allows `..` in tuple (struct) patterns
280 (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627)),
282 // Allows `impl Trait` in function return types.
283 (active, conservative_impl_trait, "1.12.0", Some(34511)),
285 // Allows tuple structs and variants in more contexts,
286 // Permits numeric fields in struct expressions and patterns.
287 (active, relaxed_adts, "1.12.0", Some(35626)),
290 (active, bang_type, "1.13.0", Some(35121))
294 (removed, import_shadowing, "1.0.0", None),
295 (removed, managed_boxes, "1.0.0", None),
296 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
297 (removed, negate_unsigned, "1.0.0", Some(29645)),
298 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
299 (removed, opt_out_copy, "1.0.0", None),
300 (removed, quad_precision_float, "1.0.0", None),
301 (removed, struct_inherit, "1.0.0", None),
302 (removed, test_removed_feature, "1.0.0", None),
303 (removed, visible_private_types, "1.0.0", None)
307 (accepted, associated_types, "1.0.0", None),
308 // allow overloading augmented assignment operations like `a += b`
309 (accepted, augmented_assignments, "1.8.0", Some(28235)),
310 // allow empty structs and enum variants with braces
311 (accepted, braced_empty_structs, "1.8.0", Some(29720)),
312 (accepted, default_type_params, "1.0.0", None),
313 (accepted, globs, "1.0.0", None),
314 (accepted, if_let, "1.0.0", None),
315 // A temporary feature gate used to enable parser extensions needed
316 // to bootstrap fix for #5723.
317 (accepted, issue_5723_bootstrap, "1.0.0", None),
318 (accepted, macro_rules, "1.0.0", None),
319 // Allows using #![no_std]
320 (accepted, no_std, "1.0.0", None),
321 (accepted, slicing_syntax, "1.0.0", None),
322 (accepted, struct_variant, "1.0.0", None),
323 // These are used to test this portion of the compiler, they don't actually
325 (accepted, test_accepted_feature, "1.0.0", None),
326 (accepted, tuple_indexing, "1.0.0", None),
327 (accepted, while_let, "1.0.0", None),
328 // Allows `#[deprecated]` attribute
329 (accepted, deprecated, "1.9.0", Some(29935))
331 // (changing above list without updating src/doc/reference.md makes @cmr sad)
333 #[derive(PartialEq, Copy, Clone, Debug)]
334 pub enum AttributeType {
335 /// Normal, builtin attribute that is consumed
336 /// by the compiler before the unused_attribute check
339 /// Builtin attribute that may not be consumed by the compiler
340 /// before the unused_attribute check. These attributes
341 /// will be ignored by the unused_attribute lint
344 /// Builtin attribute that is only allowed at the crate level
348 pub enum AttributeGate {
349 /// Is gated by a given feature gate, reason
350 /// and function to check if enabled
351 Gated(&'static str, &'static str, fn(&Features) -> bool),
353 /// Ungated attribute, can be used on all release channels
358 impl ::std::fmt::Debug for AttributeGate {
359 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
361 Gated(ref name, ref expl, _) => write!(fmt, "Gated({}, {})", name, expl),
362 Ungated => write!(fmt, "Ungated")
367 macro_rules! cfg_fn {
368 ($field: ident) => {{
369 fn f(features: &Features) -> bool {
372 f as fn(&Features) -> bool
376 // Attributes that have a special meaning to rustc or rustdoc
377 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
380 ("warn", Normal, Ungated),
381 ("allow", Normal, Ungated),
382 ("forbid", Normal, Ungated),
383 ("deny", Normal, Ungated),
385 ("macro_reexport", Normal, Ungated),
386 ("macro_use", Normal, Ungated),
387 ("macro_export", Normal, Ungated),
388 ("plugin_registrar", Normal, Ungated),
390 ("cfg", Normal, Ungated),
391 ("cfg_attr", Normal, Ungated),
392 ("main", Normal, Ungated),
393 ("start", Normal, Ungated),
394 ("test", Normal, Ungated),
395 ("bench", Normal, Ungated),
396 ("simd", Normal, Ungated),
397 ("repr", Normal, Ungated),
398 ("path", Normal, Ungated),
399 ("abi", Normal, Ungated),
400 ("automatically_derived", Normal, Ungated),
401 ("no_mangle", Normal, Ungated),
402 ("no_link", Normal, Ungated),
403 ("derive", Normal, Ungated),
404 ("should_panic", Normal, Ungated),
405 ("ignore", Normal, Ungated),
406 ("no_implicit_prelude", Normal, Ungated),
407 ("reexport_test_harness_main", Normal, Ungated),
408 ("link_args", Normal, Ungated),
409 ("macro_escape", Normal, Ungated),
412 ("structural_match", Whitelisted, Gated("structural_match",
413 "the semantics of constant patterns is \
415 cfg_fn!(structural_match))),
417 // Not used any more, but we can't feature gate it
418 ("no_stack_check", Normal, Ungated),
420 ("plugin", CrateLevel, Gated("plugin",
421 "compiler plugins are experimental \
425 ("no_std", CrateLevel, Ungated),
426 ("no_core", CrateLevel, Gated("no_core",
427 "no_core is experimental",
429 ("lang", Normal, Gated("lang_items",
430 "language items are subject to change",
431 cfg_fn!(lang_items))),
432 ("linkage", Whitelisted, Gated("linkage",
433 "the `linkage` attribute is experimental \
434 and not portable across platforms",
436 ("thread_local", Whitelisted, Gated("thread_local",
437 "`#[thread_local]` is an experimental feature, and does \
438 not currently handle destructors. There is no \
439 corresponding `#[task_local]` mapping to the task \
441 cfg_fn!(thread_local))),
443 ("rustc_on_unimplemented", Normal, Gated("on_unimplemented",
444 "the `#[rustc_on_unimplemented]` attribute \
445 is an experimental feature",
446 cfg_fn!(on_unimplemented))),
447 ("allocator", Whitelisted, Gated("allocator",
448 "the `#[allocator]` attribute is an experimental feature",
449 cfg_fn!(allocator))),
450 ("needs_allocator", Normal, Gated("needs_allocator",
451 "the `#[needs_allocator]` \
452 attribute is an experimental \
454 cfg_fn!(needs_allocator))),
455 ("panic_runtime", Whitelisted, Gated("panic_runtime",
456 "the `#[panic_runtime]` attribute is \
457 an experimental feature",
458 cfg_fn!(panic_runtime))),
459 ("needs_panic_runtime", Whitelisted, Gated("needs_panic_runtime",
460 "the `#[needs_panic_runtime]` \
461 attribute is an experimental \
463 cfg_fn!(needs_panic_runtime))),
464 ("rustc_variance", Normal, Gated("rustc_attrs",
465 "the `#[rustc_variance]` attribute \
466 is just used for rustc unit tests \
467 and will never be stable",
468 cfg_fn!(rustc_attrs))),
469 ("rustc_error", Whitelisted, Gated("rustc_attrs",
470 "the `#[rustc_error]` attribute \
471 is just used for rustc unit tests \
472 and will never be stable",
473 cfg_fn!(rustc_attrs))),
474 ("rustc_if_this_changed", Whitelisted, Gated("rustc_attrs",
475 "the `#[rustc_if_this_changed]` attribute \
476 is just used for rustc unit tests \
477 and will never be stable",
478 cfg_fn!(rustc_attrs))),
479 ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs",
480 "the `#[rustc_if_this_changed]` attribute \
481 is just used for rustc unit tests \
482 and will never be stable",
483 cfg_fn!(rustc_attrs))),
484 ("rustc_dirty", Whitelisted, Gated("rustc_attrs",
485 "the `#[rustc_dirty]` attribute \
486 is just used for rustc unit tests \
487 and will never be stable",
488 cfg_fn!(rustc_attrs))),
489 ("rustc_clean", Whitelisted, Gated("rustc_attrs",
490 "the `#[rustc_clean]` attribute \
491 is just used for rustc unit tests \
492 and will never be stable",
493 cfg_fn!(rustc_attrs))),
494 ("rustc_partition_reused", Whitelisted, Gated("rustc_attrs",
496 is just used for rustc unit tests \
497 and will never be stable",
498 cfg_fn!(rustc_attrs))),
499 ("rustc_partition_translated", Whitelisted, Gated("rustc_attrs",
501 is just used for rustc unit tests \
502 and will never be stable",
503 cfg_fn!(rustc_attrs))),
504 ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs",
505 "internal rustc attributes will never be stable",
506 cfg_fn!(rustc_attrs))),
507 ("rustc_item_path", Whitelisted, Gated("rustc_attrs",
508 "internal rustc attributes will never be stable",
509 cfg_fn!(rustc_attrs))),
510 ("rustc_move_fragments", Normal, Gated("rustc_attrs",
511 "the `#[rustc_move_fragments]` attribute \
512 is just used for rustc unit tests \
513 and will never be stable",
514 cfg_fn!(rustc_attrs))),
515 ("rustc_mir", Whitelisted, Gated("rustc_attrs",
516 "the `#[rustc_mir]` attribute \
517 is just used for rustc unit tests \
518 and will never be stable",
519 cfg_fn!(rustc_attrs))),
520 ("rustc_no_mir", Whitelisted, Gated("rustc_attrs",
521 "the `#[rustc_no_mir]` attribute \
522 is just used to make tests pass \
523 and will never be stable",
524 cfg_fn!(rustc_attrs))),
525 ("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs",
526 "the `#[rustc_inherit_overflow_checks]` \
527 attribute is just used to control \
528 overflow checking behavior of several \
529 libcore functions that are inlined \
530 across crates and will never be stable",
531 cfg_fn!(rustc_attrs))),
533 ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
534 EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
535 cfg_fn!(allow_internal_unstable))),
537 ("fundamental", Whitelisted, Gated("fundamental",
538 "the `#[fundamental]` attribute \
539 is an experimental feature",
540 cfg_fn!(fundamental))),
542 ("linked_from", Normal, Gated("linked_from",
543 "the `#[linked_from]` attribute \
544 is an experimental feature",
545 cfg_fn!(linked_from))),
547 // FIXME: #14408 whitelist docs since rustdoc looks at them
548 ("doc", Whitelisted, Ungated),
550 // FIXME: #14406 these are processed in trans, which happens after the
552 ("cold", Whitelisted, Ungated),
553 ("naked", Whitelisted, Gated("naked_functions",
554 "the `#[naked]` attribute \
555 is an experimental feature",
556 cfg_fn!(naked_functions))),
557 ("export_name", Whitelisted, Ungated),
558 ("inline", Whitelisted, Ungated),
559 ("link", Whitelisted, Ungated),
560 ("link_name", Whitelisted, Ungated),
561 ("link_section", Whitelisted, Ungated),
562 ("no_builtins", Whitelisted, Ungated),
563 ("no_mangle", Whitelisted, Ungated),
564 ("no_debug", Whitelisted, Gated("no_debug",
565 "the `#[no_debug]` attribute \
566 is an experimental feature",
568 ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
569 "the `#[omit_gdb_pretty_printer_section]` \
570 attribute is just used for the Rust test \
572 cfg_fn!(omit_gdb_pretty_printer_section))),
573 ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
574 "unsafe_no_drop_flag has unstable semantics \
575 and may be removed in the future",
576 cfg_fn!(unsafe_no_drop_flag))),
577 ("unsafe_destructor_blind_to_params",
579 Gated("dropck_parametricity",
580 "unsafe_destructor_blind_to_params has unstable semantics \
581 and may be removed in the future",
582 cfg_fn!(dropck_parametricity))),
583 ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental",
584 cfg_fn!(unwind_attributes))),
587 ("prelude_import", Whitelisted, Gated("prelude_import",
588 "`#[prelude_import]` is for use by rustc only",
589 cfg_fn!(prelude_import))),
591 // FIXME: #14407 these are only looked at on-demand so we can't
592 // guarantee they'll have already been checked
593 ("rustc_deprecated", Whitelisted, Ungated),
594 ("must_use", Whitelisted, Ungated),
595 ("stable", Whitelisted, Ungated),
596 ("unstable", Whitelisted, Ungated),
597 ("deprecated", Normal, Ungated),
599 ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
600 "unboxed_closures are still evolving",
601 cfg_fn!(unboxed_closures))),
602 ("rustc_reflect_like", Whitelisted, Gated("reflect",
603 "defining reflective traits is still evolving",
606 // Crate level attributes
607 ("crate_name", CrateLevel, Ungated),
608 ("crate_type", CrateLevel, Ungated),
609 ("crate_id", CrateLevel, Ungated),
610 ("feature", CrateLevel, Ungated),
611 ("no_start", CrateLevel, Ungated),
612 ("no_main", CrateLevel, Ungated),
613 ("no_builtins", CrateLevel, Ungated),
614 ("recursion_limit", CrateLevel, Ungated),
617 // cfg(...)'s that are feature gated
618 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
619 // (name in cfg, feature, function to check if the feature is enabled)
620 ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
621 ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
622 ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
623 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
626 #[derive(Debug, Eq, PartialEq)]
627 pub struct GatedCfg {
633 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
634 let name = cfg.name();
636 .position(|info| info.0 == name)
645 pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
646 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
647 if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
648 let diagnostic = &sess.span_diagnostic;
649 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
650 emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
656 features: &'a Features,
657 span_handler: &'a Handler,
659 plugin_attributes: &'a [(String, AttributeType)],
662 macro_rules! gate_feature_fn {
663 ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
664 let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
665 let has_feature: bool = has_feature(&$cx.features);
666 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
667 if !has_feature && !cx.cm.span_allows_unstable(span) {
668 emit_feature_err(cx.span_handler, name, span, GateIssue::Language, explain);
673 macro_rules! gate_feature {
674 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
675 gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
679 impl<'a> Context<'a> {
680 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
681 debug!("check_attribute(attr = {:?})", attr);
682 let name = &*attr.name();
683 for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES {
685 if let &Gated(ref name, ref desc, ref has_feature) = gateage {
686 gate_feature_fn!(self, has_feature, attr.span, name, desc);
688 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
692 for &(ref n, ref ty) in self.plugin_attributes {
694 // Plugins can't gate attributes, so we don't check for it
695 // unlike the code above; we only use this loop to
696 // short-circuit to avoid the checks below
697 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
701 if name.starts_with("rustc_") {
702 gate_feature!(self, rustc_attrs, attr.span,
703 "unless otherwise specified, attributes \
704 with the prefix `rustc_` \
705 are reserved for internal compiler diagnostics");
706 } else if name.starts_with("derive_") {
707 gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
709 // Only run the custom attribute lint during regular
710 // feature gate checking. Macro gating runs
711 // before the plugin attributes are registered
712 // so we skip this then
714 gate_feature!(self, custom_attribute, attr.span,
715 &format!("The attribute `{}` is currently \
716 unknown to the compiler and \
718 added to it in the future",
725 pub fn check_attribute(attr: &ast::Attribute, handler: &Handler,
726 cm: &CodeMap, features: &Features) {
728 features: features, span_handler: handler,
729 cm: cm, plugin_attributes: &[]
731 cx.check_attribute(attr, true);
734 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
735 ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
738 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
739 if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
741 // FIXME (#28244): enforce that active features have issue numbers
742 // assert!(issue.is_some())
745 // search in Accepted or Removed features
746 ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES.iter())
747 .find(|t| t.0 == feature)
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.help(&format!("add #![feature({})] to the \
776 crate attributes to enable",
781 const EXPLAIN_BOX_SYNTAX: &'static str =
782 "box expression syntax is experimental; you can call `Box::new` instead.";
784 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
785 "attributes on non-item statements and expressions are experimental.";
787 pub const EXPLAIN_ASM: &'static str =
788 "inline assembly is not stable enough for use and is subject to change";
790 pub const EXPLAIN_LOG_SYNTAX: &'static str =
791 "`log_syntax!` is not stable enough for use and is subject to change";
793 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
794 "`concat_idents` is not stable enough for use and is subject to change";
796 pub const EXPLAIN_TRACE_MACROS: &'static str =
797 "`trace_macros` is not stable enough for use and is subject to change";
798 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
799 "allow_internal_unstable side-steps feature gating and stability checks";
801 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
802 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
804 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
805 "attributes of the form `#[derive_*]` are reserved for the compiler";
807 pub const EXPLAIN_PLACEMENT_IN: &'static str =
808 "placement-in expression syntax is experimental and subject to change.";
810 struct PostExpansionVisitor<'a> {
811 context: &'a Context<'a>,
814 macro_rules! gate_feature_post {
815 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
816 let (cx, span) = ($cx, $span);
817 if !cx.context.cm.span_allows_unstable(span) {
818 gate_feature!(cx.context, $feature, span, $explain)
823 impl<'a> PostExpansionVisitor<'a> {
824 fn check_abi(&self, abi: Abi, span: Span) {
826 Abi::RustIntrinsic =>
827 gate_feature_post!(&self, intrinsics, span,
828 "intrinsics are subject to change"),
829 Abi::PlatformIntrinsic => {
830 gate_feature_post!(&self, platform_intrinsics, span,
831 "platform intrinsics are experimental and possibly buggy")
834 gate_feature_post!(&self, abi_vectorcall, span,
835 "vectorcall is experimental and subject to change")
838 gate_feature_post!(&self, unboxed_closures, span,
839 "rust-call ABI is subject to change");
846 impl<'a> Visitor for PostExpansionVisitor<'a> {
847 fn visit_attribute(&mut self, attr: &ast::Attribute) {
848 if !self.context.cm.span_allows_unstable(attr.span) {
849 self.context.check_attribute(attr, false);
853 fn visit_name(&mut self, sp: Span, name: ast::Name) {
854 if !name.as_str().is_ascii() {
855 gate_feature_post!(&self, non_ascii_idents, sp,
856 "non-ascii idents are not fully supported.");
860 fn visit_item(&mut self, i: &ast::Item) {
862 ast::ItemKind::ExternCrate(_) => {
863 if attr::contains_name(&i.attrs[..], "macro_reexport") {
864 gate_feature_post!(&self, macro_reexport, i.span,
865 "macros reexports are experimental \
866 and possibly buggy");
870 ast::ItemKind::ForeignMod(ref foreign_module) => {
871 if attr::contains_name(&i.attrs[..], "link_args") {
872 gate_feature_post!(&self, link_args, i.span,
873 "the `link_args` attribute is not portable \
874 across platforms, it is recommended to \
875 use `#[link(name = \"foo\")]` instead")
877 self.check_abi(foreign_module.abi, i.span);
880 ast::ItemKind::Fn(..) => {
881 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
882 gate_feature_post!(&self, plugin_registrar, i.span,
883 "compiler plugins are experimental and possibly buggy");
885 if attr::contains_name(&i.attrs[..], "start") {
886 gate_feature_post!(&self, start, i.span,
887 "a #[start] function is an experimental \
888 feature whose signature may change \
891 if attr::contains_name(&i.attrs[..], "main") {
892 gate_feature_post!(&self, main, i.span,
893 "declaration of a nonstandard #[main] \
894 function may change over time, for now \
895 a top-level `fn main()` is required");
899 ast::ItemKind::Struct(..) => {
900 if attr::contains_name(&i.attrs[..], "simd") {
901 gate_feature_post!(&self, simd, i.span,
902 "SIMD types are experimental and possibly buggy");
903 self.context.span_handler.span_warn(i.span,
904 "the `#[simd]` attribute is deprecated, \
905 use `#[repr(simd)]` instead");
907 for attr in &i.attrs {
908 if attr.name() == "repr" {
909 for item in attr.meta_item_list().unwrap_or(&[]) {
910 if item.name() == "simd" {
911 gate_feature_post!(&self, repr_simd, i.span,
912 "SIMD types are experimental \
913 and possibly buggy");
921 ast::ItemKind::DefaultImpl(..) => {
922 gate_feature_post!(&self, optin_builtin_traits,
924 "default trait implementations are experimental \
925 and possibly buggy");
928 ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
930 ast::ImplPolarity::Negative => {
931 gate_feature_post!(&self, 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_foreign_item(&mut self, i: &ast::ForeignItem) {
947 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
949 Some(val) => val.starts_with("llvm."),
953 gate_feature_post!(&self, link_llvm_intrinsics, i.span,
954 "linking to LLVM intrinsics is experimental");
957 visit::walk_foreign_item(self, i)
960 fn visit_ty(&mut self, ty: &ast::Ty) {
962 ast::TyKind::BareFn(ref bare_fn_ty) => {
963 self.check_abi(bare_fn_ty.abi, ty.span);
965 ast::TyKind::ImplTrait(..) => {
966 gate_feature_post!(&self, conservative_impl_trait, ty.span,
967 "`impl Trait` is experimental");
969 ast::TyKind::Empty => {
970 gate_feature_post!(&self, bang_type, ty.span,
971 "The `!` type is experimental");
975 visit::walk_ty(self, ty)
978 fn visit_fn_ret_ty(&mut self, ret_ty: &ast::FunctionRetTy) {
979 if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
980 match output_ty.node {
981 ast::TyKind::Empty => return,
984 visit::walk_ty(self, output_ty)
988 fn visit_expr(&mut self, e: &ast::Expr) {
990 ast::ExprKind::Box(_) => {
991 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
993 ast::ExprKind::Type(..) => {
994 gate_feature_post!(&self, type_ascription, e.span,
995 "type ascription is experimental");
997 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
998 gate_feature_post!(&self, inclusive_range_syntax,
1000 "inclusive range syntax is experimental");
1002 ast::ExprKind::Try(..) => {
1003 gate_feature_post!(&self, question_mark, e.span, "the `?` operator is not stable");
1005 ast::ExprKind::InPlace(..) => {
1006 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1010 visit::walk_expr(self, e);
1013 fn visit_pat(&mut self, pattern: &ast::Pat) {
1014 match pattern.node {
1015 PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => {
1016 gate_feature_post!(&self, advanced_slice_patterns,
1018 "multiple-element slice matches anywhere \
1019 but at the end of a slice (e.g. \
1020 `[0, ..xs, 0]`) are experimental")
1022 PatKind::Vec(..) => {
1023 gate_feature_post!(&self, slice_patterns,
1025 "slice pattern syntax is experimental");
1027 PatKind::Box(..) => {
1028 gate_feature_post!(&self, box_patterns,
1030 "box pattern syntax is experimental");
1032 PatKind::Tuple(_, ddpos)
1033 if ddpos.is_some() => {
1034 gate_feature_post!(&self, dotdot_in_tuple_patterns,
1036 "`..` in tuple patterns is experimental");
1038 PatKind::TupleStruct(_, ref fields, ddpos)
1039 if ddpos.is_some() && !fields.is_empty() => {
1040 gate_feature_post!(&self, dotdot_in_tuple_patterns,
1042 "`..` in tuple struct patterns is experimental");
1044 PatKind::TupleStruct(_, ref fields, ddpos)
1045 if ddpos.is_none() && fields.is_empty() => {
1046 gate_feature_post!(&self, relaxed_adts, pattern.span,
1047 "empty tuple structs patterns are unstable");
1051 visit::walk_pat(self, pattern)
1054 fn visit_fn(&mut self,
1056 fn_decl: &ast::FnDecl,
1060 // check for const fn declarations
1062 FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1063 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1066 // stability of const fn methods are covered in
1067 // visit_trait_item and visit_impl_item below; this is
1068 // because default methods don't pass through this
1074 FnKind::ItemFn(_, _, _, _, abi, _) |
1075 FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => {
1076 self.check_abi(abi, span);
1080 visit::walk_fn(self, fn_kind, fn_decl, block, span);
1083 fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
1085 ast::TraitItemKind::Const(..) => {
1086 gate_feature_post!(&self, associated_consts,
1088 "associated constants are experimental")
1090 ast::TraitItemKind::Method(ref sig, ref block) => {
1091 if block.is_none() {
1092 self.check_abi(sig.abi, ti.span);
1094 if sig.constness == ast::Constness::Const {
1095 gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1098 ast::TraitItemKind::Type(_, Some(_)) => {
1099 gate_feature_post!(&self, associated_type_defaults, ti.span,
1100 "associated type defaults are unstable");
1104 visit::walk_trait_item(self, ti);
1107 fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
1108 if ii.defaultness == ast::Defaultness::Default {
1109 gate_feature_post!(&self, specialization,
1111 "specialization is unstable");
1115 ast::ImplItemKind::Const(..) => {
1116 gate_feature_post!(&self, associated_consts,
1118 "associated constants are experimental")
1120 ast::ImplItemKind::Method(ref sig, _) => {
1121 if sig.constness == ast::Constness::Const {
1122 gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1127 visit::walk_impl_item(self, ii);
1130 fn visit_variant_data(&mut self, vdata: &ast::VariantData, _: ast::Ident,
1131 _: &ast::Generics, _: NodeId, span: Span) {
1132 if vdata.fields().is_empty() {
1133 if vdata.is_tuple() {
1134 gate_feature_post!(&self, relaxed_adts, span,
1135 "empty tuple structs and enum variants are unstable, \
1136 use unit structs and enum variants instead");
1140 visit::walk_struct_def(self, vdata)
1143 fn visit_vis(&mut self, vis: &ast::Visibility) {
1144 let span = match *vis {
1145 ast::Visibility::Crate(span) => span,
1146 ast::Visibility::Restricted { ref path, .. } => path.span,
1149 gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental");
1151 visit::walk_vis(self, vis)
1155 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1156 let mut features = Features::new();
1158 for attr in krate_attrs {
1159 if !attr.check_name("feature") {
1163 match attr.meta_item_list() {
1165 span_err!(span_handler, attr.span, E0555,
1166 "malformed feature attribute, expected #![feature(...)]");
1170 let name = if mi.is_word() {
1173 span_err!(span_handler, mi.span, E0556,
1174 "malformed feature, expected just one word");
1177 if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1178 .find(|& &(n, _, _, _)| name == n) {
1179 *(setter(&mut features)) = true;
1181 else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1182 .find(|& &(n, _, _)| name == n) {
1183 span_err!(span_handler, mi.span, E0557, "feature has been removed");
1185 else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1186 .find(|& &(n, _, _)| name == n) {
1187 features.declared_stable_lang_features.push((name, mi.span));
1189 features.declared_lib_features.push((name, mi.span));
1199 pub fn check_crate(krate: &ast::Crate,
1201 features: &Features,
1202 plugin_attributes: &[(String, AttributeType)],
1203 unstable: UnstableFeatures) {
1204 maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1207 span_handler: &sess.span_diagnostic,
1209 plugin_attributes: plugin_attributes,
1211 visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1214 #[derive(Clone, Copy)]
1215 pub enum UnstableFeatures {
1216 /// Hard errors for unstable features are active, as on
1217 /// beta/stable channels.
1219 /// Allow features to me activated, as on nightly.
1221 /// Errors are bypassed for bootstrapping. This is required any time
1222 /// during the build that feature-related lints are set to warn or above
1223 /// because the build turns on warnings-as-errors and uses lots of unstable
1224 /// features. As a result, this is always required for building Rust itself.
1228 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1229 unstable: UnstableFeatures) {
1230 let allow_features = match unstable {
1231 UnstableFeatures::Allow => true,
1232 UnstableFeatures::Disallow => false,
1233 UnstableFeatures::Cheat => true
1235 if !allow_features {
1236 for attr in &krate.attrs {
1237 if attr.check_name("feature") {
1238 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1239 span_err!(span_handler, attr.span, E0554,
1240 "#[feature] may not be used on the {} release channel",