diff options
author | dim <dim@FreeBSD.org> | 2014-11-24 18:11:16 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2014-11-24 18:11:16 +0000 |
commit | 6148c19c738a92f344008aa3f88f4e008bada0ee (patch) | |
tree | d4426858455f04d0d8c25a2f9eb9ea5582ffe1b6 /contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp | |
parent | 2c8643c6396b0a3db33430cf9380e70bbb9efce0 (diff) | |
parent | 173a4f43a911175643bda81ee675e8d9269056ea (diff) | |
download | FreeBSD-src-6148c19c738a92f344008aa3f88f4e008bada0ee.zip FreeBSD-src-6148c19c738a92f344008aa3f88f4e008bada0ee.tar.gz |
Merge clang 3.5.0 release from ^/vendor/clang/dist, resolve conflicts,
and preserve our customizations, where necessary.
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp | 1104 |
1 files changed, 697 insertions, 407 deletions
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp index 405488c..0f52a9f 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp @@ -17,14 +17,15 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclLookups.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/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemStatCache.h" -#include "clang/Basic/OnDiskHashTable.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/TargetInfo.h" @@ -45,8 +46,10 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Support/EndianStream.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/OnDiskHashTable.h" #include "llvm/Support/Path.h" #include <algorithm> #include <cstdio> @@ -113,6 +116,12 @@ void ASTTypeWriter::VisitDecayedType(const DecayedType *T) { Code = TYPE_DECAYED; } +void ASTTypeWriter::VisitAdjustedType(const AdjustedType *T) { + Writer.AddTypeRef(T->getOriginalType(), Record); + Writer.AddTypeRef(T->getAdjustedType(), Record); + Code = TYPE_ADJUSTED; +} + void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) { Writer.AddTypeRef(T->getPointeeType(), Record); Code = TYPE_BLOCK_POINTER; @@ -173,7 +182,7 @@ void ASTTypeWriter::VisitExtVectorType(const ExtVectorType *T) { } void ASTTypeWriter::VisitFunctionType(const FunctionType *T) { - Writer.AddTypeRef(T->getResultType(), Record); + Writer.AddTypeRef(T->getReturnType(), Record); FunctionType::ExtInfo C = T->getExtInfo(); Record.push_back(C.getNoReturn()); Record.push_back(C.getHasRegParm()); @@ -188,15 +197,8 @@ void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { Code = TYPE_FUNCTION_NO_PROTO; } -void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { - VisitFunctionType(T); - Record.push_back(T->getNumArgs()); - for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I) - Writer.AddTypeRef(T->getArgType(I), Record); - Record.push_back(T->isVariadic()); - Record.push_back(T->hasTrailingReturn()); - Record.push_back(T->getTypeQuals()); - Record.push_back(static_cast<unsigned>(T->getRefQualifier())); +static void addExceptionSpec(ASTWriter &Writer, const FunctionProtoType *T, + ASTWriter::RecordDataImpl &Record) { Record.push_back(T->getExceptionSpecType()); if (T->getExceptionSpecType() == EST_Dynamic) { Record.push_back(T->getNumExceptions()); @@ -210,6 +212,18 @@ void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { } else if (T->getExceptionSpecType() == EST_Unevaluated) { Writer.AddDeclRef(T->getExceptionSpecDecl(), Record); } +} + +void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { + VisitFunctionType(T); + Record.push_back(T->getNumParams()); + for (unsigned I = 0, N = T->getNumParams(); I != N; ++I) + Writer.AddTypeRef(T->getParamType(I), Record); + Record.push_back(T->isVariadic()); + Record.push_back(T->hasTrailingReturn()); + Record.push_back(T->getTypeQuals()); + Record.push_back(static_cast<unsigned>(T->getRefQualifier())); + addExceptionSpec(Writer, T, Record); Code = TYPE_FUNCTION_PROTO; } @@ -395,9 +409,8 @@ void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { Writer.AddTypeRef(T->getBaseType(), Record); Record.push_back(T->getNumProtocols()); - for (ObjCObjectType::qual_iterator I = T->qual_begin(), - E = T->qual_end(); I != E; ++I) - Writer.AddDeclRef(*I, Record); + for (const auto *I : T->quals()) + Writer.AddDeclRef(I, Record); Code = TYPE_OBJC_OBJECT; } @@ -455,6 +468,9 @@ void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) { void TypeLocWriter::VisitDecayedTypeLoc(DecayedTypeLoc TL) { // nothing to do } +void TypeLocWriter::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { + // nothing to do +} void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { Writer.AddSourceLocation(TL.getCaretLoc(), Record); } @@ -503,8 +519,8 @@ void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { Writer.AddSourceLocation(TL.getLParenLoc(), Record); Writer.AddSourceLocation(TL.getRParenLoc(), Record); Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record); - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) - Writer.AddDeclRef(TL.getArg(i), Record); + for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) + Writer.AddDeclRef(TL.getParam(i), Record); } void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); @@ -645,7 +661,8 @@ static void EmitBlockID(unsigned ID, const char *Name, Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); // Emit the block name if present. - if (Name == 0 || Name[0] == 0) return; + if (!Name || Name[0] == 0) + return; Record.clear(); while (*Name) Record.push_back(*Name++); @@ -764,10 +781,8 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream, RECORD(EXPR_CXX_UNRESOLVED_CONSTRUCT); RECORD(EXPR_CXX_UNRESOLVED_MEMBER); RECORD(EXPR_CXX_UNRESOLVED_LOOKUP); - RECORD(EXPR_CXX_UNARY_TYPE_TRAIT); RECORD(EXPR_CXX_NOEXCEPT); RECORD(EXPR_OPAQUE_VALUE); - RECORD(EXPR_BINARY_TYPE_TRAIT); RECORD(EXPR_PACK_EXPANSION); RECORD(EXPR_SIZEOF_PACK); RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK); @@ -785,6 +800,8 @@ void ASTWriter::WriteBlockInfoBlock() { // Control Block. BLOCK(CONTROL_BLOCK); RECORD(METADATA); + RECORD(MODULE_NAME); + RECORD(MODULE_MAP_FILE); RECORD(IMPORTS); RECORD(LANGUAGE_OPTIONS); RECORD(TARGET_OPTIONS); @@ -806,7 +823,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DECL_OFFSET); RECORD(IDENTIFIER_OFFSET); RECORD(IDENTIFIER_TABLE); - RECORD(EXTERNAL_DEFINITIONS); + RECORD(EAGERLY_DESERIALIZED_DECLS); RECORD(SPECIAL_TYPES); RECORD(STATISTICS); RECORD(TENTATIVE_DEFINITIONS); @@ -849,6 +866,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(MACRO_OFFSET); RECORD(MACRO_TABLE); RECORD(LATE_PARSED_TEMPLATE); + RECORD(OPTIMIZE_PRAGMA_OPTIONS); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); @@ -1037,10 +1055,35 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record, getClangFullRepositoryVersion()); + // Module name + if (WritingModule) { + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); + RecordData Record; + Record.push_back(MODULE_NAME); + Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name); + } + + // Module map file + if (WritingModule) { + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(MODULE_MAP_FILE)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Filename + unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); + + assert(WritingModule->ModuleMap && "missing module map"); + SmallString<128> ModuleMap(WritingModule->ModuleMap->getName()); + llvm::sys::fs::make_absolute(ModuleMap); + RecordData Record; + Record.push_back(MODULE_MAP_FILE); + Stream.EmitRecordWithBlob(AbbrevCode, Record, ModuleMap.str()); + } + // Imports if (Chain) { serialization::ModuleManager &Mgr = Chain->getModuleManager(); - SmallVector<char, 128> ModulePaths; Record.clear(); for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end(); @@ -1053,7 +1096,6 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, 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()); Record.append(FileName.begin(), FileName.end()); @@ -1097,8 +1139,6 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, AddString(TargetOpts.Triple, Record); AddString(TargetOpts.CPU, Record); AddString(TargetOpts.ABI, Record); - AddString(TargetOpts.CXXABI, Record); - AddString(TargetOpts.LinkerVersion, Record); Record.push_back(TargetOpts.FeaturesAsWritten.size()); for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); I != N; ++I) { AddString(TargetOpts.FeaturesAsWritten[I], Record); @@ -1120,6 +1160,9 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Record.push_back(DiagOpts.Warnings.size()); for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I) AddString(DiagOpts.Warnings[I], Record); + Record.push_back(DiagOpts.Remarks.size()); + for (unsigned I = 0, N = DiagOpts.Remarks.size(); I != N; ++I) + AddString(DiagOpts.Remarks[I], Record); // Note: we don't serialize the log or serialization file names, because they // are generally transient files and will almost always be overridden. Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record); @@ -1156,6 +1199,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, AddString(HSOpts.ResourceDir, Record); AddString(HSOpts.ModuleCachePath, Record); + AddString(HSOpts.ModuleUserBuildPath, Record); Record.push_back(HSOpts.DisableModuleHash); Record.push_back(HSOpts.UseBuiltinIncludes); Record.push_back(HSOpts.UseStandardSystemIncludes); @@ -1294,33 +1338,6 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, 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); - } - } - - // Add the compiler's own module.map in the set of (non-system) input files. - // This is a simple heuristic for detecting whether the compiler's headers - // have changed, because we don't want to stat() all of them. - if (Modules && !Chain) { - SmallString<128> P = StringRef(HSOpts.ResourceDir); - llvm::sys::path::append(P, "include"); - llvm::sys::path::append(P, "module.map"); - if (const FileEntry *ModuleMapFile = FileMgr.getFile(P)) { - InputFileEntry Entry = { ModuleMapFile, false, false }; - SortedFiles.push_front(Entry); - } - } - unsigned UserFilesNum = 0; // Write out all of the input files. std::vector<uint32_t> InputFileOffsets; @@ -1357,7 +1374,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, // Ask the file manager to fixup the relative path for us. This will // honor the working directory. - FileMgr.FixupRelativePath(FilePath); + SourceMgr.getFileManager().FixupRelativePath(FilePath); // FIXME: This call to make_absolute shouldn't be necessary, the // call to FixupRelativePath should always return an absolute path. @@ -1470,8 +1487,10 @@ namespace { typedef HeaderFileInfo data_type; typedef const data_type &data_type_ref; + typedef unsigned hash_value_type; + typedef unsigned offset_type; - static unsigned ComputeHash(key_type_ref key) { + static hash_value_type 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. @@ -1481,26 +1500,31 @@ namespace { std::pair<unsigned,unsigned> EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) { + using namespace llvm::support; + endian::Writer<little> Writer(Out); unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8; - clang::io::Emit16(Out, KeyLen); + Writer.write<uint16_t>(KeyLen); unsigned DataLen = 1 + 2 + 4 + 4; if (Data.isModuleHeader) DataLen += 4; - clang::io::Emit8(Out, DataLen); + Writer.write<uint8_t>(DataLen); return std::make_pair(KeyLen, DataLen); } void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) { - clang::io::Emit64(Out, key.FE->getSize()); + using namespace llvm::support; + endian::Writer<little> LE(Out); + LE.write<uint64_t>(key.FE->getSize()); KeyLen -= 8; - clang::io::Emit64(Out, key.FE->getModificationTime()); + LE.write<uint64_t>(key.FE->getModificationTime()); KeyLen -= 8; Out.write(key.Filename, KeyLen); } void EmitData(raw_ostream &Out, key_type_ref key, data_type_ref Data, unsigned DataLen) { - using namespace clang::io; + using namespace llvm::support; + endian::Writer<little> LE(Out); uint64_t Start = Out.tell(); (void)Start; unsigned char Flags = (Data.HeaderRole << 6) @@ -1509,13 +1533,13 @@ namespace { | (Data.DirInfo << 2) | (Data.Resolved << 1) | Data.IndexHeaderMapHeader; - Emit8(Out, (uint8_t)Flags); - Emit16(Out, (uint16_t) Data.NumIncludes); + LE.write<uint8_t>(Flags); + LE.write<uint16_t>(Data.NumIncludes); if (!Data.ControllingMacro) - Emit32(Out, (uint32_t)Data.ControllingMacroID); + LE.write<uint32_t>(Data.ControllingMacroID); else - Emit32(Out, (uint32_t)Writer.getIdentifierRef(Data.ControllingMacro)); + LE.write<uint32_t>(Writer.getIdentifierRef(Data.ControllingMacro)); unsigned Offset = 0; if (!Data.Framework.empty()) { @@ -1532,11 +1556,11 @@ namespace { } else Offset = Pos->second; } - Emit32(Out, Offset); + LE.write<uint32_t>(Offset); if (Data.isModuleHeader) { Module *Mod = HS.findModuleForHeader(key.FE).getModule(); - Emit32(Out, Writer.getExistingSubmoduleID(Mod)); + LE.write<uint32_t>(Writer.getExistingSubmoduleID(Mod)); } assert(Out.tell() - Start == DataLen && "Wrong data length"); @@ -1558,7 +1582,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) { FilesByUID.resize(HS.header_file_size()); HeaderFileInfoTrait GeneratorTrait(*this, HS); - OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator; + llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator; SmallVector<const char *, 4> SavedStrings; unsigned NumHeaderSearchEntries = 0; for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) { @@ -1568,10 +1592,10 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) { // Use HeaderSearch's getFileInfo to make sure we get the HeaderFileInfo // from the external source if it was not provided already. - const HeaderFileInfo &HFI = HS.getFileInfo(File); - if (HFI.External && Chain) - continue; - if (HFI.isModuleHeader && !HFI.isCompilingModuleHeader) + HeaderFileInfo HFI; + if (!HS.tryGetFileInfo(File, HFI) || + (HFI.External && Chain) || + (HFI.isModuleHeader && !HFI.isCompilingModuleHeader)) continue; // Turn the file name into an absolute path, if it isn't already. @@ -1594,9 +1618,10 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) { SmallString<4096> TableData; uint32_t BucketOffset; { + using namespace llvm::support; llvm::raw_svector_ostream Out(TableData); // Make sure that no bucket is at offset 0 - clang::io::Emit32(Out, 0); + endian::Writer<little>(Out).write<uint32_t>(0); BucketOffset = Generator.Emit(Out, GeneratorTrait); } @@ -1837,8 +1862,10 @@ public: typedef Data data_type; typedef const data_type &data_type_ref; + typedef unsigned hash_value_type; + typedef unsigned offset_type; - static unsigned ComputeHash(IdentID IdID) { + static hash_value_type ComputeHash(IdentID IdID) { return llvm::hash_value(IdID); } @@ -1851,12 +1878,14 @@ public: } static void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) { - clang::io::Emit32(Out, Key); + using namespace llvm::support; + endian::Writer<little>(Out).write<uint32_t>(Key); } static void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data, unsigned) { - clang::io::Emit32(Out, Data.MacroDirectivesOffset); + using namespace llvm::support; + endian::Writer<little>(Out).write<uint32_t>(Data.MacroDirectivesOffset); } }; } // end anonymous namespace @@ -1874,6 +1903,12 @@ static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule, return true; if (IsModule) { + // Re-export any imported directives. + // FIXME: Also ensure we re-export imported #undef directives. + if (auto *DMD = dyn_cast<DefMacroDirective>(MD)) + if (DMD->isImported()) + return false; + SourceLocation Loc = MD->getLocation(); if (Loc.isInvalid()) return true; @@ -1928,7 +1963,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { llvm::array_pod_sort(MacroDirectives.begin(), MacroDirectives.end(), &compareMacroDirectives); - OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator; + llvm::OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator; // Emit the macro directives as a list and associate the offset with the // identifier they belong to. @@ -1946,8 +1981,6 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { // Emit the macro directives in reverse source order. for (; MD; MD = MD->getPrevious()) { - if (MD->isHidden()) - continue; if (shouldIgnoreMacro(MD, IsModule, PP)) continue; @@ -2012,6 +2045,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { AddSourceLocation(MI->getDefinitionLoc(), Record); AddSourceLocation(MI->getDefinitionEndLoc(), Record); Record.push_back(MI->isUsed()); + Record.push_back(MI->isUsedForHeaderGuard()); unsigned Code; if (MI->isObjectLike()) { Code = PP_MACRO_OBJECT_LIKE; @@ -2054,9 +2088,10 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { SmallString<4096> MacroTable; uint32_t BucketOffset; { + using namespace llvm::support; llvm::raw_svector_ostream Out(MacroTable); // Make sure that no bucket is at offset 0 - clang::io::Emit32(Out, 0); + endian::Writer<little>(Out).write<uint32_t>(0); BucketOffset = Generator.Emit(Out); } @@ -2227,9 +2262,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { // other consumers of this information. SourceManager &SrcMgr = PP->getSourceManager(); ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap(); - for (ASTContext::import_iterator I = Context->local_import_begin(), - IEnd = Context->local_import_end(); - I != IEnd; ++I) { + for (const auto *I : Context->local_imports()) { if (Module *ImportedFrom = ModMap.inferModuleFromLocation(FullSourceLoc(I->getLocation(), SrcMgr))) { @@ -2248,7 +2281,8 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExternC Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild... @@ -2336,6 +2370,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Record.push_back(Mod->IsFramework); Record.push_back(Mod->IsExplicit); Record.push_back(Mod->IsSystem); + Record.push_back(Mod->IsExternC); Record.push_back(Mod->InferSubmodules); Record.push_back(Mod->InferExplicitSubmodules); Record.push_back(Mod->InferExportWildcard); @@ -2516,7 +2551,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, I = point.State->begin(), E = point.State->end(); I != E; ++I) { if (I->second.isPragma()) { Record.push_back(I->first); - Record.push_back(I->second.getMapping()); + Record.push_back((unsigned)I->second.getSeverity()); } } Record.push_back(-1); // mark the end of the diag/map pairs for this @@ -2618,9 +2653,8 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context, RecordData Record; Record.push_back(DECL_CONTEXT_LEXICAL); SmallVector<KindDeclIDPair, 64> Decls; - for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end(); - D != DEnd; ++D) - Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D))); + for (const auto *D : DC->decls()) + Decls.push_back(std::make_pair(D->getKind(), GetDeclRef(D))); ++NumLexicalDeclContexts; Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, data(Decls)); @@ -2719,17 +2753,22 @@ public: }; typedef const data_type& data_type_ref; + typedef unsigned hash_value_type; + typedef unsigned offset_type; + explicit ASTMethodPoolTrait(ASTWriter &Writer) : Writer(Writer) { } - static unsigned ComputeHash(Selector Sel) { + static hash_value_type ComputeHash(Selector Sel) { return serialization::ComputeHash(Sel); } std::pair<unsigned,unsigned> EmitKeyDataLength(raw_ostream& Out, Selector Sel, data_type_ref Methods) { + using namespace llvm::support; + endian::Writer<little> LE(Out); unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4); - clang::io::Emit16(Out, KeyLen); + LE.write<uint16_t>(KeyLen); unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->getNext()) @@ -2739,27 +2778,31 @@ public: Method = Method->getNext()) if (Method->Method) DataLen += 4; - clang::io::Emit16(Out, DataLen); + LE.write<uint16_t>(DataLen); return std::make_pair(KeyLen, DataLen); } void EmitKey(raw_ostream& Out, Selector Sel, unsigned) { + using namespace llvm::support; + endian::Writer<little> LE(Out); uint64_t Start = Out.tell(); assert((Start >> 32) == 0 && "Selector key offset too large"); Writer.SetSelectorOffset(Sel, Start); unsigned N = Sel.getNumArgs(); - clang::io::Emit16(Out, N); + LE.write<uint16_t>(N); if (N == 0) N = 1; for (unsigned I = 0; I != N; ++I) - clang::io::Emit32(Out, - Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I))); + LE.write<uint32_t>( + Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I))); } void EmitData(raw_ostream& Out, key_type_ref, data_type_ref Methods, unsigned DataLen) { + using namespace llvm::support; + endian::Writer<little> LE(Out); uint64_t Start = Out.tell(); (void)Start; - clang::io::Emit32(Out, Methods.ID); + LE.write<uint32_t>(Methods.ID); unsigned NumInstanceMethods = 0; for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->getNext()) @@ -2779,16 +2822,16 @@ public: unsigned FactoryBits = Methods.Factory.getBits(); assert(FactoryBits < 4); unsigned NumFactoryMethodsAndBits = (NumFactoryMethods << 2) | FactoryBits; - clang::io::Emit16(Out, NumInstanceMethodsAndBits); - clang::io::Emit16(Out, NumFactoryMethodsAndBits); + LE.write<uint16_t>(NumInstanceMethodsAndBits); + LE.write<uint16_t>(NumFactoryMethodsAndBits); for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->getNext()) if (Method->Method) - clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); + LE.write<uint32_t>(Writer.getDeclID(Method->Method)); for (const ObjCMethodList *Method = &Methods.Factory; Method; Method = Method->getNext()) if (Method->Method) - clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); + LE.write<uint32_t>(Writer.getDeclID(Method->Method)); assert(Out.tell() - Start == DataLen && "Data length is wrong"); } @@ -2809,7 +2852,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { unsigned NumTableEntries = 0; // Create and write out the blob that contains selectors and the method pool. { - OnDiskChainedHashTableGenerator<ASTMethodPoolTrait> Generator; + llvm::OnDiskChainedHashTableGenerator<ASTMethodPoolTrait> Generator; ASTMethodPoolTrait Trait(*this); // Create the on-disk hash table representation. We walk through every @@ -2857,10 +2900,11 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { SmallString<4096> MethodPool; uint32_t BucketOffset; { + using namespace llvm::support; ASTMethodPoolTrait Trait(*this); llvm::raw_svector_ostream Out(MethodPool); // Make sure that no bucket is at offset 0 - clang::io::Emit32(Out, 0); + endian::Writer<little>(Out).write<uint32_t>(0); BucketOffset = Generator.Emit(Out, Trait); } @@ -2959,83 +3003,110 @@ class ASTIdentifierTableTrait { return false; } - DefMacroDirective *getFirstPublicSubmoduleMacro(MacroDirective *MD, - SubmoduleID &ModID) { + typedef llvm::SmallVectorImpl<SubmoduleID> OverriddenList; + + MacroDirective * + getFirstPublicSubmoduleMacro(MacroDirective *MD, SubmoduleID &ModID) { ModID = 0; - if (DefMacroDirective *DefMD = getPublicSubmoduleMacro(MD, ModID)) - if (!shouldIgnoreMacro(DefMD, IsModule, PP)) - return DefMD; - return 0; + llvm::SmallVector<SubmoduleID, 1> Overridden; + if (MacroDirective *NextMD = getPublicSubmoduleMacro(MD, ModID, Overridden)) + if (!shouldIgnoreMacro(NextMD, IsModule, PP)) + return NextMD; + return nullptr; } - DefMacroDirective *getNextPublicSubmoduleMacro(DefMacroDirective *MD, - SubmoduleID &ModID) { - if (DefMacroDirective * - DefMD = getPublicSubmoduleMacro(MD->getPrevious(), ModID)) - if (!shouldIgnoreMacro(DefMD, IsModule, PP)) - return DefMD; - return 0; + MacroDirective * + getNextPublicSubmoduleMacro(MacroDirective *MD, SubmoduleID &ModID, + OverriddenList &Overridden) { + if (MacroDirective *NextMD = + getPublicSubmoduleMacro(MD->getPrevious(), ModID, Overridden)) + if (!shouldIgnoreMacro(NextMD, IsModule, PP)) + return NextMD; + return nullptr; } /// \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, + /// public macro definition or undefinition that is not in ModID. + /// 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) { + /// ModID is updated to the module containing the returned directive. + /// + /// FIXME: This process breaks down if a module defines a macro, imports + /// another submodule that changes the macro, then changes the + /// macro again itself. + MacroDirective *getPublicSubmoduleMacro(MacroDirective *MD, + SubmoduleID &ModID, + OverriddenList &Overridden) { + Overridden.clear(); if (!MD) - return 0; + return nullptr; SubmoduleID OrigModID = ModID; - bool isUndefined = false; - Optional<bool> isPublic; + Optional<bool> IsPublic; for (; MD; MD = MD->getPrevious()) { - if (MD->isHidden()) - continue; - SubmoduleID ThisModID = getSubmoduleID(MD); if (ThisModID == 0) { - isUndefined = false; - isPublic = Optional<bool>(); + IsPublic = Optional<bool>(); + + // If we have no directive location, this macro was installed when + // finalizing the ASTReader. + if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) + if (DefMD->getInfo()->getOwningModuleID()) + return MD; + // Skip imports that only produce #undefs for now. + // FIXME: We should still re-export them! + continue; } - if (ThisModID != ModID){ + if (ThisModID != ModID) { ModID = ThisModID; - isUndefined = false; - isPublic = Optional<bool>(); + IsPublic = Optional<bool>(); } + + // If this is a definition from a submodule import, that submodule's + // definition is overridden by the definition or undefinition that we + // started with. + // FIXME: This should only apply to macros defined in OrigModID. + // We can't do that currently, because a #include of a different submodule + // of the same module just leaks through macros instead of providing new + // DefMacroDirectives for them. + if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) { + // Figure out which submodule the macro was originally defined within. + SubmoduleID SourceID = DefMD->getInfo()->getOwningModuleID(); + if (!SourceID) { + SourceLocation DefLoc = DefMD->getInfo()->getDefinitionLoc(); + if (DefLoc == MD->getLocation()) + SourceID = ThisModID; + else + SourceID = Writer.inferSubmoduleIDFromLocation(DefLoc); + } + if (OrigModID && SourceID != OrigModID) + Overridden.push_back(SourceID); + } + // 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; + // The latest visibility directive for a name in a submodule affects all + // the directives that come before it. + if (VisibilityMacroDirective *VisMD = + dyn_cast<VisibilityMacroDirective>(MD)) { + if (!IsPublic.hasValue()) + IsPublic = VisMD->isPublic(); + } else if (!IsPublic.hasValue() || IsPublic.getValue()) { + // FIXME: If we find an imported macro, we should include its list of + // overrides in our export. + return MD; } - - VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD); - if (!isPublic.hasValue()) - isPublic = VisMD->isPublic(); } - return 0; + return nullptr; } 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()); } @@ -3046,11 +3117,14 @@ public: typedef IdentID data_type; typedef data_type data_type_ref; + typedef unsigned hash_value_type; + typedef unsigned offset_type; + ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, IdentifierResolver &IdResolver, bool IsModule) : Writer(Writer), PP(PP), IdResolver(IdResolver), IsModule(IsModule) { } - static unsigned ComputeHash(const IdentifierInfo* II) { + static hash_value_type ComputeHash(const IdentifierInfo* II) { return llvm::HashString(II->getName()); } @@ -3058,7 +3132,7 @@ public: EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) { unsigned KeyLen = II->getLength() + 1; unsigned DataLen = 4; // 4 bytes for the persistent ID << 1 - MacroDirective *Macro = 0; + MacroDirective *Macro = nullptr; if (isInterestingIdentifier(II, Macro)) { DataLen += 2; // 2 bytes for builtin ID DataLen += 2; // 2 bytes for flags @@ -3066,11 +3140,18 @@ public: DataLen += 4; // MacroDirectives offset. if (IsModule) { SubmoduleID ModID; - for (DefMacroDirective * - DefMD = getFirstPublicSubmoduleMacro(Macro, ModID); - DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) { - DataLen += 4; // MacroInfo ID. + llvm::SmallVector<SubmoduleID, 4> Overridden; + for (MacroDirective * + MD = getFirstPublicSubmoduleMacro(Macro, ModID); + MD; MD = getNextPublicSubmoduleMacro(MD, ModID, Overridden)) { + // Previous macro's overrides. + if (!Overridden.empty()) + DataLen += 4 * (1 + Overridden.size()); + DataLen += 4; // MacroInfo ID or ModuleID. } + // Previous macro's overrides. + if (!Overridden.empty()) + DataLen += 4 * (1 + Overridden.size()); DataLen += 4; } } @@ -3080,11 +3161,14 @@ public: D != DEnd; ++D) DataLen += sizeof(DeclID); } - clang::io::Emit16(Out, DataLen); + using namespace llvm::support; + endian::Writer<little> LE(Out); + + LE.write<uint16_t>(DataLen); // We emit the key length after the data length so that every // string is preceded by a 16-bit length. This matches the PTH // format for storing identifiers. - clang::io::Emit16(Out, KeyLen); + LE.write<uint16_t>(KeyLen); return std::make_pair(KeyLen, DataLen); } @@ -3096,18 +3180,31 @@ public: Out.write(II->getNameStart(), KeyLen); } + static void emitMacroOverrides(raw_ostream &Out, + ArrayRef<SubmoduleID> Overridden) { + if (!Overridden.empty()) { + using namespace llvm::support; + endian::Writer<little> LE(Out); + LE.write<uint32_t>(Overridden.size() | 0x80000000U); + for (unsigned I = 0, N = Overridden.size(); I != N; ++I) + LE.write<uint32_t>(Overridden[I]); + } + } + void EmitData(raw_ostream& Out, IdentifierInfo* II, IdentID ID, unsigned) { - MacroDirective *Macro = 0; + using namespace llvm::support; + endian::Writer<little> LE(Out); + MacroDirective *Macro = nullptr; if (!isInterestingIdentifier(II, Macro)) { - clang::io::Emit32(Out, ID << 1); + LE.write<uint32_t>(ID << 1); return; } - clang::io::Emit32(Out, (ID << 1) | 0x01); + LE.write<uint32_t>((ID << 1) | 0x01); uint32_t Bits = (uint32_t)II->getObjCOrBuiltinID(); assert((Bits & 0xffff) == Bits && "ObjCOrBuiltinID too big for ASTReader."); - clang::io::Emit16(Out, Bits); + LE.write<uint16_t>(Bits); Bits = 0; bool HadMacroDefinition = hadMacroDefinition(II, Macro); Bits = (Bits << 1) | unsigned(HadMacroDefinition); @@ -3116,21 +3213,30 @@ public: Bits = (Bits << 1) | unsigned(II->isPoisoned()); Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier()); Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); - clang::io::Emit16(Out, Bits); + LE.write<uint16_t>(Bits); if (HadMacroDefinition) { - clang::io::Emit32(Out, Writer.getMacroDirectivesOffset(II)); + LE.write<uint32_t>(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); + llvm::SmallVector<SubmoduleID, 4> Overridden; + for (MacroDirective * + MD = getFirstPublicSubmoduleMacro(Macro, ModID); + MD; MD = getNextPublicSubmoduleMacro(MD, ModID, Overridden)) { + MacroID InfoID = 0; + emitMacroOverrides(Out, Overridden); + if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) { + InfoID = Writer.getMacroID(DefMD->getInfo()); + assert(InfoID); + LE.write<uint32_t>(InfoID << 1); + } else { + assert(isa<UndefMacroDirective>(MD)); + LE.write<uint32_t>((ModID << 1) | 1); + } } - clang::io::Emit32(Out, 0); + emitMacroOverrides(Out, Overridden); + LE.write<uint32_t>(0); } } @@ -3145,7 +3251,7 @@ public: for (SmallVectorImpl<Decl *>::reverse_iterator D = Decls.rbegin(), DEnd = Decls.rend(); D != DEnd; ++D) - clang::io::Emit32(Out, Writer.getDeclID(getMostRecentLocalDecl(*D))); + LE.write<uint32_t>(Writer.getDeclID(getMostRecentLocalDecl(*D))); } /// \brief Returns the most recent local decl or the given decl if there are @@ -3184,7 +3290,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, // Create and write out the blob that contains the identifier // strings. { - OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator; + llvm::OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator; ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule); // Look for any identifiers that were named while processing the @@ -3214,10 +3320,11 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, SmallString<4096> IdentifierTable; uint32_t BucketOffset; { + using namespace llvm::support; ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule); llvm::raw_svector_ostream Out(IdentifierTable); // Make sure that no bucket is at offset 0 - clang::io::Emit32(Out, 0); + endian::Writer<little>(Out).write<uint32_t>(0); BucketOffset = Generator.Emit(Out, Trait); } @@ -3272,9 +3379,12 @@ public: typedef DeclContext::lookup_result data_type; typedef const data_type& data_type_ref; + typedef unsigned hash_value_type; + typedef unsigned offset_type; + explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { } - unsigned ComputeHash(DeclarationName Name) { + hash_value_type ComputeHash(DeclarationName Name) { llvm::FoldingSetNodeID ID; ID.AddInteger(Name.getNameKind()); @@ -3306,6 +3416,8 @@ public: std::pair<unsigned,unsigned> EmitKeyDataLength(raw_ostream& Out, DeclarationName Name, data_type_ref Lookup) { + using namespace llvm::support; + endian::Writer<little> LE(Out); unsigned KeyLen = 1; switch (Name.getNameKind()) { case DeclarationName::Identifier: @@ -3324,35 +3436,35 @@ public: case DeclarationName::CXXUsingDirective: break; } - clang::io::Emit16(Out, KeyLen); + LE.write<uint16_t>(KeyLen); // 2 bytes for num of decls and 4 for each DeclID. unsigned DataLen = 2 + 4 * Lookup.size(); - clang::io::Emit16(Out, DataLen); + LE.write<uint16_t>(DataLen); return std::make_pair(KeyLen, DataLen); } void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) { - using namespace clang::io; - - Emit8(Out, Name.getNameKind()); + using namespace llvm::support; + endian::Writer<little> LE(Out); + LE.write<uint8_t>(Name.getNameKind()); switch (Name.getNameKind()) { case DeclarationName::Identifier: - Emit32(Out, Writer.getIdentifierRef(Name.getAsIdentifierInfo())); + LE.write<uint32_t>(Writer.getIdentifierRef(Name.getAsIdentifierInfo())); return; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - Emit32(Out, Writer.getSelectorRef(Name.getObjCSelector())); + LE.write<uint32_t>(Writer.getSelectorRef(Name.getObjCSelector())); return; case DeclarationName::CXXOperatorName: assert(Name.getCXXOverloadedOperator() < NUM_OVERLOADED_OPERATORS && "Invalid operator?"); - Emit8(Out, Name.getCXXOverloadedOperator()); + LE.write<uint8_t>(Name.getCXXOverloadedOperator()); return; case DeclarationName::CXXLiteralOperatorName: - Emit32(Out, Writer.getIdentifierRef(Name.getCXXLiteralIdentifier())); + LE.write<uint32_t>(Writer.getIdentifierRef(Name.getCXXLiteralIdentifier())); return; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: @@ -3366,17 +3478,134 @@ public: void EmitData(raw_ostream& Out, key_type_ref, data_type Lookup, unsigned DataLen) { + using namespace llvm::support; + endian::Writer<little> LE(Out); uint64_t Start = Out.tell(); (void)Start; - clang::io::Emit16(Out, Lookup.size()); + LE.write<uint16_t>(Lookup.size()); for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end(); I != E; ++I) - clang::io::Emit32(Out, Writer.GetDeclRef(*I)); + LE.write<uint32_t>(Writer.GetDeclRef(*I)); assert(Out.tell() - Start == DataLen && "Data length is wrong"); } }; } // end anonymous namespace +template<typename Visitor> +static void visitLocalLookupResults(const DeclContext *ConstDC, + bool NeedToReconcileExternalVisibleStorage, + Visitor AddLookupResult) { + // FIXME: We need to build the lookups table, which is logically const. + DeclContext *DC = const_cast<DeclContext*>(ConstDC); + assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table"); + + SmallVector<DeclarationName, 16> ExternalNames; + for (auto &Lookup : *DC->buildLookup()) { + if (Lookup.second.hasExternalDecls() || + NeedToReconcileExternalVisibleStorage) { + // We don't know for sure what declarations are found by this name, + // because the external source might have a different set from the set + // that are in the lookup map, and we can't update it now without + // risking invalidating our lookup iterator. So add it to a queue to + // deal with later. + ExternalNames.push_back(Lookup.first); + continue; + } + + AddLookupResult(Lookup.first, Lookup.second.getLookupResult()); + } + + // Add the names we needed to defer. Note, this shouldn't add any new decls + // to the list we need to serialize: any new declarations we find here should + // be imported from an external source. + // FIXME: What if the external source isn't an ASTReader? + for (const auto &Name : ExternalNames) + AddLookupResult(Name, DC->lookup(Name)); +} + +void ASTWriter::AddUpdatedDeclContext(const DeclContext *DC) { + if (UpdatedDeclContexts.insert(DC) && WritingAST) { + // Ensure we emit all the visible declarations. + visitLocalLookupResults(DC, DC->NeedToReconcileExternalVisibleStorage, + [&](DeclarationName Name, + DeclContext::lookup_const_result Result) { + for (auto *Decl : Result) + GetDeclRef(Decl); + }); + } +} + +uint32_t +ASTWriter::GenerateNameLookupTable(const DeclContext *DC, + llvm::SmallVectorImpl<char> &LookupTable) { + assert(!DC->LookupPtr.getInt() && "must call buildLookups first"); + + llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> + Generator; + ASTDeclContextNameLookupTrait Trait(*this); + + // Create the on-disk hash table representation. + DeclarationName ConstructorName; + DeclarationName ConversionName; + SmallVector<NamedDecl *, 8> ConstructorDecls; + SmallVector<NamedDecl *, 4> ConversionDecls; + + visitLocalLookupResults(DC, DC->NeedToReconcileExternalVisibleStorage, + [&](DeclarationName Name, + DeclContext::lookup_result Result) { + if (Result.empty()) + return; + + // Different DeclarationName values of certain kinds are mapped to + // identical serialized keys, because we don't want to use type + // identifiers in the keys (since type ids are local to the module). + switch (Name.getNameKind()) { + case DeclarationName::CXXConstructorName: + // There may be different CXXConstructorName DeclarationName values + // in a DeclContext because a UsingDecl that inherits constructors + // has the DeclarationName of the inherited constructors. + if (!ConstructorName) + ConstructorName = Name; + ConstructorDecls.append(Result.begin(), Result.end()); + return; + + case DeclarationName::CXXConversionFunctionName: + if (!ConversionName) + ConversionName = Name; + ConversionDecls.append(Result.begin(), Result.end()); + return; + + default: + break; + } + + Generator.insert(Name, Result, Trait); + }); + + // Add the constructors. + if (!ConstructorDecls.empty()) { + Generator.insert(ConstructorName, + DeclContext::lookup_result(ConstructorDecls.begin(), + ConstructorDecls.end()), + Trait); + } + + // Add the conversion functions. + if (!ConversionDecls.empty()) { + Generator.insert(ConversionName, + DeclContext::lookup_result(ConversionDecls.begin(), + ConversionDecls.end()), + Trait); + } + + // Create the on-disk hash table in a buffer. + llvm::raw_svector_ostream Out(LookupTable); + // Make sure that no bucket is at offset 0 + using namespace llvm::support; + endian::Writer<little>(Out).write<uint32_t>(0); + return Generator.Emit(Out, Trait); +} + /// \brief Write the block containing all of the declaration IDs /// visible from the given DeclContext. /// @@ -3407,50 +3636,9 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, if (!Map || Map->empty()) return 0; - OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> Generator; - ASTDeclContextNameLookupTrait Trait(*this); - - // Create the on-disk hash table representation. - DeclarationName ConversionName; - 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.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 - // key (since such type information is not stable across different - // modules), so the intended effect is to coalesce all of the conversion - // functions under a single key. - if (!ConversionName) - ConversionName = Name; - ConversionDecls.append(Result.begin(), Result.end()); - continue; - } - - Generator.insert(Name, Result, Trait); - } - } - - // Add the conversion functions - if (!ConversionDecls.empty()) { - Generator.insert(ConversionName, - DeclContext::lookup_result(ConversionDecls.begin(), - ConversionDecls.end()), - Trait); - } - // Create the on-disk hash table in a buffer. SmallString<4096> LookupTable; - uint32_t BucketOffset; - { - llvm::raw_svector_ostream Out(LookupTable); - // Make sure that no bucket is at offset 0 - clang::io::Emit32(Out, 0); - BucketOffset = Generator.Emit(Out, Trait); - } + uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable); // Write the lookup table RecordData Record; @@ -3471,33 +3659,13 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, /// (in C++), for namespaces, and for classes with forward-declared unscoped /// enumeration members (in C++11). void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) { - StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr()); + StoredDeclsMap *Map = DC->getLookupPtr(); if (!Map || Map->empty()) return; - OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> Generator; - ASTDeclContextNameLookupTrait Trait(*this); - - // Create the hash table. - for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end(); - D != DEnd; ++D) { - DeclarationName Name = D->first; - 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.empty()) - Generator.insert(Name, Result, Trait); - } - // Create the on-disk hash table in a buffer. SmallString<4096> LookupTable; - uint32_t BucketOffset; - { - llvm::raw_svector_ostream Out(LookupTable); - // Make sure that no bucket is at offset 0 - clang::io::Emit32(Out, 0); - BucketOffset = Generator.Emit(Out, Trait); - } + uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable); // Write the lookup table RecordData Record; @@ -3667,7 +3835,7 @@ void ASTWriter::WriteMergedDecls() { IEnd = Chain->MergedDecls.end(); I != IEnd; ++I) { DeclID CanonID = I->first->isFromASTFile()? I->first->getGlobalID() - : getDeclID(I->first); + : GetDeclRef(I->first); assert(CanonID && "Merged declaration not known?"); Record.push_back(CanonID); @@ -3701,6 +3869,14 @@ void ASTWriter::WriteLateParsedTemplates(Sema &SemaRef) { Stream.EmitRecord(LATE_PARSED_TEMPLATE, Record); } +/// \brief Write the state of 'pragma clang optimize' at the end of the module. +void ASTWriter::WriteOptimizePragmaOptions(Sema &SemaRef) { + RecordData Record; + SourceLocation PragmaLoc = SemaRef.getOptimizeOffPragmaLocation(); + AddSourceLocation(PragmaLoc, Record); + Stream.EmitRecord(OPTIMIZE_PRAGMA_OPTIONS, Record); +} + //===----------------------------------------------------------------------===// // General Serialization Routines //===----------------------------------------------------------------------===// @@ -3774,8 +3950,8 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) { } ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) - : Stream(Stream), Context(0), PP(0), Chain(0), WritingModule(0), - WritingAST(false), DoneWritingDeclsAndTypes(false), + : Stream(Stream), Context(nullptr), PP(nullptr), Chain(nullptr), + WritingModule(nullptr), WritingAST(false), DoneWritingDeclsAndTypes(false), ASTHasCompilerErrors(false), FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID), FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID), @@ -3799,9 +3975,7 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) } ASTWriter::~ASTWriter() { - for (FileDeclIDsTy::iterator - I = FileDeclIDs.begin(), E = FileDeclIDs.end(); I != E; ++I) - delete I->second; + llvm::DeleteContainerSeconds(FileDeclIDs); } void ASTWriter::WriteAST(Sema &SemaRef, @@ -3824,18 +3998,18 @@ void ASTWriter::WriteAST(Sema &SemaRef, PP = &SemaRef.PP; this->WritingModule = WritingModule; WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule); - Context = 0; - PP = 0; - this->WritingModule = 0; - + Context = nullptr; + PP = nullptr; + this->WritingModule = nullptr; + WritingAST = false; } template<typename Vector> static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec, ASTWriter::RecordData &Record) { - for (typename Vector::iterator I = Vec.begin(0, true), E = Vec.end(); - I != E; ++I) { + for (typename Vector::iterator I = Vec.begin(nullptr, true), E = Vec.end(); + I != E; ++I) { Writer.AddDeclRef(*I, Record); } } @@ -3846,7 +4020,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Module *WritingModule) { using namespace llvm; - bool isModule = WritingModule != 0; + bool isModule = WritingModule != nullptr; // Make sure that the AST reader knows to finalize itself. if (Chain) @@ -3906,6 +4080,15 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, } } + // If we saw any DeclContext updates before we started writing the AST file, + // make sure all visible decls in those DeclContexts are written out. + if (!UpdatedDeclContexts.empty()) { + auto OldUpdatedDeclContexts = std::move(UpdatedDeclContexts); + UpdatedDeclContexts.clear(); + for (auto *DC : OldUpdatedDeclContexts) + AddUpdatedDeclContext(DC); + } + // Build a record containing all of the tentative definitions in this file, in // TentativeDefinitions order. Generally, this record will be empty for // headers. @@ -4032,11 +4215,9 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // translation unit that do not come from other AST files. const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); SmallVector<KindDeclIDPair, 64> NewGlobalDecls; - for (DeclContext::decl_iterator I = TU->noload_decls_begin(), - E = TU->noload_decls_end(); - I != E; ++I) { - if (!(*I)->isFromASTFile()) - NewGlobalDecls.push_back(std::make_pair((*I)->getKind(), GetDeclRef(*I))); + for (const auto *I : TU->noload_decls()) { + if (!I->isFromASTFile()) + NewGlobalDecls.push_back(std::make_pair(I->getKind(), GetDeclRef(I))); } llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev(); @@ -4059,14 +4240,25 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // If the translation unit has an anonymous namespace, and we don't already // have an update block for it, write it as an update block. + // FIXME: Why do we not do this if there's already an update block? if (NamespaceDecl *NS = TU->getAnonymousNamespace()) { ASTWriter::UpdateRecord &Record = DeclUpdates[TU]; - if (Record.empty()) { - Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE); - Record.push_back(reinterpret_cast<uint64_t>(NS)); - } + if (Record.empty()) + Record.push_back(DeclUpdate(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, NS)); } + // Add update records for all mangling numbers and static local numbers. + // These aren't really update records, but this is a convenient way of + // tagging this rare extra data onto the declarations. + for (const auto &Number : Context.MangleNumbers) + if (!Number.first->isFromASTFile()) + DeclUpdates[Number.first].push_back(DeclUpdate(UPD_MANGLING_NUMBER, + Number.second)); + for (const auto &Number : Context.StaticLocalNumbers) + if (!Number.first->isFromASTFile()) + DeclUpdates[Number.first].push_back(DeclUpdate(UPD_STATIC_LOCAL_NUMBER, + Number.second)); + // Make sure visible decls, added to DeclContexts previously loaded from // an AST file, are registered for serialization. for (SmallVectorImpl<const Decl *>::iterator @@ -4090,9 +4282,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, } } - // Resolve any declaration pointers within the declaration updates block. - ResolveDeclUpdatesBlocks(); - // Form the record of special types. RecordData SpecialTypes; AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes); @@ -4104,30 +4293,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes); AddTypeRef(Context.getucontext_tType(), SpecialTypes); - // Keep writing types and declarations until all types and - // declarations have been written. - Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE); - WriteDeclsBlockAbbrevs(); - for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(), - E = DeclsToRewrite.end(); - I != E; ++I) - DeclTypesToEmit.push(const_cast<Decl*>(*I)); - while (!DeclTypesToEmit.empty()) { - DeclOrType DOT = DeclTypesToEmit.front(); - DeclTypesToEmit.pop(); - if (DOT.isType()) - WriteType(DOT.getType()); - else - WriteDecl(Context, DOT.getDecl()); - } - Stream.ExitBlock(); - - DoneWritingDeclsAndTypes = true; - - WriteFileDeclIDsMap(); - WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); - WriteComments(); - if (Chain) { // Write the mapping information describing our module dependencies and how // each of those modules were mapped into our own offset/ID space, so that @@ -4154,17 +4319,19 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, for (ModuleManager::ModuleConstIterator M = Chain->ModuleMgr.begin(), MEnd = Chain->ModuleMgr.end(); M != MEnd; ++M) { + using namespace llvm::support; + endian::Writer<little> LE(Out); StringRef FileName = (*M)->FileName; - io::Emit16(Out, FileName.size()); + LE.write<uint16_t>(FileName.size()); Out.write(FileName.data(), FileName.size()); - io::Emit32(Out, (*M)->SLocEntryBaseOffset); - io::Emit32(Out, (*M)->BaseIdentifierID); - io::Emit32(Out, (*M)->BaseMacroID); - io::Emit32(Out, (*M)->BasePreprocessedEntityID); - io::Emit32(Out, (*M)->BaseSubmoduleID); - io::Emit32(Out, (*M)->BaseSelectorID); - io::Emit32(Out, (*M)->BaseDeclID); - io::Emit32(Out, (*M)->BaseTypeIndex); + LE.write<uint32_t>((*M)->SLocEntryBaseOffset); + LE.write<uint32_t>((*M)->BaseIdentifierID); + LE.write<uint32_t>((*M)->BaseMacroID); + LE.write<uint32_t>((*M)->BasePreprocessedEntityID); + LE.write<uint32_t>((*M)->BaseSubmoduleID); + LE.write<uint32_t>((*M)->BaseSelectorID); + LE.write<uint32_t>((*M)->BaseDeclID); + LE.write<uint32_t>((*M)->BaseTypeIndex); } } Record.clear(); @@ -4172,6 +4339,41 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record, Buffer.data(), Buffer.size()); } + + RecordData DeclUpdatesOffsetsRecord; + + // Keep writing types, declarations, and declaration update records + // until we've emitted all of them. + Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE); + WriteDeclsBlockAbbrevs(); + for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(), + E = DeclsToRewrite.end(); + I != E; ++I) + DeclTypesToEmit.push(const_cast<Decl*>(*I)); + do { + WriteDeclUpdatesBlocks(DeclUpdatesOffsetsRecord); + while (!DeclTypesToEmit.empty()) { + DeclOrType DOT = DeclTypesToEmit.front(); + DeclTypesToEmit.pop(); + if (DOT.isType()) + WriteType(DOT.getType()); + else + WriteDecl(Context, DOT.getDecl()); + } + } while (!DeclUpdates.empty()); + Stream.ExitBlock(); + + DoneWritingDeclsAndTypes = true; + + // These things can only be done once we've written out decls and types. + WriteTypeDeclOffsets(); + if (!DeclUpdatesOffsetsRecord.empty()) + Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord); + WriteCXXBaseSpecifiersOffsets(); + WriteFileDeclIDsMap(); + WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); + + WriteComments(); WritePreprocessor(PP, isModule); WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot); WriteSelectors(SemaRef); @@ -4179,12 +4381,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, WriteIdentifierTable(PP, SemaRef.IdResolver, isModule); WriteFPPragmaOptions(SemaRef.getFPOptions()); WriteOpenCLExtensions(SemaRef); - - WriteTypeDeclOffsets(); WritePragmaDiagnosticMappings(Context.getDiagnostics(), isModule); - WriteCXXBaseSpecifiersOffsets(); - // If we're emitting a module, write out the submodule information. if (WritingModule) WriteSubmodules(WritingModule); @@ -4192,8 +4390,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes); // Write the record containing external, unnamed definitions. - if (!ExternalDefinitions.empty()) - Stream.EmitRecord(EXTERNAL_DEFINITIONS, ExternalDefinitions); + if (!EagerlyDeserializedDecls.empty()) + Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls); // Write the record containing tentative definitions. if (!TentativeDefinitions.empty()) @@ -4250,40 +4448,53 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed); // Write the visible updates to DeclContexts. - for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator - I = UpdatedDeclContexts.begin(), - E = UpdatedDeclContexts.end(); - I != E; ++I) - WriteDeclContextVisibleUpdate(*I); + for (auto *DC : UpdatedDeclContexts) + WriteDeclContextVisibleUpdate(DC); if (!WritingModule) { // Write the submodules that were imported, if any. - RecordData ImportedModules; - for (ASTContext::import_iterator I = Context.local_import_begin(), - IEnd = Context.local_import_end(); - I != IEnd; ++I) { + struct ModuleInfo { + uint64_t ID; + Module *M; + ModuleInfo(uint64_t ID, Module *M) : ID(ID), M(M) {} + }; + llvm::SmallVector<ModuleInfo, 64> Imports; + for (const auto *I : Context.local_imports()) { assert(SubmoduleIDs.find(I->getImportedModule()) != SubmoduleIDs.end()); - ImportedModules.push_back(SubmoduleIDs[I->getImportedModule()]); + Imports.push_back(ModuleInfo(SubmoduleIDs[I->getImportedModule()], + I->getImportedModule())); } - if (!ImportedModules.empty()) { - // Sort module IDs. - llvm::array_pod_sort(ImportedModules.begin(), ImportedModules.end()); - - // Unique module IDs. - ImportedModules.erase(std::unique(ImportedModules.begin(), - ImportedModules.end()), - ImportedModules.end()); - + + if (!Imports.empty()) { + auto Cmp = [](const ModuleInfo &A, const ModuleInfo &B) { + return A.ID < B.ID; + }; + + // Sort and deduplicate module IDs. + std::sort(Imports.begin(), Imports.end(), Cmp); + Imports.erase(std::unique(Imports.begin(), Imports.end(), Cmp), + Imports.end()); + + RecordData ImportedModules; + for (const auto &Import : Imports) { + ImportedModules.push_back(Import.ID); + // FIXME: If the module has macros imported then later has declarations + // imported, this location won't be the right one as a location for the + // declaration imports. + AddSourceLocation(Import.M->MacroVisibilityLoc, ImportedModules); + } + Stream.EmitRecord(IMPORTED_MODULES, ImportedModules); } } - WriteDeclUpdatesBlocks(); WriteDeclReplacementsBlock(); WriteRedeclarations(); WriteMergedDecls(); WriteObjCCategories(); WriteLateParsedTemplates(SemaRef); + if(!WritingModule) + WriteOptimizePragmaOptions(SemaRef); // Some simple statistics Record.clear(); @@ -4295,64 +4506,129 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Stream.ExitBlock(); } -/// \brief Go through the declaration update blocks and resolve declaration -/// pointers into declaration IDs. -void ASTWriter::ResolveDeclUpdatesBlocks() { - for (DeclUpdateMap::iterator - I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) { - const Decl *D = I->first; - UpdateRecord &URec = I->second; - +void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { + if (DeclUpdates.empty()) + return; + + DeclUpdateMap LocalUpdates; + LocalUpdates.swap(DeclUpdates); + + for (auto &DeclUpdate : LocalUpdates) { + const Decl *D = DeclUpdate.first; if (isRewritten(D)) - continue; // The decl will be written completely + continue; // The decl will be written completely,no need to store updates. - unsigned Idx = 0, N = URec.size(); - while (Idx < N) { - switch ((DeclUpdateKind)URec[Idx++]) { + bool HasUpdatedBody = false; + RecordData Record; + for (auto &Update : DeclUpdate.second) { + DeclUpdateKind Kind = (DeclUpdateKind)Update.getKind(); + + Record.push_back(Kind); + switch (Kind) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: - URec[Idx] = GetDeclRef(reinterpret_cast<Decl *>(URec[Idx])); - ++Idx; + assert(Update.getDecl() && "no decl to add?"); + Record.push_back(GetDeclRef(Update.getDecl())); break; case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: - case UPD_DECL_MARKED_USED: - ++Idx; + AddSourceLocation(Update.getLoc(), Record); + break; + + case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION: + // An updated body is emitted last, so that the reader doesn't need + // to skip over the lazy body to reach statements for other records. + Record.pop_back(); + HasUpdatedBody = true; + break; + + case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: { + auto *RD = cast<CXXRecordDecl>(D); + AddUpdatedDeclContext(RD->getPrimaryContext()); + AddCXXDefinitionData(RD, Record); + Record.push_back(WriteDeclContextLexicalBlock( + *Context, const_cast<CXXRecordDecl *>(RD))); + + // This state is sometimes updated by template instantiation, when we + // switch from the specialization referring to the template declaration + // to it referring to the template definition. + if (auto *MSInfo = RD->getMemberSpecializationInfo()) { + Record.push_back(MSInfo->getTemplateSpecializationKind()); + AddSourceLocation(MSInfo->getPointOfInstantiation(), Record); + } else { + auto *Spec = cast<ClassTemplateSpecializationDecl>(RD); + Record.push_back(Spec->getTemplateSpecializationKind()); + AddSourceLocation(Spec->getPointOfInstantiation(), Record); + + // The instantiation might have been resolved to a partial + // specialization. If so, record which one. + auto From = Spec->getInstantiatedFrom(); + if (auto PartialSpec = + From.dyn_cast<ClassTemplatePartialSpecializationDecl*>()) { + Record.push_back(true); + AddDeclRef(PartialSpec, Record); + AddTemplateArgumentList(&Spec->getTemplateInstantiationArgs(), + Record); + } else { + Record.push_back(false); + } + } + Record.push_back(RD->getTagKind()); + AddSourceLocation(RD->getLocation(), Record); + AddSourceLocation(RD->getLocStart(), Record); + AddSourceLocation(RD->getRBraceLoc(), Record); + + // Instantiation may change attributes; write them all out afresh. + Record.push_back(D->hasAttrs()); + if (Record.back()) + WriteAttributes(ArrayRef<const Attr*>(D->getAttrs().begin(), + D->getAttrs().size()), Record); + + // FIXME: Ensure we don't get here for explicit instantiations. + break; + } + + case UPD_CXX_RESOLVED_EXCEPTION_SPEC: + addExceptionSpec( + *this, + cast<FunctionDecl>(D)->getType()->castAs<FunctionProtoType>(), + Record); break; case UPD_CXX_DEDUCED_RETURN_TYPE: - URec[Idx] = GetOrCreateTypeID( - QualType::getFromOpaquePtr(reinterpret_cast<void *>(URec[Idx]))); - ++Idx; + Record.push_back(GetOrCreateTypeID(Update.getType())); + break; + + case UPD_DECL_MARKED_USED: + break; + + case UPD_MANGLING_NUMBER: + case UPD_STATIC_LOCAL_NUMBER: + Record.push_back(Update.getNumber()); break; } } - } -} -void ASTWriter::WriteDeclUpdatesBlocks() { - if (DeclUpdates.empty()) - return; + if (HasUpdatedBody) { + const FunctionDecl *Def = cast<FunctionDecl>(D); + Record.push_back(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION); + Record.push_back(Def->isInlined()); + AddSourceLocation(Def->getInnerLocStart(), Record); + AddFunctionDefinition(Def, Record); + } - RecordData OffsetsRecord; - Stream.EnterSubblock(DECL_UPDATES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE); - for (DeclUpdateMap::iterator - I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) { - const Decl *D = I->first; - UpdateRecord &URec = I->second; + OffsetsRecord.push_back(GetDeclRef(D)); + OffsetsRecord.push_back(Stream.GetCurrentBitNo()); - if (isRewritten(D)) - continue; // The decl will be written completely,no need to store updates. + Stream.EmitRecord(DECL_UPDATES, Record); - uint64_t Offset = Stream.GetCurrentBitNo(); - Stream.EmitRecord(DECL_UPDATES, URec); + // Flush any statements that were written as part of this update record. + FlushStmts(); - OffsetsRecord.push_back(GetDeclRef(D)); - OffsetsRecord.push_back(Offset); + // Flush C++ base specifiers, if there are any. + FlushCXXBaseSpecifiers(); } - Stream.ExitBlock(); - Stream.EmitRecord(DECL_UPDATE_OFFSETS, OffsetsRecord); } void ASTWriter::WriteDeclReplacementsBlock() { @@ -4398,7 +4674,7 @@ void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Recor } IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) { - if (II == 0) + if (!II) return 0; IdentID &ID = IdentifierIDs[II]; @@ -4411,7 +4687,7 @@ 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). - if (MI == 0 || MI->isBuiltinMacro()) + if (!MI || MI->isBuiltinMacro()) return 0; MacroID &ID = MacroIDs[MI]; @@ -4424,7 +4700,7 @@ MacroID ASTWriter::getMacroRef(MacroInfo *MI, const IdentifierInfo *Name) { } MacroID ASTWriter::getMacroID(MacroInfo *MI) { - if (MI == 0 || MI->isBuiltinMacro()) + if (!MI || MI->isBuiltinMacro()) return 0; assert(MacroIDs.find(MI) != MacroIDs.end() && "Macro not emitted!"); @@ -4441,7 +4717,7 @@ void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) { } SelectorID ASTWriter::getSelectorRef(Selector Sel) { - if (Sel.getAsOpaquePtr() == 0) { + if (Sel.getAsOpaquePtr() == nullptr) { return 0; } @@ -4519,7 +4795,7 @@ void ASTWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, void ASTWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordDataImpl &Record) { - if (TInfo == 0) { + if (!TInfo) { AddTypeRef(QualType(), Record); return; } @@ -4587,8 +4863,8 @@ void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) { DeclID ASTWriter::GetDeclRef(const Decl *D) { assert(WritingAST && "Cannot request a declaration ID before AST writing"); - - if (D == 0) { + + if (!D) { return 0; } @@ -4615,7 +4891,7 @@ DeclID ASTWriter::GetDeclRef(const Decl *D) { } DeclID ASTWriter::getDeclID(const Decl *D) { - if (D == 0) + if (!D) return 0; // If D comes from an AST file, its declaration ID is already known and @@ -4648,7 +4924,7 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) { assert(SM.isLocalSourceLocation(FileLoc)); FileID FID; unsigned Offset; - llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc); + std::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc); if (FID.isInvalid()) return; assert(SM.getSLocEntry(FID).isFile()); @@ -4934,9 +5210,8 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg, break; case TemplateArgument::Pack: Record.push_back(Arg.pack_size()); - for (TemplateArgument::pack_iterator I=Arg.pack_begin(), E=Arg.pack_end(); - I != E; ++I) - AddTemplateArgument(*I, Record); + for (const auto &P : Arg.pack_elements()) + AddTemplateArgument(P, Record); break; } } @@ -5068,8 +5343,7 @@ void ASTWriter::AddCXXCtorInitializers( } void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record) { - assert(D->DefinitionData); - struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData; + auto &Data = D->data(); Record.push_back(Data.IsLambda); Record.push_back(Data.UserDeclaredConstructor); Record.push_back(Data.UserDeclaredSpecialMembers); @@ -5084,6 +5358,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.HasProtectedFields); Record.push_back(Data.HasPublicFields); Record.push_back(Data.HasMutableFields); + Record.push_back(Data.HasVariantMembers); Record.push_back(Data.HasOnlyCMembers); Record.push_back(Data.HasInClassInitializer); Record.push_back(Data.HasUninitializedReferenceMember); @@ -5094,6 +5369,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.DefaultedMoveAssignmentIsDeleted); Record.push_back(Data.DefaultedDestructorIsDeleted); Record.push_back(Data.HasTrivialSpecialMembers); + Record.push_back(Data.DeclaredNonTrivialSpecialMembers); Record.push_back(Data.HasIrrelevantDestructor); Record.push_back(Data.HasConstexprNonCopyMoveConstructor); Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr); @@ -5126,7 +5402,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec // Add lambda-specific data. if (Data.IsLambda) { - CXXRecordDecl::LambdaDefinitionData &Lambda = D->getLambdaData(); + auto &Lambda = D->getLambdaData(); Record.push_back(Lambda.Dependent); Record.push_back(Lambda.IsGenericLambda); Record.push_back(Lambda.CaptureDefault); @@ -5136,7 +5412,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec AddDeclRef(Lambda.ContextDecl, Record); AddTypeSourceInfo(Lambda.MethodTyInfo, Record); for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { - LambdaExpr::Capture &Capture = Lambda.Captures[I]; + const LambdaCapture &Capture = Lambda.Captures[I]; AddSourceLocation(Capture.getLocation(), Record); Record.push_back(Capture.isImplicit()); Record.push_back(Capture.getCaptureKind()); @@ -5146,7 +5422,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec case LCK_ByCopy: case LCK_ByRef: VarDecl *Var = - Capture.capturesVariable() ? Capture.getCapturedVar() : 0; + Capture.capturesVariable() ? Capture.getCapturedVar() : nullptr; AddDeclRef(Var, Record); AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc() : SourceLocation(), @@ -5236,7 +5512,10 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) { // A forward reference was mutated into a definition. Rewrite it. // FIXME: This happens during template instantiation, should we // have created a new definition decl instead ? - RewriteDecl(RD); + assert(isTemplateInstantiation(RD->getTemplateSpecializationKind()) && + "completed a tag from another module but not by instantiation?"); + DeclUpdates[RD].push_back( + DeclUpdate(UPD_CXX_INSTANTIATED_CLASS_DEFINITION)); } } } @@ -5266,9 +5545,7 @@ void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) { // A decl coming from PCH was modified. assert(RD->isCompleteDefinition()); - UpdateRecord &Record = DeclUpdates[RD]; - Record.push_back(UPD_CXX_ADDED_IMPLICIT_MEMBER); - Record.push_back(reinterpret_cast<uint64_t>(D)); + DeclUpdates[RD].push_back(DeclUpdate(UPD_CXX_ADDED_IMPLICIT_MEMBER, D)); } void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, @@ -5279,9 +5556,8 @@ void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, if (!(!D->isFromASTFile() && TD->isFromASTFile())) return; // Not a source specialization added to a template from PCH. - UpdateRecord &Record = DeclUpdates[TD]; - Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); - Record.push_back(reinterpret_cast<uint64_t>(D)); + DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, + D)); } void ASTWriter::AddedCXXTemplateSpecialization( @@ -5292,9 +5568,8 @@ void ASTWriter::AddedCXXTemplateSpecialization( if (!(!D->isFromASTFile() && TD->isFromASTFile())) return; // Not a source specialization added to a template from PCH. - UpdateRecord &Record = DeclUpdates[TD]; - Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); - Record.push_back(reinterpret_cast<uint64_t>(D)); + DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, + D)); } void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, @@ -5305,9 +5580,17 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, if (!(!D->isFromASTFile() && TD->isFromASTFile())) return; // Not a source specialization added to a template from PCH. - UpdateRecord &Record = DeclUpdates[TD]; - Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); - Record.push_back(reinterpret_cast<uint64_t>(D)); + DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, + D)); +} + +void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) { + assert(!WritingAST && "Already writing the AST!"); + FD = FD->getCanonicalDecl(); + if (!FD->isFromASTFile()) + return; // Not a function declared in PCH and defined outside. + + DeclUpdates[FD].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC); } void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) { @@ -5316,9 +5599,7 @@ void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) { if (!FD->isFromASTFile()) return; // Not a function declared in PCH and defined outside. - UpdateRecord &Record = DeclUpdates[FD]; - Record.push_back(UPD_CXX_DEDUCED_RETURN_TYPE); - Record.push_back(reinterpret_cast<uint64_t>(ReturnType.getAsOpaquePtr())); + DeclUpdates[FD].push_back(DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType)); } void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { @@ -5331,6 +5612,17 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { RewriteDecl(D); } +void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) { + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + // Since the actual instantiation is delayed, this really means that we need + // to update the instantiation location. + DeclUpdates[D].push_back( + DeclUpdate(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION)); +} + void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) @@ -5338,10 +5630,9 @@ void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { // Since the actual instantiation is delayed, this really means that we need // to update the instantiation location. - UpdateRecord &Record = DeclUpdates[D]; - Record.push_back(UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER); - AddSourceLocation( - D->getMemberSpecializationInfo()->getPointOfInstantiation(), Record); + DeclUpdates[D].push_back( + DeclUpdate(UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER, + D->getMemberSpecializationInfo()->getPointOfInstantiation())); } void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, @@ -5375,6 +5666,5 @@ void ASTWriter::DeclarationMarkedUsed(const Decl *D) { if (!D->isFromASTFile()) return; - UpdateRecord &Record = DeclUpdates[D]; - Record.push_back(UPD_DECL_MARKED_USED); + DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_USED)); } |