diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index dcc4cf2478f..762ebc47ca9 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -153,7 +153,7 @@ pub enum StabilityLevel { } /// Rust release in which a feature is stabilized. -#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] +#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)] #[derive(HashStable_Generic)] pub enum StableSince { Version(RustcVersion), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 31710bc014a..a0f44d152b2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -384,7 +384,45 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { impl Item { pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option { - self.def_id().and_then(|did| tcx.lookup_stability(did)) + let (mut def_id, mut stability) = if let Some(inlined) = self.inline_stmt_id { + let inlined_def_id = inlined.to_def_id(); + if let Some(stability) = tcx.lookup_stability(inlined_def_id) { + (inlined_def_id, stability) + } else { + // For re-exports into crates without `staged_api`, reuse the original stability. + // This is necessary, because we always want to mark unstable items. + let def_id = self.def_id()?; + return tcx.lookup_stability(def_id); + } + } else { + let def_id = self.def_id()?; + let stability = tcx.lookup_stability(def_id)?; + (def_id, stability) + }; + + let StabilityLevel::Stable { mut since, allowed_through_unstable_modules: false } = + stability.level + else { + return Some(stability); + }; + + // If any of the item's ancestors was stabilized later or is still unstable, + // then report the ancestor's stability instead. + while let Some(parent_def_id) = tcx.opt_parent(def_id) { + if let Some(parent_stability) = tcx.lookup_stability(parent_def_id) { + match parent_stability.level { + StabilityLevel::Unstable { .. } => return Some(parent_stability), + StabilityLevel::Stable { since: parent_since, .. } => { + if parent_since > since { + stability = parent_stability; + since = parent_since; + } + } + } + } + def_id = parent_def_id; + } + Some(stability) } pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option { diff --git a/tests/rustdoc/const-display.rs b/tests/rustdoc/const-display.rs index ac55a6302f7..a71825d883d 100644 --- a/tests/rustdoc/const-display.rs +++ b/tests/rustdoc/const-display.rs @@ -1,8 +1,6 @@ #![crate_name = "foo"] -#![unstable(feature = "humans", - reason = "who ever let humans program computers, we're apparently really bad at it", - issue = "none")] +#![stable(feature = "rust1", since = "1.0.0")] #![feature(foo, foo2)] #![feature(staged_api)] @@ -48,10 +46,18 @@ pub const fn bar2() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const unsafe fn bar2_gated() -> u32 { 42 } -//@ has 'foo/fn.bar_not_gated.html' '//pre' 'pub const unsafe fn bar_not_gated() -> u32' -//@ !hasraw - '//span[@class="since"]' -pub const unsafe fn bar_not_gated() -> u32 { 42 } +#[unstable( + feature = "humans", + reason = "who ever let humans program computers, we're apparently really bad at it", + issue = "none", +)] +pub mod unstable { + //@ has 'foo/unstable/fn.bar_not_gated.html' '//pre' 'pub const unsafe fn bar_not_gated() -> u32' + //@ !hasraw - '//span[@class="since"]' + pub const unsafe fn bar_not_gated() -> u32 { 42 } +} +#[stable(feature = "rust1", since = "1.0.0")] pub struct Foo; impl Foo { diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc/stability.rs index 270da822c00..de855b43ba5 100644 --- a/tests/rustdoc/stability.rs +++ b/tests/rustdoc/stability.rs @@ -1,6 +1,6 @@ #![feature(staged_api)] -#![unstable(feature = "test", issue = "none")] +#![stable(feature = "rust1", since = "1.0.0")] //@ has stability/index.html //@ has - '//ul[@class="item-table"]/li[1]//a' AaStable @@ -10,6 +10,7 @@ #[stable(feature = "rust2", since = "2.2.2")] pub struct AaStable; +#[unstable(feature = "test", issue = "none")] pub struct Unstable { //@ has stability/struct.Unstable.html \ // '//span[@class="item-info"]//div[@class="stab unstable"]' \ @@ -21,3 +22,31 @@ pub struct Unstable { #[stable(feature = "rust2", since = "2.2.2")] pub struct ZzStable; + +#[unstable(feature = "unstable", issue = "none")] +pub mod unstable { + //@ !hasraw stability/unstable/struct.Foo.html '//span[@class="since"]' + //@ has - '//div[@class="stab unstable"]' 'experimental' + #[stable(feature = "rust1", since = "1.0.0")] + pub struct Foo; +} + +#[stable(feature = "rust2", since = "2.2.2")] +pub mod stable_later { + //@ has stability/stable_later/struct.Bar.html '//span[@class="since"]' '2.2.2' + #[stable(feature = "rust1", since = "1.0.0")] + pub struct Bar; +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod stable_earlier { + //@ has stability/stable_earlier/struct.Foo.html '//span[@class="since"]' '1.0.0' + #[doc(inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::unstable::Foo; + + //@ has stability/stable_earlier/struct.Bar.html '//span[@class="since"]' '1.0.0' + #[doc(inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::stable_later::Bar; +}