Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,9 @@ pub(crate) fn print_evaluated_const(
) -> Option<String> {
tcx.const_eval_poly(def_id).ok().and_then(|val| {
let ty = tcx.type_of(def_id).instantiate_identity();
if !ty.is_primitive() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't include all types that have literals, meaning it's stricter than is_literal_expr leading us to display fewer kinds of literals if extern compared to local.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having the filter after const_eval_poly means we're still evaluating assoc (and free) const items that were cross-crate inlined meaning it doesn't address the recent regression & its older "duplicates".

return None;
}
match (val, ty.kind()) {
(_, &ty::Ref(..)) => None,
(mir::ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
Expand Down Expand Up @@ -439,19 +442,16 @@ fn print_const_with_custom_print_scalar<'tcx>(
}

pub(crate) fn is_literal_expr(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
if let hir::Node::Expr(expr) = tcx.hir_node(hir_id) {
if let hir::ExprKind::Lit(_) = &expr.kind {
return true;
}

if let hir::ExprKind::Unary(hir::UnOp::Neg, expr) = &expr.kind
&& let hir::ExprKind::Lit(_) = &expr.kind
{
return true;
}
}

false
use ExprKind::{Lit, Path, Unary};
use hir::{Expr, ExprKind, Node, UnOp};

matches!(
tcx.hir_node(hir_id),
Node::Expr(Expr {
kind: Lit(_) | Path(_) | Unary(UnOp::Neg, Expr { kind: Lit(_) | Path(_), .. }),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path is hardly a primitive. We might want to rename this function to is_simple_expr.

..
})
)
}

/// Given a type Path, resolve it to a Type using the TyCtxt
Expand Down
40 changes: 11 additions & 29 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1920,9 +1920,19 @@ fn item_constant(
let tcx = cx.tcx();
render_attributes_in_code(w, it, "", cx)?;

let val = fmt::from_fn(|f| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we could continue using c.value() for free const items that don't have non-lifetime (generic) parameters since rustc evaluates them already anyway. 🤷 As I've said in a bunch of comments, we definitely want to stop evaluating associated const items by default.

However, if you consider it not worth the complexity we can leave like this for the time being.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, sorry about that, managed to get a bit lost on the way :)
Let me try to implement it and we'll see just how complex it ends up.

Copy link
Member

@fmease fmease Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addendum

I've now actually reviewed the code & have realized that you've modified item_constant which is called for free const items only (for assoc consts, it's fn assoc_const in render/mod.rs).

I actually want to take a step back. Your PR was originally only wanted to fix #150312 (ValTree's dbg repr leaking through) but I steered you towards also addressing the "diverging assoc consts" issues while you're at it. As a result, it feels a bit tangled & confusing to me. I'm sorry about that.

I'll spin up a separate PR that exclusively fixes the new regression and doesn't try to restrict the kinds of const exprs since the latter doesn't have any time pressure.

Feel free to revert back to the initial version which I can then review w/o having the "divering assoc consts" issues in mind.

let is_literal = c.is_literal(tcx);
let expr = c.expr(tcx);
if is_literal {
write!(f, " = {expr}", expr = Escape(&expr))
} else {
f.write_str(" = _")
}
});

write!(
w,
"{vis}const {name}{generics}: {typ}{where_clause}",
"{vis}const {name}{generics}: {typ}{val}{where_clause};",
vis = visibility_print_with_space(it, cx),
name = it.name.unwrap(),
generics = print_generics(generics, cx),
Expand All @@ -1931,34 +1941,6 @@ fn item_constant(
print_where_clause(generics, cx, 0, Ending::NoNewline).maybe_display(),
)?;

// FIXME: The code below now prints
// ` = _; // 100i32`
// if the expression is
// `50 + 50`
// which looks just wrong.
// Should we print
// ` = 100i32;`
// instead?

let value = c.value(tcx);
let is_literal = c.is_literal(tcx);
let expr = c.expr(tcx);
if value.is_some() || is_literal {
write!(w, " = {expr};", expr = Escape(&expr))?;
} else {
w.write_str(";")?;
}

if !is_literal && let Some(value) = &value {
let value_lowercase = value.to_lowercase();
let expr_lowercase = expr.to_lowercase();

if value_lowercase != expr_lowercase
&& value_lowercase.trim_end_matches("i32") != expr_lowercase
{
write!(w, " // {value}", value = Escape(value))?;
}
}
Ok::<(), fmt::Error>(())
})?;

Expand Down
4 changes: 2 additions & 2 deletions tests/rustdoc-html/constant/const-value-display.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#![crate_name = "foo"]

//@ has 'foo/constant.HOUR_IN_SECONDS.html'
//@ has - '//*[@class="rust item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = _; // 3_600u64'
//@ has - '//*[@class="rust item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = _;'
pub const HOUR_IN_SECONDS: u64 = 60 * 60;

//@ has 'foo/constant.NEGATIVE.html'
//@ has - '//*[@class="rust item-decl"]//code' 'pub const NEGATIVE: i64 = _; // -3_600i64'
//@ has - '//*[@class="rust item-decl"]//code' 'pub const NEGATIVE: i64 = _;'
pub const NEGATIVE: i64 = -60 * 60;
2 changes: 1 addition & 1 deletion tests/rustdoc-html/constant/generic-const-items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

//@ has 'generic_const_items/constant.K.html'
//@ has - '//*[@class="rust item-decl"]//code' \
// "pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> \
// "pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> = None \
// where \
// String: From<T>;"
pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> = None
Expand Down
16 changes: 7 additions & 9 deletions tests/rustdoc-html/constant/show-const-contents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ pub const CONST_NEG_I32: i32 = -42;
//@ !hasraw show_const_contents/constant.CONST_EQ_TO_VALUE_I32.html '// 42i32'
pub const CONST_EQ_TO_VALUE_I32: i32 = 42i32;

//@ hasraw show_const_contents/constant.CONST_CALC_I32.html '= _; // 43i32'
//@ hasraw show_const_contents/constant.CONST_CALC_I32.html '= _;'
pub const CONST_CALC_I32: i32 = 42 + 1;

//@ !hasraw show_const_contents/constant.CONST_REF_I32.html '= &42;'
//@ !hasraw show_const_contents/constant.CONST_REF_I32.html '; //'
pub const CONST_REF_I32: &'static i32 = &42;

//@ hasraw show_const_contents/constant.CONST_I32_MAX.html '= i32::MAX; // 2_147_483_647i32'
//@ hasraw show_const_contents/constant.CONST_I32_MAX.html '= i32::MAX;'
pub const CONST_I32_MAX: i32 = i32::MAX;

//@ !hasraw show_const_contents/constant.UNIT.html '= ();'
Expand All @@ -47,21 +47,19 @@ pub struct MyTypeWithStr(&'static str);
//@ !hasraw show_const_contents/constant.MY_TYPE_WITH_STR.html '; //'
pub const MY_TYPE_WITH_STR: MyTypeWithStr = MyTypeWithStr("show this");

//@ hasraw show_const_contents/constant.PI.html '= 3.14159265358979323846264338327950288_f32;'
//@ hasraw show_const_contents/constant.PI.html '; // 3.14159274f32'
//@ hasraw show_const_contents/constant.PI.html '= _;'
pub use std::f32::consts::PI;

//@ hasraw show_const_contents/constant.MAX.html '= i32::MAX; // 2_147_483_647i32'
//@ hasraw show_const_contents/constant.MAX.html '= i32::MAX;'
#[allow(deprecated, deprecated_in_future)]
pub use std::i32::MAX;

macro_rules! int_module {
($T:ident) => (
($T:ident) => {
pub const MIN: $T = $T::MIN;
)
};
}

//@ hasraw show_const_contents/constant.MIN.html '= i16::MIN; // -32_768i16'
//@ hasraw show_const_contents/constant.MIN.html '= i16::MIN;'
int_module!(i16);

//@ has show_const_contents/constant.ESCAPE.html //pre '= r#"<script>alert("ESCAPE");</script>"#;'
Expand Down
2 changes: 1 addition & 1 deletion tests/rustdoc-html/inline_cross/generic-const-items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

//@ has 'user/constant.K.html'
//@ has - '//*[@class="rust item-decl"]//code' \
// "pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> \
// "pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> = _ \
// where \
// String: From<T>;"
pub use generic_const_items::K;
Expand Down
18 changes: 18 additions & 0 deletions tests/rustdoc-html/non-primitive-assoc-const-150312.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![crate_name = "foo"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also please add a comment explaining what this is testing (we should maybe enforce that in all tests).


pub trait Foo {
type AssocType;

const THE_CONST: Self::AssocType;
}

pub struct Bar;

impl Foo for Bar {
type AssocType = (u32,);

//@ has foo/struct.Bar.html
//@ matches - '//section[@id="associatedconstant.THE_CONST"]/h4[@class="code-header"]' '^const THE_CONST: Self::AssocType'
//@ !matches - '//section[@id="associatedconstant.THE_CONST"]//*[last()]' '{transmute'
const THE_CONST: Self::AssocType = (1u32,);
}
2 changes: 1 addition & 1 deletion tests/rustdoc-ui/const-evalutation-ice.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//@ check-pass
// Just check we don't get an ICE for `N`.

use std::cell::Cell;
Expand All @@ -8,4 +9,3 @@ pub struct S {
}

pub const N: usize = 0 - (mem::size_of::<S>() != 400) as usize;
//~^ ERROR overflow
9 changes: 0 additions & 9 deletions tests/rustdoc-ui/const-evalutation-ice.stderr

This file was deleted.

2 changes: 1 addition & 1 deletion tests/rustdoc-ui/issues/issue-79494.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ check-pass
//@ only-64bit

#![feature(const_transmute)]

pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
//~^ ERROR transmuting from 8-byte type to 16-byte type
9 changes: 0 additions & 9 deletions tests/rustdoc-ui/issues/issue-79494.stderr

This file was deleted.

8 changes: 1 addition & 7 deletions tests/rustdoc-ui/track-diagnostics.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
//@ check-pass
//@ compile-flags: -Z track-diagnostics

// Normalize the emitted location so this doesn't need
// updating everytime someone adds or removes a line.
//@ normalize-stderr: ".rs:\d+:\d+" -> ".rs:LL:CC"

struct A;
struct B;

pub const S: A = B;
//~^ ERROR mismatched types
//~| NOTE created at
//~| NOTE expected `A`, found `B`
11 changes: 0 additions & 11 deletions tests/rustdoc-ui/track-diagnostics.stderr

This file was deleted.

Loading