Skip to content
Closed
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