Skip to content

Commit 7d60f8d

Browse files
committed
Make unstable library feature errors translatable
Translation is in an awkward position, but this provides a similar interface for both errors and soft-unstable lints, and enables the use of `DiagSymbolList` for simplifying error message construction.
1 parent 9a80171 commit 7d60f8d

File tree

9 files changed

+107
-72
lines changed

9 files changed

+107
-72
lines changed

compiler/rustc_lint/src/context/diagnostics.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,9 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
382382
BuiltinLintDiag::MacroRuleNeverUsed(n, name) => {
383383
lints::MacroRuleNeverUsed { n: n + 1, name }.decorate_lint(diag);
384384
}
385-
BuiltinLintDiag::UnstableFeature(msg) => {
386-
lints::UnstableFeature { msg }.decorate_lint(diag);
385+
BuiltinLintDiag::SoftUnstableMacro { feature, reason } => {
386+
rustc_middle::error::SoftUnstableLibraryFeature::new(feature, reason)
387+
.decorate_lint(diag);
387388
}
388389
BuiltinLintDiag::AvoidUsingIntelSyntax => {
389390
lints::AvoidIntelSyntax.decorate_lint(diag);

compiler/rustc_lint/src/lints.rs

-10
Original file line numberDiff line numberDiff line change
@@ -2408,16 +2408,6 @@ pub(crate) struct MacroRuleNeverUsed {
24082408
pub name: Symbol,
24092409
}
24102410

2411-
pub(crate) struct UnstableFeature {
2412-
pub msg: DiagMessage,
2413-
}
2414-
2415-
impl<'a> LintDiagnostic<'a, ()> for UnstableFeature {
2416-
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
2417-
diag.primary_message(self.msg);
2418-
}
2419-
}
2420-
24212411
#[derive(LintDiagnostic)]
24222412
#[diag(lint_avoid_intel_syntax)]
24232413
pub(crate) struct AvoidIntelSyntax;

compiler/rustc_lint_defs/src/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
99
use rustc_data_structures::stable_hasher::{
1010
HashStable, StableCompare, StableHasher, ToStableHashKey,
1111
};
12-
use rustc_error_messages::{DiagMessage, MultiSpan};
12+
use rustc_error_messages::MultiSpan;
1313
use rustc_hir::def::Namespace;
1414
use rustc_hir::{HashStableContext, HirId, MissingLifetimeKind};
1515
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
@@ -720,7 +720,10 @@ pub enum BuiltinLintDiag {
720720
MacroIsPrivate(Ident),
721721
UnusedMacroDefinition(Symbol),
722722
MacroRuleNeverUsed(usize, Symbol),
723-
UnstableFeature(DiagMessage),
723+
SoftUnstableMacro {
724+
feature: Symbol,
725+
reason: Option<Symbol>,
726+
},
724727
AvoidUsingIntelSyntax,
725728
AvoidUsingAttSyntax,
726729
IncompleteInclude,

compiler/rustc_middle/messages.ftl

+9
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ middle_type_length_limit = reached the type-length limit while instantiating `{$
102102
middle_unknown_layout =
103103
the type `{$ty}` has an unknown layout
104104
105+
middle_unstable_library_feature =
106+
use of unstable library {$count ->
107+
[one] feature
108+
*[other] features
109+
} {$features}{STREQ($reason, "") ->
110+
[true] {""}
111+
*[false] : {$reason}
112+
}
113+
105114
middle_values_too_big =
106115
values of the type `{$ty}` are too big for the target architecture
107116
middle_written_to_path = the full type name has been written to '{$path}'

compiler/rustc_middle/src/error.rs

+39-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use std::fmt;
22
use std::path::PathBuf;
33

44
use rustc_errors::codes::*;
5-
use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage};
6-
use rustc_macros::{Diagnostic, Subdiagnostic};
5+
use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, DiagSymbolList};
6+
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
77
use rustc_span::{Span, Symbol};
88

99
use crate::ty::Ty;
@@ -164,3 +164,40 @@ pub struct TypeLengthLimit {
164164
pub path: PathBuf,
165165
pub type_length: usize,
166166
}
167+
168+
#[derive(Diagnostic)]
169+
#[diag(middle_unstable_library_feature, code = E0658)]
170+
pub struct UnstableLibraryFeatureError {
171+
#[primary_span]
172+
pub span: Span,
173+
pub features: DiagSymbolList,
174+
pub count: usize,
175+
pub reason: String,
176+
}
177+
178+
impl UnstableLibraryFeatureError {
179+
pub fn new(feature: Symbol, reason: Option<Symbol>, span: Span) -> Self {
180+
let SoftUnstableLibraryFeature { features, count, reason } =
181+
SoftUnstableLibraryFeature::new(feature, reason);
182+
UnstableLibraryFeatureError { span, features, count, reason }
183+
}
184+
}
185+
186+
/// Lint diagnostic for soft_unstable
187+
#[derive(LintDiagnostic)]
188+
#[diag(middle_unstable_library_feature)]
189+
pub struct SoftUnstableLibraryFeature {
190+
pub features: DiagSymbolList,
191+
pub count: usize,
192+
pub reason: String,
193+
}
194+
195+
impl SoftUnstableLibraryFeature {
196+
pub fn new(feature: Symbol, reason: Option<Symbol>) -> Self {
197+
SoftUnstableLibraryFeature {
198+
features: vec![feature].into(),
199+
count: 1,
200+
reason: reason.map_or(String::new(), |r| r.to_string()),
201+
}
202+
}
203+
}

compiler/rustc_middle/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#![feature(if_let_guard)]
4949
#![feature(intra_doc_pointers)]
5050
#![feature(iter_from_coroutine)]
51+
#![feature(iter_intersperse)]
5152
#![feature(let_chains)]
5253
#![feature(macro_metavar_expr)]
5354
#![feature(min_specialization)]

compiler/rustc_middle/src/middle/stability.rs

+28-32
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
1818
use rustc_session::Session;
1919
use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
2020
use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint, LintBuffer};
21-
use rustc_session::parse::feature_err_issues;
21+
use rustc_session::parse::add_feature_diagnostics_for_issues;
2222
use rustc_span::Span;
2323
use rustc_span::symbol::{Symbol, sym};
2424
use tracing::debug;
2525

2626
pub use self::StabilityLevel::*;
27+
use crate::error::{SoftUnstableLibraryFeature, UnstableLibraryFeatureError};
2728
use crate::ty::{self, TyCtxt};
2829

2930
#[derive(PartialEq, Clone, Copy, Debug)]
@@ -107,25 +108,23 @@ pub fn report_unstable(
107108
reason: Option<Symbol>,
108109
issue: Option<NonZero<u32>>,
109110
suggestion: Option<(Span, String, String, Applicability)>,
110-
is_soft: bool,
111111
span: Span,
112-
soft_handler: impl FnOnce(&'static Lint, Span, String),
113112
) {
114-
let msg = match reason {
115-
Some(r) => format!("use of unstable library feature `{feature}`: {r}"),
116-
None => format!("use of unstable library feature `{feature}`"),
117-
};
118-
119-
if is_soft {
120-
soft_handler(SOFT_UNSTABLE, span, msg)
121-
} else {
122-
let issues = Vec::from_iter(issue);
123-
let mut err = feature_err_issues(sess, &[feature], span, GateIssues::Library(issues), msg);
124-
if let Some((inner_types, msg, sugg, applicability)) = suggestion {
125-
err.span_suggestion(inner_types, msg, sugg, applicability);
126-
}
127-
err.emit();
113+
let features = vec![feature];
114+
115+
let mut err = sess.dcx().create_err(UnstableLibraryFeatureError::new(feature, reason, span));
116+
add_feature_diagnostics_for_issues(
117+
&mut err,
118+
sess,
119+
&features,
120+
GateIssues::Library(Vec::from_iter(issue)),
121+
false,
122+
None,
123+
);
124+
if let Some((inner_types, msg, sugg, applicability)) = suggestion {
125+
err.span_suggestion(inner_types, msg, sugg, applicability);
128126
}
127+
err.emit();
129128
}
130129

131130
fn deprecation_lint(is_in_effect: bool) -> &'static Lint {
@@ -592,26 +591,23 @@ impl<'tcx> TyCtxt<'tcx> {
592591
allow_unstable: AllowUnstable,
593592
unmarked: impl FnOnce(Span, DefId),
594593
) -> bool {
595-
let soft_handler = |lint, span, msg: String| {
596-
self.node_span_lint(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| {
597-
lint.primary_message(msg);
598-
})
599-
};
600594
let eval_result =
601595
self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable);
602596
let is_allowed = matches!(eval_result, EvalResult::Allow);
603597
match eval_result {
604598
EvalResult::Allow => {}
605-
EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => report_unstable(
606-
self.sess,
607-
feature,
608-
reason,
609-
issue,
610-
suggestion,
611-
is_soft,
612-
span,
613-
soft_handler,
614-
),
599+
EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => {
600+
if is_soft {
601+
self.emit_node_span_lint(
602+
SOFT_UNSTABLE,
603+
id.unwrap_or(hir::CRATE_HIR_ID),
604+
span,
605+
SoftUnstableLibraryFeature::new(feature, reason),
606+
);
607+
} else {
608+
report_unstable(self.sess, feature, reason, issue, suggestion, span);
609+
}
610+
}
615611
EvalResult::Unmarked => unmarked(span, def_id),
616612
}
617613

compiler/rustc_middle/src/ty/context.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -2965,22 +2965,22 @@ impl<'tcx> TyCtxt<'tcx> {
29652965
self,
29662966
diag: &mut Diag<'_, E>,
29672967
hir_id: Option<HirId>,
2968-
features: impl IntoIterator<Item = (String, Symbol)>,
2968+
featuresets: impl IntoIterator<Item = (String, impl std::fmt::Display)>,
29692969
) {
29702970
if !self.sess.is_nightly_build() {
29712971
return;
29722972
}
29732973

29742974
let span = hir_id.and_then(|id| self.crate_level_attribute_injection_span(id));
2975-
for (desc, feature) in features {
2975+
for (desc, features) in featuresets {
29762976
// FIXME: make this string translatable
29772977
let msg =
2978-
format!("add `#![feature({feature})]` to the crate attributes to enable{desc}");
2978+
format!("add `#![feature({features})]` to the crate attributes to enable{desc}");
29792979
if let Some(span) = span {
29802980
diag.span_suggestion_verbose(
29812981
span,
29822982
msg,
2983-
format!("#![feature({feature})]\n"),
2983+
format!("#![feature({features})]\n"),
29842984
Applicability::MaybeIncorrect,
29852985
);
29862986
} else {

compiler/rustc_resolve/src/macros.rs

+18-20
Original file line numberDiff line numberDiff line change
@@ -1009,28 +1009,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
10091009
|feature| self.tcx.features().enabled(feature) || span.allows_unstable(feature);
10101010
let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature));
10111011
if !is_allowed(feature) && !allowed_by_implication {
1012-
let lint_buffer = &mut self.lint_buffer;
1013-
let soft_handler = |lint, span, msg: String| {
1014-
lint_buffer.buffer_lint(
1015-
lint,
1012+
if is_soft {
1013+
self.lint_buffer.buffer_lint(
1014+
SOFT_UNSTABLE,
10161015
node_id,
10171016
span,
1018-
BuiltinLintDiag::UnstableFeature(
1019-
// FIXME make this translatable
1020-
msg.into(),
1021-
),
1022-
)
1023-
};
1024-
stability::report_unstable(
1025-
self.tcx.sess,
1026-
feature,
1027-
reason.to_opt_reason(),
1028-
issue,
1029-
None,
1030-
is_soft,
1031-
span,
1032-
soft_handler,
1033-
);
1017+
BuiltinLintDiag::SoftUnstableMacro {
1018+
feature,
1019+
reason: reason.to_opt_reason(),
1020+
},
1021+
);
1022+
} else {
1023+
stability::report_unstable(
1024+
self.tcx.sess,
1025+
feature,
1026+
reason.to_opt_reason(),
1027+
issue,
1028+
None,
1029+
span,
1030+
);
1031+
}
10341032
}
10351033
}
10361034
}

0 commit comments

Comments
 (0)