about summary refs log tree commit diff
diff options
context:
space:
mode:
authorfinalchild <finalchild2@gmail.com>2022-08-19 02:43:01 +0900
committerfinalchild <finalchild2@gmail.com>2022-08-22 01:11:59 +0900
commite331ae57df08e6eab346a9caab3fc354ce61c5d5 (patch)
tree8f8ba7a0b369bb46d5913ec333f27c7f28788f5a
parent8ed8aac3caa9c943e600392e49702c7215428d23 (diff)
downloadrust-e331ae57df08e6eab346a9caab3fc354ce61c5d5.tar.gz
rust-e331ae57df08e6eab346a9caab3fc354ce61c5d5.zip
Migrate forbidden_default and *_without_body
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs128
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs100
-rw-r--r--compiler/rustc_error_messages/locales/en-US/ast_passes.ftl33
3 files changed, 185 insertions, 76 deletions
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index c8b46dde1c7..b337e5328c5 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -13,7 +13,7 @@ use rustc_ast::walk_list;
 use rustc_ast::*;
 use rustc_ast_pretty::pprust::{self, State};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability, Diagnostic};
+use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability};
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::{
     DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -390,47 +390,20 @@ impl<'a> AstValidator<'a> {
     fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
         if let Defaultness::Default(def_span) = defaultness {
             let span = self.session.source_map().guess_head_span(span);
-            self.err_handler()
-                .struct_span_err(span, "`default` is only allowed on items in trait impls")
-                .span_label(def_span, "`default` because of this")
-                .emit();
+            self.session.emit_err(ForbiddenDefault { span, def_span });
         }
     }
 
-    fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
-        self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ());
-    }
-
-    fn error_item_without_body_with_help(
-        &self,
-        sp: Span,
-        ctx: &str,
-        msg: &str,
-        sugg: &str,
-        help: impl FnOnce(&mut Diagnostic),
-    ) {
+    /// If `sp` ends with a semicolon, returns it as a `Span`
+    /// Otherwise, returns `sp.shrink_to_hi()`
+    fn ending_semi_or_hi(&self, sp: Span) -> Span {
         let source_map = self.session.source_map();
         let end = source_map.end_point(sp);
-        let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
+
+        if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
             end
         } else {
             sp.shrink_to_hi()
-        };
-        let mut err = self.err_handler().struct_span_err(sp, msg);
-        err.span_suggestion(
-            replace_span,
-            &format!("provide a definition for the {}", ctx),
-            sugg,
-            Applicability::HasPlaceholders,
-        );
-        help(&mut err);
-        err.emit();
-    }
-
-    fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
-        if body.is_none() {
-            let msg = format!("associated {} in `impl` without body", ctx);
-            self.error_item_without_body(sp, ctx, &msg, sugg);
         }
     }
 
@@ -1123,37 +1096,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.check_defaultness(item.span, defaultness);
 
                 if body.is_none() {
-                    let msg = "free function without a body";
-                    let ext = sig.header.ext;
-
-                    let f = |e: &mut Diagnostic| {
-                        if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
-                        {
-                            let start_suggestion = if let Extern::Explicit(abi, _) = ext {
-                                format!("extern \"{}\" {{", abi.symbol_unescaped)
-                            } else {
-                                "extern {".to_owned()
-                            };
-
-                            let end_suggestion = " }".to_owned();
-                            let end_span = item.span.shrink_to_hi();
-
-                            e
-                            .multipart_suggestion(
-                                "if you meant to declare an externally defined function, use an `extern` block",
-                                vec![(*start_span, start_suggestion), (end_span, end_suggestion)],
-                                Applicability::MaybeIncorrect,
-                             );
-                        }
-                    };
-
-                    self.error_item_without_body_with_help(
-                        item.span,
-                        "function",
-                        msg,
-                        " { <body> }",
-                        f,
-                    );
+                    self.session.emit_err(FnWithoutBody {
+                        span: item.span,
+                        replace_span: self.ending_semi_or_hi(item.span),
+                        extern_block_suggestion: match sig.header.ext {
+                            Extern::None => None,
+                            Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
+                                start_span,
+                                end_span: item.span.shrink_to_hi(),
+                                abi: None,
+                            }),
+                            Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
+                                start_span,
+                                end_span: item.span.shrink_to_hi(),
+                                abi: Some(abi.symbol_unescaped),
+                            }),
+                        },
+                    });
                 }
 
                 self.visit_vis(&item.vis);
@@ -1259,12 +1218,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             ItemKind::Const(def, .., None) => {
                 self.check_defaultness(item.span, def);
-                let msg = "free constant item without body";
-                self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
+                self.session.emit_err(ConstWithoutBody {
+                    span: item.span,
+                    replace_span: self.ending_semi_or_hi(item.span),
+                });
             }
             ItemKind::Static(.., None) => {
-                let msg = "free static item without body";
-                self.error_item_without_body(item.span, "static", msg, " = <expr>;");
+                self.session.emit_err(StaticWithoutBody {
+                    span: item.span,
+                    replace_span: self.ending_semi_or_hi(item.span),
+                });
             }
             ItemKind::TyAlias(box TyAlias {
                 defaultness,
@@ -1275,8 +1238,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }) => {
                 self.check_defaultness(item.span, defaultness);
                 if ty.is_none() {
-                    let msg = "free type alias without body";
-                    self.error_item_without_body(item.span, "type", msg, " = <type>;");
+                    self.session.emit_err(TyAliasWithoutBody {
+                        span: item.span,
+                        replace_span: self.ending_semi_or_hi(item.span),
+                    });
                 }
                 self.check_type_no_bounds(bounds, "this context");
                 if where_clauses.1.0 {
@@ -1580,10 +1545,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         if ctxt == AssocCtxt::Impl {
             match &item.kind {
                 AssocItemKind::Const(_, _, body) => {
-                    self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
+                    if body.is_none() {
+                        self.session.emit_err(AssocConstWithoutBody {
+                            span: item.span,
+                            replace_span: self.ending_semi_or_hi(item.span),
+                        });
+                    }
                 }
                 AssocItemKind::Fn(box Fn { body, .. }) => {
-                    self.check_impl_item_provided(item.span, body, "function", " { <body> }");
+                    if body.is_none() {
+                        self.session.emit_err(AssocFnWithoutBody {
+                            span: item.span,
+                            replace_span: self.ending_semi_or_hi(item.span),
+                        });
+                    }
                 }
                 AssocItemKind::TyAlias(box TyAlias {
                     generics,
@@ -1593,7 +1568,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     ty,
                     ..
                 }) => {
-                    self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
+                    if ty.is_none() {
+                        self.session.emit_err(AssocTypeWithoutBody {
+                            span: item.span,
+                            replace_span: self.ending_semi_or_hi(item.span),
+                        });
+                    }
                     self.check_type_no_bounds(bounds, "`impl`s");
                     if ty.is_some() {
                         self.check_gat_where(
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 0287d71feb3..1ac4dac10e2 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -1,7 +1,6 @@
 //! Errors emitted by ast_passes.
 
-use rustc_errors::fluent;
-use rustc_errors::{AddSubdiagnostic, Diagnostic};
+use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic};
 use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
 use rustc_span::{Span, Symbol};
 
@@ -150,3 +149,100 @@ pub struct FnParamForbiddenSelf {
     #[label]
     pub span: Span,
 }
+
+#[derive(SessionDiagnostic)]
+#[error(ast_passes::forbidden_default)]
+pub struct ForbiddenDefault {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub def_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(ast_passes::assoc_const_without_body)]
+pub struct AssocConstWithoutBody {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
+    pub replace_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(ast_passes::assoc_fn_without_body)]
+pub struct AssocFnWithoutBody {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = " {{ <body> }}", applicability = "has-placeholders")]
+    pub replace_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(ast_passes::assoc_type_without_body)]
+pub struct AssocTypeWithoutBody {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = " = <type>;", applicability = "has-placeholders")]
+    pub replace_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(ast_passes::const_without_body)]
+pub struct ConstWithoutBody {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
+    pub replace_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(ast_passes::static_without_body)]
+pub struct StaticWithoutBody {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
+    pub replace_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(ast_passes::ty_alias_without_body)]
+pub struct TyAliasWithoutBody {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = " = <type>;", applicability = "has-placeholders")]
+    pub replace_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(ast_passes::fn_without_body)]
+pub struct FnWithoutBody {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(code = " {{ <body> }}", applicability = "has-placeholders")]
+    pub replace_span: Span,
+    #[subdiagnostic]
+    pub extern_block_suggestion: Option<ExternBlockSuggestion>,
+}
+
+pub struct ExternBlockSuggestion {
+    pub start_span: Span,
+    pub end_span: Span,
+    pub abi: Option<Symbol>,
+}
+
+impl AddSubdiagnostic for ExternBlockSuggestion {
+    fn add_to_diagnostic(self, diag: &mut Diagnostic) {
+        let start_suggestion = if let Some(abi) = self.abi {
+            format!("extern \"{}\" {{", abi)
+        } else {
+            "extern {".to_owned()
+        };
+        let end_suggestion = " }".to_owned();
+
+        diag.multipart_suggestion(
+            fluent::ast_passes::extern_block_suggestion,
+            vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)],
+            Applicability::MaybeIncorrect,
+        );
+    }
+}
diff --git a/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
index 77826f639f4..db91a886c72 100644
--- a/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
@@ -58,3 +58,36 @@ ast_passes_fn_param_forbidden_self =
     `self` parameter is only allowed in associated functions
     .label = not semantically valid as function parameter
     .note = associated functions are those in `impl` or `trait` definitions
+
+ast_passes_forbidden_default =
+    `default` is only allowed on items in trait impls
+    .label = `default` because of this
+
+ast_passes_assoc_const_without_body =
+    associated constant in `impl` without body
+    .suggestion = provide a definition for the constant
+
+ast_passes_assoc_fn_without_body =
+    associated function in `impl` without body
+    .suggestion = provide a definition for the function
+
+ast_passes_assoc_type_without_body =
+    associated type in `impl` without body
+    .suggestion = provide a definition for the type
+
+ast_passes_const_without_body =
+    free constant item without body
+    .suggestion = provide a definition for the constant
+
+ast_passes_static_without_body =
+    free static item without body
+    .suggestion = provide a definition for the static
+
+ast_passes_ty_alias_without_body =
+    free type alias without body
+    .suggestion = provide a definition for the type
+
+ast_passes_fn_without_body =
+    free function without a body
+    .suggestion = provide a definition for the function
+    .extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block