authorbors <bors@rust-lang.org> 2026-01-17 16:15:18 UTC
committerbors <bors@rust-lang.org> 2026-01-17 16:15:18 UTC
logfe98ddcfcfb6f185dbf4adeaf439d8a756da0273
treef18aad59d84cb99132bb0545af5ac2e8b3b23e6f
parent9f6cd6defbd7ef13f6777aa8e43b14d69f0a830a
parentac8e8505b7c12d826f970e8e8ec8c18b067c6dc8

Auto merge of #151232 - fmease:rustdoc-dont-eval-assoc-consts, r=yotamofek

rustdoc: Stop unconditionally evaluating the initializer of associated consts See the descriptions of the added tests for details. Fixes rust-lang/rust#131625. Fixes [after beta-1.93 backport] rust-lang/rust#149635. Fixes rust-lang/rust#150312. Supersedes rust-lang/rust#150629 IINM. CC @cuviper (https://github.com/rust-lang/rust/issues/149635#issuecomment-3761125727) r? @GuillaumeGomez or @yotamofek (rust-lang/rust#150629)

9 files changed, 75 insertions(+), 14 deletions(-)

src/librustdoc/html/render/mod.rs+3-6
......@@ -1050,14 +1050,11 @@ fn assoc_const(
10501050 ty = print_type(ty, cx),
10511051 )?;
10521052 if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value {
1053 // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
1054 // hood which adds noisy underscores and a type suffix to number literals.
1055 // This hurts readability in this context especially when more complex expressions
1056 // are involved and it doesn't add much of value.
1057 // Find a way to print constants here without all that jazz.
1058 let repr = konst.value(tcx).unwrap_or_else(|| konst.expr(tcx));
1053 let repr = konst.expr(tcx);
10591054 if match value {
10601055 AssocConstValue::TraitDefault(_) => true, // always show
1056 // FIXME: Comparing against the special string "_" denoting overly complex const exprs
1057 // is rather hacky; `ConstKind::expr` should have a richer return type.
10611058 AssocConstValue::Impl(_) => repr != "_", // show if there is a meaningful value to show
10621059 AssocConstValue::None => unreachable!(),
10631060 } {
tests/rustdoc-html/anchors/anchors.no_const_anchor2.html+1-1
......@@ -1 +1 @@
1<section id="associatedconstant.X" class="associatedconstant"><a class="src rightside" href="../src/foo/anchors.rs.html#42">Source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
\ No newline at end of file
1<section id="associatedconstant.X" class="associatedconstant"><a class="src rightside" href="../src/foo/anchors.rs.html#42">Source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0</h4></section>
\ No newline at end of file
tests/rustdoc-html/attributes.rs+1-1
......@@ -59,7 +59,7 @@ pub enum Enum {
5959pub trait Trait {
6060 //@ has 'foo/trait.Trait.html'
6161 //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]/*[@class="code-attribute"]' '#[unsafe(link_section = "bar")]'
62 //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' 'const BAR: u32 = 0u32'
62 //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' 'const BAR: u32 = 0'
6363 #[unsafe(link_section = "bar")]
6464 const BAR: u32 = 0;
6565
tests/rustdoc-html/constant/assoc-const-has-projection-ty.rs created+31
......@@ -0,0 +1,31 @@
1// Ensure that we properly print the value `1` as `1` in the initializer of associated constants
2// that have user type "projection".
3//
4// We once used to evaluate the initializer in rustdoc and use rustc's MIR pretty-printer to
5// render the resulting MIR const value. This pretty printer matches on the type to interpret
6// the data and falls back to a cryptic `"{transmute(0x$data): $ty}"` for types it can't handle.
7// Crucially, when constructing the MIR const we passed the unnormalized type of the initializer,
8// i.e., the projection `<Struct as Trait>::Ty` instead of the normalized `u32` which the
9// pretty printer obviously can't handle.
10//
11// Now we no longer evaluate it and use a custom printer for the const expr.
12//
13// issue: <https://github.com/rust-lang/rust/issues/150312>
14
15#![crate_name = "it"]
16
17pub trait Trait {
18 type Ty;
19
20 const CT: Self::Ty;
21}
22
23pub struct Struct;
24
25impl Trait for Struct {
26 type Ty = u32;
27
28 //@ has it/struct.Struct.html
29 //@ has - '//*[@id="associatedconstant.CT"]' 'const CT: Self::Ty = 1'
30 const CT: Self::Ty = 1;
31}
tests/rustdoc-html/constant/assoc-consts.rs+1-1
......@@ -1,6 +1,6 @@
11pub trait Foo {
22 //@ has assoc_consts/trait.Foo.html '//pre[@class="rust item-decl"]' \
3 // 'const FOO: usize = 13usize;'
3 // 'const FOO: usize = _;'
44 //@ has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
55 const FOO: usize = 12 + 1;
66 //@ has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool'
tests/rustdoc-html/deref/deref-to-primitive.rs+1-1
......@@ -3,7 +3,7 @@
33//@ has 'foo/struct.Foo.html'
44//@ has - '//*[@id="deref-methods-i32"]' 'Methods from Deref<Target = i32>'
55//@ has - '//*[@id="deref-methods-i32-1"]//*[@id="associatedconstant.BITS"]/h4' \
6// 'pub const BITS: u32 = 32u32'
6// 'pub const BITS: u32 = u32::BITS'
77pub struct Foo(i32);
88
99impl std::ops::Deref for Foo {
tests/rustdoc-html/display-hidden-items.rs+2-2
......@@ -20,7 +20,7 @@ pub trait TraitHidden {}
2020//@ has 'foo/index.html' '//dt/a[@class="trait"]' 'Trait'
2121pub trait Trait {
2222 //@ has 'foo/trait.Trait.html'
23 //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0u32'
23 //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0'
2424 #[doc(hidden)]
2525 const BAR: u32 = 0;
2626
......@@ -44,7 +44,7 @@ impl Struct {
4444}
4545
4646impl Trait for Struct {
47 //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0u32'
47 //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0'
4848 //@ has - '//*[@id="method.foo"]/*[@class="code-header"]' '#[doc(hidden)] fn foo()'
4949}
5050//@ has - '//*[@id="impl-TraitHidden-for-Struct"]/*[@class="code-header"]' 'impl TraitHidden for Struct'
tests/rustdoc-html/impl/impl-associated-items-order.rs+2-2
......@@ -16,7 +16,7 @@ impl Bar {
1616 // 'pub fn foo()'
1717 pub fn foo() {}
1818 //@ has - '//*[@id="implementations-list"]//*[@class="impl-items"]/section[1]/h4' \
19 // 'pub const X: u8 = 12u8'
19 // 'pub const X: u8 = 12'
2020 pub const X: u8 = 12;
2121 //@ has - '//*[@id="implementations-list"]//*[@class="impl-items"]/section[2]/h4' \
2222 // 'pub type Y = u8'
......@@ -34,7 +34,7 @@ impl Foo for Bar {
3434 // 'type Z = u8'
3535 type Z = u8;
3636 //@ has - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]/section[1]/h4' \
37 // 'const W: u32 = 12u32'
37 // 'const W: u32 = 12'
3838 const W: u32 = 12;
3939 //@ has - '//*[@id="trait-implementations-list"]//*[@class="impl-items"]/section[3]/h4' \
4040 // 'fn yeay()'
tests/rustdoc-ui/diverging-assoc-consts.rs created+33
......@@ -0,0 +1,33 @@
1// Ensure that we don't unconditionally evaluate the initializer of associated constants.
2//
3// We once used to evaluate them so we could display more kinds of expressions
4// (like `1 + 1` as `2`) given the fact that we generally only want to render
5// literals (otherwise we would risk dumping extremely large exprs or leaking
6// private struct fields).
7//
8// However, that deviated from rustc's behavior, made rustdoc accept less code
9// and was understandably surprising to users. So let's not.
10//
11// In the future we *might* provide users a mechanism to control this behavior.
12// E.g., via a new `#[doc(...)]` attribute.
13//
14// See also:
15// issue: <https://github.com/rust-lang/rust/issues/131625>
16// issue: <https://github.com/rust-lang/rust/issues/149635>
17
18//@ check-pass
19
20pub struct Type;
21
22impl Type {
23 pub const K0: () = panic!();
24 pub const K1: std::convert::Infallible = loop {};
25}
26
27pub trait Trait {
28 const K2: i32 = panic!();
29}
30
31impl Trait for Type {
32 const K2: i32 = loop {};
33}