Skip to content

Commit

Permalink
Add sanity checks for reason and soft on unstable attributes
Browse files Browse the repository at this point in the history
`reason` must appear at most once: it's the reason for the item being unstable, rather than a
particular feature. This simplifies diagnostic formatting.

`soft` must either be on all or no unstable attributes: it doesn't make sense for something to be
partially soft, and allowing inconsistent softness markers would risk an item accidentally becoming
properly unstable as its features stabilize.
  • Loading branch information
dianne committed Nov 19, 2024
1 parent edf10f8 commit b23f28d
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 5 deletions.
6 changes: 6 additions & 0 deletions compiler/rustc_attr/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ attr_multiple_item =
attr_multiple_stability_levels =
multiple stability levels for feature `{$feature}`
attr_multiple_unstable_reasons =
multiple reasons provided for unstability
attr_non_ident_feature =
'feature' is not an identifier
Expand All @@ -97,6 +100,9 @@ attr_rustc_const_stable_indirect_pairing =
attr_rustc_promotable_pairing =
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
attr_soft_inconsistent =
`soft` must be present on either none or all of an item's `unstable` attributes
attr_soft_no_args =
`soft` should not have any arguments
Expand Down
16 changes: 13 additions & 3 deletions compiler/rustc_attr/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,11 +416,21 @@ fn add_level(
(_, UnstableReason::None) => {}
(reason @ UnstableReason::None, _) => *reason = new_reason,
_ => {
// TODO: sanity check for only one reason
sess.dcx()
.emit_err(session_diagnostics::MultipleUnstableReasons { span: attr.span });
}
}
// TODO: sanity check for is_soft consistency
*is_soft |= new_soft;
// If any unstable attributes are marked 'soft', all should be. This keeps soft-unstable
// items from accidentally being made properly unstable as attributes are removed.
if *is_soft != new_soft {
let spans = stab_spans
.iter()
.filter(|(stab, _)| stab.is_unstable())
.map(|&(_, sp)| sp)
.chain([attr.span])
.collect();
sess.dcx().emit_err(session_diagnostics::SoftInconsistent { spans });
}
}
// an item with some stable and some unstable features is unstable
(Some(Unstable { .. }), Stable { .. }) => {}
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_attr/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ pub(crate) struct MultipleStabilityLevels {
pub feature: Symbol,
}

#[derive(Diagnostic)]
#[diag(attr_multiple_unstable_reasons)]
pub(crate) struct MultipleUnstableReasons {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(attr_invalid_issue_string, code = E0545)]
pub(crate) struct InvalidIssueString {
Expand Down Expand Up @@ -400,6 +407,13 @@ pub(crate) struct SoftNoArgs {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(attr_soft_inconsistent)]
pub(crate) struct SoftInconsistent {
#[primary_span]
pub spans: Vec<Span>,
}

#[derive(Diagnostic)]
#[diag(attr_unknown_version_literal)]
pub(crate) struct UnknownVersionLiteral {
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/stability-attribute/mixed-levels.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ error: `const_unstable_fn` is not yet stable as a const fn
LL | const USE_UNSTABLE: () = mixed_levels::const_unstable_fn();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: use of unstable library feature `unstable_c`
= help: add `#![feature(unstable_c)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 2 previous errors

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//! Checks that multiple stability attributes are used correctly together
#![feature(staged_api)]

#![stable(feature = "stable_test_feature", since = "1.0.0")]

#[unstable(feature = "a", issue = "none", reason = "reason 1")]
#[unstable(feature = "b", issue = "none", reason = "reason 2")] //~ ERROR multiple reasons provided for unstability
fn f1() { }

#[unstable(feature = "a", issue = "none", reason = "reason 1")]
#[unstable(feature = "b", issue = "none", reason = "reason 2")] //~ ERROR multiple reasons provided for unstability
#[unstable(feature = "c", issue = "none", reason = "reason 3")] //~ ERROR multiple reasons provided for unstability
fn f2() { }

#[unstable(feature = "a", issue = "none")] //~ ERROR `soft` must be present on either none or all of an item's `unstable` attributes
#[unstable(feature = "b", issue = "none", soft)]
fn f3() { }

#[unstable(feature = "a", issue = "none", soft)] //~ ERROR `soft` must be present on either none or all of an item's `unstable` attributes
#[unstable(feature = "b", issue = "none")]
fn f4() { }

fn main() { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
error: multiple reasons provided for unstability
--> $DIR/multiple-stability-attribute-sanity.rs:8:1
|
LL | #[unstable(feature = "b", issue = "none", reason = "reason 2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: multiple reasons provided for unstability
--> $DIR/multiple-stability-attribute-sanity.rs:12:1
|
LL | #[unstable(feature = "b", issue = "none", reason = "reason 2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: multiple reasons provided for unstability
--> $DIR/multiple-stability-attribute-sanity.rs:13:1
|
LL | #[unstable(feature = "c", issue = "none", reason = "reason 3")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: `soft` must be present on either none or all of an item's `unstable` attributes
--> $DIR/multiple-stability-attribute-sanity.rs:16:1
|
LL | #[unstable(feature = "a", issue = "none")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[unstable(feature = "b", issue = "none", soft)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: `soft` must be present on either none or all of an item's `unstable` attributes
--> $DIR/multiple-stability-attribute-sanity.rs:20:1
|
LL | #[unstable(feature = "a", issue = "none", soft)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[unstable(feature = "b", issue = "none")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 5 previous errors

0 comments on commit b23f28d

Please sign in to comment.