From 9a720d96eb0c78b493aa8113771f9d1cf1aa572a Mon Sep 17 00:00:00 2001 From: Yonggang Luo Date: Mon, 30 Jun 2025 17:48:26 +0800 Subject: [PATCH] clang-cl: Add support for C23 Although there is no `cl -std:c23` flag, the underlying Clang compiler does have a C23 mode we can activate by passing `-std=c23` through a `clang-cl` wrapper flag. Also port the fix from commit 30139913e9 (VS: Restore support for mixing C++23 and C in one target with clang-cl, 2024-12-09, v3.31.3~10^2). Fixes: #27038 Signed-off-by: Yonggang Luo Co-authored-by: Brad King --- .gitlab/ci/configure_windows_clang_common.cmake | 4 ++-- Modules/Compiler/Clang-C.cmake | 12 ++++++++++++ Source/cmVisualStudio10TargetGenerator.cxx | 13 +++++++++++++ Templates/MSBuild/FlagTables/v143_CL.json | 7 +++++++ Tests/CompileFeatures/CMakeLists.txt | 9 +++++++++ 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/.gitlab/ci/configure_windows_clang_common.cmake b/.gitlab/ci/configure_windows_clang_common.cmake index 738477e21a..0d002854dc 100644 --- a/.gitlab/ci/configure_windows_clang_common.cmake +++ b/.gitlab/ci/configure_windows_clang_common.cmake @@ -2,8 +2,8 @@ if("$ENV{CMAKE_CI_BUILD_NAME}" MATCHES "(^|_)gnu(_|$)") set(CMake_TEST_C_STANDARDS "90;99;11;17;23" CACHE STRING "") set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23;26" CACHE STRING "") else() - # FIXME: Implement C23 support for clang-cl. - set(CMake_TEST_C_STANDARDS "90;99;11;17" CACHE STRING "") + # Testing for clang-cl. + set(CMake_TEST_C_STANDARDS "90;99;11;17;23" CACHE STRING "") set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23" CACHE STRING "") endif() diff --git a/Modules/Compiler/Clang-C.cmake b/Modules/Compiler/Clang-C.cmake index 2df31de52a..24b7157e16 100644 --- a/Modules/Compiler/Clang-C.cmake +++ b/Modules/Compiler/Clang-C.cmake @@ -78,6 +78,18 @@ else() endif() set(CMAKE_C_STANDARD_LATEST 17) + + if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 18.0) + # This version of clang-cl does not have a -std:c23 flag. + # Pass the standard through to the underlying clang directly. + # Note that cmVisualStudio10TargetGenerator::ComputeClOptions + # has a special case to map this back to -std:clatest in .vcxproj + # files that also have CXX sources. + set(CMAKE_C23_STANDARD_COMPILE_OPTION "-clang:-std=c23") + set(CMAKE_C23_EXTENSION_COMPILE_OPTION "-clang:-std=c23") + + set(CMAKE_C_STANDARD_LATEST 23) + endif() endif() if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 2.1) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 5387f02605..13d4b42b6d 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -3553,6 +3553,19 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( flagsC, this->GeneratorTarget, cmBuildStep::Compile, "C", configName); this->LocalGenerator->AddCompileOptions(flagsC, this->GeneratorTarget, "C", configName); + + // Modules/Compiler/Clang-C.cmake has a special case for clang-cl versions + // that do not have a -std:c23 flag to pass the standard through to the + // underlying clang directly. Unfortunately that flag applies to all + // sources in a single .vcxproj file, so if we have CXX sources too then + // we cannot use it. Map it back to -std:clatest, even though that might + // enable a different C level, so it does not apply to CXX sources. + static std::string const kClangStdC23 = "-clang:-std=c23"; + std::string::size_type p = flagsC.find(kClangStdC23); + if (p != std::string::npos) { + flagsC.replace(p, kClangStdC23.size(), "-std:clatest"); + } + Options optC(this->LocalGenerator, Options::Compiler, gg->GetClFlagTable()); optC.Parse(flagsC); diff --git a/Templates/MSBuild/FlagTables/v143_CL.json b/Templates/MSBuild/FlagTables/v143_CL.json index f0431a6d04..1e91c3ebb0 100644 --- a/Templates/MSBuild/FlagTables/v143_CL.json +++ b/Templates/MSBuild/FlagTables/v143_CL.json @@ -524,6 +524,13 @@ "value": "stdc17", "flags": [] }, + { + "name": "LanguageStandard_C", + "switch": "std:clatest", + "comment": "Preview - Features from the Latest C Working Draft", + "value": "stdclatest", + "flags": [] + }, { "name": "PrecompiledHeader", "switch": "Yc", diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt index 5bbefe49d6..1a65699d3c 100644 --- a/Tests/CompileFeatures/CMakeLists.txt +++ b/Tests/CompileFeatures/CMakeLists.txt @@ -37,6 +37,15 @@ if(("23" IN_LIST CMake_TEST_CXX_STANDARDS OR CMAKE_CXX23_STANDARD_COMPILE_OPTION target_compile_features(test_cxx_std_23_with_c_std_11 PRIVATE cxx_std_23 c_std_11) endif() +if(("23" IN_LIST CMake_TEST_C_STANDARDS OR CMAKE_C23_STANDARD_COMPILE_OPTION) + AND ("17" IN_LIST CMake_TEST_CXX_STANDARDS OR CMAKE_CXX17_STANDARD_COMPILE_OPTION) + # FIXME: "clang-cl -stc:clatest" does not enable C23. + AND NOT CMAKE_GENERATOR MATCHES "Visual Studio" + ) + add_library(test_c_std_23_with_cxx_std_17 OBJECT c_std_23.c cxx_std_17.cpp) + target_compile_features(test_c_std_23_with_cxx_std_17 PRIVATE c_std_23 cxx_std_17) +endif() + macro(run_test feature lang) if (${feature} IN_LIST CMAKE_${lang}_COMPILE_FEATURES) add_library(test_${feature} OBJECT ${feature}.${ext_${lang}})