From bde80f745b86750a31294013fef590dd9e6965c3 Mon Sep 17 00:00:00 2001 From: rdvdev2 Date: Mon, 22 Aug 2022 08:56:46 +0200 Subject: [PATCH 01/29] Add lint for diagnostic migration --- compiler/rustc_passes/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 6e621b7eb5eb0..15f60f626c89a 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -5,6 +5,8 @@ //! This API is completely unstable and subject to change. #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(iter_intersperse)] #![feature(let_chains)] From 2f74d1d14ff08bfc5995ba1379840e5bd3f30efb Mon Sep 17 00:00:00 2001 From: rdvdev2 Date: Mon, 22 Aug 2022 10:05:13 +0200 Subject: [PATCH 02/29] Migrate weak_lang_items.rs --- .../locales/en-US/passes.ftl | 9 +++++++++ compiler/rustc_passes/src/errors.rs | 17 +++++++++++++++++ compiler/rustc_passes/src/weak_lang_items.rs | 15 +++++---------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 995ad4fe25859..bfe22727483da 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -271,3 +271,12 @@ passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect .suggestion = remove the unnecessary deprecation attribute + +passes_missing_panic_handler = `#[panic_handler]` function required, but not found + +passes_missing_alloc_error_handler = `#[alloc_error_handler]` function required, but not found + .note = use `#![feature(default_alloc_error_handler)]` for a default error handler + +passes_missing_lang_item = language item required, but not found: `{$name}` + .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library + .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config` diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index cc231af71a274..7dbdee8a87ae5 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -665,3 +665,20 @@ pub struct DeprecatedAnnotationHasNoEffect { #[suggestion(applicability = "machine-applicable", code = "")] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(passes::missing_panic_handler)] +pub struct MissingPanicHandler; + +#[derive(Diagnostic)] +#[diag(passes::missing_alloc_error_handler)] +#[note] +pub struct MissingAllocErrorHandler; + +#[derive(Diagnostic)] +#[diag(passes::missing_lang_item)] +#[note] +#[help] +pub struct MissingLangItem { + pub name: Symbol, +} diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index c48b4ecf87a3a..2345de74bdfbc 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -8,6 +8,8 @@ use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; +use crate::errors::{MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler}; + /// Checks the crate for usage of weak lang items, returning a vector of all the /// language items required by this crate, but not defined yet. pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItems) { @@ -71,20 +73,13 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { for (name, &item) in WEAK_ITEMS_REFS.iter() { if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() { if item == LangItem::PanicImpl { - tcx.sess.err("`#[panic_handler]` function required, but not found"); + tcx.sess.emit_err(MissingPanicHandler); } else if item == LangItem::Oom { if !tcx.features().default_alloc_error_handler { - tcx.sess.err("`#[alloc_error_handler]` function required, but not found"); - tcx.sess.note_without_error("use `#![feature(default_alloc_error_handler)]` for a default error handler"); + tcx.sess.emit_err(MissingAllocErrorHandler); } } else { - tcx - .sess - .diagnostic() - .struct_err(&format!("language item required, but not found: `{}`", name)) - .note(&format!("this can occur when a binary crate with `#![no_std]` is compiled for a target where `{}` is defined in the standard library", name)) - .help(&format!("you may be able to compile for a target that doesn't need `{}`, specify a target with `--target` or in `.cargo/config`", name)) - .emit(); + tcx.sess.emit_err(MissingLangItem { name: *name }); } } } From 17a4a68ab0ffa0e8736d5ccf71f6e56794a0320a Mon Sep 17 00:00:00 2001 From: rdvdev2 Date: Fri, 2 Sep 2022 00:11:44 +0200 Subject: [PATCH 03/29] Migrate derivable diagnostics in lang_items.rs --- .../locales/en-US/passes.ftl | 8 +++++ compiler/rustc_passes/src/errors.rs | 21 +++++++++++++ compiler/rustc_passes/src/lang_items.rs | 30 +++++-------------- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index bfe22727483da..6512af1d14c86 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -280,3 +280,11 @@ passes_missing_alloc_error_handler = `#[alloc_error_handler]` function required, passes_missing_lang_item = language item required, but not found: `{$name}` .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config` + +passes_lang_item_on_incorrect_target = `{$name}` language item must be applied to a {$expected_target} + .label = attribute should be applied to a {$expected_target}, not a {$actual_target} + +passes_unknown_lang_item = definition of an unknown language item: `{$name}` + .label = definition of unknown language item `{$name}` + +passes_local_duplicate_lang_item = found duplicate lang item `{$name}` diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 7dbdee8a87ae5..cd05784cd53b3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,4 +1,5 @@ use rustc_errors::{Applicability, MultiSpan}; +use rustc_hir::Target; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -682,3 +683,23 @@ pub struct MissingAllocErrorHandler; pub struct MissingLangItem { pub name: Symbol, } + +#[derive(Diagnostic)] +#[diag(passes::lang_item_on_incorrect_target, code = "E0718")] +pub struct LangItemOnIncorrectTarget { + #[primary_span] + #[label] + pub span: Span, + pub name: Symbol, + pub expected_target: Target, + pub actual_target: Target, +} + +#[derive(Diagnostic)] +#[diag(passes::unknown_lang_item, code = "E0522")] +pub struct UnknownLangItem { + #[primary_span] + #[label] + pub span: Span, + pub name: Symbol, +} diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 79900a90aed63..98ff625d09469 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -7,6 +7,7 @@ //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Functions called by the compiler itself. +use crate::errors::{LangItemOnIncorrectTarget, UnknownLangItem}; use crate::check_attr::target_from_impl_item; use crate::weak_lang_items; @@ -42,34 +43,19 @@ impl<'tcx> LanguageItemCollector<'tcx> { } // Known lang item with attribute on incorrect target. Some((_, expected_target)) => { - struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(LangItemOnIncorrectTarget { span, - E0718, - "`{}` language item must be applied to a {}", - value, + name: value, expected_target, - ) - .span_label( - span, - format!( - "attribute should be applied to a {}, not a {}", - expected_target, actual_target, - ), - ) - .emit(); + actual_target, + }); } // Unknown lang item. _ => { - struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(UnknownLangItem { span, - E0522, - "definition of an unknown language item: `{}`", - value - ) - .span_label(span, format!("definition of unknown language item `{}`", value)) - .emit(); + name: value, + }); } } } From 0315d7c9dbc33164ce8d1a7ad0464fa695a59399 Mon Sep 17 00:00:00 2001 From: rdvdev2 Date: Fri, 2 Sep 2022 04:54:42 +0200 Subject: [PATCH 04/29] Migrate derivable diagnostics in check_attr.rs --- .../rustc_error_messages/locales/en-US/passes.ftl | 2 ++ compiler/rustc_passes/src/check_attr.rs | 14 ++++++-------- compiler/rustc_passes/src/errors.rs | 11 +++++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 6512af1d14c86..9a3ea51c778df 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -217,6 +217,8 @@ passes_debug_visualizer_invalid = invalid argument .note_2 = OR .note_3 = expected: `gdb_script_file = "..."` +passes_debug_visualizer_unreadable = couldn't read {$file}: {$error} + passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn` .label = not a `const fn` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 87433538512b9..864ce751588f1 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -4,7 +4,7 @@ //! conflicts between multiple such attributes attached to the same //! item. -use crate::errors; +use crate::errors::{self, DebugVisualizerUnreadable}; use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan}; @@ -1863,13 +1863,11 @@ impl CheckAttrVisitor<'_> { match std::fs::File::open(&file) { Ok(_) => true, Err(err) => { - self.tcx - .sess - .struct_span_err( - meta_item.span, - &format!("couldn't read {}: {}", file.display(), err), - ) - .emit(); + self.tcx.sess.emit_err(DebugVisualizerUnreadable { + span: meta_item.span, + file: &file, + error: err, + } ); false } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index cd05784cd53b3..5730e9db66685 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,3 +1,5 @@ +use std::{io::Error, path::Path}; + use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::Target; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -527,6 +529,15 @@ pub struct DebugVisualizerInvalid { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes::debug_visualizer_unreadable)] +pub struct DebugVisualizerUnreadable<'a> { + #[primary_span] + pub span: Span, + pub file: &'a Path, + pub error: Error, +} + #[derive(Diagnostic)] #[diag(passes::rustc_allow_const_fn_unstable)] pub struct RustcAllowConstFnUnstable { From 2c3351c9a64caf76775c1335201a4762f5fdeaf8 Mon Sep 17 00:00:00 2001 From: rdvdev2 Date: Fri, 2 Sep 2022 05:19:03 +0200 Subject: [PATCH 05/29] Migrate InvalidAttrAtCrateLevel Co-authored-by: Nathan Stocks Co-authored-by: rdvdev2 --- .../locales/en-US/passes.ftl | 3 ++ compiler/rustc_passes/src/check_attr.rs | 28 ++++------------ compiler/rustc_passes/src/errors.rs | 32 ++++++++++++++++++- compiler/rustc_passes/src/lang_items.rs | 7 ++-- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 9a3ea51c778df..c1c2f379fa52a 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -290,3 +290,6 @@ passes_unknown_lang_item = definition of an unknown language item: `{$name}` .label = definition of unknown language item `{$name}` passes_local_duplicate_lang_item = found duplicate lang item `{$name}` + +passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level + .suggestion = perhaps you meant to use an outer attribute diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 864ce751588f1..2a9578e8ce32c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -4,7 +4,7 @@ //! conflicts between multiple such attributes attached to the same //! item. -use crate::errors::{self, DebugVisualizerUnreadable}; +use crate::errors::{self, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel}; use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan}; @@ -1867,7 +1867,7 @@ impl CheckAttrVisitor<'_> { span: meta_item.span, file: &file, error: err, - } ); + }); false } } @@ -2178,25 +2178,11 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { if attr.style == AttrStyle::Inner { for attr_to_check in ATTRS_TO_CHECK { if attr.has_name(*attr_to_check) { - let mut err = tcx.sess.struct_span_err( - attr.span, - &format!( - "`{}` attribute cannot be used at crate level", - attr_to_check.to_ident_string() - ), - ); - // Only emit an error with a suggestion if we can create a - // string out of the attribute span - if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) { - let replacement = src.replace("#!", "#"); - err.span_suggestion_verbose( - attr.span, - "perhaps you meant to use an outer attribute", - replacement, - rustc_errors::Applicability::MachineApplicable, - ); - } - err.emit(); + tcx.sess.emit_err(InvalidAttrAtCrateLevel { + span: attr.span, + snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(), + name: *attr_to_check, + }); } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 5730e9db66685..9b8eebd6be0be 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,6 +1,6 @@ use std::{io::Error, path::Path}; -use rustc_errors::{Applicability, MultiSpan}; +use rustc_errors::{Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; use rustc_hir::Target; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -714,3 +714,33 @@ pub struct UnknownLangItem { pub span: Span, pub name: Symbol, } + +pub struct InvalidAttrAtCrateLevel { + pub span: Span, + pub snippet: Option, + pub name: Symbol, +} + +impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { + fn into_diagnostic( + self, + handler: &'_ rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = + handler.struct_err(rustc_errors::fluent::passes::invalid_attr_at_crate_level); + diag.set_span(self.span); + diag.set_arg("name", self.name); + // Only emit an error with a suggestion if we can create a string out + // of the attribute span + if let Some(src) = self.snippet { + let replacement = src.replace("#!", "#"); + diag.span_suggestion_verbose( + self.span, + rustc_errors::fluent::passes::suggestion, + replacement, + rustc_errors::Applicability::MachineApplicable, + ); + } + diag + } +} diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 98ff625d09469..24657372486f2 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -7,8 +7,8 @@ //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Functions called by the compiler itself. -use crate::errors::{LangItemOnIncorrectTarget, UnknownLangItem}; use crate::check_attr::target_from_impl_item; +use crate::errors::{LangItemOnIncorrectTarget, UnknownLangItem}; use crate::weak_lang_items; use rustc_errors::{pluralize, struct_span_err}; @@ -52,10 +52,7 @@ impl<'tcx> LanguageItemCollector<'tcx> { } // Unknown lang item. _ => { - self.tcx.sess.emit_err(UnknownLangItem { - span, - name: value, - }); + self.tcx.sess.emit_err(UnknownLangItem { span, name: value }); } } } From c24a87315af884680332f850753b3eeef18c22c8 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Wed, 21 Sep 2022 14:05:15 -0600 Subject: [PATCH 06/29] always put ftl message on next line, resolve all but 1 output comparison error --- .../locales/en-US/passes.ftl | 269 ++++++++++++------ 1 file changed, 180 insertions(+), 89 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index c1c2f379fa52a..bd6a973e9163f 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -10,88 +10,119 @@ passes_outer_crate_level_attr = passes_inner_crate_level_attr = crate-level attribute should be in the root module -passes_ignored_attr_with_macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs +passes_ignored_attr_with_macro = + `#[{$sym}]` is ignored on struct fields, match arms and macro defs .warn = {-passes_previously_accepted} .note = {-passes_see_issue(issue: "80564")} -passes_ignored_attr = `#[{$sym}]` is ignored on struct fields and match arms +passes_ignored_attr = + `#[{$sym}]` is ignored on struct fields and match arms .warn = {-passes_previously_accepted} .note = {-passes_see_issue(issue: "80564")} -passes_inline_ignored_function_prototype = `#[inline]` is ignored on function prototypes +passes_inline_ignored_function_prototype = + `#[inline]` is ignored on function prototypes -passes_inline_ignored_constants = `#[inline]` is ignored on constants +passes_inline_ignored_constants = + `#[inline]` is ignored on constants .warn = {-passes_previously_accepted} .note = {-passes_see_issue(issue: "65833")} -passes_inline_not_fn_or_closure = attribute should be applied to function or closure +passes_inline_not_fn_or_closure = + attribute should be applied to function or closure .label = not a function or closure -passes_no_coverage_ignored_function_prototype = `#[no_coverage]` is ignored on function prototypes +passes_no_coverage_ignored_function_prototype = + `#[no_coverage]` is ignored on function prototypes passes_no_coverage_propagate = `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly -passes_no_coverage_fn_defn = `#[no_coverage]` may only be applied to function definitions +passes_no_coverage_fn_defn = + `#[no_coverage]` may only be applied to function definitions -passes_no_coverage_not_coverable = `#[no_coverage]` must be applied to coverable code +passes_no_coverage_not_coverable = + `#[no_coverage]` must be applied to coverable code .label = not coverable code -passes_should_be_applied_to_fn = attribute should be applied to a function definition +passes_should_be_applied_to_fn = + attribute should be applied to a function definition .label = not a function definition -passes_naked_tracked_caller = cannot use `#[track_caller]` with `#[naked]` +passes_naked_tracked_caller = + cannot use `#[track_caller]` with `#[naked]` -passes_should_be_applied_to_struct_enum = attribute should be applied to a struct or enum +passes_should_be_applied_to_struct_enum = + attribute should be applied to a struct or enum .label = not a struct or enum -passes_should_be_applied_to_trait = attribute should be applied to a trait +passes_should_be_applied_to_trait = + attribute should be applied to a trait .label = not a trait -passes_target_feature_on_statement = {passes_should_be_applied_to_fn} +passes_target_feature_on_statement = + {passes_should_be_applied_to_fn} .warn = {-passes_previously_accepted} .label = {passes_should_be_applied_to_fn.label} -passes_should_be_applied_to_static = attribute should be applied to a static +passes_should_be_applied_to_static = + attribute should be applied to a static .label = not a static -passes_doc_expect_str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] +passes_doc_expect_str = + doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] -passes_doc_alias_empty = {$attr_str} attribute cannot have empty value +passes_doc_alias_empty = + {$attr_str} attribute cannot have empty value -passes_doc_alias_bad_char = {$char_} character isn't allowed in {$attr_str} +passes_doc_alias_bad_char = + {$char_} character isn't allowed in {$attr_str} -passes_doc_alias_start_end = {$attr_str} cannot start or end with ' ' +passes_doc_alias_start_end = + {$attr_str} cannot start or end with ' ' -passes_doc_alias_bad_location = {$attr_str} isn't allowed on {$location} +passes_doc_alias_bad_location = + {$attr_str} isn't allowed on {$location} -passes_doc_alias_not_an_alias = {$attr_str} is the same as the item's name +passes_doc_alias_not_an_alias = + {$attr_str} is the same as the item's name passes_doc_alias_duplicated = doc alias is duplicated .label = first defined here -passes_doc_alias_not_string_literal = `#[doc(alias("a"))]` expects string literals +passes_doc_alias_not_string_literal = + `#[doc(alias("a"))]` expects string literals passes_doc_alias_malformed = doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` -passes_doc_keyword_empty_mod = `#[doc(keyword = "...")]` should be used on empty modules +passes_doc_keyword_empty_mod = + `#[doc(keyword = "...")]` should be used on empty modules -passes_doc_keyword_not_mod = `#[doc(keyword = "...")]` should be used on modules +passes_doc_keyword_not_mod = + `#[doc(keyword = "...")]` should be used on modules -passes_doc_keyword_invalid_ident = `{$doc_keyword}` is not a valid identifier +passes_doc_keyword_invalid_ident = + `{$doc_keyword}` is not a valid identifier passes_doc_fake_variadic_not_valid = `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity -passes_doc_keyword_only_impl = `#[doc(keyword = "...")]` should be used on impl blocks +passes_doc_keyword_only_impl = + `#[doc(keyword = "...")]` should be used on impl blocks -passes_doc_inline_conflict_first = this attribute... -passes_doc_inline_conflict_second = ...conflicts with this attribute -passes_doc_inline_conflict = conflicting doc inlining attributes +passes_doc_inline_conflict_first = + this attribute... + +passes_doc_inline_conflict_second = + {"."}..conflicts with this attribute + +passes_doc_inline_conflict = + conflicting doc inlining attributes .help = remove one of the conflicting attributes -passes_doc_inline_only_use = this attribute can only be applied to a `use` item +passes_doc_inline_only_use = + this attribute can only be applied to a `use` item .label = only applicable on `use` items .not_a_use_item_label = not a `use` item .note = read for more information @@ -99,30 +130,39 @@ passes_doc_inline_only_use = this attribute can only be applied to a `use` item passes_doc_attr_not_crate_level = `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute -passes_attr_crate_level = this attribute can only be applied at the crate level +passes_attr_crate_level = + this attribute can only be applied at the crate level .suggestion = to apply to the crate, use an inner attribute .help = to apply to the crate, use an inner attribute .note = read for more information -passes_doc_test_unknown = unknown `doc(test)` attribute `{$path}` +passes_doc_test_unknown = + unknown `doc(test)` attribute `{$path}` -passes_doc_test_takes_list = `#[doc(test(...)]` takes a list of attributes +passes_doc_test_takes_list = + `#[doc(test(...)]` takes a list of attributes -passes_doc_primitive = `doc(primitive)` should never have been stable +passes_doc_primitive = + `doc(primitive)` should never have been stable -passes_doc_test_unknown_any = unknown `doc` attribute `{$path}` +passes_doc_test_unknown_any = + unknown `doc` attribute `{$path}` -passes_doc_test_unknown_spotlight = unknown `doc` attribute `{$path}` +passes_doc_test_unknown_spotlight = + unknown `doc` attribute `{$path}` .note = `doc(spotlight)` was renamed to `doc(notable_trait)` .suggestion = use `notable_trait` instead .no_op_note = `doc(spotlight)` is now a no-op -passes_doc_test_unknown_include = unknown `doc` attribute `{$path}` +passes_doc_test_unknown_include = + unknown `doc` attribute `{$path}` .suggestion = use `doc = include_str!` instead -passes_doc_invalid = invalid `doc` attribute +passes_doc_invalid = + invalid `doc` attribute -passes_pass_by_value = `pass_by_value` attribute should be applied to a struct, enum or type alias +passes_pass_by_value = + `pass_by_value` attribute should be applied to a struct, enum or type alias .label = is not a struct, enum or type alias passes_allow_incoherent_impl = @@ -137,42 +177,54 @@ passes_must_use_async = `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use` -passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target} +passes_must_use_no_effect = + `#[must_use]` has no effect when applied to {$article} {$target} -passes_must_not_suspend = `must_not_suspend` attribute should be applied to a struct, enum, or trait +passes_must_not_suspend = + `must_not_suspend` attribute should be applied to a struct, enum, or trait .label = is not a struct, enum, or trait -passes_cold = {passes_should_be_applied_to_fn} +passes_cold = + {passes_should_be_applied_to_fn} .warn = {-passes_previously_accepted} .label = {passes_should_be_applied_to_fn.label} -passes_link = attribute should be applied to an `extern` block with non-Rust ABI +passes_link = + attribute should be applied to an `extern` block with non-Rust ABI .warn = {-passes_previously_accepted} .label = not an `extern` block -passes_link_name = attribute should be applied to a foreign function or static +passes_link_name = + attribute should be applied to a foreign function or static .warn = {-passes_previously_accepted} .label = not a foreign function or static .help = try `#[link(name = "{$value}")]` instead -passes_no_link = attribute should be applied to an `extern crate` item +passes_no_link = + attribute should be applied to an `extern crate` item .label = not an `extern crate` item -passes_export_name = attribute should be applied to a free function, impl method or static +passes_export_name = + attribute should be applied to a free function, impl method or static .label = not a free function, impl method or static -passes_rustc_layout_scalar_valid_range_not_struct = attribute should be applied to a struct +passes_rustc_layout_scalar_valid_range_not_struct = + attribute should be applied to a struct .label = not a struct -passes_rustc_layout_scalar_valid_range_arg = expected exactly one integer literal argument +passes_rustc_layout_scalar_valid_range_arg = + expected exactly one integer literal argument -passes_rustc_legacy_const_generics_only = #[rustc_legacy_const_generics] functions must only have const generics +passes_rustc_legacy_const_generics_only = + #[rustc_legacy_const_generics] functions must only have const generics .label = non-const generic parameter -passes_rustc_legacy_const_generics_index = #[rustc_legacy_const_generics] must have one index for each generic parameter +passes_rustc_legacy_const_generics_index = + #[rustc_legacy_const_generics] must have one index for each generic parameter .label = generic parameters -passes_rustc_legacy_const_generics_index_exceed = index exceeds number of arguments +passes_rustc_legacy_const_generics_index_exceed = + index exceeds number of arguments .label = there {$arg_count -> [one] is *[other] are @@ -181,115 +233,154 @@ passes_rustc_legacy_const_generics_index_exceed = index exceeds number of argume *[other] arguments } -passes_rustc_legacy_const_generics_index_negative = arguments should be non-negative integers +passes_rustc_legacy_const_generics_index_negative = + arguments should be non-negative integers -passes_rustc_dirty_clean = attribute requires -Z query-dep-graph to be enabled +passes_rustc_dirty_clean = + attribute requires -Z query-dep-graph to be enabled -passes_link_section = attribute should be applied to a function or static +passes_link_section = + attribute should be applied to a function or static .warn = {-passes_previously_accepted} .label = not a function or static -passes_no_mangle_foreign = `#[no_mangle]` has no effect on a foreign {$foreign_item_kind} +passes_no_mangle_foreign = + `#[no_mangle]` has no effect on a foreign {$foreign_item_kind} .warn = {-passes_previously_accepted} .label = foreign {$foreign_item_kind} .note = symbol names in extern blocks are not mangled .suggestion = remove this attribute -passes_no_mangle = attribute should be applied to a free function, impl method or static +passes_no_mangle = + attribute should be applied to a free function, impl method or static .warn = {-passes_previously_accepted} .label = not a free function, impl method or static -passes_repr_ident = meta item in `repr` must be an identifier +passes_repr_ident = + meta item in `repr` must be an identifier -passes_repr_conflicting = conflicting representation hints +passes_repr_conflicting = + conflicting representation hints -passes_used_static = attribute must be applied to a `static` variable +passes_used_static = + attribute must be applied to a `static` variable -passes_used_compiler_linker = `used(compiler)` and `used(linker)` can't be used together +passes_used_compiler_linker = + `used(compiler)` and `used(linker)` can't be used together -passes_allow_internal_unstable = attribute should be applied to a macro +passes_allow_internal_unstable = + attribute should be applied to a macro .label = not a macro -passes_debug_visualizer_placement = attribute should be applied to a module +passes_debug_visualizer_placement = + attribute should be applied to a module -passes_debug_visualizer_invalid = invalid argument +passes_debug_visualizer_invalid = + invalid argument .note_1 = expected: `natvis_file = "..."` .note_2 = OR .note_3 = expected: `gdb_script_file = "..."` -passes_debug_visualizer_unreadable = couldn't read {$file}: {$error} +passes_debug_visualizer_unreadable = + couldn't read {$file}: {$error} -passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn` +passes_rustc_allow_const_fn_unstable = + attribute should be applied to `const fn` .label = not a `const fn` -passes_rustc_std_internal_symbol = attribute should be applied to functions or statics +passes_rustc_std_internal_symbol = + attribute should be applied to functions or statics .label = not a function or static -passes_const_trait = attribute should be applied to a trait +passes_const_trait = + attribute should be applied to a trait -passes_stability_promotable = attribute cannot be applied to an expression +passes_stability_promotable = + attribute cannot be applied to an expression -passes_deprecated = attribute is ignored here +passes_deprecated = + attribute is ignored here -passes_macro_use = `#[{$name}]` only has an effect on `extern crate` and modules +passes_macro_use = + `#[{$name}]` only has an effect on `extern crate` and modules -passes_macro_export = `#[macro_export]` only has an effect on macro definitions +passes_macro_export = + `#[macro_export]` only has an effect on macro definitions -passes_plugin_registrar = `#[plugin_registrar]` only has an effect on functions +passes_plugin_registrar = + `#[plugin_registrar]` only has an effect on functions -passes_unused_empty_lints_note = attribute `{$name}` with an empty list has no effect +passes_unused_empty_lints_note = + attribute `{$name}` with an empty list has no effect -passes_unused_no_lints_note = attribute `{$name}` without any lints has no effect +passes_unused_no_lints_note = + attribute `{$name}` without any lints has no effect passes_unused_default_method_body_const_note = `default_method_body_is_const` has been replaced with `#[const_trait]` on traits -passes_unused = unused attribute +passes_unused = + unused attribute .suggestion = remove this attribute -passes_non_exported_macro_invalid_attrs = attribute should be applied to function or closure +passes_non_exported_macro_invalid_attrs = + attribute should be applied to function or closure .label = not a function or closure -passes_unused_duplicate = unused attribute +passes_unused_duplicate = + unused attribute .suggestion = remove this attribute .note = attribute also specified here .warn = {-passes_previously_accepted} -passes_unused_multiple = multiple `{$name}` attributes +passes_unused_multiple = + multiple `{$name}` attributes .suggestion = remove this attribute .note = attribute also specified here -passes_rustc_lint_opt_ty = `#[rustc_lint_opt_ty]` should be applied to a struct +passes_rustc_lint_opt_ty = + `#[rustc_lint_opt_ty]` should be applied to a struct .label = not a struct -passes_rustc_lint_opt_deny_field_access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field +passes_rustc_lint_opt_deny_field_access = + `#[rustc_lint_opt_deny_field_access]` should be applied to a field .label = not a field -passes_link_ordinal = attribute should be applied to a foreign function or static +passes_link_ordinal = + attribute should be applied to a foreign function or static .label = not a foreign function or static -passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to macro definitions +passes_collapse_debuginfo = + `collapse_debuginfo` attribute should be applied to macro definitions .label = not a macro definition -passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect +passes_deprecated_annotation_has_no_effect = + this `#[deprecated]` annotation has no effect .suggestion = remove the unnecessary deprecation attribute -passes_missing_panic_handler = `#[panic_handler]` function required, but not found +passes_missing_panic_handler = + `#[panic_handler]` function required, but not found -passes_missing_alloc_error_handler = `#[alloc_error_handler]` function required, but not found +passes_missing_alloc_error_handler = + `#[alloc_error_handler]` function required, but not found .note = use `#![feature(default_alloc_error_handler)]` for a default error handler -passes_missing_lang_item = language item required, but not found: `{$name}` +passes_missing_lang_item = + language item required, but not found: `{$name}` .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config` -passes_lang_item_on_incorrect_target = `{$name}` language item must be applied to a {$expected_target} +passes_lang_item_on_incorrect_target = + `{$name}` language item must be applied to a {$expected_target} .label = attribute should be applied to a {$expected_target}, not a {$actual_target} -passes_unknown_lang_item = definition of an unknown language item: `{$name}` +passes_unknown_lang_item = + definition of an unknown language item: `{$name}` .label = definition of unknown language item `{$name}` -passes_local_duplicate_lang_item = found duplicate lang item `{$name}` +passes_local_duplicate_lang_item = + found duplicate lang item `{$name}` -passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level +passes_invalid_attr_at_crate_level = + `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute From b8e03cfa55d6133f8fc1fd3a82a7e686a9cf006e Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Wed, 21 Sep 2022 22:30:14 -0600 Subject: [PATCH 07/29] use consistent names --- compiler/rustc_passes/src/check_attr.rs | 4 ++-- compiler/rustc_passes/src/lang_items.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2a9578e8ce32c..18e1233fa84fd 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1862,11 +1862,11 @@ impl CheckAttrVisitor<'_> { match std::fs::File::open(&file) { Ok(_) => true, - Err(err) => { + Err(error) => { self.tcx.sess.emit_err(DebugVisualizerUnreadable { span: meta_item.span, file: &file, - error: err, + error, }); false } diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 24657372486f2..2b090e036fe99 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -35,8 +35,8 @@ impl<'tcx> LanguageItemCollector<'tcx> { fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) { let attrs = self.tcx.hir().attrs(hir_id); - if let Some((value, span)) = extract(&attrs) { - match ITEM_REFS.get(&value).cloned() { + if let Some((name, span)) = extract(&attrs) { + match ITEM_REFS.get(&name).cloned() { // Known lang item with attribute on correct target. Some((item_index, expected_target)) if actual_target == expected_target => { self.collect_item_extended(item_index, hir_id, span); @@ -45,14 +45,14 @@ impl<'tcx> LanguageItemCollector<'tcx> { Some((_, expected_target)) => { self.tcx.sess.emit_err(LangItemOnIncorrectTarget { span, - name: value, + name, expected_target, actual_target, }); } // Unknown lang item. _ => { - self.tcx.sess.emit_err(UnknownLangItem { span, name: value }); + self.tcx.sess.emit_err(UnknownLangItem { span, name }); } } } From 1222541cfd69386d0383c37042d8bbfd9f2ad0a3 Mon Sep 17 00:00:00 2001 From: Diego de Oliveira Date: Wed, 14 Sep 2022 15:03:12 -0300 Subject: [PATCH 08/29] resolve merge conflict from cherry-picking 6a47326a0452cc8d5cb57676508b5469d648c67f --- compiler/rustc_error_messages/locales/en-US/passes.ftl | 3 +++ compiler/rustc_passes/src/errors.rs | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index bd6a973e9163f..0c98f567276b4 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -384,3 +384,6 @@ passes_local_duplicate_lang_item = passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute + +passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect + .suggestion = remove the unnecessary deprecation attribute diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 9b8eebd6be0be..10deb4db55ffa 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -744,3 +744,10 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { diag } } + +#[derive(LintDiagnostic)] +#[diag(passes::deprecated_annotation_has_no_effect)] +pub struct DeprecatedAnnotationHasNoEffect { + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, +} From c103c3059f5481f60ae43465fce0646aa2c0dfa3 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Wed, 21 Sep 2022 22:49:30 -0600 Subject: [PATCH 09/29] migrate the rest of weak_lang_items.rs to translateable diagnostics --- .../rustc_error_messages/locales/en-US/passes.ftl | 6 +++--- compiler/rustc_passes/src/errors.rs | 15 ++++++++------- compiler/rustc_passes/src/weak_lang_items.rs | 14 ++++---------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 0c98f567276b4..7dddc6e10b655 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -358,6 +358,9 @@ passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect .suggestion = remove the unnecessary deprecation attribute +passes_unknown_external_lang_item = + unknown external lang item: `{$lang_item}` + passes_missing_panic_handler = `#[panic_handler]` function required, but not found @@ -384,6 +387,3 @@ passes_local_duplicate_lang_item = passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute - -passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect - .suggestion = remove the unnecessary deprecation attribute diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 10deb4db55ffa..0fabbb206cf92 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -678,6 +678,14 @@ pub struct DeprecatedAnnotationHasNoEffect { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes::unknown_external_lang_item, code = "E0264")] +pub struct UnknownExternLangItem { + #[primary_span] + pub span: Span, + pub lang_item: Symbol, +} + #[derive(Diagnostic)] #[diag(passes::missing_panic_handler)] pub struct MissingPanicHandler; @@ -744,10 +752,3 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { diag } } - -#[derive(LintDiagnostic)] -#[diag(passes::deprecated_annotation_has_no_effect)] -pub struct DeprecatedAnnotationHasNoEffect { - #[suggestion(applicability = "machine-applicable", code = "")] - pub span: Span, -} diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 2345de74bdfbc..0d2745fb5f40f 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -1,14 +1,15 @@ //! Validity checking for weak lang items use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; use rustc_hir::lang_items::{self, LangItem}; use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS; use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; -use crate::errors::{MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler}; +use crate::errors::{ + MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler, UnknownExternLangItem, +}; /// Checks the crate for usage of weak lang items, returning a vector of all the /// language items required by this crate, but not defined yet. @@ -33,14 +34,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem } } else { let span = tcx.def_span(id.def_id); - struct_span_err!( - tcx.sess, - span, - E0264, - "unknown external lang item: `{}`", - lang_item - ) - .emit(); + tcx.sess.emit_err(UnknownExternLangItem { span, lang_item }); } } } From 1e86226e9d6720b5c60c51d75b0a3f038d8bc5f5 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Wed, 21 Sep 2022 22:55:29 -0600 Subject: [PATCH 10/29] migrate debugger_visualizer.rs to translateable diagnostics --- compiler/rustc_passes/src/debugger_visualizer.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index e08683fe23b20..253b0a88e48aa 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -13,6 +13,8 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType}; use std::sync::Arc; +use crate::errors::DebugVisualizerUnreadable; + fn check_for_debugger_visualizer<'tcx>( tcx: TyCtxt<'tcx>, hir_id: HirId, @@ -54,13 +56,12 @@ fn check_for_debugger_visualizer<'tcx>( debugger_visualizers .insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type)); } - Err(err) => { - tcx.sess - .struct_span_err( - meta_item.span, - &format!("couldn't read {}: {}", file.display(), err), - ) - .emit(); + Err(error) => { + tcx.sess.emit_err(DebugVisualizerUnreadable { + span: meta_item.span, + file: &file, + error, + }); } } } From f8ebc72b4aa138772434039950126f2c7f07a3f4 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 1 Sep 2022 11:40:43 +0100 Subject: [PATCH 11/29] errors: add `emit_note`/`create_note` Add `Noted` marker struct that implements `EmissionGuarantee` so that `emit_note` and `create_note` can be implemented for struct diagnostics. Signed-off-by: David Wood --- .../rustc_errors/src/diagnostic_builder.rs | 50 +++++++++++++++++++ compiler/rustc_errors/src/lib.rs | 8 ++- compiler/rustc_session/src/parse.rs | 13 ++++- compiler/rustc_session/src/session.rs | 11 +++- 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index bbe6435be59f4..9b41234dcfb66 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -255,6 +255,56 @@ impl EmissionGuarantee for () { } } +/// Marker type which enables implementation of `create_note` and `emit_note` functions for +/// note-without-error struct diagnostics. +#[derive(Copy, Clone)] +pub struct Noted; + +impl<'a> DiagnosticBuilder<'a, Noted> { + /// Convenience function for internal use, clients should use one of the + /// `struct_*` methods on [`Handler`]. + pub(crate) fn new_note(handler: &'a Handler, message: impl Into) -> Self { + let diagnostic = Diagnostic::new_with_code(Level::Note, None, message); + Self::new_diagnostic_note(handler, diagnostic) + } + + /// Creates a new `DiagnosticBuilder` with an already constructed + /// diagnostic. + pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self { + debug!("Created new diagnostic"); + Self { + inner: DiagnosticBuilderInner { + state: DiagnosticBuilderState::Emittable(handler), + diagnostic: Box::new(diagnostic), + }, + _marker: PhantomData, + } + } +} + +impl EmissionGuarantee for Noted { + fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { + match db.inner.state { + // First `.emit()` call, the `&Handler` is still available. + DiagnosticBuilderState::Emittable(handler) => { + db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + handler.emit_diagnostic(&mut db.inner.diagnostic); + } + // `.emit()` was previously called, disallowed from repeating it. + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} + } + + Noted + } + + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into, + ) -> DiagnosticBuilder<'_, Self> { + DiagnosticBuilder::new_note(handler, msg) + } +} + impl<'a> DiagnosticBuilder<'a, !> { /// Convenience function for internal use, clients should use one of the /// `struct_*` methods on [`Handler`]. diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 94a493992e593..a7fe280bc20ed 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -374,7 +374,7 @@ pub use diagnostic::{ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; -pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee}; +pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted}; use std::backtrace::Backtrace; /// A handler deals with errors and other compiler output. @@ -988,7 +988,11 @@ impl Handler { } pub fn has_errors(&self) -> Option { - if self.inner.borrow().has_errors() { Some(ErrorGuaranteed(())) } else { None } + if self.inner.borrow().has_errors() { + Some(ErrorGuaranteed(())) + } else { + None + } } pub fn has_errors_or_lint_errors(&self) -> Option { if self.inner.borrow().has_errors_or_lint_errors() { diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 2c3d8d5283b57..a199947ebed05 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -12,7 +12,7 @@ use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{ fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, - EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, StashKey, + EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -354,6 +354,17 @@ impl ParseSess { self.create_warning(warning).emit() } + pub fn create_note<'a>( + &'a self, + note: impl IntoDiagnostic<'a, Noted>, + ) -> DiagnosticBuilder<'a, Noted> { + note.into_diagnostic(&self.span_diagnostic) + } + + pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted { + self.create_note(note).emit() + } + pub fn create_fatal<'a>( &'a self, fatal: impl IntoDiagnostic<'a, !>, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 5926cdc9dad9a..beb22ab3eb951 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -28,7 +28,7 @@ use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, - ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, + ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -489,6 +489,15 @@ impl Session { pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { self.parse_sess.emit_warning(warning) } + pub fn create_note<'a>( + &'a self, + note: impl IntoDiagnostic<'a, Noted>, + ) -> DiagnosticBuilder<'a, Noted> { + self.parse_sess.create_note(note) + } + pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted { + self.parse_sess.emit_note(note) + } pub fn create_fatal<'a>( &'a self, fatal: impl IntoDiagnostic<'a, !>, From 3a748330af35ec9da4b07f55b78e8f08f2af0888 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 22 Sep 2022 10:15:51 -0600 Subject: [PATCH 12/29] use cherry-picked commit from #100754 to emit note without error --- compiler/rustc_error_messages/locales/en-US/passes.ftl | 6 ++++-- compiler/rustc_passes/src/errors.rs | 5 ++++- compiler/rustc_passes/src/weak_lang_items.rs | 6 ++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 7dddc6e10b655..49cd2ee17588c 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -364,9 +364,11 @@ passes_unknown_external_lang_item = passes_missing_panic_handler = `#[panic_handler]` function required, but not found -passes_missing_alloc_error_handler = +passes_alloc_func_required = `#[alloc_error_handler]` function required, but not found - .note = use `#![feature(default_alloc_error_handler)]` for a default error handler + +passes_missing_alloc_error_handler = + use `#![feature(default_alloc_error_handler)]` for a default error handler passes_missing_lang_item = language item required, but not found: `{$name}` diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 0fabbb206cf92..26190af03587d 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -690,9 +690,12 @@ pub struct UnknownExternLangItem { #[diag(passes::missing_panic_handler)] pub struct MissingPanicHandler; +#[derive(Diagnostic)] +#[diag(passes::alloc_func_required)] +pub struct AllocFuncRequired; + #[derive(Diagnostic)] #[diag(passes::missing_alloc_error_handler)] -#[note] pub struct MissingAllocErrorHandler; #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 0d2745fb5f40f..92024989a75e2 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -8,7 +8,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; use crate::errors::{ - MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler, UnknownExternLangItem, + AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler, + UnknownExternLangItem, }; /// Checks the crate for usage of weak lang items, returning a vector of all the @@ -70,7 +71,8 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { tcx.sess.emit_err(MissingPanicHandler); } else if item == LangItem::Oom { if !tcx.features().default_alloc_error_handler { - tcx.sess.emit_err(MissingAllocErrorHandler); + tcx.sess.emit_err(AllocFuncRequired); + tcx.sess.emit_note(MissingAllocErrorHandler); } } else { tcx.sess.emit_err(MissingLangItem { name: *name }); From 0609c0f1da13c8b0aeb90b5ff66f527bb16d58bf Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 22 Sep 2022 18:23:05 -0600 Subject: [PATCH 13/29] migrate diagnostic_items.rs to translateable diagnostics --- .../locales/en-US/passes.ftl | 12 ++++++- compiler/rustc_passes/src/diagnostic_items.rs | 36 +++++++++---------- compiler/rustc_passes/src/errors.rs | 20 +++++++++++ 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 49cd2ee17588c..04fd0a3a6ac22 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -357,7 +357,7 @@ passes_collapse_debuginfo = passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect .suggestion = remove the unnecessary deprecation attribute - + passes_unknown_external_lang_item = unknown external lang item: `{$lang_item}` @@ -389,3 +389,13 @@ passes_local_duplicate_lang_item = passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute + +passes_duplicate_diagnostic_item = + duplicate diagnostic item found: `{$name}`. + +passes_duplicate_diagnostic_item_in_crate = + duplicate diagnostic item in crate `{$crate_name}`: `{$name}`. + +passes_diagnostic_item_first_defined = + the diagnostic item is first defined here + .note = the diagnostic item is first defined in crate `{$orig_crate_name}`. diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index e428d9293db17..c411a24716598 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -16,6 +16,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; +use crate::errors::{DuplicateDiagnosticItem, DuplicateDiagnosticItemInCrate}; + fn observe_item<'tcx>( tcx: TyCtxt<'tcx>, diagnostic_items: &mut DiagnosticItems, @@ -33,25 +35,23 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item items.id_to_name.insert(item_def_id, name); if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) { if original_def_id != item_def_id { - let mut err = match tcx.hir().span_if_local(item_def_id) { - Some(span) => tcx - .sess - .struct_span_err(span, &format!("duplicate diagnostic item found: `{name}`.")), - None => tcx.sess.struct_err(&format!( - "duplicate diagnostic item in crate `{}`: `{}`.", - tcx.crate_name(item_def_id.krate), - name - )), - }; - if let Some(span) = tcx.hir().span_if_local(original_def_id) { - err.span_note(span, "the diagnostic item is first defined here"); + let orig_span = tcx.hir().span_if_local(original_def_id); + let orig_crate_name = if orig_span.is_some() { + None } else { - err.note(&format!( - "the diagnostic item is first defined in crate `{}`.", - tcx.crate_name(original_def_id.krate) - )); - } - err.emit(); + Some(tcx.crate_name(original_def_id.krate)) + }; + match tcx.hir().span_if_local(item_def_id) { + Some(span) => tcx.sess.emit_err(DuplicateDiagnosticItem { span, name }), + None => tcx.sess.emit_err(DuplicateDiagnosticItemInCrate { + span: orig_span, + // FIXME: We should not provide `name` to `orig_crate_name`. How do you create a blank/empty symbol? + orig_crate_name: orig_crate_name.unwrap_or(name), + have_orig_crate_name: orig_crate_name.map(|_| ()), + crate_name: tcx.crate_name(item_def_id.krate), + name, + }), + }; } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 26190af03587d..a94cac8c79542 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -755,3 +755,23 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { diag } } + +#[derive(Diagnostic)] +#[diag(passes::duplicate_diagnostic_item)] +pub struct DuplicateDiagnosticItem { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes::duplicate_diagnostic_item_in_crate)] +pub struct DuplicateDiagnosticItemInCrate { + #[note(passes::diagnostic_item_first_defined)] + pub span: Option, + pub orig_crate_name: Symbol, + #[note] + pub have_orig_crate_name: Option<()>, + pub crate_name: Symbol, + pub name: Symbol, +} From 40d5f00e16230ce67c018bb05b8772f02634146c Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Fri, 23 Sep 2022 12:23:18 -0600 Subject: [PATCH 14/29] migrate layout_test.rs to translateable diagnostics --- .../locales/en-US/passes.ftl | 21 ++++++ compiler/rustc_passes/src/errors.rs | 57 +++++++++++++++ compiler/rustc_passes/src/layout_test.rs | 70 ++++++++++--------- 3 files changed, 115 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 04fd0a3a6ac22..9493d95be5dc0 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -399,3 +399,24 @@ passes_duplicate_diagnostic_item_in_crate = passes_diagnostic_item_first_defined = the diagnostic item is first defined here .note = the diagnostic item is first defined in crate `{$orig_crate_name}`. + +passes_abi = + abi: {$abi} + +passes_align = + align: {$align} + +passes_size = + size: {$size} + +passes_homogeneous_aggregate = + homogeneous_aggregate: {$homogeneous_aggregate} + +passes_layout_of = + layout_of({$normalized_ty}) = {$ty_layout} + +passes_unrecognized_field = + unrecognized field name `{$name}` + +passes_layout = + layout error: {$layout_error} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index a94cac8c79542..e7a592d5a4748 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -775,3 +775,60 @@ pub struct DuplicateDiagnosticItemInCrate { pub crate_name: Symbol, pub name: Symbol, } + +#[derive(Diagnostic)] +#[diag(passes::abi)] +pub struct Abi { + #[primary_span] + pub span: Span, + pub abi: String, +} + +#[derive(Diagnostic)] +#[diag(passes::align)] +pub struct Align { + #[primary_span] + pub span: Span, + pub align: String, +} + +#[derive(Diagnostic)] +#[diag(passes::size)] +pub struct Size { + #[primary_span] + pub span: Span, + pub size: String, +} + +#[derive(Diagnostic)] +#[diag(passes::homogeneous_aggregate)] +pub struct HomogeneousAggregate { + #[primary_span] + pub span: Span, + pub homogeneous_aggregate: String, +} + +#[derive(Diagnostic)] +#[diag(passes::layout_of)] +pub struct LayoutOf { + #[primary_span] + pub span: Span, + pub normalized_ty: String, + pub ty_layout: String, +} + +#[derive(Diagnostic)] +#[diag(passes::unrecognized_field)] +pub struct UnrecognizedField { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes::layout)] +pub struct Layout { + #[primary_span] + pub span: Span, + pub layout_error: String, +} diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 46c4a702fde95..7af1dda1ecbdb 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -7,6 +7,8 @@ use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, TargetDataLayout}; +use crate::errors::{Abi, Align, HomogeneousAggregate, Layout, LayoutOf, Size, UnrecognizedField}; + pub fn test_layout(tcx: TyCtxt<'_>) { if tcx.features().rustc_attrs { // if the `rustc_attrs` feature is not enabled, don't bother testing layout @@ -35,62 +37,64 @@ fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attri for meta_item in meta_items { match meta_item.name_or_empty() { sym::abi => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("abi: {:?}", ty_layout.abi), - ); + tcx.sess.emit_err(Abi { + span: tcx.def_span(item_def_id.to_def_id()), + abi: format!("{:?}", ty_layout.abi), + }); } sym::align => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("align: {:?}", ty_layout.align), - ); + tcx.sess.emit_err(Align { + span: tcx.def_span(item_def_id.to_def_id()), + align: format!("{:?}", ty_layout.align), + }); } sym::size => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("size: {:?}", ty_layout.size), - ); + tcx.sess.emit_err(Size { + span: tcx.def_span(item_def_id.to_def_id()), + size: format!("{:?}", ty_layout.size), + }); } sym::homogeneous_aggregate => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!( - "homogeneous_aggregate: {:?}", - ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }), + tcx.sess.emit_err(HomogeneousAggregate { + span: tcx.def_span(item_def_id.to_def_id()), + homogeneous_aggregate: format!( + "{:?}", + ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }) ), - ); + }); } sym::debug => { - let normalized_ty = tcx.normalize_erasing_regions( - param_env.with_reveal_all_normalized(tcx), - ty, - ); - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout), + let normalized_ty = format!( + "{:?}", + tcx.normalize_erasing_regions( + param_env.with_reveal_all_normalized(tcx), + ty, + ) ); + let ty_layout = format!("{:#?}", *ty_layout); + tcx.sess.emit_err(LayoutOf { + span: tcx.def_span(item_def_id.to_def_id()), + normalized_ty, + ty_layout, + }); } name => { - tcx.sess.span_err( - meta_item.span(), - &format!("unrecognized field name `{}`", name), - ); + tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); } } } } Err(layout_error) => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("layout error: {:?}", layout_error), - ); + tcx.sess.emit_err(Layout { + span: tcx.def_span(item_def_id.to_def_id()), + layout_error: format!("{:?}", layout_error), + }); } } } From c457abee2e913ebb6f46329c15c6b43fbcb8c703 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sat, 24 Sep 2022 12:21:58 -0600 Subject: [PATCH 15/29] migrate lib_features.rs to translateable diagnostics --- .../locales/en-US/passes.ftl | 6 ++++ compiler/rustc_passes/src/errors.rs | 20 +++++++++++ compiler/rustc_passes/src/lib_features.rs | 34 ++++++++----------- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 9493d95be5dc0..b2c54aaccfe35 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -420,3 +420,9 @@ passes_unrecognized_field = passes_layout = layout error: {$layout_error} + +passes_feature_stable_twice = + feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since} + +passes_feature_previously_declared = + feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index e7a592d5a4748..7c3a575242f32 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -832,3 +832,23 @@ pub struct Layout { pub span: Span, pub layout_error: String, } + +#[derive(Diagnostic)] +#[diag(passes::feature_stable_twice, code = "E0711")] +pub struct FeatureStableTwice { + #[primary_span] + pub span: Span, + pub feature: Symbol, + pub since: Symbol, + pub prev_since: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes::feature_previously_declared, code = "E0711")] +pub struct FeaturePreviouslyDeclared<'a, 'b> { + #[primary_span] + pub span: Span, + pub feature: Symbol, + pub declared: &'a str, + pub prev_declared: &'b str, +} diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 04173c792a979..b5843c0ae488b 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -6,7 +6,6 @@ use rustc_ast::{Attribute, MetaItemKind}; use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER}; -use rustc_errors::struct_span_err; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::LibFeatures; @@ -15,6 +14,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; +use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice}; + fn new_lib_features() -> LibFeatures { LibFeatures { stable: Default::default(), unstable: Default::default() } } @@ -92,14 +93,12 @@ impl<'tcx> LibFeatureCollector<'tcx> { (Some(since), _, false) => { if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) { if *prev_since != since { - self.span_feature_error( + self.tcx.sess.emit_err(FeatureStableTwice { span, - &format!( - "feature `{}` is declared stable since {}, \ - but was previously declared stable since {}", - feature, since, prev_since, - ), - ); + feature, + since, + prev_since: *prev_since, + }); return; } } @@ -110,22 +109,17 @@ impl<'tcx> LibFeatureCollector<'tcx> { self.lib_features.unstable.insert(feature, span); } (Some(_), _, true) | (None, true, _) => { - self.span_feature_error( + let declared = if since.is_some() { "stable" } else { "unstable" }; + let prev_declared = if since.is_none() { "stable" } else { "unstable" }; + self.tcx.sess.emit_err(FeaturePreviouslyDeclared { span, - &format!( - "feature `{}` is declared {}, but was previously declared {}", - feature, - if since.is_some() { "stable" } else { "unstable" }, - if since.is_none() { "stable" } else { "unstable" }, - ), - ); + feature, + declared, + prev_declared, + }); } } } - - fn span_feature_error(&self, span: Span, msg: &str) { - struct_span_err!(self.tcx.sess, span, E0711, "{}", &msg).emit(); - } } impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> { From 572f3414b782311a8ec4143c50bbe3b006594898 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sat, 24 Sep 2022 12:49:29 -0600 Subject: [PATCH 16/29] migrate check_const.rs to translateable diagnostics --- .../locales/en-US/passes.ftl | 7 ++++ compiler/rustc_passes/src/check_const.rs | 33 ++++++++++++++++--- compiler/rustc_passes/src/errors.rs | 18 ++++++++++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index b2c54aaccfe35..550096469bb0b 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -426,3 +426,10 @@ passes_feature_stable_twice = passes_feature_previously_declared = feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared} + +passes_expr_not_allowed_in_context = + {$expr} is not allowed in a `{$context}` + +passes_const_impl_const_trait = + const `impl`s must be for traits marked with `#[const_trait]` + .note = this trait must be annotated with `#[const_trait]` diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index e502b9b54e302..0a509598ec51d 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -8,7 +8,6 @@ //! through, but errors for structured control flow in a `const` should be emitted here. use rustc_attr as attr; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; @@ -18,6 +17,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; +use crate::errors::{ConstImplConstTrait, ExprNotAllowedInContext}; + /// An expression that is not *always* legal in a const context. #[derive(Clone, Copy)] enum NonConstExpr { @@ -133,18 +134,22 @@ impl<'tcx> CheckConstVisitor<'tcx> { let const_kind = const_kind.expect("`const_check_violated` may only be called inside a const context"); - let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name()); - let required_gates = required_gates.unwrap_or(&[]); let missing_gates: Vec<_> = required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect(); match missing_gates.as_slice() { [] => { - struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(); + tcx.sess.emit_err(ExprNotAllowedInContext { + span, + expr: expr.name(), + context: const_kind.keyword_name(), + }); } [missing_primary, ref missing_secondary @ ..] => { + let msg = + format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name()); let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg); // If multiple feature gates would be required to enable this expression, include @@ -191,6 +196,26 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.tcx.hir() } + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + let tcx = self.tcx; + if let hir::ItemKind::Impl(hir::Impl { + constness: hir::Constness::Const, + of_trait: Some(trait_ref), + .. + }) = item.kind + && let Some(def_id) = trait_ref.trait_def_id() + { + let source_map = tcx.sess.source_map(); + if !tcx.has_attr(def_id, sym::const_trait) { + tcx.sess.emit_err(ConstImplConstTrait { + span: source_map.guess_head_span(item.span), + def_span: source_map.guess_head_span(tcx.def_span(def_id)), + }); + } + } + intravisit::walk_item(self, item); + } + fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) { let kind = Some(hir::ConstContext::Const); self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 7c3a575242f32..fe169c566f635 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -852,3 +852,21 @@ pub struct FeaturePreviouslyDeclared<'a, 'b> { pub declared: &'a str, pub prev_declared: &'b str, } + +#[derive(Diagnostic)] +#[diag(passes::expr_not_allowed_in_context, code = "E0744")] +pub struct ExprNotAllowedInContext<'a> { + #[primary_span] + pub span: Span, + pub expr: String, + pub context: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes::const_impl_const_trait)] +pub struct ConstImplConstTrait { + #[primary_span] + pub span: Span, + #[note] + pub def_span: Span, +} From 69766e4f167f4097e1f8975bd866c1f782fa26d5 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sun, 25 Sep 2022 22:52:19 -0600 Subject: [PATCH 17/29] migrate loops.rs to translateable diagnostics --- .../locales/en-US/passes.ftl | 34 ++++ compiler/rustc_passes/src/errors.rs | 121 ++++++++++++- compiler/rustc_passes/src/loops.rs | 161 +++++------------- 3 files changed, 198 insertions(+), 118 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 550096469bb0b..3dc4204f986a4 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -433,3 +433,37 @@ passes_expr_not_allowed_in_context = passes_const_impl_const_trait = const `impl`s must be for traits marked with `#[const_trait]` .note = this trait must be annotated with `#[const_trait]` + +passes_break_non_loop = + `break` with value from a `{$kind}` loop + .label = can only break with a value inside `loop` or breakable block + .label2 = you can't `break` with a value in a `{$kind}` loop + .suggestion = use `break` on its own without a value inside this `{$kind}` loop + .break_expr_suggestion = alternatively, you might have meant to use the available loop label + +passes_continue_labeled_block = + `continue` pointing to a labeled block + .label = labeled blocks cannot be `continue`'d + .block_label = labeled block the `continue` points to + +passes_break_inside_closure = + `{$name}` inside of a closure + .label = cannot `{$name}` inside of a closure + .closure_label = enclosing closure + +passes_break_inside_async_block = + `{$name}` inside of an `async` block + .label = cannot `{$name}` inside of an `async` block + .async_block_label = enclosing `async` block + +passes_outside_loop = + `{$name}` outside of a loop + .label = cannot `{$name}` outside of a loop + +passes_unlabeled_in_labeled_block = + unlabeled `{$cf_type}` inside of a labeled block + .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label + +passes_unlabeled_cf_in_while_condition = + `break` or `continue` with no label in the condition of a `while` loop + .label = unlabeled `{$cf_type}` in the condition of a `while` loop diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index fe169c566f635..fcbcc298bd5b7 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,7 +1,8 @@ use std::{io::Error, path::Path}; -use rustc_errors::{Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; -use rustc_hir::Target; +use rustc_ast::Label; +use rustc_errors::{error_code, Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; +use rustc_hir::{self as hir, ExprKind, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -870,3 +871,119 @@ pub struct ConstImplConstTrait { #[note] pub def_span: Span, } + +pub struct BreakNonLoop<'a> { + pub span: Span, + pub head: Option, + pub kind: &'a str, + pub suggestion: String, + pub loop_label: Option