Repository navigation
ci: run clippy on Windows so cfg(windows) code is lint-gated too - #488
Conversation
jussielo-amd
left a comment
There was a problem hiding this comment.
Code review
Blocking
.github/workflows/ci.yml:590— The new "Clippy (Windows targets)" step runs twocargo clippycommands in one pwsh script with no error handling. pwsh defaults to$ErrorActionPreference: Continue, and GitHub Actions reads the step's pass/fail from$LASTEXITCODEat the end of the script — which only reflects the last command. So if the first (broader) clippy invocation fails but the second (narrower,e2e-cucumber-only) one passes, the whole step reports green. The entire point of this PR is to lint-gatecfg(windows)code, and this bug means it can silently fail to do that. The same file's "Probe sccache cache backend" step already handles this correctly with explicit$LASTEXITCODEchecks, so this isn't a tooling limitation — just a gap in the new step.
Worth raising
ci.yml:590— Runningcargo clippy --workspace --all-targetsimmediately beforecargo build --workspace --all-targetsin the same job causes Cargo to recompile the workspace twice (clippy'sRUSTC_WORKSPACE_WRAPPERchanges the build fingerprint, sobuilddoesn't reuse clippy's artifacts). Risks eating into the job's ~13min/45min timeout headroom the PR itself cites.ci.yml:590— This new lint step runs serially insidewindows-build-and-test(the repo's slowest job), rather than following the existing convention (seepowershell-lint) of a separate parallel job — so it adds to critical-path time instead of overlapping with the Linuxclippyjob, and a Windows-lint failure surfaces buried inside a build/test job rather than its own check.Cargo.toml:74— The workspace already has a[workspace.lints.clippy]allow-list mechanism for exactly this kind of structural false-positive (nursery lints on cfg-split platform stubs), but the PR hand-applies#[allow(...)]with duplicated justification comments to 9+ individual functions instead of one workspace-level policy change. Future platform stubs will keep re-triggering this and require copy-pasting the same idiom.
Minor
crates/rocm-core/src/uv.rs:283— The justification comment is copy-pasted near-verbatim across 9 files; one of them (make_executable) already describes a structurally different situation using near-identical wording, so drift has already started.ci.yml:593— The two clippy invocations run sequentially with no data dependency forcing that.apps/rocm/src/main.rs:3492—#[allow(clippy::missing_const_for_fn)]is applied unconditionally to a function that isn't actually cfg-split (just has one non-const branch), unlike every other suppression in this PR — if that branch ever becomes const-compatible, the suppression would stay in place with nothing forcing re-evaluation.
1ebb430 to
06d809f
Compare
|
Thanks for the thorough review. Rebased onto
Also corrected in the description: the allow count is 16 (13 |
jussielo-amd
left a comment
There was a problem hiding this comment.
Follow-up on the blocking finding and the two I'd flagged as worth a closer look.
Blocking — step masks a clippy failure (ci.yml): fixed in ce00f8e9, confirmed by reading the diff and the CI run. Each cargo clippy/cargo build invocation now has its own step, so pwsh's last-exit-code behavior can't hide a failing first command behind a passing second one anymore. The Windows job's actual run (37275489997/windows-build-and-test) shows all four steps executing and reporting independently, which is also the first clean full Windows-target clippy run against this code — nice to have that confirmation land in the same PR that adds the gate.
PrivilegeEscalation::detect's unconditional allow: also fixed, and fixed at the right layer — 06d809ff turns the off-Linux running_as_root stub from pub const fn back into a plain fn (matching the non-const Linux signature) instead of leaving detect with a blanket suppression. Checked the callers; none of them need running_as_root in a const context, so this doesn't cost anything.
On the rest — the double-compile, the in-job vs. separate-job placement, the per-function allows vs. workspace lint table, and sequential clippy invocations — I buy the reasoning in the write-up (clippy's wrapper really does invalidate the build's fingerprint, the lints table can't be scoped by cfg, and the two invocations do share the target dir/lock). None of those were blocking to begin with, so I'm fine leaving them as documented tradeoffs rather than holding up the PR over them.
Spot-checked the uv.rs comment claim too — make_executable is a single function with internal #[cfg] blocks, not a cfg-split pair, so its comment being worded differently from the "Platform stub" ones elsewhere is correct, not drift.
CI is green except E2E tests (MI350P), which timed out waiting 24h for a self-hosted runner — infra, not this change.
Good to go.
06d809f to
82fa27b
Compare
|
This was ejected from the merge queue by the gate it adds. I rebased onto A full Windows-target clippy cross-check from Linux is clean on the rebased head, so nothing else on main trips the gate. It used |
82fa27b to
5099eeb
Compare
|
Rebased onto What the rebase changed:
Every one of the 12 Re-ran the Windows cross-check from Linux on On whether the new gate would be red on code this PR does not otherwise touch: measured rather than assumed. Restoring the pinned-main content of every file this PR edits and re-running the gate gives exit 101 with 21 diagnostics — 9 Caveat for reviewers: the local cross-check is the GNU target and CI is MSVC, so target-env-conditional differences would only show on the Local gates: fmt; workspace clippy and the e2e-target clippy, both One unrelated flake seen locally: |
The clippy job runs on Linux only, so it compiles the cfg(unix) side of
every platform conditional and never sees the cfg(windows) side. Windows
-gated code was outside the warnings-as-errors gate entirely, not merely
under-linted: a lint could land there and no check in the set could fail.
Add both of the Linux job's clippy invocations to windows-build-and-test,
before the build so a lint failure costs seconds rather than the full
build/test/package cycle. That job is already a required check, so the
gate becomes load-bearing without a branch-protection change.
Turning it on surfaced 21 existing violations, fixed here. Most are
mechanical: `&mut x` passed to a Win32 call becomes `&raw mut x`, which
also avoids materialising a reference just to take a pointer from it;
`if c { 1 } else { 0 }` becomes `i32::from(c)`; `map(..).unwrap_or(..)`
becomes `map_or_else`/`is_ok_and`.
The rest are `missing_const_for_fn` and `unused_async` on platform stubs,
and those are deliberately silenced rather than "fixed". Making only the
off-unix arm of a cfg-split pair `const` would give the two platforms
different signatures — two of these are `pub` — and would push the same
lint onto every caller in turn, which is how the burn-down kept growing.
The `async` stubs must keep their signature because callers `.await` them
either way. Each site carries the reason inline.
Verified by cross-compiling the whole workspace to x86_64-pc-windows-gnu
(the msvc target cannot be checked off Windows: ring and aws-lc-sys need
a Windows C toolchain to build their build scripts). Both clippy
invocations are clean for that target and for Linux, and the test suite
passes.
Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
The Windows clippy step ran two `cargo clippy` invocations in one `shell: pwsh` block. pwsh does not stop on a failing native command, and the step's result is the last command's exit code, so a first clippy that failed was turned green by a second that passed. Reproduced with pwsh 7.4: two commands where the first exits 3 leave the step at 0; the failing command alone exits 3. Split it into one step per invocation, the way the Linux `clippy` job already does. The Build step had the identical two-command shape, so it is split the same way. Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
The off-Linux stub of `running_as_root` was a `pub const fn` while the Linux implementation is not const: the two platforms had different signatures, which is the pattern this change argues against. It also pushed `missing_const_for_fn` onto its caller, which is why `PrivilegeEscalation::detect` needed an unconditional allow. Make the stub a plain `fn` with the same inline reason and `#[allow(clippy::missing_const_for_fn)]` as the other platform stubs, and drop the allow on `detect`. Checked against a scratch crate under the workspace's `nursery` level for the Windows target: without the allow the stub fails clippy, with it clippy passes. Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
The VRAM-usage fallback added on main has a Linux implementation that reads DRM sysfs counters and an off-Linux stub that returns `None`. On Windows, clippy's `missing_const_for_fn` flags the stub, which fails the Windows clippy gate this branch adds. Give the stub the same inline reason and `#[allow(clippy::missing_const_for_fn)]` as the other platform stubs rather than making it `const`, so both platforms keep one signature. A full Windows-target clippy cross-check (x86_64-pc-windows-gnu, both CI invocations) is clean after this change. Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
5099eeb to
11069ab
Compare
|
Rebased onto The Windows-target gate passes locally against the new base on
Main's new code from #583 ( Heads-up for merge order: #499 deletes these same two helpers, so whichever of the two lands second will conflict at their stubs in |
Stale: approved 06d809f; head is now 11069ab, so a fresh look is needed on the current head. Since the approval: rebased twice onto main. The Windows clippy gate ejected this from the merge queue on a new off-Linux stub main had landed, gpu_vram_usage_sysfs, fixed in 11069ab. #528 and #487 moved the stubs this PR annotates into host_gpu.rs and service.rs, where the allow-attributes now sit. The other commits (cfecb60, ddd0d74, 77d7498) are the reviewed ones, rebased. The Windows-target cross-check is clean.
jussielo-amd
left a comment
There was a problem hiding this comment.
Reviewed PR #488 (fetched head to a local branch, diffed against origin/main) with a full code-review pass at high effort. The change is CI-only: it adds clippy to the windows-build-and-test job (the same two invocations the Linux clippy job already runs), splits the Build step into Build and Build (release) so a single run: block no longer hides a failing first command behind a passing second one, and fixes the 21 lints that surfaced. Most of those fixes are #[allow(clippy::missing_const_for_fn)] or #[allow(clippy::unused_async)] on platform-stub functions, each with an inline comment explaining why applying the suggestion would either give the two cfg(unix)/cfg(not(unix)) arms different signatures or break a caller that awaits the stub on both platforms; the rest are mechanical (if/else to i32::from, map(..).unwrap_or_else(..) to map_or_else(..), map(..).unwrap_or(false) to is_ok_and(..), and &mut to &raw mut/&raw const for the Win32 FFI calls in crates/rocm-core/src/lib.rs around lines 1267, 1283, 1333, 1516, and 1659-1660). I checked each suppression's stated rationale against its sibling cfg arm and they hold up, and the &raw mut/&raw const rewrites are semantically equivalent to the references they replace for those FFI calls. No user-observable behavior changes here, so no Gherkin/BDD scenario is needed, and the PR description says so explicitly.
Two non-blocking notes for a possible follow-up:
- .github/workflows/ci.yml:669-675 ("Acceptance harness self-tests" in windows-build-and-test) still runs three python --self-test invocations inside one shell: pwsh run: block, which is the exact failure-masking pattern this PR's own description calls out and fixes for the Clippy and Build steps just above it (pwsh continues past a failing native command, and the step's reported result is only the last command's exit code). It's pre-existing and outside this PR's stated scope, not something this diff introduces, but since the PR already established the one-command-per-step fix, it'd be worth applying it here too in a follow-up.
- The "Platform stub..." justification comment plus #[allow(clippy::missing_const_for_fn)] is duplicated near-verbatim across roughly a dozen stub functions across apps/rocm, apps/rocmd, crates/rocm-core, and tests/e2e-cucumber (e.g. crates/rocm-core/src/openmpi.rs:184, crates/rocm-core/src/proc_lifecycle.rs:311 and :336, apps/rocmd/src/service.rs:104 and :254). That's a minor future maintenance cost if the underlying rationale ever needs correcting, but inline reasoning at each call site is a defensible tradeoff given Rust has no clean way to share an #[allow] across a cfg-split signature pair.
Approving: the lint fixes are correct and each is matched to the actual constraint on its platform stub, the CI change achieves its stated goal of gating cfg(windows) code behind clippy, and neither note above rises to a correctness or scope problem with this PR.
|
On the approval's two non-blocking notes:
|
Windows clippy now runs in CI (#488). The two cfg(not(unix)) stubs in atomic_write.rs trip missing_const_for_fn; making only one arm const would split the two platforms' signatures, so allow it with the same comment #488 uses for its stubs. Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
Windows clippy now runs in CI (#488). The two cfg(not(unix)) stubs in atomic_write.rs trip missing_const_for_fn; making only one arm const would split the two platforms' signatures, so allow it with the same comment #488 uses for its stubs. Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
Windows clippy now runs in CI (#488). The two cfg(not(unix)) stubs in atomic_write.rs trip missing_const_for_fn; making only one arm const would split the two platforms' signatures, so allow it with the same comment #488 uses for its stubs. Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
Windows clippy now runs in CI (#488). The two cfg(not(unix)) stubs in atomic_write.rs trip missing_const_for_fn; making only one arm const would split the two platforms' signatures, so allow it with the same comment #488 uses for its stubs. Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
Windows clippy now runs in CI (#488). The two cfg(not(unix)) stubs in atomic_write.rs trip missing_const_for_fn; making only one arm const would split the two platforms' signatures, so allow it with the same comment #488 uses for its stubs. Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
Windows clippy now runs in CI (#488). The two cfg(not(unix)) stubs in atomic_write.rs trip missing_const_for_fn; making only one arm const would split the two platforms' signatures, so allow it with the same comment #488 uses for its stubs. Signed-off-by: Roman Inflianskas <Roman.Inflianskas@amd.com>
What was wrong
The
clippyjob runs on Linux only. It therefore compiles thecfg(unix)side of every platform conditional and never sees thecfg(windows)side.That is not "Windows code is under-linted" — it is outside the warnings-as-errors gate entirely. A lint could land in Windows-gated code and no check in the set could fail, because no check ever compiled it.
windows-build-and-testbuilds and tests on Windows, so type errors are caught there; lints are not.What this does
Adds both of the Linux job's clippy invocations to
windows-build-and-test, before the build so a lint failure costs seconds rather than the full build/test/package cycle — the same reasoning behind that job's existingneeds: clippy.It goes in the existing job rather than a new one on purpose:
windows-build-and-testis already a required status check, so the gate becomes load-bearing immediately with no branch-protection change. With the clippy steps added the job took 18 minutes on this PR's last run (clippy 5m23s, build 7m29s, test 1m43s), against a 45-minute timeout, so there is headroom. Clippy and build compile separately; clippy's output is metadata only, so the build cannot reuse it.The 21 violations it surfaced
Most are mechanical and are fixed here:
&mut xpassed to a Win32 call →&raw mut x(also avoids materialising a reference just to take a pointer from it)if c { 1 } else { 0 }→i32::from(c)map(..).unwrap_or(..)→is_ok_and(..),map(..).unwrap_or_else(..)→map_or_else(..)use_self,uninlined_format_argsThe rest are deliberately silenced rather than "fixed", and that is the part worth reviewing.
Sixteen are
missing_const_for_fn(13) orunused_async(3) on platform stubs. Applying Clippy's suggestion there is wrong in two ways:constgives the two platforms different signatures. Two of these arepub, so a const-context call would compile on Windows and fail on Linux.process_start_ticksconst pushed the same lint ontoProcessIdentity::capture; makingprobe_usable_amd_gpu_indicesconst pushed it ontousable_amd_gpu_indices. This is why the burn-down grew on each pass rather than shrinking.The
asyncstubs are the same shape: callers.awaitthem on both platforms, so droppingasyncwould not compile. Each site carries its reason inline. The one case whereconstis applied isWindowsExamineInventory::is_empty, which iscfg(windows)-only with no sibling to disagree with.Verification, and its limit
Cross-compiled the whole workspace to
x86_64-pc-windows-gnuwith mingw. Both clippy invocations are clean for that target, both are clean for Linux (no regression), andcargo test --workspace --all-targetspasses.The
msvctarget could not be checked locally:ringandaws-lc-sysneed a Windows C toolchain to build their build scripts, which does not exist off Windows. Thecfg(windows)code is identical between the two targets, but an msvc-only lint would appear for the first time in this PR's own CI run — which is, conveniently, exactly the gate being added. If one shows up, it is a real finding, not a flake.Clippy also stops at the first failing crate, so this converged over several passes (e2e-cucumber → rocm-core → rocmd → apps/rocm). The final pass reports zero.
Scope
CI config plus the lint fixes it requires — no behaviour change. No Gherkin scenario: nothing user-observable changes. The
&raw mutrewrites are the only edits insideunsafeFFI blocks, and they are the compiler-suggested form for taking a raw pointer without an intervening reference.