feature_gate.rs 100.0 KB
Newer Older
1
//! # Feature gating
2
//!
L
Luke Gallagher 已提交
3
//! This module implements the gating necessary for preventing certain compiler
4 5 6 7 8
//! 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
9
//! `#![feature(...)]` with a comma-separated list of features.
B
Brian Anderson 已提交
10 11 12 13
//!
//! 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 已提交
14

T
Taiki Endo 已提交
15 16 17
use AttributeType::*;
use AttributeGate::*;

V
varkor 已提交
18
use crate::ast::{self, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd};
T
Taiki Endo 已提交
19 20 21 22 23
use crate::attr;
use crate::early_buffered_lints::BufferedEarlyLintId;
use crate::source_map::Spanned;
use crate::edition::{ALL_EDITIONS, Edition};
use crate::visit::{self, FnKind, Visitor};
24
use crate::parse::{token, ParseSess};
T
Taiki Endo 已提交
25
use crate::symbol::Symbol;
26
use crate::tokenstream::TokenTree;
27

T
Taiki Endo 已提交
28
use errors::{DiagnosticBuilder, Handler};
29
use rustc_data_structures::fx::FxHashMap;
30
use rustc_target::spec::abi::Abi;
31
use syntax_pos::{Span, DUMMY_SP};
T
Taiki Endo 已提交
32
use log::debug;
33

M
Mazdak Farrokhzad 已提交
34
use std::env;
35

36
macro_rules! set {
37
    ($field: ident) => {{
38 39
        fn f(features: &mut Features, _: Span) {
            features.$field = true;
40
        }
41
        f as fn(&mut Features, Span)
42 43
    }}
}
44

45
macro_rules! declare_features {
K
Kurtis Nusbaum 已提交
46
    ($((active, $feature: ident, $ver: expr, $issue: expr, $edition: expr),)+) => {
47 48
        /// Represents active features that are currently being implemented or
        /// currently being considered for addition/removal.
49
        const ACTIVE_FEATURES:
50
            &[(&str, &str, Option<u32>, Option<Edition>, fn(&mut Features, Span))] =
K
Kurtis Nusbaum 已提交
51
            &[$((stringify!($feature), $ver, $issue, $edition, set!($feature))),+];
52 53

        /// A set of features to be used by later passes.
54
        #[derive(Clone)]
55
        pub struct Features {
V
varkor 已提交
56 57
            /// `#![feature]` attrs for language features, for error reporting
            pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
58
            /// `#![feature]` attrs for non-language (library) features
59
            pub declared_lib_features: Vec<(Symbol, Span)>,
60 61
            $(pub $feature: bool),+
        }
62

63 64 65
        impl Features {
            pub fn new() -> Features {
                Features {
V
varkor 已提交
66
                    declared_lang_features: Vec::new(),
67 68 69 70
                    declared_lib_features: Vec::new(),
                    $($feature: false),+
                }
            }
71 72 73 74 75 76

            pub fn walk_feature_fields<F>(&self, mut f: F)
                where F: FnMut(&str, bool)
            {
                $(f(stringify!($feature), self.$feature);)+
            }
77 78 79
        }
    };

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

87
    ($((stable_removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => {
88
        /// Represents stable features which have since been removed (it was once Accepted)
89 90
        const STABLE_REMOVED_FEATURES: &[(&str, &str, Option<u32>, Option<&str>)] = &[
            $((stringify!($feature), $ver, $issue, None)),+
91 92 93
        ];
    };

94
    ($((accepted, $feature: ident, $ver: expr, $issue: expr, None),)+) => {
95
        /// Those language feature has since been Accepted (it was once Active)
96 97
        const ACCEPTED_FEATURES: &[(&str, &str, Option<u32>, Option<&str>)] = &[
            $((stringify!($feature), $ver, $issue, None)),+
98 99
        ];
    }
100 101
}

102
// If you change this, please modify `src/doc/unstable-book` as well.
S
Steve Klabnik 已提交
103
//
B
Brian Anderson 已提交
104
// Don't ever remove anything from this list; set them to 'Removed'.
S
Steve Klabnik 已提交
105
//
B
Brian Anderson 已提交
106 107 108
// 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).
S
Steve Klabnik 已提交
109
//
110
// N.B., `tools/tidy/src/features.rs` parses this information directly out of the
111
// source, so take care when modifying it.
112 113

declare_features! (
114 115 116 117
    (active, asm, "1.0.0", Some(29722), None),
    (active, concat_idents, "1.0.0", Some(29599), None),
    (active, link_args, "1.0.0", Some(29596), None),
    (active, log_syntax, "1.0.0", Some(29598), None),
118
    (active, non_ascii_idents, "1.0.0", Some(55467), None),
119 120 121
    (active, plugin_registrar, "1.0.0", Some(29597), None),
    (active, thread_local, "1.0.0", Some(29594), None),
    (active, trace_macros, "1.0.0", Some(29598), None),
A
Aaron Turon 已提交
122

A
Alexander Regueiro 已提交
123
    // rustc internal, for now
124 125
    (active, intrinsics, "1.0.0", None, None),
    (active, lang_items, "1.0.0", None, None),
126
    (active, format_args_nl, "1.29.0", None, None),
127

128 129
    (active, link_llvm_intrinsics, "1.0.0", Some(29602), None),
    (active, linkage, "1.0.0", Some(29603), None),
130

A
Aaron Turon 已提交
131
    // rustc internal
132 133
    (active, rustc_diagnostic_macros, "1.0.0", None, None),
    (active, rustc_const_unstable, "1.0.0", None, None),
134
    (active, box_syntax, "1.0.0", Some(49733), None),
135 136 137 138 139 140 141 142 143 144 145 146
    (active, unboxed_closures, "1.0.0", Some(29625), None),

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

148
    // Features specific to OIBIT (auto traits)
149
    (active, optin_builtin_traits, "1.0.0", Some(13231), None),
150

151
    // Allows `#[staged_api]`.
A
Alexander Regueiro 已提交
152
    //
A
Aaron Turon 已提交
153
    // rustc internal
154
    (active, staged_api, "1.0.0", None, None),
155

156
    // Allows `#![no_core]`.
157
    (active, no_core, "1.3.0", Some(29639), None),
A
Alex Crichton 已提交
158

159
    // Allows the use of `box` in patterns (RFC 469).
160
    (active, box_patterns, "1.0.0", Some(29641), None),
161

162
    // Allows the use of the `unsafe_destructor_blind_to_params` attribute (RFC 1238).
163
    (active, dropck_parametricity, "1.3.0", Some(28498), None),
164

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

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

171
    // Allows the use of `rustc_*` attributes (RFC 572).
172
    (active, rustc_attrs, "1.0.0", Some(29642), None),
H
Huon Wilson 已提交
173

174
    // Allows the use of non lexical lifetimes (RFC 2094).
175
    (active, nll, "1.0.0", Some(43234), None),
176

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

185 186
    // Allows the use of `#[allow_internal_unsafe]`. This is an
    // attribute on `macro_rules!` and can't use the attribute handling
187 188 189 190
    // below (it has to be checked before expansion possibly makes
    // macros disappear).
    //
    // rustc internal
191
    (active, allow_internal_unsafe, "1.0.0", None, None),
192

193
    // Allows the use of slice patterns (issue #23121).
194
    (active, slice_patterns, "1.0.0", Some(23121), None),
195

196
    // Allows the definition of `const` functions with some advanced features.
197
    (active, const_fn, "1.2.0", Some(57563), None),
198

199
    // Allows accessing fields of unions inside `const` functions.
200 201
    (active, const_fn_union, "1.27.0", Some(51909), None),

202
    // Allows casting raw pointers to `usize` during const eval.
203 204
    (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None),

205
    // Allows dereferencing raw pointers during const eval.
206 207
    (active, const_raw_ptr_deref, "1.27.0", Some(51911), None),

208
    // Allows reinterpretation of the bits of a value of one type as another type during const eval.
209 210
    (active, const_transmute, "1.29.0", Some(53605), None),

211
    // Allows comparing raw pointers during const eval.
212 213
    (active, const_compare_raw_pointers, "1.27.0", Some(53020), None),

214
    // Allows panicking during const eval (producing compile-time errors).
215
    (active, const_panic, "1.30.0", Some(51999), None),
216

217
    // Allows using `#[prelude_import]` on glob `use` items.
A
Aaron Turon 已提交
218 219
    //
    // rustc internal
220
    (active, prelude_import, "1.2.0", None, None),
221

B
Brian Anderson 已提交
222
    // Allows default type parameters to influence type inference.
223
    (active, default_type_parameter_fallback, "1.3.0", Some(27336), None),
224

225
    // Allows associated type defaults.
226
    (active, associated_type_defaults, "1.2.0", Some(29661), None),
J
Jared Roesch 已提交
227

228
    // Allows `repr(simd)` and importing the various simd intrinsics.
229
    (active, repr_simd, "1.4.0", Some(27731), None),
230

231
    // Allows `extern "platform-intrinsic" { ... }`.
232
    (active, platform_intrinsics, "1.4.0", Some(27731), None),
233

234 235
    // Allows `#[unwind(..)]`.
    //
236 237
    // Permits specifying whether a function should permit unwinding or abort on unwind.
    (active, unwind_attributes, "1.4.0", Some(58760), None),
V
Vadim Petrochenkov 已提交
238

A
Alexander Regueiro 已提交
239
    // Allows the use of `#[naked]` on functions.
240
    (active, naked_functions, "1.9.0", Some(32408), None),
241

242
    // Allows `#[no_debug]`.
243
    (active, no_debug, "1.5.0", Some(29721), None),
244

245
    // Allows `#[omit_gdb_pretty_printer_section]`.
A
Alexander Regueiro 已提交
246 247
    //
    // rustc internal
248
    (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
249

250
    // Allows attributes on expressions and non-item statements.
251
    (active, stmt_expr_attributes, "1.6.0", Some(15701), None),
252

253
    // Allows the use of type ascription in expressions.
254
    (active, type_ascription, "1.6.0", Some(23416), None),
255

256
    // Allows `cfg(target_thread_local)`.
257
    (active, cfg_target_thread_local, "1.7.0", Some(29594), None),
258 259

    // rustc internal
260
    (active, abi_vectorcall, "1.7.0", None, None),
A
Alex Burka 已提交
261

262
    // Allows `X..Y` patterns.
263
    (active, exclusive_range_pattern, "1.11.0", Some(37854), None),
264

A
Aaron Turon 已提交
265
    // impl specialization (RFC 1210)
266
    (active, specialization, "1.7.0", Some(31844), None),
267

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

271
    // The `!` type. Does not imply 'exhaustive_patterns' (below) any more.
272 273
    (active, never_type, "1.13.0", Some(35121), None),

274
    // Allows exhaustive pattern matching on types that contain uninhabited types.
275
    (active, exhaustive_patterns, "1.13.0", Some(51085), None),
276

277
    // Allows untagged unions `union U { ... }`.
278
    (active, untagged_unions, "1.13.0", Some(32836), None),
A
Andre Bogus 已提交
279

280 281 282
    // Used to identify the `compiler_builtins` crate.
    //
    // rustc internal.
283
    (active, compiler_builtins, "1.13.0", None, None),
284

285
    // Allows `#[link(..., cfg(..))]`.
286
    (active, link_cfg, "1.14.0", Some(37406), None),
287

288
    // Allows `extern "ptx-*" fn()`.
289
    (active, abi_ptx, "1.15.0", Some(38788), None),
290

291
    // The `repr(i128)` annotation for enums.
292
    (active, repr128, "1.16.0", Some(35118), None),
293

G
gnzlbg 已提交
294
    // Allows the use of `#[ffi_returns_twice]` on foreign functions.
G
gnzlbg 已提交
295 296
    (active, ffi_returns_twice, "1.34.0", Some(58314), None),

297 298
    // The `unadjusted` ABI; perma-unstable.
    //
299
    // rustc internal
300
    (active, abi_unadjusted, "1.16.0", None, None),
301

302
    // Declarative macros 2.0 (`macro`).
303
    (active, decl_macro, "1.17.0", Some(39412), None),
304

305
    // Allows `#[link(kind="static-nobundle"...)]`.
306
    (active, static_nobundle, "1.16.0", Some(37403), None),
V
Vadim Chugunov 已提交
307

308
    // Allows `extern "msp430-interrupt" fn()`.
309
    (active, abi_msp430_interrupt, "1.16.0", Some(38487), None),
J
Jorge Aparicio 已提交
310

311 312
    // Used to identify crates that contain sanitizer runtimes.
    //
J
Jorge Aparicio 已提交
313
    // rustc internal
314
    (active, sanitizer_runtime, "1.17.0", None, None),
315

316
    // Used to identify crates that contain the profiler runtime.
A
Alexander Regueiro 已提交
317
    //
318
    // rustc internal
319
    (active, profiler_runtime, "1.18.0", None, None),
320

321
    // Allows `extern "x86-interrupt" fn()`.
322
    (active, abi_x86_interrupt, "1.17.0", Some(40180), None),
J
Jorge Aparicio 已提交
323

324
    // Allows the `try {...}` expression.
325
    (active, try_blocks, "1.29.0", Some(31436), None),
326

327
    // Allows module-level inline assembly by way of `global_asm!()`.
328
    (active, global_asm, "1.18.0", Some(35119), None),
329

330
    // Allows overlapping impls of marker traits.
331
    (active, overlapping_marker_traits, "1.18.0", Some(29864), None),
332

333
    // Trait attribute to allow overlapping impls.
334 335
    (active, marker_trait_attr, "1.30.0", Some(29864), None),

336
    // rustc internal
337
    (active, abi_thiscall, "1.19.0", None, None),
338

339
    // Allows a test to fail without failing the whole suite.
340
    (active, allow_fail, "1.19.0", Some(46488), None),
341 342

    // Allows unsized tuple coercion.
343
    (active, unsized_tuple_coercion, "1.20.0", Some(42877), None),
344

J
John Kåre Alsaker 已提交
345
    // Generators
346
    (active, generators, "1.21.0", Some(43122), None),
J
John Kåre Alsaker 已提交
347

A
Alex Burka 已提交
348
    // Trait aliases
349
    (active, trait_alias, "1.24.0", Some(41517), None),
J
John Kåre Alsaker 已提交
350

351
    // rustc internal
352
    (active, allocator_internals, "1.20.0", None, None),
K
kennytm 已提交
353

354
    // `#[doc(cfg(...))]`
355
    (active, doc_cfg, "1.21.0", Some(43781), None),
356
    // `#[doc(masked)]`
357
    (active, doc_masked, "1.21.0", Some(44027), None),
358
    // `#[doc(spotlight)]`
359
    (active, doc_spotlight, "1.22.0", Some(45040), None),
360
    // `#[doc(include = "some-file")]`
361
    (active, external_doc, "1.22.0", Some(44732), None),
362

363
    // Future-proofing enums/structs with `#[non_exhaustive]` attribute (RFC 2008).
364
    (active, non_exhaustive, "1.22.0", Some(44109), None),
D
David Wood 已提交
365

366
    // Adds `crate` as visibility modifier, synonymous with `pub(crate)`.
367
    (active, crate_visibility_modifier, "1.23.0", Some(53120), None),
P
Paul Lietar 已提交
368 369

    // extern types
370
    (active, extern_types, "1.23.0", Some(43467), None),
371

372
    // Allows trait methods with arbitrary self types.
373
    (active, arbitrary_self_types, "1.23.0", Some(44874), None),
374

375
    // In-band lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`).
376
    (active, in_band_lifetimes, "1.23.0", Some(44524), None),
377

A
Alexander Regueiro 已提交
378
    // Generic associated types (RFC 1598)
379
    (active, generic_associated_types, "1.23.0", Some(44265), None),
380

381
    // Infer static outlives requirements (RFC 2093).
382
    (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None),
383

384
    // Allows macro invocations in `extern {}` blocks.
385
    (active, macros_in_extern, "1.27.0", Some(49476), None),
386

O
Oliver Schneider 已提交
387 388 389
    // `existential type`
    (active, existential_type, "1.28.0", Some(34511), None),

390
    // unstable `#[target_feature]` directives
391 392 393 394 395 396 397 398 399
    (active, arm_target_feature, "1.27.0", Some(44839), None),
    (active, aarch64_target_feature, "1.27.0", Some(44839), None),
    (active, hexagon_target_feature, "1.27.0", Some(44839), None),
    (active, powerpc_target_feature, "1.27.0", Some(44839), None),
    (active, mips_target_feature, "1.27.0", Some(44839), None),
    (active, avx512_target_feature, "1.27.0", Some(44839), None),
    (active, mmx_target_feature, "1.27.0", Some(44839), None),
    (active, sse4a_target_feature, "1.27.0", Some(44839), None),
    (active, tbm_target_feature, "1.27.0", Some(44839), None),
G
gnzlbg 已提交
400
    (active, wasm_target_feature, "1.30.0", Some(44839), None),
401 402
    (active, adx_target_feature, "1.32.0", Some(44839), None),
    (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None),
J
Jethro Beekman 已提交
403
    (active, movbe_target_feature, "1.34.0", Some(44839), None),
404 405 406

    // Allows macro invocations on modules expressions and statements and
    // procedural macros to expand to non-items.
407
    (active, proc_macro_hygiene, "1.30.0", Some(54727), None),
G
Guillaume Gomez 已提交
408

409
    // `#[doc(alias = "...")]`
410
    (active, doc_alias, "1.27.0", Some(50146), None),
411

M
Matthew Jasper 已提交
412 413
    // inconsistent bounds in where clauses
    (active, trivial_bounds, "1.28.0", Some(48214), None),
E
est31 已提交
414

415
    // `'a: { break 'a; }`
E
est31 已提交
416
    (active, label_break_value, "1.28.0", Some(48594), None),
417

V
varkor 已提交
418 419
    // Exhaustive pattern matching on `usize` and `isize`.
    (active, precise_pointer_size_matching, "1.32.0", Some(56354), None),
V
varkor 已提交
420

421
    // `#[doc(keyword = "...")]`
422
    (active, doc_keyword, "1.28.0", Some(51315), None),
W
Without Boats 已提交
423

424
    // Allows async and await syntax.
T
Taylor Cramer 已提交
425
    (active, async_await, "1.28.0", Some(50547), None),
S
Simon Sapin 已提交
426

427
    // `#[alloc_error_handler]`
S
Simon Sapin 已提交
428
    (active, alloc_error_handler, "1.29.0", Some(51540), None),
R
Richard Diamond 已提交
429 430

    (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None),
431

432
    // Added for testing E0705; perma-unstable.
433
    (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)),
434

435
    // Allows unsized rvalues at arguments and parameters.
M
Masaki Hara 已提交
436
    (active, unsized_locals, "1.30.0", Some(48055), None),
J
John Renner 已提交
437

438 439
    // `#![test_runner]`
    // `#[test_case]`
J
John Renner 已提交
440
    (active, custom_test_frameworks, "1.30.0", Some(50297), None),
441

442
    // non-builtin attributes in inner attribute position
443
    (active, custom_inner_attributes, "1.30.0", Some(54726), None),
F
F001 已提交
444

445
    // Allow mixing of bind-by-move in patterns and references to
446
    // those identifiers in guards, *if* we are using MIR-borrowck
447 448
    // (aka NLL). Essentially this means you need to be using the
    // 2018 edition or later.
449
    (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None),
450

451
    // Allows `impl Trait` in bindings (`let`, `const`, `static`).
452
    (active, impl_trait_in_bindings, "1.30.0", Some(34511), None),
H
Havvy (Ryan Scheel) 已提交
453

454
    // Allows `const _: TYPE = VALUE`.
455
    (active, underscore_const_names, "1.31.0", Some(54912), None),
456

457
    // Adds `reason` and `expect` lint attributes.
Z
Zack M. Davis 已提交
458
    (active, lint_reasons, "1.31.0", Some(54503), None),
459

460 461
    // Allows paths to enum variants on type aliases.
    (active, type_alias_enum_variants, "1.31.0", Some(49683), None),
462 463 464

    // Re-Rebalance coherence
    (active, re_rebalance_coherence, "1.32.0", Some(55437), None),
465

V
varkor 已提交
466 467 468
    // Const generic types.
    (active, const_generics, "1.34.0", Some(44580), None),

469 470
    // #[optimize(X)]
    (active, optimize_attribute, "1.34.0", Some(54882), None),
471 472 473

    // #[repr(align(X))] on enums
    (active, repr_align_enum, "1.34.0", Some(57996), None),
474 475 476

    // Allows the use of C-variadics
    (active, c_variadic, "1.34.0", Some(44930), None),
477 478 479
);

declare_features! (
480 481
    (removed, import_shadowing, "1.0.0", None, None, None),
    (removed, managed_boxes, "1.0.0", None, None, None),
482
    // Allows use of unary negate on unsigned integers, e.g., -e for e: u8
483 484
    (removed, negate_unsigned, "1.0.0", Some(29645), None, None),
    (removed, reflect, "1.0.0", Some(27749), None, None),
485
    // A way to temporarily opt out of opt in copy. This will *never* be accepted.
486 487 488 489 490 491
    (removed, opt_out_copy, "1.0.0", None, None, None),
    (removed, quad_precision_float, "1.0.0", None, None, None),
    (removed, struct_inherit, "1.0.0", None, None, None),
    (removed, test_removed_feature, "1.0.0", None, None, None),
    (removed, visible_private_types, "1.0.0", None, None, None),
    (removed, unsafe_no_drop_flag, "1.0.0", None, None, None),
492 493
    // Allows using items which are missing stability attributes
    // rustc internal
494 495 496 497 498 499 500 501
    (removed, unmarked_api, "1.0.0", None, None, None),
    (removed, pushpop_unsafe, "1.2.0", None, None, None),
    (removed, allocator, "1.0.0", None, None, None),
    (removed, simd, "1.0.0", Some(27731), None,
     Some("removed in favor of `#[repr(simd)]`")),
    (removed, advanced_slice_patterns, "1.0.0", Some(23121), None,
     Some("merged into `#![feature(slice_patterns)]`")),
    (removed, macro_reexport, "1.0.0", Some(29638), None,
502
     Some("subsumed by `pub use`")),
503 504 505 506 507 508 509 510
    (removed, proc_macro_mod, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
    (removed, proc_macro_expr, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
    (removed, proc_macro_non_items, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
    (removed, proc_macro_gen, "1.27.0", Some(54727), None,
     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
511 512
    (removed, panic_implementation, "1.28.0", Some(44489), None,
     Some("subsumed by `#[panic_handler]`")),
513 514 515
    // Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`.
    (removed, custom_derive, "1.0.0", Some(29644), None,
     Some("subsumed by `#[proc_macro_derive]`")),
M
Mazdak Farrokhzad 已提交
516 517 518
    // Paths of the form: `extern::foo::bar`
    (removed, extern_in_paths, "1.33.0", Some(55600), None,
     Some("subsumed by `::foo::bar` paths")),
519
    (removed, quote, "1.0.0", Some(29601), None, None),
520 521
);

522
declare_features! (
523
    (stable_removed, no_stack_check, "1.0.0", None, None),
524 525 526
);

declare_features! (
527
    (accepted, associated_types, "1.0.0", None, None),
528
    // Allows overloading augmented assignment operations like `a += b`.
529
    (accepted, augmented_assignments, "1.8.0", Some(28235), None),
530
    // Allows empty structs and enum variants with braces.
531
    (accepted, braced_empty_structs, "1.8.0", Some(29720), None),
532
    // Allows indexing into constant arrays.
533
    (accepted, const_indexing, "1.26.0", Some(29947), None),
534 535 536
    (accepted, default_type_params, "1.0.0", None, None),
    (accepted, globs, "1.0.0", None, None),
    (accepted, if_let, "1.0.0", None, None),
537 538
    // A temporary feature gate used to enable parser extensions needed
    // to bootstrap fix for #5723.
539 540
    (accepted, issue_5723_bootstrap, "1.0.0", None, None),
    (accepted, macro_rules, "1.0.0", None, None),
541
    // Allows using `#![no_std]`.
542 543 544
    (accepted, no_std, "1.6.0", None, None),
    (accepted, slicing_syntax, "1.0.0", None, None),
    (accepted, struct_variant, "1.0.0", None, None),
545
    // These are used to test this portion of the compiler, they don't actually
546
    // mean anything.
547 548
    (accepted, test_accepted_feature, "1.0.0", None, None),
    (accepted, tuple_indexing, "1.0.0", None, None),
D
Daniele Baracchi 已提交
549
    // Allows macros to appear in the type position.
550 551
    (accepted, type_macros, "1.13.0", Some(27245), None),
    (accepted, while_let, "1.0.0", None, None),
552
    // Allows `#[deprecated]` attribute.
553
    (accepted, deprecated, "1.9.0", Some(29935), None),
N
Nick Cameron 已提交
554
    // `expr?`
555
    (accepted, question_mark, "1.13.0", Some(31436), None),
556
    // Allows `..` in tuple (struct) patterns.
557 558
    (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None),
    (accepted, item_like_imports, "1.15.0", Some(35120), None),
559
    // Allows using `Self` and associated types in struct expressions and patterns.
560
    (accepted, more_struct_aliases, "1.16.0", Some(37544), None),
561
    // elide `'static` lifetimes in `static`s and `const`s.
562
    (accepted, static_in_const, "1.17.0", Some(35897), None),
E
est31 已提交
563
    // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
564
    (accepted, field_init_shorthand, "1.17.0", Some(37340), None),
T
Taylor Cramer 已提交
565
    // Allows the definition recursive static items.
566
    (accepted, static_recursion, "1.17.0", Some(29719), None),
567
    // `pub(restricted)` visibilities (RFC 1422)
568
    (accepted, pub_restricted, "1.18.0", Some(32409), None),
569
    // `#![windows_subsystem]`
570
    (accepted, windows_subsystem, "1.18.0", Some(37499), None),
571
    // Allows `break {expr}` with a value inside `loop`s.
572
    (accepted, loop_break_value, "1.19.0", Some(37339), None),
573
    // Permits numeric fields in struct expressions and patterns.
574
    (accepted, relaxed_adts, "1.19.0", Some(35626), None),
575
    // Coerces non capturing closures to function pointers.
576
    (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None),
577
    // Allows attributes on struct literal fields.
578
    (accepted, struct_field_attributes, "1.20.0", Some(38814), None),
579
    // Allows the definition of associated constants in `trait` or `impl` blocks.
580
    (accepted, associated_consts, "1.20.0", Some(29646), None),
581
    // Usage of the `compile_error!` macro.
582
    (accepted, compile_error, "1.20.0", Some(40872), None),
583
    // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
584
    (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None),
585
    // Allows `Drop` types in constants (RFC 1440).
586
    (accepted, drop_types_in_const, "1.22.0", Some(33156), None),
C
CensoredUsername 已提交
587
    // Allows the sysV64 ABI to be specified on all platforms
588
    // instead of just the platforms on which it is the C ABI.
589
    (accepted, abi_sysv64, "1.24.0", Some(36167), None),
590
    // Allows `repr(align(16))` struct attribute (RFC 1358).
591
    (accepted, repr_align, "1.25.0", Some(33626), None),
592
    // Allows '|' at beginning of match arms (RFC 1925).
593
    (accepted, match_beginning_vert, "1.25.0", Some(44101), None),
P
Pietro Albini 已提交
594
    // Nested groups in `use` (RFC 2128)
595
    (accepted, use_nested_groups, "1.25.0", Some(44494), None),
596
    // `a..=b` and `..=b`
597
    (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None),
598
    // Allows `..=` in patterns (RFC 1192).
599
    (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None),
600 601
    // Termination trait in main (RFC 1937)
    (accepted, termination_trait, "1.26.0", Some(43301), None),
602
    // `Copy`/`Clone` closures (RFC 2132).
603 604
    (accepted, clone_closures, "1.26.0", Some(44490), None),
    (accepted, copy_closures, "1.26.0", Some(44490), None),
T
Taylor Cramer 已提交
605 606
    // Allows `impl Trait` in function arguments.
    (accepted, universal_impl_trait, "1.26.0", Some(34511), None),
607 608
    // Allows `impl Trait` in function return types.
    (accepted, conservative_impl_trait, "1.26.0", Some(34511), None),
M
Mark Mansi 已提交
609 610
    // The `i128` type
    (accepted, i128_type, "1.26.0", Some(35118), None),
T
Taylor Cramer 已提交
611 612
    // Default match binding modes (RFC 2005)
    (accepted, match_default_bindings, "1.26.0", Some(42640), None),
613
    // Allows `'_` placeholder lifetimes.
T
Taylor Cramer 已提交
614
    (accepted, underscore_lifetimes, "1.26.0", Some(44524), None),
615
    // Allows attributes on lifetime/type formal parameters in generics (RFC 1327).
616
    (accepted, generic_param_attrs, "1.27.0", Some(48848), None),
617
    // Allows `cfg(target_feature = "...")`.
A
Alex Crichton 已提交
618
    (accepted, cfg_target_feature, "1.27.0", Some(29717), None),
619
    // Allows `#[target_feature(...)]`.
A
Alex Crichton 已提交
620
    (accepted, target_feature, "1.27.0", None, None),
621
    // Trait object syntax with `dyn` prefix
622
    (accepted, dyn_trait, "1.27.0", Some(44662), None),
623
    // Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940).
624
    (accepted, fn_must_use, "1.27.0", Some(43302), None),
625
    // Allows use of the `:lifetime` macro fragment specifier.
A
Alex Burka 已提交
626
    (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
D
dylan_DPC 已提交
627
    // Termination trait in tests (RFC 1937)
D
dylan_DPC 已提交
628
    (accepted, termination_trait_test, "1.27.0", Some(48854), None),
629
    // The `#[global_allocator]` attribute
630
    (accepted, global_allocator, "1.28.0", Some(27389), None),
631
    // Allows `#[repr(transparent)]` attribute on newtype structs.
S
Simon Sapin 已提交
632
    (accepted, repr_transparent, "1.28.0", Some(43036), None),
633
    // Procedural macros in `proc-macro` crates
634
    (accepted, proc_macro, "1.29.0", Some(38356), None),
R
Rusty Blitzerr 已提交
635 636
    // `foo.rs` as an alternative to `foo/mod.rs`
    (accepted, non_modrs_mods, "1.30.0", Some(44660), None),
637
    // Allows use of the `:vis` macro fragment specifier
638
    (accepted, macro_vis_matcher, "1.30.0", Some(41022), None),
639 640 641
    // Allows importing and reexporting macros with `use`,
    // enables macro modularization in general.
    (accepted, use_extern_macros, "1.30.0", Some(35896), None),
642
    // Allows keywords to be escaped for use as identifiers.
643
    (accepted, raw_identifiers, "1.30.0", Some(48589), None),
644
    // Attributes scoped to tools.
645
    (accepted, tool_attributes, "1.30.0", Some(44690), None),
646
    // Allows multi-segment paths in attributes and derives.
647
    (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None),
648 649
    // Allows all literals in attribute lists and values of key-value pairs.
    (accepted, attr_literals, "1.30.0", Some(34981), None),
650
    // Infer outlives requirements (RFC 2093).
651
    (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None),
J
Jorge Aparicio 已提交
652
    (accepted, panic_handler, "1.30.0", Some(44489), None),
653
    // Used to preserve symbols (see llvm.used).
J
Jorge Aparicio 已提交
654
    (accepted, used, "1.30.0", Some(40289), None),
655 656
    // `crate` in paths
    (accepted, crate_in_paths, "1.30.0", Some(45477), None),
657
    // Resolve absolute paths as paths from other crates.
658
    (accepted, extern_absolute_paths, "1.30.0", Some(44660), None),
659
    // Access to crate names passed via `--extern` through prelude.
660
    (accepted, extern_prelude, "1.30.0", Some(44660), None),
661 662
    // Parentheses in patterns
    (accepted, pattern_parentheses, "1.31.0", Some(51087), None),
663
    // Allows the definition of `const fn` functions.
664
    (accepted, min_const_fn, "1.31.0", Some(53555), None),
F
flip1995 已提交
665 666
    // Scoped lints
    (accepted, tool_lints, "1.31.0", Some(44690), None),
667 668
    // `impl<I:Iterator> Iterator for &mut Iterator`
    // `impl Debug for Foo<'_>`
669
    (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None),
670
    // `extern crate foo as bar;` puts `bar` into extern prelude.
671
    (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None),
672
    // Allows use of the `:literal` macro fragment specifier (RFC 1576).
673
    (accepted, macro_literal_matcher, "1.32.0", Some(35625), None),
674
    // Use `?` as the Kleene "at most one" operator.
M
Mark Mansi 已提交
675
    (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None),
A
Alexander Regueiro 已提交
676
    // `Self` struct constructor (RFC 2302)
A
Alexander Regueiro 已提交
677
    (accepted, self_struct_ctor, "1.32.0", Some(51994), None),
A
Alexander Regueiro 已提交
678 679
    // `Self` in type definitions (RFC 2300)
    (accepted, self_in_typedefs, "1.32.0", Some(49303), None),
680 681
    // Allows `use x::y;` to search `x` in the current scope.
    (accepted, uniform_paths, "1.32.0", Some(53130), None),
682 683
    // Integer match exhaustiveness checking (RFC 2591)
    (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None),
684 685
    // `use path as _;` and `extern crate c as _;`
    (accepted, underscore_imports, "1.33.0", Some(48216), None),
T
Taylor Cramer 已提交
686 687
    // Allows `#[repr(packed(N))]` attribute on structs.
    (accepted, repr_packed, "1.33.0", Some(33158), None),
688 689
    // Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086).
    (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None),
690 691
    // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions.
    (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None),
O
Oliver Scherer 已提交
692 693 694
    // Allows let bindings, assignments and destructuring in `const` functions and constants.
    // As long as control flow is not implemented in const eval, `&&` and `||` may not be used
    // at the same time as let bindings.
695
    (accepted, const_let, "1.33.0", Some(48821), None),
696
    // `#[cfg_attr(predicate, multiple, attributes, here)]`
D
dylan_DPC 已提交
697
    (accepted, cfg_attr_multi, "1.33.0", Some(54881), None),
698 699
    // Top level or-patterns (`p | q`) in `if let` and `while let`.
    (accepted, if_while_or_patterns, "1.33.0", Some(48215), None),
700 701
    // Allows `cfg(target_vendor = "...")`.
    (accepted, cfg_target_vendor, "1.33.0", Some(29718), None),
R
Ryan Leckey 已提交
702 703
    // `extern crate self as foo;` puts local crate root into extern prelude under name `foo`.
    (accepted, extern_crate_self, "1.34.0", Some(56409), None),
704 705
    // support for arbitrary delimited token streams in non-macro attributes
    (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None),
706
);
707

A
Alexander Regueiro 已提交
708
// If you change this, please modify `src/doc/unstable-book` as well. You must
S
Steve Klabnik 已提交
709 710
// move that documentation into the relevant place in the other docs, and
// remove the chapter on the flag.
711

712
#[derive(Copy, Clone, PartialEq, Debug)]
713 714 715 716
pub enum AttributeType {
    /// Normal, builtin attribute that is consumed
    /// by the compiler before the unused_attribute check
    Normal,
717

718 719 720 721
    /// 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,
722

723 724 725 726 727 728 729
    /// 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
730
    Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
731 732 733 734 735

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

V
Vadim Petrochenkov 已提交
736 737
/// A template that the attribute input must match.
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
738 739 740 741 742 743 744 745
#[derive(Clone, Copy)]
pub struct AttributeTemplate {
    word: bool,
    list: Option<&'static str>,
    name_value_str: Option<&'static str>,
}

impl AttributeTemplate {
A
Alexander Regueiro 已提交
746
    /// Checks that the given meta-item is compatible with this template.
747 748 749 750 751 752 753 754 755 756
    fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool {
        match meta_item_kind {
            ast::MetaItemKind::Word => self.word,
            ast::MetaItemKind::List(..) => self.list.is_some(),
            ast::MetaItemKind::NameValue(lit) if lit.node.is_str() => self.name_value_str.is_some(),
            ast::MetaItemKind::NameValue(..) => false,
        }
    }
}

V
Vadim Petrochenkov 已提交
757
/// A convenience macro for constructing attribute templates.
A
Alexander Regueiro 已提交
758
/// E.g., `template!(Word, List: "description")` means that the attribute
V
Vadim Petrochenkov 已提交
759
/// supports forms `#[attr]` and `#[attr(description)]`.
760 761 762 763 764 765 766 767 768 769 770 771
macro_rules! template {
    (Word) => { template!(@ true, None, None) };
    (List: $descr: expr) => { template!(@ false, Some($descr), None) };
    (NameValueStr: $descr: expr) => { template!(@ false, None, Some($descr)) };
    (Word, List: $descr: expr) => { template!(@ true, Some($descr), None) };
    (Word, NameValueStr: $descr: expr) => { template!(@ true, None, Some($descr)) };
    (List: $descr1: expr, NameValueStr: $descr2: expr) => {
        template!(@ false, Some($descr1), Some($descr2))
    };
    (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => {
        template!(@ true, Some($descr1), Some($descr2))
    };
V
Vadim Petrochenkov 已提交
772 773 774
    (@ $word: expr, $list: expr, $name_value_str: expr) => { AttributeTemplate {
        word: $word, list: $list, name_value_str: $name_value_str
    } };
775 776
}

N
Nick Cameron 已提交
777 778 779
impl AttributeGate {
    fn is_deprecated(&self) -> bool {
        match *self {
780
            Gated(Stability::Deprecated(_, _), ..) => true,
N
Nick Cameron 已提交
781 782 783 784 785
            _ => false,
        }
    }
}

786
#[derive(Copy, Clone, Debug)]
787 788
pub enum Stability {
    Unstable,
789 790 791
    // First argument is tracking issue link; second argument is an optional
    // help message, which defaults to "remove this attribute"
    Deprecated(&'static str, Option<&'static str>),
792 793
}

794
// fn() is not Debug
T
Taiki Endo 已提交
795 796
impl std::fmt::Debug for AttributeGate {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
797
        match *self {
798
            Gated(ref stab, name, expl, _) =>
N
Nick Cameron 已提交
799
                write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
800 801 802 803 804 805 806 807 808 809 810 811
            Ungated => write!(fmt, "Ungated")
        }
    }
}

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

814 815 816
pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType,
                                                AttributeTemplate, AttributeGate)> {
    BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect()
N
Nick Cameron 已提交
817 818
}

819
pub fn is_builtin_attr_name(name: ast::Name) -> bool {
820
    BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, ..)| name == builtin_name)
821 822
}

823
pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
824
    BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, ..)| attr.path == builtin_name)
825 826
}

827
// Attributes that have a special meaning to rustc or rustdoc
828
pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, AttributeGate)] = &[
829 830
    // Normal attributes

831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
    ("warn", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated),
    ("allow", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated),
    ("forbid", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated),
    ("deny", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated),

    ("macro_use", Normal, template!(Word, List: "name1, name2, ..."), Ungated),
    ("macro_export", Normal, template!(Word, List: "local_inner_macros"), Ungated),
    ("plugin_registrar", Normal, template!(Word), Ungated),

    ("cfg", Normal, template!(List: "predicate"), Ungated),
    ("cfg_attr", Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated),
    ("main", Normal, template!(Word), Ungated),
    ("start", Normal, template!(Word), Ungated),
    ("repr", Normal, template!(List: "C, packed, ..."), Ungated),
    ("path", Normal, template!(NameValueStr: "file"), Ungated),
    ("automatically_derived", Normal, template!(Word), Ungated),
    ("no_mangle", Normal, template!(Word), Ungated),
    ("no_link", Normal, template!(Word), Ungated),
    ("derive", Normal, template!(List: "Trait1, Trait2, ..."), Ungated),
    ("should_panic", Normal, template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"),
                                Ungated),
    ("ignore", Normal, template!(Word, NameValueStr: "reason"), Ungated),
    ("no_implicit_prelude", Normal, template!(Word), Ungated),
    ("reexport_test_harness_main", Normal, template!(NameValueStr: "name"), Ungated),
    ("link_args", Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable,
856 857 858 859 860
                                "link_args",
                                "the `link_args` attribute is experimental and not \
                                 portable across platforms, it is recommended to \
                                 use `#[link(name = \"foo\")] instead",
                                cfg_fn!(link_args))),
861
    ("macro_escape", Normal, template!(Word), Ungated),
862

863
    // RFC #1445.
864
    ("structural_match", Whitelisted, template!(Word), Gated(Stability::Unstable,
865
                                            "structural_match",
866
                                            "the semantics of constant patterns is \
867 868
                                             not yet settled",
                                            cfg_fn!(structural_match))),
869

D
David Wood 已提交
870
    // RFC #2008
871
    ("non_exhaustive", Whitelisted, template!(Word), Gated(Stability::Unstable,
D
David Wood 已提交
872 873 874 875
                                          "non_exhaustive",
                                          "non exhaustive is an experimental feature",
                                          cfg_fn!(non_exhaustive))),

876
    // RFC #1268
877
    ("marker", Normal, template!(Word), Gated(Stability::Unstable,
878 879 880 881
                             "marker_trait_attr",
                             "marker traits is an experimental feature",
                             cfg_fn!(marker_trait_attr))),

882
    ("plugin", CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable,
883
                                 "plugin",
884
                                 "compiler plugins are experimental \
885 886 887
                                  and possibly buggy",
                                 cfg_fn!(plugin))),

888 889
    ("no_std", CrateLevel, template!(Word), Ungated),
    ("no_core", CrateLevel, template!(Word), Gated(Stability::Unstable,
890
                                  "no_core",
891 892
                                  "no_core is experimental",
                                  cfg_fn!(no_core))),
893
    ("lang", Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable,
894
                           "lang_items",
895 896
                           "language items are subject to change",
                           cfg_fn!(lang_items))),
897 898
    ("linkage", Whitelisted, template!(NameValueStr: "external|internal|..."),
                                   Gated(Stability::Unstable,
899
                                   "linkage",
900
                                   "the `linkage` attribute is experimental \
901 902
                                    and not portable across platforms",
                                   cfg_fn!(linkage))),
903
    ("thread_local", Whitelisted, template!(Word), Gated(Stability::Unstable,
904
                                        "thread_local",
905
                                        "`#[thread_local]` is an experimental feature, and does \
906
                                         not currently handle destructors.",
907
                                        cfg_fn!(thread_local))),
908

909 910 911 912
    ("rustc_on_unimplemented", Normal, template!(List:
                          r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
                          NameValueStr: "message"),
                                             Gated(Stability::Unstable,
913
                                             "on_unimplemented",
914
                                             "the `#[rustc_on_unimplemented]` attribute \
915 916
                                              is an experimental feature",
                                             cfg_fn!(on_unimplemented))),
917 918
    ("rustc_const_unstable", Normal, template!(List: r#"feature = "name""#),
                                             Gated(Stability::Unstable,
919 920 921 922
                                             "rustc_const_unstable",
                                             "the `#[rustc_const_unstable]` attribute \
                                              is an internal feature",
                                             cfg_fn!(rustc_const_unstable))),
923 924
    ("global_allocator", Normal, template!(Word), Ungated),
    ("default_lib_allocator", Whitelisted, template!(Word), Gated(Stability::Unstable,
925 926 927 928
                                            "allocator_internals",
                                            "the `#[default_lib_allocator]` \
                                             attribute is an experimental feature",
                                            cfg_fn!(allocator_internals))),
929
    ("needs_allocator", Normal, template!(Word), Gated(Stability::Unstable,
930
                                      "allocator_internals",
931 932
                                      "the `#[needs_allocator]` \
                                       attribute is an experimental \
933
                                       feature",
934
                                      cfg_fn!(allocator_internals))),
935
    ("panic_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable,
936
                                         "panic_runtime",
937 938 939
                                         "the `#[panic_runtime]` attribute is \
                                          an experimental feature",
                                         cfg_fn!(panic_runtime))),
940
    ("needs_panic_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable,
941
                                               "needs_panic_runtime",
942 943 944 945
                                               "the `#[needs_panic_runtime]` \
                                                attribute is an experimental \
                                                feature",
                                               cfg_fn!(needs_panic_runtime))),
946
    ("rustc_outlives", Normal, template!(Word), Gated(Stability::Unstable,
947 948 949 950 951
                                     "rustc_attrs",
                                     "the `#[rustc_outlives]` attribute \
                                      is just used for rustc unit tests \
                                      and will never be stable",
                                     cfg_fn!(rustc_attrs))),
952
    ("rustc_variance", Normal, template!(Word), Gated(Stability::Unstable,
953
                                     "rustc_attrs",
954
                                     "the `#[rustc_variance]` attribute \
N
Niko Matsakis 已提交
955
                                      is just used for rustc unit tests \
956 957
                                      and will never be stable",
                                     cfg_fn!(rustc_attrs))),
958 959 960 961 962 963 964
    ("rustc_layout", Normal, template!(List: "field1, field2, ..."),
     Gated(Stability::Unstable,
           "rustc_attrs",
           "the `#[rustc_layout]` attribute \
            is just used for rustc unit tests \
            and will never be stable",
           cfg_fn!(rustc_attrs))),
965
    ("rustc_regions", Normal, template!(Word), Gated(Stability::Unstable,
966 967 968 969 970
                                    "rustc_attrs",
                                    "the `#[rustc_regions]` attribute \
                                     is just used for rustc unit tests \
                                     and will never be stable",
                                    cfg_fn!(rustc_attrs))),
971
    ("rustc_error", Whitelisted, template!(Word), Gated(Stability::Unstable,
972
                                       "rustc_attrs",
973
                                       "the `#[rustc_error]` attribute \
N
Niko Matsakis 已提交
974
                                        is just used for rustc unit tests \
975 976
                                        and will never be stable",
                                       cfg_fn!(rustc_attrs))),
977
    ("rustc_dump_user_substs", Whitelisted, template!(Word), Gated(Stability::Unstable,
978
                                       "rustc_attrs",
N
Niko Matsakis 已提交
979
                                       "this attribute \
980 981 982
                                        is just used for rustc unit tests \
                                        and will never be stable",
                                       cfg_fn!(rustc_attrs))),
983 984
    ("rustc_if_this_changed", Whitelisted, template!(Word, List: "DepNode"),
                                                 Gated(Stability::Unstable,
985
                                                 "rustc_attrs",
986 987 988 989
                                                 "the `#[rustc_if_this_changed]` attribute \
                                                  is just used for rustc unit tests \
                                                  and will never be stable",
                                                 cfg_fn!(rustc_attrs))),
990 991
    ("rustc_then_this_would_need", Whitelisted, template!(List: "DepNode"),
                                                      Gated(Stability::Unstable,
992
                                                      "rustc_attrs",
993 994 995 996
                                                      "the `#[rustc_if_this_changed]` attribute \
                                                       is just used for rustc unit tests \
                                                       and will never be stable",
                                                      cfg_fn!(rustc_attrs))),
997 998 999
    ("rustc_dirty", Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...",
                                                    /*opt*/ except = "...""#),
                                       Gated(Stability::Unstable,
1000
                                       "rustc_attrs",
1001 1002
                                       "the `#[rustc_dirty]` attribute \
                                        is just used for rustc unit tests \
1003 1004
                                        and will never be stable",
                                       cfg_fn!(rustc_attrs))),
1005 1006 1007
    ("rustc_clean", Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...",
                                                    /*opt*/ except = "...""#),
                                       Gated(Stability::Unstable,
1008
                                       "rustc_attrs",
1009 1010
                                       "the `#[rustc_clean]` attribute \
                                        is just used for rustc unit tests \
1011 1012
                                        and will never be stable",
                                       cfg_fn!(rustc_attrs))),
1013 1014
    ("rustc_partition_reused", Whitelisted, template!(List: r#"cfg = "...", module = "...""#),
                                                  Gated(Stability::Unstable,
1015
                                                  "rustc_attrs",
1016 1017 1018 1019
                                                  "this attribute \
                                                   is just used for rustc unit tests \
                                                   and will never be stable",
                                                  cfg_fn!(rustc_attrs))),
1020 1021
    ("rustc_partition_codegened", Whitelisted, template!(List: r#"cfg = "...", module = "...""#),
                                                      Gated(Stability::Unstable,
1022
                                                      "rustc_attrs",
1023 1024 1025 1026
                                                      "this attribute \
                                                       is just used for rustc unit tests \
                                                       and will never be stable",
                                                      cfg_fn!(rustc_attrs))),
1027 1028 1029
    ("rustc_expected_cgu_reuse", Whitelisted, template!(List: r#"cfg = "...", module = "...",
                                                              kind = "...""#),
                                                    Gated(Stability::Unstable,
1030 1031 1032 1033 1034
                                                    "rustc_attrs",
                                                    "this attribute \
                                                     is just used for rustc unit tests \
                                                     and will never be stable",
                                                    cfg_fn!(rustc_attrs))),
1035
    ("rustc_synthetic", Whitelisted, template!(Word), Gated(Stability::Unstable,
1036 1037 1038 1039 1040
                                                      "rustc_attrs",
                                                      "this attribute \
                                                       is just used for rustc unit tests \
                                                       and will never be stable",
                                                      cfg_fn!(rustc_attrs))),
1041
    ("rustc_symbol_name", Whitelisted, template!(Word), Gated(Stability::Unstable,
1042
                                             "rustc_attrs",
1043 1044
                                             "internal rustc attributes will never be stable",
                                             cfg_fn!(rustc_attrs))),
1045
    ("rustc_def_path", Whitelisted, template!(Word), Gated(Stability::Unstable,
1046
                                           "rustc_attrs",
1047 1048
                                           "internal rustc attributes will never be stable",
                                           cfg_fn!(rustc_attrs))),
1049
    ("rustc_mir", Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable,
1050
                                     "rustc_attrs",
1051 1052
                                     "the `#[rustc_mir]` attribute \
                                      is just used for rustc unit tests \
1053 1054
                                      and will never be stable",
                                     cfg_fn!(rustc_attrs))),
1055
    ("rustc_inherit_overflow_checks", Whitelisted, template!(Word), Gated(Stability::Unstable,
1056
                                                         "rustc_attrs",
1057 1058 1059 1060 1061 1062
                                                         "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))),
1063

1064
    ("rustc_dump_program_clauses", Whitelisted, template!(Word), Gated(Stability::Unstable,
S
scalexm 已提交
1065 1066 1067 1068 1069
                                                     "rustc_attrs",
                                                     "the `#[rustc_dump_program_clauses]` \
                                                      attribute is just used for rustc unit \
                                                      tests and will never be stable",
                                                     cfg_fn!(rustc_attrs))),
1070
    ("rustc_test_marker", Normal, template!(Word), Gated(Stability::Unstable,
1071 1072 1073 1074
                                     "rustc_attrs",
                                     "the `#[rustc_test_marker]` attribute \
                                      is used internally to track tests",
                                     cfg_fn!(rustc_attrs))),
1075
    ("rustc_transparent_macro", Whitelisted, template!(Word), Gated(Stability::Unstable,
1076 1077 1078
                                                   "rustc_attrs",
                                                   "used internally for testing macro hygiene",
                                                    cfg_fn!(rustc_attrs))),
1079
    ("compiler_builtins", Whitelisted, template!(Word), Gated(Stability::Unstable,
1080
                                             "compiler_builtins",
1081 1082 1083 1084 1085
                                             "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))),
1086
    ("sanitizer_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable,
J
Jorge Aparicio 已提交
1087 1088 1089 1090 1091
                                             "sanitizer_runtime",
                                             "the `#[sanitizer_runtime]` attribute is used to \
                                              identify crates that contain the runtime of a \
                                              sanitizer and will never be stable",
                                             cfg_fn!(sanitizer_runtime))),
1092
    ("profiler_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable,
1093 1094 1095 1096 1097 1098
                                             "profiler_runtime",
                                             "the `#[profiler_runtime]` attribute is used to \
                                              identify the `profiler_builtins` crate which \
                                              contains the profiler runtime and will never be \
                                              stable",
                                             cfg_fn!(profiler_runtime))),
1099

1100
    ("allow_internal_unstable", Normal, template!(Word, List: "feat1, feat2, ..."),
1101
                                              Gated(Stability::Unstable,
1102
                                              "allow_internal_unstable",
1103 1104
                                              EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
                                              cfg_fn!(allow_internal_unstable))),
1105

1106
    ("allow_internal_unsafe", Normal, template!(Word), Gated(Stability::Unstable,
1107 1108 1109 1110
                                            "allow_internal_unsafe",
                                            EXPLAIN_ALLOW_INTERNAL_UNSAFE,
                                            cfg_fn!(allow_internal_unsafe))),

1111
    ("fundamental", Whitelisted, template!(Word), Gated(Stability::Unstable,
1112
                                       "fundamental",
1113
                                       "the `#[fundamental]` attribute \
1114 1115
                                        is an experimental feature",
                                       cfg_fn!(fundamental))),
1116

V
Vadim Petrochenkov 已提交
1117 1118
    ("proc_macro_derive", Normal, template!(List: "TraitName, \
                                                   /*opt*/ attributes(name1, name2, ...)"),
1119
                                       Ungated),
1120

1121
    ("rustc_copy_clone_marker", Whitelisted, template!(Word), Gated(Stability::Unstable,
1122
                                                   "rustc_attrs",
1123 1124 1125
                                                   "internal implementation detail",
                                                   cfg_fn!(rustc_attrs))),

1126
    // FIXME: #14408 whitelist docs since rustdoc looks at them
1127
    ("doc", Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string"), Ungated),
1128

I
Irina Popa 已提交
1129
    // FIXME: #14406 these are processed in codegen, which happens after the
1130
    // lint pass
1131 1132
    ("cold", Whitelisted, template!(Word), Ungated),
    ("naked", Whitelisted, template!(Word), Gated(Stability::Unstable,
1133
                                 "naked_functions",
T
Ticki 已提交
1134
                                 "the `#[naked]` attribute \
1135
                                  is an experimental feature",
1136
                                 cfg_fn!(naked_functions))),
G
gnzlbg 已提交
1137 1138 1139 1140 1141
    ("ffi_returns_twice", Whitelisted, template!(Word), Gated(Stability::Unstable,
                                 "ffi_returns_twice",
                                 "the `#[ffi_returns_twice]` attribute \
                                  is an experimental feature",
                                 cfg_fn!(ffi_returns_twice))),
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
    ("target_feature", Whitelisted, template!(List: r#"enable = "name""#), Ungated),
    ("export_name", Whitelisted, template!(NameValueStr: "name"), Ungated),
    ("inline", Whitelisted, template!(Word, List: "always|never"), Ungated),
    ("link", Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...",
                                             /*opt*/ cfg = "...""#), Ungated),
    ("link_name", Whitelisted, template!(NameValueStr: "name"), Ungated),
    ("link_section", Whitelisted, template!(NameValueStr: "name"), Ungated),
    ("no_builtins", Whitelisted, template!(Word), Ungated),
    ("no_mangle", Whitelisted, template!(Word), Ungated),
    ("no_debug", Whitelisted, template!(Word), Gated(
1152
        Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None),
N
Nick Cameron 已提交
1153
        "no_debug",
1154 1155
        "the `#[no_debug]` attribute was an experimental feature that has been \
         deprecated due to lack of demand",
N
Nick Cameron 已提交
1156
        cfg_fn!(no_debug))),
1157
    ("omit_gdb_pretty_printer_section", Whitelisted, template!(Word), Gated(Stability::Unstable,
1158
                                                       "omit_gdb_pretty_printer_section",
1159 1160
                                                       "the `#[omit_gdb_pretty_printer_section]` \
                                                        attribute is just used for the Rust test \
1161 1162
                                                        suite",
                                                       cfg_fn!(omit_gdb_pretty_printer_section))),
1163 1164
    ("unsafe_destructor_blind_to_params",
     Normal,
1165
     template!(Word),
1166 1167
     Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761",
                                 Some("replace this attribute with `#[may_dangle]`")),
1168
           "dropck_parametricity",
1169 1170
           "unsafe_destructor_blind_to_params has been replaced by \
            may_dangle and will be removed in the future",
1171
           cfg_fn!(dropck_parametricity))),
1172 1173
    ("may_dangle",
     Normal,
1174
     template!(Word),
1175 1176
     Gated(Stability::Unstable,
           "dropck_eyepatch",
1177 1178
           "may_dangle has unstable semantics and may be removed in the future",
           cfg_fn!(dropck_eyepatch))),
1179
    ("unwind", Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable,
1180 1181
                                  "unwind_attributes",
                                  "#[unwind] is experimental",
1182
                                  cfg_fn!(unwind_attributes))),
1183
    ("used", Whitelisted, template!(Word), Ungated),
1184 1185

    // used in resolve
1186
    ("prelude_import", Whitelisted, template!(Word), Gated(Stability::Unstable,
1187
                                          "prelude_import",
1188 1189
                                          "`#[prelude_import]` is for use by rustc only",
                                          cfg_fn!(prelude_import))),
1190 1191 1192

    // FIXME: #14407 these are only looked at on-demand so we can't
    // guarantee they'll have already been checked
1193 1194 1195 1196 1197 1198
    ("rustc_deprecated", Whitelisted, template!(List: r#"since = "version", reason = "...""#),
                                        Ungated),
    ("must_use", Whitelisted, template!(Word, NameValueStr: "reason"), Ungated),
    ("stable", Whitelisted, template!(List: r#"feature = "name", since = "version""#), Ungated),
    ("unstable", Whitelisted, template!(List: r#"feature = "name", reason = "...", issue = "N""#),
                                        Ungated),
1199 1200 1201 1202 1203 1204 1205 1206 1207
    ("deprecated",
        Normal,
        template!(
            Word,
            List: r#"/*opt*/ since = "version", /*opt*/ note = "reason"#,
            NameValueStr: "reason"
        ),
        Ungated
    ),
1208 1209

    ("rustc_paren_sugar", Normal, template!(Word), Gated(Stability::Unstable,
1210
                                        "unboxed_closures",
1211 1212
                                        "unboxed_closures are still evolving",
                                        cfg_fn!(unboxed_closures))),
1213

1214
    ("windows_subsystem", Whitelisted, template!(NameValueStr: "windows|console"), Ungated),
1215

1216 1217
    ("proc_macro_attribute", Normal, template!(Word), Ungated),
    ("proc_macro", Normal, template!(Word), Ungated),
1218

1219
    ("rustc_proc_macro_decls", Normal, template!(Word), Gated(Stability::Unstable,
1220
                                             "rustc_attrs",
1221 1222 1223
                                             "used internally by rustc",
                                             cfg_fn!(rustc_attrs))),

1224
    ("allow_fail", Normal, template!(Word), Gated(Stability::Unstable,
1225 1226 1227 1228
                                 "allow_fail",
                                 "allow_fail attribute is currently unstable",
                                 cfg_fn!(allow_fail))),

1229
    ("rustc_std_internal_symbol", Whitelisted, template!(Word), Gated(Stability::Unstable,
1230 1231 1232 1233 1234
                                     "rustc_attrs",
                                     "this is an internal attribute that will \
                                      never be stable",
                                     cfg_fn!(rustc_attrs))),

1235
    // whitelists "identity-like" conversion methods to suggest on type mismatch
1236
    ("rustc_conversion_suggestion", Whitelisted, template!(Word), Gated(Stability::Unstable,
1237 1238 1239 1240 1241
                                                       "rustc_attrs",
                                                       "this is an internal attribute that will \
                                                        never be stable",
                                                       cfg_fn!(rustc_attrs))),

1242
    ("rustc_args_required_const", Whitelisted, template!(List: "N"), Gated(Stability::Unstable,
1243 1244 1245
                                 "rustc_attrs",
                                 "never will be stable",
                                 cfg_fn!(rustc_attrs))),
1246
    // RFC 2070
1247
    ("panic_handler", Normal, template!(Word), Ungated),
1248

1249
    ("alloc_error_handler", Normal, template!(Word), Gated(Stability::Unstable,
S
Simon Sapin 已提交
1250 1251 1252 1253
                           "alloc_error_handler",
                           "#[alloc_error_handler] is an unstable feature",
                           cfg_fn!(alloc_error_handler))),

1254
    // RFC 2412
S
Simonas Kazlauskas 已提交
1255
    ("optimize", Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable,
1256 1257 1258 1259
                               "optimize_attribute",
                               "#[optimize] attribute is an unstable feature",
                               cfg_fn!(optimize_attribute))),

1260
    // Crate level attributes
1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
    ("crate_name", CrateLevel, template!(NameValueStr: "name"), Ungated),
    ("crate_type", CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated),
    ("crate_id", CrateLevel, template!(NameValueStr: "ignored"), Ungated),
    ("feature", CrateLevel, template!(List: "name1, name1, ..."), Ungated),
    ("no_start", CrateLevel, template!(Word), Ungated),
    ("no_main", CrateLevel, template!(Word), Ungated),
    ("no_builtins", CrateLevel, template!(Word), Ungated),
    ("recursion_limit", CrateLevel, template!(NameValueStr: "N"), Ungated),
    ("type_length_limit", CrateLevel, template!(NameValueStr: "N"), Ungated),
    ("test_runner", CrateLevel, template!(List: "path"), Gated(Stability::Unstable,
J
John Renner 已提交
1271
                    "custom_test_frameworks",
1272
                    EXPLAIN_CUSTOM_TEST_FRAMEWORKS,
J
John Renner 已提交
1273
                    cfg_fn!(custom_test_frameworks))),
1274 1275
];

1276
// cfg(...)'s that are feature gated
1277
const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[
1278
    // (name in cfg, feature, function to check if the feature is enabled)
1279
    ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
1280
    ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
1281
    ("rustdoc", "doc_cfg", cfg_fn!(doc_cfg)),
1282 1283
];

1284
#[derive(Debug)]
1285 1286 1287 1288
pub struct GatedCfg {
    span: Span,
    index: usize,
}
1289

1290 1291 1292
impl GatedCfg {
    pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
        GATED_CFGS.iter()
1293
                  .position(|info| cfg.check_name(info.0))
1294 1295 1296 1297 1298 1299 1300
                  .map(|idx| {
                      GatedCfg {
                          span: cfg.span,
                          index: idx
                      }
                  })
    }
J
Jeffrey Seyfried 已提交
1301 1302

    pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
1303
        let (cfg, feature, has_feature) = GATED_CFGS[self.index];
1304
        if !has_feature(features) && !self.span.allows_unstable(feature) {
1305
            let explain = format!("`cfg({})` is experimental and subject to change", cfg);
1306
            emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
1307 1308 1309 1310
        }
    }
}

E
Eduard Burtescu 已提交
1311
struct Context<'a> {
L
Leo Testard 已提交
1312
    features: &'a Features,
1313
    parse_sess: &'a ParseSess,
1314
    plugin_attributes: &'a [(String, AttributeType)],
1315 1316
}

1317
macro_rules! gate_feature_fn {
1318 1319 1320
    ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
        let (cx, has_feature, span,
             name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level);
1321 1322
        let has_feature: bool = has_feature(&$cx.features);
        debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
1323
        if !has_feature && !span.allows_unstable($name) {
1324 1325
            leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
                .emit();
1326
        }
1327 1328 1329 1330 1331
    }}
}

macro_rules! gate_feature {
    ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
1332 1333 1334 1335 1336 1337 1338
        gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
                         stringify!($feature), $explain, GateStrength::Hard)
    };
    ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {
        gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
                         stringify!($feature), $explain, $level)
    };
1339
}
1340

1341
impl<'a> Context<'a> {
1342
    fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
1343
        debug!("check_attribute(attr = {:?})", attr);
1344
        let name = attr.name_or_empty();
1345
        for &(n, ty, _template, ref gateage) in BUILTIN_ATTRIBUTES {
1346
            if name == n {
1347
                if let Gated(_, name, desc, ref has_feature) = *gateage {
1348 1349 1350 1351 1352
                    if !attr.span.allows_unstable(name) {
                        gate_feature_fn!(
                            self, has_feature, attr.span, name, desc, GateStrength::Hard
                        );
                    }
1353
                } else if n == "doc" {
1354 1355 1356 1357 1358 1359 1360
                    if let Some(content) = attr.meta_item_list() {
                        if content.iter().any(|c| c.check_name("include")) {
                            gate_feature!(self, external_doc, attr.span,
                                "#[doc(include = \"...\")] is experimental"
                            );
                        }
                    }
1361
                }
1362
                debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
1363 1364 1365
                return;
            }
        }
1366
        for &(ref n, ref ty) in self.plugin_attributes {
1367
            if attr.path == &**n {
1368
                // Plugins can't gate attributes, so we don't check for it
M
Manish Goregaokar 已提交
1369
                // unlike the code above; we only use this loop to
1370
                // short-circuit to avoid the checks below.
1371
                debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty);
1372 1373 1374
                return;
            }
        }
1375
        if !attr::is_known(attr) {
1376
            if name.starts_with("rustc_") {
1377 1378 1379 1380 1381 1382 1383
                let msg = "unless otherwise specified, attributes with the prefix `rustc_` \
                           are reserved for internal compiler diagnostics";
                gate_feature!(self, rustc_attrs, attr.span, msg);
            } else if !is_macro {
                // Only run the custom attribute lint during regular feature gate
                // checking. Macro gating runs before the plugin attributes are
                // registered, so we skip this in that case.
1384 1385 1386
                let msg = format!("The attribute `{}` is currently unknown to the compiler and \
                                   may have meaning added to it in the future", attr.path);
                gate_feature!(self, custom_attribute, attr.span, &msg);
1387
            }
1388 1389
        }
    }
1390 1391
}

1392 1393
pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
    let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] };
L
Leo Testard 已提交
1394 1395 1396
    cx.check_attribute(attr, true);
}

1397
fn find_lang_feature_issue(feature: &str) -> Option<u32> {
1398 1399
    if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
        let issue = info.2;
1400 1401
        // FIXME (#28244): enforce that active features have issue numbers
        // assert!(issue.is_some())
1402 1403
        issue
    } else {
1404 1405 1406 1407
        // search in Accepted, Removed, or Stable Removed features
        let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES)
            .find(|t| t.0 == feature);
        match found {
1408
            Some(&(_, _, issue, _)) => issue,
1409 1410
            None => panic!("Feature `{}` is not declared anywhere", feature),
        }
1411 1412 1413 1414 1415 1416 1417 1418
    }
}

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

1419
#[derive(Debug, Copy, Clone, PartialEq)]
1420 1421 1422 1423 1424 1425 1426
pub enum GateStrength {
    /// A hard error. (Most feature gates should use this.)
    Hard,
    /// Only a warning. (Use this only as backwards-compatibility demands.)
    Soft,
}

1427
pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue,
1428
                        explain: &str) {
1429 1430 1431 1432
    feature_err(sess, feature, span, issue, explain).emit();
}

pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
1433
                       explain: &str) -> DiagnosticBuilder<'a> {
1434 1435 1436 1437 1438
    leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
}

fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue,
                           explain: &str, level: GateStrength) -> DiagnosticBuilder<'a> {
1439 1440
    let diag = &sess.span_diagnostic;

1441 1442 1443 1444 1445
    let issue = match issue {
        GateIssue::Language => find_lang_feature_issue(feature),
        GateIssue::Library(lib) => lib,
    };

Z
Zack M. Davis 已提交
1446 1447 1448
    let explanation = match issue {
        None | Some(0) => explain.to_owned(),
        Some(n) => format!("{} (see issue #{})", explain, n)
1449 1450 1451
    };

    let mut err = match level {
1452 1453 1454
        GateStrength::Hard => {
            diag.struct_span_err_with_code(span, &explanation, stringify_error_code!(E0658))
        }
1455
        GateStrength::Soft => diag.struct_span_warn(span, &explanation),
N
Nick Cameron 已提交
1456
    };
1457 1458

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

1465 1466 1467 1468 1469 1470 1471
    // If we're on stable and only emitting a "soft" warning, add a note to
    // clarify that the feature isn't "on" (rather than being on but
    // warning-worthy).
    if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft {
        err.help("a nightly build of the compiler is required to enable this feature");
    }

1472
    err
1473

1474 1475
}

1476
const EXPLAIN_BOX_SYNTAX: &str =
L
Leo Testard 已提交
1477 1478
    "box expression syntax is experimental; you can call `Box::new` instead.";

1479
pub const EXPLAIN_STMT_ATTR_SYNTAX: &str =
1480
    "attributes on expressions are experimental.";
L
Leo Testard 已提交
1481

1482
pub const EXPLAIN_ASM: &str =
1483 1484
    "inline assembly is not stable enough for use and is subject to change";

1485
pub const EXPLAIN_GLOBAL_ASM: &str =
A
A.J. Gardner 已提交
1486
    "`global_asm!` is not stable enough for use and is subject to change";
1487

1488
pub const EXPLAIN_CUSTOM_TEST_FRAMEWORKS: &str =
1489 1490
    "custom test frameworks are an unstable feature";

1491
pub const EXPLAIN_LOG_SYNTAX: &str =
1492 1493
    "`log_syntax!` is not stable enough for use and is subject to change";

1494
pub const EXPLAIN_CONCAT_IDENTS: &str =
1495
    "`concat_idents` is not stable enough for use and is subject to change";
W
Wesley Wiser 已提交
1496

1497
pub const EXPLAIN_FORMAT_ARGS_NL: &str =
1498 1499
    "`format_args_nl` is only for internal language use and is subject to change";

1500
pub const EXPLAIN_TRACE_MACROS: &str =
1501
    "`trace_macros` is not stable enough for use and is subject to change";
1502
pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &str =
1503
    "allow_internal_unstable side-steps feature gating and stability checks";
1504
pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &str =
1505
    "allow_internal_unsafe side-steps the unsafe_code lint";
1506

1507
pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str =
M
mark 已提交
1508
    "unsized tuple coercion is not stable enough for use and is subject to change";
1509

C
Corey Richardson 已提交
1510
struct PostExpansionVisitor<'a> {
N
Nick Cameron 已提交
1511
    context: &'a Context<'a>,
C
Corey Richardson 已提交
1512 1513
}

1514 1515 1516
macro_rules! gate_feature_post {
    ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
        let (cx, span) = ($cx, $span);
1517
        if !span.allows_unstable(stringify!($feature)) {
1518
            gate_feature!(cx.context, $feature, span, $explain)
C
Corey Richardson 已提交
1519
        }
1520 1521 1522
    }};
    ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
        let (cx, span) = ($cx, $span);
1523
        if !span.allows_unstable(stringify!($feature)) {
1524 1525
            gate_feature!(cx.context, $feature, span, $explain, $level)
        }
1526
    }}
C
Corey Richardson 已提交
1527 1528
}

1529 1530 1531
impl<'a> PostExpansionVisitor<'a> {
    fn check_abi(&self, abi: Abi, span: Span) {
        match abi {
1532
            Abi::RustIntrinsic => {
1533
                gate_feature_post!(&self, intrinsics, span,
1534 1535
                                   "intrinsics are subject to change");
            },
1536 1537
            Abi::PlatformIntrinsic => {
                gate_feature_post!(&self, platform_intrinsics, span,
1538
                                   "platform intrinsics are experimental and possibly buggy");
1539 1540 1541
            },
            Abi::Vectorcall => {
                gate_feature_post!(&self, abi_vectorcall, span,
1542 1543
                                   "vectorcall is experimental and subject to change");
            },
1544 1545 1546 1547
            Abi::Thiscall => {
                gate_feature_post!(&self, abi_thiscall, span,
                                   "thiscall is experimental and subject to change");
            },
1548 1549 1550
            Abi::RustCall => {
                gate_feature_post!(&self, unboxed_closures, span,
                                   "rust-call ABI is subject to change");
1551
            },
J
Jorge Aparicio 已提交
1552 1553 1554
            Abi::PtxKernel => {
                gate_feature_post!(&self, abi_ptx, span,
                                   "PTX ABIs are experimental and subject to change");
1555 1556 1557 1558 1559
            },
            Abi::Unadjusted => {
                gate_feature_post!(&self, abi_unadjusted, span,
                                   "unadjusted ABI is an implementation detail and perma-unstable");
            },
1560 1561 1562 1563
            Abi::Msp430Interrupt => {
                gate_feature_post!(&self, abi_msp430_interrupt, span,
                                   "msp430-interrupt ABI is experimental and subject to change");
            },
1564 1565 1566 1567
            Abi::X86Interrupt => {
                gate_feature_post!(&self, abi_x86_interrupt, span,
                                   "x86-interrupt ABI is experimental and subject to change");
            },
R
Richard Diamond 已提交
1568 1569 1570 1571
            Abi::AmdGpuKernel => {
                gate_feature_post!(&self, abi_amdgpu_kernel, span,
                                   "amdgpu-kernel ABI is experimental and subject to change");
            },
J
Jorge Aparicio 已提交
1572 1573 1574 1575 1576 1577
            // Stable
            Abi::Cdecl |
            Abi::Stdcall |
            Abi::Fastcall |
            Abi::Aapcs |
            Abi::Win64 |
C
CensoredUsername 已提交
1578
            Abi::SysV64 |
J
Jorge Aparicio 已提交
1579 1580 1581
            Abi::Rust |
            Abi::C |
            Abi::System => {}
1582 1583
        }
    }
1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629

    fn check_builtin_attribute(&mut self, attr: &ast::Attribute, name: &str,
                               template: AttributeTemplate) {
        // Some special attributes like `cfg` must be checked
        // before the generic check, so we skip them here.
        let should_skip = |name| name == "cfg";
        // Some of previously accepted forms were used in practice,
        // report them as warnings for now.
        let should_warn = |name| name == "doc" || name == "ignore" ||
                                 name == "inline" || name == "link";

        match attr.parse_meta(self.context.parse_sess) {
            Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) {
                let mut msg = "attribute must be of the form ".to_owned();
                let mut first = true;
                if template.word {
                    first = false;
                    msg.push_str(&format!("`#[{}{}]`", name, ""));
                }
                if let Some(descr) = template.list {
                    if !first {
                        msg.push_str(" or ");
                    }
                    first = false;
                    msg.push_str(&format!("`#[{}({})]`", name, descr));
                }
                if let Some(descr) = template.name_value_str {
                    if !first {
                        msg.push_str(" or ");
                    }
                    msg.push_str(&format!("`#[{} = \"{}\"]`", name, descr));
                }
                if should_warn(name) {
                    self.context.parse_sess.buffer_lint(
                        BufferedEarlyLintId::IllFormedAttributeInput,
                        meta.span,
                        ast::CRATE_NODE_ID,
                        &msg,
                    );
                } else {
                    self.context.parse_sess.span_diagnostic.span_err(meta.span, &msg);
                }
            }
            Err(mut err) => err.emit(),
        }
    }
1630 1631
}

1632
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
1633
    fn visit_attribute(&mut self, attr: &ast::Attribute) {
1634 1635
        // check for gated attributes
        self.context.check_attribute(attr, false);
1636

K
kennytm 已提交
1637 1638 1639 1640 1641 1642
        if attr.check_name("doc") {
            if let Some(content) = attr.meta_item_list() {
                if content.len() == 1 && content[0].check_name("cfg") {
                    gate_feature_post!(&self, doc_cfg, attr.span,
                        "#[doc(cfg(...))] is experimental"
                    );
1643 1644 1645 1646
                } else if content.iter().any(|c| c.check_name("masked")) {
                    gate_feature_post!(&self, doc_masked, attr.span,
                        "#[doc(masked)] is experimental"
                    );
1647 1648 1649 1650
                } else if content.iter().any(|c| c.check_name("spotlight")) {
                    gate_feature_post!(&self, doc_spotlight, attr.span,
                        "#[doc(spotlight)] is experimental"
                    );
G
Guillaume Gomez 已提交
1651 1652 1653 1654
                } else if content.iter().any(|c| c.check_name("alias")) {
                    gate_feature_post!(&self, doc_alias, attr.span,
                        "#[doc(alias = \"...\")] is experimental"
                    );
1655 1656 1657 1658
                } else if content.iter().any(|c| c.check_name("keyword")) {
                    gate_feature_post!(&self, doc_keyword, attr.span,
                        "#[doc(keyword = \"...\")] is experimental"
                    );
K
kennytm 已提交
1659 1660 1661 1662
                }
            }
        }

1663 1664
        match BUILTIN_ATTRIBUTES.iter().find(|(name, ..)| attr.path == name) {
            Some(&(name, _, template, _)) => self.check_builtin_attribute(attr, name, template),
1665 1666 1667
            None => if let Some(TokenTree::Token(_, token::Eq)) = attr.tokens.trees().next() {
                // All key-value attributes are restricted to meta-item syntax.
                attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok();
1668
            }
1669
        }
1670 1671
    }

1672
    fn visit_name(&mut self, sp: Span, name: ast::Name) {
1673
        if !name.as_str().is_ascii() {
1674 1675
            gate_feature_post!(&self,
                               non_ascii_idents,
D
Donato Sciarra 已提交
1676
                               self.context.parse_sess.source_map().def_span(sp),
1677
                               "non-ascii idents are not fully supported.");
1678 1679 1680
        }
    }

1681
    fn visit_item(&mut self, i: &'a ast::Item) {
1682
        match i.node {
1683 1684 1685 1686 1687 1688 1689
            ast::ItemKind::Const(_,_) => {
                if i.ident.name == "_" {
                    gate_feature_post!(&self, underscore_const_names, i.span,
                                        "naming constants with `_` is unstable");
                }
            }

1690
            ast::ItemKind::ForeignMod(ref foreign_module) => {
1691
                self.check_abi(foreign_module.abi, i.span);
1692 1693
            }

1694
            ast::ItemKind::Fn(..) => {
1695
                if attr::contains_name(&i.attrs[..], "plugin_registrar") {
1696 1697
                    gate_feature_post!(&self, plugin_registrar, i.span,
                                       "compiler plugins are experimental and possibly buggy");
1698
                }
1699
                if attr::contains_name(&i.attrs[..], "start") {
1700
                    gate_feature_post!(&self, start, i.span,
1701 1702 1703 1704
                                      "a #[start] function is an experimental \
                                       feature whose signature may change \
                                       over time");
                }
1705
                if attr::contains_name(&i.attrs[..], "main") {
1706 1707 1708 1709
                    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");
1710
                }
1711 1712
            }

1713
            ast::ItemKind::Struct(..) => {
1714
                for attr in attr::filter_by_name(&i.attrs[..], "repr") {
1715 1716 1717 1718 1719
                    for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
                        if item.check_name("simd") {
                            gate_feature_post!(&self, repr_simd, attr.span,
                                               "SIMD types are experimental and possibly buggy");
                        }
1720
                    }
1721
                }
D
David Manescu 已提交
1722 1723
            }

1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734
            ast::ItemKind::Enum(..) => {
                for attr in attr::filter_by_name(&i.attrs[..], "repr") {
                    for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
                        if item.check_name("align") {
                            gate_feature_post!(&self, repr_align_enum, attr.span,
                                               "`#[repr(align(x))]` on enums is experimental");
                        }
                    }
                }
            }

1735
            ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => {
1736
                if polarity == ast::ImplPolarity::Negative {
1737 1738 1739 1740
                    gate_feature_post!(&self, optin_builtin_traits,
                                       i.span,
                                       "negative trait bounds are not yet fully implemented; \
                                        use marker types for now");
1741
                }
1742

1743 1744 1745 1746
                if let ast::Defaultness::Default = defaultness {
                    gate_feature_post!(&self, specialization,
                                       i.span,
                                       "specialization is unstable");
1747
                }
1748 1749
            }

1750 1751 1752 1753 1754
            ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => {
                gate_feature_post!(&self, optin_builtin_traits,
                                   i.span,
                                   "auto traits are experimental and possibly buggy");
            }
1755

1756 1757 1758 1759 1760 1761 1762 1763 1764
            ast::ItemKind::TraitAlias(..) => {
                gate_feature_post!(
                    &self,
                    trait_alias,
                    i.span,
                    "trait aliases are experimental"
                );
            }

1765 1766 1767 1768 1769
            ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
                let msg = "`macro` is experimental";
                gate_feature_post!(&self, decl_macro, i.span, msg);
            }

O
Oliver Schneider 已提交
1770 1771 1772 1773 1774 1775 1776 1777 1778
            ast::ItemKind::Existential(..) => {
                gate_feature_post!(
                    &self,
                    existential_type,
                    i.span,
                    "existential types are unstable"
                );
            }

1779 1780 1781
            _ => {}
        }

1782
        visit::walk_item(self, i);
1783
    }
1784

1785
    fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
P
Paul Lietar 已提交
1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802
        match i.node {
            ast::ForeignItemKind::Fn(..) |
            ast::ForeignItemKind::Static(..) => {
                let link_name = attr::first_attr_value_str_by_name(&i.attrs, "link_name");
                let links_to_llvm = match link_name {
                    Some(val) => val.as_str().starts_with("llvm."),
                    _ => false
                };
                if links_to_llvm {
                    gate_feature_post!(&self, link_llvm_intrinsics, i.span,
                                       "linking to LLVM intrinsics is experimental");
                }
            }
            ast::ForeignItemKind::Ty => {
                    gate_feature_post!(&self, extern_types, i.span,
                                       "extern types are experimental");
            }
1803
            ast::ForeignItemKind::Macro(..) => {}
1804 1805
        }

1806
        visit::walk_foreign_item(self, i)
1807 1808
    }

1809
    fn visit_ty(&mut self, ty: &'a ast::Ty) {
1810 1811 1812 1813
        match ty.node {
            ast::TyKind::BareFn(ref bare_fn_ty) => {
                self.check_abi(bare_fn_ty.abi, ty.span);
            }
1814 1815 1816 1817
            ast::TyKind::Never => {
                gate_feature_post!(&self, never_type, ty.span,
                                   "The `!` type is experimental");
            }
1818 1819 1820 1821 1822
            _ => {}
        }
        visit::walk_ty(self, ty)
    }

1823
    fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
1824
        if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
1825 1826 1827
            if let ast::TyKind::Never = output_ty.node {
                // Do nothing
            } else {
1828
                self.visit_ty(output_ty)
1829
            }
1830 1831 1832
        }
    }

1833
    fn visit_expr(&mut self, e: &'a ast::Expr) {
1834
        match e.node {
1835
            ast::ExprKind::Box(_) => {
1836
                gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
1837
            }
1838
            ast::ExprKind::Type(..) => {
1839
                gate_feature_post!(&self, type_ascription, e.span,
1840 1841
                                  "type ascription is experimental");
            }
1842 1843 1844
            ast::ExprKind::ObsoleteInPlace(..) => {
                // these get a hard error in ast-validation
            }
J
John Kåre Alsaker 已提交
1845 1846 1847 1848 1849
            ast::ExprKind::Yield(..) => {
                gate_feature_post!(&self, generators,
                                  e.span,
                                  "yield syntax is experimental");
            }
1850
            ast::ExprKind::TryBlock(_) => {
1851
                gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
1852
            }
E
est31 已提交
1853 1854 1855 1856 1857 1858
            ast::ExprKind::Block(_, opt_label) => {
                if let Some(label) = opt_label {
                    gate_feature_post!(&self, label_break_value, label.ident.span,
                                    "labels on blocks are unstable");
                }
            }
1859
            ast::ExprKind::Closure(_, ast::IsAsync::Async { .. }, ..) => {
T
Taylor Cramer 已提交
1860 1861 1862 1863 1864
                gate_feature_post!(&self, async_await, e.span, "async closures are unstable");
            }
            ast::ExprKind::Async(..) => {
                gate_feature_post!(&self, async_await, e.span, "async blocks are unstable");
            }
1865 1866
            _ => {}
        }
1867
        visit::walk_expr(self, e);
1868
    }
1869

M
Matt Ickstadt 已提交
1870
    fn visit_arm(&mut self, arm: &'a ast::Arm) {
M
Matt Ickstadt 已提交
1871
        visit::walk_arm(self, arm)
M
Matt Ickstadt 已提交
1872 1873
    }

1874
    fn visit_pat(&mut self, pattern: &'a ast::Pat) {
1875
        match pattern.node {
1876
            PatKind::Slice(_, Some(ref subslice), _) => {
1877
                gate_feature_post!(&self, slice_patterns,
1878 1879
                                   subslice.span,
                                   "syntax for subslices in slice patterns is not yet stabilized");
1880
            }
1881
            PatKind::Box(..) => {
1882
                gate_feature_post!(&self, box_patterns,
1883
                                  pattern.span,
1884
                                  "box pattern syntax is experimental");
1885
            }
1886
            PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => {
1887 1888 1889
                gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
                                   "exclusive range pattern syntax is experimental");
            }
1890 1891
            _ => {}
        }
1892
        visit::walk_pat(self, pattern)
1893 1894
    }

1895
    fn visit_fn(&mut self,
1896 1897
                fn_kind: FnKind<'a>,
                fn_decl: &'a ast::FnDecl,
1898
                span: Span,
1899
                _node_id: NodeId) {
1900
        match fn_kind {
W
Without Boats 已提交
1901
            FnKind::ItemFn(_, header, _, _) => {
1902
                // Check for const fn and async fn declarations.
N
Nathan Corbyn 已提交
1903
                if header.asyncness.node.is_async() {
W
Without Boats 已提交
1904 1905
                    gate_feature_post!(&self, async_await, span, "async fn is unstable");
                }
1906 1907 1908 1909 1910

                if fn_decl.c_variadic {
                    gate_feature_post!(&self, c_variadic, span,
                                       "C-varaidic functions are unstable");
                }
1911 1912 1913
                // 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.
W
Without Boats 已提交
1914 1915 1916 1917 1918

                self.check_abi(header.abi, span);
            }
            FnKind::Method(_, sig, _, _) => {
                self.check_abi(sig.header.abi, span);
1919
            }
1920 1921
            _ => {}
        }
1922
        visit::walk_fn(self, fn_kind, fn_decl, span);
1923
    }
1924

V
varkor 已提交
1925 1926 1927 1928 1929 1930 1931 1932
    fn visit_generic_param(&mut self, param: &'a GenericParam) {
        if let GenericParamKind::Const { .. } = param.kind {
            gate_feature_post!(&self, const_generics, param.ident.span,
                "const generics are unstable");
        }
        visit::walk_generic_param(self, param);
    }

1933
    fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
1934
        match ti.node {
1935 1936
            ast::TraitItemKind::Method(ref sig, ref block) => {
                if block.is_none() {
W
Without Boats 已提交
1937
                    self.check_abi(sig.header.abi, ti.span);
1938
                }
1939 1940 1941 1942
                if sig.decl.c_variadic {
                    gate_feature_post!(&self, c_variadic, ti.span,
                                       "C-varaidic functions are unstable");
                }
W
Without Boats 已提交
1943
                if sig.header.constness.node == ast::Constness::Const {
1944
                    gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
N
Niko Matsakis 已提交
1945 1946
                }
            }
1947
            ast::TraitItemKind::Type(_, ref default) => {
1948 1949
                // We use three if statements instead of something like match guards so that all
                // of these errors can be emitted if all cases apply.
1950 1951 1952 1953
                if default.is_some() {
                    gate_feature_post!(&self, associated_type_defaults, ti.span,
                                       "associated type defaults are unstable");
                }
1954
                if !ti.generics.params.is_empty() {
1955 1956 1957
                    gate_feature_post!(&self, generic_associated_types, ti.span,
                                       "generic associated types are unstable");
                }
1958 1959 1960 1961
                if !ti.generics.where_clause.predicates.is_empty() {
                    gate_feature_post!(&self, generic_associated_types, ti.span,
                                       "where clauses on associated types are unstable");
                }
S
Sunjay Varma 已提交
1962
            }
1963 1964 1965 1966 1967
            _ => {}
        }
        visit::walk_trait_item(self, ti);
    }

1968
    fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
A
Aaron Turon 已提交
1969
        if ii.defaultness == ast::Defaultness::Default {
1970
            gate_feature_post!(&self, specialization,
A
Aaron Turon 已提交
1971 1972 1973 1974
                              ii.span,
                              "specialization is unstable");
        }

1975
        match ii.node {
O
Oliver Schneider 已提交
1976
            ast::ImplItemKind::Method(..) => {}
O
Oliver Schneider 已提交
1977 1978 1979 1980 1981 1982 1983 1984
            ast::ImplItemKind::Existential(..) => {
                gate_feature_post!(
                    &self,
                    existential_type,
                    ii.span,
                    "existential types are unstable"
                );
            }
1985 1986 1987 1988 1989 1990 1991 1992 1993
            ast::ImplItemKind::Type(_) => {
                if !ii.generics.params.is_empty() {
                    gate_feature_post!(&self, generic_associated_types, ii.span,
                                       "generic associated types are unstable");
                }
                if !ii.generics.where_clause.predicates.is_empty() {
                    gate_feature_post!(&self, generic_associated_types, ii.span,
                                       "where clauses on associated types are unstable");
                }
S
Sunjay Varma 已提交
1994
            }
1995 1996 1997 1998
            _ => {}
        }
        visit::walk_impl_item(self, ii);
    }
1999

2000
    fn visit_vis(&mut self, vis: &'a ast::Visibility) {
2001 2002
        if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node {
            gate_feature_post!(&self, crate_visibility_modifier, vis.span,
2003 2004 2005 2006
                               "`crate` visibility modifier is experimental");
        }
        visit::walk_vis(self, vis);
    }
2007 2008
}

2009
pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
T
Tyler Mandry 已提交
2010
                    crate_edition: Edition, allow_features: &Option<Vec<String>>) -> Features {
2011 2012 2013 2014 2015 2016
    fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
        let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
        if let Some(reason) = reason {
            err.span_note(span, reason);
        }
        err.emit();
2017 2018
    }

2019 2020 2021
    // Some features are known to be incomplete and using them is likely to have
    // unanticipated results, such as compiler crashes. We warn the user about these
    // to alert them.
V
varkor 已提交
2022
    let incomplete_features = ["generic_associated_types", "const_generics"];
2023

2024
    let mut features = Features::new();
2025
    let mut edition_enabled_features = FxHashMap::default();
2026

2027 2028 2029
    for &edition in ALL_EDITIONS {
        if edition <= crate_edition {
            // The `crate_edition` implies its respective umbrella feature-gate
2030
            // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
2031 2032 2033 2034
            edition_enabled_features.insert(Symbol::intern(edition.feature_name()), edition);
        }
    }

2035
    for &(name, .., f_edition, set) in ACTIVE_FEATURES {
2036 2037 2038
        if let Some(f_edition) = f_edition {
            if f_edition <= crate_edition {
                set(&mut features, DUMMY_SP);
2039
                edition_enabled_features.insert(Symbol::intern(name), crate_edition);
2040
            }
2041 2042 2043
        }
    }

2044 2045
    // Process the edition umbrella feature-gates first, to ensure
    // `edition_enabled_features` is completed before it's queried.
J
Jeffrey Seyfried 已提交
2046
    for attr in krate_attrs {
S
Steven Fackler 已提交
2047
        if !attr.check_name("feature") {
2048 2049
            continue
        }
2050

2051 2052
        let list = match attr.meta_item_list() {
            Some(list) => list,
2053
            None => continue,
2054 2055 2056
        };

        for mi in list {
2057 2058 2059
            if !mi.is_word() {
                continue;
            }
2060

2061 2062
            let name = mi.name_or_empty();
            if incomplete_features.iter().any(|f| name == *f) {
2063
                span_handler.struct_span_warn(
2064
                    mi.span(),
2065 2066 2067 2068 2069 2070 2071
                    &format!(
                        "the feature `{}` is incomplete and may cause the compiler to crash",
                        name
                    )
                ).emit();
            }

2072 2073
            if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
                if *edition <= crate_edition {
2074
                    continue;
2075 2076
                }

2077
                for &(name, .., f_edition, set) in ACTIVE_FEATURES {
2078 2079 2080 2081 2082 2083 2084 2085 2086
                    if let Some(f_edition) = f_edition {
                        if f_edition <= *edition {
                            // FIXME(Manishearth) there is currently no way to set
                            // lib features by edition
                            set(&mut features, DUMMY_SP);
                            edition_enabled_features.insert(Symbol::intern(name), *edition);
                        }
                    }
                }
2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097
            }
        }
    }

    for attr in krate_attrs {
        if !attr.check_name("feature") {
            continue
        }

        let list = match attr.meta_item_list() {
            Some(list) => list,
2098
            None => continue,
2099
        };
2100

2101
        for mi in list {
2102 2103 2104
            let name = match mi.ident() {
                Some(ident) if mi.is_word() => ident.name,
                _ => {
2105
                    span_err!(span_handler, mi.span(), E0556,
2106 2107 2108
                            "malformed feature, expected just one word");
                    continue
                }
2109 2110
            };

2111 2112 2113
            if let Some(edition) = edition_enabled_features.get(&name) {
                struct_span_warn!(
                    span_handler,
2114
                    mi.span(),
2115 2116 2117 2118 2119 2120 2121 2122
                    E0705,
                    "the feature `{}` is included in the Rust {} edition",
                    name,
                    edition,
                ).emit();
                continue;
            }

2123 2124 2125
            if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) {
                // Handled in the separate loop above.
                continue;
2126 2127
            }

2128
            if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
T
Tyler Mandry 已提交
2129 2130
                if let Some(allowed) = allow_features.as_ref() {
                    if allowed.iter().find(|f| *f == name.as_str()).is_none() {
2131
                        span_err!(span_handler, mi.span(), E0725,
T
Tyler Mandry 已提交
2132 2133 2134 2135 2136 2137
                                  "the feature `{}` is not in the list of allowed features",
                                  name);
                        continue;
                    }
                }

2138 2139
                set(&mut features, mi.span());
                features.declared_lang_features.push((name, mi.span(), None));
2140
                continue
2141
            }
2142

2143 2144 2145
            let removed = REMOVED_FEATURES.iter().find(|f| name == f.0);
            let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0);
            if let Some((.., reason)) = removed.or(stable_removed) {
2146
                feature_removed(span_handler, mi.span(), *reason);
2147 2148 2149
                continue
            }

V
varkor 已提交
2150 2151
            if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) {
                let since = Some(Symbol::intern(since));
2152
                features.declared_lang_features.push((name, mi.span(), since));
2153 2154 2155
                continue
            }

2156
            features.declared_lib_features.push((name, mi.span()));
2157 2158 2159
        }
    }

L
Leo Testard 已提交
2160
    features
C
Corey Richardson 已提交
2161 2162
}

J
Jeffrey Seyfried 已提交
2163 2164 2165
pub fn check_crate(krate: &ast::Crate,
                   sess: &ParseSess,
                   features: &Features,
2166
                   plugin_attributes: &[(String, AttributeType)],
J
Jeffrey Seyfried 已提交
2167 2168 2169
                   unstable: UnstableFeatures) {
    maybe_stage_features(&sess.span_diagnostic, krate, unstable);
    let ctx = Context {
2170
        features,
2171
        parse_sess: sess,
2172
        plugin_attributes,
J
Jeffrey Seyfried 已提交
2173
    };
L
Lymia Aluysia 已提交
2174

2175 2176
    let visitor = &mut PostExpansionVisitor { context: &ctx };
    visit::walk_crate(visitor, krate);
C
Corey Richardson 已提交
2177
}
2178

2179
#[derive(Clone, Copy, Hash)]
2180
pub enum UnstableFeatures {
A
Alexander Regueiro 已提交
2181
    /// Hard errors for unstable features are active, as on beta/stable channels.
2182
    Disallow,
J
John Hodge 已提交
2183
    /// Allow features to be activated, as on nightly.
2184 2185 2186 2187
    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
2188
    /// features. As a result, this is always required for building Rust itself.
2189 2190 2191
    Cheat
}

T
Tim Neumann 已提交
2192 2193
impl UnstableFeatures {
    pub fn from_environment() -> UnstableFeatures {
2194
        // Whether this is a feature-staged build, i.e., on the beta or stable channel
T
Tim Neumann 已提交
2195
        let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
2196 2197 2198 2199 2200 2201
        // 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 已提交
2202 2203
        }
    }
2204 2205 2206 2207 2208 2209 2210

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

2213
fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223
                        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 已提交
2224
                span_err!(span_handler, attr.span, E0554,
2225
                          "#![feature] may not be used on the {} release channel",
G
ggomez 已提交
2226
                          release_channel);
2227 2228 2229 2230
            }
        }
    }
}