Skip to content

Commit de1fbaf

Browse files
committed
Simplify unstable language feature use diagnostics
Reasons provided on `#[unstable]` attributes are now per-item rather than per-feature. This is how they mostly are used anyway, and it simplifies both the implementation and the diagnostics themselves.
1 parent c4ac551 commit de1fbaf

File tree

26 files changed

+232
-190
lines changed

26 files changed

+232
-190
lines changed

compiler/rustc_attr/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ attr_multiple_item =
8585
attr_multiple_stability_levels =
8686
multiple stability levels for feature `{$feature}`
8787
88+
attr_multiple_unstable_reasons =
89+
multiple reasons provided for unstability
90+
8891
attr_non_ident_feature =
8992
'feature' is not an identifier
9093

compiler/rustc_attr/src/builtin.rs

+26-14
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,10 @@ pub struct DefaultBodyStability {
137137
pub enum StabilityLevel {
138138
/// `#[unstable]`
139139
Unstable {
140-
/// The information unique to each `#[unstable]` attribute
140+
/// The feature and optional github issue for each `#[unstable]` attribute
141141
unstables: SmallVec<[Unstability; 1]>,
142+
/// Reason for the current stability level.
143+
reason: UnstableReason,
142144
is_soft: bool,
143145
},
144146
/// `#[stable]`
@@ -159,7 +161,12 @@ pub enum ConstStabilityLevel {
159161
/// For functions declared const-stable
160162
Stable { since: StableSince },
161163
/// For functions declared const-unstable
162-
Unstable { unstables: SmallVec<[Unstability; 1]> },
164+
Unstable {
165+
/// The feature and optional github issue for each `#[rustc_const_unstable]` attribute
166+
unstables: SmallVec<[Unstability; 1]>,
167+
/// Reason for the current stability level.
168+
reason: UnstableReason,
169+
},
163170
/// For functions with no explicit const-stability attribute that require checking recursive
164171
/// const stability. This is either an unmarked const fn or a `const_stable_indirect` intrinsic.
165172
Implicit,
@@ -207,8 +214,8 @@ impl StabilityLevel {
207214

208215
fn to_const_stab_level(self) -> ConstStabilityLevel {
209216
match self {
210-
StabilityLevel::Unstable { unstables, .. } => {
211-
ConstStabilityLevel::Unstable { unstables }
217+
StabilityLevel::Unstable { unstables, reason, .. } => {
218+
ConstStabilityLevel::Unstable { unstables, reason }
212219
}
213220
StabilityLevel::Stable { since, .. } => ConstStabilityLevel::Stable { since },
214221
}
@@ -247,8 +254,6 @@ impl ConstStabilityLevel {
247254
#[derive(HashStable_Generic)]
248255
pub struct Unstability {
249256
pub feature: Symbol,
250-
/// Reason for the current stability level.
251-
pub reason: UnstableReason,
252257
/// Relevant `rust-lang/rust` issue.
253258
pub issue: Option<NonZero<u32>>,
254259
/// If part of a feature is stabilized and a new feature is added for the remaining parts,
@@ -485,10 +490,18 @@ fn add_level(
485490
(level @ None, new_level) => *level = Some(new_level),
486491
// if multiple unstable attributes have been found, merge them
487492
(
488-
Some(Unstable { unstables, is_soft }),
489-
Unstable { unstables: new_unstable, is_soft: new_soft },
493+
Some(Unstable { unstables, reason, is_soft }),
494+
Unstable { unstables: new_unstable, reason: new_reason, is_soft: new_soft },
490495
) => {
491496
unstables.extend(new_unstable);
497+
match (reason, new_reason) {
498+
(_, UnstableReason::None) => {}
499+
(reason @ UnstableReason::None, _) => *reason = new_reason,
500+
_ => {
501+
sess.dcx()
502+
.emit_err(session_diagnostics::MultipleUnstableReasons { span: attr.span });
503+
}
504+
}
492505
// Make the unstability soft if any unstable attributes are marked 'soft'; if an
493506
// unstable item is allowed in stable rust, another attribute shouldn't break that.
494507
// FIXME(dianne): should there be a check that all unstables are soft if any are?
@@ -669,13 +682,12 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
669682

670683
match (feature, issue) {
671684
(Ok(feature), Ok(_)) => {
672-
let unstability = Unstability {
673-
feature,
685+
let unstability = Unstability { feature, issue: issue_num, implied_by };
686+
Some((feature, StabilityLevel::Unstable {
687+
unstables: smallvec![unstability],
674688
reason: UnstableReason::from_opt_reason(reason),
675-
issue: issue_num,
676-
implied_by,
677-
};
678-
Some((feature, StabilityLevel::Unstable { unstables: smallvec![unstability], is_soft }))
689+
is_soft,
690+
}))
679691
}
680692
(Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
681693
}

compiler/rustc_attr/src/session_diagnostics.rs

+7
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ pub(crate) struct MultipleStabilityLevels {
8383
pub feature: Symbol,
8484
}
8585

86+
#[derive(Diagnostic)]
87+
#[diag(attr_multiple_unstable_reasons)]
88+
pub(crate) struct MultipleUnstableReasons {
89+
#[primary_span]
90+
pub span: Span,
91+
}
92+
8693
#[derive(Diagnostic)]
8794
#[diag(attr_invalid_issue_string, code = E0545)]
8895
pub(crate) struct InvalidIssueString {

compiler/rustc_const_eval/src/check_consts/check.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -773,12 +773,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
773773
}
774774
}
775775
Some(ConstStability {
776-
level: ConstStabilityLevel::Unstable { unstables },
776+
level: ConstStabilityLevel::Unstable { unstables, reason },
777777
..
778778
}) => {
779779
self.check_op(ops::IntrinsicUnstable {
780780
name: intrinsic.name,
781781
features: unstables.iter().map(|u| u.into()).collect(),
782+
reason: *reason,
782783
const_stable: is_const_stable,
783784
});
784785
}
@@ -828,7 +829,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
828829
}
829830
}
830831
Some(ConstStability {
831-
level: ConstStabilityLevel::Unstable { unstables },
832+
level: ConstStabilityLevel::Unstable { unstables, reason },
832833
..
833834
}) => {
834835
// An unstable const fn with feature gates.
@@ -874,6 +875,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
874875
self.check_op(ops::FnCallUnstable {
875876
def_id: callee,
876877
features: missing_features,
878+
reason: *reason,
877879
safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
878880
});
879881
}

compiler/rustc_const_eval/src/check_consts/ops.rs

+16-16
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
311311
pub(crate) struct FnCallUnstable {
312312
pub def_id: DefId,
313313
pub features: SmallVec<[stability::EvalDenial; 1]>,
314+
pub reason: rustc_attr::UnstableReason,
314315
pub safe_to_expose_on_stable: bool,
315316
}
316317

@@ -324,17 +325,16 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
324325
}
325326

326327
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
327-
let (features, info) = stability::unstable_notes(&self.features);
328-
// Only suggest adding `#![feature]` on nightly.
329-
let nightly_subdiags =
330-
stability::unstable_nightly_subdiags(&ccx.tcx.sess, &self.features, None);
331-
332328
ccx.dcx().create_err(errors::UnstableConstFn {
333329
span,
334330
def_path: ccx.tcx.def_path_str(self.def_id),
335-
features,
336-
info,
337-
nightly_subdiags,
331+
features: stability::unstable_message(&self.features, self.reason.to_opt_reason()),
332+
issues: stability::unstable_issues(&self.features),
333+
nightly_subdiags: stability::unstable_nightly_subdiags(
334+
&ccx.tcx.sess,
335+
&self.features,
336+
None,
337+
),
338338
})
339339
}
340340
}
@@ -360,6 +360,7 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst {
360360
pub(crate) struct IntrinsicUnstable {
361361
pub name: Symbol,
362362
pub features: SmallVec<[stability::EvalDenial; 1]>,
363+
pub reason: rustc_attr::UnstableReason,
363364
pub const_stable: bool,
364365
}
365366

@@ -375,17 +376,16 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
375376
}
376377

377378
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
378-
let (features, info) = stability::unstable_notes(&self.features);
379-
// Only suggest adding `#![feature]` on nightly.
380-
let nightly_subdiags =
381-
stability::unstable_nightly_subdiags(&ccx.tcx.sess, &self.features, None);
382-
383379
ccx.dcx().create_err(errors::UnstableIntrinsic {
384380
span,
385381
name: self.name,
386-
features,
387-
info,
388-
nightly_subdiags,
382+
features: stability::unstable_message(&self.features, self.reason.to_opt_reason()),
383+
issues: stability::unstable_issues(&self.features),
384+
nightly_subdiags: stability::unstable_nightly_subdiags(
385+
&ccx.tcx.sess,
386+
&self.features,
387+
None,
388+
),
389389
})
390390
}
391391
}

compiler/rustc_const_eval/src/errors.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ pub(crate) struct UnstableConstFn {
122122
#[subdiagnostic]
123123
pub features: rustc_middle::error::UnstableLibraryFeatureNote,
124124
#[subdiagnostic]
125-
pub info: Vec<rustc_middle::error::UnstableLibraryFeatureInfo>,
125+
pub issues: Vec<rustc_middle::error::UnstableLibraryFeatureIssue>,
126126
#[subdiagnostic]
127127
pub nightly_subdiags: Vec<rustc_session::errors::NightlyFeatureDiagnostic>,
128128
}
@@ -136,7 +136,7 @@ pub(crate) struct UnstableIntrinsic {
136136
#[subdiagnostic]
137137
pub features: rustc_middle::error::UnstableLibraryFeatureNote,
138138
#[subdiagnostic]
139-
pub info: Vec<rustc_middle::error::UnstableLibraryFeatureInfo>,
139+
pub issues: Vec<rustc_middle::error::UnstableLibraryFeatureIssue>,
140140
#[subdiagnostic]
141141
pub nightly_subdiags: Vec<rustc_session::errors::NightlyFeatureDiagnostic>,
142142
}

compiler/rustc_hir_analysis/src/check/check.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -922,8 +922,14 @@ fn check_impl_items_against_trait<'tcx>(
922922
if !is_implemented_here {
923923
let full_impl_span = tcx.hir().span_with_body(tcx.local_def_id_to_hir_id(impl_id));
924924
match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {
925-
EvalResult::Deny { denials, .. } => {
926-
default_body_is_unstable(tcx, full_impl_span, trait_item_id, &denials);
925+
EvalResult::Deny { denials, reason, .. } => {
926+
default_body_is_unstable(
927+
tcx,
928+
full_impl_span,
929+
trait_item_id,
930+
&denials,
931+
reason,
932+
);
927933
}
928934

929935
// Unmarked default bodies are considered stable (at least for now).

compiler/rustc_hir_analysis/src/check/mod.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ use rustc_middle::{bug, span_bug};
8989
use rustc_session::parse::feature_err;
9090
use rustc_span::def_id::CRATE_DEF_ID;
9191
use rustc_span::symbol::{Ident, kw, sym};
92-
use rustc_span::{BytePos, DUMMY_SP, Span};
92+
use rustc_span::{BytePos, DUMMY_SP, Span, Symbol};
9393
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
9494
use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _;
9595
use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
@@ -294,20 +294,19 @@ fn default_body_is_unstable(
294294
impl_span: Span,
295295
item_did: DefId,
296296
denials: &[stability::EvalDenial],
297+
reason: Option<Symbol>,
297298
) {
298299
let missing_item_name = tcx.associated_item(item_did).name;
299300
let inject_span = item_did
300301
.as_local()
301302
.and_then(|id| tcx.crate_level_attribute_injection_span(tcx.local_def_id_to_hir_id(id)));
302-
let (features, info) = stability::unstable_notes(denials);
303-
let nightly_subdiags = stability::unstable_nightly_subdiags(&tcx.sess, denials, inject_span);
304303

305304
tcx.dcx().emit_err(errors::MissingTraitItemUnstable {
306305
span: impl_span,
307306
missing_item_name,
308-
features,
309-
info,
310-
nightly_subdiags,
307+
features: stability::unstable_message(denials, reason),
308+
issues: stability::unstable_issues(denials),
309+
nightly_subdiags: stability::unstable_nightly_subdiags(&tcx.sess, denials, inject_span),
311310
});
312311
}
313312

compiler/rustc_hir_analysis/src/errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ pub(crate) struct MissingTraitItemUnstable {
981981
#[subdiagnostic]
982982
pub features: rustc_middle::error::UnstableLibraryFeatureNote,
983983
#[subdiagnostic]
984-
pub info: Vec<rustc_middle::error::UnstableLibraryFeatureInfo>,
984+
pub issues: Vec<rustc_middle::error::UnstableLibraryFeatureIssue>,
985985
#[subdiagnostic]
986986
pub nightly_subdiags: Vec<rustc_session::errors::NightlyFeatureDiagnostic>,
987987
}

compiler/rustc_lint/src/context/diagnostics.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -382,12 +382,12 @@ 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::SoftUnstableMacro { features } => {
385+
BuiltinLintDiag::SoftUnstableMacro { features, reason } => {
386386
let denials = features
387387
.iter()
388-
.map(|&(feature, reason, issue)| stability::EvalDenial { feature, reason, issue })
388+
.map(|&(feature, issue)| stability::EvalDenial { feature, issue })
389389
.collect::<Vec<_>>();
390-
stability::soft_unstable(sess, &denials, vec![]).decorate_lint(diag);
390+
stability::soft_unstable(sess, &denials, reason, vec![]).decorate_lint(diag);
391391
}
392392
BuiltinLintDiag::AvoidUsingIntelSyntax => {
393393
lints::AvoidIntelSyntax.decorate_lint(diag);

compiler/rustc_lint_defs/src/lib.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -723,8 +723,10 @@ pub enum BuiltinLintDiag {
723723
UnusedMacroDefinition(Symbol),
724724
MacroRuleNeverUsed(usize, Symbol),
725725
SoftUnstableMacro {
726-
/// The name, optional reason, and issue number for each disabled unstable feature used.
727-
features: Vec<(Symbol, Option<Symbol>, Option<NonZero<u32>>)>,
726+
/// The name and optional issue number for each disabled unstable feature used.
727+
features: Vec<(Symbol, Option<NonZero<u32>>)>,
728+
/// An optional reason for the macro's unstability.
729+
reason: Option<Symbol>,
728730
},
729731
AvoidUsingIntelSyntax,
730732
AvoidUsingAttSyntax,

compiler/rustc_middle/messages.ftl

+7-8
Original file line numberDiff line numberDiff line change
@@ -102,22 +102,21 @@ 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 = use of unstable library {$count ->
106-
[one] feature {$features}{$single_feature_has_reason ->
107-
[true] : {$reason_for_single_feature}
108-
*[false] {""}
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}
109112
}
110-
*[other] features {$features}
111-
}
112113
113114
middle_unstable_library_feature_issue =
114115
see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information{$show_feature ->
115116
[true] {" "}about `{$feature}`
116117
*[false] {""}
117118
}
118119
119-
middle_unstable_library_feature_reason = reason for `{$feature}`: {$reason}
120-
121120
middle_unstable_library_feature_suggestion_for_allocator_api =
122121
consider wrapping the inner types in tuple
123122

compiler/rustc_middle/src/error.rs

+10-13
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,9 @@ pub struct UnstableLibraryFeatureError {
173173
pub span: Span,
174174
pub features: DiagSymbolList,
175175
pub count: usize,
176-
pub single_feature_has_reason: bool,
177-
pub reason_for_single_feature: String,
176+
pub reason: String,
178177
#[subdiagnostic]
179-
pub info: Vec<UnstableLibraryFeatureInfo>,
178+
pub issues: Vec<UnstableLibraryFeatureIssue>,
180179
#[subdiagnostic]
181180
pub nightly_subdiags: Vec<rustc_session::errors::NightlyFeatureDiagnostic>,
182181
#[subdiagnostic]
@@ -189,10 +188,9 @@ pub struct UnstableLibraryFeatureError {
189188
pub struct SoftUnstableLibraryFeature {
190189
pub features: DiagSymbolList,
191190
pub count: usize,
192-
pub single_feature_has_reason: bool,
193-
pub reason_for_single_feature: String,
191+
pub reason: String,
194192
#[subdiagnostic]
195-
pub info: Vec<UnstableLibraryFeatureInfo>,
193+
pub issues: Vec<UnstableLibraryFeatureIssue>,
196194
#[subdiagnostic]
197195
pub nightly_subdiags: Vec<rustc_session::errors::NightlyFeatureDiagnostic>,
198196
#[subdiagnostic]
@@ -205,16 +203,15 @@ pub struct SoftUnstableLibraryFeature {
205203
pub struct UnstableLibraryFeatureNote {
206204
pub features: DiagSymbolList,
207205
pub count: usize,
208-
pub single_feature_has_reason: bool,
209-
pub reason_for_single_feature: String,
206+
pub reason: String,
210207
}
211208

212209
#[derive(Subdiagnostic)]
213-
pub enum UnstableLibraryFeatureInfo {
214-
#[note(middle_unstable_library_feature_reason)]
215-
Reason { reason: String, feature: Symbol },
216-
#[note(middle_unstable_library_feature_issue)]
217-
Issue { issue: NonZero<u32>, feature: Symbol, show_feature: bool },
210+
#[note(middle_unstable_library_feature_issue)]
211+
pub struct UnstableLibraryFeatureIssue {
212+
pub issue: NonZero<u32>,
213+
pub feature: Symbol,
214+
pub show_feature: bool,
218215
}
219216

220217
#[derive(Subdiagnostic)]

0 commit comments

Comments
 (0)