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))
291 (removed, import_shadowing, "1.0.0", None),
292 (removed, managed_boxes, "1.0.0", None),
293 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
294 (removed, negate_unsigned, "1.0.0", Some(29645)),
295 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
296 (removed, opt_out_copy, "1.0.0", None),
297 (removed, quad_precision_float, "1.0.0", None),
298 (removed, struct_inherit, "1.0.0", None),
299 (removed, test_removed_feature, "1.0.0", None),
300 (removed, visible_private_types, "1.0.0", None)
304 (accepted, associated_types, "1.0.0", None),
305 // allow overloading augmented assignment operations like `a += b`
306 (accepted, augmented_assignments, "1.8.0", Some(28235)),
307 // allow empty structs and enum variants with braces
308 (accepted, braced_empty_structs, "1.8.0", Some(29720)),
309 (accepted, default_type_params, "1.0.0", None),
310 (accepted, globs, "1.0.0", None),
311 (accepted, if_let, "1.0.0", None),
312 // A temporary feature gate used to enable parser extensions needed
313 // to bootstrap fix for #5723.
314 (accepted, issue_5723_bootstrap, "1.0.0", None),
315 (accepted, macro_rules, "1.0.0", None),
316 // Allows using #![no_std]
317 (accepted, no_std, "1.0.0", None),
318 (accepted, slicing_syntax, "1.0.0", None),
319 (accepted, struct_variant, "1.0.0", None),
320 // These are used to test this portion of the compiler, they don't actually
322 (accepted, test_accepted_feature, "1.0.0", None),
323 (accepted, tuple_indexing, "1.0.0", None),
324 (accepted, while_let, "1.0.0", None),
325 // Allows `#[deprecated]` attribute
326 (accepted, deprecated, "1.9.0", Some(29935))
328 // (changing above list without updating src/doc/reference.md makes @cmr sad)
330 #[derive(PartialEq, Copy, Clone, Debug)]
331 pub enum AttributeType {
332 /// Normal, builtin attribute that is consumed
333 /// by the compiler before the unused_attribute check
336 /// Builtin attribute that may not be consumed by the compiler
337 /// before the unused_attribute check. These attributes
338 /// will be ignored by the unused_attribute lint
341 /// Builtin attribute that is only allowed at the crate level
345 pub enum AttributeGate {
346 /// Is gated by a given feature gate, reason
347 /// and function to check if enabled
348 Gated(&'static str, &'static str, fn(&Features) -> bool),
350 /// Ungated attribute, can be used on all release channels
355 impl ::std::fmt::Debug for AttributeGate {
356 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
358 Gated(ref name, ref expl, _) => write!(fmt, "Gated({}, {})", name, expl),
359 Ungated => write!(fmt, "Ungated")
364 macro_rules! cfg_fn {
365 ($field: ident) => {{
366 fn f(features: &Features) -> bool {
369 f as fn(&Features) -> bool
373 // Attributes that have a special meaning to rustc or rustdoc
374 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
377 ("warn", Normal, Ungated),
378 ("allow", Normal, Ungated),
379 ("forbid", Normal, Ungated),
380 ("deny", Normal, Ungated),
382 ("macro_reexport", Normal, Ungated),
383 ("macro_use", Normal, Ungated),
384 ("macro_export", Normal, Ungated),
385 ("plugin_registrar", Normal, Ungated),
387 ("cfg", Normal, Ungated),
388 ("cfg_attr", Normal, Ungated),
389 ("main", Normal, Ungated),
390 ("start", Normal, Ungated),
391 ("test", Normal, Ungated),
392 ("bench", Normal, Ungated),
393 ("simd", Normal, Ungated),
394 ("repr", Normal, Ungated),
395 ("path", Normal, Ungated),
396 ("abi", Normal, Ungated),
397 ("automatically_derived", Normal, Ungated),
398 ("no_mangle", Normal, Ungated),
399 ("no_link", Normal, Ungated),
400 ("derive", Normal, Ungated),
401 ("should_panic", Normal, Ungated),
402 ("ignore", Normal, Ungated),
403 ("no_implicit_prelude", Normal, Ungated),
404 ("reexport_test_harness_main", Normal, Ungated),
405 ("link_args", Normal, Ungated),
406 ("macro_escape", Normal, Ungated),
409 ("structural_match", Whitelisted, Gated("structural_match",
410 "the semantics of constant patterns is \
412 cfg_fn!(structural_match))),
414 // Not used any more, but we can't feature gate it
415 ("no_stack_check", Normal, Ungated),
417 ("plugin", CrateLevel, Gated("plugin",
418 "compiler plugins are experimental \
422 ("no_std", CrateLevel, Ungated),
423 ("no_core", CrateLevel, Gated("no_core",
424 "no_core is experimental",
426 ("lang", Normal, Gated("lang_items",
427 "language items are subject to change",
428 cfg_fn!(lang_items))),
429 ("linkage", Whitelisted, Gated("linkage",
430 "the `linkage` attribute is experimental \
431 and not portable across platforms",
433 ("thread_local", Whitelisted, Gated("thread_local",
434 "`#[thread_local]` is an experimental feature, and does \
435 not currently handle destructors. There is no \
436 corresponding `#[task_local]` mapping to the task \
438 cfg_fn!(thread_local))),
440 ("rustc_on_unimplemented", Normal, Gated("on_unimplemented",
441 "the `#[rustc_on_unimplemented]` attribute \
442 is an experimental feature",
443 cfg_fn!(on_unimplemented))),
444 ("allocator", Whitelisted, Gated("allocator",
445 "the `#[allocator]` attribute is an experimental feature",
446 cfg_fn!(allocator))),
447 ("needs_allocator", Normal, Gated("needs_allocator",
448 "the `#[needs_allocator]` \
449 attribute is an experimental \
451 cfg_fn!(needs_allocator))),
452 ("panic_runtime", Whitelisted, Gated("panic_runtime",
453 "the `#[panic_runtime]` attribute is \
454 an experimental feature",
455 cfg_fn!(panic_runtime))),
456 ("needs_panic_runtime", Whitelisted, Gated("needs_panic_runtime",
457 "the `#[needs_panic_runtime]` \
458 attribute is an experimental \
460 cfg_fn!(needs_panic_runtime))),
461 ("rustc_variance", Normal, Gated("rustc_attrs",
462 "the `#[rustc_variance]` attribute \
463 is just used for rustc unit tests \
464 and will never be stable",
465 cfg_fn!(rustc_attrs))),
466 ("rustc_error", Whitelisted, Gated("rustc_attrs",
467 "the `#[rustc_error]` attribute \
468 is just used for rustc unit tests \
469 and will never be stable",
470 cfg_fn!(rustc_attrs))),
471 ("rustc_if_this_changed", Whitelisted, Gated("rustc_attrs",
472 "the `#[rustc_if_this_changed]` attribute \
473 is just used for rustc unit tests \
474 and will never be stable",
475 cfg_fn!(rustc_attrs))),
476 ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs",
477 "the `#[rustc_if_this_changed]` attribute \
478 is just used for rustc unit tests \
479 and will never be stable",
480 cfg_fn!(rustc_attrs))),
481 ("rustc_dirty", Whitelisted, Gated("rustc_attrs",
482 "the `#[rustc_dirty]` attribute \
483 is just used for rustc unit tests \
484 and will never be stable",
485 cfg_fn!(rustc_attrs))),
486 ("rustc_clean", Whitelisted, Gated("rustc_attrs",
487 "the `#[rustc_clean]` attribute \
488 is just used for rustc unit tests \
489 and will never be stable",
490 cfg_fn!(rustc_attrs))),
491 ("rustc_partition_reused", Whitelisted, Gated("rustc_attrs",
493 is just used for rustc unit tests \
494 and will never be stable",
495 cfg_fn!(rustc_attrs))),
496 ("rustc_partition_translated", Whitelisted, Gated("rustc_attrs",
498 is just used for rustc unit tests \
499 and will never be stable",
500 cfg_fn!(rustc_attrs))),
501 ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs",
502 "internal rustc attributes will never be stable",
503 cfg_fn!(rustc_attrs))),
504 ("rustc_item_path", Whitelisted, Gated("rustc_attrs",
505 "internal rustc attributes will never be stable",
506 cfg_fn!(rustc_attrs))),
507 ("rustc_move_fragments", Normal, Gated("rustc_attrs",
508 "the `#[rustc_move_fragments]` attribute \
509 is just used for rustc unit tests \
510 and will never be stable",
511 cfg_fn!(rustc_attrs))),
512 ("rustc_mir", Whitelisted, Gated("rustc_attrs",
513 "the `#[rustc_mir]` attribute \
514 is just used for rustc unit tests \
515 and will never be stable",
516 cfg_fn!(rustc_attrs))),
517 ("rustc_no_mir", Whitelisted, Gated("rustc_attrs",
518 "the `#[rustc_no_mir]` attribute \
519 is just used to make tests pass \
520 and will never be stable",
521 cfg_fn!(rustc_attrs))),
522 ("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs",
523 "the `#[rustc_inherit_overflow_checks]` \
524 attribute is just used to control \
525 overflow checking behavior of several \
526 libcore functions that are inlined \
527 across crates and will never be stable",
528 cfg_fn!(rustc_attrs))),
530 ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
531 EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
532 cfg_fn!(allow_internal_unstable))),
534 ("fundamental", Whitelisted, Gated("fundamental",
535 "the `#[fundamental]` attribute \
536 is an experimental feature",
537 cfg_fn!(fundamental))),
539 ("linked_from", Normal, Gated("linked_from",
540 "the `#[linked_from]` attribute \
541 is an experimental feature",
542 cfg_fn!(linked_from))),
544 // FIXME: #14408 whitelist docs since rustdoc looks at them
545 ("doc", Whitelisted, Ungated),
547 // FIXME: #14406 these are processed in trans, which happens after the
549 ("cold", Whitelisted, Ungated),
550 ("naked", Whitelisted, Gated("naked_functions",
551 "the `#[naked]` attribute \
552 is an experimental feature",
553 cfg_fn!(naked_functions))),
554 ("export_name", Whitelisted, Ungated),
555 ("inline", Whitelisted, Ungated),
556 ("link", Whitelisted, Ungated),
557 ("link_name", Whitelisted, Ungated),
558 ("link_section", Whitelisted, Ungated),
559 ("no_builtins", Whitelisted, Ungated),
560 ("no_mangle", Whitelisted, Ungated),
561 ("no_debug", Whitelisted, Gated("no_debug",
562 "the `#[no_debug]` attribute \
563 is an experimental feature",
565 ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
566 "the `#[omit_gdb_pretty_printer_section]` \
567 attribute is just used for the Rust test \
569 cfg_fn!(omit_gdb_pretty_printer_section))),
570 ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
571 "unsafe_no_drop_flag has unstable semantics \
572 and may be removed in the future",
573 cfg_fn!(unsafe_no_drop_flag))),
574 ("unsafe_destructor_blind_to_params",
576 Gated("dropck_parametricity",
577 "unsafe_destructor_blind_to_params has unstable semantics \
578 and may be removed in the future",
579 cfg_fn!(dropck_parametricity))),
580 ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental",
581 cfg_fn!(unwind_attributes))),
584 ("prelude_import", Whitelisted, Gated("prelude_import",
585 "`#[prelude_import]` is for use by rustc only",
586 cfg_fn!(prelude_import))),
588 // FIXME: #14407 these are only looked at on-demand so we can't
589 // guarantee they'll have already been checked
590 ("rustc_deprecated", Whitelisted, Ungated),
591 ("must_use", Whitelisted, Ungated),
592 ("stable", Whitelisted, Ungated),
593 ("unstable", Whitelisted, Ungated),
594 ("deprecated", Normal, Ungated),
596 ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
597 "unboxed_closures are still evolving",
598 cfg_fn!(unboxed_closures))),
599 ("rustc_reflect_like", Whitelisted, Gated("reflect",
600 "defining reflective traits is still evolving",
603 // Crate level attributes
604 ("crate_name", CrateLevel, Ungated),
605 ("crate_type", CrateLevel, Ungated),
606 ("crate_id", CrateLevel, Ungated),
607 ("feature", CrateLevel, Ungated),
608 ("no_start", CrateLevel, Ungated),
609 ("no_main", CrateLevel, Ungated),
610 ("no_builtins", CrateLevel, Ungated),
611 ("recursion_limit", CrateLevel, Ungated),
614 // cfg(...)'s that are feature gated
615 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
616 // (name in cfg, feature, function to check if the feature is enabled)
617 ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
618 ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
619 ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
620 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
623 #[derive(Debug, Eq, PartialEq)]
624 pub struct GatedCfg {
630 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
631 let name = cfg.name();
633 .position(|info| info.0 == name)
642 pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
643 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
644 if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
645 let diagnostic = &sess.span_diagnostic;
646 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
647 emit_feature_err(diagnostic, feature, self.span, GateIssue::Language, &explain);
653 features: &'a Features,
654 span_handler: &'a Handler,
656 plugin_attributes: &'a [(String, AttributeType)],
659 macro_rules! gate_feature_fn {
660 ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
661 let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
662 let has_feature: bool = has_feature(&$cx.features);
663 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
664 if !has_feature && !cx.cm.span_allows_unstable(span) {
665 emit_feature_err(cx.span_handler, name, span, GateIssue::Language, explain);
670 macro_rules! gate_feature {
671 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
672 gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
676 impl<'a> Context<'a> {
677 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
678 debug!("check_attribute(attr = {:?})", attr);
679 let name = &*attr.name();
680 for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES {
682 if let &Gated(ref name, ref desc, ref has_feature) = gateage {
683 gate_feature_fn!(self, has_feature, attr.span, name, desc);
685 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
689 for &(ref n, ref ty) in self.plugin_attributes {
691 // Plugins can't gate attributes, so we don't check for it
692 // unlike the code above; we only use this loop to
693 // short-circuit to avoid the checks below
694 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
698 if name.starts_with("rustc_") {
699 gate_feature!(self, rustc_attrs, attr.span,
700 "unless otherwise specified, attributes \
701 with the prefix `rustc_` \
702 are reserved for internal compiler diagnostics");
703 } else if name.starts_with("derive_") {
704 gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
706 // Only run the custom attribute lint during regular
707 // feature gate checking. Macro gating runs
708 // before the plugin attributes are registered
709 // so we skip this then
711 gate_feature!(self, custom_attribute, attr.span,
712 &format!("The attribute `{}` is currently \
713 unknown to the compiler and \
715 added to it in the future",
722 pub fn check_attribute(attr: &ast::Attribute, handler: &Handler,
723 cm: &CodeMap, features: &Features) {
725 features: features, span_handler: handler,
726 cm: cm, plugin_attributes: &[]
728 cx.check_attribute(attr, true);
731 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
732 ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
735 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
736 if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
738 // FIXME (#28244): enforce that active features have issue numbers
739 // assert!(issue.is_some())
742 // search in Accepted or Removed features
743 ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES.iter())
744 .find(|t| t.0 == feature)
754 pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
756 let issue = match issue {
757 GateIssue::Language => find_lang_feature_issue(feature),
758 GateIssue::Library(lib) => lib,
761 let mut err = if let Some(n) = issue {
762 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
764 diag.struct_span_err(span, explain)
767 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
768 if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
772 err.help(&format!("add #![feature({})] to the \
773 crate attributes to enable",
778 const EXPLAIN_BOX_SYNTAX: &'static str =
779 "box expression syntax is experimental; you can call `Box::new` instead.";
781 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
782 "attributes on non-item statements and expressions are experimental.";
784 pub const EXPLAIN_ASM: &'static str =
785 "inline assembly is not stable enough for use and is subject to change";
787 pub const EXPLAIN_LOG_SYNTAX: &'static str =
788 "`log_syntax!` is not stable enough for use and is subject to change";
790 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
791 "`concat_idents` is not stable enough for use and is subject to change";
793 pub const EXPLAIN_TRACE_MACROS: &'static str =
794 "`trace_macros` is not stable enough for use and is subject to change";
795 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
796 "allow_internal_unstable side-steps feature gating and stability checks";
798 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
799 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
801 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
802 "attributes of the form `#[derive_*]` are reserved for the compiler";
804 pub const EXPLAIN_PLACEMENT_IN: &'static str =
805 "placement-in expression syntax is experimental and subject to change.";
807 struct PostExpansionVisitor<'a> {
808 context: &'a Context<'a>,
811 macro_rules! gate_feature_post {
812 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
813 let (cx, span) = ($cx, $span);
814 if !cx.context.cm.span_allows_unstable(span) {
815 gate_feature!(cx.context, $feature, span, $explain)
820 impl<'a> PostExpansionVisitor<'a> {
821 fn check_abi(&self, abi: Abi, span: Span) {
823 Abi::RustIntrinsic =>
824 gate_feature_post!(&self, intrinsics, span,
825 "intrinsics are subject to change"),
826 Abi::PlatformIntrinsic => {
827 gate_feature_post!(&self, platform_intrinsics, span,
828 "platform intrinsics are experimental and possibly buggy")
831 gate_feature_post!(&self, abi_vectorcall, span,
832 "vectorcall is experimental and subject to change")
835 gate_feature_post!(&self, unboxed_closures, span,
836 "rust-call ABI is subject to change");
843 impl<'a> Visitor for PostExpansionVisitor<'a> {
844 fn visit_attribute(&mut self, attr: &ast::Attribute) {
845 if !self.context.cm.span_allows_unstable(attr.span) {
846 self.context.check_attribute(attr, false);
850 fn visit_name(&mut self, sp: Span, name: ast::Name) {
851 if !name.as_str().is_ascii() {
852 gate_feature_post!(&self, non_ascii_idents, sp,
853 "non-ascii idents are not fully supported.");
857 fn visit_item(&mut self, i: &ast::Item) {
859 ast::ItemKind::ExternCrate(_) => {
860 if attr::contains_name(&i.attrs[..], "macro_reexport") {
861 gate_feature_post!(&self, macro_reexport, i.span,
862 "macros reexports are experimental \
863 and possibly buggy");
867 ast::ItemKind::ForeignMod(ref foreign_module) => {
868 if attr::contains_name(&i.attrs[..], "link_args") {
869 gate_feature_post!(&self, link_args, i.span,
870 "the `link_args` attribute is not portable \
871 across platforms, it is recommended to \
872 use `#[link(name = \"foo\")]` instead")
874 self.check_abi(foreign_module.abi, i.span);
877 ast::ItemKind::Fn(..) => {
878 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
879 gate_feature_post!(&self, plugin_registrar, i.span,
880 "compiler plugins are experimental and possibly buggy");
882 if attr::contains_name(&i.attrs[..], "start") {
883 gate_feature_post!(&self, start, i.span,
884 "a #[start] function is an experimental \
885 feature whose signature may change \
888 if attr::contains_name(&i.attrs[..], "main") {
889 gate_feature_post!(&self, main, i.span,
890 "declaration of a nonstandard #[main] \
891 function may change over time, for now \
892 a top-level `fn main()` is required");
896 ast::ItemKind::Struct(..) => {
897 if attr::contains_name(&i.attrs[..], "simd") {
898 gate_feature_post!(&self, simd, i.span,
899 "SIMD types are experimental and possibly buggy");
900 self.context.span_handler.span_warn(i.span,
901 "the `#[simd]` attribute is deprecated, \
902 use `#[repr(simd)]` instead");
904 for attr in &i.attrs {
905 if attr.name() == "repr" {
906 for item in attr.meta_item_list().unwrap_or(&[]) {
907 if item.name() == "simd" {
908 gate_feature_post!(&self, repr_simd, i.span,
909 "SIMD types are experimental \
910 and possibly buggy");
918 ast::ItemKind::DefaultImpl(..) => {
919 gate_feature_post!(&self, optin_builtin_traits,
921 "default trait implementations are experimental \
922 and possibly buggy");
925 ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
927 ast::ImplPolarity::Negative => {
928 gate_feature_post!(&self, optin_builtin_traits,
930 "negative trait bounds are not yet fully implemented; \
931 use marker types for now");
940 visit::walk_item(self, i);
943 fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
944 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
946 Some(val) => val.starts_with("llvm."),
950 gate_feature_post!(&self, link_llvm_intrinsics, i.span,
951 "linking to LLVM intrinsics is experimental");
954 visit::walk_foreign_item(self, i)
957 fn visit_ty(&mut self, ty: &ast::Ty) {
959 ast::TyKind::BareFn(ref bare_fn_ty) => {
960 self.check_abi(bare_fn_ty.abi, ty.span);
962 ast::TyKind::ImplTrait(..) => {
963 gate_feature_post!(&self, conservative_impl_trait, ty.span,
964 "`impl Trait` is experimental");
968 visit::walk_ty(self, ty)
971 fn visit_expr(&mut self, e: &ast::Expr) {
973 ast::ExprKind::Box(_) => {
974 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
976 ast::ExprKind::Type(..) => {
977 gate_feature_post!(&self, type_ascription, e.span,
978 "type ascription is experimental");
980 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
981 gate_feature_post!(&self, inclusive_range_syntax,
983 "inclusive range syntax is experimental");
985 ast::ExprKind::Try(..) => {
986 gate_feature_post!(&self, question_mark, e.span, "the `?` operator is not stable");
988 ast::ExprKind::InPlace(..) => {
989 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
993 visit::walk_expr(self, e);
996 fn visit_pat(&mut self, pattern: &ast::Pat) {
998 PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => {
999 gate_feature_post!(&self, advanced_slice_patterns,
1001 "multiple-element slice matches anywhere \
1002 but at the end of a slice (e.g. \
1003 `[0, ..xs, 0]`) are experimental")
1005 PatKind::Vec(..) => {
1006 gate_feature_post!(&self, slice_patterns,
1008 "slice pattern syntax is experimental");
1010 PatKind::Box(..) => {
1011 gate_feature_post!(&self, box_patterns,
1013 "box pattern syntax is experimental");
1015 PatKind::Tuple(_, ddpos)
1016 if ddpos.is_some() => {
1017 gate_feature_post!(&self, dotdot_in_tuple_patterns,
1019 "`..` in tuple patterns is experimental");
1021 PatKind::TupleStruct(_, ref fields, ddpos)
1022 if ddpos.is_some() && !fields.is_empty() => {
1023 gate_feature_post!(&self, dotdot_in_tuple_patterns,
1025 "`..` in tuple struct patterns is experimental");
1027 PatKind::TupleStruct(_, ref fields, ddpos)
1028 if ddpos.is_none() && fields.is_empty() => {
1029 gate_feature_post!(&self, relaxed_adts, pattern.span,
1030 "empty tuple structs patterns are unstable");
1034 visit::walk_pat(self, pattern)
1037 fn visit_fn(&mut self,
1039 fn_decl: &ast::FnDecl,
1043 // check for const fn declarations
1045 FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1046 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1049 // stability of const fn methods are covered in
1050 // visit_trait_item and visit_impl_item below; this is
1051 // because default methods don't pass through this
1057 FnKind::ItemFn(_, _, _, _, abi, _) |
1058 FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => {
1059 self.check_abi(abi, span);
1063 visit::walk_fn(self, fn_kind, fn_decl, block, span);
1066 fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
1068 ast::TraitItemKind::Const(..) => {
1069 gate_feature_post!(&self, associated_consts,
1071 "associated constants are experimental")
1073 ast::TraitItemKind::Method(ref sig, ref block) => {
1074 if block.is_none() {
1075 self.check_abi(sig.abi, ti.span);
1077 if sig.constness == ast::Constness::Const {
1078 gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1081 ast::TraitItemKind::Type(_, Some(_)) => {
1082 gate_feature_post!(&self, associated_type_defaults, ti.span,
1083 "associated type defaults are unstable");
1087 visit::walk_trait_item(self, ti);
1090 fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
1091 if ii.defaultness == ast::Defaultness::Default {
1092 gate_feature_post!(&self, specialization,
1094 "specialization is unstable");
1098 ast::ImplItemKind::Const(..) => {
1099 gate_feature_post!(&self, associated_consts,
1101 "associated constants are experimental")
1103 ast::ImplItemKind::Method(ref sig, _) => {
1104 if sig.constness == ast::Constness::Const {
1105 gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1110 visit::walk_impl_item(self, ii);
1113 fn visit_variant_data(&mut self, vdata: &ast::VariantData, _: ast::Ident,
1114 _: &ast::Generics, _: NodeId, span: Span) {
1115 if vdata.fields().is_empty() {
1116 if vdata.is_tuple() {
1117 gate_feature_post!(&self, relaxed_adts, span,
1118 "empty tuple structs and enum variants are unstable, \
1119 use unit structs and enum variants instead");
1123 visit::walk_struct_def(self, vdata)
1126 fn visit_vis(&mut self, vis: &ast::Visibility) {
1127 let span = match *vis {
1128 ast::Visibility::Crate(span) => span,
1129 ast::Visibility::Restricted { ref path, .. } => path.span,
1132 gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental");
1134 visit::walk_vis(self, vis)
1138 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1139 let mut features = Features::new();
1141 for attr in krate_attrs {
1142 if !attr.check_name("feature") {
1146 match attr.meta_item_list() {
1148 span_err!(span_handler, attr.span, E0555,
1149 "malformed feature attribute, expected #![feature(...)]");
1153 let name = if mi.is_word() {
1156 span_err!(span_handler, mi.span, E0556,
1157 "malformed feature, expected just one word");
1160 if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1161 .find(|& &(n, _, _, _)| name == n) {
1162 *(setter(&mut features)) = true;
1164 else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1165 .find(|& &(n, _, _)| name == n) {
1166 span_err!(span_handler, mi.span, E0557, "feature has been removed");
1168 else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1169 .find(|& &(n, _, _)| name == n) {
1170 features.declared_stable_lang_features.push((name, mi.span));
1172 features.declared_lib_features.push((name, mi.span));
1182 pub fn check_crate(krate: &ast::Crate,
1184 features: &Features,
1185 plugin_attributes: &[(String, AttributeType)],
1186 unstable: UnstableFeatures) {
1187 maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1190 span_handler: &sess.span_diagnostic,
1192 plugin_attributes: plugin_attributes,
1194 visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1197 #[derive(Clone, Copy)]
1198 pub enum UnstableFeatures {
1199 /// Hard errors for unstable features are active, as on
1200 /// beta/stable channels.
1202 /// Allow features to me activated, as on nightly.
1204 /// Errors are bypassed for bootstrapping. This is required any time
1205 /// during the build that feature-related lints are set to warn or above
1206 /// because the build turns on warnings-as-errors and uses lots of unstable
1207 /// features. As a result, this is always required for building Rust itself.
1211 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1212 unstable: UnstableFeatures) {
1213 let allow_features = match unstable {
1214 UnstableFeatures::Allow => true,
1215 UnstableFeatures::Disallow => false,
1216 UnstableFeatures::Cheat => true
1218 if !allow_features {
1219 for attr in &krate.attrs {
1220 if attr.check_name("feature") {
1221 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1222 span_err!(span_handler, attr.span, E0554,
1223 "#[feature] may not be used on the {} release channel",