Skip to content

Commit 1e7a7a4

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 dbe379c commit 1e7a7a4

File tree

26 files changed

+232
-190
lines changed

26 files changed

+232
-190
lines changed

compiler/rustc_attr/messages.ftl

Lines changed: 3 additions & 0 deletions
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

Lines changed: 26 additions & 14 deletions
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,
@@ -486,10 +491,18 @@ fn add_level(
486491
(level @ None, new_level) => *level = Some(new_level),
487492
// if multiple unstable attributes have been found, merge them
488493
(
489-
Some(Unstable { unstables, is_soft }),
490-
Unstable { unstables: new_unstable, is_soft: new_soft },
494+
Some(Unstable { unstables, reason, is_soft }),
495+
Unstable { unstables: new_unstable, reason: new_reason, is_soft: new_soft },
491496
) => {
492497
unstables.extend(new_unstable);
498+
match (reason, new_reason) {
499+
(_, UnstableReason::None) => {}
500+
(reason @ UnstableReason::None, _) => *reason = new_reason,
501+
_ => {
502+
sess.dcx()
503+
.emit_err(session_diagnostics::MultipleUnstableReasons { span: attr.span });
504+
}
505+
}
493506
// Make the unstability soft if any unstable attributes are marked 'soft'; if an
494507
// unstable item is allowed in stable rust, another attribute shouldn't break that.
495508
// FIXME(dianne): should there be a check that all unstables are soft if any are?
@@ -670,13 +683,12 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
670683

671684
match (feature, issue) {
672685
(Ok(feature), Ok(_)) => {
673-
let unstability = Unstability {
674-
feature,
686+
let unstability = Unstability { feature, issue: issue_num, implied_by };
687+
Some((feature, StabilityLevel::Unstable {
688+
unstables: smallvec![unstability],
675689
reason: UnstableReason::from_opt_reason(reason),
676-
issue: issue_num,
677-
implied_by,
678-
};
679-
Some((feature, StabilityLevel::Unstable { unstables: smallvec![unstability], is_soft }))
690+
is_soft,
691+
}))
680692
}
681693
(Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
682694
}

compiler/rustc_attr/src/session_diagnostics.rs

Lines changed: 7 additions & 0 deletions
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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -735,13 +735,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
735735
}
736736
}
737737
Some(ConstStability {
738-
level: ConstStabilityLevel::Unstable { unstables },
738+
level: ConstStabilityLevel::Unstable { unstables, reason },
739739
const_stable_indirect,
740740
..
741741
}) => {
742742
self.check_op(ops::IntrinsicUnstable {
743743
name: intrinsic.name,
744744
features: unstables.iter().map(|u| u.into()).collect(),
745+
reason: *reason,
745746
const_stable_indirect: *const_stable_indirect,
746747
});
747748
}
@@ -789,7 +790,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
789790
}
790791
}
791792
Some(ConstStability {
792-
level: ConstStabilityLevel::Unstable { unstables },
793+
level: ConstStabilityLevel::Unstable { unstables, reason },
793794
..
794795
}) => {
795796
// An unstable const fn with feature gates.
@@ -835,6 +836,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
835836
self.check_op(ops::FnCallUnstable {
836837
def_id: callee,
837838
features: missing_features,
839+
reason: *reason,
838840
safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
839841
});
840842
}

compiler/rustc_const_eval/src/check_consts/ops.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
312312
pub(crate) struct FnCallUnstable {
313313
pub def_id: DefId,
314314
pub features: SmallVec<[stability::EvalDenial; 1]>,
315+
pub reason: rustc_attr::UnstableReason,
315316
pub safe_to_expose_on_stable: bool,
316317
}
317318

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

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

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

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

compiler/rustc_const_eval/src/errors.rs

Lines changed: 2 additions & 2 deletions
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

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

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

compiler/rustc_hir_analysis/src/check/mod.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ use rustc_middle::{bug, span_bug};
8888
use rustc_session::parse::feature_err;
8989
use rustc_span::def_id::CRATE_DEF_ID;
9090
use rustc_span::symbol::{Ident, kw, sym};
91-
use rustc_span::{BytePos, DUMMY_SP, Span};
91+
use rustc_span::{BytePos, DUMMY_SP, Span, Symbol};
9292
use rustc_target::abi::VariantIdx;
9393
use rustc_target::spec::abi::Abi;
9494
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -295,20 +295,19 @@ fn default_body_is_unstable(
295295
impl_span: Span,
296296
item_did: DefId,
297297
denials: &[stability::EvalDenial],
298+
reason: Option<Symbol>,
298299
) {
299300
let missing_item_name = tcx.associated_item(item_did).name;
300301
let inject_span = item_did
301302
.as_local()
302303
.and_then(|id| tcx.crate_level_attribute_injection_span(tcx.local_def_id_to_hir_id(id)));
303-
let (features, info) = stability::unstable_notes(denials);
304-
let nightly_subdiags = stability::unstable_nightly_subdiags(&tcx.sess, denials, inject_span);
305304

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

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 1 addition & 1 deletion
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 4 additions & 2 deletions
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

Lines changed: 7 additions & 8 deletions
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

Lines changed: 10 additions & 13 deletions
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)