]> git.proxmox.com Git - rustc.git/blob - src/libsyntax/feature_gate.rs
New upstream version 1.13.0+dfsg1
[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::{self, NodeId, PatKind};
30 use attr;
31 use codemap::{CodeMap, Spanned};
32 use syntax_pos::Span;
33 use errors::Handler;
34 use visit::{self, FnKind, Visitor};
35 use parse::ParseSess;
36 use parse::token::InternedString;
37
38 use std::ascii::AsciiExt;
39 use std::env;
40
41 macro_rules! setter {
42 ($field: ident) => {{
43 fn f(features: &mut Features) -> &mut bool {
44 &mut features.$field
45 }
46 f as fn(&mut Features) -> &mut bool
47 }}
48 }
49
50 macro_rules! declare_features {
51 ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => {
52 /// Represents active features that are currently being implemented or
53 /// currently being considered for addition/removal.
54 const ACTIVE_FEATURES: &'static [(&'static str, &'static str,
55 Option<u32>, fn(&mut Features) -> &mut bool)] = &[
56 $((stringify!($feature), $ver, $issue, setter!($feature))),+
57 ];
58
59 /// A set of features to be used by later passes.
60 pub struct Features {
61 /// #![feature] attrs for stable language features, for error reporting
62 pub declared_stable_lang_features: Vec<(InternedString, Span)>,
63 /// #![feature] attrs for non-language (library) features
64 pub declared_lib_features: Vec<(InternedString, Span)>,
65 $(pub $feature: bool),+
66 }
67
68 impl Features {
69 pub fn new() -> Features {
70 Features {
71 declared_stable_lang_features: Vec::new(),
72 declared_lib_features: Vec::new(),
73 $($feature: false),+
74 }
75 }
76 }
77 };
78
79 ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
80 /// Represents features which has since been removed (it was once Active)
81 const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
82 $((stringify!($feature), $ver, $issue)),+
83 ];
84 };
85
86 ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => {
87 /// Those language feature has since been Accepted (it was once Active)
88 const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
89 $((stringify!($feature), $ver, $issue)),+
90 ];
91 }
92 }
93
94 // If you change this list without updating src/doc/reference.md, @cmr will be sad
95 // Don't ever remove anything from this list; set them to 'Removed'.
96 // The version numbers here correspond to the version in which the current status
97 // was set. This is most important for knowing when a particular feature became
98 // stable (active).
99 // NB: The featureck.py script parses this information directly out of the source
100 // so take care when modifying it.
101
102 declare_features! (
103 (active, asm, "1.0.0", Some(29722)),
104 (active, concat_idents, "1.0.0", Some(29599)),
105 (active, link_args, "1.0.0", Some(29596)),
106 (active, log_syntax, "1.0.0", Some(29598)),
107 (active, non_ascii_idents, "1.0.0", Some(28979)),
108 (active, plugin_registrar, "1.0.0", Some(29597)),
109 (active, thread_local, "1.0.0", Some(29594)),
110 (active, trace_macros, "1.0.0", Some(29598)),
111
112 // rustc internal, for now:
113 (active, intrinsics, "1.0.0", None),
114 (active, lang_items, "1.0.0", None),
115
116 (active, link_llvm_intrinsics, "1.0.0", Some(29602)),
117 (active, linkage, "1.0.0", Some(29603)),
118 (active, quote, "1.0.0", Some(29601)),
119 (active, simd, "1.0.0", Some(27731)),
120
121
122 // rustc internal
123 (active, rustc_diagnostic_macros, "1.0.0", None),
124 (active, advanced_slice_patterns, "1.0.0", Some(23121)),
125 (active, box_syntax, "1.0.0", Some(27779)),
126 (active, placement_in_syntax, "1.0.0", Some(27779)),
127 (active, reflect, "1.0.0", Some(27749)),
128 (active, unboxed_closures, "1.0.0", Some(29625)),
129
130 // rustc internal.
131 (active, pushpop_unsafe, "1.2.0", None),
132
133 (active, allocator, "1.0.0", Some(27389)),
134 (active, fundamental, "1.0.0", Some(29635)),
135 (active, linked_from, "1.3.0", Some(29629)),
136 (active, main, "1.0.0", Some(29634)),
137 (active, needs_allocator, "1.4.0", Some(27389)),
138 (active, on_unimplemented, "1.0.0", Some(29628)),
139 (active, plugin, "1.0.0", Some(29597)),
140 (active, simd_ffi, "1.0.0", Some(27731)),
141 (active, start, "1.0.0", Some(29633)),
142 (active, structural_match, "1.8.0", Some(31434)),
143 (active, panic_runtime, "1.10.0", Some(32837)),
144 (active, needs_panic_runtime, "1.10.0", Some(32837)),
145
146 // OIBIT specific features
147 (active, optin_builtin_traits, "1.0.0", Some(13231)),
148
149 // macro reexport needs more discussion and stabilization
150 (active, macro_reexport, "1.0.0", Some(29638)),
151
152 // Allows use of #[staged_api]
153 // rustc internal
154 (active, staged_api, "1.0.0", None),
155
156 // Allows using items which are missing stability attributes
157 // rustc internal
158 (active, unmarked_api, "1.0.0", None),
159
160 // Allows using #![no_core]
161 (active, no_core, "1.3.0", Some(29639)),
162
163 // Allows using `box` in patterns; RFC 469
164 (active, box_patterns, "1.0.0", Some(29641)),
165
166 // Allows using the unsafe_destructor_blind_to_params attribute;
167 // RFC 1238
168 (active, dropck_parametricity, "1.3.0", Some(28498)),
169
170 // Allows the use of custom attributes; RFC 572
171 (active, custom_attribute, "1.0.0", Some(29642)),
172
173 // Allows the use of #[derive(Anything)] as sugar for
174 // #[derive_Anything].
175 (active, custom_derive, "1.0.0", Some(29644)),
176
177 // Allows the use of rustc_* attributes; RFC 572
178 (active, rustc_attrs, "1.0.0", Some(29642)),
179
180 // Allows the use of #[allow_internal_unstable]. This is an
181 // attribute on macro_rules! and can't use the attribute handling
182 // below (it has to be checked before expansion possibly makes
183 // macros disappear).
184 //
185 // rustc internal
186 (active, allow_internal_unstable, "1.0.0", None),
187
188 // #23121. Array patterns have some hazards yet.
189 (active, slice_patterns, "1.0.0", Some(23121)),
190
191 // Allows the definition of associated constants in `trait` or `impl`
192 // blocks.
193 (active, associated_consts, "1.0.0", Some(29646)),
194
195 // Allows the definition of `const fn` functions.
196 (active, const_fn, "1.2.0", Some(24111)),
197
198 // Allows indexing into constant arrays.
199 (active, const_indexing, "1.4.0", Some(29947)),
200
201 // Allows using #[prelude_import] on glob `use` items.
202 //
203 // rustc internal
204 (active, prelude_import, "1.2.0", None),
205
206 // Allows the definition recursive static items.
207 (active, static_recursion, "1.3.0", Some(29719)),
208
209 // Allows default type parameters to influence type inference.
210 (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
211
212 // Allows associated type defaults
213 (active, associated_type_defaults, "1.2.0", Some(29661)),
214
215 // allow `repr(simd)`, and importing the various simd intrinsics
216 (active, repr_simd, "1.4.0", Some(27731)),
217
218 // Allows cfg(target_feature = "...").
219 (active, cfg_target_feature, "1.4.0", Some(29717)),
220
221 // allow `extern "platform-intrinsic" { ... }`
222 (active, platform_intrinsics, "1.4.0", Some(27731)),
223
224 // allow `#[unwind]`
225 // rust runtime internal
226 (active, unwind_attributes, "1.4.0", None),
227
228 // allow the use of `#[naked]` on functions.
229 (active, naked_functions, "1.9.0", Some(32408)),
230
231 // allow `#[no_debug]`
232 (active, no_debug, "1.5.0", Some(29721)),
233
234 // allow `#[omit_gdb_pretty_printer_section]`
235 // rustc internal.
236 (active, omit_gdb_pretty_printer_section, "1.5.0", None),
237
238 // Allows cfg(target_vendor = "...").
239 (active, cfg_target_vendor, "1.5.0", Some(29718)),
240
241 // Allow attributes on expressions and non-item statements
242 (active, stmt_expr_attributes, "1.6.0", Some(15701)),
243
244 // allow using type ascription in expressions
245 (active, type_ascription, "1.6.0", Some(23416)),
246
247 // Allows cfg(target_thread_local)
248 (active, cfg_target_thread_local, "1.7.0", Some(29594)),
249
250 // rustc internal
251 (active, abi_vectorcall, "1.7.0", None),
252
253 // a...b and ...b
254 (active, inclusive_range_syntax, "1.7.0", Some(28237)),
255
256 // impl specialization (RFC 1210)
257 (active, specialization, "1.7.0", Some(31844)),
258
259 // pub(restricted) visibilities (RFC 1422)
260 (active, pub_restricted, "1.9.0", Some(32409)),
261
262 // Allow Drop types in statics/const functions (RFC 1440)
263 (active, drop_types_in_const, "1.9.0", Some(33156)),
264
265 // Allows cfg(target_has_atomic = "...").
266 (active, cfg_target_has_atomic, "1.9.0", Some(32976)),
267
268 // Allows `..` in tuple (struct) patterns
269 (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627)),
270
271 // Allows `impl Trait` in function return types.
272 (active, conservative_impl_trait, "1.12.0", Some(34511)),
273
274 // Allows tuple structs and variants in more contexts,
275 // Permits numeric fields in struct expressions and patterns.
276 (active, relaxed_adts, "1.12.0", Some(35626)),
277
278 // The `!` type
279 (active, never_type, "1.13.0", Some(35121)),
280
281 // Allows all literals in attribute lists and values of key-value pairs.
282 (active, attr_literals, "1.13.0", Some(34981)),
283
284 // Allows the sysV64 ABI to be specified on all platforms
285 // instead of just the platforms on which it is the C ABI
286 (active, abi_sysv64, "1.13.0", Some(36167)),
287
288 // Use the import semantics from RFC 1560.
289 (active, item_like_imports, "1.13.0", Some(35120)),
290
291 // Macros 1.1
292 (active, rustc_macro, "1.13.0", Some(35900)),
293
294 // Allows untagged unions `union U { ... }`
295 (active, untagged_unions, "1.13.0", Some(32836)),
296
297 // elide `'static` lifetimes in `static`s and `const`s
298 (active, static_in_const, "1.13.0", Some(35897)),
299
300 // Used to identify the `compiler_builtins` crate
301 // rustc internal
302 (active, compiler_builtins, "1.13.0", None),
303 );
304
305 declare_features! (
306 (removed, import_shadowing, "1.0.0", None),
307 (removed, managed_boxes, "1.0.0", None),
308 // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
309 (removed, negate_unsigned, "1.0.0", Some(29645)),
310 // A way to temporarily opt out of opt in copy. This will *never* be accepted.
311 (removed, opt_out_copy, "1.0.0", None),
312 (removed, quad_precision_float, "1.0.0", None),
313 (removed, struct_inherit, "1.0.0", None),
314 (removed, test_removed_feature, "1.0.0", None),
315 (removed, visible_private_types, "1.0.0", None),
316 (removed, unsafe_no_drop_flag, "1.0.0", None),
317 );
318
319 declare_features! (
320 (accepted, associated_types, "1.0.0", None),
321 // allow overloading augmented assignment operations like `a += b`
322 (accepted, augmented_assignments, "1.8.0", Some(28235)),
323 // allow empty structs and enum variants with braces
324 (accepted, braced_empty_structs, "1.8.0", Some(29720)),
325 (accepted, default_type_params, "1.0.0", None),
326 (accepted, globs, "1.0.0", None),
327 (accepted, if_let, "1.0.0", None),
328 // A temporary feature gate used to enable parser extensions needed
329 // to bootstrap fix for #5723.
330 (accepted, issue_5723_bootstrap, "1.0.0", None),
331 (accepted, macro_rules, "1.0.0", None),
332 // Allows using #![no_std]
333 (accepted, no_std, "1.6.0", None),
334 (accepted, slicing_syntax, "1.0.0", None),
335 (accepted, struct_variant, "1.0.0", None),
336 // These are used to test this portion of the compiler, they don't actually
337 // mean anything
338 (accepted, test_accepted_feature, "1.0.0", None),
339 (accepted, tuple_indexing, "1.0.0", None),
340 // Allows macros to appear in the type position.
341 (accepted, type_macros, "1.13.0", Some(27245)),
342 (accepted, while_let, "1.0.0", None),
343 // Allows `#[deprecated]` attribute
344 (accepted, deprecated, "1.9.0", Some(29935)),
345 // `expr?`
346 (accepted, question_mark, "1.14.0", Some(31436)),
347 );
348 // (changing above list without updating src/doc/reference.md makes @cmr sad)
349
350 #[derive(PartialEq, Copy, Clone, Debug)]
351 pub enum AttributeType {
352 /// Normal, builtin attribute that is consumed
353 /// by the compiler before the unused_attribute check
354 Normal,
355
356 /// Builtin attribute that may not be consumed by the compiler
357 /// before the unused_attribute check. These attributes
358 /// will be ignored by the unused_attribute lint
359 Whitelisted,
360
361 /// Builtin attribute that is only allowed at the crate level
362 CrateLevel,
363 }
364
365 pub enum AttributeGate {
366 /// Is gated by a given feature gate, reason
367 /// and function to check if enabled
368 Gated(&'static str, &'static str, fn(&Features) -> bool),
369
370 /// Ungated attribute, can be used on all release channels
371 Ungated,
372 }
373
374 // fn() is not Debug
375 impl ::std::fmt::Debug for AttributeGate {
376 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
377 match *self {
378 Gated(ref name, ref expl, _) => write!(fmt, "Gated({}, {})", name, expl),
379 Ungated => write!(fmt, "Ungated")
380 }
381 }
382 }
383
384 macro_rules! cfg_fn {
385 ($field: ident) => {{
386 fn f(features: &Features) -> bool {
387 features.$field
388 }
389 f as fn(&Features) -> bool
390 }}
391 }
392
393 // Attributes that have a special meaning to rustc or rustdoc
394 pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
395 // Normal attributes
396
397 ("warn", Normal, Ungated),
398 ("allow", Normal, Ungated),
399 ("forbid", Normal, Ungated),
400 ("deny", Normal, Ungated),
401
402 ("macro_reexport", Normal, Ungated),
403 ("macro_use", Normal, Ungated),
404 ("macro_export", Normal, Ungated),
405 ("plugin_registrar", Normal, Ungated),
406
407 ("cfg", Normal, Ungated),
408 ("cfg_attr", Normal, Ungated),
409 ("main", Normal, Ungated),
410 ("start", Normal, Ungated),
411 ("test", Normal, Ungated),
412 ("bench", Normal, Ungated),
413 ("simd", Normal, Ungated),
414 ("repr", Normal, Ungated),
415 ("path", Normal, Ungated),
416 ("abi", Normal, Ungated),
417 ("automatically_derived", Normal, Ungated),
418 ("no_mangle", Normal, Ungated),
419 ("no_link", Normal, Ungated),
420 ("derive", Normal, Ungated),
421 ("should_panic", Normal, Ungated),
422 ("ignore", Normal, Ungated),
423 ("no_implicit_prelude", Normal, Ungated),
424 ("reexport_test_harness_main", Normal, Ungated),
425 ("link_args", Normal, Ungated),
426 ("macro_escape", Normal, Ungated),
427
428 // RFC #1445.
429 ("structural_match", Whitelisted, Gated("structural_match",
430 "the semantics of constant patterns is \
431 not yet settled",
432 cfg_fn!(structural_match))),
433
434 // Not used any more, but we can't feature gate it
435 ("no_stack_check", Normal, Ungated),
436
437 ("plugin", CrateLevel, Gated("plugin",
438 "compiler plugins are experimental \
439 and possibly buggy",
440 cfg_fn!(plugin))),
441
442 ("no_std", CrateLevel, Ungated),
443 ("no_core", CrateLevel, Gated("no_core",
444 "no_core is experimental",
445 cfg_fn!(no_core))),
446 ("lang", Normal, Gated("lang_items",
447 "language items are subject to change",
448 cfg_fn!(lang_items))),
449 ("linkage", Whitelisted, Gated("linkage",
450 "the `linkage` attribute is experimental \
451 and not portable across platforms",
452 cfg_fn!(linkage))),
453 ("thread_local", Whitelisted, Gated("thread_local",
454 "`#[thread_local]` is an experimental feature, and does \
455 not currently handle destructors. There is no \
456 corresponding `#[task_local]` mapping to the task \
457 model",
458 cfg_fn!(thread_local))),
459
460 ("rustc_on_unimplemented", Normal, Gated("on_unimplemented",
461 "the `#[rustc_on_unimplemented]` attribute \
462 is an experimental feature",
463 cfg_fn!(on_unimplemented))),
464 ("allocator", Whitelisted, Gated("allocator",
465 "the `#[allocator]` attribute is an experimental feature",
466 cfg_fn!(allocator))),
467 ("needs_allocator", Normal, Gated("needs_allocator",
468 "the `#[needs_allocator]` \
469 attribute is an experimental \
470 feature",
471 cfg_fn!(needs_allocator))),
472 ("panic_runtime", Whitelisted, Gated("panic_runtime",
473 "the `#[panic_runtime]` attribute is \
474 an experimental feature",
475 cfg_fn!(panic_runtime))),
476 ("needs_panic_runtime", Whitelisted, Gated("needs_panic_runtime",
477 "the `#[needs_panic_runtime]` \
478 attribute is an experimental \
479 feature",
480 cfg_fn!(needs_panic_runtime))),
481 ("rustc_variance", Normal, Gated("rustc_attrs",
482 "the `#[rustc_variance]` attribute \
483 is just used for rustc unit tests \
484 and will never be stable",
485 cfg_fn!(rustc_attrs))),
486 ("rustc_error", Whitelisted, Gated("rustc_attrs",
487 "the `#[rustc_error]` attribute \
488 is just used for rustc unit tests \
489 and will never be stable",
490 cfg_fn!(rustc_attrs))),
491 ("rustc_if_this_changed", Whitelisted, Gated("rustc_attrs",
492 "the `#[rustc_if_this_changed]` attribute \
493 is just used for rustc unit tests \
494 and will never be stable",
495 cfg_fn!(rustc_attrs))),
496 ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs",
497 "the `#[rustc_if_this_changed]` attribute \
498 is just used for rustc unit tests \
499 and will never be stable",
500 cfg_fn!(rustc_attrs))),
501 ("rustc_dirty", Whitelisted, Gated("rustc_attrs",
502 "the `#[rustc_dirty]` attribute \
503 is just used for rustc unit tests \
504 and will never be stable",
505 cfg_fn!(rustc_attrs))),
506 ("rustc_clean", Whitelisted, Gated("rustc_attrs",
507 "the `#[rustc_clean]` attribute \
508 is just used for rustc unit tests \
509 and will never be stable",
510 cfg_fn!(rustc_attrs))),
511 ("rustc_metadata_dirty", Whitelisted, Gated("rustc_attrs",
512 "the `#[rustc_metadata_dirty]` attribute \
513 is just used for rustc unit tests \
514 and will never be stable",
515 cfg_fn!(rustc_attrs))),
516 ("rustc_metadata_clean", Whitelisted, Gated("rustc_attrs",
517 "the `#[rustc_metadata_clean]` attribute \
518 is just used for rustc unit tests \
519 and will never be stable",
520 cfg_fn!(rustc_attrs))),
521 ("rustc_partition_reused", Whitelisted, Gated("rustc_attrs",
522 "this attribute \
523 is just used for rustc unit tests \
524 and will never be stable",
525 cfg_fn!(rustc_attrs))),
526 ("rustc_partition_translated", Whitelisted, Gated("rustc_attrs",
527 "this attribute \
528 is just used for rustc unit tests \
529 and will never be stable",
530 cfg_fn!(rustc_attrs))),
531 ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs",
532 "internal rustc attributes will never be stable",
533 cfg_fn!(rustc_attrs))),
534 ("rustc_item_path", Whitelisted, Gated("rustc_attrs",
535 "internal rustc attributes will never be stable",
536 cfg_fn!(rustc_attrs))),
537 ("rustc_move_fragments", Normal, Gated("rustc_attrs",
538 "the `#[rustc_move_fragments]` attribute \
539 is just used for rustc unit tests \
540 and will never be stable",
541 cfg_fn!(rustc_attrs))),
542 ("rustc_mir", Whitelisted, Gated("rustc_attrs",
543 "the `#[rustc_mir]` attribute \
544 is just used for rustc unit tests \
545 and will never be stable",
546 cfg_fn!(rustc_attrs))),
547 ("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs",
548 "the `#[rustc_inherit_overflow_checks]` \
549 attribute is just used to control \
550 overflow checking behavior of several \
551 libcore functions that are inlined \
552 across crates and will never be stable",
553 cfg_fn!(rustc_attrs))),
554 ("compiler_builtins", Whitelisted, Gated("compiler_builtins",
555 "the `#[compiler_builtins]` attribute is used to \
556 identify the `compiler_builtins` crate which \
557 contains compiler-rt intrinsics and will never be \
558 stable",
559 cfg_fn!(compiler_builtins))),
560
561 ("allow_internal_unstable", Normal, Gated("allow_internal_unstable",
562 EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
563 cfg_fn!(allow_internal_unstable))),
564
565 ("fundamental", Whitelisted, Gated("fundamental",
566 "the `#[fundamental]` attribute \
567 is an experimental feature",
568 cfg_fn!(fundamental))),
569
570 ("linked_from", Normal, Gated("linked_from",
571 "the `#[linked_from]` attribute \
572 is an experimental feature",
573 cfg_fn!(linked_from))),
574
575 ("rustc_macro_derive", Normal, Gated("rustc_macro",
576 "the `#[rustc_macro_derive]` attribute \
577 is an experimental feature",
578 cfg_fn!(rustc_macro))),
579
580 ("rustc_copy_clone_marker", Whitelisted, Gated("rustc_attrs",
581 "internal implementation detail",
582 cfg_fn!(rustc_attrs))),
583
584 // FIXME: #14408 whitelist docs since rustdoc looks at them
585 ("doc", Whitelisted, Ungated),
586
587 // FIXME: #14406 these are processed in trans, which happens after the
588 // lint pass
589 ("cold", Whitelisted, Ungated),
590 ("naked", Whitelisted, Gated("naked_functions",
591 "the `#[naked]` attribute \
592 is an experimental feature",
593 cfg_fn!(naked_functions))),
594 ("export_name", Whitelisted, Ungated),
595 ("inline", Whitelisted, Ungated),
596 ("link", Whitelisted, Ungated),
597 ("link_name", Whitelisted, Ungated),
598 ("link_section", Whitelisted, Ungated),
599 ("no_builtins", Whitelisted, Ungated),
600 ("no_mangle", Whitelisted, Ungated),
601 ("no_debug", Whitelisted, Gated("no_debug",
602 "the `#[no_debug]` attribute \
603 is an experimental feature",
604 cfg_fn!(no_debug))),
605 ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
606 "the `#[omit_gdb_pretty_printer_section]` \
607 attribute is just used for the Rust test \
608 suite",
609 cfg_fn!(omit_gdb_pretty_printer_section))),
610 ("unsafe_destructor_blind_to_params",
611 Normal,
612 Gated("dropck_parametricity",
613 "unsafe_destructor_blind_to_params has unstable semantics \
614 and may be removed in the future",
615 cfg_fn!(dropck_parametricity))),
616 ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental",
617 cfg_fn!(unwind_attributes))),
618
619 // used in resolve
620 ("prelude_import", Whitelisted, Gated("prelude_import",
621 "`#[prelude_import]` is for use by rustc only",
622 cfg_fn!(prelude_import))),
623
624 // FIXME: #14407 these are only looked at on-demand so we can't
625 // guarantee they'll have already been checked
626 ("rustc_deprecated", Whitelisted, Ungated),
627 ("must_use", Whitelisted, Ungated),
628 ("stable", Whitelisted, Ungated),
629 ("unstable", Whitelisted, Ungated),
630 ("deprecated", Normal, Ungated),
631
632 ("rustc_paren_sugar", Normal, Gated("unboxed_closures",
633 "unboxed_closures are still evolving",
634 cfg_fn!(unboxed_closures))),
635 ("rustc_reflect_like", Whitelisted, Gated("reflect",
636 "defining reflective traits is still evolving",
637 cfg_fn!(reflect))),
638
639 // Crate level attributes
640 ("crate_name", CrateLevel, Ungated),
641 ("crate_type", CrateLevel, Ungated),
642 ("crate_id", CrateLevel, Ungated),
643 ("feature", CrateLevel, Ungated),
644 ("no_start", CrateLevel, Ungated),
645 ("no_main", CrateLevel, Ungated),
646 ("no_builtins", CrateLevel, Ungated),
647 ("recursion_limit", CrateLevel, Ungated),
648 ];
649
650 // cfg(...)'s that are feature gated
651 const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
652 // (name in cfg, feature, function to check if the feature is enabled)
653 ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
654 ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
655 ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
656 ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
657 ("rustc_macro", "rustc_macro", cfg_fn!(rustc_macro)),
658 ];
659
660 #[derive(Debug, Eq, PartialEq)]
661 pub struct GatedCfg {
662 span: Span,
663 index: usize,
664 }
665
666 impl GatedCfg {
667 pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
668 let name = cfg.name();
669 GATED_CFGS.iter()
670 .position(|info| info.0 == name)
671 .map(|idx| {
672 GatedCfg {
673 span: cfg.span,
674 index: idx
675 }
676 })
677 }
678
679 pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
680 let (cfg, feature, has_feature) = GATED_CFGS[self.index];
681 if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
682 let explain = format!("`cfg({})` is experimental and subject to change", cfg);
683 emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
684 }
685 }
686 }
687
688 struct Context<'a> {
689 features: &'a Features,
690 parse_sess: &'a ParseSess,
691 cm: &'a CodeMap,
692 plugin_attributes: &'a [(String, AttributeType)],
693 }
694
695 macro_rules! gate_feature_fn {
696 ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
697 let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
698 let has_feature: bool = has_feature(&$cx.features);
699 debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
700 if !has_feature && !cx.cm.span_allows_unstable(span) {
701 emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
702 }
703 }}
704 }
705
706 macro_rules! gate_feature {
707 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
708 gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
709 }
710 }
711
712 impl<'a> Context<'a> {
713 fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
714 debug!("check_attribute(attr = {:?})", attr);
715 let name = &*attr.name();
716 for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES {
717 if n == name {
718 if let &Gated(ref name, ref desc, ref has_feature) = gateage {
719 gate_feature_fn!(self, has_feature, attr.span, name, desc);
720 }
721 debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
722 return;
723 }
724 }
725 for &(ref n, ref ty) in self.plugin_attributes {
726 if n == name {
727 // Plugins can't gate attributes, so we don't check for it
728 // unlike the code above; we only use this loop to
729 // short-circuit to avoid the checks below
730 debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
731 return;
732 }
733 }
734 if name.starts_with("rustc_") {
735 gate_feature!(self, rustc_attrs, attr.span,
736 "unless otherwise specified, attributes \
737 with the prefix `rustc_` \
738 are reserved for internal compiler diagnostics");
739 } else if name.starts_with("derive_") {
740 gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
741 } else {
742 // Only run the custom attribute lint during regular
743 // feature gate checking. Macro gating runs
744 // before the plugin attributes are registered
745 // so we skip this then
746 if !is_macro {
747 gate_feature!(self, custom_attribute, attr.span,
748 &format!("The attribute `{}` is currently \
749 unknown to the compiler and \
750 may have meaning \
751 added to it in the future",
752 name));
753 }
754 }
755 }
756 }
757
758 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
759 cm: &CodeMap, features: &Features) {
760 let cx = Context {
761 features: features, parse_sess: parse_sess,
762 cm: cm, plugin_attributes: &[]
763 };
764 cx.check_attribute(attr, true);
765 }
766
767 pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
768 ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
769 }
770
771 fn find_lang_feature_issue(feature: &str) -> Option<u32> {
772 if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
773 let issue = info.2;
774 // FIXME (#28244): enforce that active features have issue numbers
775 // assert!(issue.is_some())
776 issue
777 } else {
778 // search in Accepted or Removed features
779 ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES.iter())
780 .find(|t| t.0 == feature)
781 .unwrap().2
782 }
783 }
784
785 pub enum GateIssue {
786 Language,
787 Library(Option<u32>)
788 }
789
790 pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
791 explain: &str) {
792 let diag = &sess.span_diagnostic;
793
794 let issue = match issue {
795 GateIssue::Language => find_lang_feature_issue(feature),
796 GateIssue::Library(lib) => lib,
797 };
798
799 let mut err = if let Some(n) = issue {
800 diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
801 } else {
802 diag.struct_span_err(span, explain)
803 };
804
805 // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
806 if sess.unstable_features.is_nightly_build() {
807 err.help(&format!("add #![feature({})] to the \
808 crate attributes to enable",
809 feature));
810 }
811
812 err.emit();
813 }
814
815 const EXPLAIN_BOX_SYNTAX: &'static str =
816 "box expression syntax is experimental; you can call `Box::new` instead.";
817
818 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
819 "attributes on non-item statements and expressions are experimental.";
820
821 pub const EXPLAIN_ASM: &'static str =
822 "inline assembly is not stable enough for use and is subject to change";
823
824 pub const EXPLAIN_LOG_SYNTAX: &'static str =
825 "`log_syntax!` is not stable enough for use and is subject to change";
826
827 pub const EXPLAIN_CONCAT_IDENTS: &'static str =
828 "`concat_idents` is not stable enough for use and is subject to change";
829
830 pub const EXPLAIN_TRACE_MACROS: &'static str =
831 "`trace_macros` is not stable enough for use and is subject to change";
832 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
833 "allow_internal_unstable side-steps feature gating and stability checks";
834
835 pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
836 "`#[derive]` for custom traits is not stable enough for use and is subject to change";
837
838 pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
839 "attributes of the form `#[derive_*]` are reserved for the compiler";
840
841 pub const EXPLAIN_PLACEMENT_IN: &'static str =
842 "placement-in expression syntax is experimental and subject to change.";
843
844 struct PostExpansionVisitor<'a> {
845 context: &'a Context<'a>,
846 }
847
848 macro_rules! gate_feature_post {
849 ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
850 let (cx, span) = ($cx, $span);
851 if !cx.context.cm.span_allows_unstable(span) {
852 gate_feature!(cx.context, $feature, span, $explain)
853 }
854 }}
855 }
856
857 impl<'a> PostExpansionVisitor<'a> {
858 fn check_abi(&self, abi: Abi, span: Span) {
859 match abi {
860 Abi::RustIntrinsic => {
861 gate_feature_post!(&self, intrinsics, span,
862 "intrinsics are subject to change");
863 },
864 Abi::PlatformIntrinsic => {
865 gate_feature_post!(&self, platform_intrinsics, span,
866 "platform intrinsics are experimental and possibly buggy");
867 },
868 Abi::Vectorcall => {
869 gate_feature_post!(&self, abi_vectorcall, span,
870 "vectorcall is experimental and subject to change");
871 },
872 Abi::RustCall => {
873 gate_feature_post!(&self, unboxed_closures, span,
874 "rust-call ABI is subject to change");
875 },
876 Abi::SysV64 => {
877 gate_feature_post!(&self, abi_sysv64, span,
878 "sysv64 ABI is experimental and subject to change");
879 },
880 _ => {}
881 }
882 }
883 }
884
885 fn contains_novel_literal(item: &ast::MetaItem) -> bool {
886 use ast::MetaItemKind::*;
887 use ast::NestedMetaItemKind::*;
888
889 match item.node {
890 Word(..) => false,
891 NameValue(_, ref lit) => !lit.node.is_str(),
892 List(_, ref list) => list.iter().any(|li| {
893 match li.node {
894 MetaItem(ref mi) => contains_novel_literal(&**mi),
895 Literal(_) => true,
896 }
897 }),
898 }
899 }
900
901 impl<'a> Visitor for PostExpansionVisitor<'a> {
902 fn visit_attribute(&mut self, attr: &ast::Attribute) {
903 if !self.context.cm.span_allows_unstable(attr.span) {
904 // check for gated attributes
905 self.context.check_attribute(attr, false);
906 }
907
908 if contains_novel_literal(&*(attr.node.value)) {
909 gate_feature_post!(&self, attr_literals, attr.span,
910 "non-string literals in attributes, or string \
911 literals in top-level positions, are experimental");
912 }
913 }
914
915 fn visit_name(&mut self, sp: Span, name: ast::Name) {
916 if !name.as_str().is_ascii() {
917 gate_feature_post!(&self, non_ascii_idents, sp,
918 "non-ascii idents are not fully supported.");
919 }
920 }
921
922 fn visit_item(&mut self, i: &ast::Item) {
923 match i.node {
924 ast::ItemKind::ExternCrate(_) => {
925 if attr::contains_name(&i.attrs[..], "macro_reexport") {
926 gate_feature_post!(&self, macro_reexport, i.span,
927 "macros reexports are experimental \
928 and possibly buggy");
929 }
930 }
931
932 ast::ItemKind::ForeignMod(ref foreign_module) => {
933 if attr::contains_name(&i.attrs[..], "link_args") {
934 gate_feature_post!(&self, link_args, i.span,
935 "the `link_args` attribute is not portable \
936 across platforms, it is recommended to \
937 use `#[link(name = \"foo\")]` instead")
938 }
939 self.check_abi(foreign_module.abi, i.span);
940 }
941
942 ast::ItemKind::Fn(..) => {
943 if attr::contains_name(&i.attrs[..], "plugin_registrar") {
944 gate_feature_post!(&self, plugin_registrar, i.span,
945 "compiler plugins are experimental and possibly buggy");
946 }
947 if attr::contains_name(&i.attrs[..], "start") {
948 gate_feature_post!(&self, start, i.span,
949 "a #[start] function is an experimental \
950 feature whose signature may change \
951 over time");
952 }
953 if attr::contains_name(&i.attrs[..], "main") {
954 gate_feature_post!(&self, main, i.span,
955 "declaration of a nonstandard #[main] \
956 function may change over time, for now \
957 a top-level `fn main()` is required");
958 }
959 }
960
961 ast::ItemKind::Struct(..) => {
962 if attr::contains_name(&i.attrs[..], "simd") {
963 gate_feature_post!(&self, simd, i.span,
964 "SIMD types are experimental and possibly buggy");
965 self.context.parse_sess.span_diagnostic.span_warn(i.span,
966 "the `#[simd]` attribute \
967 is deprecated, use \
968 `#[repr(simd)]` instead");
969 }
970 for attr in &i.attrs {
971 if attr.name() == "repr" {
972 for item in attr.meta_item_list().unwrap_or(&[]) {
973 if item.check_name("simd") {
974 gate_feature_post!(&self, repr_simd, i.span,
975 "SIMD types are experimental \
976 and possibly buggy");
977
978 }
979 }
980 }
981 }
982 }
983
984 ast::ItemKind::Union(..) => {
985 gate_feature_post!(&self, untagged_unions,
986 i.span,
987 "unions are unstable and possibly buggy");
988 }
989
990 ast::ItemKind::DefaultImpl(..) => {
991 gate_feature_post!(&self, optin_builtin_traits,
992 i.span,
993 "default trait implementations are experimental \
994 and possibly buggy");
995 }
996
997 ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
998 match polarity {
999 ast::ImplPolarity::Negative => {
1000 gate_feature_post!(&self, optin_builtin_traits,
1001 i.span,
1002 "negative trait bounds are not yet fully implemented; \
1003 use marker types for now");
1004 },
1005 _ => {}
1006 }
1007 }
1008
1009 _ => {}
1010 }
1011
1012 visit::walk_item(self, i);
1013 }
1014
1015 fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
1016 let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
1017 "link_name") {
1018 Some(val) => val.starts_with("llvm."),
1019 _ => false
1020 };
1021 if links_to_llvm {
1022 gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1023 "linking to LLVM intrinsics is experimental");
1024 }
1025
1026 visit::walk_foreign_item(self, i)
1027 }
1028
1029 fn visit_ty(&mut self, ty: &ast::Ty) {
1030 match ty.node {
1031 ast::TyKind::BareFn(ref bare_fn_ty) => {
1032 self.check_abi(bare_fn_ty.abi, ty.span);
1033 }
1034 ast::TyKind::ImplTrait(..) => {
1035 gate_feature_post!(&self, conservative_impl_trait, ty.span,
1036 "`impl Trait` is experimental");
1037 }
1038 ast::TyKind::Never => {
1039 gate_feature_post!(&self, never_type, ty.span,
1040 "The `!` type is experimental");
1041 },
1042 _ => {}
1043 }
1044 visit::walk_ty(self, ty)
1045 }
1046
1047 fn visit_fn_ret_ty(&mut self, ret_ty: &ast::FunctionRetTy) {
1048 if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
1049 match output_ty.node {
1050 ast::TyKind::Never => return,
1051 _ => (),
1052 };
1053 self.visit_ty(output_ty)
1054 }
1055 }
1056
1057 fn visit_expr(&mut self, e: &ast::Expr) {
1058 match e.node {
1059 ast::ExprKind::Box(_) => {
1060 gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1061 }
1062 ast::ExprKind::Type(..) => {
1063 gate_feature_post!(&self, type_ascription, e.span,
1064 "type ascription is experimental");
1065 }
1066 ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1067 gate_feature_post!(&self, inclusive_range_syntax,
1068 e.span,
1069 "inclusive range syntax is experimental");
1070 }
1071 ast::ExprKind::InPlace(..) => {
1072 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
1073 }
1074 _ => {}
1075 }
1076 visit::walk_expr(self, e);
1077 }
1078
1079 fn visit_pat(&mut self, pattern: &ast::Pat) {
1080 match pattern.node {
1081 PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => {
1082 gate_feature_post!(&self, advanced_slice_patterns,
1083 pattern.span,
1084 "multiple-element slice matches anywhere \
1085 but at the end of a slice (e.g. \
1086 `[0, ..xs, 0]`) are experimental")
1087 }
1088 PatKind::Vec(..) => {
1089 gate_feature_post!(&self, slice_patterns,
1090 pattern.span,
1091 "slice pattern syntax is experimental");
1092 }
1093 PatKind::Box(..) => {
1094 gate_feature_post!(&self, box_patterns,
1095 pattern.span,
1096 "box pattern syntax is experimental");
1097 }
1098 PatKind::Tuple(_, ddpos)
1099 if ddpos.is_some() => {
1100 gate_feature_post!(&self, dotdot_in_tuple_patterns,
1101 pattern.span,
1102 "`..` in tuple patterns is experimental");
1103 }
1104 PatKind::TupleStruct(_, ref fields, ddpos)
1105 if ddpos.is_some() && !fields.is_empty() => {
1106 gate_feature_post!(&self, dotdot_in_tuple_patterns,
1107 pattern.span,
1108 "`..` in tuple struct patterns is experimental");
1109 }
1110 PatKind::TupleStruct(_, ref fields, ddpos)
1111 if ddpos.is_none() && fields.is_empty() => {
1112 gate_feature_post!(&self, relaxed_adts, pattern.span,
1113 "empty tuple structs patterns are unstable");
1114 }
1115 _ => {}
1116 }
1117 visit::walk_pat(self, pattern)
1118 }
1119
1120 fn visit_fn(&mut self,
1121 fn_kind: FnKind,
1122 fn_decl: &ast::FnDecl,
1123 block: &ast::Block,
1124 span: Span,
1125 _node_id: NodeId) {
1126 // check for const fn declarations
1127 match fn_kind {
1128 FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _) => {
1129 gate_feature_post!(&self, const_fn, span, "const fn is unstable");
1130 }
1131 _ => {
1132 // stability of const fn methods are covered in
1133 // visit_trait_item and visit_impl_item below; this is
1134 // because default methods don't pass through this
1135 // point.
1136 }
1137 }
1138
1139 match fn_kind {
1140 FnKind::ItemFn(_, _, _, _, abi, _) |
1141 FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => {
1142 self.check_abi(abi, span);
1143 }
1144 _ => {}
1145 }
1146 visit::walk_fn(self, fn_kind, fn_decl, block, span);
1147 }
1148
1149 fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
1150 match ti.node {
1151 ast::TraitItemKind::Const(..) => {
1152 gate_feature_post!(&self, associated_consts,
1153 ti.span,
1154 "associated constants are experimental")
1155 }
1156 ast::TraitItemKind::Method(ref sig, ref block) => {
1157 if block.is_none() {
1158 self.check_abi(sig.abi, ti.span);
1159 }
1160 if sig.constness.node == ast::Constness::Const {
1161 gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
1162 }
1163 }
1164 ast::TraitItemKind::Type(_, Some(_)) => {
1165 gate_feature_post!(&self, associated_type_defaults, ti.span,
1166 "associated type defaults are unstable");
1167 }
1168 _ => {}
1169 }
1170 visit::walk_trait_item(self, ti);
1171 }
1172
1173 fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
1174 if ii.defaultness == ast::Defaultness::Default {
1175 gate_feature_post!(&self, specialization,
1176 ii.span,
1177 "specialization is unstable");
1178 }
1179
1180 match ii.node {
1181 ast::ImplItemKind::Const(..) => {
1182 gate_feature_post!(&self, associated_consts,
1183 ii.span,
1184 "associated constants are experimental")
1185 }
1186 ast::ImplItemKind::Method(ref sig, _) => {
1187 if sig.constness.node == ast::Constness::Const {
1188 gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
1189 }
1190 }
1191 _ => {}
1192 }
1193 visit::walk_impl_item(self, ii);
1194 }
1195
1196 fn visit_variant_data(&mut self, vdata: &ast::VariantData, _: ast::Ident,
1197 _: &ast::Generics, _: NodeId, span: Span) {
1198 if vdata.fields().is_empty() {
1199 if vdata.is_tuple() {
1200 gate_feature_post!(&self, relaxed_adts, span,
1201 "empty tuple structs and enum variants are unstable, \
1202 use unit structs and enum variants instead");
1203 }
1204 }
1205
1206 visit::walk_struct_def(self, vdata)
1207 }
1208
1209 fn visit_vis(&mut self, vis: &ast::Visibility) {
1210 let span = match *vis {
1211 ast::Visibility::Crate(span) => span,
1212 ast::Visibility::Restricted { ref path, .. } => path.span,
1213 _ => return,
1214 };
1215 gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental");
1216
1217 visit::walk_vis(self, vis)
1218 }
1219 }
1220
1221 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1222 let mut features = Features::new();
1223
1224 for attr in krate_attrs {
1225 if !attr.check_name("feature") {
1226 continue
1227 }
1228
1229 match attr.meta_item_list() {
1230 None => {
1231 span_err!(span_handler, attr.span, E0555,
1232 "malformed feature attribute, expected #![feature(...)]");
1233 }
1234 Some(list) => {
1235 for mi in list {
1236 let name = if let Some(word) = mi.word() {
1237 word.name()
1238 } else {
1239 span_err!(span_handler, mi.span, E0556,
1240 "malformed feature, expected just one word");
1241 continue
1242 };
1243
1244 if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
1245 .find(|& &(n, _, _, _)| name == n) {
1246 *(setter(&mut features)) = true;
1247 }
1248 else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
1249 .find(|& &(n, _, _)| name == n) {
1250 span_err!(span_handler, mi.span, E0557, "feature has been removed");
1251 }
1252 else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
1253 .find(|& &(n, _, _)| name == n) {
1254 features.declared_stable_lang_features.push((name, mi.span));
1255 } else {
1256 features.declared_lib_features.push((name, mi.span));
1257 }
1258 }
1259 }
1260 }
1261 }
1262
1263 features
1264 }
1265
1266 pub fn check_crate(krate: &ast::Crate,
1267 sess: &ParseSess,
1268 features: &Features,
1269 plugin_attributes: &[(String, AttributeType)],
1270 unstable: UnstableFeatures) {
1271 maybe_stage_features(&sess.span_diagnostic, krate, unstable);
1272 let ctx = Context {
1273 features: features,
1274 parse_sess: sess,
1275 cm: sess.codemap(),
1276 plugin_attributes: plugin_attributes,
1277 };
1278 visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
1279 }
1280
1281 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1282 pub enum UnstableFeatures {
1283 /// Hard errors for unstable features are active, as on
1284 /// beta/stable channels.
1285 Disallow,
1286 /// Allow features to me activated, as on nightly.
1287 Allow,
1288 /// Errors are bypassed for bootstrapping. This is required any time
1289 /// during the build that feature-related lints are set to warn or above
1290 /// because the build turns on warnings-as-errors and uses lots of unstable
1291 /// features. As a result, this is always required for building Rust itself.
1292 Cheat
1293 }
1294
1295 impl UnstableFeatures {
1296 pub fn from_environment() -> UnstableFeatures {
1297 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1298 let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1299 // Whether we should enable unstable features for bootstrapping
1300 let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
1301 match (disable_unstable_features, bootstrap) {
1302 (_, true) => UnstableFeatures::Cheat,
1303 (true, _) => UnstableFeatures::Disallow,
1304 (false, _) => UnstableFeatures::Allow
1305 }
1306 }
1307
1308 pub fn is_nightly_build(&self) -> bool {
1309 match *self {
1310 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1311 _ => false,
1312 }
1313 }
1314 }
1315
1316 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1317 unstable: UnstableFeatures) {
1318 let allow_features = match unstable {
1319 UnstableFeatures::Allow => true,
1320 UnstableFeatures::Disallow => false,
1321 UnstableFeatures::Cheat => true
1322 };
1323 if !allow_features {
1324 for attr in &krate.attrs {
1325 if attr.check_name("feature") {
1326 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
1327 span_err!(span_handler, attr.span, E0554,
1328 "#[feature] may not be used on the {} release channel",
1329 release_channel);
1330 }
1331 }
1332 }
1333 }