Procházet zdrojové kódy

VS: Restore support for mixing C++23 and C in one target with clang-cl

Since commit 474eafe28c (clang-cl: Add support for C++23, 2024-09-13,
v3.31.0-rc1~97^2) we use a Clang-specific flag to enable C++23 since
`clang-cl` has no `-std:c++23` flag, and `-std:c++latest` may enable an
even newer version of C++.  However, in `.vcxproj` files there is no way
to express a target-wide `-clang:-std=c++23` flag for only C++ sources
when the target also has C sources.  Add a special case to map back to
`-std:c++latest` for targets with C++23 and C together.

Fixes: #26508
Brad King před 1 rokem
rodič
revize
30139913e9

+ 5 - 0
Modules/Compiler/Clang.cmake

@@ -255,6 +255,11 @@ macro(__compiler_clang_cxx_standards lang)
     endif()
 
     if(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL "17.0")
+      # This version of clang-cl does not have a -std:c++23 flag.
+      # Pass the standard through to the underlying clang directly.
+      # Note that cmVisualStudio10TargetGenerator::ComputeClOptions
+      # has a special case to map this back to -std:c++latest in .vcxproj
+      # files that also have C sources.
       set(CMAKE_${lang}23_STANDARD_COMPILE_OPTION "-clang:-std=c++23")
       set(CMAKE_${lang}23_EXTENSION_COMPILE_OPTION "-clang:-std=c++23")
       set(CMAKE_${lang}_STANDARD_LATEST 23)

+ 14 - 0
Source/cmVisualStudio10TargetGenerator.cxx

@@ -3480,6 +3480,20 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
     }
   }
 
+  if (isCXXwithC) {
+    // Modules/Compiler/Clang.cmake has a special case for clang-cl versions
+    // that do not have a -std:c++23 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 C sources too then we
+    // cannot use it.  Map it back to -std::c++latest, even though that might
+    // end up enabling C++26 or later, so it does not apply to C sources.
+    static const std::string kClangStdCxx23 = "-clang:-std=c++23";
+    std::string::size_type p = flags.find(kClangStdCxx23);
+    if (p != std::string::npos) {
+      flags.replace(p, kClangStdCxx23.size(), "-std:c++latest");
+    }
+  }
+
   clOptions.Parse(flags);
   clOptions.Parse(defineFlags);
   std::vector<std::string> targetDefines;

+ 6 - 0
Tests/CompileFeatures/CMakeLists.txt

@@ -32,6 +32,12 @@ foreach(lang C CXX CUDA HIP)
   endforeach()
 endforeach()
 
+if(("23" IN_LIST CMake_TEST_CXX_STANDARDS OR CMAKE_CXX23_STANDARD_COMPILE_OPTION)
+  AND ("11" IN_LIST CMake_TEST_C_STANDARDS OR CMAKE_C11_STANDARD_COMPILE_OPTION))
+  add_library(test_cxx_std_23_with_c_std_11 OBJECT cxx_std_23.cpp c_std_11.c)
+  target_compile_features(test_cxx_std_23_with_c_std_11 PRIVATE cxx_std_23 c_std_11)
+endif()
+
 macro(run_test feature lang)
   if (${feature} IN_LIST CMAKE_${lang}_COMPILE_FEATURES)
     add_library(test_${feature} OBJECT ${feature}.${ext_${lang}})