/// \brief The control block, which contains all of the
/// information that needs to be validated prior to committing
/// to loading the AST file.
- CONTROL_BLOCK_ID
+ CONTROL_BLOCK_ID,
+
+ /// \brief The block of input files, which were used as inputs
+ /// to create this AST file.
+ ///
+ /// This block is part of the control block.
+ INPUT_FILES_BLOCK_ID
};
/// \brief Record types that occur within the control block.
ORIGINAL_PCH_DIR = 6
};
+ /// \brief Record types that occur within the input-files block
+ /// inside the control block.
+ enum InputFileRecordTypes {
+ /// \brief An input file.
+ INPUT_FILE = 1
+ };
+
/// \brief Record types that occur within the AST block itself.
enum ASTRecordTypes {
/// \brief Record code for the offsets of each type.
/// \brief The list of delegating constructor declarations.
DELEGATING_CTORS = 37,
- /// \brief Record code for the table of offsets into the block
- /// of file source-location information.
- FILE_SOURCE_LOCATION_OFFSETS = 38,
-
/// \brief Record code for the set of known namespaces, which are used
/// for typo correction.
- KNOWN_NAMESPACES = 39,
+ KNOWN_NAMESPACES = 38,
/// \brief Record code for the remapping information used to relate
/// loaded modules to the various offsets and IDs(e.g., source location
/// offests, declaration and type IDs) that are used in that module to
/// refer to other modules.
- MODULE_OFFSET_MAP = 40,
+ MODULE_OFFSET_MAP = 39,
/// \brief Record code for the source manager line table information,
/// which stores information about \#line directives.
- SOURCE_MANAGER_LINE_TABLE = 41,
+ SOURCE_MANAGER_LINE_TABLE = 40,
/// \brief Record code for map of Objective-C class definition IDs to the
/// ObjC categories in a module that are attached to that class.
- OBJC_CATEGORIES_MAP = 42,
+ OBJC_CATEGORIES_MAP = 41,
/// \brief Record code for a file sorted array of DeclIDs in a module.
- FILE_SORTED_DECLS = 43,
+ FILE_SORTED_DECLS = 42,
/// \brief Record code for an array of all of the (sub)modules that were
/// imported by the AST file.
- IMPORTED_MODULES = 44,
+ IMPORTED_MODULES = 43,
/// \brief Record code for the set of merged declarations in an AST file.
- MERGED_DECLARATIONS = 45,
+ MERGED_DECLARATIONS = 44,
/// \brief Record code for the array of redeclaration chains.
///
/// This array can only be interpreted properly using the local
/// redeclarations map.
- LOCAL_REDECLARATIONS = 46,
+ LOCAL_REDECLARATIONS = 45,
/// \brief Record code for the array of Objective-C categories (including
/// extensions).
///
/// This array can only be interpreted properly using the Objective-C
/// categories map.
- OBJC_CATEGORIES = 47,
+ OBJC_CATEGORIES = 46,
/// \brief Record code for the table of offsets of each macro ID.
///
/// The offset table contains offsets into the blob stored in
/// the preprocessor block. Each offset points to the corresponding
/// macro definition.
- MACRO_OFFSET = 48,
+ MACRO_OFFSET = 47,
/// \brief Record of updates for a macro that was modified after
/// being deserialized.
- MACRO_UPDATES = 49
+ MACRO_UPDATES = 48
};
/// \brief Record types used within a source manager block.
llvm::SmallVectorImpl<ModuleFile *> &Loaded);
ASTReadResult ReadControlBlock(ModuleFile &F,
llvm::SmallVectorImpl<ModuleFile *> &Loaded);
+ ASTReadResult ReadInputFilesBlock(ModuleFile &F);
ASTReadResult ReadASTBlock(ModuleFile &F);
bool CheckPredefinesBuffers();
bool ParseLineTable(ModuleFile &F, SmallVectorImpl<uint64_t> &Record);
/// \brief Load the AST file designated by the given file name.
ASTReadResult ReadAST(const std::string &FileName, ModuleKind Type);
- /// \brief Checks that no file that is stored in PCH is out-of-sync with
- /// the actual file in the file system.
- ASTReadResult validateFileEntries(ModuleFile &M);
-
/// \brief Make the entities in the given module and any of its (non-explicit)
/// submodules visible to name lookup.
///
void WriteBlockInfoBlock();
void WriteControlBlock(ASTContext &Context, StringRef isysroot,
const std::string &OutputFile);
+ void WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot);
void WriteStatCache(MemorizeStatCalls &StatCalls);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
const Preprocessor &PP,
/// \brief SLocEntries that we're going to preload.
SmallVector<uint64_t, 4> PreloadSLocEntries;
- /// \brief The number of source location file entries in this AST file.
- unsigned LocalNumSLocFileEntries;
-
- /// \brief Offsets for all of the source location file entries in the
- /// AST file.
- const uint32_t *SLocFileOffsets;
-
/// \brief Remapping table for source locations in this module.
ContinuousRangeMap<uint32_t, int, 2> SLocRemap;
}
if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- Stream.ReadSubBlockID();
- if (!Stream.SkipBlock())
+ switch (Stream.ReadSubBlockID()) {
+ case INPUT_FILES_BLOCK_ID:
+ switch (ReadInputFilesBlock(F)) {
+ case Success:
+ break;
+
+ case Failure:
+ return Failure;
+
+ case IgnorePCH:
+ // FIXME: We could consider reading through to the end of this
+ // AST block, skipping subblocks, to see if there are other
+ // AST blocks elsewhere.
+ return IgnorePCH;
+ }
continue;
+
+ default:
+ if (!Stream.SkipBlock())
+ continue;
+ break;
+ }
Error("malformed block record in AST file");
return Failure;
return Failure;
}
+ASTReader::ASTReadResult ASTReader::ReadInputFilesBlock(ModuleFile &F) {
+ llvm::BitstreamCursor &Stream = F.Stream;
+
+ // If we're not doing any validation, there's no reason to read this
+ // input-files block.
+ if (DisableValidation) {
+ return Stream.SkipBlock()? Failure : Success;
+ }
+
+ if (Stream.EnterSubBlock(INPUT_FILES_BLOCK_ID)) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+
+ // Read all of the records and blocks for the AST file.
+ RecordData Record;
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ Error("error at end of module block in AST file");
+ return Failure;
+ }
+
+ DeclContext *DC = Context.getTranslationUnitDecl();
+ if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
+ DC->setMustBuildLookupTable();
+
+ return Success;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ Stream.ReadSubBlockID();
+ if (!Stream.SkipBlock())
+ continue;
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read and process a record.
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ switch ((InputFileRecordTypes)Stream.ReadRecord(Code, Record,
+ &BlobStart, &BlobLen)) {
+ case INPUT_FILE: {
+ // Check that the file exists.
+ StringRef Filename(BlobStart, BlobLen);
+ const FileEntry *File = getFileEntry(Filename);
+ if (File == 0) {
+ std::string ErrorStr = "could not find file '";
+ ErrorStr += Filename;
+ ErrorStr += "' referenced by AST file";
+ Error(ErrorStr.c_str());
+ return IgnorePCH;
+ }
+
+ off_t StoredSize = (off_t)Record[0];
+ time_t StoredTime = (time_t)Record[1];
+
+ // Check if there was a request to override the contents of the file
+ // that was part of the precompiled header. Overridding such a file
+ // can lead to problems when lexing using the source locations from the
+ // PCH.
+ SourceManager &SM = getSourceManager();
+ if (SM.isFileOverridden(File)) {
+ Error(diag::err_fe_pch_file_overridden, Filename);
+ // After emitting the diagnostic, recover by disabling the override so
+ // that the original file will be used.
+ SM.disableFileContentsOverride(File);
+ // The FileEntry is a virtual file entry with the size of the contents
+ // that would override the original contents. Set it to the original's
+ // size/time.
+ FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
+ StoredSize, StoredTime);
+ }
+
+ // The stat info from the FileEntry came from the cached stat
+ // info of the PCH, so we cannot trust it.
+ struct stat StatBuf;
+ if (::stat(File->getName(), &StatBuf) != 0) {
+ StatBuf.st_size = File->getSize();
+ StatBuf.st_mtime = File->getModificationTime();
+ }
+
+ if ((StoredSize != StatBuf.st_size
+#if !defined(LLVM_ON_WIN32)
+ // In our regression testing, the Windows file system seems to
+ // have inconsistent modification times that sometimes
+ // erroneously trigger this error-handling path.
+ || StoredTime != StatBuf.st_mtime
+#endif
+ )) {
+ Error(diag::err_fe_pch_file_modified, Filename);
+ return IgnorePCH;
+ }
+
+ break;
+ }
+ }
+ }
+
+ Error("premature end of bitstream in AST file");
+ return Failure;
+}
+
ASTReader::ASTReadResult
ASTReader::ReadASTBlock(ModuleFile &F) {
llvm::BitstreamCursor &Stream = F.Stream;
return Failure;
break;
- case FILE_SOURCE_LOCATION_OFFSETS:
- F.SLocFileOffsets = (const uint32_t *)BlobStart;
- F.LocalNumSLocFileEntries = Record[0];
- break;
-
case SOURCE_LOCATION_PRELOADS: {
// Need to transform from the local view (1-based IDs) to the global view,
// which is based off F.SLocEntryBaseID.
return Failure;
}
-ASTReader::ASTReadResult ASTReader::validateFileEntries(ModuleFile &M) {
- llvm::BitstreamCursor &SLocEntryCursor = M.SLocEntryCursor;
-
- for (unsigned i = 0, e = M.LocalNumSLocFileEntries; i != e; ++i) {
- SLocEntryCursor.JumpToBit(M.SLocFileOffsets[i]);
- unsigned Code = SLocEntryCursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK ||
- Code == llvm::bitc::ENTER_SUBBLOCK ||
- Code == llvm::bitc::DEFINE_ABBREV) {
- Error("incorrectly-formatted source location entry in AST file");
- return Failure;
- }
-
- RecordData Record;
- const char *BlobStart;
- unsigned BlobLen;
- switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
- default:
- Error("incorrectly-formatted source location entry in AST file");
- return Failure;
-
- case SM_SLOC_FILE_ENTRY: {
- // If the buffer was overridden, the file need not exist.
- if (Record[6])
- break;
-
- StringRef Filename(BlobStart, BlobLen);
- const FileEntry *File = getFileEntry(Filename);
-
- if (File == 0) {
- std::string ErrorStr = "could not find file '";
- ErrorStr += Filename;
- ErrorStr += "' referenced by AST file";
- Error(ErrorStr.c_str());
- return IgnorePCH;
- }
-
- if (Record.size() < 7) {
- Error("source location entry is incorrect");
- return Failure;
- }
-
- off_t StoredSize = (off_t)Record[4];
- time_t StoredTime = (time_t)Record[5];
-
- // Check if there was a request to override the contents of the file
- // that was part of the precompiled header. Overridding such a file
- // can lead to problems when lexing using the source locations from the
- // PCH.
- SourceManager &SM = getSourceManager();
- if (SM.isFileOverridden(File)) {
- Error(diag::err_fe_pch_file_overridden, Filename);
- // After emitting the diagnostic, recover by disabling the override so
- // that the original file will be used.
- SM.disableFileContentsOverride(File);
- // The FileEntry is a virtual file entry with the size of the contents
- // that would override the original contents. Set it to the original's
- // size/time.
- FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
- StoredSize, StoredTime);
- }
-
- // The stat info from the FileEntry came from the cached stat
- // info of the PCH, so we cannot trust it.
- struct stat StatBuf;
- if (::stat(File->getName(), &StatBuf) != 0) {
- StatBuf.st_size = File->getSize();
- StatBuf.st_mtime = File->getModificationTime();
- }
-
- if ((StoredSize != StatBuf.st_size
-#if !defined(LLVM_ON_WIN32)
- // In our regression testing, the Windows file system seems to
- // have inconsistent modification times that sometimes
- // erroneously trigger this error-handling path.
- || StoredTime != StatBuf.st_mtime
-#endif
- )) {
- Error(diag::err_fe_pch_file_modified, Filename);
- return IgnorePCH;
- }
-
- break;
- }
- }
- }
-
- return Success;
-}
-
void ASTReader::makeNamesVisible(const HiddenNames &Names) {
for (unsigned I = 0, N = Names.size(); I != N; ++I) {
switch (Names[I].getKind()) {
TotalModulesSizeInBits += F.SizeInBits;
GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F));
- // Make sure that the files this module was built against are
- // still available.
- // FIXME: Move this validation into ReadControlBlock.
- if (!DisableValidation) {
- switch(validateFileEntries(F)) {
- case Failure: return Failure;
- case IgnorePCH: return IgnorePCH;
- case Success: break;
- }
- }
-
// Preload SLocEntries.
for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) {
int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID;
RECORD(FP_PRAGMA_OPTIONS);
RECORD(OPENCL_EXTENSIONS);
RECORD(DELEGATING_CTORS);
- RECORD(FILE_SOURCE_LOCATION_OFFSETS);
RECORD(KNOWN_NAMESPACES);
RECORD(MODULE_OFFSET_MAP);
RECORD(SOURCE_MANAGER_LINE_TABLE);
Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
}
+ WriteInputFiles(Context.SourceMgr, isysroot);
+ Stream.ExitBlock();
+}
+
+void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
+ using namespace llvm;
+ Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
+ RecordData Record;
+
+ // Create input-file abbreviation.
+ BitCodeAbbrev *IFAbbrev = new BitCodeAbbrev();
+ IFAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE));
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time
+ IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
+ unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev);
+
+ // Write out all of the input files.
+ std::vector<uint32_t> InputFileOffsets;
+ for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) {
+ // Get this source location entry.
+ const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
+ FileID FID = FileID::get(I);
+ assert(&SourceMgr.getSLocEntry(FID) == SLoc);
+
+ // We only care about file entries that were not overridden.
+ if (!SLoc->isFile())
+ continue;
+ const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
+ if (!Cache->OrigEntry || Cache->BufferOverridden)
+ continue;
+
+ Record.clear();
+ Record.push_back(INPUT_FILE);
+
+ // Emit size/modification time for this file.
+ Record.push_back(Cache->OrigEntry->getSize());
+ Record.push_back(Cache->OrigEntry->getModificationTime());
+
+ // Turn the file name into an absolute path, if it isn't already.
+ const char *Filename = Cache->OrigEntry->getName();
+ SmallString<128> FilePath(Filename);
+
+ // Ask the file manager to fixup the relative path for us. This will
+ // honor the working directory.
+ SourceMgr.getFileManager().FixupRelativePath(FilePath);
+
+ // FIXME: This call to make_absolute shouldn't be necessary, the
+ // call to FixupRelativePath should always return an absolute path.
+ llvm::sys::fs::make_absolute(FilePath);
+ Filename = FilePath.c_str();
+
+ Filename = adjustFilenameForRelocatablePCH(Filename, isysroot);
+
+ Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename);
+ }
+
Stream.ExitBlock();
}
// Write out the source location entry table. We skip the first
// entry, which is always the same dummy entry.
std::vector<uint32_t> SLocEntryOffsets;
- // Write out the offsets of only source location file entries.
- // We will go through them in ASTReader::validateFileEntries().
- std::vector<uint32_t> SLocFileEntryOffsets;
RecordData PreloadSLocs;
SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1);
for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size();
const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache();
if (Cache->OrigEntry) {
Code = SM_SLOC_FILE_ENTRY;
- SLocFileEntryOffsets.push_back(Stream.GetCurrentBitNo());
} else
Code = SM_SLOC_BUFFER_ENTRY;
} else
Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy
Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets));
- Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(FILE_SOURCE_LOCATION_OFFSETS));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
- unsigned SLocFileOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
-
- Record.clear();
- Record.push_back(FILE_SOURCE_LOCATION_OFFSETS);
- Record.push_back(SLocFileEntryOffsets.size());
- Stream.EmitRecordWithBlob(SLocFileOffsetsAbbrev, Record,
- data(SLocFileEntryOffsets));
-
// Write the source location entry preloads array, telling the AST
// reader which source locations entries it should load eagerly.
Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs);
Generation(Generation), SizeInBits(0),
LocalNumSLocEntries(0), SLocEntryBaseID(0),
SLocEntryBaseOffset(0), SLocEntryOffsets(0),
- SLocFileOffsets(0), LocalNumIdentifiers(0),
+ LocalNumIdentifiers(0),
IdentifierOffsets(0), BaseIdentifierID(0), IdentifierTableData(0),
IdentifierLookupTable(0),
LocalNumMacros(0), MacroOffsets(0),
// RUN: rm %t.h || rm %t.h || rm %t.h
// Check diagnostic with location in original source:
-// RUN: %clang_cc1 -include-pch %t.h.pch -Wpadded -emit-obj -o %t.o %s 2> %t.stderr
-// RUN: grep 'bytes to align' %t.stderr
-
-// Check diagnostic with 2nd location in original source:
-// RUN: not %clang_cc1 -DREDECL -include-pch %t.h.pch -emit-obj -o %t.o %s 2> %t.stderr
-// RUN: grep 'previous definition is here' %t.stderr
-
-// Check diagnostic with instantiation location in original source:
-// RUN: not %clang_cc1 -DINSTANTIATION -include-pch %t.h.pch -emit-obj -o %t.o %s 2> %t.stderr
-// RUN: grep 'cannot be used prior to' %t.stderr
+// RUN: not %clang_cc1 -include-pch %t.h.pch -emit-obj -o %t.o %s 2> %t.stderr
+// RUN: grep 'could not find file' %t.stderr
void qq(S*) {}