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
