]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_ast_passes/ast_validation.rs
Auto merge of #69393 - Dylan-DPC:rollup-rxbd1zg, r=Dylan-DPC
[rust.git] / src / librustc_ast_passes / ast_validation.rs
index 206cdefecc9901ff5c364771fc7a876b7c3023e8..a9844a7059e552f1fa9c2d7f629013cfc744d85f 100644 (file)
@@ -22,6 +22,9 @@
 use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use syntax::walk_list;
 
+const MORE_EXTERN: &str =
+    "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
+
 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
 enum SelfSemantic {
     Yes,
@@ -423,14 +426,62 @@ fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sug
         }
     }
 
-    fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
+    fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
         let span = match bounds {
             [] => return,
             [b0] => b0.span(),
             [b0, .., bl] => b0.span().to(bl.span()),
         };
         self.err_handler()
-            .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
+            .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
+            .emit();
+    }
+
+    fn check_foreign_ty_genericless(&self, generics: &Generics) {
+        let cannot_have = |span, descr, remove_descr| {
+            self.err_handler()
+                .struct_span_err(
+                    span,
+                    &format!("`type`s inside `extern` blocks cannot have {}", descr),
+                )
+                .span_suggestion(
+                    span,
+                    &format!("remove the {}", remove_descr),
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                )
+                .span_label(self.current_extern_span(), "`extern` block begins here")
+                .note(MORE_EXTERN)
+                .emit();
+        };
+
+        if !generics.params.is_empty() {
+            cannot_have(generics.span, "generic parameters", "generic parameters");
+        }
+
+        if !generics.where_clause.predicates.is_empty() {
+            cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
+        }
+    }
+
+    fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
+        let body = match body {
+            None => return,
+            Some(body) => body,
+        };
+        self.err_handler()
+            .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
+            .span_label(ident.span, "cannot have a body")
+            .span_label(body, "the invalid body")
+            .span_label(
+                self.current_extern_span(),
+                format!(
+                    "`extern` blocks define existing foreign {0}s and {0}s \
+                    inside of them cannot have a body",
+                    kind
+                ),
+            )
+            .note(MORE_EXTERN)
             .emit();
     }
 
@@ -458,7 +509,7 @@ fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
                 "`extern` blocks define existing foreign functions and functions \
                 inside of them cannot have a body",
             )
-            .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
+            .note(MORE_EXTERN)
             .emit();
     }
 
@@ -531,6 +582,16 @@ fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Gener
             }
         }
     }
+
+    fn check_item_named(&self, ident: Ident, kind: &str) {
+        if ident.name != kw::Underscore {
+            return;
+        }
+        self.err_handler()
+            .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
+            .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
+            .emit();
+    }
 }
 
 enum GenericPosition {
@@ -900,6 +961,21 @@ fn visit_item(&mut self, item: &'a Item) {
                     self.err_handler().span_err(item.span, "unions cannot have zero fields");
                 }
             }
+            ItemKind::Const(.., None) => {
+                let msg = "free constant item without body";
+                self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
+            }
+            ItemKind::Static(.., None) => {
+                let msg = "free static item without body";
+                self.error_item_without_body(item.span, "static", msg, " = <expr>;");
+            }
+            ItemKind::TyAlias(_, ref bounds, ref body) => {
+                if body.is_none() {
+                    let msg = "free type alias without body";
+                    self.error_item_without_body(item.span, "type", msg, " = <type>;");
+                }
+                self.check_type_no_bounds(bounds, "this context");
+            }
             _ => {}
         }
 
@@ -912,7 +988,15 @@ fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
                 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
                 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
             }
-            ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
+            ForeignItemKind::TyAlias(generics, bounds, body) => {
+                self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
+                self.check_type_no_bounds(bounds, "`extern` blocks");
+                self.check_foreign_ty_genericless(generics);
+            }
+            ForeignItemKind::Static(_, _, body) => {
+                self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
+            }
+            ForeignItemKind::Const(..) | ForeignItemKind::Macro(..) => {}
         }
 
         visit::walk_foreign_item(self, fi)
@@ -954,7 +1038,7 @@ fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
             }
             GenericArgs::Parenthesized(ref data) => {
                 walk_list!(self, visit_ty, &data.inputs);
-                if let FunctionRetTy::Ty(ty) = &data.output {
+                if let FnRetTy::Ty(ty) = &data.output {
                     // `-> Foo` syntax is essentially an associated type binding,
                     // so it is also allowed to contain nested `impl Trait`.
                     self.with_impl_trait(None, |this| this.visit_ty(ty));
@@ -1159,7 +1243,7 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
                 }
                 AssocItemKind::TyAlias(_, bounds, body) => {
                     self.check_impl_item_provided(item.span, body, "type", " = <type>;");
-                    self.check_impl_assoc_type_no_bounds(bounds);
+                    self.check_type_no_bounds(bounds, "`impl`s");
                 }
                 _ => {}
             }
@@ -1173,6 +1257,10 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
             }
         }
 
+        if let AssocItemKind::Const(..) = item.kind {
+            self.check_item_named(item.ident, "const");
+        }
+
         self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
     }
 }