Author: Nico Weber
Date: 2026-01-27T13:53:38Z
New Revision: fa3f78ebedfaf03c671fece8c3b42f16ef7b24d6

URL: 
https://github.com/llvm/llvm-project/commit/fa3f78ebedfaf03c671fece8c3b42f16ef7b24d6
DIFF: 
https://github.com/llvm/llvm-project/commit/fa3f78ebedfaf03c671fece8c3b42f16ef7b24d6.diff

LOG: [clangd] Support clang-cl flags /std:c++23preview and /std:clatest 
(#178080)

Related to https://github.com/clangd/clangd/issues/527 and
https://github.com/clangd/clangd/issues/1850.

Previously: https://github.com/llvm/llvm-project/pull/160030

Added: 
    

Modified: 
    clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/lib/Tooling/InterpolatingCompilationDatabase.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp 
b/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
index 4d59a6151c167..0c1e0348f68a5 100644
--- a/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
@@ -535,13 +535,31 @@ TEST(CommandMangler, StdLatestFlag) {
   EXPECT_THAT(llvm::join(Cmd.CommandLine, " "), HasSubstr("/std:c++latest"));
 }
 
-TEST(CommandMangler, StdLatestFlag_Inference) {
+TEST(CommandMangler, ClangClStdFlags_Inference) {
+  // Check that clang-cl-specific /std: flags are not dropped during inference.
   const auto Mangler = CommandMangler::forTests();
-  tooling::CompileCommand Cmd;
-  Cmd.CommandLine = {"clang-cl", "/std:c++latest", "--", "/Users/foo.cc"};
-  Mangler(Cmd, "/Users/foo.hpp");
-  // Check that the /std:c++latest flag is not dropped during inference
-  EXPECT_THAT(llvm::join(Cmd.CommandLine, " "), HasSubstr("/std:c++latest"));
+
+  {
+    tooling::CompileCommand Cmd;
+    Cmd.CommandLine = {"clang-cl", "/std:c++23preview", "--", "/Users/foo.cc"};
+    Mangler(Cmd, "/Users/foo.hpp");
+    EXPECT_THAT(llvm::join(Cmd.CommandLine, " "),
+                HasSubstr("/std:c++23preview"));
+  }
+
+  {
+    tooling::CompileCommand Cmd;
+    Cmd.CommandLine = {"clang-cl", "/std:clatest", "--", "/Users/foo.c"};
+    Mangler(Cmd, "/Users/foo.h");
+    EXPECT_THAT(llvm::join(Cmd.CommandLine, " "), HasSubstr("/std:clatest"));
+  }
+
+  {
+    tooling::CompileCommand Cmd;
+    Cmd.CommandLine = {"clang-cl", "/std:c++latest", "--", "/Users/foo.cc"};
+    Mangler(Cmd, "/Users/foo.hpp");
+    EXPECT_THAT(llvm::join(Cmd.CommandLine, " "), HasSubstr("/std:c++latest"));
+  }
 }
 
 } // namespace

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index ab671d032644b..343e78973bce7 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7211,6 +7211,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
       LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue())
                              .Case("c11", "-std=c11")
                              .Case("c17", "-std=c17")
+                             // If you add cases below for spellings that are
+                             // not in LangStandards.def, update
+                             // TransferableCommand::tryParseStdArg() in
+                             // 
lib/Tooling/InterpolatingCompilationDatabase.cpp
+                             // to match.
                              // TODO: add c23 when MSVC supports it.
                              .Case("clatest", "-std=c23")
                              .Default("");
@@ -7228,6 +7233,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
                              .Case("c++14", "-std=c++14")
                              .Case("c++17", "-std=c++17")
                              .Case("c++20", "-std=c++20")
+                             // If you add cases below for spellings that are
+                             // not in LangStandards.def, update
+                             // TransferableCommand::tryParseStdArg() in
+                             // 
lib/Tooling/InterpolatingCompilationDatabase.cpp
+                             // to match.
                              // TODO add c++23 and c++26 when MSVC supports it.
                              .Case("c++23preview", "-std=c++23")
                              .Case("c++latest", "-std=c++26")

diff  --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp 
b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
index e9b72388ae4df..f8306a6ad6e90 100644
--- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -123,9 +123,18 @@ static types::ID foldType(types::ID Lang) {
   }
 }
 
+// Return the language standard that's activated by the /std:clatest
+// flag in clang-CL mode.
+static LangStandard::Kind latestLangStandardC() {
+  // FIXME: Have a single source of truth for the mapping from
+  // clatest --> c23 that's shared by the driver code
+  // (clang/lib/Driver/ToolChains/Clang.cpp) and this file.
+  return LangStandard::lang_c23;
+}
+
 // Return the language standard that's activated by the /std:c++latest
 // flag in clang-CL mode.
-static LangStandard::Kind latestLangStandard() {
+static LangStandard::Kind latestLangStandardCXX() {
   // FIXME: Have a single source of truth for the mapping from
   // c++latest --> c++26 that's shared by the driver code
   // (clang/lib/Driver/ToolChains/Clang.cpp) and this file.
@@ -243,20 +252,29 @@ struct TransferableCommand {
         Result.CommandLine.push_back(types::getTypeName(TargetType));
       }
     }
+
     // --std flag may only be transferred if the language is the same.
     // We may consider "translating" these, e.g. c++11 -> c11.
     if (Std != LangStandard::lang_unspecified && foldType(TargetType) == Type) 
{
       const char *Spelling =
           LangStandard::getLangStandardForKind(Std).getName();
-      // In clang-cl mode, the latest standard is spelled 'c++latest' rather
-      // than e.g. 'c++26', and the driver does not accept the latter, so emit
+
+      // In clang-cl mode, some standards have 
diff erent spellings, so emit
       // the spelling that the driver does accept.
-      if (ClangCLMode && Std == latestLangStandard()) {
-        Spelling = "c++latest";
+      // Keep in sync with OPT__SLASH_std handling in Clang::ConstructJob().
+      if (ClangCLMode) {
+        if (Std == LangStandard::lang_cxx23)
+          Spelling = "c++23preview";
+        else if (Std == latestLangStandardC())
+          Spelling = "clatest";
+        else if (Std == latestLangStandardCXX())
+          Spelling = "c++latest";
       }
+
       Result.CommandLine.emplace_back(
           (llvm::Twine(ClangCLMode ? "/std:" : "-std=") + Spelling).str());
     }
+
     Result.CommandLine.push_back("--");
     Result.CommandLine.push_back(std::string(Filename));
     return Result;
@@ -313,10 +331,15 @@ struct TransferableCommand {
   std::optional<LangStandard::Kind> tryParseStdArg(const llvm::opt::Arg &Arg) {
     using namespace options;
     if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ)) {
-      // "c++latest" is not a recognized LangStandard, but it's accepted by
-      // the clang driver in CL mode.
-      if (ClangCLMode && StringRef(Arg.getValue()) == "c++latest") {
-        return latestLangStandard();
+      if (ClangCLMode) {
+        // Handle clang-cl spellings not in LangStandards.def.
+        // Keep in sync with OPT__SLASH_std handling in Clang::ConstructJob().
+        if (StringRef(Arg.getValue()) == "c++23preview")
+          return LangStandard::lang_cxx23;
+        if (StringRef(Arg.getValue()) == "clatest")
+          return latestLangStandardC();
+        if (StringRef(Arg.getValue()) == "c++latest")
+          return latestLangStandardCXX();
       }
       return LangStandard::getLangKind(Arg.getValue());
     }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to