]> git.proxmox.com Git - rustc.git/blob - src/libsyntax/feature_gate.rs
27485ee65fcc037640e5309d2534d583e47e91da
[rustc.git] / src / libsyntax / feature_gate.rs
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.
4 //
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.
10
11 //! Feature gating
12 //!
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
16 //! enabled.
17 //!
18 //! Features are enabled in programs via the crate-level attributes of
19 //! `#![feature(...)]` with a comma-separated list of features.
20 //!
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
23 //! becomes stable.
24
25 use self::AttributeType::*;
26 use self::AttributeGate::*;
27
28 use abi::Abi;
29 use ast::{NodeId, PatKind};
30 use ast;
31 use attr;
32 use attr::AttrMetaMethods;
33 use codemap::CodeMap;
34 use syntax_pos::Span;
35 use errors::Handler;
36 use visit::{self, FnKind, Visitor};
37 use parse::ParseSess;
38 use parse::token::InternedString;
39
40 use std::ascii::AsciiExt;
41
42 macro_rules! setter {
43 ($field: ident) => {{
44 fn f(features: &mut Features) -> &mut bool {
45 &mut features.$field
46 }
47 f as fn(&mut Features) -> &mut bool
48 }}
49 }
50
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))),+
58 ];
59
60 /// A set of features to be used by later passes.
61 pub struct Features {
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),+
67 }
68
69 impl Features {
70 pub fn new() -> Features {
71 Features {
72 declared_stable_lang_features: Vec::new(),
73 declared_lib_features: Vec::new(),
74 $($feature: false),+
75 }
76 }
77 }
78 };
79
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)),+
84 ];
85 };
86
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)),+
91 ];
92 }
93 }
94
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
99 // stable (active).
100 // NB: The featureck.py script parses this information directly out of the source
101 // so take care when modifying it.
102
103 declare_features! (
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)),
112
113 // rustc internal, for now:
114 (active, intrinsics, "1.0.0", None),
115 (active, lang_items, "1.0.0", None),
116
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)),
121
122
123 // rustc internal
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)),
130
131 // rustc internal.
132 (active, pushpop_unsafe, "1.2.0", None),
133
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)),
146
147 // OIBIT specific features
148 (active, optin_builtin_traits, "1.0.0", Some(13231)),
149
150 // macro reexport needs more discussion and stabilization
151 (active, macro_reexport, "1.0.0", Some(29638)),
152
153 // Allows use of #[staged_api]
154 // rustc internal
155 (active, staged_api, "1.0.0", None),
156
157 // Allows using items which are missing stability attributes
158 // rustc internal
159 (active, unmarked_api, "1.0.0", None),
160
161 // Allows using #![no_core]
162 (active, no_core, "1.3.0", Some(29639)),
163
164 // Allows using `box` in patterns; RFC 469
165 (active, box_patterns, "1.0.0", Some(29641)),
166
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),
170
171 // Allows using the unsafe_destructor_blind_to_params attribute;
172 // RFC 1238
173 (active, dropck_parametricity, "1.3.0", Some(28498)),
174
175 // Allows the use of custom attributes; RFC 572
176 (active, custom_attribute, "1.0.0", Some(29642)),
177
178 // Allows the use of #[derive(Anything)] as sugar for
179 // #[derive_Anything].
180 (active, custom_derive, "1.0.0", Some(29644)),
181
182 // Allows the use of rustc_* attributes; RFC 572
183 (active, rustc_attrs, "1.0.0", Some(29642)),
184
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).
189 //
190 // rustc internal
191 (active, allow_internal_unstable, "1.0.0", None),
192
193 // #23121. Array patterns have some hazards yet.
194 (active, slice_patterns, "1.0.0", Some(23121)),
195
196 // Allows the definition of associated constants in `trait` or `impl`
197 // blocks.
198 (active, associated_consts, "1.0.0", Some(29646)),
199
200 // Allows the definition of `const fn` functions.
201 (active, const_fn, "1.2.0", Some(24111)),
202
203 // Allows indexing into constant arrays.
204 (active, const_indexing, "1.4.0", Some(29947)),
205
206 // Allows using #[prelude_import] on glob `use` items.
207 //
208 // rustc internal
209 (active, prelude_import, "1.2.0", None),
210
211 // Allows the definition recursive static items.
212 (active, static_recursion, "1.3.0", Some(29719)),
213
214 // Allows default type parameters to influence type inference.
215 (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
216
217 // Allows associated type defaults
218 (active, associated_type_defaults, "1.2.0", Some(29661)),
219
220 // Allows macros to appear in the type position.
221 (active, type_macros, "1.3.0", Some(27245)),
222
223 // allow `repr(simd)`, and importing the various simd intrinsics
224 (active, repr_simd, "1.4.0", Some(27731)),
225
226 // Allows cfg(target_feature = "...").
227 (active, cfg_target_feature, "1.4.0", Some(29717)),
228
229 // allow `extern "platform-intrinsic" { ... }`
230 (active, platform_intrinsics, "1.4.0", Some(27731)),
231
232 // allow `#[unwind]`
233 // rust runtime internal
234 (active, unwind_attributes, "1.4.0", None),
235
236 // allow the use of `#[naked]` on functions.
237 (active, naked_functions, "1.9.0", Some(32408)),
238
239 // allow `#[no_debug]`
240 (active, no_debug, "1.5.0", Some(29721)),
241
242 // allow `#[omit_gdb_pretty_printer_section]`
243 // rustc internal.
244 (active, omit_gdb_pretty_printer_section, "1.5.0", None),
245
246 // Allows cfg(target_vendor = "...").
247 (active, cfg_target_vendor, "1.5.0", Some(29718)),
248
249 // Allow attributes on expressions and non-item statements
250 (active, stmt_expr_attributes, "1.6.0", Some(15701)),
251
252 // allow using type ascription in expressions
253 (active, type_ascription, "1.6.0", Some(23416)),
254
255 // Allows cfg(target_thread_local)
256 (active, cfg_target_thread_local, "1.7.0", Some(29594)),
257
258 // rustc internal
259 (active, abi_vectorcall, "1.7.0", None),
260
261 // a...b and ...b
262 (active, inclusive_range_syntax, "1.7.0", Some(28237)),
263
264 // `expr?`
265 (active, question_mark, "1.9.0", Some(31436)),
266
267 // impl specialization (RFC 1210)
268 (active, specialization, "1.7.0", Some(31844)),
269
270 // pub(restricted) visibilities (RFC 1422)
271 (active, pub_restricted, "1.9.0", Some(32409)),
272
273 // Allow Drop types in statics/const functions (RFC 1440)
274 (active, drop_types_in_const, "1.9.0", Some(33156)),
275
276 // Allows cfg(target_has_atomic = "...").
277 (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
278
279 // Allows `..` in tuple (struct) patterns
280 (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627))
281 );
282
283 declare_features! (
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)
294 );
295
296 declare_features! (
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
314 // mean anything
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))
320 );
321 // (changing above list without updating src/doc/reference.md makes @cmr sad)
322
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
327 Normal,
328
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
332 Whitelisted,
333
334 /// Builtin attribute that is only allowed at the crate level
335 CrateLevel,
336 }
337
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),
342
343 /// Ungated attribute, can be used on all release channels
344 Ungated,
345 }
346
347 // fn() is not Debug
348 impl ::std::fmt::Debug for AttributeGate {
349 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
350 match *self {
351 Gated(ref name, ref expl, _) => write!(fmt, "Gated({}, {})", name, expl),
352 Ungated => write!(fmt, "Ungated")
353 }
354 }
355 }
356
357 macro_rules! cfg_fn {
358 ($field: ident) => {{
359 fn f(features: &Features) -> bool {
360 features.$field
361 }
362 f as fn(&Features) -> bool
363 }}
364 }
365
366 // Attributes that have a special meaning to rustc or rustdoc
367 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
368 // Normal attributes
369
370 ("warn", Normal, Ungated),
371 ("allow", Normal, Ungated),
372 ("forbid", Normal, Ungated),
373 ("deny", Normal, Ungated),
374
375 ("macro_reexport", Normal, Ungated),
376 ("macro_use", Normal, Ungated),
377 ("macro_export", Normal, Ungated),
378 ("plugin_registrar", Normal, Ungated),
379
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),
400
401 // RFC #1445.
402 ("structural_match", Whitelisted, Gated("structural_match",
403 "the semantics of constant patterns is \
404 not yet settled",
405 cfg_fn!(structural_match))),
406
407 // Not used any more, but we can't feature gate it
408 ("no_stack_check", Normal, Ungated),
409
410 ("plugin", CrateLevel, Gated("plugin",
411 "compiler plugins are experimental \
412 and possibly buggy",
413 cfg_fn!(plugin))),
414
415 ("no_std", CrateLevel, Ungated),
416 ("no_core", CrateLevel, Gated("no_core",
417 "no_core is experimental",
418 cfg_fn!(no_core))),
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",
425 cfg_fn!(linkage))),
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 \
430 model",
431 cfg_fn!(thread_local))),
432
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 \
443 feature",
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 \
452 feature",
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))),
512
513 ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
514 EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
515 cfg_fn!(allow_internal_unstable))),
516
517 ("fundamental", Whitelisted, Gated("fundamental",
518 "the `#[fundamental]` attribute \
519 is an experimental feature",
520 cfg_fn!(fundamental))),
521
522 ("linked_from", Normal, Gated("linked_from",
523 "the `#[linked_from]` attribute \
524 is an experimental feature",
525 cfg_fn!(linked_from))),
526
527 // FIXME: #14408 whitelist docs since rustdoc looks at them
528 ("doc", Whitelisted, Ungated),
529
530 // FIXME: #14406 these are processed in trans, which happens after the
531 // lint pass
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",
547 cfg_fn!(no_debug))),
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 \
551 suite",
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",
558 Normal,
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))),
565
566 // used in resolve
567 ("prelude_import", Whitelisted, Gated("prelude_import",
568 "`#[prelude_import]` is for use by rustc only",
569 cfg_fn!(prelude_import))),
570
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),
578
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",
584 cfg_fn!(reflect))),
585
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),
595 ];
596
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)),
604 ];
605
606 #[derive(Debug, Eq, PartialEq)]
607 pub struct GatedCfg {
608 span: Span,
609 index: usize,
610 }
611
612 impl GatedCfg {
613 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
614 let name = cfg.name();
615 GATED_CFGS.iter()
616 .position(|info| info.0 == name)
617 .map(|idx| {
618 GatedCfg {
619 span: cfg.span,
620 index: idx
621 }
622 })
623 }
624
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);
631 }
632 }
633 }
634
635 struct Context<'a> {
636 features: &'a Features,
637 span_handler: &'a Handler,
638 cm: &'a CodeMap,
639 plugin_attributes: &'a [(String, AttributeType)],
640 }
641
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);
649 }
650 }}
651 }
652
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)
656 }
657 }
658
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 {
664 if n == name {
665 if let &Gated(ref name, ref desc, ref has_feature) = gateage {
666 gate_feature_fn!(self, has_feature, attr.span, name, desc);
667 }
668 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
669 return;
670 }
671 }
672 for &(ref n, ref ty) in self.plugin_attributes {
673 if n == name {
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);
678 return;
679 }
680 }
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);
688 } else {
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
693 if !is_macro {
694 gate_feature!(self, custom_attribute, attr.span,
695 &format!("The attribute `{}` is currently \
696 unknown to the compiler and \
697 may have meaning \
698 added to it in the future",
699 name));
700 }
701 }
702 }
703 }
704
705 pub fn check_attribute(attr: &ast::Attribute, handler: &Handler,
706 cm: &CodeMap, features: &Features) {
707 let cx = Context {
708 features: features, span_handler: handler,
709 cm: cm, plugin_attributes: &[]
710 };
711 cx.check_attribute(attr, true);
712 }
713
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)
716 }
717
718 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
719 if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
720 let issue = info.2;
721 // FIXME (#28244): enforce that active features have issue numbers
722 // assert!(issue.is_some())
723 issue
724 } else {
725 // search in Accepted or Removed features
726 ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES.iter())
727 .find(|t| t.0 == feature)
728 .unwrap().2
729 }
730 }
731
732 pub enum GateIssue {
733 Language,
734 Library(Option<u32>)
735 }
736
737 pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIssue,
738 explain: &str) {
739 let issue = match issue {
740 GateIssue::Language => find_lang_feature_issue(feature),
741 GateIssue::Library(lib) => lib,
742 };
743
744 let mut err = if let Some(n) = issue {
745 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
746 } else {
747 diag.struct_span_err(span, explain)
748 };
749
750 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
751 if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() {
752 err.emit();
753 return;
754 }
755 err.help(&format!("add #![feature({})] to the \
756 crate attributes to enable",
757 feature));
758 err.emit();
759 }
760
761 const EXPLAIN_BOX_SYNTAX: &'static str =
762 "box expression syntax is experimental; you can call `Box::new` instead.";
763
764 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
765 "attributes on non-item statements and expressions are experimental.";
766
767 pub const EXPLAIN_ASM: &'static str =
768 "inline assembly is not stable enough for use and is subject to change";
769
770 pub const EXPLAIN_LOG_SYNTAX: &'static str =
771 "`log_syntax!` is not stable enough for use and is subject to change";
772
773 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
774 "`concat_idents` is not stable enough for use and is subject to change";
775
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";
780
781 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
782 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
783
784 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
785 "attributes of the form `#[derive_*]` are reserved for the compiler";
786
787 pub const EXPLAIN_PLACEMENT_IN: &'static str =
788 "placement-in expression syntax is experimental and subject to change.";
789
790 struct PostExpansionVisitor<'a> {
791 context: &'a Context<'a>,
792 }
793
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)
799 }
800 }}
801 }
802
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);
807 }
808 }
809
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.");
814 }
815 }
816
817 fn visit_item(&mut self, i: &ast::Item) {
818 match i.node {
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");
824 }
825 }
826
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")
833 }
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 \
841 and possibly buggy")
842 },
843 Abi::Vectorcall => {
844 gate_feature_post!(&self, abi_vectorcall, i.span,
845 "vectorcall is experimental and subject to change")
846 }
847 _ => ()
848 }
849 }
850
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");
855 }
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 \
860 over time");
861 }
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");
867 }
868 }
869
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");
877 }
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");
885
886 }
887 }
888 }
889 }
890 }
891
892 ast::ItemKind::DefaultImpl(..) => {
893 gate_feature_post!(&self, optin_builtin_traits,
894 i.span,
895 "default trait implementations are experimental \
896 and possibly buggy");
897 }
898
899 ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
900 match polarity {
901 ast::ImplPolarity::Negative => {
902 gate_feature_post!(&self, optin_builtin_traits,
903 i.span,
904 "negative trait bounds are not yet fully implemented; \
905 use marker types for now");
906 },
907 _ => {}
908 }
909 }
910
911 _ => {}
912 }
913
914 visit::walk_item(self, i);
915 }
916
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,
919 "link_name") {
920 Some(val) => val.starts_with("llvm."),
921 _ => false
922 };
923 if links_to_llvm {
924 gate_feature_post!(&self, link_llvm_intrinsics, i.span,
925 "linking to LLVM intrinsics is experimental");
926 }
927
928 visit::walk_foreign_item(self, i)
929 }
930
931 fn visit_expr(&mut self, e: &ast::Expr) {
932 match e.node {
933 ast::ExprKind::Box(_) => {
934 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
935 }
936 ast::ExprKind::Type(..) => {
937 gate_feature_post!(&self, type_ascription, e.span,
938 "type ascription is experimental");
939 }
940 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
941 gate_feature_post!(&self, inclusive_range_syntax,
942 e.span,
943 "inclusive range syntax is experimental");
944 }
945 ast::ExprKind::Try(..) => {
946 gate_feature_post!(&self, question_mark, e.span, "the `?` operator is not stable");
947 }
948 ast::ExprKind::InPlace(..) => {
949 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
950 }
951 _ => {}
952 }
953 visit::walk_expr(self, e);
954 }
955
956 fn visit_pat(&mut self, pattern: &ast::Pat) {
957 match pattern.node {
958 PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => {
959 gate_feature_post!(&self, advanced_slice_patterns,
960 pattern.span,
961 "multiple-element slice matches anywhere \
962 but at the end of a slice (e.g. \
963 `[0, ..xs, 0]`) are experimental")
964 }
965 PatKind::Vec(..) => {
966 gate_feature_post!(&self, slice_patterns,
967 pattern.span,
968 "slice pattern syntax is experimental");
969 }
970 PatKind::Box(..) => {
971 gate_feature_post!(&self, box_patterns,
972 pattern.span,
973 "box pattern syntax is experimental");
974 }
975 PatKind::Tuple(_, ddpos)
976 if ddpos.is_some() => {
977 gate_feature_post!(&self, dotdot_in_tuple_patterns,
978 pattern.span,
979 "`..` in tuple patterns is experimental");
980 }
981 PatKind::TupleStruct(_, ref fields, ddpos)
982 if ddpos.is_some() && !fields.is_empty() => {
983 gate_feature_post!(&self, dotdot_in_tuple_patterns,
984 pattern.span,
985 "`..` in tuple struct patterns is experimental");
986 }
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();
992 }
993 _ => {}
994 }
995 visit::walk_pat(self, pattern)
996 }
997
998 fn visit_fn(&mut self,
999 fn_kind: FnKind,
1000 fn_decl: &ast::FnDecl,
1001 block: &ast::Block,
1002 span: Span,
1003 _node_id: NodeId) {
1004 // check for const fn declarations
1005 match fn_kind {
1006 FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {
1007 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1008 }
1009 _ => {
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
1013 // point.
1014 }
1015 }
1016
1017 match fn_kind {
1018 FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
1019 gate_feature_post!(&self, intrinsics,
1020 span,
1021 "intrinsics are subject to change")
1022 }
1023 FnKind::ItemFn(_, _, _, _, abi, _) |
1024 FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => match abi {
1025 Abi::RustCall => {
1026 gate_feature_post!(&self, unboxed_closures, span,
1027 "rust-call ABI is subject to change");
1028 },
1029 Abi::Vectorcall => {
1030 gate_feature_post!(&self, abi_vectorcall, span,
1031 "vectorcall is experimental and subject to change");
1032 },
1033 _ => {}
1034 },
1035 _ => {}
1036 }
1037 visit::walk_fn(self, fn_kind, fn_decl, block, span);
1038 }
1039
1040 fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
1041 match ti.node {
1042 ast::TraitItemKind::Const(..) => {
1043 gate_feature_post!(&self, associated_consts,
1044 ti.span,
1045 "associated constants are experimental")
1046 }
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");
1050 }
1051 }
1052 ast::TraitItemKind::Type(_, Some(_)) => {
1053 gate_feature_post!(&self, associated_type_defaults, ti.span,
1054 "associated type defaults are unstable");
1055 }
1056 _ => {}
1057 }
1058 visit::walk_trait_item(self, ti);
1059 }
1060
1061 fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
1062 if ii.defaultness == ast::Defaultness::Default {
1063 gate_feature_post!(&self, specialization,
1064 ii.span,
1065 "specialization is unstable");
1066 }
1067
1068 match ii.node {
1069 ast::ImplItemKind::Const(..) => {
1070 gate_feature_post!(&self, associated_consts,
1071 ii.span,
1072 "associated constants are experimental")
1073 }
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");
1077 }
1078 }
1079 _ => {}
1080 }
1081 visit::walk_impl_item(self, ii);
1082 }
1083
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,
1088 _ => return,
1089 };
1090 gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental");
1091
1092 visit::walk_vis(self, vis)
1093 }
1094 }
1095
1096 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1097 let mut features = Features::new();
1098
1099 for attr in krate_attrs {
1100 if !attr.check_name("feature") {
1101 continue
1102 }
1103
1104 match attr.meta_item_list() {
1105 None => {
1106 span_err!(span_handler, attr.span, E0555,
1107 "malformed feature attribute, expected #![feature(...)]");
1108 }
1109 Some(list) => {
1110 for mi in list {
1111 let name = match mi.node {
1112 ast::MetaItemKind::Word(ref word) => (*word).clone(),
1113 _ => {
1114 span_err!(span_handler, mi.span, E0556,
1115 "malformed feature, expected just one word");
1116 continue
1117 }
1118 };
1119 if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1120 .find(|& &(n, _, _, _)| name == n) {
1121 *(setter(&mut features)) = true;
1122 }
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");
1126 }
1127 else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1128 .find(|& &(n, _, _)| name == n) {
1129 features.declared_stable_lang_features.push((name, mi.span));
1130 } else {
1131 features.declared_lib_features.push((name, mi.span));
1132 }
1133 }
1134 }
1135 }
1136 }
1137
1138 features
1139 }
1140
1141 pub fn check_crate(krate: &ast::Crate,
1142 sess: &ParseSess,
1143 features: &Features,
1144 plugin_attributes: &[(String, AttributeType)],
1145 unstable: UnstableFeatures) {
1146 maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1147 let ctx = Context {
1148 features: features,
1149 span_handler: &sess.span_diagnostic,
1150 cm: sess.codemap(),
1151 plugin_attributes: plugin_attributes,
1152 };
1153 visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1154 }
1155
1156 #[derive(Clone, Copy)]
1157 pub enum UnstableFeatures {
1158 /// Hard errors for unstable features are active, as on
1159 /// beta/stable channels.
1160 Disallow,
1161 /// Allow features to me activated, as on nightly.
1162 Allow,
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.
1167 Cheat
1168 }
1169
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
1176 };
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",
1183 release_channel);
1184 }
1185 }
1186 }
1187 }