diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 7374f6d3f27d3..0badbc40d4ac8 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` @@ -265,3 +267,23 @@ passes_rustc_lint_opt_deny_field_access = `#[rustc_lint_opt_deny_field_access]` passes_link_ordinal = attribute should be applied to a foreign function or static .label = not a foreign function or static + +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` + +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}` + +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 f376da29bd919..d7fa6d8dd4376 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, 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}; @@ -1842,13 +1842,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 } } @@ -2158,25 +2156,10 @@ 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, + name: *attr_to_check, + }); } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 901f56ad96d17..725042c2784b9 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,5 +1,9 @@ -use rustc_errors::{Applicability, MultiSpan}; +use std::{io::Error, path::Path}; + +use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; +use rustc_hir::Target; use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; +use rustc_session::SessionDiagnostic; use rustc_span::{Span, Symbol}; #[derive(LintDiagnostic)] @@ -526,6 +530,15 @@ pub struct DebugVisualizerInvalid { pub span: Span, } +#[derive(SessionDiagnostic)] +#[diag(passes::debug_visualizer_unreadable)] +pub struct DebugVisualizerUnreadable<'a> { + #[primary_span] + pub span: Span, + pub file: &'a Path, + pub error: Error, +} + #[derive(SessionDiagnostic)] #[diag(passes::rustc_allow_const_fn_unstable)] pub struct RustcAllowConstFnUnstable { @@ -649,3 +662,68 @@ pub struct RustcLintOptDenyFieldAccess { #[label] pub span: Span, } + +#[derive(SessionDiagnostic)] +#[diag(passes::missing_panic_handler)] +pub struct MissingPanicHandler; + +#[derive(SessionDiagnostic)] +#[diag(passes::missing_alloc_error_handler)] +#[note] +pub struct MissingAllocErrorHandler; + +#[derive(SessionDiagnostic)] +#[diag(passes::missing_lang_item)] +#[note] +#[help] +pub struct MissingLangItem { + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[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(SessionDiagnostic)] +#[diag(passes::unknown_lang_item, code = "E0522")] +pub struct UnknownLangItem { + #[primary_span] + #[label] + pub span: Span, + pub name: Symbol, +} + +pub struct InvalidAttrAtCrateLevel { + pub span: Span, + pub name: Symbol, +} + +impl SessionDiagnostic<'_> for InvalidAttrAtCrateLevel { + fn into_diagnostic( + self, + sess: &'_ rustc_session::parse::ParseSess, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.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 Ok(src) = sess.source_map().span_to_snippet(self.span) { + 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 79900a90aed63..24657372486f2 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -8,6 +8,7 @@ //! * Functions called by the compiler itself. 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}; @@ -42,34 +43,16 @@ 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, - span, - E0522, - "definition of an unknown language item: `{}`", - value - ) - .span_label(span, format!("definition of unknown language item `{}`", value)) - .emit(); + self.tcx.sess.emit_err(UnknownLangItem { span, name: value }); } } } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 7b2f83958af85..49ade14c0275c 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)] 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 }); } } }