rust-lang / rust-lang/rust-analyzer

Using `proc-macro` in `build.rs` causes high cpu usage

Open
#19,361 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug
Dominant language
Rust
Stars
16.9k
Forks
2.2k
Avg merge
1d 12h
Merged PRs (30d)
72

Description

The rust-analyzer cannot handle big structs with proc-macros, in this case serde's derive macro, in build.rs properly. By adding more fields to a struct, it spins up CPU usage to 100% almost exponentially.

Steps:

  1. Write the following mentioned code in build.rs
  2. Rerun the editor
  3. After finishing the first run compilation, try to edit the code
  4. You will notice that the rust-analyzer uses 100% of a single core CPU usage for a long time and the LSP functionality will be blocked

NOTE 1: More fields, much longer wait time. For a struct with 200 fields, it goes into an almost infinite loop.
NOTE 2: It's just bound to build.rs and it works fine in lib.rs.

rust-analyzer version: rust-analyzer 1.87.0-nightly (9fb94b3 2025-03-10)

rustc version: rustc 1.87.0-nightly (9fb94b32d 2025-03-10)

editor or extension: neovim

relevant settings: enabled procMacro and buildScript features.

rust-analyzer command: cargo clippy --message-format=json --all-targets --all-features

repository link (if public, optional): N/A

code snippet to reproduce:

// Cargo.toml
[package]
name = "test_script"
version = "0.1.0"
edition = "2024"

[build-dependencies]
serde = { version = "1.0.219", features = ["derive"] }

// build.rs
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Translations {
    pub af: Option<String>,
    pub am: Option<String>,
    pub ar: Option<String>,
    pub az: Option<String>,
    pub be: Option<String>,
    pub bg: Option<String>,
    pub bn: Option<String>,
    pub ca: Option<String>,
    pub cs: Option<String>,
    pub da: Option<String>,
    pub de: Option<String>,
    pub el: Option<String>,
    pub en: Option<String>,
    pub es: Option<String>,
    pub et: Option<String>,
    pub eu: Option<String>,
    pub fa: Option<String>,
    pub fi: Option<String>,
    pub fr: Option<String>,
    pub gl: Option<String>,
    pub gu: Option<String>,
    pub he: Option<String>,
    pub hi: Option<String>,
    pub hr: Option<String>,
    pub hu: Option<String>,
    pub hy: Option<String>,
    pub id: Option<String>,
    pub is: Option<String>,
    pub it: Option<String>,
    pub ja: Option<String>,
    pub ka: Option<String>,
    pub kn: Option<String>,
    pub ko: Option<String>,
    pub lt: Option<String>,
    pub lv: Option<String>,
    pub ml: Option<String>,
    pub mn: Option<String>,
    pub mr: Option<String>,
    pub ms: Option<String>,
    pub nb: Option<String>,
    pub nl: Option<String>,
    pub pl: Option<String>,
    pub ps: Option<String>,
    pub pt: Option<String>,
    pub ro: Option<String>,
    pub ru: Option<String>,
    pub si: Option<String>,
    pub sk: Option<String>,
    pub sl: Option<String>,
    pub sr: Option<String>,
    pub sv: Option<String>,
    pub sw: Option<String>,
    pub ta: Option<String>,
    pub te: Option<String>,
    pub th: Option<String>,
    pub tk: Option<String>,
    pub tr: Option<String>,
    pub uk: Option<String>,
    pub ur: Option<String>,
    pub vi: Option<String>,
    pub zh: Option<String>,
    pub cy: Option<String>,
    pub ceb: Option<String>,
    pub sr_latn: Option<String>,
    pub yue_hans: Option<String>,
    pub jv: Option<String>,
    pub sq: Option<String>,
    pub ccp: Option<String>,
    pub ga: Option<String>,
    pub ky: Option<String>,
    pub pa: Option<String>,
    pub kk: Option<String>,
    pub yue: Option<String>,
    pub yo: Option<String>,
    pub uz: Option<String>,
    pub bs: Option<String>,
    pub mk: Option<String>,
    pub ne: Option<String>,
    pub no: Option<String>,
    pub yo_bj: Option<String>,
    pub my: Option<String>,
    pub sd: Option<String>,
    pub ha: Option<String>,
    pub ha_ne: Option<String>,
    pub or: Option<String>,
    pub tm: Option<String>,
    pub so: Option<String>,
    pub km: Option<String>,
    pub zu: Option<String>,
    pub as_: Option<String>,
    pub lo: Option<String>,
    pub ig: Option<String>,
    pub tl: Option<String>,
    pub de_ch: Option<String>,
    pub la: Option<String>,
    pub fil: Option<String>,
    pub zh_hant: Option<String>,
    pub sc: Option<String>,
    pub dv: Option<String>,
    pub os: Option<String>,
    pub oc: Option<String>,
    pub br: Option<String>,
    pub lb: Option<String>,
    pub ast: Option<String>,
}

fn main() {}

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 report with the supplied Cargo.toml and build.rs, then compare the same struct in lib.rs while procMacro and buildScript are enabled. Trace the rust-analyzer build-script and proc-macro path; done when the large struct no longer causes prolonged single-core saturation and LSP functionality remains responsive.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
devtools, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.