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