about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/html/format.rs26
-rw-r--r--src/librustdoc/html/render/mod.rs62
-rw-r--r--src/librustdoc/html/render/print_item.rs49
-rw-r--r--src/test/rustdoc/const-display.rs26
4 files changed, 112 insertions, 51 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 918a5cb5094..58c609cf252 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 62d3c142eeb..03b607c2d2c 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,
                 "<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>",
-                v, cv
+                v, since
             );
         }
+        // stable and const unstable
+        (
+            Some(v),
+            Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }),
+        ) => {
+            write!(
+                w,
+                "<span class=\"since\" title=\"Stable since Rust version {0}, const unstable\">{0} (const: ",
+                v
+            );
+            if let Some(n) = issue {
+                write!(
+                    w,
+                    "<a href=\"https://github.com/rust-lang/rust/issues/{}\" title=\"Tracking issue for {}\">unstable</a>",
+                    n, feature
+                );
+            } else {
+                write!(w, "unstable");
+            }
+            write!(w, ")</span>");
+        }
+        // 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 + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
         write!(
             w,
-            "{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
+            "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
              {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 48cbd94ccab..0174bfec32d 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("<pre class=\"rust fn\">");
     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}</pre>",
-        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 2761f92ef57..8c995b9426b 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)'