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))
284 (removed
, import_shadowing
, "1.0.0", None
),
285 (removed
, managed_boxes
, "1.0.0", None
),
286 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
287 (removed
, negate_unsigned
, "1.0.0", Some(29645)),
288 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
289 (removed
, opt_out_copy
, "1.0.0", None
),
290 (removed
, quad_precision_float
, "1.0.0", None
),
291 (removed
, struct_inherit
, "1.0.0", None
),
292 (removed
, test_removed_feature
, "1.0.0", None
),
293 (removed
, visible_private_types
, "1.0.0", None
)
297 (accepted
, associated_types
, "1.0.0", None
),
298 // allow overloading augmented assignment operations like `a += b`
299 (accepted
, augmented_assignments
, "1.8.0", Some(28235)),
300 // allow empty structs and enum variants with braces
301 (accepted
, braced_empty_structs
, "1.8.0", Some(29720)),
302 (accepted
, default_type_params
, "1.0.0", None
),
303 (accepted
, globs
, "1.0.0", None
),
304 (accepted
, if_let
, "1.0.0", None
),
305 // A temporary feature gate used to enable parser extensions needed
306 // to bootstrap fix for #5723.
307 (accepted
, issue_5723_bootstrap
, "1.0.0", None
),
308 (accepted
, macro_rules
, "1.0.0", None
),
309 // Allows using #![no_std]
310 (accepted
, no_std
, "1.0.0", None
),
311 (accepted
, slicing_syntax
, "1.0.0", None
),
312 (accepted
, struct_variant
, "1.0.0", None
),
313 // These are used to test this portion of the compiler, they don't actually
315 (accepted
, test_accepted_feature
, "1.0.0", None
),
316 (accepted
, tuple_indexing
, "1.0.0", None
),
317 (accepted
, while_let
, "1.0.0", None
),
318 // Allows `#[deprecated]` attribute
319 (accepted
, deprecated
, "1.9.0", Some(29935))
321 // (changing above list without updating src/doc/reference.md makes @cmr sad)
323 #[derive(PartialEq, Copy, Clone, Debug)]
324 pub enum AttributeType
{
325 /// Normal, builtin attribute that is consumed
326 /// by the compiler before the unused_attribute check
329 /// Builtin attribute that may not be consumed by the compiler
330 /// before the unused_attribute check. These attributes
331 /// will be ignored by the unused_attribute lint
334 /// Builtin attribute that is only allowed at the crate level
338 pub enum AttributeGate
{
339 /// Is gated by a given feature gate, reason
340 /// and function to check if enabled
341 Gated(&'
static str, &'
static str, fn(&Features
) -> bool
),
343 /// Ungated attribute, can be used on all release channels
348 impl ::std
::fmt
::Debug
for AttributeGate
{
349 fn fmt(&self, fmt
: &mut ::std
::fmt
::Formatter
) -> ::std
::fmt
::Result
{
351 Gated(ref name
, ref expl
, _
) => write
!(fmt
, "Gated({}, {})", name
, expl
),
352 Ungated
=> write
!(fmt
, "Ungated")
357 macro_rules
! cfg_fn
{
358 ($field
: ident
) => {{
359 fn f(features
: &Features
) -> bool
{
362 f
as fn(&Features
) -> bool
366 // Attributes that have a special meaning to rustc or rustdoc
367 pub const KNOWN_ATTRIBUTES
: &'
static [(&'
static str, AttributeType
, AttributeGate
)] = &[
370 ("warn", Normal
, Ungated
),
371 ("allow", Normal
, Ungated
),
372 ("forbid", Normal
, Ungated
),
373 ("deny", Normal
, Ungated
),
375 ("macro_reexport", Normal
, Ungated
),
376 ("macro_use", Normal
, Ungated
),
377 ("macro_export", Normal
, Ungated
),
378 ("plugin_registrar", Normal
, Ungated
),
380 ("cfg", Normal
, Ungated
),
381 ("cfg_attr", Normal
, Ungated
),
382 ("main", Normal
, Ungated
),
383 ("start", Normal
, Ungated
),
384 ("test", Normal
, Ungated
),
385 ("bench", Normal
, Ungated
),
386 ("simd", Normal
, Ungated
),
387 ("repr", Normal
, Ungated
),
388 ("path", Normal
, Ungated
),
389 ("abi", Normal
, Ungated
),
390 ("automatically_derived", Normal
, Ungated
),
391 ("no_mangle", Normal
, Ungated
),
392 ("no_link", Normal
, Ungated
),
393 ("derive", Normal
, Ungated
),
394 ("should_panic", Normal
, Ungated
),
395 ("ignore", Normal
, Ungated
),
396 ("no_implicit_prelude", Normal
, Ungated
),
397 ("reexport_test_harness_main", Normal
, Ungated
),
398 ("link_args", Normal
, Ungated
),
399 ("macro_escape", Normal
, Ungated
),
402 ("structural_match", Whitelisted
, Gated("structural_match",
403 "the semantics of constant patterns is \
405 cfg_fn
!(structural_match
))),
407 // Not used any more, but we can't feature gate it
408 ("no_stack_check", Normal
, Ungated
),
410 ("plugin", CrateLevel
, Gated("plugin",
411 "compiler plugins are experimental \
415 ("no_std", CrateLevel
, Ungated
),
416 ("no_core", CrateLevel
, Gated("no_core",
417 "no_core is experimental",
419 ("lang", Normal
, Gated("lang_items",
420 "language items are subject to change",
421 cfg_fn
!(lang_items
))),
422 ("linkage", Whitelisted
, Gated("linkage",
423 "the `linkage` attribute is experimental \
424 and not portable across platforms",
426 ("thread_local", Whitelisted
, Gated("thread_local",
427 "`#[thread_local]` is an experimental feature, and does \
428 not currently handle destructors. There is no \
429 corresponding `#[task_local]` mapping to the task \
431 cfg_fn
!(thread_local
))),
433 ("rustc_on_unimplemented", Normal
, Gated("on_unimplemented",
434 "the `#[rustc_on_unimplemented]` attribute \
435 is an experimental feature",
436 cfg_fn
!(on_unimplemented
))),
437 ("allocator", Whitelisted
, Gated("allocator",
438 "the `#[allocator]` attribute is an experimental feature",
439 cfg_fn
!(allocator
))),
440 ("needs_allocator", Normal
, Gated("needs_allocator",
441 "the `#[needs_allocator]` \
442 attribute is an experimental \
444 cfg_fn
!(needs_allocator
))),
445 ("panic_runtime", Whitelisted
, Gated("panic_runtime",
446 "the `#[panic_runtime]` attribute is \
447 an experimental feature",
448 cfg_fn
!(panic_runtime
))),
449 ("needs_panic_runtime", Whitelisted
, Gated("needs_panic_runtime",
450 "the `#[needs_panic_runtime]` \
451 attribute is an experimental \
453 cfg_fn
!(needs_panic_runtime
))),
454 ("rustc_variance", Normal
, Gated("rustc_attrs",
455 "the `#[rustc_variance]` attribute \
456 is just used for rustc unit tests \
457 and will never be stable",
458 cfg_fn
!(rustc_attrs
))),
459 ("rustc_error", Whitelisted
, Gated("rustc_attrs",
460 "the `#[rustc_error]` attribute \
461 is just used for rustc unit tests \
462 and will never be stable",
463 cfg_fn
!(rustc_attrs
))),
464 ("rustc_if_this_changed", Whitelisted
, Gated("rustc_attrs",
465 "the `#[rustc_if_this_changed]` attribute \
466 is just used for rustc unit tests \
467 and will never be stable",
468 cfg_fn
!(rustc_attrs
))),
469 ("rustc_then_this_would_need", Whitelisted
, Gated("rustc_attrs",
470 "the `#[rustc_if_this_changed]` attribute \
471 is just used for rustc unit tests \
472 and will never be stable",
473 cfg_fn
!(rustc_attrs
))),
474 ("rustc_dirty", Whitelisted
, Gated("rustc_attrs",
475 "the `#[rustc_dirty]` attribute \
476 is just used for rustc unit tests \
477 and will never be stable",
478 cfg_fn
!(rustc_attrs
))),
479 ("rustc_clean", Whitelisted
, Gated("rustc_attrs",
480 "the `#[rustc_clean]` attribute \
481 is just used for rustc unit tests \
482 and will never be stable",
483 cfg_fn
!(rustc_attrs
))),
484 ("rustc_symbol_name", Whitelisted
, Gated("rustc_attrs",
485 "internal rustc attributes will never be stable",
486 cfg_fn
!(rustc_attrs
))),
487 ("rustc_item_path", Whitelisted
, Gated("rustc_attrs",
488 "internal rustc attributes will never be stable",
489 cfg_fn
!(rustc_attrs
))),
490 ("rustc_move_fragments", Normal
, Gated("rustc_attrs",
491 "the `#[rustc_move_fragments]` attribute \
492 is just used for rustc unit tests \
493 and will never be stable",
494 cfg_fn
!(rustc_attrs
))),
495 ("rustc_mir", Whitelisted
, Gated("rustc_attrs",
496 "the `#[rustc_mir]` attribute \
497 is just used for rustc unit tests \
498 and will never be stable",
499 cfg_fn
!(rustc_attrs
))),
500 ("rustc_no_mir", Whitelisted
, Gated("rustc_attrs",
501 "the `#[rustc_no_mir]` attribute \
502 is just used to make tests pass \
503 and will never be stable",
504 cfg_fn
!(rustc_attrs
))),
505 ("rustc_inherit_overflow_checks", Whitelisted
, Gated("rustc_attrs",
506 "the `#[rustc_inherit_overflow_checks]` \
507 attribute is just used to control \
508 overflow checking behavior of several \
509 libcore functions that are inlined \
510 across crates and will never be stable",
511 cfg_fn
!(rustc_attrs
))),
513 ("allow_internal_unstable", Normal
, Gated("allow_internal_unstable",
514 EXPLAIN_ALLOW_INTERNAL_UNSTABLE
,
515 cfg_fn
!(allow_internal_unstable
))),
517 ("fundamental", Whitelisted
, Gated("fundamental",
518 "the `#[fundamental]` attribute \
519 is an experimental feature",
520 cfg_fn
!(fundamental
))),
522 ("linked_from", Normal
, Gated("linked_from",
523 "the `#[linked_from]` attribute \
524 is an experimental feature",
525 cfg_fn
!(linked_from
))),
527 // FIXME: #14408 whitelist docs since rustdoc looks at them
528 ("doc", Whitelisted
, Ungated
),
530 // FIXME: #14406 these are processed in trans, which happens after the
532 ("cold", Whitelisted
, Ungated
),
533 ("naked", Whitelisted
, Gated("naked_functions",
534 "the `#[naked]` attribute \
535 is an experimental feature",
536 cfg_fn
!(naked_functions
))),
537 ("export_name", Whitelisted
, Ungated
),
538 ("inline", Whitelisted
, Ungated
),
539 ("link", Whitelisted
, Ungated
),
540 ("link_name", Whitelisted
, Ungated
),
541 ("link_section", Whitelisted
, Ungated
),
542 ("no_builtins", Whitelisted
, Ungated
),
543 ("no_mangle", Whitelisted
, Ungated
),
544 ("no_debug", Whitelisted
, Gated("no_debug",
545 "the `#[no_debug]` attribute \
546 is an experimental feature",
548 ("omit_gdb_pretty_printer_section", Whitelisted
, Gated("omit_gdb_pretty_printer_section",
549 "the `#[omit_gdb_pretty_printer_section]` \
550 attribute is just used for the Rust test \
552 cfg_fn
!(omit_gdb_pretty_printer_section
))),
553 ("unsafe_no_drop_flag", Whitelisted
, Gated("unsafe_no_drop_flag",
554 "unsafe_no_drop_flag has unstable semantics \
555 and may be removed in the future",
556 cfg_fn
!(unsafe_no_drop_flag
))),
557 ("unsafe_destructor_blind_to_params",
559 Gated("dropck_parametricity",
560 "unsafe_destructor_blind_to_params has unstable semantics \
561 and may be removed in the future",
562 cfg_fn
!(dropck_parametricity
))),
563 ("unwind", Whitelisted
, Gated("unwind_attributes", "#[unwind] is experimental",
564 cfg_fn
!(unwind_attributes
))),
567 ("prelude_import", Whitelisted
, Gated("prelude_import",
568 "`#[prelude_import]` is for use by rustc only",
569 cfg_fn
!(prelude_import
))),
571 // FIXME: #14407 these are only looked at on-demand so we can't
572 // guarantee they'll have already been checked
573 ("rustc_deprecated", Whitelisted
, Ungated
),
574 ("must_use", Whitelisted
, Ungated
),
575 ("stable", Whitelisted
, Ungated
),
576 ("unstable", Whitelisted
, Ungated
),
577 ("deprecated", Normal
, Ungated
),
579 ("rustc_paren_sugar", Normal
, Gated("unboxed_closures",
580 "unboxed_closures are still evolving",
581 cfg_fn
!(unboxed_closures
))),
582 ("rustc_reflect_like", Whitelisted
, Gated("reflect",
583 "defining reflective traits is still evolving",
586 // Crate level attributes
587 ("crate_name", CrateLevel
, Ungated
),
588 ("crate_type", CrateLevel
, Ungated
),
589 ("crate_id", CrateLevel
, Ungated
),
590 ("feature", CrateLevel
, Ungated
),
591 ("no_start", CrateLevel
, Ungated
),
592 ("no_main", CrateLevel
, Ungated
),
593 ("no_builtins", CrateLevel
, Ungated
),
594 ("recursion_limit", CrateLevel
, Ungated
),
597 // cfg(...)'s that are feature gated
598 const GATED_CFGS
: &'
static [(&'
static str, &'
static str, fn(&Features
) -> bool
)] = &[
599 // (name in cfg, feature, function to check if the feature is enabled)
600 ("target_feature", "cfg_target_feature", cfg_fn
!(cfg_target_feature
)),
601 ("target_vendor", "cfg_target_vendor", cfg_fn
!(cfg_target_vendor
)),
602 ("target_thread_local", "cfg_target_thread_local", cfg_fn
!(cfg_target_thread_local
)),
603 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn
!(cfg_target_has_atomic
)),
606 #[derive(Debug, Eq, PartialEq)]
607 pub struct GatedCfg
{
613 pub fn gate(cfg
: &ast
::MetaItem
) -> Option
<GatedCfg
> {
614 let name
= cfg
.name();
616 .position(|info
| info
.0 == name
)
625 pub fn check_and_emit(&self, sess
: &ParseSess
, features
: &Features
) {
626 let (cfg
, feature
, has_feature
) = GATED_CFGS
[self.index
];
627 if !has_feature(features
) && !sess
.codemap().span_allows_unstable(self.span
) {
628 let diagnostic
= &sess
.span_diagnostic
;
629 let explain
= format
!("`cfg({})` is experimental and subject to change", cfg
);
630 emit_feature_err(diagnostic
, feature
, self.span
, GateIssue
::Language
, &explain
);
636 features
: &'a Features
,
637 span_handler
: &'a Handler
,
639 plugin_attributes
: &'a
[(String
, AttributeType
)],
642 macro_rules
! gate_feature_fn
{
643 ($cx
: expr
, $has_feature
: expr
, $span
: expr
, $name
: expr
, $explain
: expr
) => {{
644 let (cx
, has_feature
, span
, name
, explain
) = ($cx
, $has_feature
, $span
, $name
, $explain
);
645 let has_feature
: bool
= has_feature(&$cx
.features
);
646 debug
!("gate_feature(feature = {:?}, span = {:?}); has? {}", name
, span
, has_feature
);
647 if !has_feature
&& !cx
.cm
.span_allows_unstable(span
) {
648 emit_feature_err(cx
.span_handler
, name
, span
, GateIssue
::Language
, explain
);
653 macro_rules
! gate_feature
{
654 ($cx
: expr
, $feature
: ident
, $span
: expr
, $explain
: expr
) => {
655 gate_feature_fn
!($cx
, |x
:&Features
| x
.$feature
, $span
, stringify
!($feature
), $explain
)
659 impl<'a
> Context
<'a
> {
660 fn check_attribute(&self, attr
: &ast
::Attribute
, is_macro
: bool
) {
661 debug
!("check_attribute(attr = {:?})", attr
);
662 let name
= &*attr
.name();
663 for &(n
, ty
, ref gateage
) in KNOWN_ATTRIBUTES
{
665 if let &Gated(ref name
, ref desc
, ref has_feature
) = gateage
{
666 gate_feature_fn
!(self, has_feature
, attr
.span
, name
, desc
);
668 debug
!("check_attribute: {:?} is known, {:?}, {:?}", name
, ty
, gateage
);
672 for &(ref n
, ref ty
) in self.plugin_attributes
{
674 // Plugins can't gate attributes, so we don't check for it
675 // unlike the code above; we only use this loop to
676 // short-circuit to avoid the checks below
677 debug
!("check_attribute: {:?} is registered by a plugin, {:?}", name
, ty
);
681 if name
.starts_with("rustc_") {
682 gate_feature
!(self, rustc_attrs
, attr
.span
,
683 "unless otherwise specified, attributes \
684 with the prefix `rustc_` \
685 are reserved for internal compiler diagnostics");
686 } else if name
.starts_with("derive_") {
687 gate_feature
!(self, custom_derive
, attr
.span
, EXPLAIN_DERIVE_UNDERSCORE
);
689 // Only run the custom attribute lint during regular
690 // feature gate checking. Macro gating runs
691 // before the plugin attributes are registered
692 // so we skip this then
694 gate_feature
!(self, custom_attribute
, attr
.span
,
695 &format
!("The attribute `{}` is currently \
696 unknown to the compiler and \
698 added to it in the future",
705 pub fn check_attribute(attr
: &ast
::Attribute
, handler
: &Handler
,
706 cm
: &CodeMap
, features
: &Features
) {
708 features
: features
, span_handler
: handler
,
709 cm
: cm
, plugin_attributes
: &[]
711 cx
.check_attribute(attr
, true);
714 pub fn find_lang_feature_accepted_version(feature
: &str) -> Option
<&'
static str> {
715 ACCEPTED_FEATURES
.iter().find(|t
| t
.0 == feature
).map(|t
| t
.1)
718 fn find_lang_feature_issue(feature
: &str) -> Option
<u32> {
719 if let Some(info
) = ACTIVE_FEATURES
.iter().find(|t
| t
.0 == feature
) {
721 // FIXME (#28244): enforce that active features have issue numbers
722 // assert!(issue.is_some())
725 // search in Accepted or Removed features
726 ACCEPTED_FEATURES
.iter().chain(REMOVED_FEATURES
.iter())
727 .find(|t
| t
.0 == feature
)
737 pub fn emit_feature_err(diag
: &Handler
, feature
: &str, span
: Span
, issue
: GateIssue
,
739 let issue
= match issue
{
740 GateIssue
::Language
=> find_lang_feature_issue(feature
),
741 GateIssue
::Library(lib
) => lib
,
744 let mut err
= if let Some(n
) = issue
{
745 diag
.struct_span_err(span
, &format
!("{} (see issue #{})", explain
, n
))
747 diag
.struct_span_err(span
, explain
)
750 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
751 if option_env
!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
755 err
.help(&format
!("add #![feature({})] to the \
756 crate attributes to enable",
761 const EXPLAIN_BOX_SYNTAX
: &'
static str =
762 "box expression syntax is experimental; you can call `Box::new` instead.";
764 pub const EXPLAIN_STMT_ATTR_SYNTAX
: &'
static str =
765 "attributes on non-item statements and expressions are experimental.";
767 pub const EXPLAIN_ASM
: &'
static str =
768 "inline assembly is not stable enough for use and is subject to change";
770 pub const EXPLAIN_LOG_SYNTAX
: &'
static str =
771 "`log_syntax!` is not stable enough for use and is subject to change";
773 pub const EXPLAIN_CONCAT_IDENTS
: &'
static str =
774 "`concat_idents` is not stable enough for use and is subject to change";
776 pub const EXPLAIN_TRACE_MACROS
: &'
static str =
777 "`trace_macros` is not stable enough for use and is subject to change";
778 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE
: &'
static str =
779 "allow_internal_unstable side-steps feature gating and stability checks";
781 pub const EXPLAIN_CUSTOM_DERIVE
: &'
static str =
782 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
784 pub const EXPLAIN_DERIVE_UNDERSCORE
: &'
static str =
785 "attributes of the form `#[derive_*]` are reserved for the compiler";
787 pub const EXPLAIN_PLACEMENT_IN
: &'
static str =
788 "placement-in expression syntax is experimental and subject to change.";
790 struct PostExpansionVisitor
<'a
> {
791 context
: &'a Context
<'a
>,
794 macro_rules
! gate_feature_post
{
795 ($cx
: expr
, $feature
: ident
, $span
: expr
, $explain
: expr
) => {{
796 let (cx
, span
) = ($cx
, $span
);
797 if !cx
.context
.cm
.span_allows_unstable(span
) {
798 gate_feature
!(cx
.context
, $feature
, span
, $explain
)
803 impl<'a
> Visitor
for PostExpansionVisitor
<'a
> {
804 fn visit_attribute(&mut self, attr
: &ast
::Attribute
) {
805 if !self.context
.cm
.span_allows_unstable(attr
.span
) {
806 self.context
.check_attribute(attr
, false);
810 fn visit_name(&mut self, sp
: Span
, name
: ast
::Name
) {
811 if !name
.as_str().is_ascii() {
812 gate_feature_post
!(&self, non_ascii_idents
, sp
,
813 "non-ascii idents are not fully supported.");
817 fn visit_item(&mut self, i
: &ast
::Item
) {
819 ast
::ItemKind
::ExternCrate(_
) => {
820 if attr
::contains_name(&i
.attrs
[..], "macro_reexport") {
821 gate_feature_post
!(&self, macro_reexport
, i
.span
,
822 "macros reexports are experimental \
823 and possibly buggy");
827 ast
::ItemKind
::ForeignMod(ref foreign_module
) => {
828 if attr
::contains_name(&i
.attrs
[..], "link_args") {
829 gate_feature_post
!(&self, link_args
, i
.span
,
830 "the `link_args` attribute is not portable \
831 across platforms, it is recommended to \
832 use `#[link(name = \"foo\")]` instead")
834 match foreign_module
.abi
{
835 Abi
::RustIntrinsic
=>
836 gate_feature_post
!(&self, intrinsics
, i
.span
,
837 "intrinsics are subject to change"),
838 Abi
::PlatformIntrinsic
=> {
839 gate_feature_post
!(&self, platform_intrinsics
, i
.span
,
840 "platform intrinsics are experimental \
844 gate_feature_post
!(&self, abi_vectorcall
, i
.span
,
845 "vectorcall is experimental and subject to change")
851 ast
::ItemKind
::Fn(..) => {
852 if attr
::contains_name(&i
.attrs
[..], "plugin_registrar") {
853 gate_feature_post
!(&self, plugin_registrar
, i
.span
,
854 "compiler plugins are experimental and possibly buggy");
856 if attr
::contains_name(&i
.attrs
[..], "start") {
857 gate_feature_post
!(&self, start
, i
.span
,
858 "a #[start] function is an experimental \
859 feature whose signature may change \
862 if attr
::contains_name(&i
.attrs
[..], "main") {
863 gate_feature_post
!(&self, main
, i
.span
,
864 "declaration of a nonstandard #[main] \
865 function may change over time, for now \
866 a top-level `fn main()` is required");
870 ast
::ItemKind
::Struct(..) => {
871 if attr
::contains_name(&i
.attrs
[..], "simd") {
872 gate_feature_post
!(&self, simd
, i
.span
,
873 "SIMD types are experimental and possibly buggy");
874 self.context
.span_handler
.span_warn(i
.span
,
875 "the `#[simd]` attribute is deprecated, \
876 use `#[repr(simd)]` instead");
878 for attr
in &i
.attrs
{
879 if attr
.name() == "repr" {
880 for item
in attr
.meta_item_list().unwrap_or(&[]) {
881 if item
.name() == "simd" {
882 gate_feature_post
!(&self, repr_simd
, i
.span
,
883 "SIMD types are experimental \
884 and possibly buggy");
892 ast
::ItemKind
::DefaultImpl(..) => {
893 gate_feature_post
!(&self, optin_builtin_traits
,
895 "default trait implementations are experimental \
896 and possibly buggy");
899 ast
::ItemKind
::Impl(_
, polarity
, _
, _
, _
, _
) => {
901 ast
::ImplPolarity
::Negative
=> {
902 gate_feature_post
!(&self, optin_builtin_traits
,
904 "negative trait bounds are not yet fully implemented; \
905 use marker types for now");
914 visit
::walk_item(self, i
);
917 fn visit_foreign_item(&mut self, i
: &ast
::ForeignItem
) {
918 let links_to_llvm
= match attr
::first_attr_value_str_by_name(&i
.attrs
,
920 Some(val
) => val
.starts_with("llvm."),
924 gate_feature_post
!(&self, link_llvm_intrinsics
, i
.span
,
925 "linking to LLVM intrinsics is experimental");
928 visit
::walk_foreign_item(self, i
)
931 fn visit_expr(&mut self, e
: &ast
::Expr
) {
933 ast
::ExprKind
::Box(_
) => {
934 gate_feature_post
!(&self, box_syntax
, e
.span
, EXPLAIN_BOX_SYNTAX
);
936 ast
::ExprKind
::Type(..) => {
937 gate_feature_post
!(&self, type_ascription
, e
.span
,
938 "type ascription is experimental");
940 ast
::ExprKind
::Range(_
, _
, ast
::RangeLimits
::Closed
) => {
941 gate_feature_post
!(&self, inclusive_range_syntax
,
943 "inclusive range syntax is experimental");
945 ast
::ExprKind
::Try(..) => {
946 gate_feature_post
!(&self, question_mark
, e
.span
, "the `?` operator is not stable");
948 ast
::ExprKind
::InPlace(..) => {
949 gate_feature_post
!(&self, placement_in_syntax
, e
.span
, EXPLAIN_PLACEMENT_IN
);
953 visit
::walk_expr(self, e
);
956 fn visit_pat(&mut self, pattern
: &ast
::Pat
) {
958 PatKind
::Vec(_
, Some(_
), ref last
) if !last
.is_empty() => {
959 gate_feature_post
!(&self, advanced_slice_patterns
,
961 "multiple-element slice matches anywhere \
962 but at the end of a slice (e.g. \
963 `[0, ..xs, 0]`) are experimental")
965 PatKind
::Vec(..) => {
966 gate_feature_post
!(&self, slice_patterns
,
968 "slice pattern syntax is experimental");
970 PatKind
::Box(..) => {
971 gate_feature_post
!(&self, box_patterns
,
973 "box pattern syntax is experimental");
975 PatKind
::Tuple(_
, ddpos
)
976 if ddpos
.is_some() => {
977 gate_feature_post
!(&self, dotdot_in_tuple_patterns
,
979 "`..` in tuple patterns is experimental");
981 PatKind
::TupleStruct(_
, ref fields
, ddpos
)
982 if ddpos
.is_some() && !fields
.is_empty() => {
983 gate_feature_post
!(&self, dotdot_in_tuple_patterns
,
985 "`..` in tuple struct patterns is experimental");
987 PatKind
::TupleStruct(_
, ref fields
, ddpos
)
988 if ddpos
.is_none() && fields
.is_empty() => {
989 self.context
.span_handler
.struct_span_err(pattern
.span
,
990 "nullary enum variants are written with \
991 no trailing `( )`").emit();
995 visit
::walk_pat(self, pattern
)
998 fn visit_fn(&mut self,
1000 fn_decl
: &ast
::FnDecl
,
1004 // check for const fn declarations
1006 FnKind
::ItemFn(_
, _
, _
, ast
::Constness
::Const
, _
, _
) => {
1007 gate_feature_post
!(&self, const_fn
, span
, "const fn is unstable");
1010 // stability of const fn methods are covered in
1011 // visit_trait_item and visit_impl_item below; this is
1012 // because default methods don't pass through this
1018 FnKind
::ItemFn(_
, _
, _
, _
, abi
, _
) if abi
== Abi
::RustIntrinsic
=> {
1019 gate_feature_post
!(&self, intrinsics
,
1021 "intrinsics are subject to change")
1023 FnKind
::ItemFn(_
, _
, _
, _
, abi
, _
) |
1024 FnKind
::Method(_
, &ast
::MethodSig { abi, .. }
, _
) => match abi
{
1026 gate_feature_post
!(&self, unboxed_closures
, span
,
1027 "rust-call ABI is subject to change");
1029 Abi
::Vectorcall
=> {
1030 gate_feature_post
!(&self, abi_vectorcall
, span
,
1031 "vectorcall is experimental and subject to change");
1037 visit
::walk_fn(self, fn_kind
, fn_decl
, block
, span
);
1040 fn visit_trait_item(&mut self, ti
: &ast
::TraitItem
) {
1042 ast
::TraitItemKind
::Const(..) => {
1043 gate_feature_post
!(&self, associated_consts
,
1045 "associated constants are experimental")
1047 ast
::TraitItemKind
::Method(ref sig
, _
) => {
1048 if sig
.constness
== ast
::Constness
::Const
{
1049 gate_feature_post
!(&self, const_fn
, ti
.span
, "const fn is unstable");
1052 ast
::TraitItemKind
::Type(_
, Some(_
)) => {
1053 gate_feature_post
!(&self, associated_type_defaults
, ti
.span
,
1054 "associated type defaults are unstable");
1058 visit
::walk_trait_item(self, ti
);
1061 fn visit_impl_item(&mut self, ii
: &ast
::ImplItem
) {
1062 if ii
.defaultness
== ast
::Defaultness
::Default
{
1063 gate_feature_post
!(&self, specialization
,
1065 "specialization is unstable");
1069 ast
::ImplItemKind
::Const(..) => {
1070 gate_feature_post
!(&self, associated_consts
,
1072 "associated constants are experimental")
1074 ast
::ImplItemKind
::Method(ref sig
, _
) => {
1075 if sig
.constness
== ast
::Constness
::Const
{
1076 gate_feature_post
!(&self, const_fn
, ii
.span
, "const fn is unstable");
1081 visit
::walk_impl_item(self, ii
);
1084 fn visit_vis(&mut self, vis
: &ast
::Visibility
) {
1085 let span
= match *vis
{
1086 ast
::Visibility
::Crate(span
) => span
,
1087 ast
::Visibility
::Restricted { ref path, .. }
=> path
.span
,
1090 gate_feature_post
!(&self, pub_restricted
, span
, "`pub(restricted)` syntax is experimental");
1092 visit
::walk_vis(self, vis
)
1096 pub fn get_features(span_handler
: &Handler
, krate_attrs
: &[ast
::Attribute
]) -> Features
{
1097 let mut features
= Features
::new();
1099 for attr
in krate_attrs
{
1100 if !attr
.check_name("feature") {
1104 match attr
.meta_item_list() {
1106 span_err
!(span_handler
, attr
.span
, E0555
,
1107 "malformed feature attribute, expected #![feature(...)]");
1111 let name
= match mi
.node
{
1112 ast
::MetaItemKind
::Word(ref word
) => (*word
).clone(),
1114 span_err
!(span_handler
, mi
.span
, E0556
,
1115 "malformed feature, expected just one word");
1119 if let Some(&(_
, _
, _
, setter
)) = ACTIVE_FEATURES
.iter()
1120 .find(|& &(n
, _
, _
, _
)| name
== n
) {
1121 *(setter(&mut features
)) = true;
1123 else if let Some(&(_
, _
, _
)) = REMOVED_FEATURES
.iter()
1124 .find(|& &(n
, _
, _
)| name
== n
) {
1125 span_err
!(span_handler
, mi
.span
, E0557
, "feature has been removed");
1127 else if let Some(&(_
, _
, _
)) = ACCEPTED_FEATURES
.iter()
1128 .find(|& &(n
, _
, _
)| name
== n
) {
1129 features
.declared_stable_lang_features
.push((name
, mi
.span
));
1131 features
.declared_lib_features
.push((name
, mi
.span
));
1141 pub fn check_crate(krate
: &ast
::Crate
,
1143 features
: &Features
,
1144 plugin_attributes
: &[(String
, AttributeType
)],
1145 unstable
: UnstableFeatures
) {
1146 maybe_stage_features(&sess
.span_diagnostic
, krate
, unstable
);
1149 span_handler
: &sess
.span_diagnostic
,
1151 plugin_attributes
: plugin_attributes
,
1153 visit
::walk_crate(&mut PostExpansionVisitor { context: &ctx }
, krate
);
1156 #[derive(Clone, Copy)]
1157 pub enum UnstableFeatures
{
1158 /// Hard errors for unstable features are active, as on
1159 /// beta/stable channels.
1161 /// Allow features to me activated, as on nightly.
1163 /// Errors are bypassed for bootstrapping. This is required any time
1164 /// during the build that feature-related lints are set to warn or above
1165 /// because the build turns on warnings-as-errors and uses lots of unstable
1166 /// features. As a result, this is always required for building Rust itself.
1170 fn maybe_stage_features(span_handler
: &Handler
, krate
: &ast
::Crate
,
1171 unstable
: UnstableFeatures
) {
1172 let allow_features
= match unstable
{
1173 UnstableFeatures
::Allow
=> true,
1174 UnstableFeatures
::Disallow
=> false,
1175 UnstableFeatures
::Cheat
=> true
1177 if !allow_features
{
1178 for attr
in &krate
.attrs
{
1179 if attr
.check_name("feature") {
1180 let release_channel
= option_env
!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1181 span_err
!(span_handler
, attr
.span
, E0554
,
1182 "#[feature] may not be used on the {} release channel",