]> git.lizzy.rs Git - rust.git/blobdiff - src/libsyntax/feature_gate.rs
Turn `#[allocator]` into a built-in attribute and rename it to `#[rustc_allocator]`
[rust.git] / src / libsyntax / feature_gate.rs
index 6a049b80acae225c851ab9af390fc92593ce82e3..ac4a7271221bb982752fe9824b2503ede447bd45 100644 (file)
 use AttributeType::*;
 use AttributeGate::*;
 
-use crate::ast::{self, NodeId, GenericParam, GenericParamKind, PatKind, RangeEnd};
+use crate::ast::{
+    self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
+    PatKind, RangeEnd,
+};
 use crate::attr;
 use crate::early_buffered_lints::BufferedEarlyLintId;
 use crate::source_map::Spanned;
@@ -25,7 +28,7 @@
 use crate::symbol::{Symbol, kw, sym};
 use crate::tokenstream::TokenTree;
 
-use errors::{DiagnosticBuilder, Handler};
+use errors::{Applicability, DiagnosticBuilder, Handler};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_target::spec::abi::Abi;
 use syntax_pos::{Span, DUMMY_SP};
@@ -554,6 +557,13 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
     // Allows using C-variadics.
     (active, c_variadic, "1.34.0", Some(44930), None),
 
+    // Allows the user of associated type bounds.
+    (active, associated_type_bounds, "1.34.0", Some(52662), None),
+
+    // Allows calling constructor functions in `const fn`
+    // FIXME Create issue
+    (active, const_constructor, "1.37.0", Some(61456), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -1321,6 +1331,11 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
                                                 "internal implementation detail",
                                                 cfg_fn!(rustc_attrs))),
 
+    (sym::rustc_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                                sym::rustc_attrs,
+                                                "internal implementation detail",
+                                                cfg_fn!(rustc_attrs))),
+
     // FIXME: #14408 whitelist docs since rustdoc looks at them
     (
         sym::doc,
@@ -1422,7 +1437,7 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
         Normal,
         template!(
             Word,
-            List: r#"/*opt*/ since = "version", /*opt*/ note = "reason"#,
+            List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
             NameValueStr: "reason"
         ),
         Ungated
@@ -1858,24 +1873,32 @@ fn check_builtin_attribute(&mut self, attr: &ast::Attribute, name: Symbol,
 
         match attr.parse_meta(self.context.parse_sess) {
             Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) {
+                let error_msg = format!("malformed `{}` attribute input", name);
                 let mut msg = "attribute must be of the form ".to_owned();
+                let mut suggestions = vec![];
                 let mut first = true;
                 if template.word {
                     first = false;
-                    msg.push_str(&format!("`#[{}{}]`", name, ""));
+                    let code = format!("#[{}]", name);
+                    msg.push_str(&format!("`{}`", &code));
+                    suggestions.push(code);
                 }
                 if let Some(descr) = template.list {
                     if !first {
                         msg.push_str(" or ");
                     }
                     first = false;
-                    msg.push_str(&format!("`#[{}({})]`", name, descr));
+                    let code = format!("#[{}({})]", name, descr);
+                    msg.push_str(&format!("`{}`", &code));
+                    suggestions.push(code);
                 }
                 if let Some(descr) = template.name_value_str {
                     if !first {
                         msg.push_str(" or ");
                     }
-                    msg.push_str(&format!("`#[{} = \"{}\"]`", name, descr));
+                    let code = format!("#[{} = \"{}\"]", name, descr);
+                    msg.push_str(&format!("`{}`", &code));
+                    suggestions.push(code);
                 }
                 if should_warn(name) {
                     self.context.parse_sess.buffer_lint(
@@ -1885,7 +1908,17 @@ fn check_builtin_attribute(&mut self, attr: &ast::Attribute, name: Symbol,
                         &msg,
                     );
                 } else {
-                    self.context.parse_sess.span_diagnostic.span_err(meta.span, &msg);
+                    self.context.parse_sess.span_diagnostic.struct_span_err(meta.span, &error_msg)
+                        .span_suggestions(
+                            meta.span,
+                            if suggestions.len() == 1 {
+                                "must be of the form"
+                            } else {
+                                "the following are the possible correct uses"
+                            },
+                            suggestions.into_iter(),
+                            Applicability::HasPlaceholders,
+                        ).emit();
                 }
             }
             Err(mut err) => err.emit(),
@@ -1899,7 +1932,7 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
             self.builtin_attributes.get(&ident.name).map(|a| *a)
         });
 
-        // check for gated attributes
+        // Check for gated attributes.
         self.context.check_attribute(attr, attr_info, false);
 
         if attr.check_name(sym::doc) {
@@ -1934,9 +1967,11 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
                 name,
                 template
             ),
-            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();
+            None => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() {
+                if token == token::Eq {
+                    // All key-value attributes are restricted to meta-item syntax.
+                    attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok();
+                }
             }
         }
     }
@@ -2097,7 +2132,7 @@ fn visit_ty(&mut self, ty: &'a ast::Ty) {
     fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
         if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
             if let ast::TyKind::Never = output_ty.node {
-                // Do nothing
+                // Do nothing.
             } else {
                 self.visit_ty(output_ty)
             }
@@ -2153,7 +2188,7 @@ fn visit_expr(&mut self, e: &'a ast::Expr) {
             }
             _ => {}
         }
-        visit::walk_expr(self, e);
+        visit::walk_expr(self, e)
     }
 
     fn visit_arm(&mut self, arm: &'a ast::Arm) {
@@ -2202,15 +2237,27 @@ fn visit_fn(&mut self,
             gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
         }
 
-        visit::walk_fn(self, fn_kind, fn_decl, span);
+        visit::walk_fn(self, fn_kind, fn_decl, span)
     }
 
     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");
+        match param.kind {
+            GenericParamKind::Const { .. } =>
+                gate_feature_post!(&self, const_generics, param.ident.span,
+                    "const generics are unstable"),
+            _ => {}
         }
-        visit::walk_generic_param(self, param);
+        visit::walk_generic_param(self, param)
+    }
+
+    fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
+        match constraint.kind {
+            AssocTyConstraintKind::Bound { .. } =>
+                gate_feature_post!(&self, associated_type_bounds, constraint.span,
+                    "associated type bounds are unstable"),
+            _ => {}
+        }
+        visit::walk_assoc_ty_constraint(self, constraint)
     }
 
     fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
@@ -2248,7 +2295,7 @@ fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
             }
             _ => {}
         }
-        visit::walk_trait_item(self, ti);
+        visit::walk_trait_item(self, ti)
     }
 
     fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
@@ -2280,7 +2327,7 @@ fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
             }
             _ => {}
         }
-        visit::walk_impl_item(self, ii);
+        visit::walk_impl_item(self, ii)
     }
 
     fn visit_vis(&mut self, vis: &'a ast::Visibility) {
@@ -2288,7 +2335,7 @@ fn visit_vis(&mut self, vis: &'a ast::Visibility) {
             gate_feature_post!(&self, crate_visibility_modifier, vis.span,
                                "`crate` visibility modifier is experimental");
         }
-        visit::walk_vis(self, vis);
+        visit::walk_vis(self, vis)
     }
 }
 
@@ -2298,6 +2345,8 @@ 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);
+        } else {
+            err.span_label(span, "feature has been removed");
         }
         err.emit();
     }
@@ -2379,12 +2428,24 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
             None => continue,
         };
 
+        let bad_input = |span| {
+            struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input")
+        };
+
         for mi in list {
             let name = match mi.ident() {
                 Some(ident) if mi.is_word() => ident.name,
-                _ => {
-                    span_err!(span_handler, mi.span(), E0556,
-                            "malformed feature, expected just one word");
+                Some(ident) => {
+                    bad_input(mi.span()).span_suggestion(
+                        mi.span(),
+                        "expected just one word",
+                        format!("{}", ident.name),
+                        Applicability::MaybeIncorrect,
+                    ).emit();
+                    continue
+                }
+                None => {
+                    bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit();
                     continue
                 }
             };