Skip to content

Commit 8d9bde2

Browse files
authored
fix: build std.compat with Clang and MSVC STL (#769)
* fix: build std.compat with Clang and MSVC STL * style: align compat module flags with std module builder
1 parent c94234b commit 8d9bde2

3 files changed

Lines changed: 34 additions & 6 deletions

File tree

‎src/build/prepare/toolchain_env.cpp‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,21 +231,22 @@ bind_msvc_sysroot(mcpp::toolchain::Toolchain& tc,
231231
// by its own search. A toolset without one leaves `import std` unavailable
232232
// rather than borrowing another toolset's.
233233
//
234-
// Only `std` is rebound. Detection never gave this row a `std.compat`
235-
// source, and the clang builder for it passes the file without
236-
// `-x c++-module`: given `std.compat.ixx`, clang takes it for linker
237-
// input, `--precompile` writes nothing and exits 0, and the next command
238-
// fails on the missing BMI (measured on the Windows runners).
234+
// Bind both standard modules to this toolset. A compat module from another
235+
// STL cannot safely import the selected std BMI.
239236
std::error_code ec;
240237
const auto ixx = choice->toolsDir / "modules" / "std.ixx";
241238
const bool msvcStl = tc.stdModuleSource.empty()
242239
|| tc.stdModuleSource.filename() == "std.ixx";
243240
if (msvcStl && std::filesystem::exists(ixx, ec)) {
244241
tc.stdModuleSource = ixx;
242+
const auto compat = ixx.parent_path() / "std.compat.ixx";
243+
tc.stdCompatSource = std::filesystem::exists(compat, ec)
244+
? compat : std::filesystem::path{};
245245
tc.hasImportStd = true;
246246
tc.importStdMinLevel = msvc::std_module_min_level_for_stl(ixx);
247247
} else if (msvcStl && !tc.stdModuleSource.empty()) {
248248
tc.stdModuleSource.clear();
249+
tc.stdCompatSource.clear();
249250
tc.hasImportStd = false;
250251
}
251252

‎src/toolchain/clang.cppm‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,8 +566,13 @@ std::vector<std::string> std_compat_build_commands(const Toolchain& tc,
566566
auto absBmi = (cacheDir / relBmi).string();
567567
auto absStdBmi = (cacheDir / relStdBmi).string();
568568
auto absObj = (cacheDir / "std.compat.o").string();
569+
// MSVC STL ships .ixx, which Clang does not infer as C++ module input.
570+
// Apply the override only when parsing source, never when compiling a BMI.
571+
std::string ixxFlags = (tc.stdCompatSource.extension() == ".ixx")
572+
? " -x c++-module -Wno-include-angled-in-module-purview"
573+
: "";
569574
return {
570-
std::format("{}{} {}{} -Wno-reserved-module-identifier{}{} "
575+
std::format("{}{} {}{} -Wno-reserved-module-identifier{}{}{} "
571576
"-fmodule-file=std={} "
572577
"--precompile {} -o {} 2>&1",
573578
mcpp::toolchain::compiler_env_prefix(tc),
@@ -576,6 +581,7 @@ std::vector<std::string> std_compat_build_commands(const Toolchain& tc,
576581
crtToken,
577582
sysrootFlag,
578583
precompileFlags,
584+
ixxFlags,
579585
absStdBmi,
580586
mcpp::xlings::shq(tc.stdCompatSource.string()),
581587
mcpp::xlings::shq(absBmi)),

‎tests/unit/test_toolchain_stdmod.cpp‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,27 @@ TEST(ToolchainStdmod, ClangStdCompatCommandsUseRequestedStandard) {
7171
}
7272
}
7373

74+
TEST(ToolchainStdmod, MsvcCompatSourceIsParsedAsAModuleButItsBmiIsNot) {
75+
auto tc = clang_toolchain();
76+
tc.stdModuleSource = "std.ixx";
77+
tc.stdCompatSource = "std.compat.ixx";
78+
auto cmds = clang::std_compat_build_commands(
79+
tc, "cache", "cache/pcm.cache/std.compat.pcm",
80+
"cache/pcm.cache/std.pcm", "", "-std=c++23", "-fms-runtime-lib=dll");
81+
ASSERT_EQ(cmds.size(), 2u);
82+
EXPECT_NE(cmds[0].find("-x c++-module"), std::string::npos);
83+
EXPECT_EQ(cmds[1].find("-x c++-module"), std::string::npos);
84+
for (auto const& cmd : cmds) {
85+
EXPECT_NE(cmd.find("-fmodule-file=std="), std::string::npos);
86+
EXPECT_NE(cmd.find("-fms-runtime-lib=dll"), std::string::npos);
87+
}
88+
tc.stdCompatSource = "std.compat.cppm";
89+
cmds = clang::std_compat_build_commands(
90+
tc, "cache", "cache/pcm.cache/std.compat.pcm",
91+
"cache/pcm.cache/std.pcm", "", "-std=c++23");
92+
EXPECT_EQ(cmds[0].find("-x c++-module"), std::string::npos);
93+
}
94+
7495
// THE PRECOMPILE HAS TO KNOW WHICH MACHINE, AND ONLY ONE OF TWO SOURCES EVER
7596
// CARRIES IT.
7697
//

0 commit comments

Comments
 (0)