rust-lang / rust-lang/rust

rustc borrowck free-region closure is superlinear for explicit lifetime chains

Open
#158,175 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-borrow-checker C-bug I-compiletime needs-triage
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I tried this code:

cat > free_region_lifetime_chain_repro.py <<'PY'
#!/usr/bin/env python3
import os
import subprocess
import time
from pathlib import Path

N = int(os.environ.get("N", "6400"))
RUSTC = os.environ.get("RUSTC", "rustc")


def write_lifetime_chain(path: Path) -> None:
    lifetimes = ", ".join(f"'a{i}" for i in range(N))
    args = ", ".join(f"_x{i}: &'a{i} u8" for i in range(N))
    where_clauses = ", ".join(f"'a{i}: 'a{i + 1}" for i in range(N - 1))
    path.write_text(
        "#![allow(dead_code, unused_variables)]\n"
        f"pub fn f<{lifetimes}>({args})\n"
        f"where\n    {where_clauses}\n"
        "{\n}\n",
        encoding="utf-8",
    )


src = Path(f"free_region_chain_{N}.rs")
write_lifetime_chain(src)
out = Path(f"free_region_chain_{N}.rmeta")

start = time.perf_counter()
proc = subprocess.run(
    [
        RUSTC,
        "--edition=2024",
        "--crate-type=lib",
        "--emit=metadata",
        "-Awarnings",
        str(src),
        "-o",
        str(out),
    ],
    stdout=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
    check=False,
)
seconds = time.perf_counter() - start
print(f"lifetimes={N} status={proc.returncode} elapsed={seconds:.3f}s source={src.stat().st_size}")
PY

RUSTC=/path/to/rustc N=6400 python3 free_region_lifetime_chain_repro.py

I expected to see this happen: explanation

Instead, this happened: explanation

Meta

rustc --version --verbose:

4008bbdf34b

The generated version just extends this pattern to thousands of lifetime
parameters. The program is valid and compiles successfully; this does not rely on
a diagnostic path, rustdoc, macro expansion, or failing compilation.

With N=6400, I see:

lifetimes=6400 status=0 elapsed=12.307s

Here are the timings I collected with the same rustc binary:

lifetimes  exit_status  elapsed_s
800        0            0.116
1600       0            0.432
3200       0            2.267
6400       0            12.307

The source size grows linearly, but compile time grows much faster than linearly.

Backtrace

<backtrace>

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

Start by running free_region_lifetime_chain_repro.py with the reported rustc binary and compare timings across N values. Then trace the compiler's borrow-checking path for explicit lifetime outlives constraints; done means the generated valid program no longer shows superlinear compile-time growth, with a regression test or benchmark covering the chain.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.