Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More translatable diagnostics #123822

Closed
wants to merge 12 commits into from
5 changes: 5 additions & 0 deletions compiler/rustc_ast_lowering/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use rustc_errors::codes::*;
use rustc_errors::{Diag, DiagArgFromDisplay, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_session::errors::FeatureGateSubdiagnostic;
use rustc_span::symbol::Ident;
use rustc_span::{Span, Symbol};

Expand Down Expand Up @@ -386,12 +387,16 @@ pub(crate) enum BadReturnTypeNotation {
#[primary_span]
#[suggestion(code = "()", applicability = "maybe-incorrect")]
span: Span,
#[subdiagnostic]
subdiag: Option<FeatureGateSubdiagnostic>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use a more descriptive name?

},
#[diag(ast_lowering_bad_return_type_notation_output)]
Output {
#[primary_span]
#[suggestion(code = "", applicability = "maybe-incorrect")]
span: Span,
#[subdiagnostic]
subdiag: Option<FeatureGateSubdiagnostic>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use a more descriptive name?

},
#[diag(ast_lowering_bad_return_type_notation_needs_dots)]
NeedsDots {
Expand Down
38 changes: 19 additions & 19 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_macros::extension;
use rustc_middle::span_bug;
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
use rustc_session::parse::{add_feature_diagnostics, feature_err};
use rustc_session::parse::{feature_err, get_feature_diagnostics};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{DesugaringKind, Span, DUMMY_SP};
use smallvec::{smallvec, SmallVec};
Expand Down Expand Up @@ -1008,29 +1008,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
if let Some(first_char) = constraint.ident.as_str().chars().next()
&& first_char.is_ascii_lowercase()
{
let mut err = if !data.inputs.is_empty() {
self.dcx().create_err(errors::BadReturnTypeNotation::Inputs {
let subdiag = if !self.tcx.features().return_type_notation
&& self.tcx.sess.is_nightly_build()
{
Some(get_feature_diagnostics(&self.tcx.sess, sym::return_type_notation))
} else {
None
};

let err = if !data.inputs.is_empty() {
errors::BadReturnTypeNotation::Inputs {
span: data.inputs_span,
})
subdiag,
}
} else if let FnRetTy::Ty(ty) = &data.output {
self.dcx().create_err(errors::BadReturnTypeNotation::Output {
errors::BadReturnTypeNotation::Output {
span: data.inputs_span.shrink_to_hi().to(ty.span),
})
subdiag,
}
} else {
self.dcx().create_err(errors::BadReturnTypeNotation::NeedsDots {
span: data.inputs_span,
})
errors::BadReturnTypeNotation::NeedsDots { span: data.inputs_span }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No subdiagnostic for this one?

};
if !self.tcx.features().return_type_notation
&& self.tcx.sess.is_nightly_build()
{
add_feature_diagnostics(
&mut err,
&self.tcx.sess,
sym::return_type_notation,
);
}
err.emit();
self.dcx().create_err(err).emit();

GenericArgsCtor {
args: Default::default(),
constraints: &[],
Expand Down
24 changes: 12 additions & 12 deletions compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,28 +310,28 @@ fn default_body_is_unstable(
None => none_note = true,
};

let mut err = tcx.dcx().create_err(errors::MissingTraitItemUnstable {
span: impl_span,
some_note,
none_note,
missing_item_name,
feature,
reason: reason_str,
});

let inject_span = item_did
.as_local()
.and_then(|id| tcx.crate_level_attribute_injection_span(tcx.local_def_id_to_hir_id(id)));
rustc_session::parse::add_feature_diagnostics_for_issue(
&mut err,
let subdiag = rustc_session::parse::get_feature_diagnostics_for_issue(
&tcx.sess,
feature,
rustc_feature::GateIssue::Library(issue),
false,
inject_span,
);

err.emit();
tcx.dcx()
.create_err(errors::MissingTraitItemUnstable {
span: impl_span,
some_note,
none_note,
missing_item_name,
feature,
reason: reason_str,
subdiag,
})
.emit();
}

/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use rustc_errors::{
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_session::errors::FeatureGateSubdiagnostic;
use rustc_span::symbol::Ident;
use rustc_span::{Span, Symbol};

Expand Down Expand Up @@ -987,6 +988,8 @@ pub(crate) struct MissingTraitItemUnstable {
pub some_note: bool,
#[note(hir_analysis_none_note)]
pub none_note: bool,
#[subdiagnostic]
pub subdiag: FeatureGateSubdiagnostic,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use a more descriptive name?

pub missing_item_name: Symbol,
pub feature: Symbol,
pub reason: String,
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_lint/src/levels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -875,14 +875,13 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
lint.primary_message(fluent::lint_unknown_gated_lint);
lint.arg("name", lint_id.lint.name_lower());
lint.note(fluent::lint_note);
rustc_session::parse::add_feature_diagnostics_for_issue(
lint,
lint.subdiagnostic(rustc_session::parse::get_feature_diagnostics_for_issue(
&self.sess,
feature,
GateIssue::Language,
lint_from_cli,
None,
);
));
});
}

Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,10 @@ impl<'a> LintDiagnostic<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
diag.primary_message(fluent::lint_ungated_async_fn_track_caller);
diag.span_label(self.label, fluent::lint_label);
rustc_session::parse::add_feature_diagnostics(
diag,
diag.subdiagnostic(rustc_session::parse::get_feature_diagnostics(
self.session,
sym::async_fn_track_caller,
);
));
}
}

Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_session/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@ use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
use crate::config::CrateType;
use crate::parse::ParseSess;

// FIXME: factor into separate structs to avoid dynamic DiagMessage field
pub(crate) struct FeatureGateError {
pub(crate) span: MultiSpan,
pub(crate) explain: DiagMessage,
pub(crate) subdiag: FeatureGateSubdiagnostic,
}

impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for FeatureGateError {
#[track_caller]
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
Diag::new(dcx, level, self.explain).with_span(self.span).with_code(E0658)
let mut diag = Diag::new(dcx, level, self.explain).with_span(self.span).with_code(E0658);
diag.subdiagnostic(self.subdiag);
diag
}
}

Expand Down
34 changes: 14 additions & 20 deletions compiler/rustc_session/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc};
use rustc_errors::emitter::{stderr_destination, HumanEmitter, SilentEmitter};
use rustc_errors::{
fallback_fluent_bundle, ColorConfig, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage,
EmissionGuarantee, MultiSpan, StashKey,
fallback_fluent_bundle, ColorConfig, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, MultiSpan,
StashKey,
};
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
use rustc_span::edition::Edition;
Expand Down Expand Up @@ -111,9 +111,9 @@ pub fn feature_err_issue(
}
}

let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() });
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None);
err
let subdiag = get_feature_diagnostics_for_issue(sess, feature, issue, false, None);

sess.dcx().create_err(FeatureGateError { span, explain: explain.into(), subdiag })
}

/// Construct a future incompatibility diagnostic for a feature gate.
Expand Down Expand Up @@ -141,7 +141,7 @@ pub fn feature_warn_issue(
explain: &'static str,
) {
let mut err = sess.dcx().struct_span_warn(span, explain);
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None);
err.subdiagnostic(get_feature_diagnostics_for_issue(sess, feature, issue, false, None));

// Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level
let lint = UNSTABLE_SYNTAX_PRE_EXPANSION;
Expand All @@ -154,29 +154,23 @@ pub fn feature_warn_issue(
err.stash(span, StashKey::EarlySyntaxWarning);
}

/// Adds the diagnostics for a feature to an existing error.
pub fn add_feature_diagnostics<G: EmissionGuarantee>(
err: &mut Diag<'_, G>,
sess: &Session,
feature: Symbol,
) {
add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None);
/// Returns the subdiagnostics for a feature gate error.
pub fn get_feature_diagnostics(sess: &Session, feature: Symbol) -> FeatureGateSubdiagnostic {
get_feature_diagnostics_for_issue(sess, feature, GateIssue::Language, false, None)
}

/// Adds the diagnostics for a feature to an existing error.
/// Returns the subdiagnostics for a feature gate error.
///
/// This variant allows you to control whether it is a library or language feature.
/// Almost always, you want to use this for a language feature. If so, prefer
/// `add_feature_diagnostics`.
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
err: &mut Diag<'_, G>,
/// [`get_feature_diagnostics`].
pub fn get_feature_diagnostics_for_issue(
sess: &Session,
feature: Symbol,
issue: GateIssue,
feature_from_cli: bool,
inject_span: Option<Span>,
) {
) -> FeatureGateSubdiagnostic {
let issue = find_feature_issue(feature, issue).map(|n| FeatureDiagnosticForIssue { n });

// #23973: do not suggest `#![feature(...)]` if we are in beta/stable
Expand All @@ -202,7 +196,7 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
(None, None)
};

err.subdiagnostic(FeatureGateSubdiagnostic { issue, upgrade_compiler, enable_feature });
FeatureGateSubdiagnostic { issue, upgrade_compiler, enable_feature }
}

/// Info about a parsing session.
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use crate::config::{
InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents,
SwitchWithOptPath,
};
use crate::parse::{add_feature_diagnostics, ParseSess};
use crate::parse::{get_feature_diagnostics, ParseSess};
use crate::search_paths::{PathKind, SearchPath};
use crate::{errors, filesearch, lint};

Expand Down Expand Up @@ -300,13 +300,13 @@ impl Session {
}

#[track_caller]
#[allow(rustc::diagnostic_outside_of_impl)]
pub fn create_feature_err<'a>(&'a self, err: impl Diagnostic<'a>, feature: Symbol) -> Diag<'a> {
let mut err = self.dcx().create_err(err);
if err.code.is_none() {
#[allow(rustc::diagnostic_outside_of_impl)]
err.code(E0658);
}
add_feature_diagnostics(&mut err, self, feature);
err.subdiagnostic(get_feature_diagnostics(self, feature));
err
}

Expand Down