diff --git a/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl b/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl new file mode 100644 index 0000000000000..004e0ab189694 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl @@ -0,0 +1,26 @@ +trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries} + +trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated} + +trait_selection_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}` + .label = deref recursion limit reached + .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) + +trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]` + .label = empty on-clause here + +trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]` + .label = invalid on-clause here + +trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value + .label = expected value here + .note = eg `#[rustc_on_unimplemented(message="foo")]` + +trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc -> + [none] {""} + *[default] {" "}for type `{$self_desc}` + }: + .negative_implementation_here = negative implementation here + .negative_implementation_in_crate = negative implementation in crate `{$negative_impl_cname}` + .positive_implementation_here = positive implementation here + .positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}` diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 8f47be25db917..5fe107fbc530a 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -51,6 +51,7 @@ fluent_messages! { plugin_impl => "../locales/en-US/plugin_impl.ftl", privacy => "../locales/en-US/privacy.ftl", query_system => "../locales/en-US/query_system.ftl", + trait_selection => "../locales/en-US/trait_selection.ftl", save_analysis => "../locales/en-US/save_analysis.ftl", ty_utils => "../locales/en-US/ty_utils.ftl", typeck => "../locales/en-US/typeck.ftl", diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index cb0137d2e5e09..3840e79cebd84 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -20,6 +20,12 @@ pub struct Unevaluated<'tcx, P = Option> { pub promoted: P, } +impl rustc_errors::IntoDiagnosticArg for Unevaluated<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + format!("{:?}", self).into_diagnostic_arg() + } +} + impl<'tcx> Unevaluated<'tcx> { #[inline] pub fn shrink(self) -> Unevaluated<'tcx, ()> { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 80354a3f8a226..9fb91b5fe8700 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -849,6 +849,12 @@ impl<'tcx> PolyTraitRef<'tcx> { } } +impl rustc_errors::IntoDiagnosticArg for PolyTraitRef<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + /// An existential reference to a trait, where `Self` is erased. /// For example, the trait object `Trait<'a, 'b, X, Y>` is: /// ```ignore (illustrative) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ec5e5170d3594..a49af23be2316 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -110,6 +110,12 @@ impl Mul for Limit { } } +impl rustc_errors::IntoDiagnosticArg for Limit { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + #[derive(Clone, Copy, Debug, HashStable_Generic)] pub struct Limits { /// The maximum recursion limit for potentially infinitely recursive diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 8b7e8984a8adb..36ab8f3bd8845 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -1,6 +1,6 @@ +use crate::errors::AutoDerefReachedRecursionLimit; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{self, TraitEngine}; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt}; @@ -222,19 +222,10 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa Limit(0) => Limit(2), limit => limit * 2, }; - struct_span_err!( - tcx.sess, + tcx.sess.emit_err(AutoDerefReachedRecursionLimit { span, - E0055, - "reached the recursion limit while auto-dereferencing `{:?}`", - ty - ) - .span_label(span, "deref recursion limit reached") - .help(&format!( - "consider increasing the recursion limit by adding a \ - `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", + ty, suggested_limit, - tcx.crate_name(LOCAL_CRATE), - )) - .emit(); + crate_name: tcx.crate_name(LOCAL_CRATE), + }); } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs new file mode 100644 index 0000000000000..81977f25ca21f --- /dev/null +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -0,0 +1,102 @@ +use rustc_errors::{fluent, ErrorGuaranteed}; +use rustc_macros::SessionDiagnostic; +use rustc_middle::ty::{PolyTraitRef, Ty, Unevaluated}; +use rustc_session::{parse::ParseSess, Limit, SessionDiagnostic}; +use rustc_span::{Span, Symbol}; + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::dump_vtable_entries)] +pub struct DumpVTableEntries<'a> { + #[primary_span] + pub span: Span, + pub trait_ref: PolyTraitRef<'a>, + pub entries: String, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::unable_to_construct_constant_value)] +pub struct UnableToConstructConstantValue<'a> { + #[primary_span] + pub span: Span, + pub unevaluated: Unevaluated<'a>, +} + +#[derive(SessionDiagnostic)] +#[help] +#[diag(trait_selection::auto_deref_reached_recursion_limit, code = "E0055")] +pub struct AutoDerefReachedRecursionLimit<'a> { + #[primary_span] + #[label] + pub span: Span, + pub ty: Ty<'a>, + pub suggested_limit: Limit, + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::empty_on_clause_in_rustc_on_unimplemented, code = "E0232")] +pub struct EmptyOnClauseInOnUnimplemented { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")] +pub struct InvalidOnClauseInOnUnimplemented { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::no_value_in_rustc_on_unimplemented, code = "E0232")] +#[note] +pub struct NoValueInOnUnimplemented { + #[primary_span] + #[label] + pub span: Span, +} + +pub struct NegativePositiveConflict<'a> { + pub impl_span: Span, + pub trait_desc: &'a str, + pub self_desc: &'a Option, + pub negative_impl_span: Result, + pub positive_impl_span: Result, +} + +impl SessionDiagnostic<'_> for NegativePositiveConflict<'_> { + fn into_diagnostic( + self, + sess: &ParseSess, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.struct_err(fluent::trait_selection::negative_positive_conflict); + diag.set_arg("trait_desc", self.trait_desc); + diag.set_arg( + "self_desc", + self.self_desc.clone().map_or_else(|| String::from("none"), |ty| ty), + ); + diag.set_span(self.impl_span); + diag.code(rustc_errors::error_code!(E0751)); + match self.negative_impl_span { + Ok(span) => { + diag.span_label(span, fluent::trait_selection::negative_implementation_here); + } + Err(cname) => { + diag.note(fluent::trait_selection::negative_implementation_in_crate); + diag.set_arg("negative_impl_cname", cname.to_string()); + } + } + match self.positive_impl_span { + Ok(span) => { + diag.span_label(span, fluent::trait_selection::positive_implementation_here); + } + Err(cname) => { + diag.note(fluent::trait_selection::positive_implementation_in_crate); + diag.set_arg("positive_impl_cname", cname.to_string()); + } + } + diag + } +} diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 77cc2c164c34c..f039b1fca1817 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -37,5 +37,6 @@ extern crate rustc_middle; extern crate smallvec; pub mod autoderef; +pub mod errors; pub mod infer; pub mod traits; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 4bab99355012e..1223c7ced7abc 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -3,6 +3,7 @@ use super::*; +use crate::errors::UnableToConstructConstantValue; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::InferCtxt; use crate::traits::project::ProjectAndUnifyResult; @@ -830,8 +831,11 @@ impl<'tcx> AutoTraitFinder<'tcx> { Ok(None) => { let tcx = self.tcx; let def_id = unevaluated.def.did; - let reported = tcx.sess.struct_span_err(tcx.def_span(def_id), &format!("unable to construct a constant value for the unevaluated constant {:?}", unevaluated)).emit(); - + let reported = + tcx.sess.emit_err(UnableToConstructConstantValue { + span: tcx.def_span(def_id), + unevaluated, + }); Err(ErrorHandled::Reported(reported)) } Err(err) => Err(err), diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index e11ea7751aa73..14e078096783e 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -23,6 +23,7 @@ mod structural_match; mod util; pub mod wf; +use crate::errors::DumpVTableEntries; use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::traits::error_reporting::InferCtxtExt as _; @@ -763,8 +764,11 @@ fn dump_vtable_entries<'tcx>( trait_ref: ty::PolyTraitRef<'tcx>, entries: &[VtblEntry<'tcx>], ) { - let msg = format!("vtable entries for `{}`: {:#?}", trait_ref, entries); - tcx.sess.struct_span_err(sp, &msg).emit(); + tcx.sess.emit_err(DumpVTableEntries { + span: sp, + trait_ref, + entries: format!("{:#?}", entries), + }); } fn own_existential_vtable_entries<'tcx>( diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index 9227bbf011dbf..3d8840e9e7421 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -8,6 +8,10 @@ use rustc_parse_format::{ParseMode, Parser, Piece, Position}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use crate::errors::{ + EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, +}; + #[derive(Clone, Debug)] pub struct OnUnimplementedFormatString(Symbol); @@ -35,21 +39,6 @@ pub struct OnUnimplementedNote { pub append_const_msg: Option>, } -fn parse_error( - tcx: TyCtxt<'_>, - span: Span, - message: &str, - label: &str, - note: Option<&str>, -) -> ErrorGuaranteed { - let mut diag = struct_span_err!(tcx.sess, span, E0232, "{}", message); - diag.span_label(span, label); - if let Some(note) = note { - diag.note(note); - } - diag.emit() -} - impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, @@ -70,25 +59,9 @@ impl<'tcx> OnUnimplementedDirective { } else { let cond = item_iter .next() - .ok_or_else(|| { - parse_error( - tcx, - span, - "empty `on`-clause in `#[rustc_on_unimplemented]`", - "empty on-clause here", - None, - ) - })? + .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))? .meta_item() - .ok_or_else(|| { - parse_error( - tcx, - span, - "invalid `on`-clause in `#[rustc_on_unimplemented]`", - "invalid on-clause here", - None, - ) - })?; + .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?; attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| { if let Some(value) = cfg.value && let Err(guar) = parse_value(value) { errored = Some(guar); @@ -150,13 +123,7 @@ impl<'tcx> OnUnimplementedDirective { } // nothing found - parse_error( - tcx, - item.span(), - "this attribute must have a valid value", - "expected value here", - Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#), - ); + tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() }); } if let Some(reported) = errored { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 0f76fef0eee22..7d299e30ae041 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -12,6 +12,7 @@ pub mod specialization_graph; use specialization_graph::GraphExt; +use crate::errors::NegativePositiveConflict; use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause}; @@ -327,35 +328,13 @@ fn report_negative_positive_conflict( positive_impl_def_id: DefId, sg: &mut specialization_graph::Graph, ) { - let impl_span = tcx.def_span(local_impl_def_id); - - let mut err = struct_span_err!( - tcx.sess, - impl_span, - E0751, - "found both positive and negative implementation of trait `{}`{}:", - overlap.trait_desc, - overlap.self_desc.clone().map_or_else(String::new, |ty| format!(" for type `{}`", ty)) - ); - - match tcx.span_of_impl(negative_impl_def_id) { - Ok(span) => { - err.span_label(span, "negative implementation here"); - } - Err(cname) => { - err.note(&format!("negative implementation in crate `{}`", cname)); - } - } - - match tcx.span_of_impl(positive_impl_def_id) { - Ok(span) => { - err.span_label(span, "positive implementation here"); - } - Err(cname) => { - err.note(&format!("positive implementation in crate `{}`", cname)); - } - } - + let mut err = tcx.sess.create_err(NegativePositiveConflict { + impl_span: tcx.def_span(local_impl_def_id), + trait_desc: &overlap.trait_desc, + self_desc: &overlap.self_desc, + negative_impl_span: tcx.span_of_impl(negative_impl_def_id), + positive_impl_span: tcx.span_of_impl(positive_impl_def_id), + }); sg.has_errored = Some(err.emit()); }