]> git.lizzy.rs Git - rust.git/blobdiff - src/libsyntax/feature_gate/check.rs
ast: Keep `extern` qualifiers in functions more precisely
[rust.git] / src / libsyntax / feature_gate / check.rs
index ecff89ad59bd94dbe22d08752ad2b4868ba93528..d90fa9addf7f6f28154484c28e913a7ce606eda0 100644 (file)
@@ -3,25 +3,25 @@
 use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
 use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
 
-use crate::ast::{
-    self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
-    PatKind, RangeEnd, VariantData,
-};
-use crate::attr::{self, check_builtin_attribute};
+use crate::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
+use crate::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
+use crate::attr;
 use crate::source_map::Spanned;
 use crate::edition::{ALL_EDITIONS, Edition};
 use crate::visit::{self, FnKind, Visitor};
-use crate::token;
 use crate::sess::ParseSess;
 use crate::symbol::{Symbol, sym};
-use crate::tokenstream::TokenTree;
 
 use errors::{Applicability, DiagnosticBuilder, Handler};
 use rustc_data_structures::fx::FxHashMap;
 use syntax_pos::{Span, DUMMY_SP, MultiSpan};
 use log::debug;
 
+use rustc_error_codes::*;
+
+
 use std::env;
+use std::num::NonZeroU32;
 
 #[derive(Copy, Clone, Debug)]
 pub enum Stability {
@@ -59,25 +59,28 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features:
     PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
 }
 
-fn find_lang_feature_issue(feature: Symbol) -> Option<u32> {
+fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
     if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
         // FIXME (#28244): enforce that active features have issue numbers
-        // assert!(info.issue.is_some())
-        info.issue
+        // assert!(info.issue().is_some())
+        info.issue()
     } else {
         // search in Accepted, Removed, or Stable Removed features
-        let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES)
+        let found = ACCEPTED_FEATURES
+            .iter()
+            .chain(REMOVED_FEATURES)
+            .chain(STABLE_REMOVED_FEATURES)
             .find(|t| t.name == feature);
         match found {
-            Some(&Feature { issue, .. }) => issue,
-            None => panic!("Feature `{}` is not declared anywhere", feature),
+            Some(found) => found.issue(),
+            None => panic!("feature `{}` is not declared anywhere", feature),
         }
     }
 }
 
 pub enum GateIssue {
     Language,
-    Library(Option<u32>)
+    Library(Option<NonZeroU32>)
 }
 
 #[derive(Debug, Copy, Clone, PartialEq)]
@@ -130,14 +133,11 @@ fn leveled_feature_err<'a, S: Into<MultiSpan>>(
         GateStrength::Soft => diag.struct_span_warn(span, explain),
     };
 
-    match issue {
-        None | Some(0) => {}  // We still accept `0` as a stand-in for backwards compatibility
-        Some(n) => {
-            err.note(&format!(
-                "for more information, see https://github.com/rust-lang/rust/issues/{}",
-                n,
-            ));
-        }
+    if let Some(n) = issue {
+        err.note(&format!(
+            "for more information, see https://github.com/rust-lang/rust/issues/{}",
+            n,
+        ));
     }
 
     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
@@ -258,6 +258,12 @@ fn check_abi(&self, abi: ast::Abi) {
         }
     }
 
+    fn check_extern(&self, ext: ast::Extern) {
+        if let ast::Extern::Explicit(abi) = ext {
+            self.check_abi(abi);
+        }
+    }
+
     fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
         let has_fields = variants.iter().any(|variant| match variant.data {
             VariantData::Tuple(..) | VariantData::Struct(..) => true,
@@ -321,6 +327,27 @@ fn check_gat(&self, generics: &ast::Generics, span: Span) {
             );
         }
     }
+
+    /// Feature gate `impl Trait` inside `type Alias = $type_expr;`.
+    fn check_impl_trait(&self, ty: &ast::Ty) {
+        struct ImplTraitVisitor<'a> {
+            vis: &'a PostExpansionVisitor<'a>,
+        }
+        impl Visitor<'_> for ImplTraitVisitor<'_> {
+            fn visit_ty(&mut self, ty: &ast::Ty) {
+                if let ast::TyKind::ImplTrait(..) = ty.kind {
+                    gate_feature_post!(
+                        &self.vis,
+                        type_alias_impl_trait,
+                        ty.span,
+                        "`impl Trait` in type aliases is unstable"
+                    );
+                }
+                visit::walk_ty(self, ty);
+            }
+        }
+        ImplTraitVisitor { vis: self }.visit_ty(ty);
+    }
 }
 
 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
@@ -331,19 +358,6 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
         if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
             gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard);
         }
-        // Check input tokens for built-in and key-value attributes.
-        match attr_info {
-            // `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
-            Some((name, _, template, _)) if name != sym::rustc_dummy =>
-                check_builtin_attribute(self.parse_sess, attr, name, template),
-            _ => if let Some(TokenTree::Token(token)) =
-                    attr.get_normal_item().tokens.trees().next() {
-                if token == token::Eq {
-                    // All key-value attributes are restricted to meta-item syntax.
-                    attr.parse_meta(self.parse_sess).map_err(|mut err| err.emit()).ok();
-                }
-            }
-        }
         // Check unstable flavors of the `#[doc]` attribute.
         if attr.check_name(sym::doc) {
             for nested_meta in attr.meta_item_list().unwrap_or_default() {
@@ -380,7 +394,9 @@ fn visit_name(&mut self, sp: Span, name: ast::Name) {
     fn visit_item(&mut self, i: &'a ast::Item) {
         match i.kind {
             ast::ItemKind::ForeignMod(ref foreign_module) => {
-                self.check_abi(foreign_module.abi);
+                if let Some(abi) = foreign_module.abi {
+                    self.check_abi(abi);
+                }
             }
 
             ast::ItemKind::Fn(..) => {
@@ -468,14 +484,7 @@ fn visit_item(&mut self, i: &'a ast::Item) {
                 gate_feature_post!(&self, decl_macro, i.span, msg);
             }
 
-            ast::ItemKind::OpaqueTy(..) => {
-                gate_feature_post!(
-                    &self,
-                    type_alias_impl_trait,
-                    i.span,
-                    "`impl Trait` in type aliases is unstable"
-                );
-            }
+            ast::ItemKind::TyAlias(ref ty, ..) => self.check_impl_trait(&ty),
 
             _ => {}
         }
@@ -510,7 +519,7 @@ fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
     fn visit_ty(&mut self, ty: &'a ast::Ty) {
         match ty.kind {
             ast::TyKind::BareFn(ref bare_fn_ty) => {
-                self.check_abi(bare_fn_ty.abi);
+                self.check_extern(bare_fn_ty.ext);
             }
             ast::TyKind::Never => {
                 gate_feature_post!(&self, never_type, ty.span,
@@ -604,7 +613,7 @@ fn visit_fn(&mut self,
             // 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.
-            self.check_abi(header.abi);
+            self.check_extern(header.ext);
         }
 
         if fn_decl.c_variadic() {
@@ -638,7 +647,7 @@ fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
         match ti.kind {
             ast::TraitItemKind::Method(ref sig, ref block) => {
                 if block.is_none() {
-                    self.check_abi(sig.header.abi);
+                    self.check_extern(sig.header.ext);
                 }
                 if sig.decl.c_variadic() {
                     gate_feature_post!(&self, c_variadic, ti.span,
@@ -649,9 +658,8 @@ fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
                 }
             }
             ast::TraitItemKind::Type(_, ref default) => {
-                // We use three if statements instead of something like match guards so that all
-                // of these errors can be emitted if all cases apply.
-                if default.is_some() {
+                if let Some(ty) = default {
+                    self.check_impl_trait(ty);
                     gate_feature_post!(&self, associated_type_defaults, ti.span,
                                        "associated type defaults are unstable");
                 }
@@ -676,15 +684,8 @@ fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
                                        "C-variadic functions are unstable");
                 }
             }
-            ast::ImplItemKind::OpaqueTy(..) => {
-                gate_feature_post!(
-                    &self,
-                    type_alias_impl_trait,
-                    ii.span,
-                    "`impl Trait` in type aliases is unstable"
-                );
-            }
-            ast::ImplItemKind::TyAlias(_) => {
+            ast::ImplItemKind::TyAlias(ref ty) => {
+                self.check_impl_trait(ty);
                 self.check_gat(&ii.generics, ii.span);
             }
             _ => {}