feature_gate.rs 61.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Feature gating
//!
L
Luke Gallagher 已提交
13
//! This module implements the gating necessary for preventing certain compiler
14 15 16 17 18
//! features from being used by default. This module will crawl a pre-expanded
//! AST to ensure that there are no features which are used that are not
//! enabled.
//!
//! Features are enabled in programs via the crate-level attributes of
19
//! `#![feature(...)]` with a comma-separated list of features.
B
Brian Anderson 已提交
20 21 22 23
//!
//! For the purpose of future feature-tracking, once code for detection of feature
//! gate usage is added, *do not remove it again* even once the feature
//! becomes stable.
G
GuillaumeGomez 已提交
24

25
use self::AttributeType::*;
26
use self::AttributeGate::*;
27

N
Niko Matsakis 已提交
28
use abi::Abi;
29
use ast::{self, NodeId, PatKind};
30
use attr;
31
use codemap::{CodeMap, Spanned};
32
use syntax_pos::Span;
33
use errors::{DiagnosticBuilder, Handler};
34
use visit::{self, FnKind, Visitor};
J
Jeffrey Seyfried 已提交
35
use parse::ParseSess;
36
use symbol::Symbol;
37

38
use std::ascii::AsciiExt;
T
Tim Neumann 已提交
39
use std::env;
40

41 42 43 44 45 46 47 48
macro_rules! setter {
    ($field: ident) => {{
        fn f(features: &mut Features) -> &mut bool {
            &mut features.$field
        }
        f as fn(&mut Features) -> &mut bool
    }}
}
49

50
macro_rules! declare_features {
51
    ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => {
52 53 54 55 56 57 58 59 60
        /// Represents active features that are currently being implemented or
        /// currently being considered for addition/removal.
        const ACTIVE_FEATURES: &'static [(&'static str, &'static str,
                                          Option<u32>, fn(&mut Features) -> &mut bool)] = &[
            $((stringify!($feature), $ver, $issue, setter!($feature))),+
        ];

        /// A set of features to be used by later passes.
        pub struct Features {
61
            /// #![feature] attrs for stable language features, for error reporting
62
            pub declared_stable_lang_features: Vec<(Symbol, Span)>,
63
            /// #![feature] attrs for non-language (library) features
64
            pub declared_lib_features: Vec<(Symbol, Span)>,
65 66
            $(pub $feature: bool),+
        }
67

68 69 70 71 72 73 74 75 76 77 78
        impl Features {
            pub fn new() -> Features {
                Features {
                    declared_stable_lang_features: Vec::new(),
                    declared_lib_features: Vec::new(),
                    $($feature: false),+
                }
            }
        }
    };

79
    ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => {
80 81 82 83 84 85
        /// Represents features which has since been removed (it was once Active)
        const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
            $((stringify!($feature), $ver, $issue)),+
        ];
    };

86
    ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => {
87 88 89 90 91
        /// Those language feature has since been Accepted (it was once Active)
        const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option<u32>)] = &[
            $((stringify!($feature), $ver, $issue)),+
        ];
    }
92 93
}

B
Brian Anderson 已提交
94 95 96 97 98
// If you change this list without updating src/doc/reference.md, @cmr will be sad
// Don't ever remove anything from this list; set them to 'Removed'.
// The version numbers here correspond to the version in which the current status
// was set. This is most important for knowing when a particular feature became
// stable (active).
99 100 101 102 103 104 105 106 107 108 109 110
// NB: The featureck.py script parses this information directly out of the source
// so take care when modifying it.

declare_features! (
    (active, asm, "1.0.0", Some(29722)),
    (active, concat_idents, "1.0.0", Some(29599)),
    (active, link_args, "1.0.0", Some(29596)),
    (active, log_syntax, "1.0.0", Some(29598)),
    (active, non_ascii_idents, "1.0.0", Some(28979)),
    (active, plugin_registrar, "1.0.0", Some(29597)),
    (active, thread_local, "1.0.0", Some(29594)),
    (active, trace_macros, "1.0.0", Some(29598)),
A
Aaron Turon 已提交
111 112

    // rustc internal, for now:
113 114
    (active, intrinsics, "1.0.0", None),
    (active, lang_items, "1.0.0", None),
115

116 117 118 119
    (active, link_llvm_intrinsics, "1.0.0", Some(29602)),
    (active, linkage, "1.0.0", Some(29603)),
    (active, quote, "1.0.0", Some(29601)),
    (active, simd, "1.0.0", Some(27731)),
120 121


A
Aaron Turon 已提交
122
    // rustc internal
123 124 125 126 127 128
    (active, rustc_diagnostic_macros, "1.0.0", None),
    (active, advanced_slice_patterns, "1.0.0", Some(23121)),
    (active, box_syntax, "1.0.0", Some(27779)),
    (active, placement_in_syntax, "1.0.0", Some(27779)),
    (active, reflect, "1.0.0", Some(27749)),
    (active, unboxed_closures, "1.0.0", Some(29625)),
A
Aaron Turon 已提交
129 130

    // rustc internal.
131 132 133 134 135 136 137 138 139 140 141
    (active, pushpop_unsafe, "1.2.0", None),

    (active, allocator, "1.0.0", Some(27389)),
    (active, fundamental, "1.0.0", Some(29635)),
    (active, main, "1.0.0", Some(29634)),
    (active, needs_allocator, "1.4.0", Some(27389)),
    (active, on_unimplemented, "1.0.0", Some(29628)),
    (active, plugin, "1.0.0", Some(29597)),
    (active, simd_ffi, "1.0.0", Some(27731)),
    (active, start, "1.0.0", Some(29633)),
    (active, structural_match, "1.8.0", Some(31434)),
142 143
    (active, panic_runtime, "1.10.0", Some(32837)),
    (active, needs_panic_runtime, "1.10.0", Some(32837)),
144

145
    // OIBIT specific features
146
    (active, optin_builtin_traits, "1.0.0", Some(13231)),
147

J
Joseph Crail 已提交
148
    // macro reexport needs more discussion and stabilization
149
    (active, macro_reexport, "1.0.0", Some(29638)),
150 151

    // Allows use of #[staged_api]
A
Aaron Turon 已提交
152
    // rustc internal
153
    (active, staged_api, "1.0.0", None),
154

A
Alex Crichton 已提交
155
    // Allows using #![no_core]
156
    (active, no_core, "1.3.0", Some(29639)),
A
Alex Crichton 已提交
157

158
    // Allows using `box` in patterns; RFC 469
159
    (active, box_patterns, "1.0.0", Some(29641)),
160

161 162
    // Allows using the unsafe_destructor_blind_to_params attribute;
    // RFC 1238
163
    (active, dropck_parametricity, "1.3.0", Some(28498)),
164

165 166 167
    // Allows using the may_dangle attribute; RFC 1327
    (active, dropck_eyepatch, "1.10.0", Some(34761)),

168
    // Allows the use of custom attributes; RFC 572
169
    (active, custom_attribute, "1.0.0", Some(29642)),
M
Manish Goregaokar 已提交
170

171 172
    // Allows the use of #[derive(Anything)] as sugar for
    // #[derive_Anything].
173
    (active, custom_derive, "1.0.0", Some(29644)),
174

M
Manish Goregaokar 已提交
175
    // Allows the use of rustc_* attributes; RFC 572
176
    (active, rustc_attrs, "1.0.0", Some(29642)),
H
Huon Wilson 已提交
177

178 179 180 181
    // Allows the use of #[allow_internal_unstable]. This is an
    // attribute on macro_rules! and can't use the attribute handling
    // below (it has to be checked before expansion possibly makes
    // macros disappear).
A
Aaron Turon 已提交
182 183
    //
    // rustc internal
184
    (active, allow_internal_unstable, "1.0.0", None),
185 186

    // #23121. Array patterns have some hazards yet.
187
    (active, slice_patterns, "1.0.0", Some(23121)),
188 189 190

    // Allows the definition of associated constants in `trait` or `impl`
    // blocks.
191
    (active, associated_consts, "1.0.0", Some(29646)),
N
Niko Matsakis 已提交
192 193

    // Allows the definition of `const fn` functions.
194
    (active, const_fn, "1.2.0", Some(24111)),
195

196
    // Allows indexing into constant arrays.
197
    (active, const_indexing, "1.4.0", Some(29947)),
198

199
    // Allows using #[prelude_import] on glob `use` items.
A
Aaron Turon 已提交
200 201
    //
    // rustc internal
202
    (active, prelude_import, "1.2.0", None),
203 204

    // Allows the definition recursive static items.
205
    (active, static_recursion, "1.3.0", Some(29719)),
B
Brian Anderson 已提交
206 207

    // Allows default type parameters to influence type inference.
208
    (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
209 210

    // Allows associated type defaults
211
    (active, associated_type_defaults, "1.2.0", Some(29661)),
J
Jared Roesch 已提交
212

213
    // allow `repr(simd)`, and importing the various simd intrinsics
214
    (active, repr_simd, "1.4.0", Some(27731)),
215 216

    // Allows cfg(target_feature = "...").
217
    (active, cfg_target_feature, "1.4.0", Some(29717)),
218 219

    // allow `extern "platform-intrinsic" { ... }`
220
    (active, platform_intrinsics, "1.4.0", Some(27731)),
221 222

    // allow `#[unwind]`
A
Aaron Turon 已提交
223
    // rust runtime internal
224
    (active, unwind_attributes, "1.4.0", None),
V
Vadim Petrochenkov 已提交
225

T
Ticki 已提交
226
    // allow the use of `#[naked]` on functions.
227
    (active, naked_functions, "1.9.0", Some(32408)),
228 229

    // allow `#[no_debug]`
230
    (active, no_debug, "1.5.0", Some(29721)),
231 232

    // allow `#[omit_gdb_pretty_printer_section]`
A
Aaron Turon 已提交
233
    // rustc internal.
234
    (active, omit_gdb_pretty_printer_section, "1.5.0", None),
235 236

    // Allows cfg(target_vendor = "...").
237
    (active, cfg_target_vendor, "1.5.0", Some(29718)),
238 239

    // Allow attributes on expressions and non-item statements
240
    (active, stmt_expr_attributes, "1.6.0", Some(15701)),
241 242

    // allow using type ascription in expressions
243
    (active, type_ascription, "1.6.0", Some(23416)),
244 245

    // Allows cfg(target_thread_local)
246
    (active, cfg_target_thread_local, "1.7.0", Some(29594)),
247 248

    // rustc internal
249
    (active, abi_vectorcall, "1.7.0", None),
A
Alex Burka 已提交
250 251

    // a...b and ...b
252
    (active, inclusive_range_syntax, "1.7.0", Some(28237)),
J
Jorge Aparicio 已提交
253

A
Aaron Turon 已提交
254
    // impl specialization (RFC 1210)
255
    (active, specialization, "1.7.0", Some(31844)),
256 257

    // pub(restricted) visibilities (RFC 1422)
258 259
    (active, pub_restricted, "1.9.0", Some(32409)),

260 261 262 263
    // Allow Drop types in statics/const functions (RFC 1440)
    (active, drop_types_in_const, "1.9.0", Some(33156)),

    // Allows cfg(target_has_atomic = "...").
264 265
    (active, cfg_target_has_atomic, "1.9.0", Some(32976)),

266
    // Allows `impl Trait` in function return types.
267 268 269
    (active, conservative_impl_trait, "1.12.0", Some(34511)),

    // Permits numeric fields in struct expressions and patterns.
270 271 272
    (active, relaxed_adts, "1.12.0", Some(35626)),

    // The `!` type
273 274 275
    (active, never_type, "1.13.0", Some(35121)),

    // Allows all literals in attribute lists and values of key-value pairs.
276 277 278 279
    (active, attr_literals, "1.13.0", Some(34981)),

    // Allows the sysV64 ABI to be specified on all platforms
    // instead of just the platforms on which it is the C ABI
280 281
    (active, abi_sysv64, "1.13.0", Some(36167)),

282
    // Macros 1.1
283
    (active, proc_macro, "1.13.0", Some(35900)),
284 285 286

    // Allows untagged unions `union U { ... }`
    (active, untagged_unions, "1.13.0", Some(32836)),
A
Andre Bogus 已提交
287 288 289

    // elide `'static` lifetimes in `static`s and `const`s
    (active, static_in_const, "1.13.0", Some(35897)),
290 291 292 293

    // Used to identify the `compiler_builtins` crate
    // rustc internal
    (active, compiler_builtins, "1.13.0", None),
294 295 296

    // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
    (active, generic_param_attrs, "1.11.0", Some(34761)),
297 298 299

    // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
    (active, field_init_shorthand, "1.14.0", Some(37340)),
300 301 302

    // The #![windows_subsystem] attribute
    (active, windows_subsystem, "1.14.0", Some(37499)),
303

304 305
    // Allows using `Self` and associated types in struct expressions and patterns.
    (active, more_struct_aliases, "1.14.0", Some(37544)),
306

G
Guillaume Gomez 已提交
307

308 309
    // Allows #[link(..., cfg(..))]
    (active, link_cfg, "1.14.0", Some(37406)),
310 311

    (active, use_extern_macros, "1.15.0", Some(35896)),
312 313 314

    // Allows `break {expr}` with a value inside `loop`s.
    (active, loop_break_value, "1.14.0", Some(37339)),
315 316 317

    // Allows #[target_feature(...)]
    (active, target_feature, "1.15.0", None),
G
Guillaume Gomez 已提交
318 319 320

    // Allow safe suggestions for potential type conversions.
    (active, safe_suggestion, "1.0.0", Some(37384)),
J
Jorge Aparicio 已提交
321 322 323

    // `extern "ptx-*" fn()`
    (active, abi_ptx, "1.15.0", None),
324 325 326

    // The `i128` type
    (active, i128_type, "1.15.0", Some(35118)),
327 328 329 330 331 332 333 334 335 336 337 338
);

declare_features! (
    (removed, import_shadowing, "1.0.0", None),
    (removed, managed_boxes, "1.0.0", None),
    // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
    (removed, negate_unsigned, "1.0.0", Some(29645)),
    // A way to temporarily opt out of opt in copy. This will *never* be accepted.
    (removed, opt_out_copy, "1.0.0", None),
    (removed, quad_precision_float, "1.0.0", None),
    (removed, struct_inherit, "1.0.0", None),
    (removed, test_removed_feature, "1.0.0", None),
339
    (removed, visible_private_types, "1.0.0", None),
340
    (removed, unsafe_no_drop_flag, "1.0.0", None),
341 342 343
    // Allows using items which are missing stability attributes
    // rustc internal
    (removed, unmarked_api, "1.0.0", None),
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
);

declare_features! (
    (accepted, associated_types, "1.0.0", None),
    // allow overloading augmented assignment operations like `a += b`
    (accepted, augmented_assignments, "1.8.0", Some(28235)),
    // allow empty structs and enum variants with braces
    (accepted, braced_empty_structs, "1.8.0", Some(29720)),
    (accepted, default_type_params, "1.0.0", None),
    (accepted, globs, "1.0.0", None),
    (accepted, if_let, "1.0.0", None),
    // A temporary feature gate used to enable parser extensions needed
    // to bootstrap fix for #5723.
    (accepted, issue_5723_bootstrap, "1.0.0", None),
    (accepted, macro_rules, "1.0.0", None),
    // Allows using #![no_std]
360
    (accepted, no_std, "1.6.0", None),
361 362 363 364 365 366
    (accepted, slicing_syntax, "1.0.0", None),
    (accepted, struct_variant, "1.0.0", None),
    // These are used to test this portion of the compiler, they don't actually
    // mean anything
    (accepted, test_accepted_feature, "1.0.0", None),
    (accepted, tuple_indexing, "1.0.0", None),
D
Daniele Baracchi 已提交
367 368
    // Allows macros to appear in the type position.
    (accepted, type_macros, "1.13.0", Some(27245)),
369 370
    (accepted, while_let, "1.0.0", None),
    // Allows `#[deprecated]` attribute
371
    (accepted, deprecated, "1.9.0", Some(29935)),
N
Nick Cameron 已提交
372
    // `expr?`
373
    (accepted, question_mark, "1.13.0", Some(31436)),
374 375
    // Allows `..` in tuple (struct) patterns
    (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
J
Jeffrey Seyfried 已提交
376
    (accepted, item_like_imports, "1.14.0", Some(35120)),
377
);
378
// (changing above list without updating src/doc/reference.md makes @cmr sad)
379

380 381 382 383 384
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum AttributeType {
    /// Normal, builtin attribute that is consumed
    /// by the compiler before the unused_attribute check
    Normal,
385

386 387 388 389
    /// Builtin attribute that may not be consumed by the compiler
    /// before the unused_attribute check. These attributes
    /// will be ignored by the unused_attribute lint
    Whitelisted,
390

391 392 393 394 395 396 397
    /// Builtin attribute that is only allowed at the crate level
    CrateLevel,
}

pub enum AttributeGate {
    /// Is gated by a given feature gate, reason
    /// and function to check if enabled
398
    Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
399 400 401 402 403

    /// Ungated attribute, can be used on all release channels
    Ungated,
}

N
Nick Cameron 已提交
404 405 406 407 408 409 410 411 412 413
impl AttributeGate {
    fn is_deprecated(&self) -> bool {
        match *self {
            Gated(Stability::Deprecated(_), ..) => true,
            _ => false,
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
414 415
pub enum Stability {
    Unstable,
N
Nick Cameron 已提交
416 417
    // Argument is tracking issue link.
    Deprecated(&'static str),
418 419
}

420 421 422 423
// fn() is not Debug
impl ::std::fmt::Debug for AttributeGate {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
N
Nick Cameron 已提交
424 425
            Gated(ref stab, ref name, ref expl, _) =>
                write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
426 427 428 429 430 431 432 433 434 435 436 437
            Ungated => write!(fmt, "Ungated")
        }
    }
}

macro_rules! cfg_fn {
    ($field: ident) => {{
        fn f(features: &Features) -> bool {
            features.$field
        }
        f as fn(&Features) -> bool
    }}
438 439
}

N
Nick Cameron 已提交
440
pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
441
    BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
N
Nick Cameron 已提交
442 443
}

444
// Attributes that have a special meaning to rustc or rustdoc
445
pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
446 447
    // Normal attributes

448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
    ("warn", Normal, Ungated),
    ("allow", Normal, Ungated),
    ("forbid", Normal, Ungated),
    ("deny", Normal, Ungated),

    ("macro_reexport", Normal, Ungated),
    ("macro_use", Normal, Ungated),
    ("macro_export", Normal, Ungated),
    ("plugin_registrar", Normal, Ungated),

    ("cfg", Normal, Ungated),
    ("cfg_attr", Normal, Ungated),
    ("main", Normal, Ungated),
    ("start", Normal, Ungated),
    ("test", Normal, Ungated),
    ("bench", Normal, Ungated),
    ("simd", Normal, Ungated),
    ("repr", Normal, Ungated),
    ("path", Normal, Ungated),
    ("abi", Normal, Ungated),
    ("automatically_derived", Normal, Ungated),
    ("no_mangle", Normal, Ungated),
    ("no_link", Normal, Ungated),
    ("derive", Normal, Ungated),
    ("should_panic", Normal, Ungated),
    ("ignore", Normal, Ungated),
    ("no_implicit_prelude", Normal, Ungated),
    ("reexport_test_harness_main", Normal, Ungated),
    ("link_args", Normal, Ungated),
    ("macro_escape", Normal, Ungated),
478

479
    // RFC #1445.
480 481
    ("structural_match", Whitelisted, Gated(Stability::Unstable,
                                            "structural_match",
482
                                            "the semantics of constant patterns is \
483 484
                                             not yet settled",
                                            cfg_fn!(structural_match))),
485

A
Alex Crichton 已提交
486
    // Not used any more, but we can't feature gate it
487 488
    ("no_stack_check", Normal, Ungated),

489 490
    ("plugin", CrateLevel, Gated(Stability::Unstable,
                                 "plugin",
491
                                 "compiler plugins are experimental \
492 493 494
                                  and possibly buggy",
                                 cfg_fn!(plugin))),

495
    ("no_std", CrateLevel, Ungated),
496 497
    ("no_core", CrateLevel, Gated(Stability::Unstable,
                                  "no_core",
498 499
                                  "no_core is experimental",
                                  cfg_fn!(no_core))),
500 501
    ("lang", Normal, Gated(Stability::Unstable,
                           "lang_items",
502 503
                           "language items are subject to change",
                           cfg_fn!(lang_items))),
504 505
    ("linkage", Whitelisted, Gated(Stability::Unstable,
                                   "linkage",
506
                                   "the `linkage` attribute is experimental \
507 508
                                    and not portable across platforms",
                                   cfg_fn!(linkage))),
509 510
    ("thread_local", Whitelisted, Gated(Stability::Unstable,
                                        "thread_local",
511 512 513
                                        "`#[thread_local]` is an experimental feature, and does \
                                         not currently handle destructors. There is no \
                                         corresponding `#[task_local]` mapping to the task \
514 515
                                         model",
                                        cfg_fn!(thread_local))),
516

517 518
    ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
                                             "on_unimplemented",
519
                                             "the `#[rustc_on_unimplemented]` attribute \
520 521
                                              is an experimental feature",
                                             cfg_fn!(on_unimplemented))),
522 523
    ("allocator", Whitelisted, Gated(Stability::Unstable,
                                     "allocator",
524 525
                                     "the `#[allocator]` attribute is an experimental feature",
                                     cfg_fn!(allocator))),
526 527
    ("needs_allocator", Normal, Gated(Stability::Unstable,
                                      "needs_allocator",
528 529
                                      "the `#[needs_allocator]` \
                                       attribute is an experimental \
530 531
                                       feature",
                                      cfg_fn!(needs_allocator))),
532 533
    ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
                                         "panic_runtime",
534 535 536
                                         "the `#[panic_runtime]` attribute is \
                                          an experimental feature",
                                         cfg_fn!(panic_runtime))),
537 538
    ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
                                               "needs_panic_runtime",
539 540 541 542
                                               "the `#[needs_panic_runtime]` \
                                                attribute is an experimental \
                                                feature",
                                               cfg_fn!(needs_panic_runtime))),
543 544
    ("rustc_variance", Normal, Gated(Stability::Unstable,
                                     "rustc_attrs",
545
                                     "the `#[rustc_variance]` attribute \
N
Niko Matsakis 已提交
546
                                      is just used for rustc unit tests \
547 548
                                      and will never be stable",
                                     cfg_fn!(rustc_attrs))),
549 550
    ("rustc_error", Whitelisted, Gated(Stability::Unstable,
                                       "rustc_attrs",
551
                                       "the `#[rustc_error]` attribute \
N
Niko Matsakis 已提交
552
                                        is just used for rustc unit tests \
553 554
                                        and will never be stable",
                                       cfg_fn!(rustc_attrs))),
555 556
    ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
                                                 "rustc_attrs",
557 558 559 560
                                                 "the `#[rustc_if_this_changed]` attribute \
                                                  is just used for rustc unit tests \
                                                  and will never be stable",
                                                 cfg_fn!(rustc_attrs))),
561 562
    ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
                                                      "rustc_attrs",
563 564 565 566
                                                      "the `#[rustc_if_this_changed]` attribute \
                                                       is just used for rustc unit tests \
                                                       and will never be stable",
                                                      cfg_fn!(rustc_attrs))),
567 568
    ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
                                       "rustc_attrs",
569 570
                                       "the `#[rustc_dirty]` attribute \
                                        is just used for rustc unit tests \
571 572
                                        and will never be stable",
                                       cfg_fn!(rustc_attrs))),
573 574
    ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
                                       "rustc_attrs",
575 576
                                       "the `#[rustc_clean]` attribute \
                                        is just used for rustc unit tests \
577 578
                                        and will never be stable",
                                       cfg_fn!(rustc_attrs))),
579 580
    ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
                                                "rustc_attrs",
581 582 583 584
                                                "the `#[rustc_metadata_dirty]` attribute \
                                                 is just used for rustc unit tests \
                                                 and will never be stable",
                                                 cfg_fn!(rustc_attrs))),
585 586
    ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
                                                "rustc_attrs",
587 588 589 590
                                                "the `#[rustc_metadata_clean]` attribute \
                                                 is just used for rustc unit tests \
                                                 and will never be stable",
                                                 cfg_fn!(rustc_attrs))),
591 592
    ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
                                                  "rustc_attrs",
593 594 595 596
                                                  "this attribute \
                                                   is just used for rustc unit tests \
                                                   and will never be stable",
                                                  cfg_fn!(rustc_attrs))),
597 598
    ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
                                                      "rustc_attrs",
599 600 601 602
                                                      "this attribute \
                                                       is just used for rustc unit tests \
                                                       and will never be stable",
                                                      cfg_fn!(rustc_attrs))),
603 604
    ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
                                             "rustc_attrs",
605 606
                                             "internal rustc attributes will never be stable",
                                             cfg_fn!(rustc_attrs))),
607 608
    ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
                                           "rustc_attrs",
609 610
                                           "internal rustc attributes will never be stable",
                                           cfg_fn!(rustc_attrs))),
611 612
    ("rustc_move_fragments", Normal, Gated(Stability::Unstable,
                                           "rustc_attrs",
613
                                           "the `#[rustc_move_fragments]` attribute \
N
Niko Matsakis 已提交
614
                                            is just used for rustc unit tests \
615 616
                                            and will never be stable",
                                           cfg_fn!(rustc_attrs))),
617 618
    ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
                                     "rustc_attrs",
619 620
                                     "the `#[rustc_mir]` attribute \
                                      is just used for rustc unit tests \
621 622
                                      and will never be stable",
                                     cfg_fn!(rustc_attrs))),
623 624
    ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
                                                         "rustc_attrs",
625 626 627 628 629 630
                                                         "the `#[rustc_inherit_overflow_checks]` \
                                                          attribute is just used to control \
                                                          overflow checking behavior of several \
                                                          libcore functions that are inlined \
                                                          across crates and will never be stable",
                                                          cfg_fn!(rustc_attrs))),
631 632
    ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
                                             "compiler_builtins",
633 634 635 636 637
                                             "the `#[compiler_builtins]` attribute is used to \
                                              identify the `compiler_builtins` crate which \
                                              contains compiler-rt intrinsics and will never be \
                                              stable",
                                          cfg_fn!(compiler_builtins))),
638

639 640
    ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
                                              "allow_internal_unstable",
641 642
                                              EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
                                              cfg_fn!(allow_internal_unstable))),
643

644 645
    ("fundamental", Whitelisted, Gated(Stability::Unstable,
                                       "fundamental",
646
                                       "the `#[fundamental]` attribute \
647 648
                                        is an experimental feature",
                                       cfg_fn!(fundamental))),
649

650 651
    ("proc_macro_derive", Normal, Gated(Stability::Unstable,
                                        "proc_macro",
652 653 654
                                        "the `#[proc_macro_derive]` attribute \
                                         is an experimental feature",
                                        cfg_fn!(proc_macro))),
655

656 657
    ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
                                                   "rustc_attrs",
658 659 660
                                                   "internal implementation detail",
                                                   cfg_fn!(rustc_attrs))),

661
    // FIXME: #14408 whitelist docs since rustdoc looks at them
662
    ("doc", Whitelisted, Ungated),
663 664 665

    // FIXME: #14406 these are processed in trans, which happens after the
    // lint pass
666
    ("cold", Whitelisted, Ungated),
667 668
    ("naked", Whitelisted, Gated(Stability::Unstable,
                                 "naked_functions",
T
Ticki 已提交
669
                                 "the `#[naked]` attribute \
670
                                  is an experimental feature",
671
                                 cfg_fn!(naked_functions))),
672 673 674 675
    ("target_feature", Whitelisted, Gated(
        Stability::Unstable, "target_feature",
        "the `#[target_feature]` attribute is an experimental feature",
        cfg_fn!(target_feature))),
676 677 678 679 680 681 682
    ("export_name", Whitelisted, Ungated),
    ("inline", Whitelisted, Ungated),
    ("link", Whitelisted, Ungated),
    ("link_name", Whitelisted, Ungated),
    ("link_section", Whitelisted, Ungated),
    ("no_builtins", Whitelisted, Ungated),
    ("no_mangle", Whitelisted, Ungated),
N
Nick Cameron 已提交
683 684 685 686 687
    ("no_debug", Whitelisted, Gated(
        Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
        "no_debug",
        "the `#[no_debug]` attribute is an experimental feature",
        cfg_fn!(no_debug))),
688 689
    ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
                                                       "omit_gdb_pretty_printer_section",
690 691
                                                       "the `#[omit_gdb_pretty_printer_section]` \
                                                        attribute is just used for the Rust test \
692 693
                                                        suite",
                                                       cfg_fn!(omit_gdb_pretty_printer_section))),
694 695
    ("unsafe_destructor_blind_to_params",
     Normal,
696 697
     Gated(Stability::Unstable,
           "dropck_parametricity",
698
           "unsafe_destructor_blind_to_params has unstable semantics \
699 700
            and may be removed in the future",
           cfg_fn!(dropck_parametricity))),
701 702
    ("may_dangle",
     Normal,
703 704
     Gated(Stability::Unstable,
           "dropck_eyepatch",
705 706
           "may_dangle has unstable semantics and may be removed in the future",
           cfg_fn!(dropck_eyepatch))),
707 708 709
    ("unwind", Whitelisted, Gated(Stability::Unstable,
                                  "unwind_attributes",
                                  "#[unwind] is experimental",
710
                                  cfg_fn!(unwind_attributes))),
711 712

    // used in resolve
713 714
    ("prelude_import", Whitelisted, Gated(Stability::Unstable,
                                          "prelude_import",
715 716
                                          "`#[prelude_import]` is for use by rustc only",
                                          cfg_fn!(prelude_import))),
717 718 719

    // FIXME: #14407 these are only looked at on-demand so we can't
    // guarantee they'll have already been checked
720
    ("rustc_deprecated", Whitelisted, Ungated),
721 722 723
    ("must_use", Whitelisted, Ungated),
    ("stable", Whitelisted, Ungated),
    ("unstable", Whitelisted, Ungated),
724
    ("deprecated", Normal, Ungated),
725

726 727
    ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
                                        "unboxed_closures",
728 729
                                        "unboxed_closures are still evolving",
                                        cfg_fn!(unboxed_closures))),
730 731
    ("rustc_reflect_like", Whitelisted, Gated(Stability::Unstable,
                                              "reflect",
732 733
                                              "defining reflective traits is still evolving",
                                              cfg_fn!(reflect))),
734

735 736 737
    ("windows_subsystem", Whitelisted, Gated(Stability::Unstable,
                                             "windows_subsystem",
                                             "the windows subsystem attribute \
A
Alex Crichton 已提交
738
                                              is currently unstable",
739 740
                                             cfg_fn!(windows_subsystem))),

741
    // Crate level attributes
742 743 744 745 746 747 748 749
    ("crate_name", CrateLevel, Ungated),
    ("crate_type", CrateLevel, Ungated),
    ("crate_id", CrateLevel, Ungated),
    ("feature", CrateLevel, Ungated),
    ("no_start", CrateLevel, Ungated),
    ("no_main", CrateLevel, Ungated),
    ("no_builtins", CrateLevel, Ungated),
    ("recursion_limit", CrateLevel, Ungated),
750
    ("type_length_limit", CrateLevel, Ungated),
751 752
];

753 754 755
// cfg(...)'s that are feature gated
const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
    // (name in cfg, feature, function to check if the feature is enabled)
756 757 758
    ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
    ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
    ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
759
    ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
760
    ("proc_macro", "proc_macro", cfg_fn!(proc_macro)),
761 762 763 764 765 766 767
];

#[derive(Debug, Eq, PartialEq)]
pub struct GatedCfg {
    span: Span,
    index: usize,
}
768

769 770
impl GatedCfg {
    pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
771
        let name = &*cfg.name().as_str();
772 773 774 775 776 777 778 779 780
        GATED_CFGS.iter()
                  .position(|info| info.0 == name)
                  .map(|idx| {
                      GatedCfg {
                          span: cfg.span,
                          index: idx
                      }
                  })
    }
J
Jeffrey Seyfried 已提交
781 782

    pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
783
        let (cfg, feature, has_feature) = GATED_CFGS[self.index];
J
Jeffrey Seyfried 已提交
784
        if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
785
            let explain = format!("`cfg({})` is experimental and subject to change", cfg);
786
            emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
787 788 789 790
        }
    }
}

E
Eduard Burtescu 已提交
791
struct Context<'a> {
L
Leo Testard 已提交
792
    features: &'a Features,
793
    parse_sess: &'a ParseSess,
C
Corey Richardson 已提交
794
    cm: &'a CodeMap,
795
    plugin_attributes: &'a [(String, AttributeType)],
796 797
}

798 799 800 801 802 803
macro_rules! gate_feature_fn {
    ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
        let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
        let has_feature: bool = has_feature(&$cx.features);
        debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
        if !has_feature && !cx.cm.span_allows_unstable(span) {
804
            emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
805
        }
806 807 808 809 810 811
    }}
}

macro_rules! gate_feature {
    ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
        gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain)
812
    }
813
}
814

815
impl<'a> Context<'a> {
816
    fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
817
        debug!("check_attribute(attr = {:?})", attr);
818
        let name = &*attr.name().as_str();
819
        for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
820
            if n == name {
821
                if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
822
                    gate_feature_fn!(self, has_feature, attr.span, name, desc);
823
                }
824
                debug!("check_attribute: {:?} is builtin, {:?}, {:?}", name, ty, gateage);
825 826 827
                return;
            }
        }
828
        for &(ref n, ref ty) in self.plugin_attributes {
829
            if n == name {
830
                // Plugins can't gate attributes, so we don't check for it
M
Manish Goregaokar 已提交
831 832
                // unlike the code above; we only use this loop to
                // short-circuit to avoid the checks below
833 834 835 836
                debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
                return;
            }
        }
837
        if name.starts_with("rustc_") {
838 839 840 841
            gate_feature!(self, rustc_attrs, attr.span,
                          "unless otherwise specified, attributes \
                           with the prefix `rustc_` \
                           are reserved for internal compiler diagnostics");
842
        } else if name.starts_with("derive_") {
L
Leo Testard 已提交
843
            gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
844 845
        } else if attr::is_known(attr) {
            debug!("check_attribute: {:?} is known", name);
846
        } else {
M
Manish Goregaokar 已提交
847 848 849 850
            // Only run the custom attribute lint during regular
            // feature gate checking. Macro gating runs
            // before the plugin attributes are registered
            // so we skip this then
851
            if !is_macro {
852 853 854 855 856 857
                gate_feature!(self, custom_attribute, attr.span,
                              &format!("The attribute `{}` is currently \
                                        unknown to the compiler and \
                                        may have meaning \
                                        added to it in the future",
                                       name));
858
            }
859 860
        }
    }
861 862
}

863
pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
L
Leo Testard 已提交
864 865
                       cm: &CodeMap, features: &Features) {
    let cx = Context {
866
        features: features, parse_sess: parse_sess,
L
Leo Testard 已提交
867 868 869 870 871
        cm: cm, plugin_attributes: &[]
    };
    cx.check_attribute(attr, true);
}

872 873 874 875
pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
    ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
}

876
fn find_lang_feature_issue(feature: &str) -> Option<u32> {
877 878
    if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
        let issue = info.2;
879 880
        // FIXME (#28244): enforce that active features have issue numbers
        // assert!(issue.is_some())
881 882 883 884 885 886
        issue
    } else {
        // search in Accepted or Removed features
        ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES.iter())
            .find(|t| t.0 == feature)
            .unwrap().2
887 888 889 890 891 892 893 894
    }
}

pub enum GateIssue {
    Language,
    Library(Option<u32>)
}

895
pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
896
                        explain: &str) {
897 898 899 900 901
    feature_err(sess, feature, span, issue, explain).emit();
}

pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
                   explain: &str) -> DiagnosticBuilder<'a> {
902 903
    let diag = &sess.span_diagnostic;

904 905 906 907 908
    let issue = match issue {
        GateIssue::Language => find_lang_feature_issue(feature),
        GateIssue::Library(lib) => lib,
    };

N
Nick Cameron 已提交
909 910
    let mut err = if let Some(n) = issue {
        diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
911
    } else {
N
Nick Cameron 已提交
912 913
        diag.struct_span_err(span, explain)
    };
914 915

    // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
T
Tim Neumann 已提交
916 917 918 919
    if sess.unstable_features.is_nightly_build() {
        err.help(&format!("add #![feature({})] to the \
                           crate attributes to enable",
                          feature));
N
Nick Cameron 已提交
920
    }
T
Tim Neumann 已提交
921

922
    err
923 924
}

L
Leo Testard 已提交
925 926 927
const EXPLAIN_BOX_SYNTAX: &'static str =
    "box expression syntax is experimental; you can call `Box::new` instead.";

J
Jeffrey Seyfried 已提交
928
pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
L
Leo Testard 已提交
929 930
    "attributes on non-item statements and expressions are experimental.";

931 932 933
pub const EXPLAIN_ASM: &'static str =
    "inline assembly is not stable enough for use and is subject to change";

934 935 936 937 938 939 940 941
pub const EXPLAIN_LOG_SYNTAX: &'static str =
    "`log_syntax!` is not stable enough for use and is subject to change";

pub const EXPLAIN_CONCAT_IDENTS: &'static str =
    "`concat_idents` is not stable enough for use and is subject to change";

pub const EXPLAIN_TRACE_MACROS: &'static str =
    "`trace_macros` is not stable enough for use and is subject to change";
942 943
pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
    "allow_internal_unstable side-steps feature gating and stability checks";
944

945
pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
N
Nick Cameron 已提交
946 947 948 949 950 951
    "`#[derive]` for custom traits is not stable enough for use. It is deprecated and will \
     be removed in v1.15";

pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str =
    "`#[derive]` for custom traits is deprecated and will be removed in v1.15. Prefer using \
     procedural macro custom derive";
952

L
Leo Testard 已提交
953 954
pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str =
    "attributes of the form `#[derive_*]` are reserved for the compiler";
955

L
Leo Testard 已提交
956 957
pub const EXPLAIN_PLACEMENT_IN: &'static str =
    "placement-in expression syntax is experimental and subject to change.";
C
Corey Richardson 已提交
958 959

struct PostExpansionVisitor<'a> {
N
Nick Cameron 已提交
960
    context: &'a Context<'a>,
C
Corey Richardson 已提交
961 962
}

963 964 965 966 967
macro_rules! gate_feature_post {
    ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
        let (cx, span) = ($cx, $span);
        if !cx.context.cm.span_allows_unstable(span) {
            gate_feature!(cx.context, $feature, span, $explain)
C
Corey Richardson 已提交
968
        }
969
    }}
C
Corey Richardson 已提交
970 971
}

972 973 974
impl<'a> PostExpansionVisitor<'a> {
    fn check_abi(&self, abi: Abi, span: Span) {
        match abi {
975
            Abi::RustIntrinsic => {
976
                gate_feature_post!(&self, intrinsics, span,
977 978
                                   "intrinsics are subject to change");
            },
979 980
            Abi::PlatformIntrinsic => {
                gate_feature_post!(&self, platform_intrinsics, span,
981
                                   "platform intrinsics are experimental and possibly buggy");
982 983 984
            },
            Abi::Vectorcall => {
                gate_feature_post!(&self, abi_vectorcall, span,
985 986
                                   "vectorcall is experimental and subject to change");
            },
987 988 989
            Abi::RustCall => {
                gate_feature_post!(&self, unboxed_closures, span,
                                   "rust-call ABI is subject to change");
990 991 992 993 994
            },
            Abi::SysV64 => {
                gate_feature_post!(&self, abi_sysv64, span,
                                   "sysv64 ABI is experimental and subject to change");
            },
J
Jorge Aparicio 已提交
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
            Abi::PtxKernel => {
                gate_feature_post!(&self, abi_ptx, span,
                                   "PTX ABIs are experimental and subject to change");
            }
            // Stable
            Abi::Cdecl |
            Abi::Stdcall |
            Abi::Fastcall |
            Abi::Aapcs |
            Abi::Win64 |
            Abi::Rust |
            Abi::C |
            Abi::System => {}
1008 1009 1010 1011
        }
    }
}

1012 1013 1014 1015 1016
fn contains_novel_literal(item: &ast::MetaItem) -> bool {
    use ast::MetaItemKind::*;
    use ast::NestedMetaItemKind::*;

    match item.node {
1017 1018 1019
        Word => false,
        NameValue(ref lit) => !lit.node.is_str(),
        List(ref list) => list.iter().any(|li| {
1020
            match li.node {
1021
                MetaItem(ref mi) => contains_novel_literal(&mi),
1022 1023 1024 1025 1026 1027
                Literal(_) => true,
            }
        }),
    }
}

1028 1029 1030 1031
fn starts_with_digit(s: &str) -> bool {
    s.as_bytes().first().cloned().map_or(false, |b| b >= b'0' && b <= b'9')
}

1032
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1033 1034
    fn visit_attribute(&mut self, attr: &ast::Attribute) {
        if !self.context.cm.span_allows_unstable(attr.span) {
1035
            // check for gated attributes
1036
            self.context.check_attribute(attr, false);
1037
        }
1038

1039
        if contains_novel_literal(&attr.value) {
1040 1041 1042 1043
            gate_feature_post!(&self, attr_literals, attr.span,
                               "non-string literals in attributes, or string \
                               literals in top-level positions, are experimental");
        }
1044 1045
    }

1046
    fn visit_name(&mut self, sp: Span, name: ast::Name) {
1047
        if !name.as_str().is_ascii() {
1048 1049
            gate_feature_post!(&self, non_ascii_idents, sp,
                               "non-ascii idents are not fully supported.");
1050 1051 1052
        }
    }

1053
    fn visit_item(&mut self, i: &'a ast::Item) {
1054
        match i.node {
1055
            ast::ItemKind::ExternCrate(_) => {
1056
                if attr::contains_name(&i.attrs[..], "macro_reexport") {
1057 1058 1059
                    gate_feature_post!(&self, macro_reexport, i.span,
                                       "macros reexports are experimental \
                                        and possibly buggy");
1060 1061 1062
                }
            }

1063
            ast::ItemKind::ForeignMod(ref foreign_module) => {
1064
                if attr::contains_name(&i.attrs[..], "link_args") {
1065
                    gate_feature_post!(&self, link_args, i.span,
1066 1067 1068 1069
                                      "the `link_args` attribute is not portable \
                                       across platforms, it is recommended to \
                                       use `#[link(name = \"foo\")]` instead")
                }
1070
                self.check_abi(foreign_module.abi, i.span);
1071 1072
            }

1073
            ast::ItemKind::Fn(..) => {
1074
                if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1075 1076
                    gate_feature_post!(&self, plugin_registrar, i.span,
                                       "compiler plugins are experimental and possibly buggy");
1077
                }
1078
                if attr::contains_name(&i.attrs[..], "start") {
1079
                    gate_feature_post!(&self, start, i.span,
1080 1081 1082 1083
                                      "a #[start] function is an experimental \
                                       feature whose signature may change \
                                       over time");
                }
1084
                if attr::contains_name(&i.attrs[..], "main") {
1085 1086 1087 1088
                    gate_feature_post!(&self, main, i.span,
                                       "declaration of a nonstandard #[main] \
                                        function may change over time, for now \
                                        a top-level `fn main()` is required");
1089
                }
1090 1091
            }

1092
            ast::ItemKind::Struct(..) => {
1093
                if attr::contains_name(&i.attrs[..], "simd") {
1094 1095
                    gate_feature_post!(&self, simd, i.span,
                                       "SIMD types are experimental and possibly buggy");
1096 1097 1098 1099
                    self.context.parse_sess.span_diagnostic.span_warn(i.span,
                                                                      "the `#[simd]` attribute \
                                                                       is deprecated, use \
                                                                       `#[repr(simd)]` instead");
1100 1101 1102 1103
                }
                for attr in &i.attrs {
                    if attr.name() == "repr" {
                        for item in attr.meta_item_list().unwrap_or(&[]) {
1104
                            if item.check_name("simd") {
1105 1106 1107
                                gate_feature_post!(&self, repr_simd, i.span,
                                                   "SIMD types are experimental \
                                                    and possibly buggy");
1108 1109 1110 1111

                            }
                        }
                    }
1112
                }
D
David Manescu 已提交
1113 1114
            }

1115 1116 1117
            ast::ItemKind::Union(..) => {
                gate_feature_post!(&self, untagged_unions,
                                   i.span,
V
Vadim Petrochenkov 已提交
1118
                                   "unions are unstable and possibly buggy");
1119 1120
            }

1121
            ast::ItemKind::DefaultImpl(..) => {
1122 1123 1124 1125
                gate_feature_post!(&self, optin_builtin_traits,
                                   i.span,
                                   "default trait implementations are experimental \
                                    and possibly buggy");
F
Flavio Percoco 已提交
1126 1127
            }

1128
            ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
1129 1130
                match polarity {
                    ast::ImplPolarity::Negative => {
1131 1132 1133 1134
                        gate_feature_post!(&self, optin_builtin_traits,
                                           i.span,
                                           "negative trait bounds are not yet fully implemented; \
                                            use marker types for now");
1135 1136 1137
                    },
                    _ => {}
                }
1138 1139
            }

1140 1141 1142
            _ => {}
        }

1143
        visit::walk_item(self, i);
1144
    }
1145

1146
    fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
1147 1148
        let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
            Some(val) => val.as_str().starts_with("llvm."),
1149 1150 1151
            _ => false
        };
        if links_to_llvm {
1152
            gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1153 1154 1155
                              "linking to LLVM intrinsics is experimental");
        }

1156
        visit::walk_foreign_item(self, i)
1157 1158
    }

1159
    fn visit_ty(&mut self, ty: &'a ast::Ty) {
1160 1161 1162 1163
        match ty.node {
            ast::TyKind::BareFn(ref bare_fn_ty) => {
                self.check_abi(bare_fn_ty.abi, ty.span);
            }
1164 1165 1166 1167
            ast::TyKind::ImplTrait(..) => {
                gate_feature_post!(&self, conservative_impl_trait, ty.span,
                                   "`impl Trait` is experimental");
            }
A
Andrew Cann 已提交
1168 1169
            ast::TyKind::Never => {
                gate_feature_post!(&self, never_type, ty.span,
1170 1171
                                   "The `!` type is experimental");
            },
1172 1173 1174 1175 1176
            _ => {}
        }
        visit::walk_ty(self, ty)
    }

1177
    fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
1178 1179
        if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
            match output_ty.node {
A
Andrew Cann 已提交
1180
                ast::TyKind::Never => return,
1181 1182
                _ => (),
            };
A
Andrew Cann 已提交
1183
            self.visit_ty(output_ty)
1184 1185 1186
        }
    }

1187
    fn visit_expr(&mut self, e: &'a ast::Expr) {
1188
        match e.node {
1189
            ast::ExprKind::Box(_) => {
1190
                gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1191
            }
1192
            ast::ExprKind::Type(..) => {
1193
                gate_feature_post!(&self, type_ascription, e.span,
1194 1195
                                  "type ascription is experimental");
            }
1196
            ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1197
                gate_feature_post!(&self, inclusive_range_syntax,
A
Alex Burka 已提交
1198 1199 1200
                                  e.span,
                                  "inclusive range syntax is experimental");
            }
1201 1202 1203
            ast::ExprKind::InPlace(..) => {
                gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
            }
1204 1205 1206 1207 1208 1209
            ast::ExprKind::Struct(_, ref fields, _) => {
                for field in fields {
                    if field.is_shorthand {
                        gate_feature_post!(&self, field_init_shorthand, field.span,
                                           "struct field shorthands are unstable");
                    }
1210 1211 1212 1213 1214
                    if starts_with_digit(&field.ident.node.name.as_str()) {
                        gate_feature_post!(&self, relaxed_adts,
                                          field.span,
                                          "numeric fields in struct expressions are unstable");
                    }
1215 1216
                }
            }
1217 1218 1219 1220
            ast::ExprKind::Break(_, Some(_)) => {
                gate_feature_post!(&self, loop_break_value, e.span,
                                   "`break` with a value is experimental");
            }
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
            ast::ExprKind::Lit(ref lit) => {
                if let ast::LitKind::Int(_, ref ty) = lit.node {
                    match *ty {
                        ast::LitIntType::Signed(ast::IntTy::I128) |
                        ast::LitIntType::Unsigned(ast::UintTy::U128) => {
                            gate_feature_post!(&self, i128_type, e.span,
                                               "128-bit integers are not stable");
                        }
                        _ => {}
                    }
                }
            }
1233 1234
            _ => {}
        }
1235
        visit::walk_expr(self, e);
1236
    }
1237

1238
    fn visit_pat(&mut self, pattern: &'a ast::Pat) {
1239
        match pattern.node {
1240
            PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
1241
                gate_feature_post!(&self, advanced_slice_patterns,
1242 1243 1244
                                  pattern.span,
                                  "multiple-element slice matches anywhere \
                                   but at the end of a slice (e.g. \
1245
                                   `[0, ..xs, 0]`) are experimental")
1246
            }
1247
            PatKind::Slice(..) => {
1248
                gate_feature_post!(&self, slice_patterns,
1249 1250 1251
                                  pattern.span,
                                  "slice pattern syntax is experimental");
            }
1252
            PatKind::Box(..) => {
1253
                gate_feature_post!(&self, box_patterns,
1254
                                  pattern.span,
1255
                                  "box pattern syntax is experimental");
1256
            }
1257 1258 1259 1260 1261 1262 1263 1264
            PatKind::Struct(_, ref fields, _) => {
                for field in fields {
                    if starts_with_digit(&field.node.ident.name.as_str()) {
                        gate_feature_post!(&self, relaxed_adts,
                                          field.span,
                                          "numeric fields in struct patterns are unstable");
                    }
                }
1265
            }
1266 1267
            _ => {}
        }
1268
        visit::walk_pat(self, pattern)
1269 1270
    }

1271
    fn visit_fn(&mut self,
1272 1273
                fn_kind: FnKind<'a>,
                fn_decl: &'a ast::FnDecl,
1274
                span: Span,
1275
                _node_id: NodeId) {
N
Niko Matsakis 已提交
1276 1277
        // check for const fn declarations
        match fn_kind {
1278
            FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => {
1279
                gate_feature_post!(&self, const_fn, span, "const fn is unstable");
N
Niko Matsakis 已提交
1280 1281 1282 1283 1284 1285 1286 1287 1288
            }
            _ => {
                // stability of const fn methods are covered in
                // visit_trait_item and visit_impl_item below; this is
                // because default methods don't pass through this
                // point.
            }
        }

1289
        match fn_kind {
1290 1291
            FnKind::ItemFn(_, _, _, _, abi, _, _) |
            FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
1292 1293
                self.check_abi(abi, span);
            }
1294 1295
            _ => {}
        }
1296
        visit::walk_fn(self, fn_kind, fn_decl, span);
1297
    }
1298

1299
    fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1300
        match ti.node {
1301
            ast::TraitItemKind::Const(..) => {
1302
                gate_feature_post!(&self, associated_consts,
1303 1304 1305
                                  ti.span,
                                  "associated constants are experimental")
            }
1306 1307 1308 1309
            ast::TraitItemKind::Method(ref sig, ref block) => {
                if block.is_none() {
                    self.check_abi(sig.abi, ti.span);
                }
1310
                if sig.constness.node == ast::Constness::Const {
1311
                    gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
N
Niko Matsakis 已提交
1312 1313
                }
            }
1314
            ast::TraitItemKind::Type(_, Some(_)) => {
1315
                gate_feature_post!(&self, associated_type_defaults, ti.span,
1316 1317
                                  "associated type defaults are unstable");
            }
1318 1319 1320 1321 1322
            _ => {}
        }
        visit::walk_trait_item(self, ti);
    }

1323
    fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
A
Aaron Turon 已提交
1324
        if ii.defaultness == ast::Defaultness::Default {
1325
            gate_feature_post!(&self, specialization,
A
Aaron Turon 已提交
1326 1327 1328 1329
                              ii.span,
                              "specialization is unstable");
        }

1330
        match ii.node {
1331
            ast::ImplItemKind::Const(..) => {
1332
                gate_feature_post!(&self, associated_consts,
1333 1334 1335
                                  ii.span,
                                  "associated constants are experimental")
            }
1336
            ast::ImplItemKind::Method(ref sig, _) => {
1337
                if sig.constness.node == ast::Constness::Const {
1338
                    gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
N
Niko Matsakis 已提交
1339 1340
                }
            }
1341 1342 1343 1344
            _ => {}
        }
        visit::walk_impl_item(self, ii);
    }
1345

1346
    fn visit_vis(&mut self, vis: &'a ast::Visibility) {
1347 1348
        let span = match *vis {
            ast::Visibility::Crate(span) => span,
1349
            ast::Visibility::Restricted { ref path, .. } => path.span,
1350 1351
            _ => return,
        };
1352
        gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental");
1353 1354

        visit::walk_vis(self, vis)
1355
    }
1356

1357
    fn visit_generics(&mut self, g: &'a ast::Generics) {
1358 1359 1360 1361 1362 1363 1364 1365 1366
        for t in &g.ty_params {
            if !t.attrs.is_empty() {
                gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span,
                                   "attributes on type parameter bindings are experimental");
            }
        }
        visit::walk_generics(self, g)
    }

1367
    fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) {
1368 1369 1370 1371 1372 1373
        if !lifetime_def.attrs.is_empty() {
            gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span,
                               "attributes on lifetime bindings are experimental");
        }
        visit::walk_lifetime_def(self, lifetime_def)
    }
1374 1375
}

J
Jeffrey Seyfried 已提交
1376
pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
1377
    let mut features = Features::new();
N
Nick Cameron 已提交
1378

J
Jeffrey Seyfried 已提交
1379
    for attr in krate_attrs {
S
Steven Fackler 已提交
1380
        if !attr.check_name("feature") {
1381 1382
            continue
        }
1383 1384 1385

        match attr.meta_item_list() {
            None => {
G
ggomez 已提交
1386 1387
                span_err!(span_handler, attr.span, E0555,
                          "malformed feature attribute, expected #![feature(...)]");
1388 1389
            }
            Some(list) => {
1390
                for mi in list {
1391 1392 1393 1394 1395 1396 1397 1398
                    let name = if let Some(word) = mi.word() {
                        word.name()
                    } else {
                        span_err!(span_handler, mi.span, E0556,
                                  "malformed feature, expected just one word");
                        continue
                    };

1399 1400 1401 1402 1403 1404
                    if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter()
                        .find(|& &(n, _, _, _)| name == n) {
                        *(setter(&mut features)) = true;
                    }
                    else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter()
                        .find(|& &(n, _, _)| name == n) {
G
ggomez 已提交
1405
                        span_err!(span_handler, mi.span, E0557, "feature has been removed");
1406 1407 1408
                    }
                    else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
                        .find(|& &(n, _, _)| name == n) {
1409
                        features.declared_stable_lang_features.push((name, mi.span));
1410 1411
                    } else {
                        features.declared_lib_features.push((name, mi.span));
1412 1413 1414 1415 1416 1417
                    }
                }
            }
        }
    }

L
Leo Testard 已提交
1418
    features
C
Corey Richardson 已提交
1419 1420
}

J
Jeffrey Seyfried 已提交
1421 1422 1423
pub fn check_crate(krate: &ast::Crate,
                   sess: &ParseSess,
                   features: &Features,
1424
                   plugin_attributes: &[(String, AttributeType)],
J
Jeffrey Seyfried 已提交
1425 1426 1427 1428
                   unstable: UnstableFeatures) {
    maybe_stage_features(&sess.span_diagnostic, krate, unstable);
    let ctx = Context {
        features: features,
1429
        parse_sess: sess,
J
Jeffrey Seyfried 已提交
1430 1431 1432 1433
        cm: sess.codemap(),
        plugin_attributes: plugin_attributes,
    };
    visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
C
Corey Richardson 已提交
1434
}
1435

1436
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
1437 1438 1439 1440
pub enum UnstableFeatures {
    /// Hard errors for unstable features are active, as on
    /// beta/stable channels.
    Disallow,
J
John Hodge 已提交
1441
    /// Allow features to be activated, as on nightly.
1442 1443 1444 1445
    Allow,
    /// Errors are bypassed for bootstrapping. This is required any time
    /// during the build that feature-related lints are set to warn or above
    /// because the build turns on warnings-as-errors and uses lots of unstable
1446
    /// features. As a result, this is always required for building Rust itself.
1447 1448 1449
    Cheat
}

T
Tim Neumann 已提交
1450 1451 1452 1453
impl UnstableFeatures {
    pub fn from_environment() -> UnstableFeatures {
        // Whether this is a feature-staged build, i.e. on the beta or stable channel
        let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1454 1455 1456 1457 1458 1459
        // Whether we should enable unstable features for bootstrapping
        let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
        match (disable_unstable_features, bootstrap) {
            (_, true) => UnstableFeatures::Cheat,
            (true, _) => UnstableFeatures::Disallow,
            (false, _) => UnstableFeatures::Allow
T
Tim Neumann 已提交
1460 1461
        }
    }
1462 1463 1464 1465 1466 1467 1468

    pub fn is_nightly_build(&self) -> bool {
        match *self {
            UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
            _ => false,
        }
    }
T
Tim Neumann 已提交
1469 1470
}

1471
fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
                        unstable: UnstableFeatures) {
    let allow_features = match unstable {
        UnstableFeatures::Allow => true,
        UnstableFeatures::Disallow => false,
        UnstableFeatures::Cheat => true
    };
    if !allow_features {
        for attr in &krate.attrs {
            if attr.check_name("feature") {
                let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
G
ggomez 已提交
1482
                span_err!(span_handler, attr.span, E0554,
G
ggomez 已提交
1483 1484
                          "#[feature] may not be used on the {} release channel",
                          release_channel);
1485 1486 1487 1488
            }
        }
    }
}