Skip to content

Commit a8a36a9

Browse files
committed
rustdoc: report all unstable features needed for items
1 parent 42b461e commit a8a36a9

File tree

2 files changed

+39
-14
lines changed

2 files changed

+39
-14
lines changed

src/librustdoc/passes/propagate_stability.rs

+33-14
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//! [`core::error`] module is marked as stable since 1.81.0, so we want to show
77
//! [`core::error::Error`] as stable since 1.81.0 as well.
88
9-
use rustc_attr::{Stability, StabilityLevel};
9+
use rustc_attr::Stability;
1010
use rustc_hir::def_id::CRATE_DEF_ID;
1111

1212
use crate::clean::{Crate, Item, ItemId};
@@ -32,27 +32,46 @@ struct StabilityPropagator<'a, 'tcx> {
3232

3333
impl<'a, 'tcx> DocFolder for StabilityPropagator<'a, 'tcx> {
3434
fn fold_item(&mut self, mut item: Item) -> Option<Item> {
35+
use rustc_attr::StabilityLevel::*;
36+
3537
let parent_stability = self.parent_stability.clone();
3638

3739
let stability = match item.item_id {
3840
ItemId::DefId(def_id) => {
3941
let own_stability = self.cx.tcx.lookup_stability(def_id);
4042

41-
// If any of the item's parents was stabilized later or is still unstable,
42-
// then use the parent's stability instead.
43-
if let Some(ref own_stab) = own_stability
44-
&& let StabilityLevel::Stable {
45-
since: own_since,
46-
allowed_through_unstable_modules: false,
47-
..
48-
} = own_stab.level
43+
if let Some(own_stab) = own_stability
4944
&& let Some(ref parent_stab) = parent_stability
50-
&& (parent_stab.is_unstable()
51-
|| parent_stab
52-
.stable_since()
53-
.is_some_and(|parent_since| parent_since > own_since))
5445
{
55-
parent_stability.clone()
46+
match own_stab.level {
47+
// If any of the item's parents was stabilized later or is still unstable,
48+
// then use the parent's stability instead.
49+
Stable {
50+
since: own_since,
51+
allowed_through_unstable_modules: false,
52+
..
53+
} if parent_stab.is_unstable()
54+
|| parent_stab
55+
.stable_since()
56+
.is_some_and(|parent_since| parent_since > own_since) =>
57+
{
58+
parent_stability.clone()
59+
}
60+
// If any of an unstable item's parents depend on other unstable features,
61+
// then use those as well.
62+
Unstable { unstables: ref own_gates, is_soft }
63+
if let Unstable { unstables: parent_gates, .. } =
64+
&parent_stab.level =>
65+
{
66+
let missing_unstables = parent_gates
67+
.iter()
68+
.filter(|p| !own_gates.iter().any(|u| u.feature == p.feature));
69+
let unstables =
70+
own_gates.iter().chain(missing_unstables).cloned().collect();
71+
Some(Stability { level: Unstable { unstables, is_soft } })
72+
}
73+
_ => own_stability.cloned(),
74+
}
5675
} else {
5776
own_stability.cloned()
5877
}

tests/rustdoc/stability.rs

+6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ pub mod unstable {
3939
#[stable(feature = "rust1", since = "1.0.0")]
4040
pub struct Inner;
4141
}
42+
43+
//@ has stability/unstable/fn.nested_unstable.html \
44+
// '//span[@class="item-info"]//div[@class="stab unstable"]' \
45+
// 'This is a nightly-only experimental API. (test, unstable)'
46+
#[unstable(feature = "test", issue = "none")]
47+
pub fn nested_unstable() {}
4248
}
4349

4450
#[stable(feature = "rust2", since = "2.2.2")]

0 commit comments

Comments
 (0)