feature_gate.rs 59.6 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 parse::token::InternedString;
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 62
            /// #![feature] attrs for stable language features, for error reporting
            pub declared_stable_lang_features: Vec<(InternedString, Span)>,
63 64 65 66
            /// #![feature] attrs for non-language (library) features
            pub declared_lib_features: Vec<(InternedString, Span)>,
            $(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 142
    (active, pushpop_unsafe, "1.2.0", None),

    (active, allocator, "1.0.0", Some(27389)),
    (active, fundamental, "1.0.0", Some(29635)),
    (active, linked_from, "1.3.0", Some(29629)),
    (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)),
143 144
    (active, panic_runtime, "1.10.0", Some(32837)),
    (active, needs_panic_runtime, "1.10.0", Some(32837)),
145

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

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

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

    // Allows using items which are missing stability attributes
A
Aaron Turon 已提交
157
    // rustc internal
158
    (active, unmarked_api, "1.0.0", None),
159

A
Alex Crichton 已提交
160
    // Allows using #![no_core]
161
    (active, no_core, "1.3.0", Some(29639)),
A
Alex Crichton 已提交
162

163
    // Allows using `box` in patterns; RFC 469
164
    (active, box_patterns, "1.0.0", Some(29641)),
165

166 167
    // Allows using the unsafe_destructor_blind_to_params attribute;
    // RFC 1238
168
    (active, dropck_parametricity, "1.3.0", Some(28498)),
169

170 171 172
    // Allows using the may_dangle attribute; RFC 1327
    (active, dropck_eyepatch, "1.10.0", Some(34761)),

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

176 177
    // Allows the use of #[derive(Anything)] as sugar for
    // #[derive_Anything].
178
    (active, custom_derive, "1.0.0", Some(29644)),
179

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

183 184 185 186
    // 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 已提交
187 188
    //
    // rustc internal
189
    (active, allow_internal_unstable, "1.0.0", None),
190 191

    // #23121. Array patterns have some hazards yet.
192
    (active, slice_patterns, "1.0.0", Some(23121)),
193 194 195

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

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

201
    // Allows indexing into constant arrays.
202
    (active, const_indexing, "1.4.0", Some(29947)),
203

204
    // Allows using #[prelude_import] on glob `use` items.
A
Aaron Turon 已提交
205 206
    //
    // rustc internal
207
    (active, prelude_import, "1.2.0", None),
208 209

    // Allows the definition recursive static items.
210
    (active, static_recursion, "1.3.0", Some(29719)),
B
Brian Anderson 已提交
211 212

    // Allows default type parameters to influence type inference.
213
    (active, default_type_parameter_fallback, "1.3.0", Some(27336)),
214 215

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

218
    // allow `repr(simd)`, and importing the various simd intrinsics
219
    (active, repr_simd, "1.4.0", Some(27731)),
220 221

    // Allows cfg(target_feature = "...").
222
    (active, cfg_target_feature, "1.4.0", Some(29717)),
223 224

    // allow `extern "platform-intrinsic" { ... }`
225
    (active, platform_intrinsics, "1.4.0", Some(27731)),
226 227

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

T
Ticki 已提交
231
    // allow the use of `#[naked]` on functions.
232
    (active, naked_functions, "1.9.0", Some(32408)),
233 234

    // allow `#[no_debug]`
235
    (active, no_debug, "1.5.0", Some(29721)),
236 237

    // allow `#[omit_gdb_pretty_printer_section]`
A
Aaron Turon 已提交
238
    // rustc internal.
239
    (active, omit_gdb_pretty_printer_section, "1.5.0", None),
240 241

    // Allows cfg(target_vendor = "...").
242
    (active, cfg_target_vendor, "1.5.0", Some(29718)),
243 244

    // Allow attributes on expressions and non-item statements
245
    (active, stmt_expr_attributes, "1.6.0", Some(15701)),
246 247

    // allow using type ascription in expressions
248
    (active, type_ascription, "1.6.0", Some(23416)),
249 250

    // Allows cfg(target_thread_local)
251
    (active, cfg_target_thread_local, "1.7.0", Some(29594)),
252 253

    // rustc internal
254
    (active, abi_vectorcall, "1.7.0", None),
A
Alex Burka 已提交
255 256

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

A
Aaron Turon 已提交
259
    // impl specialization (RFC 1210)
260
    (active, specialization, "1.7.0", Some(31844)),
261 262

    // pub(restricted) visibilities (RFC 1422)
263 264
    (active, pub_restricted, "1.9.0", Some(32409)),

265 266 267 268
    // Allow Drop types in statics/const functions (RFC 1440)
    (active, drop_types_in_const, "1.9.0", Some(33156)),

    // Allows cfg(target_has_atomic = "...").
269 270
    (active, cfg_target_has_atomic, "1.9.0", Some(32976)),

271
    // Allows `impl Trait` in function return types.
272 273 274 275
    (active, conservative_impl_trait, "1.12.0", Some(34511)),

    // Allows tuple structs and variants in more contexts,
    // Permits numeric fields in struct expressions and patterns.
276 277 278
    (active, relaxed_adts, "1.12.0", Some(35626)),

    // The `!` type
279 280 281
    (active, never_type, "1.13.0", Some(35121)),

    // Allows all literals in attribute lists and values of key-value pairs.
282 283 284 285
    (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
286 287 288
    (active, abi_sysv64, "1.13.0", Some(36167)),

    // Use the import semantics from RFC 1560.
289 290 291
    (active, item_like_imports, "1.13.0", Some(35120)),

    // Macros 1.1
292
    (active, proc_macro, "1.13.0", Some(35900)),
293 294 295

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

    // elide `'static` lifetimes in `static`s and `const`s
    (active, static_in_const, "1.13.0", Some(35897)),
299 300 301 302

    // Used to identify the `compiler_builtins` crate
    // rustc internal
    (active, compiler_builtins, "1.13.0", None),
303 304 305

    // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
    (active, generic_param_attrs, "1.11.0", Some(34761)),
306 307 308

    // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
    (active, field_init_shorthand, "1.14.0", Some(37340)),
309 310 311

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

313 314
    // Allows using `Self` and associated types in struct expressions and patterns.
    (active, more_struct_aliases, "1.14.0", Some(37544)),
315 316 317 318 319 320 321 322 323 324 325 326
);

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),
327
    (removed, visible_private_types, "1.0.0", None),
328
    (removed, unsafe_no_drop_flag, "1.0.0", None),
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
);

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]
345
    (accepted, no_std, "1.6.0", None),
346 347 348 349 350 351
    (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 已提交
352 353
    // Allows macros to appear in the type position.
    (accepted, type_macros, "1.13.0", Some(27245)),
354 355
    (accepted, while_let, "1.0.0", None),
    // Allows `#[deprecated]` attribute
356
    (accepted, deprecated, "1.9.0", Some(29935)),
N
Nick Cameron 已提交
357 358
    // `expr?`
    (accepted, question_mark, "1.14.0", Some(31436)),
359 360
    // Allows `..` in tuple (struct) patterns
    (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)),
361
);
362
// (changing above list without updating src/doc/reference.md makes @cmr sad)
363

364 365 366 367 368
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum AttributeType {
    /// Normal, builtin attribute that is consumed
    /// by the compiler before the unused_attribute check
    Normal,
369

370 371 372 373
    /// 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,
374

375 376 377 378 379 380 381
    /// 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
382
    Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
383 384 385 386 387

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

N
Nick Cameron 已提交
388 389 390 391 392 393 394 395 396 397
impl AttributeGate {
    fn is_deprecated(&self) -> bool {
        match *self {
            Gated(Stability::Deprecated(_), ..) => true,
            _ => false,
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
398 399
pub enum Stability {
    Unstable,
N
Nick Cameron 已提交
400 401
    // Argument is tracking issue link.
    Deprecated(&'static str),
402 403
}

404 405 406 407
// 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 已提交
408 409
            Gated(ref stab, ref name, ref expl, _) =>
                write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
410 411 412 413 414 415 416 417 418 419 420 421
            Ungated => write!(fmt, "Ungated")
        }
    }
}

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

N
Nick Cameron 已提交
424 425 426 427
pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> {
    KNOWN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
}

428
// Attributes that have a special meaning to rustc or rustdoc
429
pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[
430 431
    // Normal attributes

432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
    ("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),
462

463
    // RFC #1445.
464 465
    ("structural_match", Whitelisted, Gated(Stability::Unstable,
                                            "structural_match",
466
                                            "the semantics of constant patterns is \
467 468
                                             not yet settled",
                                            cfg_fn!(structural_match))),
469

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

473 474
    ("plugin", CrateLevel, Gated(Stability::Unstable,
                                 "plugin",
475
                                 "compiler plugins are experimental \
476 477 478
                                  and possibly buggy",
                                 cfg_fn!(plugin))),

479
    ("no_std", CrateLevel, Ungated),
480 481
    ("no_core", CrateLevel, Gated(Stability::Unstable,
                                  "no_core",
482 483
                                  "no_core is experimental",
                                  cfg_fn!(no_core))),
484 485
    ("lang", Normal, Gated(Stability::Unstable,
                           "lang_items",
486 487
                           "language items are subject to change",
                           cfg_fn!(lang_items))),
488 489
    ("linkage", Whitelisted, Gated(Stability::Unstable,
                                   "linkage",
490
                                   "the `linkage` attribute is experimental \
491 492
                                    and not portable across platforms",
                                   cfg_fn!(linkage))),
493 494
    ("thread_local", Whitelisted, Gated(Stability::Unstable,
                                        "thread_local",
495 496 497
                                        "`#[thread_local]` is an experimental feature, and does \
                                         not currently handle destructors. There is no \
                                         corresponding `#[task_local]` mapping to the task \
498 499
                                         model",
                                        cfg_fn!(thread_local))),
500

501 502
    ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable,
                                             "on_unimplemented",
503
                                             "the `#[rustc_on_unimplemented]` attribute \
504 505
                                              is an experimental feature",
                                             cfg_fn!(on_unimplemented))),
506 507
    ("allocator", Whitelisted, Gated(Stability::Unstable,
                                     "allocator",
508 509
                                     "the `#[allocator]` attribute is an experimental feature",
                                     cfg_fn!(allocator))),
510 511
    ("needs_allocator", Normal, Gated(Stability::Unstable,
                                      "needs_allocator",
512 513
                                      "the `#[needs_allocator]` \
                                       attribute is an experimental \
514 515
                                       feature",
                                      cfg_fn!(needs_allocator))),
516 517
    ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
                                         "panic_runtime",
518 519 520
                                         "the `#[panic_runtime]` attribute is \
                                          an experimental feature",
                                         cfg_fn!(panic_runtime))),
521 522
    ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable,
                                               "needs_panic_runtime",
523 524 525 526
                                               "the `#[needs_panic_runtime]` \
                                                attribute is an experimental \
                                                feature",
                                               cfg_fn!(needs_panic_runtime))),
527 528
    ("rustc_variance", Normal, Gated(Stability::Unstable,
                                     "rustc_attrs",
529
                                     "the `#[rustc_variance]` attribute \
N
Niko Matsakis 已提交
530
                                      is just used for rustc unit tests \
531 532
                                      and will never be stable",
                                     cfg_fn!(rustc_attrs))),
533 534
    ("rustc_error", Whitelisted, Gated(Stability::Unstable,
                                       "rustc_attrs",
535
                                       "the `#[rustc_error]` attribute \
N
Niko Matsakis 已提交
536
                                        is just used for rustc unit tests \
537 538
                                        and will never be stable",
                                       cfg_fn!(rustc_attrs))),
539 540
    ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
                                                 "rustc_attrs",
541 542 543 544
                                                 "the `#[rustc_if_this_changed]` attribute \
                                                  is just used for rustc unit tests \
                                                  and will never be stable",
                                                 cfg_fn!(rustc_attrs))),
545 546
    ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable,
                                                      "rustc_attrs",
547 548 549 550
                                                      "the `#[rustc_if_this_changed]` attribute \
                                                       is just used for rustc unit tests \
                                                       and will never be stable",
                                                      cfg_fn!(rustc_attrs))),
551 552
    ("rustc_dirty", Whitelisted, Gated(Stability::Unstable,
                                       "rustc_attrs",
553 554
                                       "the `#[rustc_dirty]` attribute \
                                        is just used for rustc unit tests \
555 556
                                        and will never be stable",
                                       cfg_fn!(rustc_attrs))),
557 558
    ("rustc_clean", Whitelisted, Gated(Stability::Unstable,
                                       "rustc_attrs",
559 560
                                       "the `#[rustc_clean]` attribute \
                                        is just used for rustc unit tests \
561 562
                                        and will never be stable",
                                       cfg_fn!(rustc_attrs))),
563 564
    ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable,
                                                "rustc_attrs",
565 566 567 568
                                                "the `#[rustc_metadata_dirty]` attribute \
                                                 is just used for rustc unit tests \
                                                 and will never be stable",
                                                 cfg_fn!(rustc_attrs))),
569 570
    ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable,
                                                "rustc_attrs",
571 572 573 574
                                                "the `#[rustc_metadata_clean]` attribute \
                                                 is just used for rustc unit tests \
                                                 and will never be stable",
                                                 cfg_fn!(rustc_attrs))),
575 576
    ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable,
                                                  "rustc_attrs",
577 578 579 580
                                                  "this attribute \
                                                   is just used for rustc unit tests \
                                                   and will never be stable",
                                                  cfg_fn!(rustc_attrs))),
581 582
    ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable,
                                                      "rustc_attrs",
583 584 585 586
                                                      "this attribute \
                                                       is just used for rustc unit tests \
                                                       and will never be stable",
                                                      cfg_fn!(rustc_attrs))),
587 588
    ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable,
                                             "rustc_attrs",
589 590
                                             "internal rustc attributes will never be stable",
                                             cfg_fn!(rustc_attrs))),
591 592
    ("rustc_item_path", Whitelisted, Gated(Stability::Unstable,
                                           "rustc_attrs",
593 594
                                           "internal rustc attributes will never be stable",
                                           cfg_fn!(rustc_attrs))),
595 596
    ("rustc_move_fragments", Normal, Gated(Stability::Unstable,
                                           "rustc_attrs",
597
                                           "the `#[rustc_move_fragments]` attribute \
N
Niko Matsakis 已提交
598
                                            is just used for rustc unit tests \
599 600
                                            and will never be stable",
                                           cfg_fn!(rustc_attrs))),
601 602
    ("rustc_mir", Whitelisted, Gated(Stability::Unstable,
                                     "rustc_attrs",
603 604
                                     "the `#[rustc_mir]` attribute \
                                      is just used for rustc unit tests \
605 606
                                      and will never be stable",
                                     cfg_fn!(rustc_attrs))),
607 608
    ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable,
                                                         "rustc_attrs",
609 610 611 612 613 614
                                                         "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))),
615 616
    ("compiler_builtins", Whitelisted, Gated(Stability::Unstable,
                                             "compiler_builtins",
617 618 619 620 621
                                             "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))),
622

623 624
    ("allow_internal_unstable", Normal, Gated(Stability::Unstable,
                                              "allow_internal_unstable",
625 626
                                              EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
                                              cfg_fn!(allow_internal_unstable))),
627

628 629
    ("fundamental", Whitelisted, Gated(Stability::Unstable,
                                       "fundamental",
630
                                       "the `#[fundamental]` attribute \
631 632
                                        is an experimental feature",
                                       cfg_fn!(fundamental))),
633

634 635
    ("linked_from", Normal, Gated(Stability::Unstable,
                                  "linked_from",
636
                                  "the `#[linked_from]` attribute \
637 638
                                   is an experimental feature",
                                  cfg_fn!(linked_from))),
639

640 641
    ("proc_macro_derive", Normal, Gated(Stability::Unstable,
                                        "proc_macro",
642 643 644
                                        "the `#[proc_macro_derive]` attribute \
                                         is an experimental feature",
                                        cfg_fn!(proc_macro))),
645

646 647
    ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable,
                                                   "rustc_attrs",
648 649 650
                                                   "internal implementation detail",
                                                   cfg_fn!(rustc_attrs))),

651
    // FIXME: #14408 whitelist docs since rustdoc looks at them
652
    ("doc", Whitelisted, Ungated),
653 654 655

    // FIXME: #14406 these are processed in trans, which happens after the
    // lint pass
656
    ("cold", Whitelisted, Ungated),
657 658
    ("naked", Whitelisted, Gated(Stability::Unstable,
                                 "naked_functions",
T
Ticki 已提交
659
                                 "the `#[naked]` attribute \
660
                                  is an experimental feature",
661
                                 cfg_fn!(naked_functions))),
662 663 664 665 666 667 668
    ("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 已提交
669 670 671 672 673
    ("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))),
674 675
    ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
                                                       "omit_gdb_pretty_printer_section",
676 677
                                                       "the `#[omit_gdb_pretty_printer_section]` \
                                                        attribute is just used for the Rust test \
678 679
                                                        suite",
                                                       cfg_fn!(omit_gdb_pretty_printer_section))),
680 681
    ("unsafe_destructor_blind_to_params",
     Normal,
682 683
     Gated(Stability::Unstable,
           "dropck_parametricity",
684
           "unsafe_destructor_blind_to_params has unstable semantics \
685 686
            and may be removed in the future",
           cfg_fn!(dropck_parametricity))),
687 688
    ("may_dangle",
     Normal,
689 690
     Gated(Stability::Unstable,
           "dropck_eyepatch",
691 692
           "may_dangle has unstable semantics and may be removed in the future",
           cfg_fn!(dropck_eyepatch))),
693 694 695
    ("unwind", Whitelisted, Gated(Stability::Unstable,
                                  "unwind_attributes",
                                  "#[unwind] is experimental",
696
                                  cfg_fn!(unwind_attributes))),
697 698

    // used in resolve
699 700
    ("prelude_import", Whitelisted, Gated(Stability::Unstable,
                                          "prelude_import",
701 702
                                          "`#[prelude_import]` is for use by rustc only",
                                          cfg_fn!(prelude_import))),
703 704 705

    // FIXME: #14407 these are only looked at on-demand so we can't
    // guarantee they'll have already been checked
706
    ("rustc_deprecated", Whitelisted, Ungated),
707 708 709
    ("must_use", Whitelisted, Ungated),
    ("stable", Whitelisted, Ungated),
    ("unstable", Whitelisted, Ungated),
710
    ("deprecated", Normal, Ungated),
711

712 713
    ("rustc_paren_sugar", Normal, Gated(Stability::Unstable,
                                        "unboxed_closures",
714 715
                                        "unboxed_closures are still evolving",
                                        cfg_fn!(unboxed_closures))),
716 717
    ("rustc_reflect_like", Whitelisted, Gated(Stability::Unstable,
                                              "reflect",
718 719
                                              "defining reflective traits is still evolving",
                                              cfg_fn!(reflect))),
720

721 722 723
    ("windows_subsystem", Whitelisted, Gated(Stability::Unstable,
                                             "windows_subsystem",
                                             "the windows subsystem attribute \
A
Alex Crichton 已提交
724
                                              is currently unstable",
725 726
                                             cfg_fn!(windows_subsystem))),

727
    // Crate level attributes
728 729 730 731 732 733 734 735
    ("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),
736 737
];

738 739 740
// 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)
741 742 743
    ("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)),
744
    ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
745
    ("proc_macro", "proc_macro", cfg_fn!(proc_macro)),
746 747 748 749 750 751 752
];

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

754 755 756 757 758 759 760 761 762 763 764 765
impl GatedCfg {
    pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
        let name = cfg.name();
        GATED_CFGS.iter()
                  .position(|info| info.0 == name)
                  .map(|idx| {
                      GatedCfg {
                          span: cfg.span,
                          index: idx
                      }
                  })
    }
J
Jeffrey Seyfried 已提交
766 767

    pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
768
        let (cfg, feature, has_feature) = GATED_CFGS[self.index];
J
Jeffrey Seyfried 已提交
769
        if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
770
            let explain = format!("`cfg({})` is experimental and subject to change", cfg);
771
            emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
772 773 774 775
        }
    }
}

E
Eduard Burtescu 已提交
776
struct Context<'a> {
L
Leo Testard 已提交
777
    features: &'a Features,
778
    parse_sess: &'a ParseSess,
C
Corey Richardson 已提交
779
    cm: &'a CodeMap,
780
    plugin_attributes: &'a [(String, AttributeType)],
781 782
}

783 784 785 786 787 788
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) {
789
            emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
790
        }
791 792 793 794 795 796
    }}
}

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

800
impl<'a> Context<'a> {
801
    fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
802 803
        debug!("check_attribute(attr = {:?})", attr);
        let name = &*attr.name();
804
        for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES {
805
            if n == name {
806
                if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
807
                    gate_feature_fn!(self, has_feature, attr.span, name, desc);
808
                }
809
                debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage);
810 811 812
                return;
            }
        }
813
        for &(ref n, ref ty) in self.plugin_attributes {
814
            if n == name {
815
                // Plugins can't gate attributes, so we don't check for it
M
Manish Goregaokar 已提交
816 817
                // unlike the code above; we only use this loop to
                // short-circuit to avoid the checks below
818 819 820 821
                debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
                return;
            }
        }
822
        if name.starts_with("rustc_") {
823 824 825 826
            gate_feature!(self, rustc_attrs, attr.span,
                          "unless otherwise specified, attributes \
                           with the prefix `rustc_` \
                           are reserved for internal compiler diagnostics");
827
        } else if name.starts_with("derive_") {
L
Leo Testard 已提交
828
            gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
829
        } else {
M
Manish Goregaokar 已提交
830 831 832 833
            // 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
834
            if !is_macro {
835 836 837 838 839 840
                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));
841
            }
842 843
        }
    }
844 845
}

846
pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
L
Leo Testard 已提交
847 848
                       cm: &CodeMap, features: &Features) {
    let cx = Context {
849
        features: features, parse_sess: parse_sess,
L
Leo Testard 已提交
850 851 852 853 854
        cm: cm, plugin_attributes: &[]
    };
    cx.check_attribute(attr, true);
}

855 856 857 858
pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
    ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
}

859
fn find_lang_feature_issue(feature: &str) -> Option<u32> {
860 861
    if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
        let issue = info.2;
862 863
        // FIXME (#28244): enforce that active features have issue numbers
        // assert!(issue.is_some())
864 865 866 867 868 869
        issue
    } else {
        // search in Accepted or Removed features
        ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES.iter())
            .find(|t| t.0 == feature)
            .unwrap().2
870 871 872 873 874 875 876 877
    }
}

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

878
pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
879
                        explain: &str) {
880 881 882 883 884
    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> {
885 886
    let diag = &sess.span_diagnostic;

887 888 889 890 891
    let issue = match issue {
        GateIssue::Language => find_lang_feature_issue(feature),
        GateIssue::Library(lib) => lib,
    };

N
Nick Cameron 已提交
892 893
    let mut err = if let Some(n) = issue {
        diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n))
894
    } else {
N
Nick Cameron 已提交
895 896
        diag.struct_span_err(span, explain)
    };
897 898

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

905
    err
906 907
}

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

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

914 915 916
pub const EXPLAIN_ASM: &'static str =
    "inline assembly is not stable enough for use and is subject to change";

917 918 919 920 921 922 923 924
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";
925 926
pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str =
    "allow_internal_unstable side-steps feature gating and stability checks";
927

928
pub const EXPLAIN_CUSTOM_DERIVE: &'static str =
N
Nick Cameron 已提交
929 930 931 932 933 934
    "`#[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";
935

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

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

struct PostExpansionVisitor<'a> {
N
Nick Cameron 已提交
943
    context: &'a Context<'a>,
C
Corey Richardson 已提交
944 945
}

946 947 948 949 950
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 已提交
951
        }
952
    }}
C
Corey Richardson 已提交
953 954
}

955 956 957
impl<'a> PostExpansionVisitor<'a> {
    fn check_abi(&self, abi: Abi, span: Span) {
        match abi {
958
            Abi::RustIntrinsic => {
959
                gate_feature_post!(&self, intrinsics, span,
960 961
                                   "intrinsics are subject to change");
            },
962 963
            Abi::PlatformIntrinsic => {
                gate_feature_post!(&self, platform_intrinsics, span,
964
                                   "platform intrinsics are experimental and possibly buggy");
965 966 967
            },
            Abi::Vectorcall => {
                gate_feature_post!(&self, abi_vectorcall, span,
968 969
                                   "vectorcall is experimental and subject to change");
            },
970 971 972
            Abi::RustCall => {
                gate_feature_post!(&self, unboxed_closures, span,
                                   "rust-call ABI is subject to change");
973 974 975 976 977
            },
            Abi::SysV64 => {
                gate_feature_post!(&self, abi_sysv64, span,
                                   "sysv64 ABI is experimental and subject to change");
            },
978 979 980 981 982
            _ => {}
        }
    }
}

983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
fn contains_novel_literal(item: &ast::MetaItem) -> bool {
    use ast::MetaItemKind::*;
    use ast::NestedMetaItemKind::*;

    match item.node {
        Word(..) => false,
        NameValue(_, ref lit) => !lit.node.is_str(),
        List(_, ref list) => list.iter().any(|li| {
            match li.node {
                MetaItem(ref mi) => contains_novel_literal(&**mi),
                Literal(_) => true,
            }
        }),
    }
}

999
impl<'a> Visitor for PostExpansionVisitor<'a> {
1000 1001
    fn visit_attribute(&mut self, attr: &ast::Attribute) {
        if !self.context.cm.span_allows_unstable(attr.span) {
1002
            // check for gated attributes
1003
            self.context.check_attribute(attr, false);
1004
        }
1005 1006 1007 1008 1009 1010

        if contains_novel_literal(&*(attr.node.value)) {
            gate_feature_post!(&self, attr_literals, attr.span,
                               "non-string literals in attributes, or string \
                               literals in top-level positions, are experimental");
        }
1011 1012
    }

1013
    fn visit_name(&mut self, sp: Span, name: ast::Name) {
1014
        if !name.as_str().is_ascii() {
1015 1016
            gate_feature_post!(&self, non_ascii_idents, sp,
                               "non-ascii idents are not fully supported.");
1017 1018 1019
        }
    }

1020
    fn visit_item(&mut self, i: &ast::Item) {
1021
        match i.node {
1022
            ast::ItemKind::ExternCrate(_) => {
1023
                if attr::contains_name(&i.attrs[..], "macro_reexport") {
1024 1025 1026
                    gate_feature_post!(&self, macro_reexport, i.span,
                                       "macros reexports are experimental \
                                        and possibly buggy");
1027 1028 1029
                }
            }

1030
            ast::ItemKind::ForeignMod(ref foreign_module) => {
1031
                if attr::contains_name(&i.attrs[..], "link_args") {
1032
                    gate_feature_post!(&self, link_args, i.span,
1033 1034 1035 1036
                                      "the `link_args` attribute is not portable \
                                       across platforms, it is recommended to \
                                       use `#[link(name = \"foo\")]` instead")
                }
1037
                self.check_abi(foreign_module.abi, i.span);
1038 1039
            }

1040
            ast::ItemKind::Fn(..) => {
1041
                if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1042 1043
                    gate_feature_post!(&self, plugin_registrar, i.span,
                                       "compiler plugins are experimental and possibly buggy");
1044
                }
1045
                if attr::contains_name(&i.attrs[..], "start") {
1046
                    gate_feature_post!(&self, start, i.span,
1047 1048 1049 1050
                                      "a #[start] function is an experimental \
                                       feature whose signature may change \
                                       over time");
                }
1051
                if attr::contains_name(&i.attrs[..], "main") {
1052 1053 1054 1055
                    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");
1056
                }
1057 1058
            }

1059
            ast::ItemKind::Struct(..) => {
1060
                if attr::contains_name(&i.attrs[..], "simd") {
1061 1062
                    gate_feature_post!(&self, simd, i.span,
                                       "SIMD types are experimental and possibly buggy");
1063 1064 1065 1066
                    self.context.parse_sess.span_diagnostic.span_warn(i.span,
                                                                      "the `#[simd]` attribute \
                                                                       is deprecated, use \
                                                                       `#[repr(simd)]` instead");
1067 1068 1069 1070
                }
                for attr in &i.attrs {
                    if attr.name() == "repr" {
                        for item in attr.meta_item_list().unwrap_or(&[]) {
1071
                            if item.check_name("simd") {
1072 1073 1074
                                gate_feature_post!(&self, repr_simd, i.span,
                                                   "SIMD types are experimental \
                                                    and possibly buggy");
1075 1076 1077 1078

                            }
                        }
                    }
1079
                }
D
David Manescu 已提交
1080 1081
            }

1082 1083 1084
            ast::ItemKind::Union(..) => {
                gate_feature_post!(&self, untagged_unions,
                                   i.span,
V
Vadim Petrochenkov 已提交
1085
                                   "unions are unstable and possibly buggy");
1086 1087
            }

1088
            ast::ItemKind::DefaultImpl(..) => {
1089 1090 1091 1092
                gate_feature_post!(&self, optin_builtin_traits,
                                   i.span,
                                   "default trait implementations are experimental \
                                    and possibly buggy");
F
Flavio Percoco 已提交
1093 1094
            }

1095
            ast::ItemKind::Impl(_, polarity, _, _, _, _) => {
1096 1097
                match polarity {
                    ast::ImplPolarity::Negative => {
1098 1099 1100 1101
                        gate_feature_post!(&self, optin_builtin_traits,
                                           i.span,
                                           "negative trait bounds are not yet fully implemented; \
                                            use marker types for now");
1102 1103 1104
                    },
                    _ => {}
                }
1105 1106
            }

1107 1108 1109
            _ => {}
        }

1110
        visit::walk_item(self, i);
1111
    }
1112

1113
    fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
1114
        let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
N
fallout  
Nick Cameron 已提交
1115
                                                                     "link_name") {
G
GuillaumeGomez 已提交
1116
            Some(val) => val.starts_with("llvm."),
1117 1118 1119
            _ => false
        };
        if links_to_llvm {
1120
            gate_feature_post!(&self, link_llvm_intrinsics, i.span,
1121 1122 1123
                              "linking to LLVM intrinsics is experimental");
        }

1124
        visit::walk_foreign_item(self, i)
1125 1126
    }

1127 1128 1129 1130 1131
    fn visit_ty(&mut self, ty: &ast::Ty) {
        match ty.node {
            ast::TyKind::BareFn(ref bare_fn_ty) => {
                self.check_abi(bare_fn_ty.abi, ty.span);
            }
1132 1133 1134 1135
            ast::TyKind::ImplTrait(..) => {
                gate_feature_post!(&self, conservative_impl_trait, ty.span,
                                   "`impl Trait` is experimental");
            }
A
Andrew Cann 已提交
1136 1137
            ast::TyKind::Never => {
                gate_feature_post!(&self, never_type, ty.span,
1138 1139
                                   "The `!` type is experimental");
            },
1140 1141 1142 1143 1144
            _ => {}
        }
        visit::walk_ty(self, ty)
    }

1145 1146 1147
    fn visit_fn_ret_ty(&mut self, ret_ty: &ast::FunctionRetTy) {
        if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
            match output_ty.node {
A
Andrew Cann 已提交
1148
                ast::TyKind::Never => return,
1149 1150
                _ => (),
            };
A
Andrew Cann 已提交
1151
            self.visit_ty(output_ty)
1152 1153 1154
        }
    }

1155
    fn visit_expr(&mut self, e: &ast::Expr) {
1156
        match e.node {
1157
            ast::ExprKind::Box(_) => {
1158
                gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1159
            }
1160
            ast::ExprKind::Type(..) => {
1161
                gate_feature_post!(&self, type_ascription, e.span,
1162 1163
                                  "type ascription is experimental");
            }
1164
            ast::ExprKind::Range(_, _, ast::RangeLimits::Closed) => {
1165
                gate_feature_post!(&self, inclusive_range_syntax,
A
Alex Burka 已提交
1166 1167 1168
                                  e.span,
                                  "inclusive range syntax is experimental");
            }
1169 1170 1171
            ast::ExprKind::InPlace(..) => {
                gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
            }
1172 1173 1174 1175 1176 1177 1178 1179
            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");
                    }
                }
            }
1180 1181
            _ => {}
        }
1182
        visit::walk_expr(self, e);
1183
    }
1184

1185
    fn visit_pat(&mut self, pattern: &ast::Pat) {
1186
        match pattern.node {
1187
            PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => {
1188
                gate_feature_post!(&self, advanced_slice_patterns,
1189 1190 1191
                                  pattern.span,
                                  "multiple-element slice matches anywhere \
                                   but at the end of a slice (e.g. \
1192
                                   `[0, ..xs, 0]`) are experimental")
1193
            }
1194
            PatKind::Slice(..) => {
1195
                gate_feature_post!(&self, slice_patterns,
1196 1197 1198
                                  pattern.span,
                                  "slice pattern syntax is experimental");
            }
1199
            PatKind::Box(..) => {
1200
                gate_feature_post!(&self, box_patterns,
1201
                                  pattern.span,
1202
                                  "box pattern syntax is experimental");
1203 1204 1205
            }
            PatKind::TupleStruct(_, ref fields, ddpos)
                    if ddpos.is_none() && fields.is_empty() => {
1206 1207
                gate_feature_post!(&self, relaxed_adts, pattern.span,
                                   "empty tuple structs patterns are unstable");
1208
            }
1209 1210
            _ => {}
        }
1211
        visit::walk_pat(self, pattern)
1212 1213
    }

1214
    fn visit_fn(&mut self,
1215 1216 1217
                fn_kind: FnKind,
                fn_decl: &ast::FnDecl,
                block: &ast::Block,
1218
                span: Span,
1219
                _node_id: NodeId) {
N
Niko Matsakis 已提交
1220 1221
        // check for const fn declarations
        match fn_kind {
1222
            FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _) => {
1223
                gate_feature_post!(&self, const_fn, span, "const fn is unstable");
N
Niko Matsakis 已提交
1224 1225 1226 1227 1228 1229 1230 1231 1232
            }
            _ => {
                // 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.
            }
        }

1233
        match fn_kind {
1234
            FnKind::ItemFn(_, _, _, _, abi, _) |
1235 1236 1237
            FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => {
                self.check_abi(abi, span);
            }
1238 1239
            _ => {}
        }
1240
        visit::walk_fn(self, fn_kind, fn_decl, block, span);
1241
    }
1242

1243
    fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
1244
        match ti.node {
1245
            ast::TraitItemKind::Const(..) => {
1246
                gate_feature_post!(&self, associated_consts,
1247 1248 1249
                                  ti.span,
                                  "associated constants are experimental")
            }
1250 1251 1252 1253
            ast::TraitItemKind::Method(ref sig, ref block) => {
                if block.is_none() {
                    self.check_abi(sig.abi, ti.span);
                }
1254
                if sig.constness.node == ast::Constness::Const {
1255
                    gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
N
Niko Matsakis 已提交
1256 1257
                }
            }
1258
            ast::TraitItemKind::Type(_, Some(_)) => {
1259
                gate_feature_post!(&self, associated_type_defaults, ti.span,
1260 1261
                                  "associated type defaults are unstable");
            }
1262 1263 1264 1265 1266
            _ => {}
        }
        visit::walk_trait_item(self, ti);
    }

1267
    fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
A
Aaron Turon 已提交
1268
        if ii.defaultness == ast::Defaultness::Default {
1269
            gate_feature_post!(&self, specialization,
A
Aaron Turon 已提交
1270 1271 1272 1273
                              ii.span,
                              "specialization is unstable");
        }

1274
        match ii.node {
1275
            ast::ImplItemKind::Const(..) => {
1276
                gate_feature_post!(&self, associated_consts,
1277 1278 1279
                                  ii.span,
                                  "associated constants are experimental")
            }
1280
            ast::ImplItemKind::Method(ref sig, _) => {
1281
                if sig.constness.node == ast::Constness::Const {
1282
                    gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
N
Niko Matsakis 已提交
1283 1284
                }
            }
1285 1286 1287 1288
            _ => {}
        }
        visit::walk_impl_item(self, ii);
    }
1289

1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
    fn visit_variant_data(&mut self, vdata: &ast::VariantData, _: ast::Ident,
                          _: &ast::Generics, _: NodeId, span: Span) {
        if vdata.fields().is_empty() {
            if vdata.is_tuple() {
                gate_feature_post!(&self, relaxed_adts, span,
                                   "empty tuple structs and enum variants are unstable, \
                                    use unit structs and enum variants instead");
            }
        }

        visit::walk_struct_def(self, vdata)
    }

1303
    fn visit_vis(&mut self, vis: &ast::Visibility) {
1304 1305
        let span = match *vis {
            ast::Visibility::Crate(span) => span,
1306
            ast::Visibility::Restricted { ref path, .. } => path.span,
1307 1308
            _ => return,
        };
1309
        gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental");
1310 1311

        visit::walk_vis(self, vis)
1312
    }
1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330

    fn visit_generics(&mut self, g: &ast::Generics) {
        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)
    }

    fn visit_lifetime_def(&mut self, lifetime_def: &ast::LifetimeDef) {
        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)
    }
1331 1332
}

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

J
Jeffrey Seyfried 已提交
1336
    for attr in krate_attrs {
S
Steven Fackler 已提交
1337
        if !attr.check_name("feature") {
1338 1339
            continue
        }
1340 1341 1342

        match attr.meta_item_list() {
            None => {
G
ggomez 已提交
1343 1344
                span_err!(span_handler, attr.span, E0555,
                          "malformed feature attribute, expected #![feature(...)]");
1345 1346
            }
            Some(list) => {
1347
                for mi in list {
1348 1349 1350 1351 1352 1353 1354 1355
                    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
                    };

1356 1357 1358 1359 1360 1361
                    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 已提交
1362
                        span_err!(span_handler, mi.span, E0557, "feature has been removed");
1363 1364 1365
                    }
                    else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
                        .find(|& &(n, _, _)| name == n) {
1366
                        features.declared_stable_lang_features.push((name, mi.span));
1367 1368
                    } else {
                        features.declared_lib_features.push((name, mi.span));
1369 1370 1371 1372 1373 1374
                    }
                }
            }
        }
    }

L
Leo Testard 已提交
1375
    features
C
Corey Richardson 已提交
1376 1377
}

J
Jeffrey Seyfried 已提交
1378 1379 1380
pub fn check_crate(krate: &ast::Crate,
                   sess: &ParseSess,
                   features: &Features,
1381
                   plugin_attributes: &[(String, AttributeType)],
J
Jeffrey Seyfried 已提交
1382 1383 1384 1385
                   unstable: UnstableFeatures) {
    maybe_stage_features(&sess.span_diagnostic, krate, unstable);
    let ctx = Context {
        features: features,
1386
        parse_sess: sess,
J
Jeffrey Seyfried 已提交
1387 1388 1389 1390
        cm: sess.codemap(),
        plugin_attributes: plugin_attributes,
    };
    visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
C
Corey Richardson 已提交
1391
}
1392

1393
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
1394 1395 1396 1397
pub enum UnstableFeatures {
    /// Hard errors for unstable features are active, as on
    /// beta/stable channels.
    Disallow,
J
John Hodge 已提交
1398
    /// Allow features to be activated, as on nightly.
1399 1400 1401 1402
    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
1403
    /// features. As a result, this is always required for building Rust itself.
1404 1405 1406
    Cheat
}

T
Tim Neumann 已提交
1407 1408 1409 1410
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();
1411 1412 1413 1414 1415 1416
        // 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 已提交
1417 1418
        }
    }
1419 1420 1421 1422 1423 1424 1425

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

1428
fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
                        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 已提交
1439
                span_err!(span_handler, attr.span, E0554,
G
ggomez 已提交
1440 1441
                          "#[feature] may not be used on the {} release channel",
                          release_channel);
1442 1443 1444 1445
            }
        }
    }
}