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