Skip to content

Search manifest ancestors for the lockfile when fetching cargo metadata - #23296

Open
onlycs wants to merge 1 commit into
rust-lang:masterfrom
onlycs:rustc-src-lockfile-ancestors
Open

Search manifest ancestors for the lockfile when fetching cargo metadata#23296
onlycs wants to merge 1 commit into
rust-lang:masterfrom
onlycs:rustc-src-lockfile-ancestors

Conversation

@onlycs

@onlycs onlycs commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Problem

With a nix toolchain, every macro-generated TyCtxt query getter (tcx.mir_keys(()), e.g.) resolves to {unknown}. Three independent bugs cause this, one of which was fixed in 7015591, one with #23297, and one in this PR

the rustc-src lockfile is never found

The rustc-dev component ships compiler sources as [rustc-src]/rust/compiler/rustc/Cargo.toml, with no workspace root manifest. The lockfile lives two levels up at [rustc-src]/rust/Cargo.lock. FetchMetadata::new only looks for a lockfile directly next to the manifest, so the rustc metadata fetch runs --locked with no lockfile available. In a read-only store, cargo cannot create one and errors:

error: cannot create the lock file /nix/store/…/rustc-src/rust/compiler/rustc/Cargo.lock
because --locked was passed to prevent this

FetchMetadata::exec then silently falls back to the --no-deps pre-fetch, whose metadata contains only the rustc-main stub package. rustc_middle, rustc_hir, etc. never enter the crate graph.

Instead, we walk up the manifest's ancestor directories to find the lockfile, then reuse the existing lockfile-copy mechanism.

AI disclosure

These changes were authored with AI assistance (Claude Code); the commits carry Co-Authored-By trailers. I have reviewed the changes, use them in a current project using a patched build, and can answer questions about them myself.

See also: #23251

Version Info

cargo: cargo 1.99.0-nightly (eb98b54bc 2026-08-11)

Toolchain: nightly-2026-08-14, components rustc-dev, llvm-tools-preview, rust-src.

Configuration (Zed, .zed/settings.json):

{
  "lsp": {
    "rust-analyzer": {
      "initialization_options": {
        "rustc": {
          "source": "discover"
        }
      }
    }
  }
}

…data

The rustc-dev dist component ships the compiler sources with
`rustc-src/rust/compiler/rustc/Cargo.toml` as the entry manifest, but
without a workspace root manifest next to the lockfile, which lives at
`rustc-src/rust/Cargo.lock`. FetchMetadata only looked for a lockfile
right next to the manifest, so for `rust-analyzer.rustc.source =
"discover"` setups the metadata fetch ran with `--locked` and no usable
lockfile. On read-only toolchain installations (e.g. rustup toolchains on
nix) cargo then fails to create one, and rust-analyzer silently degrades
to `--no-deps` metadata, dropping rustc_middle and friends from the crate
graph entirely - rustc_private projects lose all type information for
rustc crates.

Walk up from the manifest to find the lockfile and reuse the existing
lockfile-copy mechanism, which keeps cargo from touching the original.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 4, 2026
@ChayimFriedman2

Copy link
Copy Markdown
Contributor

It should point at compiler/rustc/Cargo.toml and not at the top level Cargo.toml, and that works fine for me. Is Nix different? What are your rust-analyzer settings?

@onlycs

onlycs commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Yes, it should. But there is no compiler/rustc/Cargo.lock, and (currently) it only points at that unless there's a workspace manifest, which there isn't in the case of rustc.

To be a bit more specific, the directory structure is:

[rust-src]
├── Cargo.lock
├── ... # (no Cargo.toml here)
└── compiler
    ├── ...
    └── rustc
        ├── ...  # (no Cargo.lock)
        └── Cargo.toml

What happened before:

  1. RA sees Cargo.toml and does a metadata fetch assuming Cargo.lock is in the same directory
  2. There is no Cargo.lock in the same directory, and since --locked is used, cargo errors
  3. RA falls back to --no-deps mode, so other rustc components never enter the crate graph

What happens in this PR:

  1. RA sees Cargo.toml and finds the closest ancestor directory that has a Cargo.lock
  2. The metadata fetch points to a Cargo.lock that exists and succeeds
  3. Other components enter the crate graph

@ChayimFriedman2

Copy link
Copy Markdown
Contributor

Indeed it does not find the lockfile, but Cargo should find it itself. Why doesn't it for you?

@onlycs

onlycs commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Cargo never searches ancestor directories for a Cargo.lock, it only searches for a workspace root manifest. If this were the case, the lockfile lives next to that manifest.

The rustc-dev component ships with [rust]/Cargo.lock but not [rust]/Cargo.toml, i.e. the workspace root manifest is stripped from the dist tarball.

You can show this with

$ cargo locate-project --workspace --manifest-path <sysroot>/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml
{"root":".../rustc-src/rust/compiler/rustc/Cargo.toml"}

Cargo believes the lockfile lives in compiler/rustc/Cargo.lock which doesn't exist. This is not a nix-specific issue.

@onlycs

onlycs commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

If you want a full repro, pull the latest rustc-dev release tarball:

$ curl -O https://static.rust-lang.org/dist/2026-09-10/rustc-dev-nightly-x86_64-unknown-linux-gnu.tar.xz # download latest rustc-dev
$ tar -xJf rustc-dev-nightly-x86_64-unknown-linux-gnu.tar.xz --wildcards '*/rustc-src/*' # extract the relevant directory
$ cd rustc-dev-nightly-x86_64-unknown-linux-gnu/rustc-dev/lib/rustlib/rustc-src/rust
$ ls
Cargo.lock  compiler  library # notably: no Cargo.toml
$ cargo locate-project --workspace --manifest-path compiler/rustc/Cargo.toml
{"root":".../rustc-src/rust/compiler/rustc/Cargo.toml"}
$ cargo metadata --format-version 1 --manifest-path compiler/rustc/Cargo.toml --locked
error: cannot create the lock file ....

@ChayimFriedman2

Copy link
Copy Markdown
Contributor

Hmm I was indeed testing with local rustc clone. But then I think the best answer is to include the workspace Cargo.toml rustc-dev (or a modified version of it). We don't want to change the lockfile anyway.

@onlycs

onlycs commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Sorry, but I am a little confused. The lockfile doesn't change; --locked is used when fetching metadata. And, as far as I am aware, RA doesn't have control over rustc component packaging.

@ChayimFriedman2

Copy link
Copy Markdown
Contributor

The lockfile doesn't change; --locked is used when fetching metadata.

Not if we copy to a temporary lockfile.

And, as far as I am aware, RA doesn't have control over rustc component packaging.

Not directly, but we can request nicely and I see no reason t-compiler will refuse.

@Veykril

Veykril commented Sep 11, 2026

Copy link
Copy Markdown
Member

This sounds like we should pass the expected lock file path to our fetch infra and have the rustc source discovery hardcode the expected relative path for it

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

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants