Skip to content

Commit 6eeb286

Browse files
authored
Rollup merge of #132481 - lukas-code:doc-stab3, r=GuillaumeGomez
rustdoc: skip stability inheritance for some item kinds For some item kinds it's incorrect to inherit their parent's stability, because they might be accessible without referring to the parent directly -- This PR removes the stability inheritance for these items and reverts their displayed stability to that before #130798. Impl items, both inherent and trait impls, have a stability, but it is ignored when checking for enabled features. However, impl items are automatically unstable if they're nested inside an unstable module -- this caused the children of impl to inherit the instability and lead to #132440. Furthermore, for associated items only the stability of the associated item itself is checked and not that of its parent impl. This is true even for trait impls and we have [relied on this behavior in the standard library in the past](https://doc.rust-lang.org/1.37.0/std/slice/trait.SliceConcatExt.html#tymethod.concat), so these also shouldn't inherit the impl's stability. I've also removed the stability inheritance for primitives and keywords so that viewing e.g. [the `i32` docs on `core`](https://doc.rust-lang.org/nightly/core/primitive.i32.html) will no longer show "since 1.6.0". Note that we currently don't annotate stability for the keyword docs, but if we start doing so in the future then this is probably more correct. fixes (after backport) #132440
2 parents 588a420 + 728315d commit 6eeb286

File tree

2 files changed

+157
-31
lines changed

2 files changed

+157
-31
lines changed

src/librustdoc/passes/propagate_stability.rs

+57-17
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use rustc_attr::{Stability, StabilityLevel};
1010
use rustc_hir::def_id::CRATE_DEF_ID;
1111

12-
use crate::clean::{Crate, Item, ItemId};
12+
use crate::clean::{Crate, Item, ItemId, ItemKind};
1313
use crate::core::DocContext;
1414
use crate::fold::DocFolder;
1515
use crate::passes::Pass;
@@ -38,22 +38,45 @@ impl<'a, 'tcx> DocFolder for StabilityPropagator<'a, 'tcx> {
3838
ItemId::DefId(def_id) => {
3939
let own_stability = self.cx.tcx.lookup_stability(def_id);
4040

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(own_stab) = own_stability
44-
&& let StabilityLevel::Stable {
45-
since: own_since,
46-
allowed_through_unstable_modules: false,
47-
} = own_stab.level
48-
&& let Some(parent_stab) = parent_stability
49-
&& (parent_stab.is_unstable()
50-
|| parent_stab
51-
.stable_since()
52-
.is_some_and(|parent_since| parent_since > own_since))
53-
{
54-
parent_stability
55-
} else {
56-
own_stability
41+
let (ItemKind::StrippedItem(box kind) | kind) = &item.kind;
42+
match kind {
43+
ItemKind::ExternCrateItem { .. }
44+
| ItemKind::ImportItem(..)
45+
| ItemKind::StructItem(..)
46+
| ItemKind::UnionItem(..)
47+
| ItemKind::EnumItem(..)
48+
| ItemKind::FunctionItem(..)
49+
| ItemKind::ModuleItem(..)
50+
| ItemKind::TypeAliasItem(..)
51+
| ItemKind::StaticItem(..)
52+
| ItemKind::TraitItem(..)
53+
| ItemKind::TraitAliasItem(..)
54+
| ItemKind::StructFieldItem(..)
55+
| ItemKind::VariantItem(..)
56+
| ItemKind::ForeignFunctionItem(..)
57+
| ItemKind::ForeignStaticItem(..)
58+
| ItemKind::ForeignTypeItem
59+
| ItemKind::MacroItem(..)
60+
| ItemKind::ProcMacroItem(..)
61+
| ItemKind::ConstantItem(..) => {
62+
// If any of the item's parents was stabilized later or is still unstable,
63+
// then use the parent's stability instead.
64+
merge_stability(own_stability, parent_stability)
65+
}
66+
67+
// Don't inherit the parent's stability for these items, because they
68+
// are potentially accessible even if the parent is more unstable.
69+
ItemKind::ImplItem(..)
70+
| ItemKind::TyMethodItem(..)
71+
| ItemKind::MethodItem(..)
72+
| ItemKind::TyAssocConstItem(..)
73+
| ItemKind::AssocConstItem(..)
74+
| ItemKind::TyAssocTypeItem(..)
75+
| ItemKind::AssocTypeItem(..)
76+
| ItemKind::PrimitiveItem(..)
77+
| ItemKind::KeywordItem => own_stability,
78+
79+
ItemKind::StrippedItem(..) => unreachable!(),
5780
}
5881
}
5982
ItemId::Auto { .. } | ItemId::Blanket { .. } => {
@@ -70,3 +93,20 @@ impl<'a, 'tcx> DocFolder for StabilityPropagator<'a, 'tcx> {
7093
Some(item)
7194
}
7295
}
96+
97+
fn merge_stability(
98+
own_stability: Option<Stability>,
99+
parent_stability: Option<Stability>,
100+
) -> Option<Stability> {
101+
if let Some(own_stab) = own_stability
102+
&& let StabilityLevel::Stable { since: own_since, allowed_through_unstable_modules: false } =
103+
own_stab.level
104+
&& let Some(parent_stab) = parent_stability
105+
&& (parent_stab.is_unstable()
106+
|| parent_stab.stable_since().is_some_and(|parent_since| parent_since > own_since))
107+
{
108+
parent_stability
109+
} else {
110+
own_stability
111+
}
112+
}

tests/rustdoc/stability.rs

+100-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#![feature(staged_api)]
2+
#![feature(rustc_attrs)]
3+
#![feature(rustdoc_internals)]
24

3-
#![stable(feature = "rust1", since = "1.0.0")]
5+
#![stable(feature = "core", since = "1.6.0")]
46

57
//@ has stability/index.html
68
//@ has - '//ul[@class="item-table"]/li[1]//a' AaStable
@@ -26,60 +28,144 @@ pub struct ZzStable;
2628
#[unstable(feature = "unstable", issue = "none")]
2729
pub mod unstable {
2830
//@ !hasraw stability/unstable/struct.StableInUnstable.html \
29-
// '//span[@class="since"]'
31+
// '//div[@class="main-heading"]//span[@class="since"]'
3032
//@ has - '//div[@class="stab unstable"]' 'experimental'
3133
#[stable(feature = "rust1", since = "1.0.0")]
3234
pub struct StableInUnstable;
3335

3436
#[stable(feature = "rust1", since = "1.0.0")]
3537
pub mod stable_in_unstable {
3638
//@ !hasraw stability/unstable/stable_in_unstable/struct.Inner.html \
37-
// '//span[@class="since"]'
39+
// '//div[@class="main-heading"]//span[@class="since"]'
3840
//@ has - '//div[@class="stab unstable"]' 'experimental'
3941
#[stable(feature = "rust1", since = "1.0.0")]
4042
pub struct Inner;
4143
}
44+
45+
//@ has stability/struct.AaStable.html \
46+
// '//*[@id="method.foo"]//span[@class="since"]' '2.2.2'
47+
impl super::AaStable {
48+
#[stable(feature = "rust2", since = "2.2.2")]
49+
pub fn foo() {}
50+
}
51+
52+
//@ has stability/unstable/struct.StableInUnstable.html \
53+
// '//*[@id="method.foo"]//span[@class="since"]' '1.0.0'
54+
impl StableInUnstable {
55+
#[stable(feature = "rust1", since = "1.0.0")]
56+
pub fn foo() {}
57+
}
58+
}
59+
60+
#[unstable(feature = "unstable", issue = "none")]
61+
#[doc(hidden)]
62+
pub mod unstable_stripped {
63+
//@ has stability/struct.AaStable.html \
64+
// '//*[@id="method.foo"]//span[@class="since"]' '2.2.2'
65+
impl super::AaStable {
66+
#[stable(feature = "rust2", since = "2.2.2")]
67+
pub fn foo() {}
68+
}
4269
}
4370

4471
#[stable(feature = "rust2", since = "2.2.2")]
4572
pub mod stable_later {
4673
//@ has stability/stable_later/struct.StableInLater.html \
47-
// '//span[@class="since"]' '2.2.2'
74+
// '//div[@class="main-heading"]//span[@class="since"]' '2.2.2'
4875
#[stable(feature = "rust1", since = "1.0.0")]
4976
pub struct StableInLater;
5077

5178
#[stable(feature = "rust1", since = "1.0.0")]
5279
pub mod stable_in_later {
5380
//@ has stability/stable_later/stable_in_later/struct.Inner.html \
54-
// '//span[@class="since"]' '2.2.2'
81+
// '//div[@class="main-heading"]//span[@class="since"]' '2.2.2'
5582
#[stable(feature = "rust1", since = "1.0.0")]
5683
pub struct Inner;
5784
}
5885
}
5986

6087
#[stable(feature = "rust1", since = "1.0.0")]
61-
pub mod stable_earlier {
62-
//@ has stability/stable_earlier/struct.StableInUnstable.html \
63-
// '//span[@class="since"]' '1.0.0'
88+
#[rustc_allowed_through_unstable_modules]
89+
pub mod stable_earlier1 {
90+
//@ has stability/stable_earlier1/struct.StableInUnstable.html \
91+
// '//div[@class="main-heading"]//span[@class="since"]' '1.0.0'
92+
//@ has - '//*[@id="method.foo"]//span[@class="since"]' '1.0.0'
93+
#[doc(inline)]
94+
#[stable(feature = "rust1", since = "1.0.0")]
95+
pub use crate::unstable::StableInUnstable;
96+
97+
//@ has stability/stable_earlier1/stable_in_unstable/struct.Inner.html \
98+
// '//div[@class="main-heading"]//span[@class="since"]' '1.0.0'
99+
#[doc(inline)]
100+
#[stable(feature = "rust1", since = "1.0.0")]
101+
pub use crate::unstable::stable_in_unstable;
102+
103+
//@ has stability/stable_earlier1/struct.StableInLater.html \
104+
// '//div[@class="main-heading"]//span[@class="since"]' '1.0.0'
105+
#[doc(inline)]
106+
#[stable(feature = "rust1", since = "1.0.0")]
107+
pub use crate::stable_later::StableInLater;
108+
109+
//@ has stability/stable_earlier1/stable_in_later/struct.Inner.html \
110+
// '//div[@class="main-heading"]//span[@class="since"]' '1.0.0'
111+
#[doc(inline)]
112+
#[stable(feature = "rust1", since = "1.0.0")]
113+
pub use crate::stable_later::stable_in_later;
114+
}
115+
116+
/// These will inherit the crate stability.
117+
#[stable(feature = "rust1", since = "1.0.0")]
118+
pub mod stable_earlier2 {
119+
//@ has stability/stable_earlier2/struct.StableInUnstable.html \
120+
// '//div[@class="main-heading"]//span[@class="since"]' '1.6.0'
121+
//@ has - '//*[@id="method.foo"]//span[@class="since"]' '1.0.0'
64122
#[doc(inline)]
65123
#[stable(feature = "rust1", since = "1.0.0")]
66124
pub use crate::unstable::StableInUnstable;
67125

68-
//@ has stability/stable_earlier/stable_in_unstable/struct.Inner.html \
69-
// '//span[@class="since"]' '1.0.0'
126+
//@ has stability/stable_earlier2/stable_in_unstable/struct.Inner.html \
127+
// '//div[@class="main-heading"]//span[@class="since"]' '1.6.0'
70128
#[doc(inline)]
71129
#[stable(feature = "rust1", since = "1.0.0")]
72130
pub use crate::unstable::stable_in_unstable;
73131

74-
//@ has stability/stable_earlier/struct.StableInLater.html \
75-
// '//span[@class="since"]' '1.0.0'
132+
//@ has stability/stable_earlier2/struct.StableInLater.html \
133+
// '//div[@class="main-heading"]//span[@class="since"]' '1.6.0'
76134
#[doc(inline)]
77135
#[stable(feature = "rust1", since = "1.0.0")]
78136
pub use crate::stable_later::StableInLater;
79137

80-
//@ has stability/stable_earlier/stable_in_later/struct.Inner.html \
81-
// '//span[@class="since"]' '1.0.0'
138+
//@ has stability/stable_earlier2/stable_in_later/struct.Inner.html \
139+
// '//div[@class="main-heading"]//span[@class="since"]' '1.6.0'
82140
#[doc(inline)]
83141
#[stable(feature = "rust1", since = "1.0.0")]
84142
pub use crate::stable_later::stable_in_later;
85143
}
144+
145+
//@ !hasraw stability/trait.UnstableTraitWithStableMethod.html \
146+
// '//div[@class="main-heading"]//span[@class="since"]'
147+
//@ has - '//*[@id="tymethod.foo"]//span[@class="since"]' '1.0.0'
148+
//@ has - '//*[@id="method.bar"]//span[@class="since"]' '1.0.0'
149+
#[unstable(feature = "unstable", issue = "none")]
150+
pub trait UnstableTraitWithStableMethod {
151+
#[stable(feature = "rust1", since = "1.0.0")]
152+
fn foo();
153+
#[stable(feature = "rust1", since = "1.0.0")]
154+
fn bar() {}
155+
}
156+
157+
//@ has stability/primitive.i32.html \
158+
// '//div[@class="main-heading"]//span[@class="since"]' '1.0.0'
159+
#[rustc_doc_primitive = "i32"]
160+
//
161+
/// `i32` is always stable in 1.0, even if you look at it from core.
162+
#[stable(feature = "rust1", since = "1.0.0")]
163+
mod prim_i32 {}
164+
165+
//@ has stability/keyword.if.html \
166+
// '//div[@class="main-heading"]//span[@class="since"]' '1.0.0'
167+
#[doc(keyword = "if")]
168+
//
169+
/// We currently don't document stability for keywords, but let's test it anyway.
170+
#[stable(feature = "rust1", since = "1.0.0")]
171+
mod if_keyword {}

0 commit comments

Comments
 (0)