diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 918a5cb509430..58c609cf252cf 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -9,6 +9,7 @@ use std::cell::Cell; use std::fmt; use std::iter; +use rustc_attr::{ConstStability, StabilityLevel}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -1253,15 +1254,6 @@ impl PrintWithSpace for hir::Unsafety { } } -impl PrintWithSpace for hir::Constness { - fn print_with_space(&self) -> &str { - match self { - hir::Constness::Const => "const ", - hir::Constness::NotConst => "", - } - } -} - impl PrintWithSpace for hir::IsAsync { fn print_with_space(&self) -> &str { match self { @@ -1280,6 +1272,22 @@ impl PrintWithSpace for hir::Mutability { } } +crate fn print_constness_with_space( + c: &hir::Constness, + s: Option<&ConstStability>, +) -> &'static str { + match (c, s) { + // const stable or when feature(staged_api) is not set + ( + hir::Constness::Const, + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }), + ) + | (hir::Constness::Const, None) => "const ", + // const unstable or not const + _ => "", + } +} + impl clean::Import { crate fn print<'a, 'tcx: 'a>( &'a self, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 62d3c142eeb52..03b607c2d2cb7 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -42,7 +42,7 @@ use std::str; use std::string::ToString; use rustc_ast_pretty::pprust; -use rustc_attr::{Deprecation, StabilityLevel}; +use rustc_attr::{ConstStability, Deprecation, StabilityLevel}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::CtorKind; @@ -61,8 +61,8 @@ use crate::formats::item_type::ItemType; use crate::formats::{AssocItemRender, Impl, RenderMode}; use crate::html::escape::Escape; use crate::html::format::{ - href, print_abi_with_space, print_default_space, print_generic_bounds, print_where_clause, - Buffer, PrintWithSpace, + href, print_abi_with_space, print_constness_with_space, print_default_space, + print_generic_bounds, print_where_clause, Buffer, PrintWithSpace, }; use crate::html::markdown::{Markdown, MarkdownHtml, MarkdownSummaryLine}; @@ -826,21 +826,45 @@ fn assoc_type( fn render_stability_since_raw( w: &mut Buffer, ver: Option<&str>, - const_ver: Option<&str>, + const_stability: Option<&ConstStability>, containing_ver: Option<&str>, containing_const_ver: Option<&str>, ) { let ver = ver.filter(|inner| !inner.is_empty()); - let const_ver = const_ver.filter(|inner| !inner.is_empty()); - match (ver, const_ver) { - (Some(v), Some(cv)) if const_ver != containing_const_ver => { + match (ver, const_stability) { + // stable and const stable + (Some(v), Some(ConstStability { level: StabilityLevel::Stable { since }, .. })) + if Some(since.as_str()).as_deref() != containing_const_ver => + { write!( w, "{0} (const: {1})", - v, cv + v, since ); } + // stable and const unstable + ( + Some(v), + Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }), + ) => { + write!( + w, + "{0} (const: ", + v + ); + if let Some(n) = issue { + write!( + w, + "unstable", + n, feature + ); + } else { + write!(w, "unstable"); + } + write!(w, ")"); + } + // stable (Some(v), _) if ver != containing_ver => { write!( w, @@ -888,11 +912,13 @@ fn render_assoc_item( } }; let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string(); - let constness = header.constness.print_with_space(); + let constness = + print_constness_with_space(&header.constness, meth.const_stability(cx.tcx())); let asyncness = header.asyncness.print_with_space(); let unsafety = header.unsafety.print_with_space(); let defaultness = print_default_space(meth.is_default()); let abi = print_abi_with_space(header.abi).to_string(); + // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`. let generics_len = format!("{:#}", g.print(cx)).len(); let mut header_len = "fn ".len() @@ -917,15 +943,15 @@ fn render_assoc_item( w.reserve(header_len + "{".len() + "".len()); write!( w, - "{}{}{}{}{}{}{}fn {name}\ + "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn {name}\ {generics}{decl}{notable_traits}{where_clause}", - indent_str, - vis, - constness, - asyncness, - unsafety, - defaultness, - abi, + indent = indent_str, + vis = vis, + constness = constness, + asyncness = asyncness, + unsafety = unsafety, + defaultness = defaultness, + abi = abi, href = href, name = name, generics = g.print(cx), @@ -1583,7 +1609,7 @@ fn render_rightside( render_stability_since_raw( w, item.stable_since(tcx).as_deref(), - item.const_stable_since(tcx).as_deref(), + item.const_stability(tcx), containing_item.stable_since(tcx).as_deref(), containing_item.const_stable_since(tcx).as_deref(), ); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 48cbd94ccabfb..0174bfec32d7e 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -22,7 +22,9 @@ use crate::clean::{self, GetDefId}; use crate::formats::item_type::ItemType; use crate::formats::{AssocItemRender, Impl, RenderMode}; use crate::html::escape::Escape; -use crate::html::format::{print_abi_with_space, print_where_clause, Buffer, PrintWithSpace}; +use crate::html::format::{ + print_abi_with_space, print_constness_with_space, print_where_clause, Buffer, PrintWithSpace, +}; use crate::html::highlight; use crate::html::layout::Page; use crate::html::markdown::MarkdownSummaryLine; @@ -94,7 +96,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, render_stability_since_raw( buf, item.stable_since(cx.tcx()).as_deref(), - item.const_stable_since(cx.tcx()).as_deref(), + item.const_stability(cx.tcx()), None, None, ); @@ -430,29 +432,36 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> } fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) { - let header_len = format!( - "{}{}{}{}{:#}fn {}{:#}", - it.visibility.print_with_space(it.def_id, cx), - f.header.constness.print_with_space(), - f.header.asyncness.print_with_space(), - f.header.unsafety.print_with_space(), - print_abi_with_space(f.header.abi), - it.name.as_ref().unwrap(), - f.generics.print(cx), - ) - .len(); + let vis = it.visibility.print_with_space(it.def_id, cx).to_string(); + let constness = print_constness_with_space(&f.header.constness, it.const_stability(cx.tcx())); + let asyncness = f.header.asyncness.print_with_space(); + let unsafety = f.header.unsafety.print_with_space(); + let abi = print_abi_with_space(f.header.abi).to_string(); + let name = it.name.as_ref().unwrap(); + + let generics_len = format!("{:#}", f.generics.print(cx)).len(); + let header_len = "fn ".len() + + vis.len() + + constness.len() + + asyncness.len() + + unsafety.len() + + abi.len() + + name.as_str().len() + + generics_len; + w.write_str("
");
     render_attributes_in_pre(w, it, "");
+    w.reserve(header_len);
     write!(
         w,
         "{vis}{constness}{asyncness}{unsafety}{abi}fn \
          {name}{generics}{decl}{notable_traits}{where_clause}
", - vis = it.visibility.print_with_space(it.def_id, cx), - constness = f.header.constness.print_with_space(), - asyncness = f.header.asyncness.print_with_space(), - unsafety = f.header.unsafety.print_with_space(), - abi = print_abi_with_space(f.header.abi), - name = it.name.as_ref().unwrap(), + vis = vis, + constness = constness, + asyncness = asyncness, + unsafety = unsafety, + abi = abi, + name = name, generics = f.generics.print(cx), where_clause = print_where_clause(&f.generics, cx, 0, true), decl = f.decl.full_print(header_len, 0, f.header.asyncness, cx), @@ -1291,7 +1300,7 @@ fn render_stability_since( render_stability_since_raw( w, item.stable_since(tcx).as_deref(), - item.const_stable_since(tcx).as_deref(), + item.const_stability(tcx), containing_item.stable_since(tcx).as_deref(), containing_item.const_stable_since(tcx).as_deref(), ) diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs index 2761f92ef5712..8c995b9426bbb 100644 --- a/src/test/rustdoc/const-display.rs +++ b/src/test/rustdoc/const-display.rs @@ -7,12 +7,20 @@ #![feature(foo, foo2)] #![feature(staged_api)] -// @has 'foo/fn.foo.html' '//pre' 'pub unsafe fn foo() -> u32' +// @has 'foo/fn.foo.html' '//pre' 'pub fn foo() -> u32' +// @has - '//span[@class="since"]' '1.0.0 (const: unstable)' #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="foo", issue = "none")] -pub const unsafe fn foo() -> u32 { 42 } +pub const fn foo() -> u32 { 42 } + +// @has 'foo/fn.foo_unsafe.html' '//pre' 'pub unsafe fn foo_unsafe() -> u32' +// @has - '//span[@class="since"]' '1.0.0 (const: unstable)' +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature="foo", issue = "none")] +pub const unsafe fn foo_unsafe() -> u32 { 42 } // @has 'foo/fn.foo2.html' '//pre' 'pub const fn foo2() -> u32' +// @!has - '//span[@class="since"]' #[unstable(feature = "humans", issue = "none")] pub const fn foo2() -> u32 { 42 } @@ -22,7 +30,9 @@ pub const fn foo2() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn bar2() -> u32 { 42 } + // @has 'foo/fn.foo2_gated.html' '//pre' 'pub const unsafe fn foo2_gated() -> u32' +// @!has - '//span[@class="since"]' #[unstable(feature = "foo2", issue = "none")] pub const unsafe fn foo2_gated() -> u32 { 42 } @@ -33,15 +43,23 @@ pub const unsafe fn foo2_gated() -> u32 { 42 } pub const unsafe fn bar2_gated() -> u32 { 42 } // @has 'foo/fn.bar_not_gated.html' '//pre' 'pub const unsafe fn bar_not_gated() -> u32' +// @!has - '//span[@class="since"]' pub const unsafe fn bar_not_gated() -> u32 { 42 } pub struct Foo; impl Foo { - // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32' + // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/code' 'pub fn gated() -> u32' + // @has - '//span[@class="since"]' '1.0.0 (const: unstable)' + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature="foo", issue = "none")] + pub const fn gated() -> u32 { 42 } + + // @has 'foo/struct.Foo.html' '//div[@id="method.gated_unsafe"]/code' 'pub unsafe fn gated_unsafe() -> u32' + // @has - '//span[@class="since"]' '1.0.0 (const: unstable)' #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="foo", issue = "none")] - pub const unsafe fn gated() -> u32 { 42 } + pub const unsafe fn gated_unsafe() -> u32 { 42 } // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32' // @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'