]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/feature_gate/check.rs
derive(Default) for Features
[rust.git] / src / libsyntax / feature_gate / check.rs
1 use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
2 use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
3 use rustc_feature::{Features, Feature, State as FeatureState, UnstableFeatures};
4 use rustc_feature::{find_feature_issue, GateIssue};
5
6 use crate::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
7 use crate::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
8 use crate::attr;
9 use crate::source_map::Spanned;
10 use crate::edition::{ALL_EDITIONS, Edition};
11 use crate::visit::{self, FnKind, Visitor};
12 use crate::sess::ParseSess;
13 use crate::symbol::{Symbol, sym};
14
15 use errors::{Applicability, DiagnosticBuilder, Handler};
16 use rustc_data_structures::fx::FxHashMap;
17 use syntax_pos::{Span, DUMMY_SP, MultiSpan};
18 use log::debug;
19
20 use rustc_error_codes::*;
21
22 macro_rules! gate_feature_fn {
23     ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{
24         let (cx, has_feature, span,
25              name, explain, level) = (&*$cx, $has_feature, $span, $name, $explain, $level);
26         let has_feature: bool = has_feature(&$cx.features);
27         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
28         if !has_feature && !span.allows_unstable($name) {
29             leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
30                 .emit();
31         }
32     }}
33 }
34
35 macro_rules! gate_feature {
36     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
37         gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
38                          sym::$feature, $explain, GateStrength::Hard)
39     };
40     ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {
41         gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
42                          sym::$feature, $explain, $level)
43     };
44 }
45
46 pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
47     PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
48 }
49
50 #[derive(Debug, Copy, Clone, PartialEq)]
51 pub enum GateStrength {
52     /// A hard error. (Most feature gates should use this.)
53     Hard,
54     /// Only a warning. (Use this only as backwards-compatibility demands.)
55     Soft,
56 }
57
58 pub fn feature_err<'a>(
59     sess: &'a ParseSess,
60     feature: Symbol,
61     span: impl Into<MultiSpan>,
62     explain: &str,
63 ) -> DiagnosticBuilder<'a> {
64     feature_err_issue(sess, feature, span, GateIssue::Language, explain)
65 }
66
67 pub fn feature_err_issue<'a>(
68     sess: &'a ParseSess,
69     feature: Symbol,
70     span: impl Into<MultiSpan>,
71     issue: GateIssue,
72     explain: &str,
73 ) -> DiagnosticBuilder<'a> {
74     leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard)
75 }
76
77 fn leveled_feature_err<'a>(
78     sess: &'a ParseSess,
79     feature: Symbol,
80     span: impl Into<MultiSpan>,
81     issue: GateIssue,
82     explain: &str,
83     level: GateStrength,
84 ) -> DiagnosticBuilder<'a> {
85     let diag = &sess.span_diagnostic;
86
87     let mut err = match level {
88         GateStrength::Hard => {
89             diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658))
90         }
91         GateStrength::Soft => diag.struct_span_warn(span, explain),
92     };
93
94     if let Some(n) = find_feature_issue(feature, issue) {
95         err.note(&format!(
96             "for more information, see https://github.com/rust-lang/rust/issues/{}",
97             n,
98         ));
99     }
100
101     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
102     if sess.unstable_features.is_nightly_build() {
103         err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
104     }
105
106     // If we're on stable and only emitting a "soft" warning, add a note to
107     // clarify that the feature isn't "on" (rather than being on but
108     // warning-worthy).
109     if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft {
110         err.help("a nightly build of the compiler is required to enable this feature");
111     }
112
113     err
114
115 }
116
117 struct PostExpansionVisitor<'a> {
118     parse_sess: &'a ParseSess,
119     features: &'a Features,
120 }
121
122 macro_rules! gate_feature_post {
123     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
124         let (cx, span) = ($cx, $span);
125         if !span.allows_unstable(sym::$feature) {
126             gate_feature!(cx, $feature, span, $explain)
127         }
128     }};
129     ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
130         let (cx, span) = ($cx, $span);
131         if !span.allows_unstable(sym::$feature) {
132             gate_feature!(cx, $feature, span, $explain, $level)
133         }
134     }}
135 }
136
137 impl<'a> PostExpansionVisitor<'a> {
138     fn check_abi(&self, abi: ast::StrLit) {
139         let ast::StrLit { symbol_unescaped, span, .. } = abi;
140
141         match &*symbol_unescaped.as_str() {
142             // Stable
143             "Rust" |
144             "C" |
145             "cdecl" |
146             "stdcall" |
147             "fastcall" |
148             "aapcs" |
149             "win64" |
150             "sysv64" |
151             "system" => {}
152             "rust-intrinsic" => {
153                 gate_feature_post!(&self, intrinsics, span,
154                                    "intrinsics are subject to change");
155             },
156             "platform-intrinsic" => {
157                 gate_feature_post!(&self, platform_intrinsics, span,
158                                    "platform intrinsics are experimental and possibly buggy");
159             },
160             "vectorcall" => {
161                 gate_feature_post!(&self, abi_vectorcall, span,
162                                    "vectorcall is experimental and subject to change");
163             },
164             "thiscall" => {
165                 gate_feature_post!(&self, abi_thiscall, span,
166                                    "thiscall is experimental and subject to change");
167             },
168             "rust-call" => {
169                 gate_feature_post!(&self, unboxed_closures, span,
170                                    "rust-call ABI is subject to change");
171             },
172             "ptx-kernel" => {
173                 gate_feature_post!(&self, abi_ptx, span,
174                                    "PTX ABIs are experimental and subject to change");
175             },
176             "unadjusted" => {
177                 gate_feature_post!(&self, abi_unadjusted, span,
178                                    "unadjusted ABI is an implementation detail and perma-unstable");
179             },
180             "msp430-interrupt" => {
181                 gate_feature_post!(&self, abi_msp430_interrupt, span,
182                                    "msp430-interrupt ABI is experimental and subject to change");
183             },
184             "x86-interrupt" => {
185                 gate_feature_post!(&self, abi_x86_interrupt, span,
186                                    "x86-interrupt ABI is experimental and subject to change");
187             },
188             "amdgpu-kernel" => {
189                 gate_feature_post!(&self, abi_amdgpu_kernel, span,
190                                    "amdgpu-kernel ABI is experimental and subject to change");
191             },
192             "efiapi" => {
193                 gate_feature_post!(&self, abi_efiapi, span,
194                                    "efiapi ABI is experimental and subject to change");
195             },
196             abi => {
197                 self.parse_sess.span_diagnostic.delay_span_bug(
198                     span,
199                     &format!("unrecognized ABI not caught in lowering: {}", abi),
200                 )
201             }
202         }
203     }
204
205     fn check_extern(&self, ext: ast::Extern) {
206         if let ast::Extern::Explicit(abi) = ext {
207             self.check_abi(abi);
208         }
209     }
210
211     fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
212         let has_fields = variants.iter().any(|variant| match variant.data {
213             VariantData::Tuple(..) | VariantData::Struct(..) => true,
214             VariantData::Unit(..) => false,
215         });
216
217         let discriminant_spans = variants.iter().filter(|variant| match variant.data {
218             VariantData::Tuple(..) | VariantData::Struct(..) => false,
219             VariantData::Unit(..) => true,
220         })
221         .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
222         .collect::<Vec<_>>();
223
224         if !discriminant_spans.is_empty() && has_fields {
225             let mut err = feature_err(
226                 self.parse_sess,
227                 sym::arbitrary_enum_discriminant,
228                 discriminant_spans.clone(),
229                 "custom discriminant values are not allowed in enums with tuple or struct variants",
230             );
231             for sp in discriminant_spans {
232                 err.span_label(sp, "disallowed custom discriminant");
233             }
234             for variant in variants.iter() {
235                 match &variant.data {
236                     VariantData::Struct(..) => {
237                         err.span_label(
238                             variant.span,
239                             "struct variant defined here",
240                         );
241                     }
242                     VariantData::Tuple(..) => {
243                         err.span_label(
244                             variant.span,
245                             "tuple variant defined here",
246                         );
247                     }
248                     VariantData::Unit(..) => {}
249                 }
250             }
251             err.emit();
252         }
253     }
254
255     fn check_gat(&self, generics: &ast::Generics, span: Span) {
256         if !generics.params.is_empty() {
257             gate_feature_post!(
258                 &self,
259                 generic_associated_types,
260                 span,
261                 "generic associated types are unstable"
262             );
263         }
264         if !generics.where_clause.predicates.is_empty() {
265             gate_feature_post!(
266                 &self,
267                 generic_associated_types,
268                 span,
269                 "where clauses on associated types are unstable"
270             );
271         }
272     }
273
274     /// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
275     fn check_impl_trait(&self, ty: &ast::Ty) {
276         struct ImplTraitVisitor<'a> {
277             vis: &'a PostExpansionVisitor<'a>,
278         }
279         impl Visitor<'_> for ImplTraitVisitor<'_> {
280             fn visit_ty(&mut self, ty: &ast::Ty) {
281                 if let ast::TyKind::ImplTrait(..) = ty.kind {
282                     gate_feature_post!(
283                         &self.vis,
284                         type_alias_impl_trait,
285                         ty.span,
286                         "`impl Trait` in type aliases is unstable"
287                     );
288                 }
289                 visit::walk_ty(self, ty);
290             }
291         }
292         ImplTraitVisitor { vis: self }.visit_ty(ty);
293     }
294 }
295
296 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
297     fn visit_attribute(&mut self, attr: &ast::Attribute) {
298         let attr_info =
299             attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
300         // Check feature gates for built-in attributes.
301         if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
302             gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard);
303         }
304         // Check unstable flavors of the `#[doc]` attribute.
305         if attr.check_name(sym::doc) {
306             for nested_meta in attr.meta_item_list().unwrap_or_default() {
307                 macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
308                     $(if nested_meta.check_name(sym::$name) {
309                         let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental");
310                         gate_feature!(self, $feature, attr.span, msg);
311                     })*
312                 }}
313
314                 gate_doc!(
315                     include => external_doc
316                     cfg => doc_cfg
317                     masked => doc_masked
318                     spotlight => doc_spotlight
319                     alias => doc_alias
320                     keyword => doc_keyword
321                 );
322             }
323         }
324     }
325
326     fn visit_name(&mut self, sp: Span, name: ast::Name) {
327         if !name.as_str().is_ascii() {
328             gate_feature_post!(
329                 &self,
330                 non_ascii_idents,
331                 self.parse_sess.source_map().def_span(sp),
332                 "non-ascii idents are not fully supported"
333             );
334         }
335     }
336
337     fn visit_item(&mut self, i: &'a ast::Item) {
338         match i.kind {
339             ast::ItemKind::ForeignMod(ref foreign_module) => {
340                 if let Some(abi) = foreign_module.abi {
341                     self.check_abi(abi);
342                 }
343             }
344
345             ast::ItemKind::Fn(..) => {
346                 if attr::contains_name(&i.attrs[..], sym::plugin_registrar) {
347                     gate_feature_post!(&self, plugin_registrar, i.span,
348                                        "compiler plugins are experimental and possibly buggy");
349                 }
350                 if attr::contains_name(&i.attrs[..], sym::start) {
351                     gate_feature_post!(&self, start, i.span,
352                                       "a `#[start]` function is an experimental \
353                                        feature whose signature may change \
354                                        over time");
355                 }
356                 if attr::contains_name(&i.attrs[..], sym::main) {
357                     gate_feature_post!(&self, main, i.span,
358                                        "declaration of a non-standard `#[main]` \
359                                         function may change over time, for now \
360                                         a top-level `fn main()` is required");
361                 }
362             }
363
364             ast::ItemKind::Struct(..) => {
365                 for attr in attr::filter_by_name(&i.attrs[..], sym::repr) {
366                     for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
367                         if item.check_name(sym::simd) {
368                             gate_feature_post!(&self, repr_simd, attr.span,
369                                                "SIMD types are experimental and possibly buggy");
370                         }
371                     }
372                 }
373             }
374
375             ast::ItemKind::Enum(ast::EnumDef{ref variants, ..}, ..) => {
376                 for variant in variants {
377                     match (&variant.data, &variant.disr_expr) {
378                         (ast::VariantData::Unit(..), _) => {},
379                         (_, Some(disr_expr)) =>
380                             gate_feature_post!(
381                                 &self,
382                                 arbitrary_enum_discriminant,
383                                 disr_expr.value.span,
384                                 "discriminants on non-unit variants are experimental"),
385                         _ => {},
386                     }
387                 }
388
389                 let has_feature = self.features.arbitrary_enum_discriminant;
390                 if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
391                     self.maybe_report_invalid_custom_discriminants(&variants);
392                 }
393             }
394
395             ast::ItemKind::Impl(_, polarity, defaultness, ..) => {
396                 if polarity == ast::ImplPolarity::Negative {
397                     gate_feature_post!(&self, optin_builtin_traits,
398                                        i.span,
399                                        "negative trait bounds are not yet fully implemented; \
400                                         use marker types for now");
401                 }
402
403                 if let ast::Defaultness::Default = defaultness {
404                     gate_feature_post!(&self, specialization,
405                                        i.span,
406                                        "specialization is unstable");
407                 }
408             }
409
410             ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => {
411                 gate_feature_post!(&self, optin_builtin_traits,
412                                    i.span,
413                                    "auto traits are experimental and possibly buggy");
414             }
415
416             ast::ItemKind::TraitAlias(..) => {
417                 gate_feature_post!(
418                     &self,
419                     trait_alias,
420                     i.span,
421                     "trait aliases are experimental"
422                 );
423             }
424
425             ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
426                 let msg = "`macro` is experimental";
427                 gate_feature_post!(&self, decl_macro, i.span, msg);
428             }
429
430             ast::ItemKind::TyAlias(ref ty, ..) => self.check_impl_trait(&ty),
431
432             _ => {}
433         }
434
435         visit::walk_item(self, i);
436     }
437
438     fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
439         match i.kind {
440             ast::ForeignItemKind::Fn(..) |
441             ast::ForeignItemKind::Static(..) => {
442                 let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name);
443                 let links_to_llvm = match link_name {
444                     Some(val) => val.as_str().starts_with("llvm."),
445                     _ => false
446                 };
447                 if links_to_llvm {
448                     gate_feature_post!(&self, link_llvm_intrinsics, i.span,
449                                        "linking to LLVM intrinsics is experimental");
450                 }
451             }
452             ast::ForeignItemKind::Ty => {
453                     gate_feature_post!(&self, extern_types, i.span,
454                                        "extern types are experimental");
455             }
456             ast::ForeignItemKind::Macro(..) => {}
457         }
458
459         visit::walk_foreign_item(self, i)
460     }
461
462     fn visit_ty(&mut self, ty: &'a ast::Ty) {
463         match ty.kind {
464             ast::TyKind::BareFn(ref bare_fn_ty) => {
465                 self.check_extern(bare_fn_ty.ext);
466             }
467             _ => {}
468         }
469         visit::walk_ty(self, ty)
470     }
471
472     fn visit_expr(&mut self, e: &'a ast::Expr) {
473         match e.kind {
474             ast::ExprKind::Box(_) => {
475                 gate_feature_post!(
476                     &self, box_syntax, e.span,
477                     "box expression syntax is experimental; you can call `Box::new` instead"
478                 );
479             }
480             ast::ExprKind::Type(..) => {
481                 // To avoid noise about type ascription in common syntax errors, only emit if it
482                 // is the *only* error.
483                 if self.parse_sess.span_diagnostic.err_count() == 0 {
484                     gate_feature_post!(&self, type_ascription, e.span,
485                                        "type ascription is experimental");
486                 }
487             }
488             ast::ExprKind::TryBlock(_) => {
489                 gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
490             }
491             ast::ExprKind::Block(_, opt_label) => {
492                 if let Some(label) = opt_label {
493                     gate_feature_post!(&self, label_break_value, label.ident.span,
494                                     "labels on blocks are unstable");
495                 }
496             }
497             _ => {}
498         }
499         visit::walk_expr(self, e)
500     }
501
502     fn visit_pat(&mut self, pattern: &'a ast::Pat) {
503         match &pattern.kind {
504             PatKind::Slice(pats) => {
505                 for pat in &*pats {
506                     let span = pat.span;
507                     let inner_pat = match &pat.kind {
508                         PatKind::Ident(.., Some(pat)) => pat,
509                         _ => pat,
510                     };
511                     if inner_pat.is_rest() {
512                         gate_feature_post!(
513                             &self,
514                             slice_patterns,
515                             span,
516                             "subslice patterns are unstable"
517                         );
518                     }
519                 }
520             }
521             PatKind::Box(..) => {
522                 gate_feature_post!(&self, box_patterns,
523                                   pattern.span,
524                                   "box pattern syntax is experimental");
525             }
526             PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => {
527                 gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
528                                    "exclusive range pattern syntax is experimental");
529             }
530             _ => {}
531         }
532         visit::walk_pat(self, pattern)
533     }
534
535     fn visit_fn(&mut self,
536                 fn_kind: FnKind<'a>,
537                 fn_decl: &'a ast::FnDecl,
538                 span: Span,
539                 _node_id: NodeId) {
540         if let Some(header) = fn_kind.header() {
541             // Stability of const fn methods are covered in
542             // `visit_trait_item` and `visit_impl_item` below; this is
543             // because default methods don't pass through this point.
544             self.check_extern(header.ext);
545         }
546
547         if fn_decl.c_variadic() {
548             gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
549         }
550
551         visit::walk_fn(self, fn_kind, fn_decl, span)
552     }
553
554     fn visit_generic_param(&mut self, param: &'a GenericParam) {
555         match param.kind {
556             GenericParamKind::Const { .. } =>
557                 gate_feature_post!(&self, const_generics, param.ident.span,
558                     "const generics are unstable"),
559             _ => {}
560         }
561         visit::walk_generic_param(self, param)
562     }
563
564     fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
565         match constraint.kind {
566             AssocTyConstraintKind::Bound { .. } =>
567                 gate_feature_post!(&self, associated_type_bounds, constraint.span,
568                     "associated type bounds are unstable"),
569             _ => {}
570         }
571         visit::walk_assoc_ty_constraint(self, constraint)
572     }
573
574     fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
575         match ti.kind {
576             ast::TraitItemKind::Method(ref sig, ref block) => {
577                 if block.is_none() {
578                     self.check_extern(sig.header.ext);
579                 }
580                 if sig.decl.c_variadic() {
581                     gate_feature_post!(&self, c_variadic, ti.span,
582                                        "C-variadic functions are unstable");
583                 }
584                 if sig.header.constness.node == ast::Constness::Const {
585                     gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
586                 }
587             }
588             ast::TraitItemKind::Type(_, ref default) => {
589                 if let Some(ty) = default {
590                     self.check_impl_trait(ty);
591                     gate_feature_post!(&self, associated_type_defaults, ti.span,
592                                        "associated type defaults are unstable");
593                 }
594                 self.check_gat(&ti.generics, ti.span);
595             }
596             _ => {}
597         }
598         visit::walk_trait_item(self, ti)
599     }
600
601     fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
602         if ii.defaultness == ast::Defaultness::Default {
603             gate_feature_post!(&self, specialization,
604                               ii.span,
605                               "specialization is unstable");
606         }
607
608         match ii.kind {
609             ast::ImplItemKind::Method(ref sig, _) => {
610                 if sig.decl.c_variadic() {
611                     gate_feature_post!(&self, c_variadic, ii.span,
612                                        "C-variadic functions are unstable");
613                 }
614             }
615             ast::ImplItemKind::TyAlias(ref ty) => {
616                 self.check_impl_trait(ty);
617                 self.check_gat(&ii.generics, ii.span);
618             }
619             _ => {}
620         }
621         visit::walk_impl_item(self, ii)
622     }
623
624     fn visit_vis(&mut self, vis: &'a ast::Visibility) {
625         if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node {
626             gate_feature_post!(&self, crate_visibility_modifier, vis.span,
627                                "`crate` visibility modifier is experimental");
628         }
629         visit::walk_vis(self, vis)
630     }
631 }
632
633 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
634                     crate_edition: Edition, allow_features: &Option<Vec<String>>) -> Features {
635     fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
636         let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
637         err.span_label(span, "feature has been removed");
638         if let Some(reason) = reason {
639             err.note(reason);
640         }
641         err.emit();
642     }
643
644     let mut features = Features::default();
645     let mut edition_enabled_features = FxHashMap::default();
646
647     for &edition in ALL_EDITIONS {
648         if edition <= crate_edition {
649             // The `crate_edition` implies its respective umbrella feature-gate
650             // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
651             edition_enabled_features.insert(edition.feature_name(), edition);
652         }
653     }
654
655     for feature in active_features_up_to(crate_edition) {
656         feature.set(&mut features, DUMMY_SP);
657         edition_enabled_features.insert(feature.name, crate_edition);
658     }
659
660     // Process the edition umbrella feature-gates first, to ensure
661     // `edition_enabled_features` is completed before it's queried.
662     for attr in krate_attrs {
663         if !attr.check_name(sym::feature) {
664             continue
665         }
666
667         let list = match attr.meta_item_list() {
668             Some(list) => list,
669             None => continue,
670         };
671
672         for mi in list {
673             if !mi.is_word() {
674                 continue;
675             }
676
677             let name = mi.name_or_empty();
678
679             let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied();
680             if let Some(edition) = edition {
681                 if edition <= crate_edition {
682                     continue;
683                 }
684
685                 for feature in active_features_up_to(edition) {
686                     // FIXME(Manishearth) there is currently no way to set
687                     // lib features by edition
688                     feature.set(&mut features, DUMMY_SP);
689                     edition_enabled_features.insert(feature.name, edition);
690                 }
691             }
692         }
693     }
694
695     for attr in krate_attrs {
696         if !attr.check_name(sym::feature) {
697             continue
698         }
699
700         let list = match attr.meta_item_list() {
701             Some(list) => list,
702             None => continue,
703         };
704
705         let bad_input = |span| {
706             struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input")
707         };
708
709         for mi in list {
710             let name = match mi.ident() {
711                 Some(ident) if mi.is_word() => ident.name,
712                 Some(ident) => {
713                     bad_input(mi.span()).span_suggestion(
714                         mi.span(),
715                         "expected just one word",
716                         format!("{}", ident.name),
717                         Applicability::MaybeIncorrect,
718                     ).emit();
719                     continue
720                 }
721                 None => {
722                     bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit();
723                     continue
724                 }
725             };
726
727             if let Some(edition) = edition_enabled_features.get(&name) {
728                 struct_span_warn!(
729                     span_handler,
730                     mi.span(),
731                     E0705,
732                     "the feature `{}` is included in the Rust {} edition",
733                     name,
734                     edition,
735                 ).emit();
736                 continue;
737             }
738
739             if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) {
740                 // Handled in the separate loop above.
741                 continue;
742             }
743
744             let removed = REMOVED_FEATURES.iter().find(|f| name == f.name);
745             let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name);
746             if let Some(Feature { state, .. }) = removed.or(stable_removed) {
747                 if let FeatureState::Removed { reason }
748                 | FeatureState::Stabilized { reason } = state
749                 {
750                     feature_removed(span_handler, mi.span(), *reason);
751                     continue;
752                 }
753             }
754
755             if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
756                 let since = Some(Symbol::intern(since));
757                 features.declared_lang_features.push((name, mi.span(), since));
758                 continue;
759             }
760
761             if let Some(allowed) = allow_features.as_ref() {
762                 if allowed.iter().find(|&f| name.as_str() == *f).is_none() {
763                     span_err!(span_handler, mi.span(), E0725,
764                               "the feature `{}` is not in the list of allowed features",
765                               name);
766                     continue;
767                 }
768             }
769
770             if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) {
771                 f.set(&mut features, mi.span());
772                 features.declared_lang_features.push((name, mi.span(), None));
773                 continue;
774             }
775
776             features.declared_lib_features.push((name, mi.span()));
777         }
778     }
779
780     features
781 }
782
783 fn active_features_up_to(edition: Edition) -> impl Iterator<Item=&'static Feature> {
784     ACTIVE_FEATURES.iter()
785     .filter(move |feature| {
786         if let Some(feature_edition) = feature.edition {
787             feature_edition <= edition
788         } else {
789             false
790         }
791     })
792 }
793
794 pub fn check_crate(krate: &ast::Crate,
795                    parse_sess: &ParseSess,
796                    features: &Features,
797                    unstable: UnstableFeatures) {
798     maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable);
799     let mut visitor = PostExpansionVisitor { parse_sess, features };
800
801     let spans = parse_sess.gated_spans.spans.borrow();
802     macro_rules! gate_all {
803         ($gate:ident, $msg:literal) => {
804             for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
805                 gate_feature!(&visitor, $gate, *span, $msg);
806             }
807         }
808     }
809     gate_all!(let_chains, "`let` expressions in this position are experimental");
810     gate_all!(async_closure, "async closures are unstable");
811     gate_all!(generators, "yield syntax is experimental");
812     gate_all!(or_patterns, "or-patterns syntax is experimental");
813     gate_all!(const_extern_fn, "`const extern fn` definitions are unstable");
814     gate_all!(raw_ref_op, "raw address of syntax is experimental");
815
816     // All uses of `gate_all!` below this point were added in #65742,
817     // and subsequently disabled (with the non-early gating readded).
818     macro_rules! gate_all {
819         ($gate:ident, $msg:literal) => {
820             // FIXME(eddyb) do something more useful than always
821             // disabling these uses of early feature-gatings.
822             if false {
823                 for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
824                     gate_feature!(&visitor, $gate, *span, $msg);
825                 }
826             }
827         }
828     }
829
830     gate_all!(trait_alias, "trait aliases are experimental");
831     gate_all!(associated_type_bounds, "associated type bounds are unstable");
832     gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental");
833     gate_all!(const_generics, "const generics are unstable");
834     gate_all!(decl_macro, "`macro` is experimental");
835     gate_all!(box_patterns, "box pattern syntax is experimental");
836     gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
837     gate_all!(try_blocks, "`try` blocks are unstable");
838     gate_all!(label_break_value, "labels on blocks are unstable");
839     gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
840     // To avoid noise about type ascription in common syntax errors,
841     // only emit if it is the *only* error. (Also check it last.)
842     if parse_sess.span_diagnostic.err_count() == 0 {
843         gate_all!(type_ascription, "type ascription is experimental");
844     }
845
846     visit::walk_crate(&mut visitor, krate);
847 }
848
849 fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) {
850     if !unstable.is_nightly_build() {
851         for attr in krate.attrs.iter().filter(|attr| attr.check_name(sym::feature)) {
852             span_err!(
853                 span_handler, attr.span, E0554,
854                 "`#![feature]` may not be used on the {} release channel",
855                 option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)")
856             );
857         }
858     }
859 }