Skip to content

Commit bc61695

Browse files
committed
macros: raw translation of subdiagnostics
Signed-off-by: David Wood <[email protected]>
1 parent 2edb5e2 commit bc61695

File tree

25 files changed

+296
-246
lines changed

25 files changed

+296
-246
lines changed

compiler/rustc_ast_lowering/src/errors.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use rustc_errors::{
2-
codes::*, AddToDiagnostic, Diagnostic, DiagnosticArgFromDisplay, SubdiagnosticMessageOp,
3-
};
1+
use rustc_errors::{codes::*, AddToDiagnostic, DiagCtxt, Diagnostic, DiagnosticArgFromDisplay};
42
use rustc_macros::{Diagnostic, Subdiagnostic};
53
use rustc_span::{symbol::Ident, Span, Symbol};
64

@@ -40,8 +38,8 @@ pub struct InvalidAbi {
4038

4139
pub struct InvalidAbiReason(pub &'static str);
4240

43-
impl AddToDiagnostic for InvalidAbiReason {
44-
fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) {
41+
impl<'a> AddToDiagnostic<'a> for InvalidAbiReason {
42+
fn add_to_diagnostic(self, _: &'a DiagCtxt, diag: &mut Diagnostic) {
4543
#[allow(rustc::untranslatable_diagnostic)]
4644
diag.note(self.0);
4745
}

compiler/rustc_ast_passes/src/errors.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Errors emitted by ast_passes.
22
33
use rustc_ast::ParamKindOrd;
4-
use rustc_errors::{codes::*, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessageOp};
4+
use rustc_errors::{codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic};
55
use rustc_macros::{Diagnostic, Subdiagnostic};
66
use rustc_span::{symbol::Ident, Span, Symbol};
77

@@ -371,8 +371,8 @@ pub struct ArgsBeforeConstraint {
371371
pub struct EmptyLabelManySpans(pub Vec<Span>);
372372

373373
// The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each
374-
impl AddToDiagnostic for EmptyLabelManySpans {
375-
fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) {
374+
impl<'a> AddToDiagnostic<'a> for EmptyLabelManySpans {
375+
fn add_to_diagnostic(self, _: &'a DiagCtxt, diag: &mut Diagnostic) {
376376
diag.span_labels(self.0, "");
377377
}
378378
}
@@ -728,8 +728,8 @@ pub struct StableFeature {
728728
pub since: Symbol,
729729
}
730730

731-
impl AddToDiagnostic for StableFeature {
732-
fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) {
731+
impl<'a> AddToDiagnostic<'a> for StableFeature {
732+
fn add_to_diagnostic(self, _: &'a DiagCtxt, diag: &mut Diagnostic) {
733733
diag.arg("name", self.name);
734734
diag.arg("since", self.since);
735735
diag.help(fluent::ast_passes_stable_since);

compiler/rustc_builtin_macros/src/errors.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_errors::{
22
codes::*, AddToDiagnostic, DiagCtxt, Diagnostic, DiagnosticBuilder, EmissionGuarantee,
3-
IntoDiagnostic, Level, MultiSpan, SingleLabelManySpans, SubdiagnosticMessageOp,
3+
IntoDiagnostic, Level, MultiSpan, SingleLabelManySpans,
44
};
55
use rustc_macros::{Diagnostic, Subdiagnostic};
66
use rustc_span::{symbol::Ident, Span, Symbol};
@@ -610,11 +610,14 @@ pub(crate) struct FormatUnusedArg {
610610

611611
// Allow the singular form to be a subdiagnostic of the multiple-unused
612612
// form of diagnostic.
613-
impl AddToDiagnostic for FormatUnusedArg {
614-
fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F) {
613+
impl<'a> AddToDiagnostic<'a> for FormatUnusedArg {
614+
fn add_to_diagnostic(self, dcx: &'a DiagCtxt, diag: &mut Diagnostic) {
615615
diag.arg("named", self.named);
616-
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
617-
diag.span_label(self.span, msg);
616+
let message = dcx.eagerly_translate(
617+
crate::fluent_generated::builtin_macros_format_unused_arg,
618+
diag.args(),
619+
);
620+
diag.span_label(self.span, message);
618621
}
619622
}
620623

compiler/rustc_errors/src/diagnostic.rs

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::snippet::Style;
22
use crate::{
3-
CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, ErrCode, Level,
4-
MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
3+
CodeSuggestion, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, ErrCode,
4+
Level, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
55
};
66
use rustc_data_structures::fx::FxIndexMap;
77
use rustc_error_messages::fluent_value_from_str_list_sep_by_and;
@@ -66,18 +66,12 @@ impl Into<FluentValue<'static>> for DiagnosticArgValue {
6666
/// Trait implemented by error types. This should not be implemented manually. Instead, use
6767
/// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
6868
#[rustc_diagnostic_item = "AddToDiagnostic"]
69-
pub trait AddToDiagnostic
69+
pub trait AddToDiagnostic<'a>
7070
where
7171
Self: Sized,
7272
{
7373
/// Add a subdiagnostic to an existing diagnostic.
74-
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
75-
self.add_to_diagnostic_with(diag, |_, m| m);
76-
}
77-
78-
/// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
79-
/// (to optionally perform eager translation).
80-
fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F);
74+
fn add_to_diagnostic(self, dcx: &'a DiagCtxt, diag: &mut Diagnostic);
8175
}
8276

8377
pub trait SubdiagnosticMessageOp =
@@ -855,16 +849,12 @@ impl Diagnostic {
855849
/// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
856850
/// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
857851
/// interpolated variables).
858-
pub fn subdiagnostic(
852+
pub fn subdiagnostic<'a>(
859853
&mut self,
860-
dcx: &crate::DiagCtxt,
861-
subdiagnostic: impl AddToDiagnostic,
854+
dcx: &'a crate::DiagCtxt,
855+
subdiagnostic: impl AddToDiagnostic<'a>,
862856
) -> &mut Self {
863-
subdiagnostic.add_to_diagnostic_with(self, |diag, msg| {
864-
let args = diag.args();
865-
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
866-
dcx.eagerly_translate(msg, args)
867-
});
857+
subdiagnostic.add_to_diagnostic(dcx, self);
868858
self
869859
}
870860

@@ -911,7 +901,7 @@ impl Diagnostic {
911901
/// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
912902
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
913903
/// passes the user's string along).
914-
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
904+
pub fn subdiagnostic_message_to_diagnostic_message(
915905
&self,
916906
attr: impl Into<SubdiagnosticMessage>,
917907
) -> DiagnosticMessage {

compiler/rustc_errors/src/diagnostic_builder.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,25 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
403403
forward!((arg, with_arg)(
404404
name: impl Into<Cow<'static, str>>, arg: impl IntoDiagnosticArg,
405405
));
406-
forward!((subdiagnostic, with_subdiagnostic)(
407-
dcx: &DiagCtxt,
408-
subdiagnostic: impl crate::AddToDiagnostic,
409-
));
406+
407+
/// See [`Diagnostic::subdiagnostic()`].
408+
pub fn subdiagnostic(
409+
&mut self,
410+
dcx: &'a DiagCtxt,
411+
subdiagnostic: impl crate::AddToDiagnostic<'a>,
412+
) -> &mut Self {
413+
self.diag.as_mut().unwrap().subdiagnostic(dcx, subdiagnostic);
414+
self
415+
}
416+
/// See [`Diagnostic::subdiagnostic()`].
417+
pub fn with_subdiagnostic(
418+
mut self,
419+
dcx: &'a DiagCtxt,
420+
subdiagnostic: impl crate::AddToDiagnostic<'a>,
421+
) -> Self {
422+
self.diag.as_mut().unwrap().subdiagnostic(dcx, subdiagnostic);
423+
self
424+
}
410425
}
411426

412427
impl<G: EmissionGuarantee> Debug for DiagnosticBuilder<'_, G> {

compiler/rustc_errors/src/diagnostic_impls.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::diagnostic::DiagnosticLocation;
22
use crate::{fluent_generated as fluent, AddToDiagnostic};
33
use crate::{
44
DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, ErrCode, IntoDiagnostic,
5-
IntoDiagnosticArg, Level, SubdiagnosticMessageOp,
5+
IntoDiagnosticArg, Level,
66
};
77
use rustc_ast as ast;
88
use rustc_ast_pretty::pprust;
@@ -298,8 +298,8 @@ pub struct SingleLabelManySpans {
298298
pub spans: Vec<Span>,
299299
pub label: &'static str,
300300
}
301-
impl AddToDiagnostic for SingleLabelManySpans {
302-
fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut crate::Diagnostic, _: F) {
301+
impl<'a> AddToDiagnostic<'a> for SingleLabelManySpans {
302+
fn add_to_diagnostic(self, _: &'a DiagCtxt, diag: &mut crate::Diagnostic) {
303303
diag.span_labels(self.spans, self.label);
304304
}
305305
}

compiler/rustc_errors/src/lib.rs

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,26 +1532,46 @@ impl DiagCtxtInner {
15321532
self.emit_diagnostic(Diagnostic::new(Note, note2));
15331533
}
15341534

1535-
let mut bug =
1536-
if backtrace || self.ice_file.is_none() { bug.decorate(self) } else { bug.inner };
1537-
1538-
// "Undelay" the delayed bugs (into plain `Bug`s).
1539-
if bug.level != DelayedBug {
1540-
// NOTE(eddyb) not panicking here because we're already producing
1541-
// an ICE, and the more information the merrier.
1542-
let subdiag = InvalidFlushedDelayedDiagnosticLevel {
1543-
span: bug.span.primary_span().unwrap(),
1544-
level: bug.level,
1545-
};
1546-
// FIXME: Cannot use `Diagnostic::subdiagnostic` which takes `DiagCtxt`, but it
1547-
// just uses `DiagCtxtInner` functions.
1548-
subdiag.add_to_diagnostic_with(&mut bug, |diag, msg| {
1549-
let args = diag.args();
1550-
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1551-
self.eagerly_translate(msg, args)
1552-
});
1553-
}
1554-
bug.level = Bug;
1535+
// This is a bit gnarly, but the `AddToDiagnostic` type uses a `DiagCtxt` to trigger
1536+
// translation. It could take an emitter or a `DiagCtxtInner` but it would make
1537+
// every other use of `AddToDiagnostic` more complex. This function is only invoked
1538+
// during the `Drop` of `DiagCtxtInner`, so we temporarily get a `T` from the `&mut T`
1539+
// here so we can put this back into a lock and back into a `DiagCtxt` to call the
1540+
// functions from `AddToDiagnostic`.
1541+
//
1542+
// FIXME(davidtwco): `AddToDiagnostic` should eventually be merged with
1543+
// `IntoDiagnostic`, and then the context determined by an associated type, depending
1544+
// on the needs of the specific diagnostic - once this is done, we can make these
1545+
// specific diagnostics take an emitter directly.
1546+
let bug = unsafe {
1547+
let old_dcx = std::ptr::read(self);
1548+
let (new_dcx, bug) = std::panic::catch_unwind(panic::AssertUnwindSafe(|| {
1549+
let dcx = DiagCtxt { inner: Lock::new(old_dcx) };
1550+
1551+
let mut bug = if backtrace || self.ice_file.is_none() {
1552+
bug.decorate(&dcx)
1553+
} else {
1554+
bug.inner
1555+
};
1556+
1557+
// "Undelay" the delayed bugs (into plain `Bug`s).
1558+
if bug.level != DelayedBug {
1559+
// NOTE(eddyb) not panicking here because we're already producing
1560+
// an ICE, and the more information the merrier.
1561+
let subdiag = InvalidFlushedDelayedDiagnosticLevel {
1562+
span: bug.span.primary_span().unwrap(),
1563+
level: bug.level,
1564+
};
1565+
subdiag.add_to_diagnostic(&dcx, &mut bug);
1566+
}
1567+
bug.level = Bug;
1568+
1569+
(dcx.inner.into_inner(), bug)
1570+
}))
1571+
.unwrap_or_else(|_| std::process::abort());
1572+
std::ptr::write(self, new_dcx);
1573+
bug
1574+
};
15551575

15561576
self.emit_diagnostic(bug);
15571577
}
@@ -1583,15 +1603,7 @@ impl DelayedDiagnostic {
15831603
DelayedDiagnostic { inner: diagnostic, note: backtrace }
15841604
}
15851605

1586-
fn decorate(mut self, dcx: &DiagCtxtInner) -> Diagnostic {
1587-
// FIXME: Cannot use `Diagnostic::subdiagnostic` which takes `DiagCtxt`, but it
1588-
// just uses `DiagCtxtInner` functions.
1589-
let subdiag_with = |diag: &mut Diagnostic, msg| {
1590-
let args = diag.args();
1591-
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
1592-
dcx.eagerly_translate(msg, args)
1593-
};
1594-
1606+
fn decorate(mut self, dcx: &DiagCtxt) -> Diagnostic {
15951607
match self.note.status() {
15961608
BacktraceStatus::Captured => {
15971609
let inner = &self.inner;
@@ -1600,7 +1612,7 @@ impl DelayedDiagnostic {
16001612
emitted_at: inner.emitted_at.clone(),
16011613
note: self.note,
16021614
};
1603-
subdiag.add_to_diagnostic_with(&mut self.inner, subdiag_with);
1615+
subdiag.add_to_diagnostic(dcx, &mut self.inner);
16041616
}
16051617
// Avoid the needless newline when no backtrace has been captured,
16061618
// the display impl should just be a single line.
@@ -1611,7 +1623,7 @@ impl DelayedDiagnostic {
16111623
emitted_at: inner.emitted_at.clone(),
16121624
note: self.note,
16131625
};
1614-
subdiag.add_to_diagnostic_with(&mut self.inner, subdiag_with);
1626+
subdiag.add_to_diagnostic(dcx, &mut self.inner);
16151627
}
16161628
}
16171629

compiler/rustc_hir_typeck/src/errors.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::borrow::Cow;
33

44
use crate::fluent_generated as fluent;
55
use rustc_errors::{
6-
codes::*, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg,
7-
MultiSpan, SubdiagnosticMessageOp,
6+
codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticArgValue,
7+
IntoDiagnosticArg, MultiSpan,
88
};
99
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
1010
use rustc_middle::ty::Ty;
@@ -194,8 +194,8 @@ pub struct TypeMismatchFruTypo {
194194
pub expr: Option<String>,
195195
}
196196

197-
impl AddToDiagnostic for TypeMismatchFruTypo {
198-
fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) {
197+
impl<'a> AddToDiagnostic<'a> for TypeMismatchFruTypo {
198+
fn add_to_diagnostic(self, _: &'a DiagCtxt, diag: &mut Diagnostic) {
199199
diag.arg("expr", self.expr.as_deref().unwrap_or("NONE"));
200200

201201
// Only explain that `a ..b` is a range if it's split up
@@ -369,8 +369,8 @@ pub struct RemoveSemiForCoerce {
369369
pub semi: Span,
370370
}
371371

372-
impl AddToDiagnostic for RemoveSemiForCoerce {
373-
fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) {
372+
impl<'a> AddToDiagnostic<'a> for RemoveSemiForCoerce {
373+
fn add_to_diagnostic(self, _: &'a DiagCtxt, diag: &mut Diagnostic) {
374374
let mut multispan: MultiSpan = self.semi.into();
375375
multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr);
376376
multispan.push_span_label(self.ret, fluent::hir_typeck_remove_semi_for_coerce_ret);
@@ -541,18 +541,15 @@ pub enum CastUnknownPointerSub {
541541
From(Span),
542542
}
543543

544-
impl AddToDiagnostic for CastUnknownPointerSub {
545-
fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F) {
544+
impl<'a> AddToDiagnostic<'a> for CastUnknownPointerSub {
545+
fn add_to_diagnostic(self, _: &'a DiagCtxt, diag: &mut Diagnostic) {
546546
match self {
547547
CastUnknownPointerSub::To(span) => {
548-
let msg = f(diag, crate::fluent_generated::hir_typeck_label_to);
549-
diag.span_label(span, msg);
550-
let msg = f(diag, crate::fluent_generated::hir_typeck_note);
551-
diag.note(msg);
548+
diag.span_label(span, crate::fluent_generated::hir_typeck_label_to);
549+
diag.note(crate::fluent_generated::hir_typeck_note);
552550
}
553551
CastUnknownPointerSub::From(span) => {
554-
let msg = f(diag, crate::fluent_generated::hir_typeck_label_from);
555-
diag.span_label(span, msg);
552+
diag.span_label(span, crate::fluent_generated::hir_typeck_label_from);
556553
}
557554
}
558555
}

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2626
use rustc_data_structures::stack::ensure_sufficient_stack;
2727
use rustc_data_structures::unord::UnordMap;
2828
use rustc_errors::{
29-
codes::*, pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic,
30-
DiagnosticBuilder, ErrorGuaranteed, StashKey,
29+
codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder,
30+
ErrorGuaranteed, StashKey,
3131
};
3232
use rustc_hir as hir;
3333
use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -2611,7 +2611,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26112611
// We know by construction that `<expr>.await` is either on Rust 2015
26122612
// or results in `ExprKind::Await`. Suggest switching the edition to 2018.
26132613
err.note("to `.await` a `Future`, switch to Rust 2018 or later");
2614-
HelpUseLatestEdition::new().add_to_diagnostic(&mut err);
2614+
err.subdiagnostic(self.dcx(), HelpUseLatestEdition::new());
26152615
}
26162616

26172617
err.emit()

0 commit comments

Comments
 (0)