aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Frontend/FrontendActions.h1
-rw-r--r--include/clang/Serialization/ASTBitCodes.h5
-rw-r--r--include/clang/Serialization/ASTReader.h7
-rw-r--r--include/clang/Serialization/ASTWriter.h9
-rw-r--r--lib/Frontend/ASTUnit.cpp8
-rw-r--r--lib/Frontend/FrontendActions.cpp7
-rw-r--r--lib/Serialization/ASTReader.cpp52
-rw-r--r--lib/Serialization/ASTWriter.cpp30
-rw-r--r--lib/Serialization/GeneratePCH.cpp5
-rw-r--r--test/PCH/headersearch.cpp43
10 files changed, 151 insertions, 16 deletions
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 9e68a3c958..0f2637fa51 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -89,6 +89,7 @@ public:
static bool ComputeASTConsumerArguments(CompilerInstance &CI,
llvm::StringRef InFile,
std::string &Sysroot,
+ std::string &OutputFile,
llvm::raw_ostream *&OS,
bool &Chaining);
};
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index b117322d7f..5c5c893ea5 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -353,7 +353,10 @@ namespace clang {
CUDA_SPECIAL_DECL_REFS = 39,
/// \brief Record code for header search information.
- HEADER_SEARCH_TABLE = 40
+ HEADER_SEARCH_TABLE = 40,
+
+ /// \brief The directory that the PCH was originally created in.
+ ORIGINAL_PCH_DIR = 41
};
/// \brief Record types used within a source manager block.
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 015ccc9b3f..8cb0206fd7 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -613,6 +613,13 @@ private:
/// AST file.
std::string ActualOriginalFileName;
+ /// \brief The directory that the PCH was originally created in. Used to
+ /// allow resolving headers even after headers+PCH was moved to a new path.
+ std::string OriginalDir;
+
+ /// \brief The directory that the PCH we are reading is stored in.
+ std::string CurrentDir;
+
/// \brief Whether this precompiled header is a relocatable PCH file.
bool RelocatablePCH;
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 5d37eb5f36..7da0dfea83 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -309,7 +309,8 @@ private:
void WriteSubStmt(Stmt *S);
void WriteBlockInfoBlock();
- void WriteMetadata(ASTContext &Context, const char *isysroot);
+ void WriteMetadata(ASTContext &Context, const char *isysroot,
+ const std::string &OutputFile);
void WriteLanguageOptions(const LangOptions &LangOpts);
void WriteStatCache(MemorizeStatCalls &StatCalls);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
@@ -339,7 +340,7 @@ private:
void WriteDecl(ASTContext &Context, Decl *D);
void WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
- const char* isysroot);
+ const char* isysroot, const std::string &OutputFile);
void WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
const char* isysroot);
@@ -368,6 +369,7 @@ public:
/// \param PPRec Record of the preprocessing actions that occurred while
/// preprocessing this file, e.g., macro instantiations
void WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+ const std::string &OutputFile,
const char* isysroot);
/// \brief Emit a source location.
@@ -575,6 +577,7 @@ public:
/// precompiled header from the parsed source code.
class PCHGenerator : public SemaConsumer {
const Preprocessor &PP;
+ std::string OutputFile;
const char *isysroot;
llvm::raw_ostream *Out;
Sema *SemaPtr;
@@ -589,7 +592,7 @@ protected:
const ASTWriter &getWriter() const { return Writer; }
public:
- PCHGenerator(const Preprocessor &PP, bool Chaining,
+ PCHGenerator(const Preprocessor &PP, const std::string &OutputFile, bool Chaining,
const char *isysroot, llvm::raw_ostream *Out);
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
virtual void HandleTranslationUnit(ASTContext &Ctx);
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 00902e810c..0370c2e125 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -653,7 +653,7 @@ public:
PrecompilePreambleConsumer(ASTUnit &Unit,
const Preprocessor &PP, bool Chaining,
const char *isysroot, llvm::raw_ostream *Out)
- : PCHGenerator(PP, Chaining, isysroot, Out), Unit(Unit) { }
+ : PCHGenerator(PP, "", Chaining, isysroot, Out), Unit(Unit) { }
virtual void HandleTopLevelDecl(DeclGroupRef D) {
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
@@ -700,9 +700,11 @@ public:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
std::string Sysroot;
+ std::string OutputFile;
llvm::raw_ostream *OS = 0;
bool Chaining;
- if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
+ if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
+ OutputFile,
OS, Chaining))
return 0;
@@ -2008,7 +2010,7 @@ bool ASTUnit::Save(llvm::StringRef File) {
std::vector<unsigned char> Buffer;
llvm::BitstreamWriter Stream(Buffer);
ASTWriter Writer(Stream);
- Writer.WriteAST(getSema(), 0, 0);
+ Writer.WriteAST(getSema(), 0, std::string(), 0);
// Write the generated bitstream to "Out".
if (!Buffer.empty())
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 0ffea201cd..e454321c0c 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -83,19 +83,21 @@ ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
std::string Sysroot;
+ std::string OutputFile;
llvm::raw_ostream *OS = 0;
bool Chaining;
- if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OS, Chaining))
+ if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS, Chaining))
return 0;
const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
Sysroot.c_str() : 0;
- return new PCHGenerator(CI.getPreprocessor(), Chaining, isysroot, OS);
+ return new PCHGenerator(CI.getPreprocessor(), OutputFile, Chaining, isysroot, OS);
}
bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
llvm::StringRef InFile,
std::string &Sysroot,
+ std::string &OutputFile,
llvm::raw_ostream *&OS,
bool &Chaining) {
Sysroot = CI.getHeaderSearchOpts().Sysroot;
@@ -111,6 +113,7 @@ bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
if (!OS)
return true;
+ OutputFile = CI.getFrontendOpts().OutputFile;
Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH &&
!CI.getPreprocessorOpts().ImplicitPCHInclude.empty();
return false;
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 5e3fa132e6..3dcc62ebc1 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1181,6 +1181,39 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(PerFileData &F) {
}
}
+/// \brief If a header file is not found at the path that we expect it to be
+/// and the PCH file was moved from its original location, try to resolve the
+/// file by assuming that header+PCH were moved together and the header is in
+/// the same place relative to the PCH.
+static std::string
+resolveFileRelativeToOriginalDir(const std::string &Filename,
+ const std::string &OriginalDir,
+ const std::string &CurrDir) {
+ assert(OriginalDir != CurrDir &&
+ "No point trying to resolve the file if the PCH dir didn't change");
+ using namespace llvm::sys;
+ llvm::SmallString<128> filePath(Filename);
+ fs::make_absolute(filePath);
+ assert(path::is_absolute(OriginalDir));
+ llvm::SmallString<128> currPCHPath(CurrDir);
+
+ path::const_iterator fileDirI = path::begin(path::parent_path(filePath)),
+ fileDirE = path::end(path::parent_path(filePath));
+ path::const_iterator origDirI = path::begin(OriginalDir),
+ origDirE = path::end(OriginalDir);
+ // Skip the common path components from filePath and OriginalDir.
+ while (fileDirI != fileDirE && origDirI != origDirE &&
+ *fileDirI == *origDirI) {
+ ++fileDirI;
+ ++origDirI;
+ }
+ for (; origDirI != origDirE; ++origDirI)
+ path::append(currPCHPath, "..");
+ path::append(currPCHPath, fileDirI, fileDirE);
+ path::append(currPCHPath, path::filename(Filename));
+ return currPCHPath.str();
+}
+
/// \brief Get a cursor that's correctly positioned for reading the source
/// location entry with the given ID.
ASTReader::PerFileData *ASTReader::SLocCursorForID(unsigned ID) {
@@ -1235,6 +1268,14 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) {
std::string Filename(BlobStart, BlobStart + BlobLen);
MaybeAddSystemRootToFilename(Filename);
const FileEntry *File = FileMgr.getFile(Filename);
+ if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() &&
+ OriginalDir != CurrentDir) {
+ std::string resolved = resolveFileRelativeToOriginalDir(Filename,
+ OriginalDir,
+ CurrentDir);
+ if (!resolved.empty())
+ File = FileMgr.getFile(resolved);
+ }
if (File == 0)
File = FileMgr.getVirtualFile(Filename, (off_t)Record[4],
(time_t)Record[5]);
@@ -2179,6 +2220,12 @@ ASTReader::ReadASTBlock(PerFileData &F) {
MaybeAddSystemRootToFilename(OriginalFileName);
break;
+ case ORIGINAL_PCH_DIR:
+ // The primary AST will be the last to get here, so it will be the one
+ // that's used.
+ OriginalDir.assign(BlobStart, BlobLen);
+ break;
+
case VERSION_CONTROL_BRANCH_REVISION: {
const std::string &CurBranch = getClangFullRepositoryVersion();
llvm::StringRef ASTBranch(BlobStart, BlobLen);
@@ -2393,6 +2440,11 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(llvm::StringRef FileName,
// Set the AST file name.
F.FileName = FileName;
+ if (FileName != "-") {
+ CurrentDir = llvm::sys::path::parent_path(FileName);
+ if (CurrentDir.empty()) CurrentDir = ".";
+ }
+
// Open the AST file.
//
// FIXME: This shouldn't be here, we should just take a raw_ostream.
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index f1af8354a2..cb29973105 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -899,7 +899,8 @@ adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) {
}
/// \brief Write the AST metadata (e.g., i686-apple-darwin9).
-void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot) {
+void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot,
+ const std::string &OutputFile) {
using namespace llvm;
// Metadata
@@ -947,6 +948,23 @@ void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot) {
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
}
+ // Original PCH directory
+ if (!OutputFile.empty() && OutputFile != "-") {
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(ORIGINAL_PCH_DIR));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+ unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+
+ llvm::SmallString<128> OutputPath(OutputFile);
+
+ llvm::sys::fs::make_absolute(OutputPath);
+ StringRef origDir = llvm::sys::path::parent_path(OutputPath);
+
+ RecordData Record;
+ Record.push_back(ORIGINAL_PCH_DIR);
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
+ }
+
// Repository branch/version information.
BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev();
RepoAbbrev->Add(BitCodeAbbrevOp(VERSION_CONTROL_BRANCH_REVISION));
@@ -2568,6 +2586,7 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
}
void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
+ const std::string &OutputFile,
const char *isysroot) {
// Emit the file header.
Stream.Emit((unsigned)'C', 8);
@@ -2580,11 +2599,12 @@ void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
if (Chain)
WriteASTChain(SemaRef, StatCalls, isysroot);
else
- WriteASTCore(SemaRef, StatCalls, isysroot);
+ WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile);
}
void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
- const char *isysroot) {
+ const char *isysroot,
+ const std::string &OutputFile) {
using namespace llvm;
ASTContext &Context = SemaRef.Context;
@@ -2692,7 +2712,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Write the remaining AST contents.
RecordData Record;
Stream.EnterSubblock(AST_BLOCK_ID, 5);
- WriteMetadata(Context, isysroot);
+ WriteMetadata(Context, isysroot, OutputFile);
WriteLanguageOptions(Context.getLangOptions());
if (StatCalls && !isysroot)
WriteStatCache(*StatCalls);
@@ -2827,7 +2847,7 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
RecordData Record;
Stream.EnterSubblock(AST_BLOCK_ID, 5);
- WriteMetadata(Context, isysroot);
+ WriteMetadata(Context, isysroot, "");
if (StatCalls && !isysroot)
WriteStatCache(*StatCalls);
// FIXME: Source manager block should only write new stuff, which could be
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index 3b4f869c00..b8833ceacc 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -27,10 +27,11 @@
using namespace clang;
PCHGenerator::PCHGenerator(const Preprocessor &PP,
+ const std::string &OutputFile,
bool Chaining,
const char *isysroot,
llvm::raw_ostream *OS)
- : PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0),
+ : PP(PP), OutputFile(OutputFile), isysroot(isysroot), Out(OS), SemaPtr(0),
StatCalls(0), Stream(Buffer), Writer(Stream), Chaining(Chaining) {
// Install a stat() listener to keep track of all of the stat()
// calls.
@@ -50,7 +51,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
// Emit the PCH file
assert(SemaPtr && "No Sema?");
- Writer.WriteAST(*SemaPtr, StatCalls, isysroot);
+ Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, isysroot);
// Write the generated bitstream to "Out".
Out->write((char *)&Buffer.front(), Buffer.size());
diff --git a/test/PCH/headersearch.cpp b/test/PCH/headersearch.cpp
new file mode 100644
index 0000000000..c7849dc635
--- /dev/null
+++ b/test/PCH/headersearch.cpp
@@ -0,0 +1,43 @@
+// Test reading of PCH with changed location of original input files,
+// i.e. invoking header search.
+
+// Generate the original files:
+// RUN: mkdir -p %t_orig/sub %t_orig/sub2
+// RUN: echo 'struct orig_sub{char c; int i; };' > %t_orig/sub/orig_sub.h
+// RUN: echo 'void orig_sub2_1();' > %t_orig/sub2/orig_sub2_1.h
+// RUN: echo '#include "orig_sub2_1.h"' > %t_orig/sub2/orig_sub2.h
+// RUN: echo 'template <typename T> void tf() { orig_sub2_1(); T::foo(); }' >> %t_orig/sub2/orig_sub2.h
+// RUN: echo 'void foo() {}' > %t_orig/tmp2.h
+// RUN: echo '#include "tmp2.h"' > %t_orig/all.h
+// RUN: echo '#include "sub/orig_sub.h"' >> %t_orig/all.h
+// RUN: echo '#include "orig_sub2.h"' >> %t_orig/all.h
+// RUN: echo 'int all();' >> %t_orig/all.h
+
+// Generate the PCH:
+// RUN: cd %t_orig && %clang_cc1 -x c++ -emit-pch -o all.h.pch -Isub2 all.h
+// RUN: rm -rf %t_moved
+// RUN: mv %t_orig %t_moved
+
+// Check diagnostic with location in original source:
+// RUN: %clang_cc1 -include-pch all.h.pch -I%t_moved -I%t_moved/sub2 -Wpadded -emit-obj -o %t.o %s 2> %t.stderr
+// RUN: grep 'struct orig_sub' %t.stderr
+
+// Check diagnostic with 2nd location in original source:
+// RUN: not %clang_cc1 -DREDECL -include-pch all.h.pch -I%t_moved -I%t_moved/sub2 -emit-obj -o %t.o %s 2> %t.stderr
+// RUN: grep 'void foo' %t.stderr
+
+// Check diagnostic with instantiation location in original source:
+// RUN: not %clang_cc1 -DINSTANTIATION -include-pch all.h.pch -I%t_moved -I%t_moved/sub2 -emit-obj -o %t.o %s 2> %t.stderr
+// RUN: grep 'orig_sub2_1' %t.stderr
+
+void qq(orig_sub*) {all();}
+
+#ifdef REDECL
+float foo() {return 0;}
+#endif
+
+#ifdef INSTANTIATION
+void f() {
+ tf<int>();
+}
+#endif