diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp --- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -624,10 +624,8 @@ ClangdServer Server(CDB, FS, ClangdServer::optsForTest(), &DiagConsumer); auto FooCpp = testPath("foo.cpp"); - // clang cannot create CompilerInvocation if we pass two files in the - // CompileCommand. We pass the file in ExtraFlags once and CDB adds another - // one in getCompileCommand(). - CDB.ExtraClangFlags.push_back(FooCpp); + // clang cannot create CompilerInvocation in this case. + CDB.ExtraClangFlags.push_back("-###"); // Clang can't parse command args in that case, but we shouldn't crash. runAddDocument(Server, FooCpp, "int main() {}"); @@ -1080,7 +1078,7 @@ Opts.RunParser = CodeCompleteOptions::ParseIfReady; // This will make compile command broken and preamble absent. - CDB.ExtraClangFlags = {"yolo.cc"}; + CDB.ExtraClangFlags = {"-###"}; Server.addDocument(FooCpp, Code.code()); ASSERT_TRUE(Server.blockUntilIdleForTest()); auto Res = cantFail(runCodeComplete(Server, FooCpp, Code.point(), Opts)); diff --git a/clang-tools-extra/clangd/unittests/CompilerTests.cpp b/clang-tools-extra/clangd/unittests/CompilerTests.cpp --- a/clang-tools-extra/clangd/unittests/CompilerTests.cpp +++ b/clang-tools-extra/clangd/unittests/CompilerTests.cpp @@ -18,6 +18,7 @@ namespace clangd { namespace { +using testing::ElementsAre; using testing::IsEmpty; TEST(BuildCompilerInvocation, DropsPCH) { @@ -53,6 +54,22 @@ IsEmpty()); } +MATCHER_P(Named, Name, "") { return arg.Name == Name; } + +TEST(BuildCompilerInvocation, MultiArch) { + TestTU TU = TestTU::withHeaderCode(R"cpp( + #ifdef __x86_64__ + bool is64; + #elifdef __i386__ + bool is32; + #endif + )cpp"); + TU.ExtraArgs = { + "--target=x86_64-apple-darwin20", // Needed for driver multi-arch. + "-arch", "i386", "-arch", "x86_64"}; + EXPECT_THAT(TU.headerSymbols(), ElementsAre(Named("is32"))); +} + TEST(BuildCompilerInvocation, PragmaDebugCrash) { TestTU TU = TestTU::withCode("#pragma clang __debug parser_crash"); TU.build(); // no-crash diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp --- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -79,22 +79,24 @@ } } } - if (Jobs.size() == 0 || !isa(*Jobs.begin()) || - (Jobs.size() > 1 && !OffloadCompilation)) { + + bool PickFirstOfMany = OffloadCompilation || ShouldRecoverOnErorrs; + if (Jobs.size() == 0 || (Jobs.size() > 1 && !PickFirstOfMany)) { SmallString<256> Msg; llvm::raw_svector_ostream OS(Msg); Jobs.Print(OS, "; ", true); Diags->Report(diag::err_fe_expected_compiler_job) << OS.str(); return nullptr; } - - const driver::Command &Cmd = cast(*Jobs.begin()); - if (StringRef(Cmd.getCreator().getName()) != "clang") { + auto Cmd = llvm::find_if(Jobs, [](const driver::Command &Cmd) { + return StringRef(Cmd.getCreator().getName()) == "clang"; + }); + if (Cmd == Jobs.end()) { Diags->Report(diag::err_fe_expected_clang_command); return nullptr; } - const ArgStringList &CCArgs = Cmd.getArguments(); + const ArgStringList &CCArgs = Cmd->getArguments(); if (CC1Args) *CC1Args = {CCArgs.begin(), CCArgs.end()}; auto CI = std::make_unique();