Correctly set CompilingPCH in PrecompilePreambleAction.
This fixes a crash bug in clangd when used with modules. ASTWriter would end up writing references to submodules into the PCH file, but upon reading the submodules would not exists and HeaderFileInfoTrait::ReadData would crash. Differential Revision: https://reviews.llvm.org/D85532
This commit is contained in:
@@ -63,6 +63,7 @@ add_unittest(ClangdUnitTests ClangdTests
|
||||
IndexTests.cpp
|
||||
JSONTransportTests.cpp
|
||||
LSPClient.cpp
|
||||
ModulesTests.cpp
|
||||
ParsedASTTests.cpp
|
||||
PathMappingTests.cpp
|
||||
PreambleTests.cpp
|
||||
|
||||
44
clang-tools-extra/clangd/unittests/ModulesTests.cpp
Normal file
44
clang-tools-extra/clangd/unittests/ModulesTests.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
//===-- ModulesTests.cpp ---------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Annotations.h"
|
||||
#include "TestFS.h"
|
||||
#include "TestTU.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
namespace clangd {
|
||||
namespace {
|
||||
|
||||
TEST(Modules, TextualIncludeInPreamble) {
|
||||
TestTU TU = TestTU::withCode(R"cpp(
|
||||
#include "Textual.h"
|
||||
|
||||
void foo() {}
|
||||
)cpp");
|
||||
TU.ExtraArgs.push_back("-fmodule-name=M");
|
||||
TU.ExtraArgs.push_back("-fmodule-map-file=m.modulemap");
|
||||
TU.AdditionalFiles["Textual.h"] = "void foo();";
|
||||
TU.AdditionalFiles["m.modulemap"] = R"modulemap(
|
||||
module M {
|
||||
module Textual {
|
||||
textual header "Textual.h"
|
||||
}
|
||||
}
|
||||
)modulemap";
|
||||
// Test that we do not crash.
|
||||
TU.index();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace clangd
|
||||
} // namespace clang
|
||||
@@ -208,6 +208,11 @@ public:
|
||||
Callbacks.AfterPCHEmitted(Writer);
|
||||
}
|
||||
|
||||
bool BeginSourceFileAction(CompilerInstance &CI) override {
|
||||
assert(CI.getLangOpts().CompilingPCH);
|
||||
return ASTFrontendAction::BeginSourceFileAction(CI);
|
||||
}
|
||||
|
||||
bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
|
||||
bool hasCodeCompletionSupport() const override { return false; }
|
||||
bool hasASTFileSupport() const override { return false; }
|
||||
@@ -396,6 +401,8 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
|
||||
auto PreambleDepCollector = std::make_shared<PreambleDependencyCollector>();
|
||||
Clang->addDependencyCollector(PreambleDepCollector);
|
||||
|
||||
Clang->getLangOpts().CompilingPCH = true;
|
||||
|
||||
// Remap the main source file to the preamble buffer.
|
||||
StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
|
||||
auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Frontend/PCHContainerOperations.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
@@ -111,4 +112,42 @@ TEST_F(ASTUnitTest, GetBufferForFileMemoryMapping) {
|
||||
llvm::MemoryBuffer::MemoryBuffer_MMap);
|
||||
}
|
||||
|
||||
TEST_F(ASTUnitTest, ModuleTextualHeader) {
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFs =
|
||||
new llvm::vfs::InMemoryFileSystem();
|
||||
InMemoryFs->addFile("test.cpp", 0, llvm::MemoryBuffer::getMemBuffer(R"cpp(
|
||||
#include "Textual.h"
|
||||
void foo() {}
|
||||
)cpp"));
|
||||
InMemoryFs->addFile("m.modulemap", 0, llvm::MemoryBuffer::getMemBuffer(R"cpp(
|
||||
module M {
|
||||
module Textual {
|
||||
textual header "Textual.h"
|
||||
}
|
||||
}
|
||||
)cpp"));
|
||||
InMemoryFs->addFile("Textual.h", 0, llvm::MemoryBuffer::getMemBuffer(R"cpp(
|
||||
void foo();
|
||||
)cpp"));
|
||||
|
||||
const char *Args[] = {"clang", "test.cpp", "-fmodule-map-file=m.modulemap",
|
||||
"-fmodule-name=M"};
|
||||
Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions());
|
||||
CInvok = createInvocationFromCommandLine(Args, Diags);
|
||||
ASSERT_TRUE(CInvok);
|
||||
|
||||
FileManager *FileMgr = new FileManager(FileSystemOptions(), InMemoryFs);
|
||||
PCHContainerOps = std::make_shared<PCHContainerOperations>();
|
||||
|
||||
auto AU = ASTUnit::LoadFromCompilerInvocation(
|
||||
CInvok, PCHContainerOps, Diags, FileMgr, false, CaptureDiagsKind::None, 1,
|
||||
TU_Complete, false, false, false);
|
||||
ASSERT_TRUE(AU);
|
||||
auto File = AU->getFileManager().getFileRef("Textual.h", false, false);
|
||||
ASSERT_TRUE(bool(File));
|
||||
// Verify that we do not crash here.
|
||||
EXPECT_TRUE(AU->getPreprocessor().getHeaderSearchInfo().getExistingFileInfo(
|
||||
&File->getFileEntry()));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
Reference in New Issue
Block a user