From 55ad128b79495f0bc4de8a4d51c3f532130e6f58 Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Sat, 31 Oct 2026 22:59:38 +0100 Subject: [PATCH] test: lint fails when a configuration's std module cannot be built A host configuration pointed at a sysroot without libc++ cannot get its std module built, so its files cannot be parsed. With an AST rule registered, the run has to skip the rule and fail instead of reporting the files clean, as it did before the fix. The cache is redirected around this run only: the std module's directory is made before its build fails. Co-Authored-By: Claude Opus 5.5 --- tests/Lint/main.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/Lint/main.cpp b/tests/Lint/main.cpp index 69bd436..4e07d94 100644 --- a/tests/Lint/main.cpp +++ b/tests/Lint/main.cpp @@ -6,6 +6,9 @@ import Crafter.Build; namespace fs = std::filesystem; using namespace Crafter; +extern "C" int setenv(const char* name, const char* value, int overwrite); +extern "C" int unsetenv(const char* name); + namespace { std::int32_t Failures = 0; @@ -705,6 +708,31 @@ int main() { // two assertions above cover it. } + // A configuration whose std module cannot be built is in the build graph + // all the same: its files cannot be parsed, which has to fail the run. + // Its command was cleared, which read as "not a translation unit", and + // every semantic rule passed the files. A sysroot without libc++ is one + // way there. The std module's directory is made before its build fails, + // so the cache is redirected around this run. + { + Scratch s("ast-no-std-module"); + s.Write("f", "int Value = 1;\n"); + Configuration cfg = s.Config({"f"}); + cfg.sysroot = (s.dir / "empty-sysroot").string(); + fs::create_directories(cfg.sysroot); + bool ran = false; + cfg.AddAstLintRule("needs-ast", [&ran](LintContext&) { ran = true; }); + const char* realCache = std::getenv("XDG_CACHE_HOME"); + const std::string saved = realCache ? realCache : ""; + setenv("XDG_CACHE_HOME", (s.dir / "cache").c_str(), 1); + LintSummary summary = RunLint(cfg, Mode(LintMode::Report)); + if (saved.empty()) unsetenv("XDG_CACHE_HOME"); + else setenv("XDG_CACHE_HOME", saved.c_str(), 1); + Check(!ran, "ast: rule is skipped when the std module cannot be built"); + Check(summary.errors > 0, "ast: a std module that cannot be built fails the run"); + Check(!summary.Clean(), "ast: a std module that cannot be built is not Clean"); + } + // --no-ast skips those rules deliberately and exits normally. { Scratch s("ast-optout");