Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions crates/no_std_fs_operations/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,3 @@ mod usage;
pub use config::NoStdFsConfig;
#[cfg(feature = "dylint-driver")]
pub use driver::*;

#[cfg(not(feature = "dylint-driver"))]
mod stub {
//! Placeholder compiled when the `dylint-driver` feature is off, so the
//! crate still builds without the `rustc_private` toolchain internals.

#[expect(
dead_code,
reason = "Exposed only when built without the `dylint-driver` feature"
)]
pub fn no_std_fs_operations_disabled_stub() {}
}
90 changes: 90 additions & 0 deletions crates/no_std_fs_operations/tests/no_default_features_build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//! Compile-time regression guard for the `dylint-driver`-disabled build.
//!
//! The crate is a Dylint lint library: the lint logic lives behind the
//! optional `dylint-driver` feature, while the default feature set is empty so
//! the crate can be built by tools that only need a plain library. Issue #322
//! removed the private stub that previously existed solely to keep that
//! empty build warning-free. This test re-checks the configuration the stub
//! existed for: `cargo check --no-default-features --lib` must still succeed
//! with warnings denied, now without relying on that stub.
//!
//! The check is deliberately restricted to the library target: the crate's
//! integration test binaries are dylint harnesses that require `cargo-dylint`
//! and `dylint-link`, which must not be assumed here. The nested `cargo`
//! invocation therefore inherits the outer `RUSTFLAGS` (so `-D warnings` from
//! the Makefile gate applies) but uses an isolated target directory so it never
//! contends with the outer build.

use std::path::PathBuf;
use std::process::Command;

use anyhow::Context as _;
use serde_json::Value;
use tempfile::TempDir;

/// Top-level name of the package under test.
const CRATE: &str = "no_std_fs_operations";

/// Runs `cargo check --no-default-features --lib` for this crate and asserts
/// that the build succeeds with warnings denied (via inherited `RUSTFLAGS`).
///
/// The workspace manifest is located by walking up from this test crate's
/// manifest directory, mirroring `integration_exclusion.rs`, so the nested
/// invocation resolves the same workspace this test builds under.
#[test]
fn crate_builds_without_dylint_driver_feature() -> anyhow::Result<()> {
let workspace_root = workspace_root()?;
let target_dir = TempDir::new().context("failed to create isolated target directory")?;

let output = Command::new("cargo")
.arg("check")
.arg("--package")
.arg(CRATE)
.arg("--no-default-features")
.arg("--lib")
.arg("--message-format=json")
.current_dir(&workspace_root)
.env("CARGO_TARGET_DIR", target_dir.path())
.output()
.context("failed to execute nested cargo check")?;

let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"`cargo check --no-default-features --lib` for `{CRATE}` failed \
(it must compile without the `dylint-driver` feature now that the \
no-driver stub is gone):\n{stderr}"
);

let diagnostics = stdout
.lines()
.filter_map(|line| serde_json::from_str::<Value>(line).ok())
.filter(|message| message["reason"] == "compiler-message")
.collect::<Vec<_>>();
assert!(
diagnostics.is_empty(),
"`cargo check --no-default-features --lib` for `{CRATE}` emitted \
compiler diagnostics under `-D warnings`: {diagnostics:#?}"
);

Ok(())
}

/// Returns the workspace root containing this crate's manifest.
fn workspace_root() -> anyhow::Result<PathBuf> {
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let mut candidate = manifest_dir.as_path();
loop {
if candidate.join("Cargo.toml").is_file() {
let workspace = std::fs::read_to_string(candidate.join("Cargo.toml"))
.context("failed to read candidate workspace Cargo.toml")?;
if workspace.contains("[workspace]") {
return Ok(candidate.to_path_buf());
}
}
candidate = candidate
.parent()
.context("workspace root not found above CARGO_MANIFEST_DIR")?;
}
}
Loading