Skip to content

Commit 635910d

Browse files
[clang][Tooling] Support 'c++latest' in InterpolatingCompilationDatabase (#160030)
Fixes clangd/clangd#527 Fixes clangd/clangd#1850
1 parent 156e9b4 commit 635910d

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,15 @@ TEST(CommandMangler, StdLatestFlag) {
536536
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "), HasSubstr("/std:c++latest"));
537537
}
538538

539+
TEST(CommandMangler, StdLatestFlag_Inference) {
540+
const auto Mangler = CommandMangler::forTests();
541+
tooling::CompileCommand Cmd;
542+
Cmd.CommandLine = {"clang-cl", "/std:c++latest", "--", "/Users/foo.cc"};
543+
Mangler(Cmd, "/Users/foo.hpp");
544+
// Check that the /std:c++latest flag is not dropped during inference
545+
EXPECT_THAT(llvm::join(Cmd.CommandLine, " "), HasSubstr("/std:c++latest"));
546+
}
547+
539548
} // namespace
540549
} // namespace clangd
541550
} // namespace clang

clang/lib/Tooling/InterpolatingCompilationDatabase.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ static types::ID foldType(types::ID Lang) {
123123
}
124124
}
125125

126+
// Return the language standard that's activated by the /std:c++latest
127+
// flag in clang-CL mode.
128+
static LangStandard::Kind latestLangStandard() {
129+
// FIXME: Have a single source of truth for the mapping from
130+
// c++latest --> c++26 that's shared by the driver code
131+
// (clang/lib/Driver/ToolChains/Clang.cpp) and this file.
132+
return LangStandard::lang_cxx26;
133+
}
134+
126135
// A CompileCommand that can be applied to another file.
127136
struct TransferableCommand {
128137
// Flags that should not apply to all files are stripped from CommandLine.
@@ -237,9 +246,16 @@ struct TransferableCommand {
237246
// --std flag may only be transferred if the language is the same.
238247
// We may consider "translating" these, e.g. c++11 -> c11.
239248
if (Std != LangStandard::lang_unspecified && foldType(TargetType) == Type) {
240-
Result.CommandLine.emplace_back((
241-
llvm::Twine(ClangCLMode ? "/std:" : "-std=") +
242-
LangStandard::getLangStandardForKind(Std).getName()).str());
249+
const char *Spelling =
250+
LangStandard::getLangStandardForKind(Std).getName();
251+
// In clang-cl mode, the latest standard is spelled 'c++latest' rather
252+
// than e.g. 'c++26', and the driver does not accept the latter, so emit
253+
// the spelling that the driver does accept.
254+
if (ClangCLMode && Std == latestLangStandard()) {
255+
Spelling = "c++latest";
256+
}
257+
Result.CommandLine.emplace_back(
258+
(llvm::Twine(ClangCLMode ? "/std:" : "-std=") + Spelling).str());
243259
}
244260
Result.CommandLine.push_back("--");
245261
Result.CommandLine.push_back(std::string(Filename));
@@ -296,8 +312,14 @@ struct TransferableCommand {
296312
// Try to interpret the argument as '-std='.
297313
std::optional<LangStandard::Kind> tryParseStdArg(const llvm::opt::Arg &Arg) {
298314
using namespace driver::options;
299-
if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ))
315+
if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ)) {
316+
// "c++latest" is not a recognized LangStandard, but it's accepted by
317+
// the clang driver in CL mode.
318+
if (ClangCLMode && StringRef(Arg.getValue()) == "c++latest") {
319+
return latestLangStandard();
320+
}
300321
return LangStandard::getLangKind(Arg.getValue());
322+
}
301323
return std::nullopt;
302324
}
303325
};

0 commit comments

Comments
 (0)