Skip to content

rustdoc extreme slowdown with cyclic generic structures #160105

Description

@fjarri

Consider this MRE:

#![no_std]

extern crate alloc;

use alloc::{
    collections::{BTreeMap, BTreeSet},
    string::String,
    sync::Arc,
};

pub trait Erasable: Sync {}

impl<T> Erasable for T where T: Sync {}

pub trait SessionParameters {
    type Verifier;
}

pub struct Node<T>(pub Arc<T>);

pub struct ComputeScalar<SP: SessionParameters> {
    pub args: BTreeMap<String, ComputeScalarArg<SP>>,
    pub dependencies: Dependency<SP>,
}

pub struct Collect<SP: SessionParameters> {
    pub values: CollectArg<SP>,
    pub dependencies: Dependency<SP>,
}

pub struct ComputeMapping<SP: SessionParameters> {
    pub args: BTreeMap<String, ComputeMappingArg<SP>>,
    pub dependencies: Dependency<SP>,
}

pub struct SerializeAndSignBC<SP: SessionParameters> {
    pub data: Node<ComputeScalar<SP>>,
    pub dependencies: Dependency<SP>,
}

pub struct SerializeAndSignDM<SP: SessionParameters> {
    pub data: DirectMessageArg<SP>,
    pub dependencies: Dependency<SP>,
}

pub struct DeserializeAndCheck<SP: SessionParameters> {
    pub data: Node<Receive<SP>>,
    pub dependencies: Dependency<SP>,
}

pub struct SendDM<SP: SessionParameters> {
    pub data: Node<SerializeAndSignDM<SP>>,
    pub dependencies: Dependency<SP>,
}

pub struct SendBC<SP: SessionParameters> {
    pub data: Node<SerializeAndSignBC<SP>>,
    pub destinations: BTreeSet<SP::Verifier>,
    pub dependencies: Dependency<SP>,
}

pub struct Receive<SP: SessionParameters> {
    pub dependencies: Dependency<SP>,
}

pub struct MergeScalars<SP: SessionParameters> {
    pub left: ComputeScalarArg<SP>,
    pub right: ComputeScalarArg<SP>,
}

pub enum ComputeScalarArg<SP: SessionParameters> {
    ComputeScalar(Node<ComputeScalar<SP>>),
    MergeScalars(Node<MergeScalars<SP>>),
    Collect(Node<Collect<SP>>),
}

pub enum ComputeMappingArg<SP: SessionParameters> {
    ComputeScalar(Node<ComputeScalar<SP>>),
    MergeScalars(Node<MergeScalars<SP>>),
    Collect(Node<Collect<SP>>),
    ComputeMapping(Node<ComputeMapping<SP>>),
    SerializeAndSignBC(Node<SerializeAndSignBC<SP>>),
    SerializeAndSignDM(Node<SerializeAndSignDM<SP>>),
    DeserializeAndCheck(Node<DeserializeAndCheck<SP>>),
}

pub enum CollectArg<SP: SessionParameters> {
    ComputeMapping(Node<ComputeMapping<SP>>),
    SerializeAndSign(Node<SerializeAndSignDM<SP>>),
    DeserializeAndCheck(Node<DeserializeAndCheck<SP>>),
    Send(Node<SendDM<SP>>),
    Receive(Node<Receive<SP>>),
}

pub enum DirectMessageArg<SP: SessionParameters> {
    ComputeScalar(Node<ComputeScalar<SP>>),
    ComputeMapping(Node<ComputeMapping<SP>>),
    DeserializeAndCheck(Node<DeserializeAndCheck<SP>>),
}

pub enum Dependency<SP: SessionParameters> {
    ComputeScalar(Node<ComputeScalar<SP>>),
    Collect(Node<Collect<SP>>),
    MergeScalars(Node<MergeScalars<SP>>),
    SendBC(Node<SendBC<SP>>),
}

After creating a new library crate for it, running cargo doc --no-deps takes ~2 minutes on my machine. Removing the blanket impl impl<T> Erasable for T where T: Sync {} reduces the time to 0.5 seconds.

The problem seems to be caused by a combination of:

  • a public trait with a blanket impl
  • the trait is bound on Sync
  • closed loops of connections of structures to their fields (e.g. ComputeScalar -> Dependency -> ComputeScalar)
  • structures being generic
  • the trait that's the bound for that generic type having an associated type, and that type being used in some structs
  • some fields being BTreeMap/BTreeSet of other structs

Removing any one of these either removes the problem completely, or reduces the documentation generation time dramatically (e.g. from 2 minutes to 10 seconds, which is still disproportionately much, of course).

Meta

rustc --version --verbose:

rustc 1.97.1 (8bab26f4f 2026-07-14)
binary: rustc
commit-hash: 8bab26f4f68e0e26f0bb7960be334d5b520ea452
commit-date: 2026-07-14
host: aarch64-apple-darwin
release: 1.97.1
LLVM version: 22.1.6

Also tried on nightly, with the same results:

rustc 1.99.0-nightly (dc3f85158 2026-07-26)
binary: rustc
commit-hash: dc3f85158a955a87a6e4363af1fbe9cf2d063cce
commit-date: 2026-07-26
host: aarch64-apple-darwin
release: 1.99.0-nightly
LLVM version: 22.1.8

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-synthetic-implsArea: Synthetic impls, used by rustdoc to document auto traits and traits with blanket implsC-bugCategory: This is a bug.I-compiletimeIssue: Problems and improvements with respect to compile times.T-rustdocRelevant to the rustdoc team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions