summaryrefslogtreecommitdiff
path: root/lib/Serialization/ASTWriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Serialization/ASTWriter.cpp')
-rw-r--r--lib/Serialization/ASTWriter.cpp974
1 files changed, 671 insertions, 303 deletions
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index a2e8b71123b1..cf93d1cf01a7 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -13,24 +13,15 @@
#include "clang/Serialization/ASTWriter.h"
#include "ASTCommon.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/IdentifierResolver.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclContextInternals.h"
-#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
-#include "clang/Serialization/ASTReader.h"
-#include "clang/Lex/HeaderSearchOptions.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/PreprocessingRecord.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/OnDiskHashTable.h"
@@ -40,8 +31,18 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Sema/IdentifierResolver.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/FileSystem.h"
@@ -353,7 +354,7 @@ ASTTypeWriter::VisitDependentTemplateSpecializationType(
void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) {
Writer.AddTypeRef(T->getPattern(), Record);
- if (llvm::Optional<unsigned> NumExpansions = T->getNumExpansions())
+ if (Optional<unsigned> NumExpansions = T->getNumExpansions())
Record.push_back(*NumExpansions + 1);
else
Record.push_back(0);
@@ -777,6 +778,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(TARGET_OPTIONS);
RECORD(ORIGINAL_FILE);
RECORD(ORIGINAL_PCH_DIR);
+ RECORD(ORIGINAL_FILE_ID);
RECORD(INPUT_FILE_OFFSETS);
RECORD(DIAGNOSTIC_OPTIONS);
RECORD(FILE_SYSTEM_OPTIONS);
@@ -797,7 +799,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(STATISTICS);
RECORD(TENTATIVE_DEFINITIONS);
RECORD(UNUSED_FILESCOPED_DECLS);
- RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS);
+ RECORD(LOCALLY_SCOPED_EXTERN_C_DECLS);
RECORD(SELECTOR_OFFSETS);
RECORD(METHOD_POOL);
RECORD(PP_COUNTER_VALUE);
@@ -823,6 +825,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(OPENCL_EXTENSIONS);
RECORD(DELEGATING_CTORS);
RECORD(KNOWN_NAMESPACES);
+ RECORD(UNDEFINED_BUT_USED);
RECORD(MODULE_OFFSET_MAP);
RECORD(SOURCE_MANAGER_LINE_TABLE);
RECORD(OBJC_CATEGORIES_MAP);
@@ -832,7 +835,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(LOCAL_REDECLARATIONS);
RECORD(OBJC_CATEGORIES);
RECORD(MACRO_OFFSET);
- RECORD(MACRO_UPDATES);
+ RECORD(MACRO_TABLE);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -1020,7 +1023,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
// Imports
if (Chain) {
serialization::ModuleManager &Mgr = Chain->getModuleManager();
- llvm::SmallVector<char, 128> ModulePaths;
+ SmallVector<char, 128> ModulePaths;
Record.clear();
for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end();
@@ -1030,7 +1033,9 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
continue;
Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding
- // FIXME: Write import location, once it matters.
+ AddSourceLocation((*M)->ImportLoc, Record);
+ Record.push_back((*M)->File->getSize());
+ Record.push_back((*M)->File->getModificationTime());
// FIXME: This writes the absolute path for AST files we depend on.
const std::string &FileName = (*M)->FileName;
Record.push_back(FileName.size());
@@ -1047,12 +1052,24 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
#include "clang/Basic/LangOptions.def"
+#define SANITIZER(NAME, ID) Record.push_back(LangOpts.Sanitize.ID);
+#include "clang/Basic/Sanitizers.def"
Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind());
AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record);
Record.push_back(LangOpts.CurrentModule.size());
Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end());
+
+ // Comment options.
+ Record.push_back(LangOpts.CommentOpts.BlockCommandNames.size());
+ for (CommentOptions::BlockCommandNamesTy::const_iterator
+ I = LangOpts.CommentOpts.BlockCommandNames.begin(),
+ IEnd = LangOpts.CommentOpts.BlockCommandNames.end();
+ I != IEnd; ++I) {
+ AddString(*I, Record);
+ }
+
Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
// Target options.
@@ -1108,11 +1125,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I];
AddString(Entry.Path, Record);
Record.push_back(static_cast<unsigned>(Entry.Group));
- Record.push_back(Entry.IsUserSupplied);
Record.push_back(Entry.IsFramework);
Record.push_back(Entry.IgnoreSysRoot);
- Record.push_back(Entry.IsInternal);
- Record.push_back(Entry.ImplicitExternC);
}
// System header prefixes.
@@ -1180,6 +1194,10 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
}
+ Record.clear();
+ Record.push_back(SM.getMainFileID().getOpaqueValue());
+ Stream.EmitRecord(ORIGINAL_FILE_ID, Record);
+
// Original PCH directory
if (!OutputFile.empty() && OutputFile != "-") {
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
@@ -1197,11 +1215,24 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
}
- WriteInputFiles(Context.SourceMgr, isysroot);
+ WriteInputFiles(Context.SourceMgr,
+ PP.getHeaderSearchInfo().getHeaderSearchOpts(),
+ isysroot);
Stream.ExitBlock();
}
-void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
+namespace {
+ /// \brief An input file.
+ struct InputFileEntry {
+ const FileEntry *File;
+ bool IsSystemFile;
+ bool BufferOverridden;
+ };
+}
+
+void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
+ HeaderSearchOptions &HSOpts,
+ StringRef isysroot) {
using namespace llvm;
Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
RecordData Record;
@@ -1216,8 +1247,9 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev);
- // Write out all of the input files.
- std::vector<uint32_t> InputFileOffsets;
+ // Get all ContentCache objects for files, sorted by whether the file is a
+ // system one or not. System files go at the back, users files at the front.
+ std::deque<InputFileEntry> SortedFiles;
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);
@@ -1230,28 +1262,67 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
if (!Cache->OrigEntry)
continue;
+ InputFileEntry Entry;
+ Entry.File = Cache->OrigEntry;
+ Entry.IsSystemFile = Cache->IsSystemFile;
+ Entry.BufferOverridden = Cache->BufferOverridden;
+ if (Cache->IsSystemFile)
+ SortedFiles.push_back(Entry);
+ else
+ SortedFiles.push_front(Entry);
+ }
+
+ // If we have an isysroot for a Darwin SDK, include its SDKSettings.plist in
+ // the set of (non-system) input files. This is simple heuristic for
+ // detecting whether the system headers may have changed, because it is too
+ // expensive to stat() all of the system headers.
+ FileManager &FileMgr = SourceMgr.getFileManager();
+ if (!HSOpts.Sysroot.empty() && !Chain) {
+ llvm::SmallString<128> SDKSettingsFileName(HSOpts.Sysroot);
+ llvm::sys::path::append(SDKSettingsFileName, "SDKSettings.plist");
+ if (const FileEntry *SDKSettingsFile = FileMgr.getFile(SDKSettingsFileName)) {
+ InputFileEntry Entry = { SDKSettingsFile, false, false };
+ SortedFiles.push_front(Entry);
+ }
+ }
+
+ unsigned UserFilesNum = 0;
+ // Write out all of the input files.
+ std::vector<uint32_t> InputFileOffsets;
+ for (std::deque<InputFileEntry>::iterator
+ I = SortedFiles.begin(), E = SortedFiles.end(); I != E; ++I) {
+ const InputFileEntry &Entry = *I;
+
+ uint32_t &InputFileID = InputFileIDs[Entry.File];
+ if (InputFileID != 0)
+ continue; // already recorded this file.
+
// Record this entry's offset.
InputFileOffsets.push_back(Stream.GetCurrentBitNo());
- InputFileIDs[Cache->OrigEntry] = InputFileOffsets.size();
+
+ InputFileID = InputFileOffsets.size();
+
+ if (!Entry.IsSystemFile)
+ ++UserFilesNum;
Record.clear();
Record.push_back(INPUT_FILE);
Record.push_back(InputFileOffsets.size());
// Emit size/modification time for this file.
- Record.push_back(Cache->OrigEntry->getSize());
- Record.push_back(Cache->OrigEntry->getModificationTime());
+ Record.push_back(Entry.File->getSize());
+ Record.push_back(Entry.File->getModificationTime());
// Whether this file was overridden.
- Record.push_back(Cache->BufferOverridden);
+ Record.push_back(Entry.BufferOverridden);
// Turn the file name into an absolute path, if it isn't already.
- const char *Filename = Cache->OrigEntry->getName();
+ const char *Filename = Entry.File->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);
+ FileMgr.FixupRelativePath(FilePath);
// FIXME: This call to make_absolute shouldn't be necessary, the
// call to FixupRelativePath should always return an absolute path.
@@ -1262,13 +1333,15 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename);
}
-
+
Stream.ExitBlock();
// Create input file offsets abbreviation.
BitCodeAbbrev *OffsetsAbbrev = new BitCodeAbbrev();
OffsetsAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_OFFSETS));
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # input files
+ OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # non-system
+ // input files
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Array
unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev);
@@ -1276,58 +1349,11 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
Record.clear();
Record.push_back(INPUT_FILE_OFFSETS);
Record.push_back(InputFileOffsets.size());
+ Record.push_back(UserFilesNum);
Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, data(InputFileOffsets));
}
//===----------------------------------------------------------------------===//
-// stat cache Serialization
-//===----------------------------------------------------------------------===//
-
-namespace {
-// Trait used for the on-disk hash table of stat cache results.
-class ASTStatCacheTrait {
-public:
- typedef const char * key_type;
- typedef key_type key_type_ref;
-
- typedef struct stat data_type;
- typedef const data_type &data_type_ref;
-
- static unsigned ComputeHash(const char *path) {
- return llvm::HashString(path);
- }
-
- std::pair<unsigned,unsigned>
- EmitKeyDataLength(raw_ostream& Out, const char *path,
- data_type_ref Data) {
- unsigned StrLen = strlen(path);
- clang::io::Emit16(Out, StrLen);
- unsigned DataLen = 4 + 4 + 2 + 8 + 8;
- clang::io::Emit8(Out, DataLen);
- return std::make_pair(StrLen + 1, DataLen);
- }
-
- void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
- Out.write(path, KeyLen);
- }
-
- void EmitData(raw_ostream &Out, key_type_ref,
- data_type_ref Data, unsigned DataLen) {
- using namespace clang::io;
- uint64_t Start = Out.tell(); (void)Start;
-
- Emit32(Out, (uint32_t) Data.st_ino);
- Emit32(Out, (uint32_t) Data.st_dev);
- Emit16(Out, (uint16_t) Data.st_mode);
- Emit64(Out, (uint64_t) Data.st_mtime);
- Emit64(Out, (uint64_t) Data.st_size);
-
- assert(Out.tell() - Start == DataLen && "Wrong data length");
- }
-};
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
// Source Manager Serialization
//===----------------------------------------------------------------------===//
@@ -1391,44 +1417,53 @@ namespace {
// Trait used for the on-disk hash table of header search information.
class HeaderFileInfoTrait {
ASTWriter &Writer;
+ const HeaderSearch &HS;
// Keep track of the framework names we've used during serialization.
SmallVector<char, 128> FrameworkStringData;
llvm::StringMap<unsigned> FrameworkNameOffset;
public:
- HeaderFileInfoTrait(ASTWriter &Writer)
- : Writer(Writer) { }
+ HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS)
+ : Writer(Writer), HS(HS) { }
- typedef const char *key_type;
- typedef key_type key_type_ref;
+ struct key_type {
+ const FileEntry *FE;
+ const char *Filename;
+ };
+ typedef const key_type &key_type_ref;
typedef HeaderFileInfo data_type;
typedef const data_type &data_type_ref;
- static unsigned ComputeHash(const char *path) {
- // The hash is based only on the filename portion of the key, so that the
- // reader can match based on filenames when symlinking or excess path
- // elements ("foo/../", "../") change the form of the name. However,
- // complete path is still the key.
- return llvm::HashString(llvm::sys::path::filename(path));
+ static unsigned ComputeHash(key_type_ref key) {
+ // The hash is based only on size/time of the file, so that the reader can
+ // match even when symlinking or excess path elements ("foo/../", "../")
+ // change the form of the name. However, complete path is still the key.
+ return llvm::hash_combine(key.FE->getSize(),
+ key.FE->getModificationTime());
}
std::pair<unsigned,unsigned>
- EmitKeyDataLength(raw_ostream& Out, const char *path,
- data_type_ref Data) {
- unsigned StrLen = strlen(path);
- clang::io::Emit16(Out, StrLen);
+ EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {
+ unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8;
+ clang::io::Emit16(Out, KeyLen);
unsigned DataLen = 1 + 2 + 4 + 4;
+ if (Data.isModuleHeader)
+ DataLen += 4;
clang::io::Emit8(Out, DataLen);
- return std::make_pair(StrLen + 1, DataLen);
+ return std::make_pair(KeyLen, DataLen);
}
- void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
- Out.write(path, KeyLen);
+ void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) {
+ clang::io::Emit64(Out, key.FE->getSize());
+ KeyLen -= 8;
+ clang::io::Emit64(Out, key.FE->getModificationTime());
+ KeyLen -= 8;
+ Out.write(key.Filename, KeyLen);
}
- void EmitData(raw_ostream &Out, key_type_ref,
+ void EmitData(raw_ostream &Out, key_type_ref key,
data_type_ref Data, unsigned DataLen) {
using namespace clang::io;
uint64_t Start = Out.tell(); (void)Start;
@@ -1462,7 +1497,12 @@ namespace {
Offset = Pos->second;
}
Emit32(Out, Offset);
-
+
+ if (Data.isModuleHeader) {
+ Module *Mod = HS.findModuleForHeader(key.FE);
+ Emit32(Out, Writer.getExistingSubmoduleID(Mod));
+ }
+
assert(Out.tell() - Start == DataLen && "Wrong data length");
}
@@ -1481,7 +1521,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
if (FilesByUID.size() > HS.header_file_size())
FilesByUID.resize(HS.header_file_size());
- HeaderFileInfoTrait GeneratorTrait(*this);
+ HeaderFileInfoTrait GeneratorTrait(*this, HS);
OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
SmallVector<const char *, 4> SavedStrings;
unsigned NumHeaderSearchEntries = 0;
@@ -1507,7 +1547,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
SavedStrings.push_back(Filename);
}
- Generator.insert(Filename, HFI, GeneratorTrait);
+ HeaderFileInfoTrait::key_type key = { File, Filename };
+ Generator.insert(key, HFI, GeneratorTrait);
++NumHeaderSearchEntries;
}
@@ -1542,7 +1583,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
// Free all of the strings we had to duplicate.
for (unsigned I = 0, N = SavedStrings.size(); I != N; ++I)
- free((void*)SavedStrings[I]);
+ free(const_cast<char *>(SavedStrings[I]));
}
/// \brief Writes the block containing the serialized form of the
@@ -1746,14 +1787,67 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Preprocessor Serialization
//===----------------------------------------------------------------------===//
-static int compareMacroDefinitions(const void *XPtr, const void *YPtr) {
- const std::pair<const IdentifierInfo *, MacroInfo *> &X =
- *(const std::pair<const IdentifierInfo *, MacroInfo *>*)XPtr;
- const std::pair<const IdentifierInfo *, MacroInfo *> &Y =
- *(const std::pair<const IdentifierInfo *, MacroInfo *>*)YPtr;
+namespace {
+class ASTMacroTableTrait {
+public:
+ typedef IdentID key_type;
+ typedef key_type key_type_ref;
+
+ struct Data {
+ uint32_t MacroDirectivesOffset;
+ };
+
+ typedef Data data_type;
+ typedef const data_type &data_type_ref;
+
+ static unsigned ComputeHash(IdentID IdID) {
+ return llvm::hash_value(IdID);
+ }
+
+ std::pair<unsigned,unsigned>
+ static EmitKeyDataLength(raw_ostream& Out,
+ key_type_ref Key, data_type_ref Data) {
+ unsigned KeyLen = 4; // IdentID.
+ unsigned DataLen = 4; // MacroDirectivesOffset.
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ static void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {
+ clang::io::Emit32(Out, Key);
+ }
+
+ static void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
+ unsigned) {
+ clang::io::Emit32(Out, Data.MacroDirectivesOffset);
+ }
+};
+} // end anonymous namespace
+
+static int compareMacroDirectives(const void *XPtr, const void *YPtr) {
+ const std::pair<const IdentifierInfo *, MacroDirective *> &X =
+ *(const std::pair<const IdentifierInfo *, MacroDirective *>*)XPtr;
+ const std::pair<const IdentifierInfo *, MacroDirective *> &Y =
+ *(const std::pair<const IdentifierInfo *, MacroDirective *>*)YPtr;
return X.first->getName().compare(Y.first->getName());
}
+static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule,
+ const Preprocessor &PP) {
+ if (MacroInfo *MI = MD->getMacroInfo())
+ if (MI->isBuiltinMacro())
+ return true;
+
+ if (IsModule) {
+ SourceLocation Loc = MD->getLocation();
+ if (Loc.isInvalid())
+ return true;
+ if (PP.getSourceManager().getFileID(Loc) == PP.getPredefinesFileID())
+ return true;
+ }
+
+ return false;
+}
+
/// \brief Writes the block containing the serialized form of the
/// preprocessor.
///
@@ -1780,26 +1874,73 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n");
- // Loop over all the macro definitions that are live at the end of the file,
+ // Loop over all the macro directives that are live at the end of the file,
// emitting each to the PP section.
- // Construct the list of macro definitions that need to be serialized.
- SmallVector<std::pair<const IdentifierInfo *, MacroInfo *>, 2>
- MacrosToEmit;
- llvm::SmallPtrSet<const IdentifierInfo*, 4> MacroDefinitionsSeen;
- for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0),
- E = PP.macro_end(Chain == 0);
+ // Construct the list of macro directives that need to be serialized.
+ SmallVector<std::pair<const IdentifierInfo *, MacroDirective *>, 2>
+ MacroDirectives;
+ for (Preprocessor::macro_iterator
+ I = PP.macro_begin(/*IncludeExternalMacros=*/false),
+ E = PP.macro_end(/*IncludeExternalMacros=*/false);
I != E; ++I) {
- if (!IsModule || I->second->isPublic()) {
- MacroDefinitionsSeen.insert(I->first);
- MacrosToEmit.push_back(std::make_pair(I->first, I->second));
- }
+ MacroDirectives.push_back(std::make_pair(I->first, I->second));
}
// Sort the set of macro definitions that need to be serialized by the
// name of the macro, to provide a stable ordering.
- llvm::array_pod_sort(MacrosToEmit.begin(), MacrosToEmit.end(),
- &compareMacroDefinitions);
+ llvm::array_pod_sort(MacroDirectives.begin(), MacroDirectives.end(),
+ &compareMacroDirectives);
+
+ OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator;
+
+ // Emit the macro directives as a list and associate the offset with the
+ // identifier they belong to.
+ for (unsigned I = 0, N = MacroDirectives.size(); I != N; ++I) {
+ const IdentifierInfo *Name = MacroDirectives[I].first;
+ uint64_t MacroDirectiveOffset = Stream.GetCurrentBitNo();
+ MacroDirective *MD = MacroDirectives[I].second;
+
+ // If the macro or identifier need no updates, don't write the macro history
+ // for this one.
+ // FIXME: Chain the macro history instead of re-writing it.
+ if (MD->isFromPCH() &&
+ Name->isFromAST() && !Name->hasChangedSinceDeserialization())
+ continue;
+
+ // Emit the macro directives in reverse source order.
+ for (; MD; MD = MD->getPrevious()) {
+ if (MD->isHidden())
+ continue;
+ if (shouldIgnoreMacro(MD, IsModule, PP))
+ continue;
+
+ AddSourceLocation(MD->getLocation(), Record);
+ Record.push_back(MD->getKind());
+ if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ MacroID InfoID = getMacroRef(DefMD->getInfo(), Name);
+ Record.push_back(InfoID);
+ Record.push_back(DefMD->isImported());
+ Record.push_back(DefMD->isAmbiguous());
+
+ } else if (VisibilityMacroDirective *
+ VisMD = dyn_cast<VisibilityMacroDirective>(MD)) {
+ Record.push_back(VisMD->isPublic());
+ }
+ }
+ if (Record.empty())
+ continue;
+
+ Stream.EmitRecord(PP_MACRO_DIRECTIVE_HISTORY, Record);
+ Record.clear();
+
+ IdentMacroDirectivesOffsetMap[Name] = MacroDirectiveOffset;
+
+ IdentID NameID = getIdentifierRef(Name);
+ ASTMacroTableTrait::Data data;
+ data.MacroDirectivesOffset = MacroDirectiveOffset;
+ Generator.insert(NameID, data);
+ }
/// \brief Offsets of each of the macros into the bitstream, indexed by
/// the local macro ID
@@ -1809,95 +1950,107 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
/// defined.
std::vector<uint32_t> MacroOffsets;
- for (unsigned I = 0, N = MacrosToEmit.size(); I != N; ++I) {
- const IdentifierInfo *Name = MacrosToEmit[I].first;
+ for (unsigned I = 0, N = MacroInfosToEmit.size(); I != N; ++I) {
+ const IdentifierInfo *Name = MacroInfosToEmit[I].Name;
+ MacroInfo *MI = MacroInfosToEmit[I].MI;
+ MacroID ID = MacroInfosToEmit[I].ID;
- for (MacroInfo *MI = MacrosToEmit[I].second; MI;
- MI = MI->getPreviousDefinition()) {
- MacroID ID = getMacroRef(MI);
- if (!ID)
- continue;
+ if (ID < FirstMacroID) {
+ assert(0 && "Loaded MacroInfo entered MacroInfosToEmit ?");
+ continue;
+ }
- // Skip macros from a AST file if we're chaining.
- if (Chain && MI->isFromAST() && !MI->hasChangedAfterLoad())
- continue;
+ // Record the local offset of this macro.
+ unsigned Index = ID - FirstMacroID;
+ if (Index == MacroOffsets.size())
+ MacroOffsets.push_back(Stream.GetCurrentBitNo());
+ else {
+ if (Index > MacroOffsets.size())
+ MacroOffsets.resize(Index + 1);
- if (ID < FirstMacroID) {
- // This will have been dealt with via an update record.
- assert(MacroUpdates.count(MI) > 0 && "Missing macro update");
- continue;
- }
+ MacroOffsets[Index] = Stream.GetCurrentBitNo();
+ }
- // Record the local offset of this macro.
- unsigned Index = ID - FirstMacroID;
- if (Index == MacroOffsets.size())
- MacroOffsets.push_back(Stream.GetCurrentBitNo());
- else {
- if (Index > MacroOffsets.size())
- MacroOffsets.resize(Index + 1);
+ AddIdentifierRef(Name, Record);
+ Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc()));
+ AddSourceLocation(MI->getDefinitionLoc(), Record);
+ AddSourceLocation(MI->getDefinitionEndLoc(), Record);
+ Record.push_back(MI->isUsed());
+ unsigned Code;
+ if (MI->isObjectLike()) {
+ Code = PP_MACRO_OBJECT_LIKE;
+ } else {
+ Code = PP_MACRO_FUNCTION_LIKE;
- MacroOffsets[Index] = Stream.GetCurrentBitNo();
- }
+ Record.push_back(MI->isC99Varargs());
+ Record.push_back(MI->isGNUVarargs());
+ Record.push_back(MI->hasCommaPasting());
+ Record.push_back(MI->getNumArgs());
+ for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
+ I != E; ++I)
+ AddIdentifierRef(*I, Record);
+ }
- AddIdentifierRef(Name, Record);
- addMacroRef(MI, Record);
- Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc()));
- AddSourceLocation(MI->getDefinitionLoc(), Record);
- AddSourceLocation(MI->getUndefLoc(), Record);
- Record.push_back(MI->isUsed());
- Record.push_back(MI->isPublic());
- AddSourceLocation(MI->getVisibilityLocation(), Record);
- unsigned Code;
- if (MI->isObjectLike()) {
- Code = PP_MACRO_OBJECT_LIKE;
- } else {
- Code = PP_MACRO_FUNCTION_LIKE;
-
- Record.push_back(MI->isC99Varargs());
- Record.push_back(MI->isGNUVarargs());
- Record.push_back(MI->getNumArgs());
- for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
- I != E; ++I)
- AddIdentifierRef(*I, Record);
- }
+ // If we have a detailed preprocessing record, record the macro definition
+ // ID that corresponds to this macro.
+ if (PPRec)
+ Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]);
- // If we have a detailed preprocessing record, record the macro definition
- // ID that corresponds to this macro.
- if (PPRec)
- Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]);
+ Stream.EmitRecord(Code, Record);
+ Record.clear();
- Stream.EmitRecord(Code, Record);
+ // Emit the tokens array.
+ for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) {
+ // Note that we know that the preprocessor does not have any annotation
+ // tokens in it because they are created by the parser, and thus can't
+ // be in a macro definition.
+ const Token &Tok = MI->getReplacementToken(TokNo);
+
+ Record.push_back(Tok.getLocation().getRawEncoding());
+ Record.push_back(Tok.getLength());
+
+ // FIXME: When reading literal tokens, reconstruct the literal pointer
+ // if it is needed.
+ AddIdentifierRef(Tok.getIdentifierInfo(), Record);
+ // FIXME: Should translate token kind to a stable encoding.
+ Record.push_back(Tok.getKind());
+ // FIXME: Should translate token flags to a stable encoding.
+ Record.push_back(Tok.getFlags());
+
+ Stream.EmitRecord(PP_TOKEN, Record);
Record.clear();
-
- // Emit the tokens array.
- for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) {
- // Note that we know that the preprocessor does not have any annotation
- // tokens in it because they are created by the parser, and thus can't
- // be in a macro definition.
- const Token &Tok = MI->getReplacementToken(TokNo);
-
- Record.push_back(Tok.getLocation().getRawEncoding());
- Record.push_back(Tok.getLength());
-
- // FIXME: When reading literal tokens, reconstruct the literal pointer
- // if it is needed.
- AddIdentifierRef(Tok.getIdentifierInfo(), Record);
- // FIXME: Should translate token kind to a stable encoding.
- Record.push_back(Tok.getKind());
- // FIXME: Should translate token flags to a stable encoding.
- Record.push_back(Tok.getFlags());
-
- Stream.EmitRecord(PP_TOKEN, Record);
- Record.clear();
- }
- ++NumMacros;
}
+ ++NumMacros;
}
+
Stream.ExitBlock();
- // Write the offsets table for macro IDs.
+ // Create the on-disk hash table in a buffer.
+ SmallString<4096> MacroTable;
+ uint32_t BucketOffset;
+ {
+ llvm::raw_svector_ostream Out(MacroTable);
+ // Make sure that no bucket is at offset 0
+ clang::io::Emit32(Out, 0);
+ BucketOffset = Generator.Emit(Out);
+ }
+
+ // Write the macro table
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MACRO_TABLE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned MacroTableAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Record.push_back(MACRO_TABLE);
+ Record.push_back(BucketOffset);
+ Stream.EmitRecordWithBlob(MacroTableAbbrev, Record, MacroTable.str());
+ Record.clear();
+
+ // Write the offsets table for macro IDs.
+ using namespace llvm;
+ Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
@@ -2019,6 +2172,18 @@ unsigned ASTWriter::getSubmoduleID(Module *Mod) {
return SubmoduleIDs[Mod] = NextSubmoduleID++;
}
+unsigned ASTWriter::getExistingSubmoduleID(Module *Mod) const {
+ if (!Mod)
+ return 0;
+
+ llvm::DenseMap<Module *, unsigned>::const_iterator
+ Known = SubmoduleIDs.find(Mod);
+ if (Known != SubmoduleIDs.end())
+ return Known->second;
+
+ return 0;
+}
+
/// \brief Compute the number of modules within the given tree (including the
/// given module).
static unsigned getNumberOfModules(Module *Mod) {
@@ -2062,6 +2227,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
@@ -2095,6 +2261,23 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned LinkLibraryAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFIG_MACRO));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name
+ unsigned ConfigMacroAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFLICT));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Other module
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message
+ unsigned ConflictAbbrev = Stream.EmitAbbrev(Abbrev);
+
// Write the submodule metadata block.
RecordData Record;
Record.push_back(getNumberOfModules(WritingModule));
@@ -2125,6 +2308,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Record.push_back(Mod->InferSubmodules);
Record.push_back(Mod->InferExplicitSubmodules);
Record.push_back(Mod->InferExportWildcard);
+ Record.push_back(Mod->ConfigMacrosExhaustive);
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
// Emit the requirements.
@@ -2163,11 +2347,13 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record,
Mod->ExcludedHeaders[I]->getName());
}
- for (unsigned I = 0, N = Mod->TopHeaders.size(); I != N; ++I) {
+ ArrayRef<const FileEntry *>
+ TopHeaders = Mod->getTopHeaders(PP->getFileManager());
+ for (unsigned I = 0, N = TopHeaders.size(); I != N; ++I) {
Record.clear();
Record.push_back(SUBMODULE_TOPHEADER);
Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record,
- Mod->TopHeaders[I]->getName());
+ TopHeaders[I]->getName());
}
// Emit the imports.
@@ -2197,7 +2383,35 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
}
Stream.EmitRecord(SUBMODULE_EXPORTS, Record);
}
-
+
+ // Emit the link libraries.
+ for (unsigned I = 0, N = Mod->LinkLibraries.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_LINK_LIBRARY);
+ Record.push_back(Mod->LinkLibraries[I].IsFramework);
+ Stream.EmitRecordWithBlob(LinkLibraryAbbrev, Record,
+ Mod->LinkLibraries[I].Library);
+ }
+
+ // Emit the conflicts.
+ for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_CONFLICT);
+ unsigned OtherID = getSubmoduleID(Mod->Conflicts[I].Other);
+ assert(OtherID && "Unknown submodule!");
+ Record.push_back(OtherID);
+ Stream.EmitRecordWithBlob(ConflictAbbrev, Record,
+ Mod->Conflicts[I].Message);
+ }
+
+ // Emit the configuration macros.
+ for (unsigned I = 0, N = Mod->ConfigMacros.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_CONFIG_MACRO);
+ Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record,
+ Mod->ConfigMacros[I]);
+ }
+
// Queue up the submodules of this module.
for (Module::submodule_iterator Sub = Mod->submodule_begin(),
SubEnd = Mod->submodule_end();
@@ -2230,8 +2444,14 @@ ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
return getSubmoduleID(OwningMod);
}
-void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
- // FIXME: Make it work properly with modules.
+void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
+ bool isModule) {
+ // Make sure set diagnostic pragmas don't affect the translation unit that
+ // imports the module.
+ // FIXME: Make diagnostic pragma sections work properly with modules.
+ if (isModule)
+ return;
+
llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64>
DiagStateIDMap;
unsigned CurrID = 0;
@@ -2664,7 +2884,7 @@ class ASTIdentifierTableTrait {
/// \brief Determines whether this is an "interesting" identifier
/// that needs a full IdentifierInfo structure written into the hash
/// table.
- bool isInterestingIdentifier(IdentifierInfo *II, MacroInfo *&Macro) {
+ bool isInterestingIdentifier(IdentifierInfo *II, MacroDirective *&Macro) {
if (II->isPoisoned() ||
II->isExtensionToken() ||
II->getObjCOrBuiltinID() ||
@@ -2675,16 +2895,101 @@ class ASTIdentifierTableTrait {
return hadMacroDefinition(II, Macro);
}
- bool hadMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) {
+ bool hadMacroDefinition(IdentifierInfo *II, MacroDirective *&Macro) {
if (!II->hadMacroDefinition())
return false;
- if (Macro || (Macro = PP.getMacroInfoHistory(II)))
- return !Macro->isBuiltinMacro() && (!IsModule || Macro->isPublic());
+ if (Macro || (Macro = PP.getMacroDirectiveHistory(II))) {
+ if (!IsModule)
+ return !shouldIgnoreMacro(Macro, IsModule, PP);
+ SubmoduleID ModID;
+ if (getFirstPublicSubmoduleMacro(Macro, ModID))
+ return true;
+ }
return false;
}
+ DefMacroDirective *getFirstPublicSubmoduleMacro(MacroDirective *MD,
+ SubmoduleID &ModID) {
+ ModID = 0;
+ if (DefMacroDirective *DefMD = getPublicSubmoduleMacro(MD, ModID))
+ if (!shouldIgnoreMacro(DefMD, IsModule, PP))
+ return DefMD;
+ return 0;
+ }
+
+ DefMacroDirective *getNextPublicSubmoduleMacro(DefMacroDirective *MD,
+ SubmoduleID &ModID) {
+ if (DefMacroDirective *
+ DefMD = getPublicSubmoduleMacro(MD->getPrevious(), ModID))
+ if (!shouldIgnoreMacro(DefMD, IsModule, PP))
+ return DefMD;
+ return 0;
+ }
+
+ /// \brief Traverses the macro directives history and returns the latest
+ /// macro that is public and not undefined in the same submodule.
+ /// A macro that is defined in submodule A and undefined in submodule B,
+ /// will still be considered as defined/exported from submodule A.
+ DefMacroDirective *getPublicSubmoduleMacro(MacroDirective *MD,
+ SubmoduleID &ModID) {
+ if (!MD)
+ return 0;
+
+ SubmoduleID OrigModID = ModID;
+ bool isUndefined = false;
+ Optional<bool> isPublic;
+ for (; MD; MD = MD->getPrevious()) {
+ if (MD->isHidden())
+ continue;
+
+ SubmoduleID ThisModID = getSubmoduleID(MD);
+ if (ThisModID == 0) {
+ isUndefined = false;
+ isPublic = Optional<bool>();
+ continue;
+ }
+ if (ThisModID != ModID){
+ ModID = ThisModID;
+ isUndefined = false;
+ isPublic = Optional<bool>();
+ }
+ // We are looking for a definition in a different submodule than the one
+ // that we started with. If a submodule has re-definitions of the same
+ // macro, only the last definition will be used as the "exported" one.
+ if (ModID == OrigModID)
+ continue;
+
+ if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ if (!isUndefined && (!isPublic.hasValue() || isPublic.getValue()))
+ return DefMD;
+ continue;
+ }
+
+ if (isa<UndefMacroDirective>(MD)) {
+ isUndefined = true;
+ continue;
+ }
+
+ VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD);
+ if (!isPublic.hasValue())
+ isPublic = VisMD->isPublic();
+ }
+
+ return 0;
+ }
+
+ SubmoduleID getSubmoduleID(MacroDirective *MD) {
+ if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ MacroInfo *MI = DefMD->getInfo();
+ if (unsigned ID = MI->getOwningModuleID())
+ return ID;
+ return Writer.inferSubmoduleIDFromLocation(MI->getDefinitionLoc());
+ }
+ return Writer.inferSubmoduleIDFromLocation(MD->getLocation());
+ }
+
public:
typedef IdentifierInfo* key_type;
typedef key_type key_type_ref;
@@ -2704,17 +3009,21 @@ public:
EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {
unsigned KeyLen = II->getLength() + 1;
unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
- MacroInfo *Macro = 0;
+ MacroDirective *Macro = 0;
if (isInterestingIdentifier(II, Macro)) {
DataLen += 2; // 2 bytes for builtin ID
DataLen += 2; // 2 bytes for flags
if (hadMacroDefinition(II, Macro)) {
- for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) {
- if (Writer.getMacroRef(M) != 0)
- DataLen += 4;
+ DataLen += 4; // MacroDirectives offset.
+ if (IsModule) {
+ SubmoduleID ModID;
+ for (DefMacroDirective *
+ DefMD = getFirstPublicSubmoduleMacro(Macro, ModID);
+ DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) {
+ DataLen += 4; // MacroInfo ID.
+ }
+ DataLen += 4;
}
-
- DataLen += 4;
}
for (IdentifierResolver::iterator D = IdResolver.begin(II),
@@ -2740,7 +3049,7 @@ public:
void EmitData(raw_ostream& Out, IdentifierInfo* II,
IdentID ID, unsigned) {
- MacroInfo *Macro = 0;
+ MacroDirective *Macro = 0;
if (!isInterestingIdentifier(II, Macro)) {
clang::io::Emit32(Out, ID << 1);
return;
@@ -2753,6 +3062,7 @@ public:
Bits = 0;
bool HadMacroDefinition = hadMacroDefinition(II, Macro);
Bits = (Bits << 1) | unsigned(HadMacroDefinition);
+ Bits = (Bits << 1) | unsigned(IsModule);
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
Bits = (Bits << 1) | unsigned(II->isPoisoned());
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
@@ -2760,13 +3070,19 @@ public:
clang::io::Emit16(Out, Bits);
if (HadMacroDefinition) {
- // Write all of the macro IDs associated with this identifier.
- for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) {
- if (MacroID ID = Writer.getMacroRef(M))
- clang::io::Emit32(Out, ID);
+ clang::io::Emit32(Out, Writer.getMacroDirectivesOffset(II));
+ if (IsModule) {
+ // Write the IDs of macros coming from different submodules.
+ SubmoduleID ModID;
+ for (DefMacroDirective *
+ DefMD = getFirstPublicSubmoduleMacro(Macro, ModID);
+ DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) {
+ MacroID InfoID = Writer.getMacroID(DefMD->getInfo());
+ assert(InfoID);
+ clang::io::Emit32(Out, InfoID);
+ }
+ clang::io::Emit32(Out, 0);
}
-
- clang::io::Emit32(Out, 0);
}
// Emit the declaration IDs in reverse order, because the
@@ -2820,7 +3136,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
assert(ID->first && "NULL identifier in identifier table");
if (!Chain || !ID->first->isFromAST() ||
ID->first->hasChangedSinceDeserialization())
- Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,
+ Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,
Trait);
}
@@ -2857,6 +3173,11 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+#ifndef NDEBUG
+ for (unsigned I = 0, N = IdentifierOffsets.size(); I != N; ++I)
+ assert(IdentifierOffsets[I] && "Missing identifier offset?");
+#endif
+
RecordData Record;
Record.push_back(IDENTIFIER_OFFSET);
Record.push_back(IdentifierOffsets.size());
@@ -2936,7 +3257,7 @@ public:
clang::io::Emit16(Out, KeyLen);
// 2 bytes for num of decls and 4 for each DeclID.
- unsigned DataLen = 2 + 4 * (Lookup.second - Lookup.first);
+ unsigned DataLen = 2 + 4 * Lookup.size();
clang::io::Emit16(Out, DataLen);
return std::make_pair(KeyLen, DataLen);
@@ -2976,9 +3297,10 @@ public:
void EmitData(raw_ostream& Out, key_type_ref,
data_type Lookup, unsigned DataLen) {
uint64_t Start = Out.tell(); (void)Start;
- clang::io::Emit16(Out, Lookup.second - Lookup.first);
- for (; Lookup.first != Lookup.second; ++Lookup.first)
- clang::io::Emit32(Out, Writer.GetDeclRef(*Lookup.first));
+ clang::io::Emit16(Out, Lookup.size());
+ for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end();
+ I != E; ++I)
+ clang::io::Emit32(Out, Writer.GetDeclRef(*I));
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
@@ -3002,8 +3324,6 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
// If not in C++, we perform name lookup for the translation unit via the
// IdentifierInfo chains, don't bother to build a visible-declarations table.
- // FIXME: In C++ we need the visible declarations in order to "see" the
- // friend declarations, is there a way to do this without writing the table ?
if (DC->isTranslationUnit() && !Context.getLangOpts().CPlusPlus)
return 0;
@@ -3022,12 +3342,12 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
// Create the on-disk hash table representation.
DeclarationName ConversionName;
- llvm::SmallVector<NamedDecl *, 4> ConversionDecls;
+ SmallVector<NamedDecl *, 4> ConversionDecls;
for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
D != DEnd; ++D) {
DeclarationName Name = D->first;
DeclContext::lookup_result Result = D->second.getLookupResult();
- if (Result.first != Result.second) {
+ if (!Result.empty()) {
if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
// Hash all conversion function names to the same name. The actual
// type information in conversion function name is not used in the
@@ -3036,7 +3356,7 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
// functions under a single key.
if (!ConversionName)
ConversionName = Name;
- ConversionDecls.append(Result.first, Result.second);
+ ConversionDecls.append(Result.begin(), Result.end());
continue;
}
@@ -3095,7 +3415,7 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {
DeclContext::lookup_result Result = D->second.getLookupResult();
// For any name that appears in this table, the results are complete, i.e.
// they overwrite results from previous PCHs. Merging is always a mess.
- if (Result.first != Result.second)
+ if (!Result.empty())
Generator.insert(Name, Result, Trait);
}
@@ -3156,20 +3476,32 @@ void ASTWriter::WriteRedeclarations() {
LocalRedeclChains.push_back(0); // Placeholder for the size.
// Collect the set of local redeclarations of this declaration.
- for (Decl *Prev = MostRecent; Prev != First;
+ for (Decl *Prev = MostRecent; Prev != First;
Prev = Prev->getPreviousDecl()) {
if (!Prev->isFromASTFile()) {
AddDeclRef(Prev, LocalRedeclChains);
++Size;
}
}
+
+ if (!First->isFromASTFile() && Chain) {
+ Decl *FirstFromAST = MostRecent;
+ for (Decl *Prev = MostRecent; Prev; Prev = Prev->getPreviousDecl()) {
+ if (Prev->isFromASTFile())
+ FirstFromAST = Prev;
+ }
+
+ Chain->MergedDecls[FirstFromAST].push_back(getDeclID(First));
+ }
+
LocalRedeclChains[Offset] = Size;
// Reverse the set of local redeclarations, so that we store them in
// order (since we found them in reverse order).
std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end());
- // Add the mapping from the first ID to the set of local declarations.
+ // Add the mapping from the first ID from the AST to the set of local
+ // declarations.
LocalRedeclarationsInfo Info = { getDeclID(First), Offset };
LocalRedeclsMap.push_back(Info);
@@ -3204,7 +3536,7 @@ void ASTWriter::WriteRedeclarations() {
}
void ASTWriter::WriteObjCCategories() {
- llvm::SmallVector<ObjCCategoriesInfo, 2> CategoriesMap;
+ SmallVector<ObjCCategoriesInfo, 2> CategoriesMap;
RecordData Categories;
for (unsigned I = 0, N = ObjCClassesWithCategories.size(); I != N; ++I) {
@@ -3217,10 +3549,12 @@ void ASTWriter::WriteObjCCategories() {
Categories.push_back(0);
// Add the categories.
- for (ObjCCategoryDecl *Cat = Class->getCategoryList();
- Cat; Cat = Cat->getNextClassCategory(), ++Size) {
- assert(getDeclID(Cat) != 0 && "Bogus category");
- AddDeclRef(Cat, Categories);
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Class->known_categories_begin(),
+ CatEnd = Class->known_categories_end();
+ Cat != CatEnd; ++Cat, ++Size) {
+ assert(getDeclID(*Cat) != 0 && "Bogus category");
+ AddDeclRef(*Cat, Categories);
}
// Update the size.
@@ -3300,11 +3634,11 @@ void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) {
void ASTWriter::AddVersionTuple(const VersionTuple &Version,
RecordDataImpl &Record) {
Record.push_back(Version.getMajor());
- if (llvm::Optional<unsigned> Minor = Version.getMinor())
+ if (Optional<unsigned> Minor = Version.getMinor())
Record.push_back(*Minor + 1);
else
Record.push_back(0);
- if (llvm::Optional<unsigned> Subminor = Version.getSubminor())
+ if (Optional<unsigned> Subminor = Version.getSubminor())
Record.push_back(*Subminor + 1);
else
Record.push_back(0);
@@ -3405,6 +3739,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Module *WritingModule) {
using namespace llvm;
+ bool isModule = WritingModule != 0;
+
// Make sure that the AST reader knows to finalize itself.
if (Chain)
Chain->finalizeForWriting();
@@ -3447,11 +3783,19 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// If there are any out-of-date identifiers, bring them up to date.
if (ExternalPreprocessorSource *ExtSource = PP.getExternalSource()) {
+ // Find out-of-date identifiers.
+ SmallVector<IdentifierInfo *, 4> OutOfDate;
for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
IDEnd = PP.getIdentifierTable().end();
- ID != IDEnd; ++ID)
+ ID != IDEnd; ++ID) {
if (ID->second->isOutOfDate())
- ExtSource->updateOutOfDateIdentifier(*ID->second);
+ OutOfDate.push_back(ID->second);
+ }
+
+ // Update the out-of-date identifiers.
+ for (unsigned I = 0, N = OutOfDate.size(); I != N; ++I) {
+ ExtSource->updateOutOfDateIdentifier(*OutOfDate[I]);
+ }
}
// Build a record containing all of the tentative definitions in this file, in
@@ -3462,13 +3806,15 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// Build a record containing all of the file scoped decls in this file.
RecordData UnusedFileScopedDecls;
- AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls,
- UnusedFileScopedDecls);
+ if (!isModule)
+ AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls,
+ UnusedFileScopedDecls);
// Build a record containing all of the delegating constructors we still need
// to resolve.
RecordData DelegatingCtorDecls;
- AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls);
+ if (!isModule)
+ AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls);
// Write the set of weak, undeclared identifiers. We always write the
// entire table, since later PCH files in a PCH chain are only interested in
@@ -3485,18 +3831,18 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
}
}
- // Build a record containing all of the locally-scoped external
+ // Build a record containing all of the locally-scoped extern "C"
// declarations in this header file. Generally, this record will be
// empty.
- RecordData LocallyScopedExternalDecls;
+ RecordData LocallyScopedExternCDecls;
// FIXME: This is filling in the AST file in densemap order which is
// nondeterminstic!
for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
- TD = SemaRef.LocallyScopedExternalDecls.begin(),
- TDEnd = SemaRef.LocallyScopedExternalDecls.end();
+ TD = SemaRef.LocallyScopedExternCDecls.begin(),
+ TDEnd = SemaRef.LocallyScopedExternCDecls.end();
TD != TDEnd; ++TD) {
if (!TD->second->isFromASTFile())
- AddDeclRef(TD->second, LocallyScopedExternalDecls);
+ AddDeclRef(TD->second, LocallyScopedExternCDecls);
}
// Build a record containing all of the ext_vector declarations.
@@ -3542,7 +3888,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// Build a record containing all of the known namespaces.
RecordData KnownNamespaces;
- for (llvm::DenseMap<NamespaceDecl*, bool>::iterator
+ for (llvm::MapVector<NamespaceDecl*, bool>::iterator
I = SemaRef.KnownNamespaces.begin(),
IEnd = SemaRef.KnownNamespaces.end();
I != IEnd; ++I) {
@@ -3550,6 +3896,17 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
AddDeclRef(I->first, KnownNamespaces);
}
+ // Build a record of all used, undefined objects that require definitions.
+ RecordData UndefinedButUsed;
+
+ SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined;
+ SemaRef.getUndefinedButUsed(Undefined);
+ for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator
+ I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
+ AddDeclRef(I->first, UndefinedButUsed);
+ AddSourceLocation(I->second, UndefinedButUsed);
+ }
+
// Write the control block
WriteControlBlock(PP, Context, isysroot, OutputFile);
@@ -3557,6 +3914,12 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
RecordData Record;
Stream.EnterSubblock(AST_BLOCK_ID, 5);
+ // This is so that older clang versions, before the introduction
+ // of the control block, can read and reject the newer PCH format.
+ Record.clear();
+ Record.push_back(VERSION_MAJOR);
+ Stream.EmitRecord(METADATA_OLD_FORMAT, Record);
+
// Create a lexical update block containing all of the declarations in the
// translation unit that do not come from other AST files.
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
@@ -3686,16 +4049,16 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,
Buffer.data(), Buffer.size());
}
- WritePreprocessor(PP, WritingModule != 0);
+ WritePreprocessor(PP, isModule);
WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
WriteSelectors(SemaRef);
WriteReferencedSelectorsPool(SemaRef);
- WriteIdentifierTable(PP, SemaRef.IdResolver, WritingModule != 0);
+ WriteIdentifierTable(PP, SemaRef.IdResolver, isModule);
WriteFPPragmaOptions(SemaRef.getFPOptions());
WriteOpenCLExtensions(SemaRef);
WriteTypeDeclOffsets();
- WritePragmaDiagnosticMappings(Context.getDiagnostics());
+ WritePragmaDiagnosticMappings(Context.getDiagnostics(), isModule);
WriteCXXBaseSpecifiersOffsets();
@@ -3722,10 +4085,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS,
WeakUndeclaredIdentifiers);
- // Write the record containing locally-scoped external definitions.
- if (!LocallyScopedExternalDecls.empty())
- Stream.EmitRecord(LOCALLY_SCOPED_EXTERNAL_DECLS,
- LocallyScopedExternalDecls);
+ // Write the record containing locally-scoped extern "C" definitions.
+ if (!LocallyScopedExternCDecls.empty())
+ Stream.EmitRecord(LOCALLY_SCOPED_EXTERN_C_DECLS,
+ LocallyScopedExternCDecls);
// Write the record containing ext_vector type names.
if (!ExtVectorDecls.empty())
@@ -3758,6 +4121,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// Write the known namespaces.
if (!KnownNamespaces.empty())
Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces);
+
+ // Write the undefined internal functions and variables, and inline functions.
+ if (!UndefinedButUsed.empty())
+ Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed);
// Write the visible updates to DeclContexts.
for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator
@@ -3788,11 +4155,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
}
}
- WriteMacroUpdates();
WriteDeclUpdatesBlocks();
WriteDeclReplacementsBlock();
- WriteMergedDecls();
WriteRedeclarations();
+ WriteMergedDecls();
WriteObjCCategories();
// Some simple statistics
@@ -3805,21 +4171,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.ExitBlock();
}
-void ASTWriter::WriteMacroUpdates() {
- if (MacroUpdates.empty())
- return;
-
- RecordData Record;
- for (MacroUpdatesMap::iterator I = MacroUpdates.begin(),
- E = MacroUpdates.end();
- I != E; ++I) {
- addMacroRef(I->first, Record);
- AddSourceLocation(I->second.UndefLoc, Record);
- Record.push_back(inferSubmoduleIDFromLocation(I->second.UndefLoc));
- }
- Stream.EmitRecord(MACRO_UPDATES, Record);
-}
-
/// \brief Go through the declaration update blocks and resolve declaration
/// pointers into declaration IDs.
void ASTWriter::ResolveDeclUpdatesBlocks() {
@@ -3915,10 +4266,6 @@ void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Recor
Record.push_back(getIdentifierRef(II));
}
-void ASTWriter::addMacroRef(MacroInfo *MI, RecordDataImpl &Record) {
- Record.push_back(getMacroRef(MI));
-}
-
IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
if (II == 0)
return 0;
@@ -3929,7 +4276,7 @@ IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
return ID;
}
-MacroID ASTWriter::getMacroRef(MacroInfo *MI) {
+MacroID ASTWriter::getMacroRef(MacroInfo *MI, const IdentifierInfo *Name) {
// Don't emit builtin macros like __LINE__ to the AST file unless they
// have been redefined by the header (in which case they are not
// isBuiltinMacro).
@@ -3937,11 +4284,27 @@ MacroID ASTWriter::getMacroRef(MacroInfo *MI) {
return 0;
MacroID &ID = MacroIDs[MI];
- if (ID == 0)
+ if (ID == 0) {
ID = NextMacroID++;
+ MacroInfoToEmitData Info = { Name, MI, ID };
+ MacroInfosToEmit.push_back(Info);
+ }
return ID;
}
+MacroID ASTWriter::getMacroID(MacroInfo *MI) {
+ if (MI == 0 || MI->isBuiltinMacro())
+ return 0;
+
+ assert(MacroIDs.find(MI) != MacroIDs.end() && "Macro not emitted!");
+ return MacroIDs[MI];
+}
+
+uint64_t ASTWriter::getMacroDirectivesOffset(const IdentifierInfo *Name) {
+ assert(IdentMacroDirectivesOffsetMap[Name] && "not set!");
+ return IdentMacroDirectivesOffsetMap[Name];
+}
+
void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) {
Record.push_back(getSelectorRef(SelRef));
}
@@ -3951,14 +4314,16 @@ SelectorID ASTWriter::getSelectorRef(Selector Sel) {
return 0;
}
- SelectorID &SID = SelectorIDs[Sel];
+ SelectorID SID = SelectorIDs[Sel];
if (SID == 0 && Chain) {
// This might trigger a ReadSelector callback, which will set the ID for
// this selector.
Chain->LoadSelector(Sel);
+ SID = SelectorIDs[Sel];
}
if (SID == 0) {
SID = NextSelectorID++;
+ SelectorIDs[Sel] = SID;
}
return SID;
}
@@ -4431,7 +4796,7 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
break;
case TemplateArgument::TemplateExpansion:
AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record);
- if (llvm::Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions())
+ if (Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions())
Record.push_back(*NumExpansions + 1);
else
Record.push_back(0);
@@ -4474,9 +4839,9 @@ ASTWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs,
void
-ASTWriter::AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordDataImpl &Record) {
+ASTWriter::AddUnresolvedSet(const ASTUnresolvedSet &Set, RecordDataImpl &Record) {
Record.push_back(Set.size());
- for (UnresolvedSetImpl::const_iterator
+ for (ASTUnresolvedSet::const_iterator
I = Set.begin(), E = Set.end(); I != E; ++I) {
AddDeclRef(I.getDecl(), Record);
Record.push_back(I.getAccess());
@@ -4568,11 +4933,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData;
Record.push_back(Data.IsLambda);
Record.push_back(Data.UserDeclaredConstructor);
- Record.push_back(Data.UserDeclaredCopyConstructor);
- Record.push_back(Data.UserDeclaredMoveConstructor);
- Record.push_back(Data.UserDeclaredCopyAssignment);
- Record.push_back(Data.UserDeclaredMoveAssignment);
- Record.push_back(Data.UserDeclaredDestructor);
+ Record.push_back(Data.UserDeclaredSpecialMembers);
Record.push_back(Data.Aggregate);
Record.push_back(Data.PlainOldData);
Record.push_back(Data.Empty);
@@ -4586,25 +4947,26 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.HasMutableFields);
Record.push_back(Data.HasOnlyCMembers);
Record.push_back(Data.HasInClassInitializer);
- Record.push_back(Data.HasTrivialDefaultConstructor);
+ Record.push_back(Data.HasUninitializedReferenceMember);
+ Record.push_back(Data.NeedOverloadResolutionForMoveConstructor);
+ Record.push_back(Data.NeedOverloadResolutionForMoveAssignment);
+ Record.push_back(Data.NeedOverloadResolutionForDestructor);
+ Record.push_back(Data.DefaultedMoveConstructorIsDeleted);
+ Record.push_back(Data.DefaultedMoveAssignmentIsDeleted);
+ Record.push_back(Data.DefaultedDestructorIsDeleted);
+ Record.push_back(Data.HasTrivialSpecialMembers);
+ Record.push_back(Data.HasIrrelevantDestructor);
Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr);
Record.push_back(Data.HasConstexprDefaultConstructor);
- Record.push_back(Data.HasTrivialCopyConstructor);
- Record.push_back(Data.HasTrivialMoveConstructor);
- Record.push_back(Data.HasTrivialCopyAssignment);
- Record.push_back(Data.HasTrivialMoveAssignment);
- Record.push_back(Data.HasTrivialDestructor);
- Record.push_back(Data.HasIrrelevantDestructor);
Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
Record.push_back(Data.ComputedVisibleConversions);
Record.push_back(Data.UserProvidedDefaultConstructor);
- Record.push_back(Data.DeclaredDefaultConstructor);
- Record.push_back(Data.DeclaredCopyConstructor);
- Record.push_back(Data.DeclaredMoveConstructor);
- Record.push_back(Data.DeclaredCopyAssignment);
- Record.push_back(Data.DeclaredMoveAssignment);
- Record.push_back(Data.DeclaredDestructor);
+ Record.push_back(Data.DeclaredSpecialMembers);
+ Record.push_back(Data.ImplicitCopyConstructorHasConstParam);
+ Record.push_back(Data.ImplicitCopyAssignmentHasConstParam);
+ Record.push_back(Data.HasDeclaredCopyConstructorWithConstParam);
+ Record.push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
Record.push_back(Data.FailedImplicitMoveConstructor);
Record.push_back(Data.FailedImplicitMoveAssignment);
// IsLambda bit is already saved.
@@ -4676,11 +5038,17 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) {
}
void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
- IdentifierIDs[II] = ID;
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ IdentID &StoredID = IdentifierIDs[II];
+ if (ID > StoredID)
+ StoredID = ID;
}
void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) {
- MacroIDs[MI] = ID;
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ MacroID &StoredID = MacroIDs[MI];
+ if (ID > StoredID)
+ StoredID = ID;
}
void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
@@ -4695,7 +5063,10 @@ void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
}
void ASTWriter::SelectorRead(SelectorID ID, Selector S) {
- SelectorIDs[S] = ID;
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ SelectorID &StoredID = SelectorIDs[S];
+ if (ID > StoredID)
+ StoredID = ID;
}
void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID,
@@ -4709,10 +5080,6 @@ void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) {
SubmoduleIDs[Mod] = ID;
}
-void ASTWriter::UndefinedMacro(MacroInfo *MI) {
- MacroUpdates[MI].UndefLoc = MI->getUndefLoc();
-}
-
void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
assert(D->isCompleteDefinition());
assert(!WritingAST && "Already writing the AST!");
@@ -4737,6 +5104,7 @@ void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
if (!(!D->isFromASTFile() && cast<Decl>(DC)->isFromASTFile()))
return; // Not a source decl added to a DeclContext from PCH.
+ assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!");
AddUpdatedDeclContext(DC);
UpdatingVisibleDecls.push_back(D);
}