Skip to content

Add new misleading_cfg_in_build_script lint#153721

Open
GuillaumeGomez wants to merge 6 commits intorust-lang:mainfrom
GuillaumeGomez:misleading_cfg_in_build_script
Open

Add new misleading_cfg_in_build_script lint#153721
GuillaumeGomez wants to merge 6 commits intorust-lang:mainfrom
GuillaumeGomez:misleading_cfg_in_build_script

Conversation

@GuillaumeGomez
Copy link
Copy Markdown
Member

@GuillaumeGomez GuillaumeGomez commented Mar 11, 2026

View all comments

Fixes #125441.
Fixes rust-lang/rust-clippy#9419.

Take-over of rust-lang/rust-clippy#12862.

It was originally implemented in clippy but the clippy thought it made for sense for such a lint to be directly implemented in rustc. I applied all suggestions made on the original PR and also improved the code overall (added docs too).

So on a build.rs from cargo crate, we will check for any target_*, unix and windows cfg and warn about them.

Since you made the original review on clippy.

r? @Urgau

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Mar 11, 2026

Some changes occurred in check-cfg diagnostics

cc @Urgau

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 11, 2026
@GuillaumeGomez GuillaumeGomez force-pushed the misleading_cfg_in_build_script branch from 262d2e2 to 3e99ab7 Compare March 11, 2026 14:35
@GuillaumeGomez
Copy link
Copy Markdown
Member Author

Added a ui test to ensure this lint is only emitted on cargo build.rs scripts.

@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the misleading_cfg_in_build_script branch from 3e99ab7 to ea1c733 Compare March 11, 2026 16:00
@rust-log-analyzer

This comment has been minimized.

Comment on lines +202 to +205
fn is_build_script(cx: &EarlyContext<'_>) -> bool {
rustc_session::utils::was_invoked_from_cargo()
&& cx.sess().opts.crate_name.as_deref() == Some("build_script_build")
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems quite hacky and brittle for a lint.

Is there a better to detect if we are compiling a Cargo build script? If there isn't, we could maybe consider having the lint allowed by-default, but have Cargo implicitly set it to warn for build-scripts.

cc @rust-lang/cargo

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, not great. :-/

I was kinda hoping that we had a "build script" crate kind but we don't (which is logical but still, not fun).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just put it in t-cargo meeting agenda :)
next meeting time: Tue, Mar 17, 2026, 10:00 UTC-4

https://hackmd.io/-vJMV3isQfqu2d2J91t1eA

@GuillaumeGomez GuillaumeGomez force-pushed the misleading_cfg_in_build_script branch from ea1c733 to 28c7221 Compare March 11, 2026 20:58
@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez
Copy link
Copy Markdown
Member Author

CI is finally happy. ^^'

@ehuss ehuss added the I-cargo-nominated Nominated for discussion during a cargo team meeting. label Mar 13, 2026
@ehuss ehuss moved this to Nominated in Cargo status tracker Mar 17, 2026
@ehuss
Copy link
Copy Markdown
Contributor

ehuss commented Mar 17, 2026

The cargo team discussed this today (notes). Some comments from that discussion:

  1. We were largely OK with the approach of making this allow-by-default and having cargo set it to a warning when building a build script.
  2. I was concerned about the possible amount of false-positives this would generate. Has there been a crater run or other analysis of what kind of false-positives this might hit? For example, if some build script has "cfg(windows) ... run executable that only exists on windows", it seems like this would be a false positive.
  3. I assume this would need lang-team approval. It might be good to get this on their radar.
  4. As an outsider looking at the diff, I am rather surprised to see yet another cfg parser being implemented here. I'm curious why this isn't using the standard cfg parser?

@GuillaumeGomez
Copy link
Copy Markdown
Member Author

  1. Sounds good.
  2. It's a valid concern, to which I don't really have an answer to. Only answer is to run a crater run to see the impact it would have.
  3. We're not clear which team is "in charge" here.
  4. Unless I missed something, the cfg parser requires data I don't have? I'd love to be proven wrong though, would reduce the code quite a lot!

@Urgau
Copy link
Copy Markdown
Member

Urgau commented Mar 17, 2026

I assume this would need lang-team approval. It might be good to get this on their radar.

I would expect a T-cargo FCP, with maybe T-compiler, but not T-lang. The lint proposed here has nothing to do with the language, it's purely a compiler and Cargo affair.

To elaborate a bit more, this lint could be in cargo it-self if we had a custom linting system, and it wouldn't need T-lang approval for that, so I don't think it needs one. We also (T-compiler) didn't ask T-lang to FCP the #[cfg]/--cfg lints.

As an outsider looking at the diff, I am rather surprised to see yet another cfg parser being implemented here. I'm curious why this isn't using the standard cfg parser?

I wouldn't look to closely at the impl. I haven't yet done a review of it, I wanted to wait for T-cargo input first.

Copy link
Copy Markdown
Member

@Urgau Urgau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I share the concerns from Eric, about having another cfg parser.

Fortunately, this lint is simple enough that it can use the same infra as the unexpected_cfgs lint and perform the verification directly when parsing the cfgs them-selves in rustc_attr_parsing.

This will require some code re-shuffling between different crates (rustc_attr_parsing, rustc_lint_defs, rustc_lint, ...). You can follow what has been done for the UNEXPECTED_CFGS lint.

View changes since this review

Comment on lines +10 to +34
declare_lint! {
/// Checks for usage of `#[cfg]`/`#[cfg_attr]`/`cfg!()` in `build.rs` scripts.
///
/// ### Explanation
///
/// It checks the `cfg` values for the *host*, not the target. For example, `cfg!(windows)` is
/// true when compiling on Windows, so it will give the wrong answer if you are cross compiling.
/// This is because build scripts run on the machine performing compilation, rather than on the
/// target.
///
/// ### Example
///
/// ```rust,ignore (can only be run in cargo build scripts)
/// if cfg!(windows) {}
/// ```
///
/// Use instead:
///
/// ```rust
/// if std::env::var("CARGO_CFG_WINDOWS").is_ok() {}
/// ```
pub MISLEADING_CFG_IN_BUILD_SCRIPT,
Warn,
"use of host configs in `build.rs` scripts"
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be moved to rustc_lint_defs.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most lints are defined directly in their file in this crate, so I'll keep the same logic.

Comment on lines +185 to +200
fn get_invalid_cfg_attrs(attr: &MetaItem, spans: &mut Vec<Span>, has_unknown: &mut bool) {
let Some(ident) = attr.ident() else { return };
if [sym::unix, sym::windows].contains(&ident.name) {
spans.push(attr.span);
} else if attr.value_str().is_some() && ident.name.as_str().starts_with("target_") {
spans.push(attr.span);
} else if let Some(sub_attrs) = attr.meta_item_list() {
for sub_attr in sub_attrs {
if let Some(meta) = sub_attr.meta_item() {
get_invalid_cfg_attrs(meta, spans, has_unknown);
}
}
} else {
*has_unknown = true;
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be moved in parse_name_value:

pub(crate) fn parse_name_value<S: Stage>(

Comment on lines +211 to +213
if !is_build_script(cx) {
return;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be removed since T-cargo is onboard with enabling the lint for build scripts on their side.

Suggested change
if !is_build_script(cx) {
return;
}

@Urgau Urgau added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-cargo Relevant to the cargo team, which will review and decide on the PR/issue. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 18, 2026
@GuillaumeGomez GuillaumeGomez force-pushed the misleading_cfg_in_build_script branch from 2d14a6b to 06e2527 Compare March 19, 2026 13:34
@rust-log-analyzer

This comment has been minimized.

@ehuss
Copy link
Copy Markdown
Contributor

ehuss commented Mar 23, 2026

I would expect a T-cargo FCP, with maybe T-compiler, but not T-lang. The lint proposed here has nothing to do with the language, it's purely a compiler and Cargo affair.

I don't think that's how lints have been handled in the past. They all need to be approved by the lang team. I'm not aware of any exclusions.

@GuillaumeGomez
Copy link
Copy Markdown
Member Author

I'm surprised: I added lints in the past without needing t-lang approval (although it might have been a few years for the last one... ^^').

@traviscross traviscross added T-lang Relevant to the language team I-lang-nominated Nominated for discussion during a lang team meeting. labels Mar 23, 2026
@traviscross traviscross added I-lang-nominated Nominated for discussion during a lang team meeting. P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang labels Apr 1, 2026
@nikomatsakis
Copy link
Copy Markdown
Contributor

👋 Just wanted to weigh in wearing lang hat--

  1. I agree that lang's buy-in is not required for every lint, I feel that lang decides on lints that pertain to how people use the language but lints and warnings specific to the compiler seem out of scope. Sometimes there's a bit of ambiguity, a cc is always appreciated.
  2. I don't understand @GuillaumeGomez why you removed the labels. They're used to auto-generate agendas and (as everyone seems to agree) do not represent a need to block. My read of your comment is that you're frustrated with having had to discuss this at all, which I get, but don't take it out on the bots man!

@traviscross
Copy link
Copy Markdown
Contributor

Feel free to discuss it with the team if you want to provide feedback or preferences...

These tags put it on the agenda so it can be discussed with the team. That's all.

@GuillaumeGomez
Copy link
Copy Markdown
Member Author

2. I don't understand @GuillaumeGomez why you removed the labels. They're used to auto-generate agendas and (as everyone seems to agree) do not represent a need to block. My read of your comment is that you're frustrated with having had to discuss this at all, which I get, but don't take it out on the bots man!

Not very nice to call traviscross a bot. 😝

These tags put it on the agenda so it can be discussed with the team. That's all.

Noted, my bad. Please add them back then.

@Mark-Simulacrum
Copy link
Copy Markdown
Member

Is there a reason this can't be implemented via the existing check-cfg checks? Do we not support opting out of permitting built-in cfgs via check-cfg? If it can be done via check-cfg, is the reason this is a new lint just for better error messages (since we can guide the user about the build script specific context)?

@GuillaumeGomez
Copy link
Copy Markdown
Member Author

I'm supposed to rewrite a big part of this lint to reuse existing cfg attribute parsing. Also the problem here is that we need to check all cfgs, including the ones that get removed early on and the cfg! macro. For that to work, we need to run before the expansion pass.

@nikomatsakis
Copy link
Copy Markdown
Contributor

This was discussed in the lang-team call today. The consensus on the call was as follows:

  1. We are happy to have compiler/cargo drive decisions on this lint, as the thread already concluded.
  2. We don't agree that this is outside lang scope -- this seems to fall within the purview of a lang lint (i.e., it impacts which language features are used and how).
  3. But we don't think it's only lang scope. This is very tooling focused (i.e., it is tied to the workflows of cargo + compiler and the specifics of how a build.rs program is compiled) and hence it feels also compiler/cargo scope.

As usual, if multiple teams have purview, we could have all of them on the FCP, but that's pretty tedious. We think it's simpler overall for us to leave the final decision to y'all, as we did on RFC 3013.

One last thing -- we've noticed that these kind of issues that lie at the intersection of multiple teams have been a source of friction lately. Might be a good thing to talk about at the All Hands.

@traviscross traviscross added I-lang-radar Items that are on lang's radar and will need eventual work or consideration. and removed I-lang-nominated Nominated for discussion during a lang team meeting. P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang labels Apr 1, 2026
@traviscross
Copy link
Copy Markdown
Contributor

traviscross commented Apr 1, 2026

In the meeting, @nikomatsakis asked whether, setting aside jurisdictional questions, any of us had concerns about this lint. Nothing came to mind in the meeting. But looking at the situation afterward, I have some questions. Looking around GitHub briefly, these uses stood out to me as valid:

Project File Pattern What it does
mullvad/mullvadvpn-app build.rs cfg!(target_os = ...) in host_os(), CARGO_CFG_* in target_os() Deliberately uses both; compares host and target to decide whether to build a DLL.
denoland/rusty_v8 build.rs cfg!(target_os = "macos") && cfg!(target_arch = "aarch64") Documents the host/target distinction in a comment, then uses cfg! for host detection to fix GN's host_cpu.
webbeef/webviewer build.rs CARGO_CFG_TARGET_OS for target, #[cfg(windows)] for host Checks target OS first, then gates winres on host being Windows, with an explicit cross-compilation panic.
agersant/polaris build.rs #[cfg(windows)] / #[cfg(unix)] Embeds a Windows icon via winres — a host tool that only works on Windows.
tokio-rs/prost build.rs cfg!(target_arch = ...), cfg!(windows) Sets CMAKE_SYSTEM_PROCESSOR for the host and decides whether to build conformance tests.
uutils/coreutils build.rs #[cfg(target_os = ...)] Sets DYLIB_EXT (.so / .dylib / .dll) for the host platform.
AFLplusplus/LibAFL build.rs cfg!(target_os = "linux") && cfg!(target_arch = "x86_64") NYX only works on Linux x86_64 hosts; gates running a host-side build script.
webbeef/webviewer build.rs cfg!(windows) Picks python.exe vs python3 — a host tool name.

These came up immediately in my GH search; I didn't have to go digging. This makes me wonder about whether this lint would do more harm than good. It would seem, at least, that a crater run would be in order.

@Urgau
Copy link
Copy Markdown
Member

Urgau commented Apr 1, 2026

It would seem, at least, that a crater run would be in order.

I'm planning on doing one before asking the teams for approval, but I first wanted a vide-check from T-cargo.

The implementation needs some work before we can do one though (renaming, removing the custom parser, ...).

@Mark-Simulacrum
Copy link
Copy Markdown
Member

Is there a reason this can't be implemented via the existing check-cfg checks? Do we not support opting out of permitting built-in cfgs via check-cfg? If it can be done via check-cfg, is the reason this is a new lint just for better error messages (since we can guide the user about the build script specific context)?

I'm supposed to rewrite a big part of this lint to reuse existing cfg attribute parsing. Also the problem here is that we need to check all cfgs, including the ones that get removed early on and the cfg! macro. For that to work, we need to run before the expansion pass.

I don't think I follow this. cfg! does get checked by check-cfg lints, just like #[cfg]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=098a07edea7467a723355ea8931eb72e

@GuillaumeGomez
Copy link
Copy Markdown
Member Author

GuillaumeGomez commented Apr 9, 2026

Is there a reason this can't be implemented via the existing check-cfg checks? Do we not support opting out of permitting built-in cfgs via check-cfg? If it can be done via check-cfg, is the reason this is a new lint just for better error messages (since we can guide the user about the build script specific context)?

I'm supposed to rewrite a big part of this lint to reuse existing cfg attribute parsing. Also the problem here is that we need to check all cfgs, including the ones that get removed early on and the cfg! macro. For that to work, we need to run before the expansion pass.

I don't think I follow this. cfg! does get checked by check-cfg lints, just like #[cfg]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=098a07edea7467a723355ea8931eb72e

It's checked during the AST -> attribute conversion. But considering I need to store some extra info, I'm not sure it's gonna be the right place. First I rewrite using the attribute parser, then I see if I can merge both codes.

@rust-bors

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the misleading_cfg_in_build_script branch from b20987d to 1518fcc Compare April 10, 2026 13:14
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 10, 2026

Some changes occurred in compiler/rustc_attr_parsing

cc @jdonszelmann, @JonathanBrouwer

@rustbot rustbot added the A-attributes Area: Attributes (`#[…]`, `#![…]`) label Apr 10, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 10, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@GuillaumeGomez
Copy link
Copy Markdown
Member Author

The last commit is not finished at all. It's currently blocked on #155097.

I'll also likely need to update the parse_cfg/parse_cfg_entry API because the lint provides a suggestion for cfg! and I'd like to keep it.

JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Apr 10, 2026
…, r=JonathanBrouwer

Make `rustc_attr_parsing::SharedContext::emit_lint` take a `MultiSpan` instead of a `Span`

I'll likely need it for rust-lang#153721 to allow emitting the lint on one attribute at a time instead of each of the wrong values.

r? @JonathanBrouwer
rust-timer added a commit that referenced this pull request Apr 10, 2026
Rollup merge of #155097 - GuillaumeGomez:emit_lint-multispan, r=JonathanBrouwer

Make `rustc_attr_parsing::SharedContext::emit_lint` take a `MultiSpan` instead of a `Span`

I'll likely need it for #153721 to allow emitting the lint on one attribute at a time instead of each of the wrong values.

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

Labels

A-attributes Area: Attributes (`#[…]`, `#![…]`) I-lang-radar Items that are on lang's radar and will need eventual work or consideration. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-cargo Relevant to the cargo team, which will review and decide on the PR/issue. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Warn for cfg!(target_* = "whatever") usage in build scripts Lint for cfg usage which would provide a misleading result in a build script.

9 participants