rust-lang / rust-lang/rust

broken link in proc-macro-generated doc referencing later-defined macro (--document-private-items)

Open
#157,304 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug needs-triage T-rustdoc
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Code

https://www.chiark.greenend.org.uk/ucgi/~ian/git?p=rust-experiments.git;a=shortlog;h=refs/heads/rustdoc-link-2026-06

Reproduction Steps

git clone https://www.chiark.greenend.org.uk/ucgi/~ian/githttp/rust-experiments.git -b rustdoc-link-2026-06
cd rust-experiments
cargo doc --workspace --all-features --document-private-items

Expected Outcome

warning: unresolved link to `later`

Actual Output

No errors, but documentation has a broken link. To see the broken link:

  1. In your browser, visit the local path printed by the rustdoc rune
  2. Click on the entry for the macro earlier derive_deftly_template_Earlier
  3. Click on the word "Reference" (which is the start of the body of the doc comment)
  4. You're now visiting a file .../rust-experiments/target/doc/foo/later which does not exist

Version

rustdoc 1.96.0-beta.5 (a5a9a5438 2026-05-01)

Additional Details

Ordering is relevant

AFAICT the link is not resolved because it's a forward reference to a macro_rules macro. Swapping the definition of later to before Earlier makes the link resolve.

Exporting is might be relevant

Adding #[macro_export] to the definitions (via the export keyword to the derive-deflty call if necessary) makes it work.

But with the MCVE, it doesn't seem to make any difference.

Either spans, or merely the involvement of a proc macro, seem to be relevant

Update: for a repro without any external crates, see below.

I was not able to reproduce this without derive-deftly. The define_derive_deftly call in lib.rs expands to this:

#[doc = " Doc comment"] #[doc = ""] #[doc = " [Reference](later)"]
#[doc =
"\n\nThis is a `derive_deftly` template.  Do not invoke it directly.\nTo use it, write: `#[derive(Deftly)] #[derive_deftly(Earlier)]`."]
macro_rules! derive_deftly_template_Earlier
{
    [ actual macro body elided for clarity ]
}

You can get that output yourself with a rune like this:
RUSTFLAGS="--cfg derive_deftly_dprint" DERIVE_DEFTLY_DPRINT=1 cargo doc --workspace --all-features --document-private-items

But, when I replace the define_derive_deftly! call with a cut-and-paste of the whole expansion (as printed via the TokenStream's Display impl) the bug goes away: I get the warning as expected.

I experimented with replacing the define_derive_deftly call with a macro_rules macro whose expansion was a c&p of the derive-deftly output, but that also didn't repro the bug.

It may be relevant that for Reasons, derive-deftly respans its output using .resolved_at(Span::call_site) . For terminal TTs it then uses .set_span(). For groups it must use Group::new (via proc_macro2::Group::new). The precise code can be seen here https://gitlab.torproject.org/Diziet/rust-derive-deftly/-/blob/03493e38977328ce1cfd89bad38a868538479419/macros/utils.rs#L200

However, I don't think any of this should cause rustdoc to emit HTML containing broken links.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the issue with the linked rust-experiments branch using cargo doc --workspace --all-features --document-private-items, then inspect the generated page for the earlier macro and its later link. Compare the proc-macro expansion with the copied expansion and review derive-deftly's macros/utils.rs span handling. Done means rustdoc correctly resolves the forward reference or reports the broken link.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers, documentation
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.