diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 13:34:49 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 13:34:49 +0000 |
commit | 0623d7483df5fc17b32ba7bc5cb9c7beebf6db9c (patch) | |
tree | 28726ef2038e86121e353aabf52297b35a48efa2 /contrib/llvm/tools/clang/lib/Serialization | |
parent | 7d523365ff1a3cc95bc058b33102500f61e8166d (diff) | |
parent | 45b533945f0851ec234ca846e1af5ee1e4df0b6e (diff) | |
download | src-test2-0623d7483df5fc17b32ba7bc5cb9c7beebf6db9c.tar.gz src-test2-0623d7483df5fc17b32ba7bc5cb9c7beebf6db9c.zip |
Notes
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Serialization')
15 files changed, 3194 insertions, 2267 deletions
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp index b1bf4a6bff8b..2b78d745864a 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp @@ -27,52 +27,166 @@ serialization::TypeIdx serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { unsigned ID = 0; switch (BT->getKind()) { - case BuiltinType::Void: ID = PREDEF_TYPE_VOID_ID; break; - case BuiltinType::Bool: ID = PREDEF_TYPE_BOOL_ID; break; - case BuiltinType::Char_U: ID = PREDEF_TYPE_CHAR_U_ID; break; - case BuiltinType::UChar: ID = PREDEF_TYPE_UCHAR_ID; break; - case BuiltinType::UShort: ID = PREDEF_TYPE_USHORT_ID; break; - case BuiltinType::UInt: ID = PREDEF_TYPE_UINT_ID; break; - case BuiltinType::ULong: ID = PREDEF_TYPE_ULONG_ID; break; - case BuiltinType::ULongLong: ID = PREDEF_TYPE_ULONGLONG_ID; break; - case BuiltinType::UInt128: ID = PREDEF_TYPE_UINT128_ID; break; - case BuiltinType::Char_S: ID = PREDEF_TYPE_CHAR_S_ID; break; - case BuiltinType::SChar: ID = PREDEF_TYPE_SCHAR_ID; break; + case BuiltinType::Void: + ID = PREDEF_TYPE_VOID_ID; + break; + case BuiltinType::Bool: + ID = PREDEF_TYPE_BOOL_ID; + break; + case BuiltinType::Char_U: + ID = PREDEF_TYPE_CHAR_U_ID; + break; + case BuiltinType::UChar: + ID = PREDEF_TYPE_UCHAR_ID; + break; + case BuiltinType::UShort: + ID = PREDEF_TYPE_USHORT_ID; + break; + case BuiltinType::UInt: + ID = PREDEF_TYPE_UINT_ID; + break; + case BuiltinType::ULong: + ID = PREDEF_TYPE_ULONG_ID; + break; + case BuiltinType::ULongLong: + ID = PREDEF_TYPE_ULONGLONG_ID; + break; + case BuiltinType::UInt128: + ID = PREDEF_TYPE_UINT128_ID; + break; + case BuiltinType::Char_S: + ID = PREDEF_TYPE_CHAR_S_ID; + break; + case BuiltinType::SChar: + ID = PREDEF_TYPE_SCHAR_ID; + break; case BuiltinType::WChar_S: - case BuiltinType::WChar_U: ID = PREDEF_TYPE_WCHAR_ID; break; - case BuiltinType::Short: ID = PREDEF_TYPE_SHORT_ID; break; - case BuiltinType::Int: ID = PREDEF_TYPE_INT_ID; break; - case BuiltinType::Long: ID = PREDEF_TYPE_LONG_ID; break; - case BuiltinType::LongLong: ID = PREDEF_TYPE_LONGLONG_ID; break; - case BuiltinType::Int128: ID = PREDEF_TYPE_INT128_ID; break; - case BuiltinType::Half: ID = PREDEF_TYPE_HALF_ID; break; - case BuiltinType::Float: ID = PREDEF_TYPE_FLOAT_ID; break; - case BuiltinType::Double: ID = PREDEF_TYPE_DOUBLE_ID; break; - case BuiltinType::LongDouble: ID = PREDEF_TYPE_LONGDOUBLE_ID; break; - case BuiltinType::NullPtr: ID = PREDEF_TYPE_NULLPTR_ID; break; - case BuiltinType::Char16: ID = PREDEF_TYPE_CHAR16_ID; break; - case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break; - case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break; - case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; break; - case BuiltinType::PseudoObject:ID = PREDEF_TYPE_PSEUDO_OBJECT;break; - case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break; - case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break; + case BuiltinType::WChar_U: + ID = PREDEF_TYPE_WCHAR_ID; + break; + case BuiltinType::Short: + ID = PREDEF_TYPE_SHORT_ID; + break; + case BuiltinType::Int: + ID = PREDEF_TYPE_INT_ID; + break; + case BuiltinType::Long: + ID = PREDEF_TYPE_LONG_ID; + break; + case BuiltinType::LongLong: + ID = PREDEF_TYPE_LONGLONG_ID; + break; + case BuiltinType::Int128: + ID = PREDEF_TYPE_INT128_ID; + break; + case BuiltinType::Half: + ID = PREDEF_TYPE_HALF_ID; + break; + case BuiltinType::Float: + ID = PREDEF_TYPE_FLOAT_ID; + break; + case BuiltinType::Double: + ID = PREDEF_TYPE_DOUBLE_ID; + break; + case BuiltinType::LongDouble: + ID = PREDEF_TYPE_LONGDOUBLE_ID; + break; + case BuiltinType::NullPtr: + ID = PREDEF_TYPE_NULLPTR_ID; + break; + case BuiltinType::Char16: + ID = PREDEF_TYPE_CHAR16_ID; + break; + case BuiltinType::Char32: + ID = PREDEF_TYPE_CHAR32_ID; + break; + case BuiltinType::Overload: + ID = PREDEF_TYPE_OVERLOAD_ID; + break; + case BuiltinType::BoundMember: + ID = PREDEF_TYPE_BOUND_MEMBER; + break; + case BuiltinType::PseudoObject: + ID = PREDEF_TYPE_PSEUDO_OBJECT; + break; + case BuiltinType::Dependent: + ID = PREDEF_TYPE_DEPENDENT_ID; + break; + case BuiltinType::UnknownAny: + ID = PREDEF_TYPE_UNKNOWN_ANY; + break; case BuiltinType::ARCUnbridgedCast: - ID = PREDEF_TYPE_ARC_UNBRIDGED_CAST; break; - case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break; - case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break; - case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break; - case BuiltinType::OCLImage1d: ID = PREDEF_TYPE_IMAGE1D_ID; break; - case BuiltinType::OCLImage1dArray: ID = PREDEF_TYPE_IMAGE1D_ARR_ID; break; - case BuiltinType::OCLImage1dBuffer: ID = PREDEF_TYPE_IMAGE1D_BUFF_ID; break; - case BuiltinType::OCLImage2d: ID = PREDEF_TYPE_IMAGE2D_ID; break; - case BuiltinType::OCLImage2dArray: ID = PREDEF_TYPE_IMAGE2D_ARR_ID; break; - case BuiltinType::OCLImage3d: ID = PREDEF_TYPE_IMAGE3D_ID; break; - case BuiltinType::OCLSampler: ID = PREDEF_TYPE_SAMPLER_ID; break; - case BuiltinType::OCLEvent: ID = PREDEF_TYPE_EVENT_ID; break; + ID = PREDEF_TYPE_ARC_UNBRIDGED_CAST; + break; + case BuiltinType::ObjCId: + ID = PREDEF_TYPE_OBJC_ID; + break; + case BuiltinType::ObjCClass: + ID = PREDEF_TYPE_OBJC_CLASS; + break; + case BuiltinType::ObjCSel: + ID = PREDEF_TYPE_OBJC_SEL; + break; + case BuiltinType::OCLImage1d: + ID = PREDEF_TYPE_IMAGE1D_ID; + break; + case BuiltinType::OCLImage1dArray: + ID = PREDEF_TYPE_IMAGE1D_ARR_ID; + break; + case BuiltinType::OCLImage1dBuffer: + ID = PREDEF_TYPE_IMAGE1D_BUFF_ID; + break; + case BuiltinType::OCLImage2d: + ID = PREDEF_TYPE_IMAGE2D_ID; + break; + case BuiltinType::OCLImage2dArray: + ID = PREDEF_TYPE_IMAGE2D_ARR_ID; + break; + case BuiltinType::OCLImage2dDepth: + ID = PREDEF_TYPE_IMAGE2D_DEP_ID; + break; + case BuiltinType::OCLImage2dArrayDepth: + ID = PREDEF_TYPE_IMAGE2D_ARR_DEP_ID; + break; + case BuiltinType::OCLImage2dMSAA: + ID = PREDEF_TYPE_IMAGE2D_MSAA_ID; + break; + case BuiltinType::OCLImage2dArrayMSAA: + ID = PREDEF_TYPE_IMAGE2D_ARR_MSAA_ID; + break; + case BuiltinType::OCLImage2dMSAADepth: + ID = PREDEF_TYPE_IMAGE2D_MSAA_DEP_ID; + break; + case BuiltinType::OCLImage2dArrayMSAADepth: + ID = PREDEF_TYPE_IMAGE2D_ARR_MSAA_DEPTH_ID; + break; + case BuiltinType::OCLImage3d: + ID = PREDEF_TYPE_IMAGE3D_ID; + break; + case BuiltinType::OCLSampler: + ID = PREDEF_TYPE_SAMPLER_ID; + break; + case BuiltinType::OCLEvent: + ID = PREDEF_TYPE_EVENT_ID; + break; + case BuiltinType::OCLClkEvent: + ID = PREDEF_TYPE_CLK_EVENT_ID; + break; + case BuiltinType::OCLQueue: + ID = PREDEF_TYPE_QUEUE_ID; + break; + case BuiltinType::OCLNDRange: + ID = PREDEF_TYPE_NDRANGE_ID; + break; + case BuiltinType::OCLReserveID: + ID = PREDEF_TYPE_RESERVE_ID_ID; + break; case BuiltinType::BuiltinFn: - ID = PREDEF_TYPE_BUILTIN_FN; break; - + ID = PREDEF_TYPE_BUILTIN_FN; + break; + case BuiltinType::OMPArraySection: + ID = PREDEF_TYPE_OMP_ARRAY_SECTION; + break; } return TypeIdx(ID); @@ -215,6 +329,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::ClassScopeFunctionSpecialization: case Decl::Import: case Decl::OMPThreadPrivate: + case Decl::BuiltinTemplate: return false; // These indirectly derive from Redeclarable<T> but are not actually diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h index f21e8a7ea030..e59bc891f9b9 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h @@ -62,8 +62,6 @@ TypeID MakeTypeID(ASTContext &Context, QualType T, IdxForTypeTy IdxForType) { return TypeIdx(PREDEF_TYPE_AUTO_DEDUCT).asTypeID(FastQuals); if (T == Context.AutoRRefDeductTy) return TypeIdx(PREDEF_TYPE_AUTO_RREF_DEDUCT).asTypeID(FastQuals); - if (T == Context.VaListTagTy) - return TypeIdx(PREDEF_TYPE_VA_LIST_TAG).asTypeID(FastQuals); return IdxForType(T).asTypeID(FastQuals); } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp index 9fbf55bf15d1..7d88a31f44a7 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp @@ -20,6 +20,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/Frontend/PCHContainerOperations.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" @@ -138,23 +139,33 @@ bool ChainedASTReaderListener::needsSystemInputFileVisitation() { return First->needsSystemInputFileVisitation() || Second->needsSystemInputFileVisitation(); } -void ChainedASTReaderListener::visitModuleFile(StringRef Filename) { - First->visitModuleFile(Filename); - Second->visitModuleFile(Filename); +void ChainedASTReaderListener::visitModuleFile(StringRef Filename, + ModuleKind Kind) { + First->visitModuleFile(Filename, Kind); + Second->visitModuleFile(Filename, Kind); } bool ChainedASTReaderListener::visitInputFile(StringRef Filename, bool isSystem, - bool isOverridden) { + bool isOverridden, + bool isExplicitModule) { bool Continue = false; if (First->needsInputFileVisitation() && (!isSystem || First->needsSystemInputFileVisitation())) - Continue |= First->visitInputFile(Filename, isSystem, isOverridden); + Continue |= First->visitInputFile(Filename, isSystem, isOverridden, + isExplicitModule); if (Second->needsInputFileVisitation() && (!isSystem || Second->needsSystemInputFileVisitation())) - Continue |= Second->visitInputFile(Filename, isSystem, isOverridden); + Continue |= Second->visitInputFile(Filename, isSystem, isOverridden, + isExplicitModule); return Continue; } +void ChainedASTReaderListener::readModuleFileExtension( + const ModuleFileExtensionMetadata &Metadata) { + First->readModuleFileExtension(Metadata); + Second->readModuleFileExtension(Metadata); +} + //===----------------------------------------------------------------------===// // PCH validator implementation //===----------------------------------------------------------------------===// @@ -735,13 +746,26 @@ ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) { } /// \brief Whether the given identifier is "interesting". -static bool isInterestingIdentifier(IdentifierInfo &II) { - return II.isPoisoned() || - II.isExtensionToken() || - II.getObjCOrBuiltinID() || +static bool isInterestingIdentifier(ASTReader &Reader, IdentifierInfo &II, + bool IsModule) { + return II.hadMacroDefinition() || + II.isPoisoned() || + (IsModule ? II.hasRevertedBuiltin() : II.getObjCOrBuiltinID()) || II.hasRevertedTokenIDToIdentifier() || - II.hadMacroDefinition() || - II.getFETokenInfo<void>(); + (!(IsModule && Reader.getContext().getLangOpts().CPlusPlus) && + II.getFETokenInfo<void>()); +} + +static bool readBit(unsigned &Bits) { + bool Value = Bits & 0x1; + Bits >>= 1; + return Value; +} + +IdentID ASTIdentifierLookupTrait::ReadIdentifierID(const unsigned char *d) { + using namespace llvm::support; + unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d); + return Reader.getGlobalIdentifierID(F, RawID >> 1); } IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, @@ -754,62 +778,52 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, // Wipe out the "is interesting" bit. RawID = RawID >> 1; + // Build the IdentifierInfo and link the identifier ID with it. + IdentifierInfo *II = KnownII; + if (!II) { + II = &Reader.getIdentifierTable().getOwn(k); + KnownII = II; + } + if (!II->isFromAST()) { + II->setIsFromAST(); + bool IsModule = Reader.PP.getCurrentModule() != nullptr; + if (isInterestingIdentifier(Reader, *II, IsModule)) + II->setChangedSinceDeserialization(); + } + Reader.markIdentifierUpToDate(II); + IdentID ID = Reader.getGlobalIdentifierID(F, RawID); if (!IsInteresting) { - // For uninteresting identifiers, just build the IdentifierInfo - // and associate it with the persistent ID. - IdentifierInfo *II = KnownII; - if (!II) { - II = &Reader.getIdentifierTable().getOwn(k); - KnownII = II; - } + // For uninteresting identifiers, there's nothing else to do. Just notify + // the reader that we've finished loading this identifier. Reader.SetIdentifierInfo(ID, II); - if (!II->isFromAST()) { - bool WasInteresting = isInterestingIdentifier(*II); - II->setIsFromAST(); - if (WasInteresting) - II->setChangedSinceDeserialization(); - } - Reader.markIdentifierUpToDate(II); return II; } unsigned ObjCOrBuiltinID = endian::readNext<uint16_t, little, unaligned>(d); unsigned Bits = endian::readNext<uint16_t, little, unaligned>(d); - bool CPlusPlusOperatorKeyword = Bits & 0x01; - Bits >>= 1; - bool HasRevertedTokenIDToIdentifier = Bits & 0x01; - Bits >>= 1; - bool Poisoned = Bits & 0x01; - Bits >>= 1; - bool ExtensionToken = Bits & 0x01; - Bits >>= 1; - bool hadMacroDefinition = Bits & 0x01; - Bits >>= 1; + bool CPlusPlusOperatorKeyword = readBit(Bits); + bool HasRevertedTokenIDToIdentifier = readBit(Bits); + bool HasRevertedBuiltin = readBit(Bits); + bool Poisoned = readBit(Bits); + bool ExtensionToken = readBit(Bits); + bool HadMacroDefinition = readBit(Bits); assert(Bits == 0 && "Extra bits in the identifier?"); DataLen -= 8; - // Build the IdentifierInfo itself and link the identifier ID with - // the new IdentifierInfo. - IdentifierInfo *II = KnownII; - if (!II) { - II = &Reader.getIdentifierTable().getOwn(StringRef(k)); - KnownII = II; - } - Reader.markIdentifierUpToDate(II); - if (!II->isFromAST()) { - bool WasInteresting = isInterestingIdentifier(*II); - II->setIsFromAST(); - if (WasInteresting) - II->setChangedSinceDeserialization(); - } - // Set or check the various bits in the IdentifierInfo structure. // Token IDs are read-only. if (HasRevertedTokenIDToIdentifier && II->getTokenID() != tok::identifier) - II->RevertTokenIDToIdentifier(); - II->setObjCOrBuiltinID(ObjCOrBuiltinID); + II->revertTokenIDToIdentifier(); + if (!F.isModule()) + II->setObjCOrBuiltinID(ObjCOrBuiltinID); + else if (HasRevertedBuiltin && II->getBuiltinID()) { + II->revertBuiltin(); + assert((II->hasRevertedBuiltin() || + II->getObjCOrBuiltinID() == ObjCOrBuiltinID) && + "Incorrect ObjC keyword or builtin ID"); + } assert(II->isExtensionToken() == ExtensionToken && "Incorrect extension token flag"); (void)ExtensionToken; @@ -821,7 +835,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, // If this identifier is a macro, deserialize the macro // definition. - if (hadMacroDefinition) { + if (HadMacroDefinition) { uint32_t MacroDirectivesOffset = endian::readNext<uint32_t, little, unaligned>(d); DataLen -= 4; @@ -844,168 +858,187 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, return II; } -unsigned -ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) { - llvm::FoldingSetNodeID ID; - ID.AddInteger(Key.Kind); - - switch (Key.Kind) { +DeclarationNameKey::DeclarationNameKey(DeclarationName Name) + : Kind(Name.getNameKind()) { + switch (Kind) { case DeclarationName::Identifier: - case DeclarationName::CXXLiteralOperatorName: - ID.AddString(((IdentifierInfo*)Key.Data)->getName()); + Data = (uint64_t)Name.getAsIdentifierInfo(); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - ID.AddInteger(serialization::ComputeHash(Selector(Key.Data))); + Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); break; case DeclarationName::CXXOperatorName: - ID.AddInteger((OverloadedOperatorKind)Key.Data); + Data = Name.getCXXOverloadedOperator(); + break; + case DeclarationName::CXXLiteralOperatorName: + Data = (uint64_t)Name.getCXXLiteralIdentifier(); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: + Data = 0; break; } - - return ID.ComputeHash(); } -ASTDeclContextNameLookupTrait::internal_key_type -ASTDeclContextNameLookupTrait::GetInternalKey( - const external_key_type& Name) { - DeclNameKey Key; - Key.Kind = Name.getNameKind(); - switch (Name.getNameKind()) { +unsigned DeclarationNameKey::getHash() const { + llvm::FoldingSetNodeID ID; + ID.AddInteger(Kind); + + switch (Kind) { case DeclarationName::Identifier: - Key.Data = (uint64_t)Name.getAsIdentifierInfo(); + case DeclarationName::CXXLiteralOperatorName: + ID.AddString(((IdentifierInfo*)Data)->getName()); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); + ID.AddInteger(serialization::ComputeHash(Selector(Data))); break; case DeclarationName::CXXOperatorName: - Key.Data = Name.getCXXOverloadedOperator(); - break; - case DeclarationName::CXXLiteralOperatorName: - Key.Data = (uint64_t)Name.getCXXLiteralIdentifier(); + ID.AddInteger((OverloadedOperatorKind)Data); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: - Key.Data = 0; break; } - return Key; + return ID.ComputeHash(); +} + +ModuleFile * +ASTDeclContextNameLookupTrait::ReadFileRef(const unsigned char *&d) { + using namespace llvm::support; + uint32_t ModuleFileID = endian::readNext<uint32_t, little, unaligned>(d); + return Reader.getLocalModuleFile(F, ModuleFileID); } std::pair<unsigned, unsigned> -ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) { +ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char *&d) { using namespace llvm::support; unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d); unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d); return std::make_pair(KeyLen, DataLen); } -ASTDeclContextNameLookupTrait::internal_key_type -ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) { +ASTDeclContextNameLookupTrait::internal_key_type +ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) { using namespace llvm::support; - DeclNameKey Key; - Key.Kind = (DeclarationName::NameKind)*d++; - switch (Key.Kind) { + auto Kind = (DeclarationName::NameKind)*d++; + uint64_t Data; + switch (Kind) { case DeclarationName::Identifier: - Key.Data = (uint64_t)Reader.getLocalIdentifier( + Data = (uint64_t)Reader.getLocalIdentifier( F, endian::readNext<uint32_t, little, unaligned>(d)); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - Key.Data = + Data = (uint64_t)Reader.getLocalSelector( F, endian::readNext<uint32_t, little, unaligned>( d)).getAsOpaquePtr(); break; case DeclarationName::CXXOperatorName: - Key.Data = *d++; // OverloadedOperatorKind + Data = *d++; // OverloadedOperatorKind break; case DeclarationName::CXXLiteralOperatorName: - Key.Data = (uint64_t)Reader.getLocalIdentifier( + Data = (uint64_t)Reader.getLocalIdentifier( F, endian::readNext<uint32_t, little, unaligned>(d)); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: - Key.Data = 0; + Data = 0; break; } - return Key; + return DeclarationNameKey(Kind, Data); } -ASTDeclContextNameLookupTrait::data_type -ASTDeclContextNameLookupTrait::ReadData(internal_key_type, - const unsigned char* d, - unsigned DataLen) { +void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type, + const unsigned char *d, + unsigned DataLen, + data_type_builder &Val) { using namespace llvm::support; - unsigned NumDecls = endian::readNext<uint16_t, little, unaligned>(d); - LE32DeclID *Start = reinterpret_cast<LE32DeclID *>( - const_cast<unsigned char *>(d)); - return std::make_pair(Start, Start + NumDecls); + for (unsigned NumDecls = DataLen / 4; NumDecls; --NumDecls) { + uint32_t LocalID = endian::readNext<uint32_t, little, unaligned>(d); + Val.insert(Reader.getGlobalDeclID(F, LocalID)); + } } -bool ASTReader::ReadDeclContextStorage(ModuleFile &M, - BitstreamCursor &Cursor, - const std::pair<uint64_t, uint64_t> &Offsets, - DeclContextInfo &Info) { - SavedStreamPosition SavedPosition(Cursor); - // First the lexical decls. - if (Offsets.first != 0) { - Cursor.JumpToBit(Offsets.first); +bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, + BitstreamCursor &Cursor, + uint64_t Offset, + DeclContext *DC) { + assert(Offset != 0); - RecordData Record; - StringRef Blob; - unsigned Code = Cursor.ReadCode(); - unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); - if (RecCode != DECL_CONTEXT_LEXICAL) { - Error("Expected lexical block"); - return true; - } + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(Offset); - Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob.data()); - Info.NumLexicalDecls = Blob.size() / sizeof(KindDeclIDPair); + RecordData Record; + StringRef Blob; + unsigned Code = Cursor.ReadCode(); + unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); + if (RecCode != DECL_CONTEXT_LEXICAL) { + Error("Expected lexical block"); + return true; } - // Now the lookup table. - if (Offsets.second != 0) { - Cursor.JumpToBit(Offsets.second); + assert(!isa<TranslationUnitDecl>(DC) && + "expected a TU_UPDATE_LEXICAL record for TU"); + // If we are handling a C++ class template instantiation, we can see multiple + // lexical updates for the same record. It's important that we select only one + // of them, so that field numbering works properly. Just pick the first one we + // see. + auto &Lex = LexicalDecls[DC]; + if (!Lex.first) { + Lex = std::make_pair( + &M, llvm::makeArrayRef( + reinterpret_cast<const llvm::support::unaligned_uint32_t *>( + Blob.data()), + Blob.size() / 4)); + } + DC->setHasExternalLexicalStorage(true); + return false; +} - RecordData Record; - StringRef Blob; - unsigned Code = Cursor.ReadCode(); - unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); - if (RecCode != DECL_CONTEXT_VISIBLE) { - Error("Expected visible lookup table block"); - return true; - } - Info.NameLookupTableData = ASTDeclContextNameLookupTable::Create( - (const unsigned char *)Blob.data() + Record[0], - (const unsigned char *)Blob.data() + sizeof(uint32_t), - (const unsigned char *)Blob.data(), - ASTDeclContextNameLookupTrait(*this, M)); +bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M, + BitstreamCursor &Cursor, + uint64_t Offset, + DeclID ID) { + assert(Offset != 0); + + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(Offset); + + RecordData Record; + StringRef Blob; + unsigned Code = Cursor.ReadCode(); + unsigned RecCode = Cursor.readRecord(Code, Record, &Blob); + if (RecCode != DECL_CONTEXT_VISIBLE) { + Error("Expected visible lookup table block"); + return true; } + // We can't safely determine the primary context yet, so delay attaching the + // lookup table until we're done with recursive deserialization. + auto *Data = (const unsigned char*)Blob.data(); + PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data}); return false; } void ASTReader::Error(StringRef Msg) { Error(diag::err_fe_pch_malformed, Msg); - if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight()) { + if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight() && + !PP.getHeaderSearchInfo().getModuleCachePath().empty()) { Diag(diag::note_module_cache_path) << PP.getHeaderSearchInfo().getModuleCachePath(); } @@ -1032,11 +1065,12 @@ bool ASTReader::ParseLineTable(ModuleFile &F, // Parse the file names std::map<int, int> FileIDs; - for (int I = 0, N = Record[Idx++]; I != N; ++I) { + for (unsigned I = 0; Record[Idx]; ++I) { // Extract the file name auto Filename = ReadPath(F, Record, Idx); FileIDs[I] = LineTable.getLineTableFilenameID(Filename); } + ++Idx; // Parse the line entries std::vector<LineEntry> Entries; @@ -1048,7 +1082,7 @@ bool ASTReader::ParseLineTable(ModuleFile &F, // Extract the line entries unsigned NumEntries = Record[Idx++]; - assert(NumEntries && "Numentries is 00000"); + assert(NumEntries && "no line entries for file ID"); Entries.clear(); Entries.reserve(NumEntries); for (unsigned I = 0; I != NumEntries; ++I) { @@ -1225,7 +1259,8 @@ bool ASTReader::ReadSLocEntry(int ID) { = SourceMgr.getOrCreateContentCache(File, /*isSystemFile=*/FileCharacter != SrcMgr::C_User); if (OverriddenBuffer && !ContentCache->BufferOverridden && - ContentCache->ContentsEntry == ContentCache->OrigEntry) { + ContentCache->ContentsEntry == ContentCache->OrigEntry && + !ContentCache->getRawBuffer()) { unsigned Code = SLocEntryCursor.ReadCode(); Record.clear(); unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob); @@ -1313,7 +1348,7 @@ SourceLocation ASTReader::getImportLocation(ModuleFile *F) { // location of its includer. if (F->ImportedBy.empty() || !F->ImportedBy[0]) { // Main file is the importer. - assert(!SourceMgr.getMainFileID().isInvalid() && "missing main file"); + assert(SourceMgr.getMainFileID().isValid() && "missing main file"); return SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); } return F->ImportedBy[0]->FirstLoc; @@ -1323,10 +1358,8 @@ SourceLocation ASTReader::getImportLocation(ModuleFile *F) { /// specified cursor. Read the abbreviations that are at the top of the block /// and then leave the cursor pointing into the block. bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) { - if (Cursor.EnterSubBlock(BlockID)) { - Error("malformed block record in AST file"); - return Failure; - } + if (Cursor.EnterSubBlock(BlockID)) + return true; while (true) { uint64_t Offset = Cursor.GetCurrentBitNo(); @@ -1425,8 +1458,7 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { if (isC99VarArgs) MI->setIsC99Varargs(); if (isGNUVarArgs) MI->setIsGNUVarargs(); if (hasCommaPasting) MI->setHasCommaPasting(); - MI->setArgumentList(MacroArgs.data(), MacroArgs.size(), - PP.getPreprocessorAllocator()); + MI->setArgumentList(MacroArgs, PP.getPreprocessorAllocator()); } // Remember that we saw this macro last so that we add the tokens that @@ -1481,13 +1513,14 @@ unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) { HeaderFileInfoTrait::internal_key_type HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) { - internal_key_type ikey = { FE->getSize(), FE->getModificationTime(), - FE->getName(), /*Imported*/false }; + internal_key_type ikey = {FE->getSize(), + M.HasTimestamps ? FE->getModificationTime() : 0, + FE->getName(), /*Imported*/ false}; return ikey; } bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) { - if (a.Size != b.Size || a.ModTime != b.ModTime) + if (a.Size != b.Size || (a.ModTime && b.ModTime && a.ModTime != b.ModTime)) return false; if (llvm::sys::path::is_absolute(a.Filename) && @@ -1536,14 +1569,15 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, using namespace llvm::support; HeaderFileInfo HFI; unsigned Flags = *d++; - HFI.HeaderRole = static_cast<ModuleMap::ModuleHeaderRole> - ((Flags >> 6) & 0x03); - HFI.isImport = (Flags >> 5) & 0x01; - HFI.isPragmaOnce = (Flags >> 4) & 0x01; - HFI.DirInfo = (Flags >> 2) & 0x03; - HFI.Resolved = (Flags >> 1) & 0x01; + // FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp. + HFI.isImport |= (Flags >> 4) & 0x01; + HFI.isPragmaOnce |= (Flags >> 3) & 0x01; + HFI.DirInfo = (Flags >> 1) & 0x03; HFI.IndexHeaderMapHeader = Flags & 0x01; - HFI.NumIncludes = endian::readNext<uint16_t, little, unaligned>(d); + // FIXME: Find a better way to handle this. Maybe just store a + // "has been included" flag? + HFI.NumIncludes = std::max(endian::readNext<uint16_t, little, unaligned>(d), + HFI.NumIncludes); HFI.ControllingMacroID = Reader.getGlobalIdentifierID( M, endian::readNext<uint32_t, little, unaligned>(d)); if (unsigned FrameworkOffset = @@ -1553,34 +1587,36 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1); HFI.Framework = HS->getUniqueFrameworkName(FrameworkName); } - - if (d != End) { + + assert((End - d) % 4 == 0 && + "Wrong data length in HeaderFileInfo deserialization"); + while (d != End) { uint32_t LocalSMID = endian::readNext<uint32_t, little, unaligned>(d); - if (LocalSMID) { - // This header is part of a module. Associate it with the module to enable - // implicit module import. - SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID); - Module *Mod = Reader.getSubmodule(GlobalSMID); - HFI.isModuleHeader = true; - FileManager &FileMgr = Reader.getFileManager(); - ModuleMap &ModMap = - Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap(); - // FIXME: This information should be propagated through the - // SUBMODULE_HEADER etc records rather than from here. - // FIXME: We don't ever mark excluded headers. - std::string Filename = key.Filename; - if (key.Imported) - Reader.ResolveImportedPath(M, Filename); - Module::Header H = { key.Filename, FileMgr.getFile(Filename) }; - ModMap.addHeader(Mod, H, HFI.getHeaderRole()); - } - } - - assert(End == d && "Wrong data length in HeaderFileInfo deserialization"); - (void)End; - + auto HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>(LocalSMID & 3); + LocalSMID >>= 2; + + // This header is part of a module. Associate it with the module to enable + // implicit module import. + SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID); + Module *Mod = Reader.getSubmodule(GlobalSMID); + FileManager &FileMgr = Reader.getFileManager(); + ModuleMap &ModMap = + Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + + std::string Filename = key.Filename; + if (key.Imported) + Reader.ResolveImportedPath(M, Filename); + // FIXME: This is not always the right filename-as-written, but we're not + // going to use this information to rebuild the module, so it doesn't make + // a lot of difference. + Module::Header H = { key.Filename, FileMgr.getFile(Filename) }; + ModMap.addHeader(Mod, H, HeaderRole, /*Imported*/true); + HFI.isModuleHeader |= !(HeaderRole & ModuleMap::TextualHeader); + } + // This HeaderFileInfo was externally loaded. HFI.External = true; + HFI.IsValid = true; return HFI; } @@ -1595,16 +1631,15 @@ void ASTReader::ReadDefinedMacros() { // Note that we are loading defined macros. Deserializing Macros(this); - for (ModuleReverseIterator I = ModuleMgr.rbegin(), - E = ModuleMgr.rend(); I != E; ++I) { - BitstreamCursor &MacroCursor = (*I)->MacroCursor; + for (auto &I : llvm::reverse(ModuleMgr)) { + BitstreamCursor &MacroCursor = I->MacroCursor; // If there was no preprocessor block, skip this file. if (!MacroCursor.getBitStreamReader()) continue; BitstreamCursor Cursor = MacroCursor; - Cursor.JumpToBit((*I)->MacroStartOffset); + Cursor.JumpToBit(I->MacroStartOffset); RecordData Record; while (true) { @@ -1626,7 +1661,7 @@ void ASTReader::ReadDefinedMacros() { case PP_MACRO_OBJECT_LIKE: case PP_MACRO_FUNCTION_LIKE: - getLocalIdentifier(**I, Record[0]); + getLocalIdentifier(*I, Record[0]); break; case PP_TOKEN: @@ -1661,33 +1696,30 @@ namespace { Found() { } - - static bool visit(ModuleFile &M, void *UserData) { - IdentifierLookupVisitor *This - = static_cast<IdentifierLookupVisitor *>(UserData); - + + bool operator()(ModuleFile &M) { // If we've already searched this module file, skip it now. - if (M.Generation <= This->PriorGeneration) + if (M.Generation <= PriorGeneration) return true; ASTIdentifierLookupTable *IdTable = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; if (!IdTable) return false; - - ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), - M, This->Found); - ++This->NumIdentifierLookups; + + ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), M, + Found); + ++NumIdentifierLookups; ASTIdentifierLookupTable::iterator Pos = - IdTable->find_hashed(This->Name, This->NameHash, &Trait); + IdTable->find_hashed(Name, NameHash, &Trait); if (Pos == IdTable->end()) return false; // Dereferencing the iterator has the effect of building the // IdentifierInfo node and populating it with the various // declarations it needs. - ++This->NumIdentifierLookupHits; - This->Found = *Pos; + ++NumIdentifierLookupHits; + Found = *Pos; return true; } @@ -1718,7 +1750,7 @@ void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) { IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration, NumIdentifierLookups, NumIdentifierLookupHits); - ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr); + ModuleMgr.visit(Visitor, HitsPtr); markIdentifierUpToDate(&II); } @@ -1859,26 +1891,17 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) { "invalid record type for input file"); (void)Result; - std::string Filename; - off_t StoredSize; - time_t StoredTime; - bool Overridden; - assert(Record[0] == ID && "Bogus stored ID or offset"); - StoredSize = static_cast<off_t>(Record[1]); - StoredTime = static_cast<time_t>(Record[2]); - Overridden = static_cast<bool>(Record[3]); - Filename = Blob; - ResolveImportedPath(F, Filename); - - InputFileInfo R = { std::move(Filename), StoredSize, StoredTime, Overridden }; + InputFileInfo R; + R.StoredSize = static_cast<off_t>(Record[1]); + R.StoredTime = static_cast<time_t>(Record[2]); + R.Overridden = static_cast<bool>(Record[3]); + R.Transient = static_cast<bool>(Record[4]); + R.Filename = Blob; + ResolveImportedPath(F, R.Filename); return R; } -std::string ASTReader::getInputFileName(ModuleFile &F, unsigned int ID) { - return readInputFileInfo(F, ID).Filename; -} - InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { // If this ID is bogus, just return an empty input file. if (ID == 0 || ID > F.InputFilesLoaded.size()) @@ -1900,11 +1923,10 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { off_t StoredSize = FI.StoredSize; time_t StoredTime = FI.StoredTime; bool Overridden = FI.Overridden; + bool Transient = FI.Transient; StringRef Filename = FI.Filename; - const FileEntry *File - = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime) - : FileMgr.getFile(Filename, /*OpenFile=*/false); + const FileEntry *File = FileMgr.getFile(Filename, /*OpenFile=*/false); // If we didn't find the file, resolve it relative to the // original directory from which this AST file was created. @@ -1919,15 +1941,16 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { // For an overridden file, create a virtual file with the stored // size/timestamp. - if (Overridden && File == nullptr) { + if ((Overridden || Transient) && File == nullptr) File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime); - } if (File == nullptr) { if (Complain) { std::string ErrorStr = "could not find file '"; ErrorStr += Filename; - ErrorStr += "' referenced by AST file"; + ErrorStr += "' referenced by AST file '"; + ErrorStr += F.FileName; + ErrorStr += "'"; Error(ErrorStr.c_str()); } // Record that we didn't find the file. @@ -1940,11 +1963,17 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { // can lead to problems when lexing using the source locations from the // PCH. SourceManager &SM = getSourceManager(); - if (!Overridden && SM.isFileOverridden(File)) { + // FIXME: Reject if the overrides are different. + if ((!Overridden && !Transient) && SM.isFileOverridden(File)) { if (Complain) Error(diag::err_fe_pch_file_overridden, Filename); // After emitting the diagnostic, recover by disabling the override so // that the original file will be used. + // + // FIXME: This recovery is just as broken as the original state; there may + // be another precompiled module that's using the overridden contents, or + // we might be half way through parsing it. Instead, we should treat the + // overridden contents as belonging to a separate FileEntry. SM.disableFileContentsOverride(File); // The FileEntry is a virtual file entry with the size of the contents // that would override the original contents. Set it to the original's @@ -1965,14 +1994,9 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { // have inconsistent modification times that sometimes // erroneously trigger this error-handling path. // - // This also happens in networked file systems, so disable this - // check if validation is disabled or if we have an explicitly - // built PCM file. - // - // FIXME: Should we also do this for PCH files? They could also - // reasonably get shared across a network during a distributed build. - (StoredTime != File->getModificationTime() && !DisableValidation && - F.Kind != MK_ExplicitModule) + // FIXME: This probably also breaks HeaderFileInfo lookups on Windows. + (StoredTime && StoredTime != File->getModificationTime() && + !DisableValidation) #endif )) { if (Complain) { @@ -2000,8 +2024,10 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { IsOutOfDate = true; } + // FIXME: If the file is overridden and we've already opened it, + // issue an error (or split it into a separate FileEntry). - InputFile IF = InputFile(File, Overridden, IsOutOfDate); + InputFile IF = InputFile(File, Overridden || Transient, IsOutOfDate); // Note that we've loaded this input file. F.InputFilesLoaded[ID-1] = IF; @@ -2026,24 +2052,114 @@ void ASTReader::ResolveImportedPath(std::string &Filename, StringRef Prefix) { Filename.assign(Buffer.begin(), Buffer.end()); } +static bool isDiagnosedResult(ASTReader::ASTReadResult ARR, unsigned Caps) { + switch (ARR) { + case ASTReader::Failure: return true; + case ASTReader::Missing: return !(Caps & ASTReader::ARR_Missing); + case ASTReader::OutOfDate: return !(Caps & ASTReader::ARR_OutOfDate); + case ASTReader::VersionMismatch: return !(Caps & ASTReader::ARR_VersionMismatch); + case ASTReader::ConfigurationMismatch: + return !(Caps & ASTReader::ARR_ConfigurationMismatch); + case ASTReader::HadErrors: return true; + case ASTReader::Success: return false; + } + + llvm_unreachable("unknown ASTReadResult"); +} + +ASTReader::ASTReadResult ASTReader::ReadOptionsBlock( + BitstreamCursor &Stream, unsigned ClientLoadCapabilities, + bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener, + std::string &SuggestedPredefines) { + if (Stream.EnterSubBlock(OPTIONS_BLOCK_ID)) + return Failure; + + // Read all of the records in the options block. + RecordData Record; + ASTReadResult Result = Success; + while (1) { + llvm::BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::Error: + case llvm::BitstreamEntry::SubBlock: + return Failure; + + case llvm::BitstreamEntry::EndBlock: + return Result; + + case llvm::BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read and process a record. + Record.clear(); + switch ((OptionsRecordTypes)Stream.readRecord(Entry.ID, Record)) { + case LANGUAGE_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (ParseLanguageOptions(Record, Complain, Listener, + AllowCompatibleConfigurationMismatch)) + Result = ConfigurationMismatch; + break; + } + + case TARGET_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (ParseTargetOptions(Record, Complain, Listener, + AllowCompatibleConfigurationMismatch)) + Result = ConfigurationMismatch; + break; + } + + case DIAGNOSTIC_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; + if (!AllowCompatibleConfigurationMismatch && + ParseDiagnosticOptions(Record, Complain, Listener)) + return OutOfDate; + break; + } + + case FILE_SYSTEM_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (!AllowCompatibleConfigurationMismatch && + ParseFileSystemOptions(Record, Complain, Listener)) + Result = ConfigurationMismatch; + break; + } + + case HEADER_SEARCH_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (!AllowCompatibleConfigurationMismatch && + ParseHeaderSearchOptions(Record, Complain, Listener)) + Result = ConfigurationMismatch; + break; + } + + case PREPROCESSOR_OPTIONS: + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (!AllowCompatibleConfigurationMismatch && + ParsePreprocessorOptions(Record, Complain, Listener, + SuggestedPredefines)) + Result = ConfigurationMismatch; + break; + } + } +} + ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F, SmallVectorImpl<ImportedModule> &Loaded, const ModuleFile *ImportedBy, unsigned ClientLoadCapabilities) { BitstreamCursor &Stream = F.Stream; + ASTReadResult Result = Success; if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { Error("malformed block record in AST file"); return Failure; } - // Should we allow the configuration of the module file to differ from the - // configuration of the current translation unit in a compatible way? - // - // FIXME: Allow this for files explicitly specified with -include-pch too. - bool AllowCompatibleConfigurationMismatch = F.Kind == MK_ExplicitModule; - // Read all of the records and blocks in the control block. RecordData Record; unsigned NumInputs = 0; @@ -2061,8 +2177,9 @@ ASTReader::ReadControlBlock(ModuleFile &F, PP.getHeaderSearchInfo().getHeaderSearchOpts(); // All user input files reside at the index range [0, NumUserInputs), and - // system input files reside at [NumUserInputs, NumInputs). - if (!DisableValidation) { + // system input files reside at [NumUserInputs, NumInputs). For explicitly + // loaded module files, ignore missing inputs. + if (!DisableValidation && F.Kind != MK_ExplicitModule) { bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; // If we are reading a module, we will create a verification timestamp, @@ -2084,7 +2201,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, } if (Listener) - Listener->visitModuleFile(F.FileName); + Listener->visitModuleFile(F.FileName, F.Kind); if (Listener && Listener->needsInputFileVisitation()) { unsigned N = Listener->needsSystemInputFileVisitation() ? NumInputs @@ -2092,11 +2209,12 @@ ASTReader::ReadControlBlock(ModuleFile &F, for (unsigned I = 0; I < N; ++I) { bool IsSystem = I >= NumUserInputs; InputFileInfo FI = readInputFileInfo(F, I+1); - Listener->visitInputFile(FI.Filename, IsSystem, FI.Overridden); + Listener->visitInputFile(FI.Filename, IsSystem, FI.Overridden, + F.Kind == MK_ExplicitModule); } } - return Success; + return Result; } case llvm::BitstreamEntry::SubBlock: @@ -2110,6 +2228,41 @@ ASTReader::ReadControlBlock(ModuleFile &F, return Failure; } continue; + + case OPTIONS_BLOCK_ID: + // If we're reading the first module for this group, check its options + // are compatible with ours. For modules it imports, no further checking + // is required, because we checked them when we built it. + if (Listener && !ImportedBy) { + // Should we allow the configuration of the module file to differ from + // the configuration of the current translation unit in a compatible + // way? + // + // FIXME: Allow this for files explicitly specified with -include-pch. + bool AllowCompatibleConfigurationMismatch = + F.Kind == MK_ExplicitModule; + + Result = ReadOptionsBlock(Stream, ClientLoadCapabilities, + AllowCompatibleConfigurationMismatch, + *Listener, SuggestedPredefines); + if (Result == Failure) { + Error("malformed block record in AST file"); + return Result; + } + + if (DisableValidation || + (AllowConfigurationMismatch && Result == ConfigurationMismatch)) + Result = Success; + + // If we've diagnosed a problem, we're done. + if (Result != Success && + isDiagnosedResult(Result, ClientLoadCapabilities)) + return Result; + } else if (Stream.SkipBlock()) { + Error("malformed block record in AST file"); + return Failure; + } + continue; default: if (Stream.SkipBlock()) { @@ -2136,7 +2289,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, return VersionMismatch; } - bool hasErrors = Record[5]; + bool hasErrors = Record[6]; if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) { Diag(diag::err_pch_with_compiler_errors); return HadErrors; @@ -2147,6 +2300,8 @@ ASTReader::ReadControlBlock(ModuleFile &F, if (F.RelocatablePCH) F.BaseDirectory = isysroot.empty() ? "/" : isysroot; + F.HasTimestamps = Record[5]; + const std::string &CurBranch = getClangFullRepositoryVersion(); StringRef ASTBranch = Blob; if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { @@ -2178,10 +2333,23 @@ ASTReader::ReadControlBlock(ModuleFile &F, ASTFileSignature StoredSignature = Record[Idx++]; auto ImportedFile = ReadPath(F, Record, Idx); + // If our client can't cope with us being out of date, we can't cope with + // our dependency being missing. + unsigned Capabilities = ClientLoadCapabilities; + if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) + Capabilities &= ~ARR_Missing; + // Load the AST file. - switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded, - StoredSize, StoredModTime, StoredSignature, - ClientLoadCapabilities)) { + auto Result = ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, + Loaded, StoredSize, StoredModTime, + StoredSignature, Capabilities); + + // If we diagnosed a problem, produce a backtrace. + if (isDiagnosedResult(Result, Capabilities)) + Diag(diag::note_module_file_imported_by) + << F.FileName << !F.ModuleName.empty() << F.ModuleName; + + switch (Result) { case Failure: return Failure; // If we have to ignore the dependency, we'll have to ignore this too. case Missing: @@ -2195,71 +2363,6 @@ ASTReader::ReadControlBlock(ModuleFile &F, break; } - case KNOWN_MODULE_FILES: - break; - - case LANGUAGE_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; - // FIXME: The &F == *ModuleMgr.begin() check is wrong for modules. - if (Listener && &F == *ModuleMgr.begin() && - ParseLanguageOptions(Record, Complain, *Listener, - AllowCompatibleConfigurationMismatch) && - !DisableValidation && !AllowConfigurationMismatch) - return ConfigurationMismatch; - break; - } - - case TARGET_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; - if (Listener && &F == *ModuleMgr.begin() && - ParseTargetOptions(Record, Complain, *Listener, - AllowCompatibleConfigurationMismatch) && - !DisableValidation && !AllowConfigurationMismatch) - return ConfigurationMismatch; - break; - } - - case DIAGNOSTIC_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_OutOfDate)==0; - if (Listener && &F == *ModuleMgr.begin() && - !AllowCompatibleConfigurationMismatch && - ParseDiagnosticOptions(Record, Complain, *Listener) && - !DisableValidation) - return OutOfDate; - break; - } - - case FILE_SYSTEM_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; - if (Listener && &F == *ModuleMgr.begin() && - !AllowCompatibleConfigurationMismatch && - ParseFileSystemOptions(Record, Complain, *Listener) && - !DisableValidation && !AllowConfigurationMismatch) - return ConfigurationMismatch; - break; - } - - case HEADER_SEARCH_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; - if (Listener && &F == *ModuleMgr.begin() && - !AllowCompatibleConfigurationMismatch && - ParseHeaderSearchOptions(Record, Complain, *Listener) && - !DisableValidation && !AllowConfigurationMismatch) - return ConfigurationMismatch; - break; - } - - case PREPROCESSOR_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; - if (Listener && &F == *ModuleMgr.begin() && - !AllowCompatibleConfigurationMismatch && - ParsePreprocessorOptions(Record, Complain, *Listener, - SuggestedPredefines) && - !DisableValidation && !AllowConfigurationMismatch) - return ConfigurationMismatch; - break; - } - case ORIGINAL_FILE: F.OriginalSourceFileID = FileID::get(Record[0]); F.ActualOriginalSourceFileName = Blob; @@ -2499,10 +2602,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { case TU_UPDATE_LEXICAL: { DeclContext *TU = Context.getTranslationUnitDecl(); - DeclContextInfo &Info = F.DeclContextInfos[TU]; - Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(Blob.data()); - Info.NumLexicalDecls - = static_cast<unsigned int>(Blob.size() / sizeof(KindDeclIDPair)); + LexicalContents Contents( + reinterpret_cast<const llvm::support::unaligned_uint32_t *>( + Blob.data()), + static_cast<unsigned int>(Blob.size() / 4)); + TULexicalDecls.push_back(std::make_pair(&F, Contents)); TU->setHasExternalLexicalStorage(true); break; } @@ -2510,20 +2614,12 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { case UPDATE_VISIBLE: { unsigned Idx = 0; serialization::DeclID ID = ReadDeclID(F, Record, Idx); - ASTDeclContextNameLookupTable *Table = - ASTDeclContextNameLookupTable::Create( - (const unsigned char *)Blob.data() + Record[Idx++], - (const unsigned char *)Blob.data() + sizeof(uint32_t), - (const unsigned char *)Blob.data(), - ASTDeclContextNameLookupTrait(*this, F)); - if (Decl *D = GetExistingDecl(ID)) { - auto *DC = cast<DeclContext>(D); - DC->getPrimaryContext()->setHasExternalVisibleStorage(true); - auto *&LookupTable = F.DeclContextInfos[DC].NameLookupTableData; - delete LookupTable; - LookupTable = Table; - } else - PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F)); + auto *Data = (const unsigned char*)Blob.data(); + PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data}); + // If we've already loaded the decl, perform the updates when we finish + // loading this block. + if (Decl *D = GetExistingDecl(ID)) + PendingUpdateRecords.push_back(std::make_pair(ID, D)); break; } @@ -2568,6 +2664,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; } + case INTERESTING_IDENTIFIERS: + F.PreloadIdentifierOffsets.assign(Record.begin(), Record.end()); + break; + case EAGERLY_DESERIALIZED_DECLS: // FIXME: Skip reading this record if our ASTConsumer doesn't care // about "interesting" decls (for instance, if we're building a module). @@ -2696,6 +2796,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) = SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries, SLocSpaceSize); + if (!F.SLocEntryBaseID) { + Error("ran out of source locations"); + break; + } // Make our entry in the range map. BaseID is negative and growing, so // we invert it. Because we invert it, though, we need the other end of // the range. @@ -2744,7 +2848,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { RemapBuilder DeclRemap(F.DeclRemap); RemapBuilder TypeRemap(F.TypeRemap); - while(Data < DataEnd) { + while (Data < DataEnd) { using namespace llvm::support; uint16_t Len = endian::readNext<uint16_t, little, unaligned>(Data); StringRef Name = StringRef((const char*)Data, Len); @@ -3060,22 +3164,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; } - case LOCAL_REDECLARATIONS: { - F.RedeclarationChains.swap(Record); - break; - } - - case LOCAL_REDECLARATIONS_MAP: { - if (F.LocalNumRedeclarationsInMap != 0) { - Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file"); - return Failure; - } - - F.LocalNumRedeclarationsInMap = Record[0]; - F.RedeclarationsMap = (const LocalRedeclarationsInfo *)Blob.data(); - break; - } - case MACRO_OFFSET: { if (F.LocalNumMacros != 0) { Error("duplicate MACRO_OFFSET record in AST file"); @@ -3150,11 +3238,18 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr; if (!ModMap) { assert(ImportedBy && "top-level import should be verified"); - if ((ClientLoadCapabilities & ARR_Missing) == 0) - Diag(diag::err_imported_module_not_found) << F.ModuleName << F.FileName - << ImportedBy->FileName - << F.ModuleMapPath; - return Missing; + if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) { + if (auto *ASTFE = M ? M->getASTFile() : nullptr) + // This module was defined by an imported (explicit) module. + Diag(diag::err_module_file_conflict) << F.ModuleName << F.FileName + << ASTFE->getName(); + else + // This module was built with a different module map. + Diag(diag::err_imported_module_not_found) + << F.ModuleName << F.FileName << ImportedBy->FileName + << F.ModuleMapPath; + } + return OutOfDate; } assert(M->Name == F.ModuleName && "found module with different name"); @@ -3342,6 +3437,36 @@ static void updateModuleTimestamp(ModuleFile &MF) { OS << "Timestamp file\n"; } +/// \brief Given a cursor at the start of an AST file, scan ahead and drop the +/// cursor into the start of the given block ID, returning false on success and +/// true on failure. +static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) { + while (1) { + llvm::BitstreamEntry Entry = Cursor.advance(); + switch (Entry.Kind) { + case llvm::BitstreamEntry::Error: + case llvm::BitstreamEntry::EndBlock: + return true; + + case llvm::BitstreamEntry::Record: + // Ignore top-level records. + Cursor.skipRecord(Entry.ID); + break; + + case llvm::BitstreamEntry::SubBlock: + if (Entry.ID == BlockID) { + if (Cursor.EnterSubBlock(BlockID)) + return true; + // Found it! + return false; + } + + if (Cursor.SkipBlock()) + return true; + } + } +} + ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, ModuleKind Type, SourceLocation ImportLoc, @@ -3399,6 +3524,12 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, if (ASTReadResult Result = ReadASTBlock(F, ClientLoadCapabilities)) return Result; + // Read the extension blocks. + while (!SkipCursorToBlock(F.Stream, EXTENSION_BLOCK_ID)) { + if (ASTReadResult Result = ReadExtensionBlock(F)) + return Result; + } + // Once read, set the ModuleFile bit base offset and update the size in // bits of all files we've seen. F.GlobalBitOffset = TotalModulesSizeInBits; @@ -3414,6 +3545,32 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, // SourceManager. SourceMgr.getLoadedSLocEntryByID(Index); } + + // Preload all the pending interesting identifiers by marking them out of + // date. + for (auto Offset : F.PreloadIdentifierOffsets) { + const unsigned char *Data = reinterpret_cast<const unsigned char *>( + F.IdentifierTableData + Offset); + + ASTIdentifierLookupTrait Trait(*this, F); + auto KeyDataLen = Trait.ReadKeyDataLength(Data); + auto Key = Trait.ReadKey(Data, KeyDataLen.first); + auto &II = PP.getIdentifierTable().getOwn(Key); + II.setOutOfDate(true); + + // Mark this identifier as being from an AST file so that we can track + // whether we need to serialize it. + if (!II.isFromAST()) { + II.setIsFromAST(); + bool IsModule = PP.getCurrentModule() != nullptr; + if (isInterestingIdentifier(*this, II, IsModule)) + II.setChangedSinceDeserialization(); + } + + // Associate the ID with the identifier so that the writer can reuse it. + auto ID = Trait.ReadIdentifierID(Data + KeyDataLen.first); + SetIdentifierInfo(ID, &II); + } } // Setup the import locations and notify the module manager that we've @@ -3434,13 +3591,20 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, M->ImportLoc.getRawEncoding()); } - // Mark all of the identifiers in the identifier table as being out of date, - // so that various accessors know to check the loaded modules when the - // identifier is used. - for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(), - IdEnd = PP.getIdentifierTable().end(); - Id != IdEnd; ++Id) - Id->second->setOutOfDate(true); + if (!Context.getLangOpts().CPlusPlus || + (Type != MK_ImplicitModule && Type != MK_ExplicitModule)) { + // Mark all of the identifiers in the identifier table as being out of date, + // so that various accessors know to check the loaded modules when the + // identifier is used. + // + // For C++ modules, we don't need information on many identifiers (just + // those that provide macros or are poisoned), so we mark all of + // the interesting ones via PreloadIdentifierOffsets. + for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(), + IdEnd = PP.getIdentifierTable().end(); + Id != IdEnd; ++Id) + Id->second->setOutOfDate(true); + } // Resolve any unresolved module exports. for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) { @@ -3485,7 +3649,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, DeserializationListener->ReaderInitialized(this); ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule(); - if (!PrimaryModule.OriginalSourceFileID.isInvalid()) { + if (PrimaryModule.OriginalSourceFileID.isValid()) { PrimaryModule.OriginalSourceFileID = FileID::get(PrimaryModule.SLocEntryBaseID + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1); @@ -3536,6 +3700,20 @@ static bool startsWithASTFileMagic(BitstreamCursor &Stream) { Stream.Read(8) == 'H'; } +static unsigned moduleKindForDiagnostic(ModuleKind Kind) { + switch (Kind) { + case MK_PCH: + return 0; // PCH + case MK_ImplicitModule: + case MK_ExplicitModule: + return 1; // module + case MK_MainFile: + case MK_Preamble: + return 2; // main source file + } + llvm_unreachable("unknown module kind"); +} + ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, ModuleKind Type, @@ -3568,11 +3746,9 @@ ASTReader::ReadASTCore(StringRef FileName, return Missing; // Otherwise, return an error. - { - std::string Msg = "Unable to load module \"" + FileName.str() + "\": " - + ErrorStr; - Error(Msg); - } + Diag(diag::err_module_file_not_found) << moduleKindForDiagnostic(Type) + << FileName << ErrorStr.empty() + << ErrorStr; return Failure; case ModuleManager::OutOfDate: @@ -3582,11 +3758,9 @@ ASTReader::ReadASTCore(StringRef FileName, return OutOfDate; // Otherwise, return an error. - { - std::string Msg = "Unable to load module \"" + FileName.str() + "\": " - + ErrorStr; - Error(Msg); - } + Diag(diag::err_module_file_out_of_date) << moduleKindForDiagnostic(Type) + << FileName << ErrorStr.empty() + << ErrorStr; return Failure; } @@ -3607,20 +3781,20 @@ ASTReader::ReadASTCore(StringRef FileName, // Sniff for the signature. if (!startsWithASTFileMagic(Stream)) { - Diag(diag::err_not_a_pch_file) << FileName; + Diag(diag::err_module_file_invalid) << moduleKindForDiagnostic(Type) + << FileName; return Failure; } // This is used for compatibility with older PCH formats. bool HaveReadControlBlock = false; - while (1) { llvm::BitstreamEntry Entry = Stream.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: - case llvm::BitstreamEntry::EndBlock: case llvm::BitstreamEntry::Record: + case llvm::BitstreamEntry::EndBlock: Error("invalid record at top-level of AST file"); return Failure; @@ -3628,18 +3802,23 @@ ASTReader::ReadASTCore(StringRef FileName, break; } - // We only know the control subblock ID. switch (Entry.ID) { - case llvm::bitc::BLOCKINFO_BLOCK_ID: - if (Stream.ReadBlockInfoBlock()) { - Error("malformed BlockInfoBlock in AST file"); - return Failure; - } - break; case CONTROL_BLOCK_ID: HaveReadControlBlock = true; switch (ReadControlBlock(F, Loaded, ImportedBy, ClientLoadCapabilities)) { case Success: + // Check that we didn't try to load a non-module AST file as a module. + // + // FIXME: Should we also perform the converse check? Loading a module as + // a PCH file sort of works, but it's a bit wonky. + if ((Type == MK_ImplicitModule || Type == MK_ExplicitModule) && + F.ModuleName.empty()) { + auto Result = (Type == MK_ImplicitModule) ? OutOfDate : Failure; + if (Result != OutOfDate || + (ClientLoadCapabilities & ARR_OutOfDate) == 0) + Diag(diag::err_module_file_not_module) << FileName; + return Result; + } break; case Failure: return Failure; @@ -3650,6 +3829,7 @@ ASTReader::ReadASTCore(StringRef FileName, case HadErrors: return HadErrors; } break; + case AST_BLOCK_ID: if (!HaveReadControlBlock) { if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) @@ -3669,7 +3849,78 @@ ASTReader::ReadASTCore(StringRef FileName, break; } } - + + return Success; +} + +/// Parse a record and blob containing module file extension metadata. +static bool parseModuleFileExtensionMetadata( + const SmallVectorImpl<uint64_t> &Record, + StringRef Blob, + ModuleFileExtensionMetadata &Metadata) { + if (Record.size() < 4) return true; + + Metadata.MajorVersion = Record[0]; + Metadata.MinorVersion = Record[1]; + + unsigned BlockNameLen = Record[2]; + unsigned UserInfoLen = Record[3]; + + if (BlockNameLen + UserInfoLen > Blob.size()) return true; + + Metadata.BlockName = std::string(Blob.data(), Blob.data() + BlockNameLen); + Metadata.UserInfo = std::string(Blob.data() + BlockNameLen, + Blob.data() + BlockNameLen + UserInfoLen); + return false; +} + +ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) { + BitstreamCursor &Stream = F.Stream; + + RecordData Record; + while (true) { + llvm::BitstreamEntry Entry = Stream.advance(); + switch (Entry.Kind) { + case llvm::BitstreamEntry::SubBlock: + if (Stream.SkipBlock()) + return Failure; + + continue; + + case llvm::BitstreamEntry::EndBlock: + return Success; + + case llvm::BitstreamEntry::Error: + return HadErrors; + + case llvm::BitstreamEntry::Record: + break; + } + + Record.clear(); + StringRef Blob; + unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob); + switch (RecCode) { + case EXTENSION_METADATA: { + ModuleFileExtensionMetadata Metadata; + if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) + return Failure; + + // Find a module file extension with this block name. + auto Known = ModuleFileExtensions.find(Metadata.BlockName); + if (Known == ModuleFileExtensions.end()) break; + + // Form a reader. + if (auto Reader = Known->second->createExtensionReader(Metadata, *this, + F, Stream)) { + F.ExtensionReaders.push_back(std::move(Reader)); + } + + break; + } + } + } + return Success; } @@ -3811,36 +4062,6 @@ void ASTReader::finalizeForWriting() { // Nothing to do for now. } -/// \brief Given a cursor at the start of an AST file, scan ahead and drop the -/// cursor into the start of the given block ID, returning false on success and -/// true on failure. -static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) { - while (1) { - llvm::BitstreamEntry Entry = Cursor.advance(); - switch (Entry.Kind) { - case llvm::BitstreamEntry::Error: - case llvm::BitstreamEntry::EndBlock: - return true; - - case llvm::BitstreamEntry::Record: - // Ignore top-level records. - Cursor.skipRecord(Entry.ID); - break; - - case llvm::BitstreamEntry::SubBlock: - if (Entry.ID == BlockID) { - if (Cursor.EnterSubBlock(BlockID)) - return true; - // Found it! - return false; - } - - if (Cursor.SkipBlock()) - return true; - } - } -} - /// \brief Reads and return the signature record from \p StreamFile's control /// block, or else returns 0. static ASTFileSignature readASTFileSignature(llvm::BitstreamReader &StreamFile){ @@ -3968,6 +4189,7 @@ namespace { bool ASTReader::readASTFileControlBlock( StringRef Filename, FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr, + bool FindModuleFileExtensions, ASTReaderListener &Listener) { // Open the AST file. // FIXME: This allows use of the VFS; we do not allow use of the @@ -3994,36 +4216,55 @@ bool ASTReader::readASTFileControlBlock( bool NeedsSystemInputFiles = Listener.needsSystemInputFileVisitation(); bool NeedsImports = Listener.needsImportVisitation(); BitstreamCursor InputFilesCursor; - if (NeedsInputFiles) { - InputFilesCursor = Stream; - if (SkipCursorToBlock(InputFilesCursor, INPUT_FILES_BLOCK_ID)) - return true; - // Read the abbreviations - while (true) { - uint64_t Offset = InputFilesCursor.GetCurrentBitNo(); - unsigned Code = InputFilesCursor.ReadCode(); + RecordData Record; + std::string ModuleDir; + bool DoneWithControlBlock = false; + while (!DoneWithControlBlock) { + llvm::BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::SubBlock: { + switch (Entry.ID) { + case OPTIONS_BLOCK_ID: { + std::string IgnoredSuggestedPredefines; + if (ReadOptionsBlock(Stream, ARR_ConfigurationMismatch | ARR_OutOfDate, + /*AllowCompatibleConfigurationMismatch*/ false, + Listener, IgnoredSuggestedPredefines) != Success) + return true; + break; + } + + case INPUT_FILES_BLOCK_ID: + InputFilesCursor = Stream; + if (Stream.SkipBlock() || + (NeedsInputFiles && + ReadBlockAbbrevs(InputFilesCursor, INPUT_FILES_BLOCK_ID))) + return true; + break; - // We expect all abbrevs to be at the start of the block. - if (Code != llvm::bitc::DEFINE_ABBREV) { - InputFilesCursor.JumpToBit(Offset); + default: + if (Stream.SkipBlock()) + return true; break; } - InputFilesCursor.ReadAbbrevRecord(); + + continue; } - } - - // Scan for ORIGINAL_FILE inside the control block. - RecordData Record; - std::string ModuleDir; - while (1) { - llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); - if (Entry.Kind == llvm::BitstreamEntry::EndBlock) - return false; - - if (Entry.Kind != llvm::BitstreamEntry::Record) + + case llvm::BitstreamEntry::EndBlock: + DoneWithControlBlock = true; + break; + + case llvm::BitstreamEntry::Error: return true; - + + case llvm::BitstreamEntry::Record: + break; + } + + if (DoneWithControlBlock) break; + Record.clear(); StringRef Blob; unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob); @@ -4050,41 +4291,6 @@ bool ASTReader::readASTFileControlBlock( Listener.ReadModuleMapFile(Path); break; } - case LANGUAGE_OPTIONS: - if (ParseLanguageOptions(Record, false, Listener, - /*AllowCompatibleConfigurationMismatch*/false)) - return true; - break; - - case TARGET_OPTIONS: - if (ParseTargetOptions(Record, false, Listener, - /*AllowCompatibleConfigurationMismatch*/ false)) - return true; - break; - - case DIAGNOSTIC_OPTIONS: - if (ParseDiagnosticOptions(Record, false, Listener)) - return true; - break; - - case FILE_SYSTEM_OPTIONS: - if (ParseFileSystemOptions(Record, false, Listener)) - return true; - break; - - case HEADER_SEARCH_OPTIONS: - if (ParseHeaderSearchOptions(Record, false, Listener)) - return true; - break; - - case PREPROCESSOR_OPTIONS: { - std::string IgnoredSuggestedPredefines; - if (ParsePreprocessorOptions(Record, false, Listener, - IgnoredSuggestedPredefines)) - return true; - break; - } - case INPUT_FILE_OFFSETS: { if (!NeedsInputFiles) break; @@ -4112,8 +4318,8 @@ bool ASTReader::readASTFileControlBlock( bool Overridden = static_cast<bool>(Record[3]); std::string Filename = Blob; ResolveImportedPath(Filename, ModuleDir); - shouldContinue = - Listener.visitInputFile(Filename, isSystemFile, Overridden); + shouldContinue = Listener.visitInputFile( + Filename, isSystemFile, Overridden, /*IsExplicitModule*/false); break; } if (!shouldContinue) @@ -4137,25 +4343,55 @@ bool ASTReader::readASTFileControlBlock( break; } - case KNOWN_MODULE_FILES: { - // Known-but-not-technically-used module files are treated as imports. - if (!NeedsImports) - break; - - unsigned Idx = 0, N = Record.size(); - while (Idx < N) { - std::string Filename = ReadString(Record, Idx); - ResolveImportedPath(Filename, ModuleDir); - Listener.visitImport(Filename); - } - break; - } - default: // No other validation to perform. break; } } + + // Look for module file extension blocks, if requested. + if (FindModuleFileExtensions) { + while (!SkipCursorToBlock(Stream, EXTENSION_BLOCK_ID)) { + bool DoneWithExtensionBlock = false; + while (!DoneWithExtensionBlock) { + llvm::BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case llvm::BitstreamEntry::SubBlock: + if (Stream.SkipBlock()) + return true; + + continue; + + case llvm::BitstreamEntry::EndBlock: + DoneWithExtensionBlock = true; + continue; + + case llvm::BitstreamEntry::Error: + return true; + + case llvm::BitstreamEntry::Record: + break; + } + + Record.clear(); + StringRef Blob; + unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob); + switch (RecCode) { + case EXTENSION_METADATA: { + ModuleFileExtensionMetadata Metadata; + if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) + return true; + + Listener.readModuleFileExtension(Metadata); + break; + } + } + } + } + } + + return false; } bool ASTReader::isAcceptableASTFile( @@ -4166,6 +4402,7 @@ bool ASTReader::isAcceptableASTFile( SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, ExistingModuleCachePath, FileMgr); return !readASTFileControlBlock(Filename, FileMgr, PCHContainerRdr, + /*FindModuleFileExtensions=*/false, validator); } @@ -4846,22 +5083,19 @@ namespace { public: explicit HeaderFileInfoVisitor(const FileEntry *FE) : FE(FE) { } - - static bool visit(ModuleFile &M, void *UserData) { - HeaderFileInfoVisitor *This - = static_cast<HeaderFileInfoVisitor *>(UserData); - + + bool operator()(ModuleFile &M) { HeaderFileInfoLookupTable *Table = static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable); if (!Table) return false; // Look in the on-disk hash table for an entry for this file name. - HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE); + HeaderFileInfoLookupTable::iterator Pos = Table->find(FE); if (Pos == Table->end()) return false; - This->HFI = *Pos; + HFI = *Pos; return true; } @@ -4871,7 +5105,7 @@ namespace { HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { HeaderFileInfoVisitor Visitor(FE); - ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor); + ModuleMgr.visit(Visitor); if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) return *HFI; @@ -5181,9 +5415,9 @@ QualType ASTReader::readTypeRecord(unsigned Index) { case TYPE_AUTO: { QualType Deduced = readType(*Loc.F, Record, Idx); - bool IsDecltypeAuto = Record[Idx++]; + AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++]; bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; - return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent); + return Context.getAutoType(Deduced, Keyword, IsDependent); } case TYPE_RECORD: { @@ -5335,7 +5569,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) { unsigned Idx = 0; ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); - const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx); + const IdentifierInfo *Name = GetIdentifierInfo(*Loc.F, Record, Idx); QualType Canon = readType(*Loc.F, Record, Idx); if (!Canon.isNull()) Canon = Context.getCanonicalType(Canon); @@ -5346,7 +5580,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) { unsigned Idx = 0; ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); - const IdentifierInfo *Name = this->GetIdentifierInfo(*Loc.F, Record, Idx); + const IdentifierInfo *Name = GetIdentifierInfo(*Loc.F, Record, Idx); unsigned NumArgs = Record[Idx++]; SmallVector<TemplateArgument, 8> Args; Args.reserve(NumArgs); @@ -5692,9 +5926,14 @@ QualType ASTReader::GetType(TypeID ID) { if (Index < NUM_PREDEF_TYPE_IDS) { QualType T; switch ((PredefinedTypeIDs)Index) { - case PREDEF_TYPE_NULL_ID: return QualType(); - case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break; - case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break; + case PREDEF_TYPE_NULL_ID: + return QualType(); + case PREDEF_TYPE_VOID_ID: + T = Context.VoidTy; + break; + case PREDEF_TYPE_BOOL_ID: + T = Context.BoolTy; + break; case PREDEF_TYPE_CHAR_U_ID: case PREDEF_TYPE_CHAR_S_ID: @@ -5702,59 +5941,163 @@ QualType ASTReader::GetType(TypeID ID) { T = Context.CharTy; break; - case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break; - case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break; - case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break; - case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break; - case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break; - case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break; - case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break; - case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break; - case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break; - case PREDEF_TYPE_INT_ID: T = Context.IntTy; break; - case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break; - case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break; - case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break; - case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break; - case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break; - case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break; - case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; - case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break; - case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break; - case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break; - case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break; - case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break; - case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break; - case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break; - case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break; - case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break; - case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break; - case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break; - case PREDEF_TYPE_IMAGE1D_ID: T = Context.OCLImage1dTy; break; - case PREDEF_TYPE_IMAGE1D_ARR_ID: T = Context.OCLImage1dArrayTy; break; - case PREDEF_TYPE_IMAGE1D_BUFF_ID: T = Context.OCLImage1dBufferTy; break; - case PREDEF_TYPE_IMAGE2D_ID: T = Context.OCLImage2dTy; break; - case PREDEF_TYPE_IMAGE2D_ARR_ID: T = Context.OCLImage2dArrayTy; break; - case PREDEF_TYPE_IMAGE3D_ID: T = Context.OCLImage3dTy; break; - case PREDEF_TYPE_SAMPLER_ID: T = Context.OCLSamplerTy; break; - case PREDEF_TYPE_EVENT_ID: T = Context.OCLEventTy; break; - case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break; - - case PREDEF_TYPE_AUTO_RREF_DEDUCT: - T = Context.getAutoRRefDeductType(); + case PREDEF_TYPE_UCHAR_ID: + T = Context.UnsignedCharTy; + break; + case PREDEF_TYPE_USHORT_ID: + T = Context.UnsignedShortTy; + break; + case PREDEF_TYPE_UINT_ID: + T = Context.UnsignedIntTy; + break; + case PREDEF_TYPE_ULONG_ID: + T = Context.UnsignedLongTy; + break; + case PREDEF_TYPE_ULONGLONG_ID: + T = Context.UnsignedLongLongTy; + break; + case PREDEF_TYPE_UINT128_ID: + T = Context.UnsignedInt128Ty; + break; + case PREDEF_TYPE_SCHAR_ID: + T = Context.SignedCharTy; + break; + case PREDEF_TYPE_WCHAR_ID: + T = Context.WCharTy; + break; + case PREDEF_TYPE_SHORT_ID: + T = Context.ShortTy; + break; + case PREDEF_TYPE_INT_ID: + T = Context.IntTy; + break; + case PREDEF_TYPE_LONG_ID: + T = Context.LongTy; + break; + case PREDEF_TYPE_LONGLONG_ID: + T = Context.LongLongTy; + break; + case PREDEF_TYPE_INT128_ID: + T = Context.Int128Ty; + break; + case PREDEF_TYPE_HALF_ID: + T = Context.HalfTy; + break; + case PREDEF_TYPE_FLOAT_ID: + T = Context.FloatTy; + break; + case PREDEF_TYPE_DOUBLE_ID: + T = Context.DoubleTy; + break; + case PREDEF_TYPE_LONGDOUBLE_ID: + T = Context.LongDoubleTy; + break; + case PREDEF_TYPE_OVERLOAD_ID: + T = Context.OverloadTy; + break; + case PREDEF_TYPE_BOUND_MEMBER: + T = Context.BoundMemberTy; + break; + case PREDEF_TYPE_PSEUDO_OBJECT: + T = Context.PseudoObjectTy; + break; + case PREDEF_TYPE_DEPENDENT_ID: + T = Context.DependentTy; + break; + case PREDEF_TYPE_UNKNOWN_ANY: + T = Context.UnknownAnyTy; + break; + case PREDEF_TYPE_NULLPTR_ID: + T = Context.NullPtrTy; + break; + case PREDEF_TYPE_CHAR16_ID: + T = Context.Char16Ty; + break; + case PREDEF_TYPE_CHAR32_ID: + T = Context.Char32Ty; + break; + case PREDEF_TYPE_OBJC_ID: + T = Context.ObjCBuiltinIdTy; + break; + case PREDEF_TYPE_OBJC_CLASS: + T = Context.ObjCBuiltinClassTy; + break; + case PREDEF_TYPE_OBJC_SEL: + T = Context.ObjCBuiltinSelTy; + break; + case PREDEF_TYPE_IMAGE1D_ID: + T = Context.OCLImage1dTy; + break; + case PREDEF_TYPE_IMAGE1D_ARR_ID: + T = Context.OCLImage1dArrayTy; + break; + case PREDEF_TYPE_IMAGE1D_BUFF_ID: + T = Context.OCLImage1dBufferTy; + break; + case PREDEF_TYPE_IMAGE2D_ID: + T = Context.OCLImage2dTy; + break; + case PREDEF_TYPE_IMAGE2D_ARR_ID: + T = Context.OCLImage2dArrayTy; + break; + case PREDEF_TYPE_IMAGE2D_DEP_ID: + T = Context.OCLImage2dDepthTy; + break; + case PREDEF_TYPE_IMAGE2D_ARR_DEP_ID: + T = Context.OCLImage2dArrayDepthTy; + break; + case PREDEF_TYPE_IMAGE2D_MSAA_ID: + T = Context.OCLImage2dMSAATy; + break; + case PREDEF_TYPE_IMAGE2D_ARR_MSAA_ID: + T = Context.OCLImage2dArrayMSAATy; + break; + case PREDEF_TYPE_IMAGE2D_MSAA_DEP_ID: + T = Context.OCLImage2dMSAADepthTy; + break; + case PREDEF_TYPE_IMAGE2D_ARR_MSAA_DEPTH_ID: + T = Context.OCLImage2dArrayMSAADepthTy; + break; + case PREDEF_TYPE_IMAGE3D_ID: + T = Context.OCLImage3dTy; + break; + case PREDEF_TYPE_SAMPLER_ID: + T = Context.OCLSamplerTy; + break; + case PREDEF_TYPE_EVENT_ID: + T = Context.OCLEventTy; + break; + case PREDEF_TYPE_CLK_EVENT_ID: + T = Context.OCLClkEventTy; + break; + case PREDEF_TYPE_QUEUE_ID: + T = Context.OCLQueueTy; + break; + case PREDEF_TYPE_NDRANGE_ID: + T = Context.OCLNDRangeTy; + break; + case PREDEF_TYPE_RESERVE_ID_ID: + T = Context.OCLReserveIDTy; + break; + case PREDEF_TYPE_AUTO_DEDUCT: + T = Context.getAutoDeductType(); break; - case PREDEF_TYPE_ARC_UNBRIDGED_CAST: - T = Context.ARCUnbridgedCastTy; + case PREDEF_TYPE_AUTO_RREF_DEDUCT: + T = Context.getAutoRRefDeductType(); break; - case PREDEF_TYPE_VA_LIST_TAG: - T = Context.getVaListTagType(); + case PREDEF_TYPE_ARC_UNBRIDGED_CAST: + T = Context.ARCUnbridgedCastTy; break; case PREDEF_TYPE_BUILTIN_FN: T = Context.BuiltinFnTy; break; + + case PREDEF_TYPE_OMP_ARRAY_SECTION: + T = Context.OMPArraySectionTy; + break; } assert(!T.isNull() && "Unknown predefined type"); @@ -5889,17 +6232,25 @@ void ASTReader::CompleteRedeclChain(const Decl *D) { if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC) || isa<CXXRecordDecl>(DC) || isa<EnumDecl>(DC)) { if (DeclarationName Name = cast<NamedDecl>(D)->getDeclName()) { - auto *II = Name.getAsIdentifierInfo(); - if (isa<TranslationUnitDecl>(DC) && II) { + if (!getContext().getLangOpts().CPlusPlus && + isa<TranslationUnitDecl>(DC)) { // Outside of C++, we don't have a lookup table for the TU, so update - // the identifier instead. In C++, either way should work fine. + // the identifier instead. (For C++ modules, we don't store decls + // in the serialized identifier table, so we do the lookup in the TU.) + auto *II = Name.getAsIdentifierInfo(); + assert(II && "non-identifier name in C?"); if (II->isOutOfDate()) updateOutOfDateIdentifier(*II); } else DC->lookup(Name); } else if (needsAnonymousDeclarationNumber(cast<NamedDecl>(D))) { - // FIXME: It'd be nice to do something a bit more targeted here. - D->getDeclContext()->decls_begin(); + // Find all declarations of this kind from the relevant context. + for (auto *DCDecl : cast<Decl>(D->getLexicalDeclContext())->redecls()) { + auto *DC = cast<DeclContext>(DCDecl); + SmallVector<Decl*, 8> Decls; + FindExternalLexicalDecls( + DC, [&](Decl::Kind K) { return K == D->getKind(); }, Decls); + } } } @@ -6061,8 +6412,17 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) { case PREDEF_DECL_BUILTIN_VA_LIST_ID: return Context.getBuiltinVaListDecl(); + case PREDEF_DECL_VA_LIST_TAG: + return Context.getVaListTagDecl(); + + case PREDEF_DECL_BUILTIN_MS_VA_LIST_ID: + return Context.getBuiltinMSVaListDecl(); + case PREDEF_DECL_EXTERN_C_CONTEXT_ID: return Context.getExternCContextDecl(); + + case PREDEF_DECL_MAKE_INTEGER_SEQ_ID: + return Context.getMakeIntegerSeqDecl(); } llvm_unreachable("PredefinedDeclIDs unknown enum value"); } @@ -6155,71 +6515,47 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) { return ReadStmtFromStream(*Loc.F); } -namespace { - class FindExternalLexicalDeclsVisitor { - ASTReader &Reader; - const DeclContext *DC; - bool (*isKindWeWant)(Decl::Kind); - - SmallVectorImpl<Decl*> &Decls; - bool PredefsVisited[NUM_PREDEF_DECL_IDS]; - - public: - FindExternalLexicalDeclsVisitor(ASTReader &Reader, const DeclContext *DC, - bool (*isKindWeWant)(Decl::Kind), - SmallVectorImpl<Decl*> &Decls) - : Reader(Reader), DC(DC), isKindWeWant(isKindWeWant), Decls(Decls) - { - for (unsigned I = 0; I != NUM_PREDEF_DECL_IDS; ++I) - PredefsVisited[I] = false; - } +void ASTReader::FindExternalLexicalDecls( + const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, + SmallVectorImpl<Decl *> &Decls) { + bool PredefsVisited[NUM_PREDEF_DECL_IDS] = {}; - static bool visitPostorder(ModuleFile &M, void *UserData) { - FindExternalLexicalDeclsVisitor *This - = static_cast<FindExternalLexicalDeclsVisitor *>(UserData); + auto Visit = [&] (ModuleFile *M, LexicalContents LexicalDecls) { + assert(LexicalDecls.size() % 2 == 0 && "expected an even number of entries"); + for (int I = 0, N = LexicalDecls.size(); I != N; I += 2) { + auto K = (Decl::Kind)+LexicalDecls[I]; + if (!IsKindWeWant(K)) + continue; - ModuleFile::DeclContextInfosMap::iterator Info - = M.DeclContextInfos.find(This->DC); - if (Info == M.DeclContextInfos.end() || !Info->second.LexicalDecls) - return false; + auto ID = (serialization::DeclID)+LexicalDecls[I + 1]; - // Load all of the declaration IDs - for (const KindDeclIDPair *ID = Info->second.LexicalDecls, - *IDE = ID + Info->second.NumLexicalDecls; - ID != IDE; ++ID) { - if (This->isKindWeWant && !This->isKindWeWant((Decl::Kind)ID->first)) + // Don't add predefined declarations to the lexical context more + // than once. + if (ID < NUM_PREDEF_DECL_IDS) { + if (PredefsVisited[ID]) continue; - // Don't add predefined declarations to the lexical context more - // than once. - if (ID->second < NUM_PREDEF_DECL_IDS) { - if (This->PredefsVisited[ID->second]) - continue; - - This->PredefsVisited[ID->second] = true; - } - - if (Decl *D = This->Reader.GetLocalDecl(M, ID->second)) { - if (!This->DC->isDeclInLexicalTraversal(D)) - This->Decls.push_back(D); - } + PredefsVisited[ID] = true; } - return false; + if (Decl *D = GetLocalDecl(*M, ID)) { + assert(D->getKind() == K && "wrong kind for lexical decl"); + if (!DC->isDeclInLexicalTraversal(D)) + Decls.push_back(D); + } } }; -} -ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC, - bool (*isKindWeWant)(Decl::Kind), - SmallVectorImpl<Decl*> &Decls) { - // There might be lexical decls in multiple modules, for the TU at - // least. Walk all of the modules in the order they were loaded. - FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls); - ModuleMgr.visitDepthFirst( - nullptr, &FindExternalLexicalDeclsVisitor::visitPostorder, &Visitor); + if (isa<TranslationUnitDecl>(DC)) { + for (auto Lexical : TULexicalDecls) + Visit(Lexical.first, Lexical.second); + } else { + auto I = LexicalDecls.find(DC); + if (I != LexicalDecls.end()) + Visit(I->second.first, I->second.second); + } + ++NumLexicalDeclContextsRead; - return ELR_Success; } namespace { @@ -6298,168 +6634,26 @@ void ASTReader::FindFileRegionDecls(FileID File, Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt))); } -/// \brief Retrieve the "definitive" module file for the definition of the -/// given declaration context, if there is one. -/// -/// The "definitive" module file is the only place where we need to look to -/// find information about the declarations within the given declaration -/// context. For example, C++ and Objective-C classes, C structs/unions, and -/// Objective-C protocols, categories, and extensions are all defined in a -/// single place in the source code, so they have definitive module files -/// associated with them. C++ namespaces, on the other hand, can have -/// definitions in multiple different module files. -/// -/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's -/// NDEBUG checking. -static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC, - ASTReader &Reader) { - if (const DeclContext *DefDC = getDefinitiveDeclContext(DC)) - return Reader.getOwningModuleFile(cast<Decl>(DefDC)); - - return nullptr; -} - -namespace { - /// \brief ModuleFile visitor used to perform name lookup into a - /// declaration context. - class DeclContextNameLookupVisitor { - ASTReader &Reader; - ArrayRef<const DeclContext *> Contexts; - DeclarationName Name; - ASTDeclContextNameLookupTrait::DeclNameKey NameKey; - unsigned NameHash; - SmallVectorImpl<NamedDecl *> &Decls; - llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet; - - public: - DeclContextNameLookupVisitor(ASTReader &Reader, - DeclarationName Name, - SmallVectorImpl<NamedDecl *> &Decls, - llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet) - : Reader(Reader), Name(Name), - NameKey(ASTDeclContextNameLookupTrait::GetInternalKey(Name)), - NameHash(ASTDeclContextNameLookupTrait::ComputeHash(NameKey)), - Decls(Decls), DeclSet(DeclSet) {} - - void visitContexts(ArrayRef<const DeclContext*> Contexts) { - if (Contexts.empty()) - return; - this->Contexts = Contexts; - - // If we can definitively determine which module file to look into, - // only look there. Otherwise, look in all module files. - ModuleFile *Definitive; - if (Contexts.size() == 1 && - (Definitive = getDefinitiveModuleFileFor(Contexts[0], Reader))) { - visit(*Definitive, this); - } else { - Reader.getModuleManager().visit(&visit, this); - } - } - - private: - static bool visit(ModuleFile &M, void *UserData) { - DeclContextNameLookupVisitor *This - = static_cast<DeclContextNameLookupVisitor *>(UserData); - - // Check whether we have any visible declaration information for - // this context in this module. - ModuleFile::DeclContextInfosMap::iterator Info; - bool FoundInfo = false; - for (auto *DC : This->Contexts) { - Info = M.DeclContextInfos.find(DC); - if (Info != M.DeclContextInfos.end() && - Info->second.NameLookupTableData) { - FoundInfo = true; - break; - } - } - - if (!FoundInfo) - return false; - - // Look for this name within this module. - ASTDeclContextNameLookupTable *LookupTable = - Info->second.NameLookupTableData; - ASTDeclContextNameLookupTable::iterator Pos - = LookupTable->find_hashed(This->NameKey, This->NameHash); - if (Pos == LookupTable->end()) - return false; - - bool FoundAnything = false; - ASTDeclContextNameLookupTrait::data_type Data = *Pos; - for (; Data.first != Data.second; ++Data.first) { - NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first); - if (!ND) - continue; - - if (ND->getDeclName() != This->Name) { - // A name might be null because the decl's redeclarable part is - // currently read before reading its name. The lookup is triggered by - // building that decl (likely indirectly), and so it is later in the - // sense of "already existing" and can be ignored here. - // FIXME: This should not happen; deserializing declarations should - // not perform lookups since that can lead to deserialization cycles. - continue; - } - - // Record this declaration. - FoundAnything = true; - if (This->DeclSet.insert(ND).second) - This->Decls.push_back(ND); - } - - return FoundAnything; - } - }; -} - bool ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { - assert(DC->hasExternalVisibleStorage() && + assert(DC->hasExternalVisibleStorage() && DC == DC->getPrimaryContext() && "DeclContext has no visible decls in storage"); if (!Name) return false; + auto It = Lookups.find(DC); + if (It == Lookups.end()) + return false; + Deserializing LookupResults(this); + // Load the list of declarations. SmallVector<NamedDecl *, 64> Decls; - llvm::SmallPtrSet<NamedDecl*, 64> DeclSet; - - // Compute the declaration contexts we need to look into. Multiple such - // declaration contexts occur when two declaration contexts from disjoint - // modules get merged, e.g., when two namespaces with the same name are - // independently defined in separate modules. - SmallVector<const DeclContext *, 2> Contexts; - Contexts.push_back(DC); - - if (DC->isNamespace()) { - auto Key = KeyDecls.find(const_cast<Decl *>(cast<Decl>(DC))); - if (Key != KeyDecls.end()) { - for (unsigned I = 0, N = Key->second.size(); I != N; ++I) - Contexts.push_back(cast<DeclContext>(GetDecl(Key->second[I]))); - } - } - - DeclContextNameLookupVisitor Visitor(*this, Name, Decls, DeclSet); - Visitor.visitContexts(Contexts); - - // If this might be an implicit special member function, then also search - // all merged definitions of the surrounding class. We need to search them - // individually, because finding an entity in one of them doesn't imply that - // we can't find a different entity in another one. - if (isa<CXXRecordDecl>(DC)) { - auto Merged = MergedLookups.find(DC); - if (Merged != MergedLookups.end()) { - for (unsigned I = 0; I != Merged->second.size(); ++I) { - const DeclContext *Context = Merged->second[I]; - Visitor.visitContexts(Context); - // We might have just added some more merged lookups. If so, our - // iterator is now invalid, so grab a fresh one before continuing. - Merged = MergedLookups.find(DC); - } - } + for (DeclID ID : It->second.Table.find(Name)) { + NamedDecl *ND = cast<NamedDecl>(GetDecl(ID)); + if (ND->getDeclName() == Name) + Decls.push_back(ND); } ++NumVisibleDeclContextsRead; @@ -6467,92 +6661,21 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, return !Decls.empty(); } -namespace { - /// \brief ModuleFile visitor used to retrieve all visible names in a - /// declaration context. - class DeclContextAllNamesVisitor { - ASTReader &Reader; - SmallVectorImpl<const DeclContext *> &Contexts; - DeclsMap &Decls; - llvm::SmallPtrSet<NamedDecl *, 256> DeclSet; - bool VisitAll; - - public: - DeclContextAllNamesVisitor(ASTReader &Reader, - SmallVectorImpl<const DeclContext *> &Contexts, - DeclsMap &Decls, bool VisitAll) - : Reader(Reader), Contexts(Contexts), Decls(Decls), VisitAll(VisitAll) { } - - static bool visit(ModuleFile &M, void *UserData) { - DeclContextAllNamesVisitor *This - = static_cast<DeclContextAllNamesVisitor *>(UserData); - - // Check whether we have any visible declaration information for - // this context in this module. - ModuleFile::DeclContextInfosMap::iterator Info; - bool FoundInfo = false; - for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) { - Info = M.DeclContextInfos.find(This->Contexts[I]); - if (Info != M.DeclContextInfos.end() && - Info->second.NameLookupTableData) { - FoundInfo = true; - break; - } - } - - if (!FoundInfo) - return false; - - ASTDeclContextNameLookupTable *LookupTable = - Info->second.NameLookupTableData; - bool FoundAnything = false; - for (ASTDeclContextNameLookupTable::data_iterator - I = LookupTable->data_begin(), E = LookupTable->data_end(); - I != E; - ++I) { - ASTDeclContextNameLookupTrait::data_type Data = *I; - for (; Data.first != Data.second; ++Data.first) { - NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M, - *Data.first); - if (!ND) - continue; - - // Record this declaration. - FoundAnything = true; - if (This->DeclSet.insert(ND).second) - This->Decls[ND->getDeclName()].push_back(ND); - } - } - - return FoundAnything && !This->VisitAll; - } - }; -} - void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { if (!DC->hasExternalVisibleStorage()) return; - DeclsMap Decls; - // Compute the declaration contexts we need to look into. Multiple such - // declaration contexts occur when two declaration contexts from disjoint - // modules get merged, e.g., when two namespaces with the same name are - // independently defined in separate modules. - SmallVector<const DeclContext *, 2> Contexts; - Contexts.push_back(DC); + auto It = Lookups.find(DC); + assert(It != Lookups.end() && + "have external visible storage but no lookup tables"); - if (DC->isNamespace()) { - KeyDeclsMap::iterator Key = - KeyDecls.find(const_cast<Decl *>(cast<Decl>(DC))); - if (Key != KeyDecls.end()) { - for (unsigned I = 0, N = Key->second.size(); I != N; ++I) - Contexts.push_back(cast<DeclContext>(GetDecl(Key->second[I]))); - } + DeclsMap Decls; + + for (DeclID ID : It->second.Table.findAll()) { + NamedDecl *ND = cast<NamedDecl>(GetDecl(ID)); + Decls[ND->getDeclName()].push_back(ND); } - DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls, - /*VisitAll=*/DC->isFileContext()); - ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor); ++NumVisibleDeclContextsRead; for (DeclsMap::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) { @@ -6561,6 +6684,12 @@ void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false); } +const serialization::reader::DeclContextLookupTable * +ASTReader::getLoadedLookupTables(DeclContext *Primary) const { + auto I = Lookups.find(Primary); + return I == Lookups.end() ? nullptr : &I->second; +} + /// \brief Under non-PCH compilation the consumer receives the objc methods /// before receiving the implementation, and codegen depends on this. /// We simulate this by deserializing and passing to consumer the methods of the @@ -6824,24 +6953,36 @@ void ASTReader::UpdateSema() { SemaObj->ActOnPragmaOptimize(/* IsOn = */ false, OptimizeOffPragmaLocation); } -IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) { +IdentifierInfo *ASTReader::get(StringRef Name) { // Note that we are loading an identifier. Deserializing AnIdentifier(this); - StringRef Name(NameStart, NameEnd - NameStart); - // If there is a global index, look there first to determine which modules - // provably do not have any results for this identifier. - GlobalModuleIndex::HitSet Hits; - GlobalModuleIndex::HitSet *HitsPtr = nullptr; - if (!loadGlobalIndex()) { - if (GlobalIndex->lookupIdentifier(Name, Hits)) { - HitsPtr = &Hits; - } - } IdentifierLookupVisitor Visitor(Name, /*PriorGeneration=*/0, NumIdentifierLookups, NumIdentifierLookupHits); - ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr); + + // We don't need to do identifier table lookups in C++ modules (we preload + // all interesting declarations, and don't need to use the scope for name + // lookups). Perform the lookup in PCH files, though, since we don't build + // a complete initial identifier table if we're carrying on from a PCH. + if (Context.getLangOpts().CPlusPlus) { + for (auto F : ModuleMgr.pch_modules()) + if (Visitor(*F)) + break; + } else { + // If there is a global index, look there first to determine which modules + // provably do not have any results for this identifier. + GlobalModuleIndex::HitSet Hits; + GlobalModuleIndex::HitSet *HitsPtr = nullptr; + if (!loadGlobalIndex()) { + if (GlobalIndex->lookupIdentifier(Name, Hits)) { + HitsPtr = &Hits; + } + } + + ModuleMgr.visit(Visitor, HitsPtr); + } + IdentifierInfo *II = Visitor.getIdentifierInfo(); markIdentifierUpToDate(II); return II; @@ -6928,41 +7069,37 @@ namespace clang { namespace serialization { InstanceBits(0), FactoryBits(0), InstanceHasMoreThanOneDecl(false), FactoryHasMoreThanOneDecl(false) {} - static bool visit(ModuleFile &M, void *UserData) { - ReadMethodPoolVisitor *This - = static_cast<ReadMethodPoolVisitor *>(UserData); - + bool operator()(ModuleFile &M) { if (!M.SelectorLookupTable) return false; // If we've already searched this module file, skip it now. - if (M.Generation <= This->PriorGeneration) + if (M.Generation <= PriorGeneration) return true; - ++This->Reader.NumMethodPoolTableLookups; + ++Reader.NumMethodPoolTableLookups; ASTSelectorLookupTable *PoolTable = (ASTSelectorLookupTable*)M.SelectorLookupTable; - ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel); + ASTSelectorLookupTable::iterator Pos = PoolTable->find(Sel); if (Pos == PoolTable->end()) return false; - ++This->Reader.NumMethodPoolTableHits; - ++This->Reader.NumSelectorsRead; + ++Reader.NumMethodPoolTableHits; + ++Reader.NumSelectorsRead; // FIXME: Not quite happy with the statistics here. We probably should // disable this tracking when called via LoadSelector. // Also, should entries without methods count as misses? - ++This->Reader.NumMethodPoolEntriesRead; + ++Reader.NumMethodPoolEntriesRead; ASTSelectorLookupTrait::data_type Data = *Pos; - if (This->Reader.DeserializationListener) - This->Reader.DeserializationListener->SelectorRead(Data.ID, - This->Sel); - - This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); - This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); - This->InstanceBits = Data.InstanceBits; - This->FactoryBits = Data.FactoryBits; - This->InstanceHasMoreThanOneDecl = Data.InstanceHasMoreThanOneDecl; - This->FactoryHasMoreThanOneDecl = Data.FactoryHasMoreThanOneDecl; + if (Reader.DeserializationListener) + Reader.DeserializationListener->SelectorRead(Data.ID, Sel); + + InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); + FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); + InstanceBits = Data.InstanceBits; + FactoryBits = Data.FactoryBits; + InstanceHasMoreThanOneDecl = Data.InstanceHasMoreThanOneDecl; + FactoryHasMoreThanOneDecl = Data.FactoryHasMoreThanOneDecl; return true; } @@ -7002,8 +7139,8 @@ void ASTReader::ReadMethodPool(Selector Sel) { // Search for methods defined with this selector. ++NumMethodPoolLookups; ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration); - ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor); - + ModuleMgr.visit(Visitor); + if (Visitor.getInstanceMethods().empty() && Visitor.getFactoryMethods().empty()) return; @@ -7384,33 +7521,47 @@ Module *ASTReader::getModule(unsigned ID) { return getSubmodule(ID); } -ExternalASTSource::ASTSourceDescriptor -ASTReader::getSourceDescriptor(const Module &M) { - StringRef Dir, Filename; - if (M.Directory) - Dir = M.Directory->getName(); - if (auto *File = M.getASTFile()) - Filename = File->getName(); - return ASTReader::ASTSourceDescriptor{ - M.getFullModuleName(), Dir, Filename, - M.Signature - }; +ModuleFile *ASTReader::getLocalModuleFile(ModuleFile &F, unsigned ID) { + if (ID & 1) { + // It's a module, look it up by submodule ID. + auto I = GlobalSubmoduleMap.find(getGlobalSubmoduleID(F, ID >> 1)); + return I == GlobalSubmoduleMap.end() ? nullptr : I->second; + } else { + // It's a prefix (preamble, PCH, ...). Look it up by index. + unsigned IndexFromEnd = ID >> 1; + assert(IndexFromEnd && "got reference to unknown module file"); + return getModuleManager().pch_modules().end()[-IndexFromEnd]; + } +} + +unsigned ASTReader::getModuleFileID(ModuleFile *F) { + if (!F) + return 1; + + // For a file representing a module, use the submodule ID of the top-level + // module as the file ID. For any other kind of file, the number of such + // files loaded beforehand will be the same on reload. + // FIXME: Is this true even if we have an explicit module file and a PCH? + if (F->isModule()) + return ((F->BaseSubmoduleID + NUM_PREDEF_SUBMODULE_IDS) << 1) | 1; + + auto PCHModules = getModuleManager().pch_modules(); + auto I = std::find(PCHModules.begin(), PCHModules.end(), F); + assert(I != PCHModules.end() && "emitting reference to unknown file"); + return (I - PCHModules.end()) << 1; } llvm::Optional<ExternalASTSource::ASTSourceDescriptor> ASTReader::getSourceDescriptor(unsigned ID) { if (const Module *M = getSubmodule(ID)) - return getSourceDescriptor(*M); + return ExternalASTSource::ASTSourceDescriptor(*M); // If there is only a single PCH, return it instead. // Chained PCH are not suported. if (ModuleMgr.size() == 1) { ModuleFile &MF = ModuleMgr.getPrimaryModule(); - return ASTReader::ASTSourceDescriptor{ - MF.OriginalSourceFileName, MF.OriginalDir, - MF.FileName, - MF.Signature - }; + return ASTReader::ASTSourceDescriptor( + MF.OriginalSourceFileName, MF.OriginalDir, MF.FileName, MF.Signature); } return None; } @@ -7619,9 +7770,19 @@ ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record, llvm_unreachable("Unhandled template name kind!"); } -TemplateArgument -ASTReader::ReadTemplateArgument(ModuleFile &F, - const RecordData &Record, unsigned &Idx) { +TemplateArgument ASTReader::ReadTemplateArgument(ModuleFile &F, + const RecordData &Record, + unsigned &Idx, + bool Canonicalize) { + if (Canonicalize) { + // The caller wants a canonical template argument. Sometimes the AST only + // wants template arguments in canonical form (particularly as the template + // argument lists of template specializations) so ensure we preserve that + // canonical form across serialization. + TemplateArgument Arg = ReadTemplateArgument(F, Record, Idx, false); + return Context.getCanonicalTemplateArgument(Arg); + } + TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++]; switch (Kind) { case TemplateArgument::Null: @@ -7655,7 +7816,7 @@ ASTReader::ReadTemplateArgument(ModuleFile &F, TemplateArgument *Args = new (Context) TemplateArgument[NumArgs]; for (unsigned I = 0; I != NumArgs; ++I) Args[I] = ReadTemplateArgument(F, Record, Idx); - return TemplateArgument(Args, NumArgs); + return TemplateArgument(llvm::makeArrayRef(Args, NumArgs)); } } @@ -7677,7 +7838,7 @@ ASTReader::ReadTemplateParameterList(ModuleFile &F, TemplateParameterList* TemplateParams = TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, - Params.data(), Params.size(), RAngleLoc); + Params, RAngleLoc); return TemplateParams; } @@ -7685,11 +7846,11 @@ void ASTReader:: ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs, ModuleFile &F, const RecordData &Record, - unsigned &Idx) { + unsigned &Idx, bool Canonicalize) { unsigned NumTemplateArgs = Record[Idx++]; TemplArgs.reserve(NumTemplateArgs); while (NumTemplateArgs--) - TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx)); + TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx, Canonicalize)); } /// \brief Read a UnresolvedSet structure. @@ -8070,14 +8231,6 @@ void ASTReader::ReadComments() { } } -void ASTReader::getInputFiles(ModuleFile &F, - SmallVectorImpl<serialization::InputFile> &Files) { - for (unsigned I = 0, E = F.InputFilesLoaded.size(); I != E; ++I) { - unsigned ID = I+1; - Files.push_back(getInputFile(F, ID)); - } -} - std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) { // If we know the owning module, use it. if (Module *M = D->getImportedOwningModule()) @@ -8119,11 +8272,8 @@ void ASTReader::finishPendingActions() { PendingIncompleteDeclChains.clear(); // Load pending declaration chains. - for (unsigned I = 0; I != PendingDeclChains.size(); ++I) { - PendingDeclChainsKnown.erase(PendingDeclChains[I]); - loadPendingDeclChain(PendingDeclChains[I]); - } - assert(PendingDeclChainsKnown.empty()); + for (unsigned I = 0; I != PendingDeclChains.size(); ++I) + loadPendingDeclChain(PendingDeclChains[I].first, PendingDeclChains[I].second); PendingDeclChains.clear(); // Make the most recent of the top-level declarations visible. @@ -8232,9 +8382,8 @@ void ASTReader::finishPendingActions() { // Load the bodies of any functions or methods we've encountered. We do // this now (delayed) so that we can be sure that the declaration chains - // have been fully wired up. - // FIXME: There seems to be no point in delaying this, it does not depend - // on the redecl chains having been wired up. + // have been fully wired up (hasBody relies on this). + // FIXME: We shouldn't require complete redeclaration chains here. for (PendingBodiesMap::iterator PB = PendingBodies.begin(), PBEnd = PendingBodies.end(); PB != PBEnd; ++PB) { @@ -8310,21 +8459,26 @@ void ASTReader::diagnoseOdrViolations() { if (Found) continue; + // Quick check failed, time to do the slow thing. Note, we can't just + // look up the name of D in CanonDef here, because the member that is + // in CanonDef might not be found by name lookup (it might have been + // replaced by a more recent declaration in the lookup table), and we + // can't necessarily find it in the redeclaration chain because it might + // be merely mergeable, not redeclarable. llvm::SmallVector<const NamedDecl*, 4> Candidates; - DeclContext::lookup_result R = CanonDef->lookup(D->getDeclName()); - for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); - !Found && I != E; ++I) { - for (auto RI : (*I)->redecls()) { - if (RI->getLexicalDeclContext() == CanonDef) { - // This declaration is present in the canonical definition. If it's - // in the same redecl chain, it's the one we're looking for. - if (RI->getCanonicalDecl() == DCanon) - Found = true; - else - Candidates.push_back(cast<NamedDecl>(RI)); - break; - } + for (auto *CanonMember : CanonDef->decls()) { + if (CanonMember->getCanonicalDecl() == DCanon) { + // This can happen if the declaration is merely mergeable and not + // actually redeclarable (we looked for redeclarations earlier). + // + // FIXME: We should be able to detect this more efficiently, without + // pulling in all of the members of CanonDef. + Found = true; + break; } + if (auto *ND = dyn_cast<NamedDecl>(CanonMember)) + if (ND->getDeclName() == D->getDeclName()) + Candidates.push_back(ND); } if (!Found) { @@ -8428,16 +8582,19 @@ void ASTReader::FinishedDeserializing() { PendingExceptionSpecUpdates.clear(); for (auto Update : Updates) { auto *FPT = Update.second->getType()->castAs<FunctionProtoType>(); - SemaObj->UpdateExceptionSpec(Update.second, - FPT->getExtProtoInfo().ExceptionSpec); + auto ESI = FPT->getExtProtoInfo().ExceptionSpec; + if (auto *Listener = Context.getASTMutationListener()) + Listener->ResolvedExceptionSpec(cast<FunctionDecl>(Update.second)); + for (auto *Redecl : Update.second->redecls()) + Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); } } - diagnoseOdrViolations(); - if (ReadTimer) ReadTimer->stopTimer(); + diagnoseOdrViolations(); + // We are not in recursive loading, so it's safe to pass the "interesting" // decls to the consumer. if (Consumer) @@ -8450,7 +8607,7 @@ void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { // Remove any fake results before adding any real ones. auto It = PendingFakeLookupResults.find(II); if (It != PendingFakeLookupResults.end()) { - for (auto *ND : PendingFakeLookupResults[II]) + for (auto *ND : It->second) SemaObj->IdResolver.RemoveDecl(ND); // FIXME: this works around module+PCH performance issue. // Rather than erase the result from the map, which is O(n), just clear @@ -8471,13 +8628,15 @@ void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { } } -ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, - const PCHContainerReader &PCHContainerRdr, - StringRef isysroot, bool DisableValidation, - bool AllowASTWithCompilerErrors, - bool AllowConfigurationMismatch, bool ValidateSystemInputs, - bool UseGlobalIndex, - std::unique_ptr<llvm::Timer> ReadTimer) +ASTReader::ASTReader( + Preprocessor &PP, ASTContext &Context, + const PCHContainerReader &PCHContainerRdr, + ArrayRef<IntrusiveRefCntPtr<ModuleFileExtension>> Extensions, + StringRef isysroot, bool DisableValidation, + bool AllowASTWithCompilerErrors, + bool AllowConfigurationMismatch, bool ValidateSystemInputs, + bool UseGlobalIndex, + std::unique_ptr<llvm::Timer> ReadTimer) : Listener(new PCHValidator(PP, *this)), DeserializationListener(nullptr), OwnsDeserializationListener(false), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), PCHContainerRdr(PCHContainerRdr), @@ -8501,19 +8660,21 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0), PassingDeclsToConsumer(false), ReadingKind(Read_None) { SourceMgr.setExternalSLocEntrySource(this); + + for (const auto &Ext : Extensions) { + auto BlockName = Ext->getExtensionMetadata().BlockName; + auto Known = ModuleFileExtensions.find(BlockName); + if (Known != ModuleFileExtensions.end()) { + Diags.Report(diag::warn_duplicate_module_file_extension) + << BlockName; + continue; + } + + ModuleFileExtensions.insert({BlockName, Ext}); + } } ASTReader::~ASTReader() { if (OwnsDeserializationListener) delete DeserializationListener; - - for (DeclContextVisibleUpdatesPending::iterator - I = PendingVisibleUpdates.begin(), - E = PendingVisibleUpdates.end(); - I != E; ++I) { - for (DeclContextVisibleUpdates::iterator J = I->second.begin(), - F = I->second.end(); - J != F; ++J) - delete J->first; - } } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp index 1a0c5b58e7f6..8fb110e4551d 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp @@ -26,6 +26,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/Support/SaveAndRestore.h" + using namespace clang; using namespace clang::serialization; @@ -120,45 +121,20 @@ namespace clang { static void setAnonymousDeclForMerging(ASTReader &Reader, DeclContext *DC, unsigned Index, NamedDecl *D); - /// \brief RAII class used to capture the first ID within a redeclaration - /// chain and to introduce it into the list of pending redeclaration chains - /// on destruction. + /// Results from loading a RedeclarableDecl. class RedeclarableResult { - ASTReader &Reader; GlobalDeclID FirstID; Decl *MergeWith; - mutable bool Owning; bool IsKeyDecl; - Decl::Kind DeclKind; - - void operator=(RedeclarableResult &) = delete; public: - RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID, - Decl *MergeWith, Decl::Kind DeclKind, - bool IsKeyDecl) - : Reader(Reader), FirstID(FirstID), MergeWith(MergeWith), - Owning(true), IsKeyDecl(IsKeyDecl), DeclKind(DeclKind) {} - - RedeclarableResult(RedeclarableResult &&Other) - : Reader(Other.Reader), FirstID(Other.FirstID), - MergeWith(Other.MergeWith), Owning(Other.Owning), - IsKeyDecl(Other.IsKeyDecl), DeclKind(Other.DeclKind) { - Other.Owning = false; - } - - ~RedeclarableResult() { - if (FirstID && Owning && isRedeclarableDeclKind(DeclKind)) { - auto Canon = Reader.GetDecl(FirstID)->getCanonicalDecl(); - if (Reader.PendingDeclChainsKnown.insert(Canon).second) - Reader.PendingDeclChains.push_back(Canon); - } - } + RedeclarableResult(GlobalDeclID FirstID, Decl *MergeWith, bool IsKeyDecl) + : FirstID(FirstID), MergeWith(MergeWith), IsKeyDecl(IsKeyDecl) {} /// \brief Retrieve the first ID. GlobalDeclID getFirstID() const { return FirstID; } - /// \brief Is this declaration the key declaration? + /// \brief Is this declaration a key declaration? bool isKeyDecl() const { return IsKeyDecl; } /// \brief Get a known declaration that this should be merged with, if @@ -185,7 +161,7 @@ namespace clang { public: FindExistingResult(ASTReader &Reader) : Reader(Reader), New(nullptr), Existing(nullptr), AddResult(false), - AnonymousDeclNumber(0), TypedefNameForLinkage(0) {} + AnonymousDeclNumber(0), TypedefNameForLinkage(nullptr) {} FindExistingResult(ASTReader &Reader, NamedDecl *New, NamedDecl *Existing, unsigned AnonymousDeclNumber, @@ -317,6 +293,7 @@ namespace clang { DeclID VisitTemplateDecl(TemplateDecl *D); RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); void VisitClassTemplateDecl(ClassTemplateDecl *D); + void VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D); void VisitVarTemplateDecl(VarTemplateDecl *D); void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); @@ -395,7 +372,7 @@ namespace clang { } } }; -} +} // end namespace clang namespace { /// Iterator over the redeclarations of a declaration that have already @@ -431,12 +408,12 @@ public: return A.Current != B.Current; } }; -} +} // end anonymous namespace + template<typename DeclT> llvm::iterator_range<MergedRedeclIterator<DeclT>> merged_redecls(DeclT *D) { - return llvm::iterator_range<MergedRedeclIterator<DeclT>>( - MergedRedeclIterator<DeclT>(D), - MergedRedeclIterator<DeclT>()); + return llvm::make_range(MergedRedeclIterator<DeclT>(D), + MergedRedeclIterator<DeclT>()); } uint64_t ASTDeclReader::GetCurrentCursorOffset() { @@ -465,8 +442,8 @@ void ASTDeclReader::Visit(Decl *D) { // If this is a tag declaration with a typedef name for linkage, it's safe // to load that typedef now. if (NamedDeclForTagDecl) - cast<TagDecl>(D)->NamedDeclOrQualifier = - cast<NamedDecl>(Reader.GetDecl(NamedDeclForTagDecl)); + cast<TagDecl>(D)->TypedefNameDeclOrQualifier = + cast<TypedefNameDecl>(Reader.GetDecl(NamedDeclForTagDecl)); } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) { // if we have a fully initialized TypeDecl, we can safely read its type now. ID->TypeForDecl = Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull(); @@ -499,6 +476,8 @@ void ASTDeclReader::VisitDecl(Decl *D) { // placeholder. GlobalDeclID SemaDCIDForTemplateParmDecl = ReadDeclID(Record, Idx); GlobalDeclID LexicalDCIDForTemplateParmDecl = ReadDeclID(Record, Idx); + if (!LexicalDCIDForTemplateParmDecl) + LexicalDCIDForTemplateParmDecl = SemaDCIDForTemplateParmDecl; Reader.addPendingDeclContextInfo(D, SemaDCIDForTemplateParmDecl, LexicalDCIDForTemplateParmDecl); @@ -506,6 +485,8 @@ void ASTDeclReader::VisitDecl(Decl *D) { } else { DeclContext *SemaDC = ReadDeclAs<DeclContext>(Record, Idx); DeclContext *LexicalDC = ReadDeclAs<DeclContext>(Record, Idx); + if (!LexicalDC) + LexicalDC = SemaDC; DeclContext *MergedSemaDC = Reader.MergedDeclContexts.lookup(SemaDC); // Avoid calling setLexicalDeclContext() directly because it uses // Decl::getASTContext() internally which is unsafe during derialization. @@ -619,16 +600,13 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) { case 1: { // ExtInfo TagDecl::ExtInfo *Info = new (Reader.getContext()) TagDecl::ExtInfo(); ReadQualifierInfo(*Info, Record, Idx); - TD->NamedDeclOrQualifier = Info; + TD->TypedefNameDeclOrQualifier = Info; break; } case 2: // TypedefNameForAnonDecl NamedDeclForTagDecl = ReadDeclID(Record, Idx); TypedefNameForLinkage = Reader.GetIdentifierInfo(F, Record, Idx); break; - case 3: // DeclaratorForAnonDecl - NamedDeclForTagDecl = ReadDeclID(Record, Idx); - break; default: llvm_unreachable("unexpected tag info kind"); } @@ -771,8 +749,9 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { // Template arguments. SmallVector<TemplateArgument, 8> TemplArgs; - Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx); - + Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx, + /*Canonicalize*/ true); + // Template args as written. SmallVector<TemplateArgumentLoc, 8> TemplArgLocs; SourceLocation LAngleLoc, RAngleLoc; @@ -909,6 +888,7 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { void ASTDeclReader::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { VisitTypedefNameDecl(D); + D->Variance = Record[Idx++]; D->Index = Record[Idx++]; D->VarianceLoc = ReadSourceLocation(Record, Idx); @@ -1121,7 +1101,6 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { D->IvarInitializers = Reader.ReadCXXCtorInitializersRef(F, Record, Idx); } - void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { VisitDecl(D); D->setAtLoc(ReadSourceLocation(Record, Idx)); @@ -1168,6 +1147,8 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { for (unsigned I = 0; I != FD->ChainingSize; ++I) FD->Chaining[I] = ReadDeclAs<NamedDecl>(Record, Idx); + + mergeMergeable(FD); } ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { @@ -1208,8 +1189,9 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { }; switch ((VarKind)Record[Idx++]) { case VarNotTemplate: - // Only true variables (not parameters or implicit parameters) can be merged - if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam && + // Only true variables (not parameters or implicit parameters) can be + // merged; the other kinds are not really redeclarable at all. + if (!isa<ParmVarDecl>(VD) && !isa<ImplicitParamDecl>(VD) && !isa<VarTemplateSpecializationDecl>(VD)) mergeRedeclarable(VD, Redecl); break; @@ -1290,8 +1272,7 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { captures.push_back(BlockDecl::Capture(decl, byRef, nested, copyExpr)); } - BD->setCaptures(Reader.getContext(), captures.begin(), - captures.end(), capturesCXXThis); + BD->setCaptures(Reader.getContext(), captures, capturesCXXThis); } void ASTDeclReader::VisitCapturedDecl(CapturedDecl *CD) { @@ -1319,7 +1300,6 @@ void ASTDeclReader::VisitLabelDecl(LabelDecl *D) { D->setLocStart(ReadSourceLocation(Record, Idx)); } - void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); VisitNamedDecl(D); @@ -1506,21 +1486,14 @@ void ASTDeclReader::MergeDefinitionData( auto &DD = *D->DefinitionData.getNotUpdated(); if (DD.Definition != MergeDD.Definition) { - // If the new definition has new special members, let the name lookup - // code know that it needs to look in the new definition too. - // - // FIXME: We only need to do this if the merged definition declares members - // that this definition did not declare, or if it defines members that this - // definition did not define. - Reader.MergedLookups[DD.Definition].push_back(MergeDD.Definition); - DD.Definition->setHasExternalVisibleStorage(); - // Track that we merged the definitions. Reader.MergedDeclContexts.insert(std::make_pair(MergeDD.Definition, DD.Definition)); Reader.PendingDefinitions.erase(MergeDD.Definition); MergeDD.Definition->IsCompleteDefinition = false; mergeDefinitionVisibility(DD.Definition, MergeDD.Definition); + assert(Reader.Lookups.find(MergeDD.Definition) == Reader.Lookups.end() && + "already loaded pending lookups for merged definition"); } auto PFDI = Reader.PendingFakeDefinitionData.find(&DD); @@ -1758,7 +1731,7 @@ void ASTDeclReader::VisitImportDecl(ImportDecl *D) { VisitDecl(D); D->ImportedAndComplete.setPointer(readModule(Record, Idx)); D->ImportedAndComplete.setInt(Record[Idx++]); - SourceLocation *StoredLocs = reinterpret_cast<SourceLocation *>(D + 1); + SourceLocation *StoredLocs = D->getTrailingObjects<SourceLocation>(); for (unsigned I = 0, N = Record.back(); I != N; ++I) StoredLocs[I] = ReadSourceLocation(Record, Idx); ++Idx; // The number of stored source locations. @@ -1776,7 +1749,8 @@ void ASTDeclReader::VisitFriendDecl(FriendDecl *D) { else D->Friend = GetTypeSourceInfo(Record, Idx); for (unsigned i = 0; i != D->NumTPLists; ++i) - D->getTPLists()[i] = Reader.ReadTemplateParameterList(F, Record, Idx); + D->getTrailingObjects<TemplateParameterList *>()[i] = + Reader.ReadTemplateParameterList(F, Record, Idx); D->NextFriend = ReadDeclID(Record, Idx); D->UnsupportedFriend = (Record[Idx++] != 0); D->FriendLoc = ReadSourceLocation(Record, Idx); @@ -1887,6 +1861,10 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { } } +void ASTDeclReader::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) { + llvm_unreachable("BuiltinTemplates are not serialized"); +} + /// TODO: Unify with ClassTemplateDecl version? /// May require unifying ClassTemplateDecl and /// VarTemplateDecl beyond TemplateDecl... @@ -1933,7 +1911,8 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl( } SmallVector<TemplateArgument, 8> TemplArgs; - Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx); + Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx, + /*Canonicalize*/ true); D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs.data(), TemplArgs.size()); D->PointOfInstantiation = ReadSourceLocation(Record, Idx); @@ -2060,7 +2039,8 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl( } SmallVector<TemplateArgument, 8> TemplArgs; - Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx); + Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx, + /*Canonicalize*/ true); D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs.data(), TemplArgs.size()); D->PointOfInstantiation = ReadSourceLocation(Record, Idx); @@ -2070,6 +2050,7 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl( if (writtenAsCanonicalDecl) { VarTemplateDecl *CanonPattern = ReadDeclAs<VarTemplateDecl>(Record, Idx); if (D->isCanonicalDecl()) { // It's kept in the folding set. + // FIXME: If it's already present, merge it. if (VarTemplatePartialSpecializationDecl *Partial = dyn_cast<VarTemplatePartialSpecializationDecl>(D)) { CanonPattern->getCommonPtr()->PartialSpecializations @@ -2118,10 +2099,11 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { D->setDepth(Record[Idx++]); D->setPosition(Record[Idx++]); if (D->isExpandedParameterPack()) { - void **Data = reinterpret_cast<void **>(D + 1); + auto TypesAndInfos = + D->getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>(); for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { - Data[2*I] = Reader.readType(F, Record, Idx).getAsOpaquePtr(); - Data[2*I + 1] = GetTypeSourceInfo(Record, Idx); + new (&TypesAndInfos[I].first) QualType(Reader.readType(F, Record, Idx)); + TypesAndInfos[I].second = GetTypeSourceInfo(Record, Idx); } } else { // Rest of NonTypeTemplateParmDecl. @@ -2137,7 +2119,8 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { D->setDepth(Record[Idx++]); D->setPosition(Record[Idx++]); if (D->isExpandedParameterPack()) { - void **Data = reinterpret_cast<void **>(D + 1); + TemplateParameterList **Data = + D->getTrailingObjects<TemplateParameterList *>(); for (unsigned I = 0, N = D->getNumExpansionTemplateParameters(); I != N; ++I) Data[I] = Reader.ReadTemplateParameterList(F, Record, Idx); @@ -2178,23 +2161,37 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { DeclID FirstDeclID = ReadDeclID(Record, Idx); Decl *MergeWith = nullptr; + bool IsKeyDecl = ThisDeclID == FirstDeclID; + bool IsFirstLocalDecl = false; + + uint64_t RedeclOffset = 0; // 0 indicates that this declaration was the only declaration of its entity, // and is used for space optimization. if (FirstDeclID == 0) { FirstDeclID = ThisDeclID; IsKeyDecl = true; + IsFirstLocalDecl = true; } else if (unsigned N = Record[Idx++]) { - IsKeyDecl = false; + // This declaration was the first local declaration, but may have imported + // other declarations. + IsKeyDecl = N == 1; + IsFirstLocalDecl = true; // We have some declarations that must be before us in our redeclaration // chain. Read them now, and remember that we ought to merge with one of // them. // FIXME: Provide a known merge target to the second and subsequent such // declaration. - for (unsigned I = 0; I != N; ++I) + for (unsigned I = 0; I != N - 1; ++I) MergeWith = ReadDecl(Record, Idx/*, MergeWith*/); + + RedeclOffset = Record[Idx++]; + } else { + // This declaration was not the first local declaration. Read the first + // local declaration now, to trigger the import of other redeclarations. + (void)ReadDecl(Record, Idx); } T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID)); @@ -2206,14 +2203,17 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { D->RedeclLink = Redeclarable<T>::PreviousDeclLink(FirstDecl); D->First = FirstDecl->getCanonicalDecl(); } - - // Note that this declaration has been deserialized. - Reader.RedeclsDeserialized.insert(static_cast<T *>(D)); - - // The result structure takes care to note that we need to load the - // other declaration chains for this ID. - return RedeclarableResult(Reader, FirstDeclID, MergeWith, - static_cast<T *>(D)->getKind(), IsKeyDecl); + + T *DAsT = static_cast<T*>(D); + + // Note that we need to load local redeclarations of this decl and build a + // decl chain for them. This must happen *after* we perform the preloading + // above; this ensures that the redeclaration chain is built in the correct + // order. + if (IsFirstLocalDecl) + Reader.PendingDeclChains.push_back(std::make_pair(DAsT, RedeclOffset)); + + return RedeclarableResult(FirstDeclID, MergeWith, IsKeyDecl); } /// \brief Attempts to merge the given declaration (D) with another declaration @@ -2255,9 +2255,8 @@ void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D, DeclID DsID, bool IsKeyDecl) { auto *DPattern = D->getTemplatedDecl(); auto *ExistingPattern = Existing->getTemplatedDecl(); - RedeclarableResult Result(Reader, DPattern->getCanonicalDecl()->getGlobalID(), - /*MergeWith*/ExistingPattern, DPattern->getKind(), - IsKeyDecl); + RedeclarableResult Result(DPattern->getCanonicalDecl()->getGlobalID(), + /*MergeWith*/ ExistingPattern, IsKeyDecl); if (auto *DClass = dyn_cast<CXXRecordDecl>(DPattern)) { // Merge with any existing definition. @@ -2323,11 +2322,8 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing, TemplatePatternID, Redecl.isKeyDecl()); // If this declaration is a key declaration, make a note of that. - if (Redecl.isKeyDecl()) { + if (Redecl.isKeyDecl()) Reader.KeyDecls[ExistingCanon].push_back(Redecl.getFirstID()); - if (Reader.PendingDeclChainsKnown.insert(ExistingCanon).second) - Reader.PendingDeclChains.push_back(ExistingCanon); - } } } @@ -2626,6 +2622,13 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { return X->getASTContext().hasSameType(FDX->getType(), FDY->getType()); } + // Indirect fields with the same target field match. + if (auto *IFDX = dyn_cast<IndirectFieldDecl>(X)) { + auto *IFDY = cast<IndirectFieldDecl>(Y); + return IFDX->getAnonField()->getCanonicalDecl() == + IFDY->getAnonField()->getCanonicalDecl(); + } + // Enumerators with the same name match. if (isa<EnumConstantDecl>(X)) // FIXME: Also check the value is odr-equivalent. @@ -2749,12 +2752,12 @@ static NamedDecl *getDeclForMerging(NamedDecl *Found, // declaration, then we want that inner declaration. Declarations from // AST files are handled via ImportedTypedefNamesForLinkage. if (Found->isFromASTFile()) - return 0; + return nullptr; if (auto *TND = dyn_cast<TypedefNameDecl>(Found)) return TND->getAnonDeclWithTypedefName(); - return 0; + return nullptr; } NamedDecl *ASTDeclReader::getAnonymousDeclForMerging(ASTReader &Reader, @@ -2924,6 +2927,7 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, D->RedeclLink.setPrevious(cast<DeclT>(Previous)); D->First = cast<DeclT>(Previous)->First; } + namespace clang { template<> void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, @@ -2969,7 +2973,8 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, std::make_pair(Canon, IsUnresolved ? PrevFD : FD)); } } -} +} // end namespace clang + void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, ...) { llvm_unreachable("attachPreviousDecl on non-redeclarable declaration"); } @@ -3319,37 +3324,13 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { // If this declaration is also a declaration context, get the // offsets for its tables of lexical and visible declarations. if (DeclContext *DC = dyn_cast<DeclContext>(D)) { - // FIXME: This should really be - // DeclContext *LookupDC = DC->getPrimaryContext(); - // but that can walk the redeclaration chain, which might not work yet. - DeclContext *LookupDC = DC; - if (isa<NamespaceDecl>(DC)) - LookupDC = DC->getPrimaryContext(); std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC); - if (Offsets.first || Offsets.second) { - if (Offsets.first != 0) - DC->setHasExternalLexicalStorage(true); - if (Offsets.second != 0) - LookupDC->setHasExternalVisibleStorage(true); - if (ReadDeclContextStorage(*Loc.F, DeclsCursor, Offsets, - Loc.F->DeclContextInfos[DC])) - return nullptr; - } - - // Now add the pending visible updates for this decl context, if it has any. - DeclContextVisibleUpdatesPending::iterator I = - PendingVisibleUpdates.find(ID); - if (I != PendingVisibleUpdates.end()) { - // There are updates. This means the context has external visible - // storage, even if the original stored version didn't. - LookupDC->setHasExternalVisibleStorage(true); - for (const auto &Update : I->second) { - DeclContextInfo &Info = Update.second->DeclContextInfos[DC]; - delete Info.NameLookupTableData; - Info.NameLookupTableData = Update.first; - } - PendingVisibleUpdates.erase(I); - } + if (Offsets.first && + ReadLexicalDeclContextStorage(*Loc.F, DeclsCursor, Offsets.first, DC)) + return nullptr; + if (Offsets.second && + ReadVisibleDeclContextStorage(*Loc.F, DeclsCursor, Offsets.second, ID)) + return nullptr; } assert(Idx == Record.size()); @@ -3372,17 +3353,32 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { } void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) { + // Load the pending visible updates for this decl context, if it has any. + auto I = PendingVisibleUpdates.find(ID); + if (I != PendingVisibleUpdates.end()) { + auto VisibleUpdates = std::move(I->second); + PendingVisibleUpdates.erase(I); + + auto *DC = cast<DeclContext>(D)->getPrimaryContext(); + for (const PendingVisibleUpdate &Update : VisibleUpdates) + Lookups[DC].Table.add( + Update.Mod, Update.Data, + reader::ASTDeclContextNameLookupTrait(*this, *Update.Mod)); + DC->setHasExternalVisibleStorage(true); + } + // The declaration may have been modified by files later in the chain. // If this is the case, read the record containing the updates from each file // and pass it to ASTDeclReader to make the modifications. DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID); if (UpdI != DeclUpdateOffsets.end()) { - FileOffsetsTy &UpdateOffsets = UpdI->second; + auto UpdateOffsets = std::move(UpdI->second); + DeclUpdateOffsets.erase(UpdI); + bool WasInteresting = isConsumerInterestedIn(D, false); - for (FileOffsetsTy::iterator - I = UpdateOffsets.begin(), E = UpdateOffsets.end(); I != E; ++I) { - ModuleFile *F = I->first; - uint64_t Offset = I->second; + for (auto &FileAndOffset : UpdateOffsets) { + ModuleFile *F = FileAndOffset.first; + uint64_t Offset = FileAndOffset.second; llvm::BitstreamCursor &Cursor = F->DeclsCursor; SavedStreamPosition SavedPosition(Cursor); Cursor.JumpToBit(Offset); @@ -3407,154 +3403,42 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) { } } -namespace { - /// \brief Module visitor class that finds all of the redeclarations of a - /// redeclarable declaration. - class RedeclChainVisitor { - ASTReader &Reader; - SmallVectorImpl<DeclID> &SearchDecls; - llvm::SmallPtrSetImpl<Decl *> &Deserialized; - GlobalDeclID CanonID; - SmallVector<Decl *, 4> Chain; - - public: - RedeclChainVisitor(ASTReader &Reader, SmallVectorImpl<DeclID> &SearchDecls, - llvm::SmallPtrSetImpl<Decl *> &Deserialized, - GlobalDeclID CanonID) - : Reader(Reader), SearchDecls(SearchDecls), Deserialized(Deserialized), - CanonID(CanonID) { - // Ensure that the canonical ID goes at the start of the chain. - addToChain(Reader.GetDecl(CanonID)); - } - - static ModuleManager::DFSPreorderControl - visitPreorder(ModuleFile &M, void *UserData) { - return static_cast<RedeclChainVisitor *>(UserData)->visitPreorder(M); - } - - static bool visitPostorder(ModuleFile &M, void *UserData) { - return static_cast<RedeclChainVisitor *>(UserData)->visitPostorder(M); - } - - void addToChain(Decl *D) { - if (!D) - return; - - if (Deserialized.erase(D)) - Chain.push_back(D); - } - - void searchForID(ModuleFile &M, GlobalDeclID GlobalID) { - // Map global ID of the first declaration down to the local ID - // used in this module file. - DeclID ID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalID); - if (!ID) - return; - - // If the search decl was from this module, add it to the chain before any - // of its redeclarations in this module or users of it, and after any from - // imported modules. - if (CanonID != GlobalID && Reader.isDeclIDFromModule(GlobalID, M)) - addToChain(Reader.GetDecl(GlobalID)); - - // Perform a binary search to find the local redeclarations for this - // declaration (if any). - const LocalRedeclarationsInfo Compare = { ID, 0 }; - const LocalRedeclarationsInfo *Result - = std::lower_bound(M.RedeclarationsMap, - M.RedeclarationsMap + M.LocalNumRedeclarationsInMap, - Compare); - if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap || - Result->FirstID != ID) - return; - - // Dig out all of the redeclarations. - unsigned Offset = Result->Offset; - unsigned N = M.RedeclarationChains[Offset]; - M.RedeclarationChains[Offset++] = 0; // Don't try to deserialize again - for (unsigned I = 0; I != N; ++I) - addToChain(Reader.GetLocalDecl(M, M.RedeclarationChains[Offset++])); - } - - bool needsToVisitImports(ModuleFile &M, GlobalDeclID GlobalID) { - DeclID ID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalID); - if (!ID) - return false; - - const LocalRedeclarationsInfo Compare = {ID, 0}; - const LocalRedeclarationsInfo *Result = std::lower_bound( - M.RedeclarationsMap, - M.RedeclarationsMap + M.LocalNumRedeclarationsInMap, Compare); - if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap || - Result->FirstID != ID) { - return true; - } - unsigned Offset = Result->Offset; - unsigned N = M.RedeclarationChains[Offset]; - // We don't need to visit a module or any of its imports if we've already - // deserialized the redecls from this module. - return N != 0; - } +void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) { + // Attach FirstLocal to the end of the decl chain. + Decl *CanonDecl = FirstLocal->getCanonicalDecl(); + if (FirstLocal != CanonDecl) { + Decl *PrevMostRecent = ASTDeclReader::getMostRecentDecl(CanonDecl); + ASTDeclReader::attachPreviousDecl( + *this, FirstLocal, PrevMostRecent ? PrevMostRecent : CanonDecl, + CanonDecl); + } - ModuleManager::DFSPreorderControl visitPreorder(ModuleFile &M) { - for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I) { - if (needsToVisitImports(M, SearchDecls[I])) - return ModuleManager::Continue; - } - return ModuleManager::SkipImports; - } + if (!LocalOffset) { + ASTDeclReader::attachLatestDecl(CanonDecl, FirstLocal); + return; + } - bool visitPostorder(ModuleFile &M) { - // Visit each of the declarations. - for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I) - searchForID(M, SearchDecls[I]); - return false; - } - - ArrayRef<Decl *> getChain() const { - return Chain; - } - }; -} + // Load the list of other redeclarations from this module file. + ModuleFile *M = getOwningModuleFile(FirstLocal); + assert(M && "imported decl from no module file"); -void ASTReader::loadPendingDeclChain(Decl *CanonDecl) { - // The decl might have been merged into something else after being added to - // our list. If it was, just skip it. - if (!CanonDecl->isCanonicalDecl()) - return; + llvm::BitstreamCursor &Cursor = M->DeclsCursor; + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(LocalOffset); - // Determine the set of declaration IDs we'll be searching for. - SmallVector<DeclID, 16> SearchDecls; - GlobalDeclID CanonID = CanonDecl->getGlobalID(); - if (CanonID) - SearchDecls.push_back(CanonDecl->getGlobalID()); // Always first. - KeyDeclsMap::iterator KeyPos = KeyDecls.find(CanonDecl); - if (KeyPos != KeyDecls.end()) - SearchDecls.append(KeyPos->second.begin(), KeyPos->second.end()); - - // Build up the list of redeclarations. - RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID); - ModuleMgr.visitDepthFirst(&RedeclChainVisitor::visitPreorder, - &RedeclChainVisitor::visitPostorder, &Visitor); - - // Retrieve the chains. - ArrayRef<Decl *> Chain = Visitor.getChain(); - if (Chain.empty() || (Chain.size() == 1 && Chain[0] == CanonDecl)) - return; + RecordData Record; + unsigned Code = Cursor.ReadCode(); + unsigned RecCode = Cursor.readRecord(Code, Record); + (void)RecCode; + assert(RecCode == LOCAL_REDECLARATIONS && "expected LOCAL_REDECLARATIONS record!"); - // Hook up the chains. - // - // FIXME: We have three different dispatches on decl kind here; maybe + // FIXME: We have several different dispatches on decl kind here; maybe // we should instead generate one loop per kind and dispatch up-front? - Decl *MostRecent = ASTDeclReader::getMostRecentDecl(CanonDecl); - if (!MostRecent) - MostRecent = CanonDecl; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - if (Chain[I] == CanonDecl) - continue; - - ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent, CanonDecl); - MostRecent = Chain[I]; + Decl *MostRecent = FirstLocal; + for (unsigned I = 0, N = Record.size(); I != N; ++I) { + auto *D = GetLocalDecl(*M, Record[N - I - 1]); + ASTDeclReader::attachPreviousDecl(*this, D, MostRecent, CanonDecl); + MostRecent = D; } ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent); } @@ -3630,11 +3514,7 @@ namespace { } } - static bool visit(ModuleFile &M, void *UserData) { - return static_cast<ObjCCategoriesVisitor *>(UserData)->visit(M); - } - - bool visit(ModuleFile &M) { + bool operator()(ModuleFile &M) { // If we've loaded all of the category information we care about from // this module file, we're done. if (M.Generation <= PreviousGeneration) @@ -3672,14 +3552,14 @@ namespace { return true; } }; -} +} // end anonymous namespace void ASTReader::loadObjCCategories(serialization::GlobalDeclID ID, ObjCInterfaceDecl *D, unsigned PreviousGeneration) { ObjCCategoriesVisitor Visitor(*this, ID, D, CategoriesDeserialized, PreviousGeneration); - ModuleMgr.visit(ObjCCategoriesVisitor::visit, &Visitor); + ModuleMgr.visit(Visitor); } template<typename DeclT, typename Fn> @@ -3716,17 +3596,6 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile, // FIXME: We should call addHiddenDecl instead, to add the member // to its DeclContext. RD->addedMember(MD); - - // If we've added a new special member to a class definition that is not - // the canonical definition, then we need special member lookups in the - // canonical definition to also look into our class. - auto *DD = RD->DefinitionData.getNotUpdated(); - if (DD && DD->Definition != RD) { - auto &Merged = Reader.MergedLookups[DD->Definition]; - // FIXME: Avoid the linear-time scan here. - if (std::find(Merged.begin(), Merged.end(), RD) == Merged.end()) - Merged.push_back(RD); - } break; } @@ -3798,10 +3667,8 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile, // Visible update is handled separately. uint64_t LexicalOffset = Record[Idx++]; if (!HadRealDefinition && LexicalOffset) { - RD->setHasExternalLexicalStorage(true); - Reader.ReadDeclContextStorage(ModuleFile, ModuleFile.DeclsCursor, - std::make_pair(LexicalOffset, 0), - ModuleFile.DeclContextInfos[RD]); + Reader.ReadLexicalDeclContextStorage(ModuleFile, ModuleFile.DeclsCursor, + LexicalOffset, RD); Reader.PendingFakeDefinitionData.erase(OldDD); } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h index 5b1c4f4963e4..d392364a971b 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h @@ -15,8 +15,12 @@ #include "clang/AST/DeclarationName.h" #include "clang/Serialization/ASTBitCodes.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/Endian.h" #include "llvm/Support/OnDiskHashTable.h" +#include "MultiOnDiskHashTable.h" #include <utility> namespace clang { @@ -39,45 +43,86 @@ class ASTDeclContextNameLookupTrait { ModuleFile &F; public: - /// \brief Pair of begin/end iterators for DeclIDs. - /// - /// Note that these declaration IDs are local to the module that contains this - /// particular lookup t - typedef llvm::support::ulittle32_t LE32DeclID; - typedef std::pair<LE32DeclID *, LE32DeclID *> data_type; - typedef unsigned hash_value_type; - typedef unsigned offset_type; + // Maximum number of lookup tables we allow before condensing the tables. + static const int MaxTables = 4; + + /// The lookup result is a list of global declaration IDs. + typedef llvm::SmallVector<DeclID, 4> data_type; + struct data_type_builder { + data_type &Data; + llvm::DenseSet<DeclID> Found; - /// \brief Special internal key for declaration names. - /// The hash table creates keys for comparison; we do not create - /// a DeclarationName for the internal key to avoid deserializing types. - struct DeclNameKey { - DeclarationName::NameKind Kind; - uint64_t Data; - DeclNameKey() : Kind((DeclarationName::NameKind)0), Data(0) { } + data_type_builder(data_type &D) : Data(D) {} + void insert(DeclID ID) { + // Just use a linear scan unless we have more than a few IDs. + if (Found.empty() && !Data.empty()) { + if (Data.size() <= 4) { + for (auto I : Found) + if (I == ID) + return; + Data.push_back(ID); + return; + } + + // Switch to tracking found IDs in the set. + Found.insert(Data.begin(), Data.end()); + } + + if (Found.insert(ID).second) + Data.push_back(ID); + } }; + typedef unsigned hash_value_type; + typedef unsigned offset_type; + typedef ModuleFile *file_type; typedef DeclarationName external_key_type; - typedef DeclNameKey internal_key_type; + typedef DeclarationNameKey internal_key_type; explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, ModuleFile &F) : Reader(Reader), F(F) { } - static bool EqualKey(const internal_key_type& a, - const internal_key_type& b) { - return a.Kind == b.Kind && a.Data == b.Data; + static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { + return a == b; } - static hash_value_type ComputeHash(const DeclNameKey &Key); - static internal_key_type GetInternalKey(const external_key_type& Name); + static hash_value_type ComputeHash(const internal_key_type &Key) { + return Key.getHash(); + } + static internal_key_type GetInternalKey(const external_key_type &Name) { + return Name; + } static std::pair<unsigned, unsigned> - ReadKeyDataLength(const unsigned char*& d); + ReadKeyDataLength(const unsigned char *&d); - internal_key_type ReadKey(const unsigned char* d, unsigned); + internal_key_type ReadKey(const unsigned char *d, unsigned); - data_type ReadData(internal_key_type, const unsigned char* d, - unsigned DataLen); + void ReadDataInto(internal_key_type, const unsigned char *d, + unsigned DataLen, data_type_builder &Val); + + static void MergeDataInto(const data_type &From, data_type_builder &To) { + To.Data.reserve(To.Data.size() + From.size()); + for (DeclID ID : From) + To.insert(ID); + } + + file_type ReadFileRef(const unsigned char *&d); +}; + +struct DeclContextLookupTable { + MultiOnDiskHashTable<ASTDeclContextNameLookupTrait> Table; + + // These look redundant, but don't remove them -- they work around MSVC 2013's + // inability to synthesize move operations. Without them, the + // MultiOnDiskHashTable will be copied (despite being move-only!). + DeclContextLookupTable() : Table() {} + DeclContextLookupTable(DeclContextLookupTable &&O) + : Table(std::move(O.Table)) {} + DeclContextLookupTable &operator=(DeclContextLookupTable &&O) { + Table = std::move(O.Table); + return *this; + } }; /// \brief Base class for the trait describing the on-disk hash table for the @@ -137,6 +182,8 @@ public: const unsigned char* d, unsigned DataLen); + IdentID ReadIdentifierID(const unsigned char *d); + ASTReader &getReader() const { return Reader; } }; @@ -226,7 +273,7 @@ public: : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) { } static hash_value_type ComputeHash(internal_key_ref ikey); - static internal_key_type GetInternalKey(const FileEntry *FE); + internal_key_type GetInternalKey(const FileEntry *FE); bool EqualKey(internal_key_ref a, internal_key_ref b); static std::pair<unsigned, unsigned> diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp index 76e8334695f7..4082dec48c0a 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp @@ -93,6 +93,7 @@ namespace clang { /// \brief Read and initialize a ExplicitTemplateArgumentList structure. void ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args, + TemplateArgumentLoc *ArgsLocArray, unsigned NumTemplateArgs); /// \brief Read and initialize a ExplicitTemplateArgumentList structure. void ReadExplicitTemplateArgumentList(ASTTemplateArgumentListInfo &ArgList, @@ -105,9 +106,9 @@ namespace clang { }; } -void ASTStmtReader:: -ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args, - unsigned NumTemplateArgs) { +void ASTStmtReader::ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args, + TemplateArgumentLoc *ArgsLocArray, + unsigned NumTemplateArgs) { SourceLocation TemplateKWLoc = ReadSourceLocation(Record, Idx); TemplateArgumentListInfo ArgInfo; ArgInfo.setLAngleLoc(ReadSourceLocation(Record, Idx)); @@ -115,7 +116,7 @@ ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args, for (unsigned i = 0; i != NumTemplateArgs; ++i) ArgInfo.addArgument( Reader.ReadTemplateArgumentLoc(F, Record, Idx)); - Args.initializeFrom(TemplateKWLoc, ArgInfo); + Args.initializeFrom(TemplateKWLoc, ArgInfo, ArgsLocArray); } void ASTStmtReader::VisitStmt(Stmt *S) { @@ -134,7 +135,7 @@ void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) { unsigned NumStmts = Record[Idx++]; while (NumStmts--) Stmts.push_back(Reader.ReadSubStmt()); - S->setStmts(Reader.getContext(), Stmts.data(), Stmts.size()); + S->setStmts(Reader.getContext(), Stmts); S->LBraceLoc = ReadSourceLocation(Record, Idx); S->RBraceLoc = ReadSourceLocation(Record, Idx); } @@ -381,6 +382,26 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) { Constraints, Exprs, Clobbers); } +void ASTStmtReader::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtReader::VisitCoreturnStmt(CoreturnStmt *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); ++Idx; @@ -439,15 +460,17 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { NumTemplateArgs = Record[Idx++]; if (E->hasQualifier()) - E->getInternalQualifierLoc() - = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); + new (E->getTrailingObjects<NestedNameSpecifierLoc>()) + NestedNameSpecifierLoc( + Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); if (E->hasFoundDecl()) - E->getInternalFoundDecl() = ReadDeclAs<NamedDecl>(Record, Idx); + *E->getTrailingObjects<NamedDecl *>() = ReadDeclAs<NamedDecl>(Record, Idx); if (E->hasTemplateKWAndArgsInfo()) - ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(), - NumTemplateArgs); + ReadTemplateKWAndArgsInfo( + *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), + E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs); E->setDecl(ReadDeclAs<ValueDecl>(Record, Idx)); E->setLocation(ReadSourceLocation(Record, Idx)); @@ -527,7 +550,6 @@ void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) { } void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { - typedef OffsetOfExpr::OffsetOfNode Node; VisitExpr(E); assert(E->getNumComponents() == Record[Idx]); ++Idx; @@ -537,29 +559,29 @@ void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { E->setRParenLoc(ReadSourceLocation(Record, Idx)); E->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx)); for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { - Node::Kind Kind = static_cast<Node::Kind>(Record[Idx++]); + OffsetOfNode::Kind Kind = static_cast<OffsetOfNode::Kind>(Record[Idx++]); SourceLocation Start = ReadSourceLocation(Record, Idx); SourceLocation End = ReadSourceLocation(Record, Idx); switch (Kind) { - case Node::Array: - E->setComponent(I, Node(Start, Record[Idx++], End)); + case OffsetOfNode::Array: + E->setComponent(I, OffsetOfNode(Start, Record[Idx++], End)); break; - - case Node::Field: - E->setComponent(I, Node(Start, ReadDeclAs<FieldDecl>(Record, Idx), End)); + + case OffsetOfNode::Field: + E->setComponent( + I, OffsetOfNode(Start, ReadDeclAs<FieldDecl>(Record, Idx), End)); break; - case Node::Identifier: - E->setComponent(I, - Node(Start, - Reader.GetIdentifierInfo(F, Record, Idx), - End)); + case OffsetOfNode::Identifier: + E->setComponent( + I, + OffsetOfNode(Start, Reader.GetIdentifierInfo(F, Record, Idx), End)); break; - - case Node::Base: { + + case OffsetOfNode::Base: { CXXBaseSpecifier *Base = new (Reader.getContext()) CXXBaseSpecifier(); *Base = Reader.ReadCXXBaseSpecifier(F, Record, Idx); - E->setComponent(I, Node(Base)); + E->setComponent(I, OffsetOfNode(Base)); break; } } @@ -589,6 +611,15 @@ void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { E->setRBracketLoc(ReadSourceLocation(Record, Idx)); } +void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { + VisitExpr(E); + E->setBase(Reader.ReadSubExpr()); + E->setLowerBound(Reader.ReadSubExpr()); + E->setLength(Reader.ReadSubExpr()); + E->setColonLoc(ReadSourceLocation(Record, Idx)); + E->setRBracketLoc(ReadSourceLocation(Record, Idx)); +} + void ASTStmtReader::VisitCallExpr(CallExpr *E) { VisitExpr(E); E->setNumArgs(Reader.getContext(), Record[Idx++]); @@ -821,6 +852,7 @@ void ASTStmtReader::VisitVAArgExpr(VAArgExpr *E) { E->setWrittenTypeInfo(GetTypeSourceInfo(Record, Idx)); E->setBuiltinLoc(ReadSourceLocation(Record, Idx)); E->setRParenLoc(ReadSourceLocation(Record, Idx)); + E->setIsMicrosoftABI(Record[Idx++]); } void ASTStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) { @@ -1168,9 +1200,10 @@ void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) { void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) { VisitStmt(S); - S->setForLoc(ReadSourceLocation(Record, Idx)); - S->setColonLoc(ReadSourceLocation(Record, Idx)); - S->setRParenLoc(ReadSourceLocation(Record, Idx)); + S->ForLoc = ReadSourceLocation(Record, Idx); + S->CoawaitLoc = ReadSourceLocation(Record, Idx); + S->ColonLoc = ReadSourceLocation(Record, Idx); + S->RParenLoc = ReadSourceLocation(Record, Idx); S->setRangeStmt(Reader.ReadSubStmt()); S->setBeginEndStmt(Reader.ReadSubStmt()); S->setCond(Reader.ReadSubExpr()); @@ -1422,8 +1455,10 @@ ASTStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ VisitExpr(E); if (Record[Idx++]) // HasTemplateKWAndArgsInfo - ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(), - /*NumTemplateArgs=*/Record[Idx++]); + ReadTemplateKWAndArgsInfo( + *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), + E->getTrailingObjects<TemplateArgumentLoc>(), + /*NumTemplateArgs=*/Record[Idx++]); E->Base = Reader.ReadSubExpr(); E->BaseType = Reader.readType(F, Record, Idx); @@ -1439,8 +1474,10 @@ ASTStmtReader::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { VisitExpr(E); if (Record[Idx++]) // HasTemplateKWAndArgsInfo - ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(), - /*NumTemplateArgs=*/Record[Idx++]); + ReadTemplateKWAndArgsInfo( + *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), + E->getTrailingObjects<TemplateArgumentLoc>(), + /*NumTemplateArgs=*/Record[Idx++]); E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); ReadDeclarationNameInfo(E->NameInfo, Record, Idx); @@ -1462,7 +1499,8 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) { VisitExpr(E); if (Record[Idx++]) // HasTemplateKWAndArgsInfo - ReadTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo(), + ReadTemplateKWAndArgsInfo(*E->getTrailingASTTemplateKWAndArgsInfo(), + E->getTrailingTemplateArgumentLoc(), /*NumTemplateArgs=*/Record[Idx++]); unsigned NumDecls = Record[Idx++]; @@ -1544,11 +1582,20 @@ void ASTStmtReader::VisitPackExpansionExpr(PackExpansionExpr *E) { void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) { VisitExpr(E); + unsigned NumPartialArgs = Record[Idx++]; E->OperatorLoc = ReadSourceLocation(Record, Idx); E->PackLoc = ReadSourceLocation(Record, Idx); E->RParenLoc = ReadSourceLocation(Record, Idx); - E->Length = Record[Idx++]; - E->Pack = ReadDeclAs<NamedDecl>(Record, Idx); + E->Pack = Reader.ReadDeclAs<NamedDecl>(F, Record, Idx); + if (E->isPartiallySubstituted()) { + assert(E->Length == NumPartialArgs); + for (auto *I = reinterpret_cast<TemplateArgument *>(E + 1), + *E = I + NumPartialArgs; + I != E; ++I) + new (I) TemplateArgument(Reader.ReadTemplateArgument(F, Record, Idx)); + } else if (!E->isValueDependent()) { + E->Length = Record[Idx++]; + } } void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr( @@ -1622,6 +1669,13 @@ void ASTStmtReader::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { E->TheDecl = ReadDeclAs<MSPropertyDecl>(Record, Idx); } +void ASTStmtReader::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) { + VisitExpr(E); + E->setBase(Reader.ReadSubExpr()); + E->setIdx(Reader.ReadSubExpr()); + E->setRBracketLoc(ReadSourceLocation(Record, Idx)); +} + void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); E->setSourceRange(ReadSourceRange(Record, Idx)); @@ -1716,6 +1770,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_safelen: C = new (Context) OMPSafelenClause(); break; + case OMPC_simdlen: + C = new (Context) OMPSimdlenClause(); + break; case OMPC_collapse: C = new (Context) OMPCollapseClause(); break; @@ -1755,6 +1812,15 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_seq_cst: C = new (Context) OMPSeqCstClause(); break; + case OMPC_threads: + C = new (Context) OMPThreadsClause(); + break; + case OMPC_simd: + C = new (Context) OMPSIMDClause(); + break; + case OMPC_nogroup: + C = new (Context) OMPNogroupClause(); + break; case OMPC_private: C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]); break; @@ -1788,6 +1854,30 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_depend: C = OMPDependClause::CreateEmpty(Context, Record[Idx++]); break; + case OMPC_device: + C = new (Context) OMPDeviceClause(); + break; + case OMPC_map: + C = OMPMapClause::CreateEmpty(Context, Record[Idx++]); + break; + case OMPC_num_teams: + C = new (Context) OMPNumTeamsClause(); + break; + case OMPC_thread_limit: + C = new (Context) OMPThreadLimitClause(); + break; + case OMPC_priority: + C = new (Context) OMPPriorityClause(); + break; + case OMPC_grainsize: + C = new (Context) OMPGrainsizeClause(); + break; + case OMPC_num_tasks: + C = new (Context) OMPNumTasksClause(); + break; + case OMPC_hint: + C = new (Context) OMPHintClause(); + break; } Visit(C); C->setLocStart(Reader->ReadSourceLocation(Record, Idx)); @@ -1797,6 +1887,9 @@ OMPClause *OMPClauseReader::readClause() { } void OMPClauseReader::VisitOMPIfClause(OMPIfClause *C) { + C->setNameModifier(static_cast<OpenMPDirectiveKind>(Record[Idx++])); + C->setNameModifierLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setColonLoc(Reader->ReadSourceLocation(Record, Idx)); C->setCondition(Reader->Reader.ReadSubExpr()); C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); } @@ -1816,6 +1909,11 @@ void OMPClauseReader::VisitOMPSafelenClause(OMPSafelenClause *C) { C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); } +void OMPClauseReader::VisitOMPSimdlenClause(OMPSimdlenClause *C) { + C->setSimdlen(Reader->Reader.ReadSubExpr()); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); +} + void OMPClauseReader::VisitOMPCollapseClause(OMPCollapseClause *C) { C->setNumForLoops(Reader->Reader.ReadSubExpr()); C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); @@ -1838,14 +1936,23 @@ void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) { void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) { C->setScheduleKind( static_cast<OpenMPScheduleClauseKind>(Record[Idx++])); + C->setFirstScheduleModifier( + static_cast<OpenMPScheduleClauseModifier>(Record[Idx++])); + C->setSecondScheduleModifier( + static_cast<OpenMPScheduleClauseModifier>(Record[Idx++])); C->setChunkSize(Reader->Reader.ReadSubExpr()); C->setHelperChunkSize(Reader->Reader.ReadSubExpr()); C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setFirstScheduleModifierLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setSecondScheduleModifierLoc(Reader->ReadSourceLocation(Record, Idx)); C->setScheduleKindLoc(Reader->ReadSourceLocation(Record, Idx)); C->setCommaLoc(Reader->ReadSourceLocation(Record, Idx)); } -void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *) {} +void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *C) { + C->setNumForLoops(Reader->Reader.ReadSubExpr()); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); +} void OMPClauseReader::VisitOMPNowaitClause(OMPNowaitClause *) {} @@ -1863,6 +1970,12 @@ void OMPClauseReader::VisitOMPCaptureClause(OMPCaptureClause *) {} void OMPClauseReader::VisitOMPSeqCstClause(OMPSeqCstClause *) {} +void OMPClauseReader::VisitOMPThreadsClause(OMPThreadsClause *) {} + +void OMPClauseReader::VisitOMPSIMDClause(OMPSIMDClause *) {} + +void OMPClauseReader::VisitOMPNogroupClause(OMPNogroupClause *) {} + void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) { C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); unsigned NumVars = C->varlist_size(); @@ -1950,6 +2063,10 @@ void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) { Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setPrivates(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); C->setLHSExprs(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) @@ -1964,6 +2081,8 @@ void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) { void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) { C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); C->setColonLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setModifier(static_cast<OpenMPLinearClauseKind>(Record[Idx++])); + C->setModifierLoc(Reader->ReadSourceLocation(Record, Idx)); unsigned NumVars = C->varlist_size(); SmallVector<Expr *, 16> Vars; Vars.reserve(NumVars); @@ -1973,6 +2092,10 @@ void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) { Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setPrivates(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); C->setInits(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) @@ -2065,6 +2188,58 @@ void OMPClauseReader::VisitOMPDependClause(OMPDependClause *C) { C->setVarRefs(Vars); } +void OMPClauseReader::VisitOMPDeviceClause(OMPDeviceClause *C) { + C->setDevice(Reader->Reader.ReadSubExpr()); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); +} + +void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) { + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setMapTypeModifier( + static_cast<OpenMPMapClauseKind>(Record[Idx++])); + C->setMapType( + static_cast<OpenMPMapClauseKind>(Record[Idx++])); + C->setMapLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setColonLoc(Reader->ReadSourceLocation(Record, Idx)); + auto NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) { + Vars.push_back(Reader->Reader.ReadSubExpr()); + } + C->setVarRefs(Vars); +} + +void OMPClauseReader::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) { + C->setNumTeams(Reader->Reader.ReadSubExpr()); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); +} + +void OMPClauseReader::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) { + C->setThreadLimit(Reader->Reader.ReadSubExpr()); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); +} + +void OMPClauseReader::VisitOMPPriorityClause(OMPPriorityClause *C) { + C->setPriority(Reader->Reader.ReadSubExpr()); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); +} + +void OMPClauseReader::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) { + C->setGrainsize(Reader->Reader.ReadSubExpr()); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); +} + +void OMPClauseReader::VisitOMPNumTasksClause(OMPNumTasksClause *C) { + C->setNumTasks(Reader->Reader.ReadSubExpr()); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); +} + +void OMPClauseReader::VisitOMPHintClause(OMPHintClause *C) { + C->setHint(Reader->Reader.ReadSubExpr()); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); +} + //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// @@ -2110,6 +2285,10 @@ void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) { Sub.clear(); for (unsigned i = 0; i < CollapsedNum; ++i) Sub.push_back(Reader.ReadSubExpr()); + D->setPrivateCounters(Sub); + Sub.clear(); + for (unsigned i = 0; i < CollapsedNum; ++i) + Sub.push_back(Reader.ReadSubExpr()); D->setInits(Sub); Sub.clear(); for (unsigned i = 0; i < CollapsedNum; ++i) @@ -2126,6 +2305,7 @@ void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) { // The NumClauses field was read in ReadStmtFromStream. ++Idx; VisitOMPExecutableDirective(D); + D->setHasCancel(Record[Idx++]); } void ASTStmtReader::VisitOMPSimdDirective(OMPSimdDirective *D) { @@ -2134,6 +2314,7 @@ void ASTStmtReader::VisitOMPSimdDirective(OMPSimdDirective *D) { void ASTStmtReader::VisitOMPForDirective(OMPForDirective *D) { VisitOMPLoopDirective(D); + D->setHasCancel(Record[Idx++]); } void ASTStmtReader::VisitOMPForSimdDirective(OMPForSimdDirective *D) { @@ -2145,11 +2326,13 @@ void ASTStmtReader::VisitOMPSectionsDirective(OMPSectionsDirective *D) { // The NumClauses field was read in ReadStmtFromStream. ++Idx; VisitOMPExecutableDirective(D); + D->setHasCancel(Record[Idx++]); } void ASTStmtReader::VisitOMPSectionDirective(OMPSectionDirective *D) { VisitStmt(D); VisitOMPExecutableDirective(D); + D->setHasCancel(Record[Idx++]); } void ASTStmtReader::VisitOMPSingleDirective(OMPSingleDirective *D) { @@ -2166,12 +2349,15 @@ void ASTStmtReader::VisitOMPMasterDirective(OMPMasterDirective *D) { void ASTStmtReader::VisitOMPCriticalDirective(OMPCriticalDirective *D) { VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + ++Idx; VisitOMPExecutableDirective(D); ReadDeclarationNameInfo(D->DirName, Record, Idx); } void ASTStmtReader::VisitOMPParallelForDirective(OMPParallelForDirective *D) { VisitOMPLoopDirective(D); + D->setHasCancel(Record[Idx++]); } void ASTStmtReader::VisitOMPParallelForSimdDirective( @@ -2185,6 +2371,7 @@ void ASTStmtReader::VisitOMPParallelSectionsDirective( // The NumClauses field was read in ReadStmtFromStream. ++Idx; VisitOMPExecutableDirective(D); + D->setHasCancel(Record[Idx++]); } void ASTStmtReader::VisitOMPTaskDirective(OMPTaskDirective *D) { @@ -2192,6 +2379,7 @@ void ASTStmtReader::VisitOMPTaskDirective(OMPTaskDirective *D) { // The NumClauses field was read in ReadStmtFromStream. ++Idx; VisitOMPExecutableDirective(D); + D->setHasCancel(Record[Idx++]); } void ASTStmtReader::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *D) { @@ -2223,6 +2411,8 @@ void ASTStmtReader::VisitOMPFlushDirective(OMPFlushDirective *D) { void ASTStmtReader::VisitOMPOrderedDirective(OMPOrderedDirective *D) { VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + ++Idx; VisitOMPExecutableDirective(D); } @@ -2246,6 +2436,12 @@ void ASTStmtReader::VisitOMPTargetDirective(OMPTargetDirective *D) { VisitOMPExecutableDirective(D); } +void ASTStmtReader::VisitOMPTargetDataDirective(OMPTargetDataDirective *D) { + VisitStmt(D); + ++Idx; + VisitOMPExecutableDirective(D); +} + void ASTStmtReader::VisitOMPTeamsDirective(OMPTeamsDirective *D) { VisitStmt(D); // The NumClauses field was read in ReadStmtFromStream. @@ -2262,10 +2458,24 @@ void ASTStmtReader::VisitOMPCancellationPointDirective( void ASTStmtReader::VisitOMPCancelDirective(OMPCancelDirective *D) { VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + ++Idx; VisitOMPExecutableDirective(D); D->setCancelRegion(static_cast<OpenMPDirectiveKind>(Record[Idx++])); } +void ASTStmtReader::VisitOMPTaskLoopDirective(OMPTaskLoopDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPTaskLoopSimdDirective(OMPTaskLoopSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void ASTStmtReader::VisitOMPDistributeDirective(OMPDistributeDirective *D) { + VisitOMPLoopDirective(D); +} + //===----------------------------------------------------------------------===// // ASTReader Implementation //===----------------------------------------------------------------------===// @@ -2497,6 +2707,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) ArraySubscriptExpr(Empty); break; + case EXPR_OMP_ARRAY_SECTION: + S = new (Context) OMPArraySectionExpr(Empty); + break; + case EXPR_CALL: S = new (Context) CallExpr(Context, Stmt::CallExprClass, Empty); break; @@ -2800,7 +3014,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; case STMT_OMP_CRITICAL_DIRECTIVE: - S = OMPCriticalDirective::CreateEmpty(Context, Empty); + S = OMPCriticalDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); break; case STMT_OMP_PARALLEL_FOR_DIRECTIVE: { @@ -2851,7 +3066,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; case STMT_OMP_ORDERED_DIRECTIVE: - S = OMPOrderedDirective::CreateEmpty(Context, Empty); + S = OMPOrderedDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); break; case STMT_OMP_ATOMIC_DIRECTIVE: @@ -2864,6 +3080,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { Context, Record[ASTStmtReader::NumStmtFields], Empty); break; + case STMT_OMP_TARGET_DATA_DIRECTIVE: + S = OMPTargetDataDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_TEAMS_DIRECTIVE: S = OMPTeamsDirective::CreateEmpty( Context, Record[ASTStmtReader::NumStmtFields], Empty); @@ -2874,9 +3095,34 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; case STMT_OMP_CANCEL_DIRECTIVE: - S = OMPCancelDirective::CreateEmpty(Context, Empty); + S = OMPCancelDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); break; + case STMT_OMP_TASKLOOP_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTaskLoopDirective::CreateEmpty(Context, NumClauses, CollapsedNum, + Empty); + break; + } + + case STMT_OMP_TASKLOOP_SIMD_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPTaskLoopSimdDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, Empty); + break; + } + + case STMT_OMP_DISTRIBUTE_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPDistributeDirective::CreateEmpty(Context, NumClauses, CollapsedNum, + Empty); + break; + } + case EXPR_CXX_OPERATOR_CALL: S = new (Context) CXXOperatorCallExpr(Context, Empty); break; @@ -2944,6 +3190,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case EXPR_CXX_PROPERTY_REF_EXPR: S = new (Context) MSPropertyRefExpr(Empty); break; + case EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR: + S = new (Context) MSPropertySubscriptExpr(Empty); + break; case EXPR_CXX_UUIDOF_TYPE: S = new (Context) CXXUuidofExpr(Empty, false); break; @@ -3047,7 +3296,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; case EXPR_SIZEOF_PACK: - S = new (Context) SizeOfPackExpr(Empty); + S = SizeOfPackExpr::CreateDeserialized( + Context, + /*NumPartialArgs=*/Record[ASTStmtReader::NumExprFields]); break; case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM: diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp index 8b6863822c69..128935c5c73b 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp @@ -1,4 +1,4 @@ -//===--- ASTWriter.cpp - AST File Writer ----------------------------------===// +//===--- ASTWriter.cpp - AST File Writer ------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,7 +12,10 @@ //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTWriter.h" +#include "clang/Serialization/ModuleFileExtension.h" #include "ASTCommon.h" +#include "ASTReaderInternals.h" +#include "MultiOnDiskHashTable.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclContextInternals.h" @@ -41,6 +44,7 @@ #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/Sema.h" #include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/SerializationDiagnostic.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/Hashing.h" @@ -56,6 +60,7 @@ #include <cstdio> #include <string.h> #include <utility> + using namespace clang; using namespace clang::serialization; @@ -98,7 +103,7 @@ namespace { #define ABSTRACT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" }; -} +} // end anonymous namespace void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) { llvm_unreachable("Built-in types are never serialized"); @@ -277,7 +282,7 @@ void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) { void ASTTypeWriter::VisitAutoType(const AutoType *T) { Writer.AddTypeRef(T->getDeducedType(), Record); - Record.push_back(T->isDecltypeAuto()); + Record.push_back((unsigned)T->getKeyword()); if (T->getDeducedType().isNull()) Record.push_back(T->isDependentType()); Code = TYPE_AUTO; @@ -329,9 +334,8 @@ ASTTypeWriter::VisitTemplateSpecializationType( Record.push_back(T->isDependentType()); Writer.AddTemplateName(T->getTemplateName(), Record); Record.push_back(T->getNumArgs()); - for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end(); - ArgI != ArgE; ++ArgI) - Writer.AddTemplateArgument(*ArgI, Record); + for (const auto &ArgI : *T) + Writer.AddTemplateArgument(ArgI, Record); Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() : T->isCanonicalUnqualified() ? QualType() : T->getCanonicalTypeInternal(), @@ -381,9 +385,8 @@ ASTTypeWriter::VisitDependentTemplateSpecializationType( Writer.AddNestedNameSpecifier(T->getQualifier(), Record); Writer.AddIdentifierRef(T->getIdentifier(), Record); Record.push_back(T->getNumArgs()); - for (DependentTemplateSpecializationType::iterator - I = T->begin(), E = T->end(); I != E; ++I) - Writer.AddTemplateArgument(*I, Record); + for (const auto &I : *T) + Writer.AddTemplateArgument(I, Record); Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION; } @@ -462,7 +465,7 @@ public: void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc); }; -} +} // end anonymous namespace void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { // nothing to do @@ -875,15 +878,17 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(METADATA); RECORD(SIGNATURE); RECORD(MODULE_NAME); + RECORD(MODULE_DIRECTORY); RECORD(MODULE_MAP_FILE); RECORD(IMPORTS); - RECORD(KNOWN_MODULE_FILES); - RECORD(LANGUAGE_OPTIONS); - RECORD(TARGET_OPTIONS); RECORD(ORIGINAL_FILE); RECORD(ORIGINAL_PCH_DIR); RECORD(ORIGINAL_FILE_ID); RECORD(INPUT_FILE_OFFSETS); + + BLOCK(OPTIONS_BLOCK); + RECORD(LANGUAGE_OPTIONS); + RECORD(TARGET_OPTIONS); RECORD(DIAGNOSTIC_OPTIONS); RECORD(FILE_SYSTEM_OPTIONS); RECORD(HEADER_SEARCH_OPTIONS); @@ -902,17 +907,17 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(SPECIAL_TYPES); RECORD(STATISTICS); RECORD(TENTATIVE_DEFINITIONS); - RECORD(UNUSED_FILESCOPED_DECLS); RECORD(SELECTOR_OFFSETS); RECORD(METHOD_POOL); RECORD(PP_COUNTER_VALUE); RECORD(SOURCE_LOCATION_OFFSETS); RECORD(SOURCE_LOCATION_PRELOADS); RECORD(EXT_VECTOR_DECLS); + RECORD(UNUSED_FILESCOPED_DECLS); RECORD(PPD_ENTITIES_OFFSETS); + RECORD(VTABLE_USES); RECORD(REFERENCED_SELECTOR_POOL); RECORD(TU_UPDATE_LEXICAL); - RECORD(LOCAL_REDECLARATIONS_MAP); RECORD(SEMA_DECL_REFS); RECORD(WEAK_UNDECLARED_IDENTIFIERS); RECORD(PENDING_IMPLICIT_INSTANTIATIONS); @@ -928,17 +933,20 @@ 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); RECORD(FILE_SORTED_DECLS); RECORD(IMPORTED_MODULES); - RECORD(LOCAL_REDECLARATIONS); RECORD(OBJC_CATEGORIES); RECORD(MACRO_OFFSET); + RECORD(INTERESTING_IDENTIFIERS); + RECORD(UNDEFINED_BUT_USED); RECORD(LATE_PARSED_TEMPLATE); RECORD(OPTIMIZE_PRAGMA_OPTIONS); + RECORD(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES); + RECORD(CXX_CTOR_INITIALIZERS_OFFSETS); + RECORD(DELETE_EXPRS_TO_ANALYZE); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); @@ -955,6 +963,29 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(PP_MODULE_MACRO); RECORD(PP_TOKEN); + // Submodule Block. + BLOCK(SUBMODULE_BLOCK); + RECORD(SUBMODULE_METADATA); + RECORD(SUBMODULE_DEFINITION); + RECORD(SUBMODULE_UMBRELLA_HEADER); + RECORD(SUBMODULE_HEADER); + RECORD(SUBMODULE_TOPHEADER); + RECORD(SUBMODULE_UMBRELLA_DIR); + RECORD(SUBMODULE_IMPORTS); + RECORD(SUBMODULE_EXPORTS); + RECORD(SUBMODULE_REQUIRES); + RECORD(SUBMODULE_EXCLUDED_HEADER); + RECORD(SUBMODULE_LINK_LIBRARY); + RECORD(SUBMODULE_CONFIG_MACRO); + RECORD(SUBMODULE_CONFLICT); + RECORD(SUBMODULE_PRIVATE_HEADER); + RECORD(SUBMODULE_TEXTUAL_HEADER); + RECORD(SUBMODULE_PRIVATE_TEXTUAL_HEADER); + + // Comments Block. + BLOCK(COMMENTS_BLOCK); + RECORD(COMMENTS_RAW_COMMENT); + // Decls and Types block. BLOCK(DECLTYPES_BLOCK); RECORD(TYPE_EXT_QUAL); @@ -998,6 +1029,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(TYPE_ATOMIC); RECORD(TYPE_DECAYED); RECORD(TYPE_ADJUSTED); + RECORD(LOCAL_REDECLARATIONS); RECORD(DECL_TYPEDEF); RECORD(DECL_TYPEALIAS); RECORD(DECL_ENUM); @@ -1062,7 +1094,11 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(PPD_MACRO_EXPANSION); RECORD(PPD_MACRO_DEFINITION); RECORD(PPD_INCLUSION_DIRECTIVE); - + + // Decls and Types block. + BLOCK(EXTENSION_BLOCK); + RECORD(EXTENSION_METADATA); + #undef RECORD #undef BLOCK Stream.ExitBlock(); @@ -1074,14 +1110,8 @@ void ASTWriter::WriteBlockInfoBlock() { /// \return \c true if the path was changed. static bool cleanPathForOutput(FileManager &FileMgr, SmallVectorImpl<char> &Path) { - bool Changed = false; - - if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) { - llvm::sys::fs::make_absolute(Path); - Changed = true; - } - - return Changed | FileMgr.removeDotPaths(Path); + bool Changed = FileMgr.makeAbsolutePath(Path); + return Changed | llvm::sys::path::remove_dots(Path); } /// \brief Adjusts the given filename to only write out the portion of the @@ -1140,69 +1170,78 @@ static ASTFileSignature getSignature() { } /// \brief Write the control block. -void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, - StringRef isysroot, - const std::string &OutputFile) { +uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP, + ASTContext &Context, + StringRef isysroot, + const std::string &OutputFile) { + ASTFileSignature Signature = 0; + using namespace llvm; Stream.EnterSubblock(CONTROL_BLOCK_ID, 5); RecordData Record; // Metadata - BitCodeAbbrev *MetadataAbbrev = new BitCodeAbbrev(); + auto *MetadataAbbrev = new BitCodeAbbrev(); MetadataAbbrev->Add(BitCodeAbbrevOp(METADATA)); MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Major MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Minor MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang maj. MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang min. MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable + MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Timestamps MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Errors MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag unsigned MetadataAbbrevCode = Stream.EmitAbbrev(MetadataAbbrev); - Record.push_back(METADATA); - Record.push_back(VERSION_MAJOR); - Record.push_back(VERSION_MINOR); - Record.push_back(CLANG_VERSION_MAJOR); - Record.push_back(CLANG_VERSION_MINOR); assert((!WritingModule || isysroot.empty()) && "writing module as a relocatable PCH?"); - Record.push_back(!isysroot.empty()); - Record.push_back(ASTHasCompilerErrors); - Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record, - getClangFullRepositoryVersion()); - + { + RecordData::value_type Record[] = {METADATA, VERSION_MAJOR, VERSION_MINOR, + CLANG_VERSION_MAJOR, CLANG_VERSION_MINOR, + !isysroot.empty(), IncludeTimestamps, + ASTHasCompilerErrors}; + Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record, + getClangFullRepositoryVersion()); + } if (WritingModule) { // For implicit modules we output a signature that we can use to ensure // duplicate module builds don't collide in the cache as their output order // is non-deterministic. // FIXME: Remove this when output is deterministic. if (Context.getLangOpts().ImplicitModules) { - Record.clear(); - Record.push_back(getSignature()); + Signature = getSignature(); + RecordData::value_type Record[] = {Signature}; Stream.EmitRecord(SIGNATURE, Record); } // Module name - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + auto *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); + RecordData::value_type Record[] = {MODULE_NAME}; Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name); } if (WritingModule && WritingModule->Directory) { - // Module directory. - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(MODULE_DIRECTORY)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Directory - unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); - RecordData Record; - Record.push_back(MODULE_DIRECTORY); - SmallString<128> BaseDir(WritingModule->Directory->getName()); cleanPathForOutput(Context.getSourceManager().getFileManager(), BaseDir); - Stream.EmitRecordWithBlob(AbbrevCode, Record, BaseDir); + + // If the home of the module is the current working directory, then we + // want to pick up the cwd of the build process loading the module, not + // our cwd, when we load this module. + if (!PP.getHeaderSearchInfo() + .getHeaderSearchOpts() + .ModuleMapFileHomeIsCwd || + WritingModule->Directory->getName() != StringRef(".")) { + // Module directory. + auto *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(MODULE_DIRECTORY)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Directory + unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); + + RecordData::value_type Record[] = {MODULE_DIRECTORY}; + Stream.EmitRecordWithBlob(AbbrevCode, Record, BaseDir); + } // Write out all other paths relative to the base directory if possible. BaseDirectory.assign(BaseDir.begin(), BaseDir.end()); @@ -1246,22 +1285,16 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Record.push_back((unsigned)M->Kind); // FIXME: Stable encoding AddSourceLocation(M->ImportLoc, Record); Record.push_back(M->File->getSize()); - Record.push_back(M->File->getModificationTime()); + Record.push_back(getTimestampForOutput(M->File)); Record.push_back(M->Signature); AddPath(M->FileName, Record); } Stream.EmitRecord(IMPORTS, Record); - - // Also emit a list of known module files that were not imported, - // but are made available by this module. - // FIXME: Should we also include a signature here? - Record.clear(); - for (auto *E : Mgr.getAdditionalKnownModuleFiles()) - AddPath(E->getName(), Record); - if (!Record.empty()) - Stream.EmitRecord(KNOWN_MODULE_FILES, Record); } + // Write the options block. + Stream.EnterSubblock(OPTIONS_BLOCK_ID, 4); + // Language options. Record.clear(); const LangOptions &LangOpts = Context.getLangOpts(); @@ -1285,11 +1318,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, // 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); + for (const auto &I : LangOpts.CommentOpts.BlockCommandNames) { + AddString(I, Record); } Record.push_back(LangOpts.CommentOpts.ParseAllComments); @@ -1332,8 +1362,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, // File system options. Record.clear(); - const FileSystemOptions &FSOpts - = Context.getSourceManager().getFileManager().getFileSystemOptions(); + const FileSystemOptions &FSOpts = + Context.getSourceManager().getFileManager().getFileSystemOpts(); AddString(FSOpts.WorkingDir, Record); Stream.EmitRecord(FILE_SYSTEM_OPTIONS, Record); @@ -1401,10 +1431,13 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Record.push_back(static_cast<unsigned>(PPOpts.ObjCXXARCStandardLibrary)); Stream.EmitRecord(PREPROCESSOR_OPTIONS, Record); + // Leave the options block. + Stream.ExitBlock(); + // Original file name and file ID SourceManager &SM = Context.getSourceManager(); if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { - BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev(); + auto *FileAbbrev = new BitCodeAbbrev(); FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE)); FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // File ID FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name @@ -1422,18 +1455,17 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, // Original PCH directory if (!OutputFile.empty() && OutputFile != "-") { - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(ORIGINAL_PCH_DIR)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); SmallString<128> OutputPath(OutputFile); - llvm::sys::fs::make_absolute(OutputPath); + SM.getFileManager().makeAbsolutePath(OutputPath); StringRef origDir = llvm::sys::path::parent_path(OutputPath); - RecordData Record; - Record.push_back(ORIGINAL_PCH_DIR); + RecordData::value_type Record[] = {ORIGINAL_PCH_DIR}; Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir); } @@ -1441,6 +1473,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, PP.getHeaderSearchInfo().getHeaderSearchOpts(), PP.getLangOpts().Modules); Stream.ExitBlock(); + return Signature; } namespace { @@ -1448,24 +1481,25 @@ namespace { struct InputFileEntry { const FileEntry *File; bool IsSystemFile; + bool IsTransient; bool BufferOverridden; }; -} +} // end anonymous namespace void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts, bool Modules) { using namespace llvm; Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4); - RecordData Record; - + // Create input-file abbreviation. - BitCodeAbbrev *IFAbbrev = new BitCodeAbbrev(); + auto *IFAbbrev = new BitCodeAbbrev(); IFAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE)); IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden + IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Transient IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev); @@ -1487,6 +1521,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, InputFileEntry Entry; Entry.File = Cache->OrigEntry; Entry.IsSystemFile = Cache->IsSystemFile; + Entry.IsTransient = Cache->IsTransient; Entry.BufferOverridden = Cache->BufferOverridden; if (Cache->IsSystemFile) SortedFiles.push_back(Entry); @@ -1497,10 +1532,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, unsigned UserFilesNum = 0; // Write out all of the input files. std::vector<uint64_t> InputFileOffsets; - for (std::deque<InputFileEntry>::iterator - I = SortedFiles.begin(), E = SortedFiles.end(); I != E; ++I) { - const InputFileEntry &Entry = *I; - + for (const auto &Entry : SortedFiles) { uint32_t &InputFileID = InputFileIDs[Entry.File]; if (InputFileID != 0) continue; // already recorded this file. @@ -1513,16 +1545,15 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, 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(Entry.File->getSize()); - Record.push_back(Entry.File->getModificationTime()); - - // Whether this file was overridden. - Record.push_back(Entry.BufferOverridden); + // And whether this file was overridden. + RecordData::value_type Record[] = { + INPUT_FILE, + InputFileOffsets.size(), + (uint64_t)Entry.File->getSize(), + (uint64_t)getTimestampForOutput(Entry.File), + Entry.BufferOverridden, + Entry.IsTransient}; EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName()); } @@ -1530,7 +1561,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, Stream.ExitBlock(); // Create input file offsets abbreviation. - BitCodeAbbrev *OffsetsAbbrev = new BitCodeAbbrev(); + auto *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 @@ -1539,10 +1570,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev); // Write input file offsets. - Record.clear(); - Record.push_back(INPUT_FILE_OFFSETS); - Record.push_back(InputFileOffsets.size()); - Record.push_back(UserFilesNum); + RecordData::value_type Record[] = {INPUT_FILE_OFFSETS, + InputFileOffsets.size(), UserFilesNum}; Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, bytes(InputFileOffsets)); } @@ -1554,7 +1583,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, /// file. static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location @@ -1572,7 +1602,8 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { /// buffer. static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) { using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location @@ -1586,7 +1617,8 @@ static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) { /// buffer's blob. static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) { using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_BLOB)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob return Stream.EmitAbbrev(Abbrev); @@ -1596,7 +1628,8 @@ static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) { /// expansion. static unsigned CreateSLocExpansionAbbrev(llvm::BitstreamWriter &Stream) { using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_EXPANSION_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location @@ -1631,27 +1664,25 @@ namespace { typedef unsigned hash_value_type; typedef unsigned offset_type; - static hash_value_type ComputeHash(key_type_ref key) { + 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. - // - // FIXME: Using the mtime here will cause problems for explicit module - // imports. return llvm::hash_combine(key.FE->getSize(), - key.FE->getModificationTime()); + Writer.getTimestampForOutput(key.FE)); } 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); + endian::Writer<little> LE(Out); unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8; - Writer.write<uint16_t>(KeyLen); + LE.write<uint16_t>(KeyLen); unsigned DataLen = 1 + 2 + 4 + 4; - if (Data.isModuleHeader) - DataLen += 4; - Writer.write<uint8_t>(DataLen); + for (auto ModInfo : HS.getModuleMap().findAllModulesForHeader(key.FE)) + if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule())) + DataLen += 4; + LE.write<uint8_t>(DataLen); return std::make_pair(KeyLen, DataLen); } @@ -1660,7 +1691,7 @@ namespace { endian::Writer<little> LE(Out); LE.write<uint64_t>(key.FE->getSize()); KeyLen -= 8; - LE.write<uint64_t>(key.FE->getModificationTime()); + LE.write<uint64_t>(Writer.getTimestampForOutput(key.FE)); KeyLen -= 8; Out.write(key.Filename, KeyLen); } @@ -1671,11 +1702,9 @@ namespace { endian::Writer<little> LE(Out); uint64_t Start = Out.tell(); (void)Start; - unsigned char Flags = (Data.HeaderRole << 6) - | (Data.isImport << 5) - | (Data.isPragmaOnce << 4) - | (Data.DirInfo << 2) - | (Data.Resolved << 1) + unsigned char Flags = (Data.isImport << 4) + | (Data.isPragmaOnce << 3) + | (Data.DirInfo << 1) | Data.IndexHeaderMapHeader; LE.write<uint8_t>(Flags); LE.write<uint16_t>(Data.NumIncludes); @@ -1702,9 +1731,15 @@ namespace { } LE.write<uint32_t>(Offset); - if (Data.isModuleHeader) { - Module *Mod = HS.findModuleForHeader(key.FE).getModule(); - LE.write<uint32_t>(Writer.getExistingSubmoduleID(Mod)); + // FIXME: If the header is excluded, we should write out some + // record of that fact. + for (auto ModInfo : HS.getModuleMap().findAllModulesForHeader(key.FE)) { + if (uint32_t ModID = + Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule())) { + uint32_t Value = (ModID << 2) | (unsigned)ModInfo.getRole(); + assert((Value >> 2) == ModID && "overflow in header module info"); + LE.write<uint32_t>(Value); + } } assert(Out.tell() - Start == DataLen && "Wrong data length"); @@ -1734,12 +1769,15 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { if (!File) continue; - // Use HeaderSearch's getFileInfo to make sure we get the HeaderFileInfo - // from the external source if it was not provided already. - HeaderFileInfo HFI; - if (!HS.tryGetFileInfo(File, HFI) || - (HFI.External && Chain) || - (HFI.isModuleHeader && !HFI.isCompilingModuleHeader)) + // Get the file info. This will load info from the external source if + // necessary. Skip emitting this file if we have no information on it + // as a header file (in which case HFI will be null) or if it hasn't + // changed since it was loaded. Also skip it if it's for a modular header + // from a different module; in that case, we rely on the module(s) + // containing the header to provide this information. + const HeaderFileInfo *HFI = + HS.getExistingFileInfo(File, /*WantExternal*/!Chain); + if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader)) continue; // Massage the file path into an appropriate form. @@ -1753,7 +1791,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { } HeaderFileInfoTrait::key_type key = { File, Filename }; - Generator.insert(key, HFI, GeneratorTrait); + Generator.insert(key, *HFI, GeneratorTrait); ++NumHeaderSearchEntries; } @@ -1770,7 +1808,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { // Create a blob abbreviation using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_TABLE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); @@ -1779,11 +1818,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { unsigned TableAbbrev = Stream.EmitAbbrev(Abbrev); // Write the header search table - RecordData Record; - Record.push_back(HEADER_SEARCH_TABLE); - Record.push_back(BucketOffset); - Record.push_back(NumHeaderSearchEntries); - Record.push_back(TableData.size()); + RecordData::value_type Record[] = {HEADER_SEARCH_TABLE, BucketOffset, + NumHeaderSearchEntries, TableData.size()}; TableData.append(GeneratorTrait.strings_begin(),GeneratorTrait.strings_end()); Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData); @@ -1871,9 +1907,8 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Stream.EmitRecordWithAbbrev(SLocFileAbbrv, Record); - if (Content->BufferOverridden) { - Record.clear(); - Record.push_back(SM_SLOC_BUFFER_BLOB); + if (Content->BufferOverridden || Content->IsTransient) { + RecordData::value_type Record[] = {SM_SLOC_BUFFER_BLOB}; const llvm::MemoryBuffer *Buffer = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager()); Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, @@ -1892,8 +1927,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, const char *Name = Buffer->getBufferIdentifier(); Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, StringRef(Name, strlen(Name) + 1)); - Record.clear(); - Record.push_back(SM_SLOC_BUFFER_BLOB); + RecordData::value_type Record[] = {SM_SLOC_BUFFER_BLOB}; Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, StringRef(Buffer->getBufferStart(), Buffer->getBufferSize() + 1)); @@ -1927,19 +1961,20 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Write the source-location offsets table into the AST block. This // table is used for lazily loading source-location information. using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SOURCE_LOCATION_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // total size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev); - - Record.clear(); - Record.push_back(SOURCE_LOCATION_OFFSETS); - Record.push_back(SLocEntryOffsets.size()); - Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy - Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, bytes(SLocEntryOffsets)); - + { + RecordData::value_type Record[] = { + SOURCE_LOCATION_OFFSETS, SLocEntryOffsets.size(), + SourceMgr.getNextLocalOffset() - 1 /* skip dummy */}; + Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, + bytes(SLocEntryOffsets)); + } // Write the source location entry preloads array, telling the AST // reader which source locations entries it should load eagerly. Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs); @@ -1950,33 +1985,40 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, LineTableInfo &LineTable = SourceMgr.getLineTable(); Record.clear(); - // Emit the file names. - Record.push_back(LineTable.getNumFilenames()); - for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) - AddPath(LineTable.getFilename(I), Record); + + // Emit the needed file names. + llvm::DenseMap<int, int> FilenameMap; + for (const auto &L : LineTable) { + if (L.first.ID < 0) + continue; + for (auto &LE : L.second) { + if (FilenameMap.insert(std::make_pair(LE.FilenameID, + FilenameMap.size())).second) + AddPath(LineTable.getFilename(LE.FilenameID), Record); + } + } + Record.push_back(0); // Emit the line entries - for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end(); - L != LEnd; ++L) { + for (const auto &L : LineTable) { // Only emit entries for local files. - if (L->first.ID < 0) + if (L.first.ID < 0) continue; // Emit the file ID - Record.push_back(L->first.ID); + Record.push_back(L.first.ID); // Emit the line entries - Record.push_back(L->second.size()); - for (std::vector<LineEntry>::iterator LE = L->second.begin(), - LEEnd = L->second.end(); - LE != LEEnd; ++LE) { - Record.push_back(LE->FileOffset); - Record.push_back(LE->LineNo); - Record.push_back(LE->FilenameID); - Record.push_back((unsigned)LE->FileKind); - Record.push_back(LE->IncludeOffset); + Record.push_back(L.second.size()); + for (const auto &LE : L.second) { + Record.push_back(LE.FileOffset); + Record.push_back(LE.LineNo); + Record.push_back(FilenameMap[LE.FilenameID]); + Record.push_back((unsigned)LE.FileKind); + Record.push_back(LE.IncludeOffset); } } + Stream.EmitRecord(SOURCE_MANAGER_LINE_TABLE, Record); } } @@ -2015,19 +2057,17 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { // If the preprocessor __COUNTER__ value has been bumped, remember it. if (PP.getCounterValue() != 0) { - Record.push_back(PP.getCounterValue()); + RecordData::value_type Record[] = {PP.getCounterValue()}; Stream.EmitRecord(PP_COUNTER_VALUE, Record); - Record.clear(); } // Enter the preprocessor block. Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3); // If the AST file contains __DATE__ or __TIME__ emit a warning about this. - // FIXME: use diagnostics subsystem for localization etc. + // FIXME: Include a location for the use, and say which one was used. if (PP.SawDateOrTime()) - fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n"); - + PP.Diag(SourceLocation(), diag::warn_module_uses_date_time) << IsModule; // Loop over all the macro directives that are live at the end of the file, // emitting each to the PP section. @@ -2177,6 +2217,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { // Write the offsets table for macro IDs. using namespace llvm; + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros @@ -2184,12 +2225,11 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned MacroOffsetAbbrev = Stream.EmitAbbrev(Abbrev); - Record.clear(); - Record.push_back(MACRO_OFFSET); - Record.push_back(MacroOffsets.size()); - Record.push_back(FirstMacroID - NUM_PREDEF_MACRO_IDS); - Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record, - bytes(MacroOffsets)); + { + RecordData::value_type Record[] = {MACRO_OFFSET, MacroOffsets.size(), + FirstMacroID - NUM_PREDEF_MACRO_IDS}; + Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record, bytes(MacroOffsets)); + } } void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { @@ -2208,7 +2248,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { // Set up the abbreviation for unsigned InclusionAbbrev = 0; { - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(PPD_INCLUSION_DIRECTIVE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes @@ -2232,7 +2272,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { PreprocessedEntityOffsets.push_back( PPEntityOffset((*E)->getSourceRange(), Stream.GetCurrentBitNo())); - if (MacroDefinitionRecord *MD = dyn_cast<MacroDefinitionRecord>(*E)) { + if (auto *MD = dyn_cast<MacroDefinitionRecord>(*E)) { // Record this macro definition's ID. MacroDefinitions[MD] = NextPreprocessorEntityID; @@ -2241,7 +2281,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { continue; } - if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) { + if (auto *ME = dyn_cast<MacroExpansion>(*E)) { Record.push_back(ME->isBuiltinMacro()); if (ME->isBuiltinMacro()) AddIdentifierRef(ME->getName(), Record); @@ -2251,7 +2291,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { continue; } - if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) { + if (auto *ID = dyn_cast<InclusionDirective>(*E)) { Record.push_back(PPD_INCLUSION_DIRECTIVE); Record.push_back(ID->getFileName().size()); Record.push_back(ID->wasInQuotes()); @@ -2277,46 +2317,50 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { // Write the offsets table for identifier IDs. using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(PPD_ENTITIES_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first pp entity Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned PPEOffsetAbbrev = Stream.EmitAbbrev(Abbrev); - Record.clear(); - Record.push_back(PPD_ENTITIES_OFFSETS); - Record.push_back(FirstPreprocessorEntityID - NUM_PREDEF_PP_ENTITY_IDS); + RecordData::value_type Record[] = {PPD_ENTITIES_OFFSETS, + FirstPreprocessorEntityID - + NUM_PREDEF_PP_ENTITY_IDS}; Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record, bytes(PreprocessedEntityOffsets)); } } -unsigned ASTWriter::getSubmoduleID(Module *Mod) { +unsigned ASTWriter::getLocalOrImportedSubmoduleID(Module *Mod) { + if (!Mod) + return 0; + llvm::DenseMap<Module *, unsigned>::iterator Known = SubmoduleIDs.find(Mod); if (Known != SubmoduleIDs.end()) return Known->second; - - return SubmoduleIDs[Mod] = NextSubmoduleID++; -} -unsigned ASTWriter::getExistingSubmoduleID(Module *Mod) const { - if (!Mod) + if (Mod->getTopLevelModule() != WritingModule) return 0; - llvm::DenseMap<Module *, unsigned>::const_iterator - Known = SubmoduleIDs.find(Mod); - if (Known != SubmoduleIDs.end()) - return Known->second; + return SubmoduleIDs[Mod] = NextSubmoduleID++; +} - return 0; +unsigned ASTWriter::getSubmoduleID(Module *Mod) { + // FIXME: This can easily happen, if we have a reference to a submodule that + // did not result in us loading a module file for that submodule. For + // instance, a cross-top-level-module 'conflict' declaration will hit this. + unsigned ID = getLocalOrImportedSubmoduleID(Mod); + assert((ID || !Mod) && + "asked for module ID for non-local, non-imported module"); + return ID; } /// \brief Compute the number of modules within the given tree (including the /// given module). static unsigned getNumberOfModules(Module *Mod) { unsigned ChildModules = 0; - for (Module::submodule_iterator Sub = Mod->submodule_begin(), - SubEnd = Mod->submodule_end(); + for (auto Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end(); Sub != SubEnd; ++Sub) ChildModules += getNumberOfModules(*Sub); @@ -2329,7 +2373,8 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { // Write the abbreviations needed for the submodules block. using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent @@ -2408,9 +2453,9 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { unsigned ConflictAbbrev = Stream.EmitAbbrev(Abbrev); // Write the submodule metadata block. - RecordData Record; - Record.push_back(getNumberOfModules(WritingModule)); - Record.push_back(FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS); + RecordData::value_type Record[] = {getNumberOfModules(WritingModule), + FirstSubmoduleID - + NUM_PREDEF_SUBMODULE_IDS}; Stream.EmitRecord(SUBMODULE_METADATA, Record); // Write all of the submodules. @@ -2420,46 +2465,37 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Module *Mod = Q.front(); Q.pop(); unsigned ID = getSubmoduleID(Mod); - - // Emit the definition of the block. - Record.clear(); - Record.push_back(SUBMODULE_DEFINITION); - Record.push_back(ID); + + uint64_t ParentID = 0; if (Mod->Parent) { assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?"); - Record.push_back(SubmoduleIDs[Mod->Parent]); - } else { - Record.push_back(0); + ParentID = SubmoduleIDs[Mod->Parent]; } - 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); - Record.push_back(Mod->ConfigMacrosExhaustive); - Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name); - + + // Emit the definition of the block. + { + RecordData::value_type Record[] = { + SUBMODULE_DEFINITION, ID, ParentID, Mod->IsFramework, Mod->IsExplicit, + Mod->IsSystem, Mod->IsExternC, Mod->InferSubmodules, + Mod->InferExplicitSubmodules, Mod->InferExportWildcard, + Mod->ConfigMacrosExhaustive}; + Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name); + } + // Emit the requirements. - for (unsigned I = 0, N = Mod->Requirements.size(); I != N; ++I) { - Record.clear(); - Record.push_back(SUBMODULE_REQUIRES); - Record.push_back(Mod->Requirements[I].second); - Stream.EmitRecordWithBlob(RequiresAbbrev, Record, - Mod->Requirements[I].first); + for (const auto &R : Mod->Requirements) { + RecordData::value_type Record[] = {SUBMODULE_REQUIRES, R.second}; + Stream.EmitRecordWithBlob(RequiresAbbrev, Record, R.first); } // Emit the umbrella header, if there is one. if (auto UmbrellaHeader = Mod->getUmbrellaHeader()) { - Record.clear(); - Record.push_back(SUBMODULE_UMBRELLA_HEADER); + RecordData::value_type Record[] = {SUBMODULE_UMBRELLA_HEADER}; Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record, UmbrellaHeader.NameAsWritten); } else if (auto UmbrellaDir = Mod->getUmbrellaDir()) { - Record.clear(); - Record.push_back(SUBMODULE_UMBRELLA_DIR); - Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record, + RecordData::value_type Record[] = {SUBMODULE_UMBRELLA_DIR}; + Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record, UmbrellaDir.NameAsWritten); } @@ -2477,8 +2513,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { {SUBMODULE_EXCLUDED_HEADER, ExcludedHeaderAbbrev, Module::HK_Excluded} }; for (auto &HL : HeaderLists) { - Record.clear(); - Record.push_back(HL.RecordKind); + RecordData::value_type Record[] = {HL.RecordKind}; for (auto &H : Mod->Headers[HL.HeaderKind]) Stream.EmitRecordWithBlob(HL.Abbrev, Record, H.NameAsWritten); } @@ -2486,35 +2521,27 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { // Emit the top headers. { auto TopHeaders = Mod->getTopHeaders(PP->getFileManager()); - Record.clear(); - Record.push_back(SUBMODULE_TOPHEADER); + RecordData::value_type Record[] = {SUBMODULE_TOPHEADER}; for (auto *H : TopHeaders) Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record, H->getName()); } // Emit the imports. if (!Mod->Imports.empty()) { - Record.clear(); - for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) { - unsigned ImportedID = getSubmoduleID(Mod->Imports[I]); - assert(ImportedID && "Unknown submodule!"); - Record.push_back(ImportedID); - } + RecordData Record; + for (auto *I : Mod->Imports) + Record.push_back(getSubmoduleID(I)); Stream.EmitRecord(SUBMODULE_IMPORTS, Record); } // Emit the exports. if (!Mod->Exports.empty()) { - Record.clear(); - for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) { - if (Module *Exported = Mod->Exports[I].getPointer()) { - unsigned ExportedID = getSubmoduleID(Exported); - Record.push_back(ExportedID); - } else { - Record.push_back(0); - } - - Record.push_back(Mod->Exports[I].getInt()); + RecordData Record; + for (const auto &E : Mod->Exports) { + // FIXME: This may fail; we don't require that all exported modules + // are local or imported. + Record.push_back(getSubmoduleID(E.getPointer())); + Record.push_back(E.getInt()); } Stream.EmitRecord(SUBMODULE_EXPORTS, Record); } @@ -2524,45 +2551,34 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { // module itself. // 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); + for (const auto &LL : Mod->LinkLibraries) { + RecordData::value_type Record[] = {SUBMODULE_LINK_LIBRARY, + LL.IsFramework}; + Stream.EmitRecordWithBlob(LinkLibraryAbbrev, Record, LL.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); + for (const auto &C : Mod->Conflicts) { + // FIXME: This may fail; we don't require that all conflicting modules + // are local or imported. + RecordData::value_type Record[] = {SUBMODULE_CONFLICT, + getSubmoduleID(C.Other)}; + Stream.EmitRecordWithBlob(ConflictAbbrev, Record, C.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]); + for (const auto &CM : Mod->ConfigMacros) { + RecordData::value_type Record[] = {SUBMODULE_CONFIG_MACRO}; + Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record, CM); } // Queue up the submodules of this module. - for (Module::submodule_iterator Sub = Mod->submodule_begin(), - SubEnd = Mod->submodule_end(); - Sub != SubEnd; ++Sub) - Q.push(*Sub); + for (auto *M : Mod->submodules()) + Q.push(M); } Stream.ExitBlock(); - // FIXME: This can easily happen, if we have a reference to a submodule that - // did not result in us loading a module file for that submodule. For - // instance, a cross-top-level-module 'conflict' declaration will hit this. assert((NextSubmoduleID - FirstSubmoduleID == getNumberOfModules(WritingModule)) && "Wrong # of submodules; found a reference to a non-local, " @@ -2614,11 +2630,10 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, if (DiagStateID == 0) { DiagStateID = ++CurrID; - for (DiagnosticsEngine::DiagState::const_iterator - I = point.State->begin(), E = point.State->end(); I != E; ++I) { - if (I->second.isPragma()) { - Record.push_back(I->first); - Record.push_back((unsigned)I->second.getSeverity()); + for (const auto &I : *(point.State)) { + if (I.second.isPragma()) { + Record.push_back(I.first); + Record.push_back((unsigned)I.second.getSeverity()); } } Record.push_back(-1); // mark the end of the diag/map pairs for this @@ -2634,21 +2649,18 @@ void ASTWriter::WriteCXXCtorInitializersOffsets() { if (CXXCtorInitializersOffsets.empty()) return; - RecordData Record; - // Create a blob abbreviation for the C++ ctor initializer offsets. using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(CXX_CTOR_INITIALIZERS_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned CtorInitializersOffsetAbbrev = Stream.EmitAbbrev(Abbrev); // Write the base specifier offsets table. - Record.clear(); - Record.push_back(CXX_CTOR_INITIALIZERS_OFFSETS); - Record.push_back(CXXCtorInitializersOffsets.size()); + RecordData::value_type Record[] = {CXX_CTOR_INITIALIZERS_OFFSETS, + CXXCtorInitializersOffsets.size()}; Stream.EmitRecordWithBlob(CtorInitializersOffsetAbbrev, Record, bytes(CXXCtorInitializersOffsets)); } @@ -2657,21 +2669,18 @@ void ASTWriter::WriteCXXBaseSpecifiersOffsets() { if (CXXBaseSpecifiersOffsets.empty()) return; - RecordData Record; - // Create a blob abbreviation for the C++ base specifiers offsets. using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(CXX_BASE_SPECIFIER_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev); // Write the base specifier offsets table. - Record.clear(); - Record.push_back(CXX_BASE_SPECIFIER_OFFSETS); - Record.push_back(CXXBaseSpecifiersOffsets.size()); + RecordData::value_type Record[] = {CXX_BASE_SPECIFIER_OFFSETS, + CXXBaseSpecifiersOffsets.size()}; Stream.EmitRecordWithBlob(BaseSpecifierOffsetAbbrev, Record, bytes(CXXBaseSpecifiersOffsets)); } @@ -2742,33 +2751,34 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context, return 0; uint64_t Offset = Stream.GetCurrentBitNo(); - RecordData Record; - Record.push_back(DECL_CONTEXT_LEXICAL); - SmallVector<KindDeclIDPair, 64> Decls; - for (const auto *D : DC->decls()) - Decls.push_back(std::make_pair(D->getKind(), GetDeclRef(D))); + SmallVector<uint32_t, 128> KindDeclPairs; + for (const auto *D : DC->decls()) { + KindDeclPairs.push_back(D->getKind()); + KindDeclPairs.push_back(GetDeclRef(D)); + } ++NumLexicalDeclContexts; - Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, bytes(Decls)); + RecordData::value_type Record[] = {DECL_CONTEXT_LEXICAL}; + Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, + bytes(KindDeclPairs)); return Offset; } void ASTWriter::WriteTypeDeclOffsets() { using namespace llvm; - RecordData Record; // Write the type offsets array - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base type index Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev); - Record.clear(); - Record.push_back(TYPE_OFFSET); - Record.push_back(TypeOffsets.size()); - Record.push_back(FirstTypeID - NUM_PREDEF_TYPE_IDS); - Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, bytes(TypeOffsets)); + { + RecordData::value_type Record[] = {TYPE_OFFSET, TypeOffsets.size(), + FirstTypeID - NUM_PREDEF_TYPE_IDS}; + Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, bytes(TypeOffsets)); + } // Write the declaration offsets array Abbrev = new BitCodeAbbrev(); @@ -2777,16 +2787,15 @@ void ASTWriter::WriteTypeDeclOffsets() { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base decl ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev); - Record.clear(); - Record.push_back(DECL_OFFSET); - Record.push_back(DeclOffsets.size()); - Record.push_back(FirstDeclID - NUM_PREDEF_DECL_IDS); - Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, bytes(DeclOffsets)); + { + RecordData::value_type Record[] = {DECL_OFFSET, DeclOffsets.size(), + FirstDeclID - NUM_PREDEF_DECL_IDS}; + Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, bytes(DeclOffsets)); + } } void ASTWriter::WriteFileDeclIDsMap() { using namespace llvm; - RecordData Record; SmallVector<std::pair<FileID, DeclIDInFileInfo *>, 64> SortedFileDeclIDs( FileDeclIDs.begin(), FileDeclIDs.end()); @@ -2802,13 +2811,13 @@ void ASTWriter::WriteFileDeclIDsMap() { FileGroupedDeclIDs.push_back(LocDeclEntry.second); } - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); - Record.push_back(FILE_SORTED_DECLS); - Record.push_back(FileGroupedDeclIDs.size()); + RecordData::value_type Record[] = {FILE_SORTED_DECLS, + FileGroupedDeclIDs.size()}; Stream.EmitRecordWithBlob(AbbrevCode, Record, bytes(FileGroupedDeclIDs)); } @@ -2816,14 +2825,12 @@ void ASTWriter::WriteComments() { Stream.EnterSubblock(COMMENTS_BLOCK_ID, 3); ArrayRef<RawComment *> RawComments = Context->Comments.getComments(); RecordData Record; - for (ArrayRef<RawComment *>::iterator I = RawComments.begin(), - E = RawComments.end(); - I != E; ++I) { + for (const auto *I : RawComments) { Record.clear(); - AddSourceRange((*I)->getSourceRange(), Record); - Record.push_back((*I)->getKind()); - Record.push_back((*I)->isTrailingComment()); - Record.push_back((*I)->isAlmostTrailingComment()); + AddSourceRange(I->getSourceRange(), Record); + Record.push_back(I->getKind()); + Record.push_back(I->isTrailingComment()); + Record.push_back(I->isAlmostTrailingComment()); Stream.EmitRecord(COMMENTS_RAW_COMMENT, Record); } Stream.ExitBlock(); @@ -3010,7 +3017,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { } // Create a blob abbreviation - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(METHOD_POOL)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); @@ -3018,11 +3025,11 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev); // Write the method pool - RecordData Record; - Record.push_back(METHOD_POOL); - Record.push_back(BucketOffset); - Record.push_back(NumTableEntries); - Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool); + { + RecordData::value_type Record[] = {METHOD_POOL, BucketOffset, + NumTableEntries}; + Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool); + } // Create a blob abbreviation for the selector table offsets. Abbrev = new BitCodeAbbrev(); @@ -3033,12 +3040,13 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev); // Write the selector offsets table. - Record.clear(); - Record.push_back(SELECTOR_OFFSETS); - Record.push_back(SelectorOffsets.size()); - Record.push_back(FirstSelectorID - NUM_PREDEF_SELECTOR_IDS); - Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, - bytes(SelectorOffsets)); + { + RecordData::value_type Record[] = { + SELECTOR_OFFSETS, SelectorOffsets.size(), + FirstSelectorID - NUM_PREDEF_SELECTOR_IDS}; + Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, + bytes(SelectorOffsets)); + } } } @@ -3102,18 +3110,20 @@ class ASTIdentifierTableTrait { ASTWriter &Writer; Preprocessor &PP; IdentifierResolver &IdResolver; + bool IsModule; + bool NeedDecls; + ASTWriter::RecordData *InterestingIdentifierOffsets; /// \brief Determines whether this is an "interesting" identifier that needs a /// full IdentifierInfo structure written into the hash table. Notably, this /// doesn't check whether the name has macros defined; use PublicMacroIterator /// to check that. - bool isInterestingIdentifier(IdentifierInfo *II, uint64_t MacroOffset) { + bool isInterestingIdentifier(const IdentifierInfo *II, uint64_t MacroOffset) { if (MacroOffset || II->isPoisoned() || - II->isExtensionToken() || - II->getObjCOrBuiltinID() || + (IsModule ? II->hasRevertedBuiltin() : II->getObjCOrBuiltinID()) || II->hasRevertedTokenIDToIdentifier() || - II->getFETokenInfo<void>()) + (NeedDecls && II->getFETokenInfo<void>())) return true; return false; @@ -3130,13 +3140,24 @@ public: typedef unsigned offset_type; ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, - IdentifierResolver &IdResolver) - : Writer(Writer), PP(PP), IdResolver(IdResolver) {} + IdentifierResolver &IdResolver, bool IsModule, + ASTWriter::RecordData *InterestingIdentifierOffsets) + : Writer(Writer), PP(PP), IdResolver(IdResolver), IsModule(IsModule), + NeedDecls(!IsModule || !Writer.getLangOpts().CPlusPlus), + InterestingIdentifierOffsets(InterestingIdentifierOffsets) {} static hash_value_type ComputeHash(const IdentifierInfo* II) { return llvm::HashString(II->getName()); } + bool isInterestingIdentifier(const IdentifierInfo *II) { + auto MacroOffset = Writer.getMacroDirectivesOffset(II); + return isInterestingIdentifier(II, MacroOffset); + } + bool isInterestingNonMacroIdentifier(const IdentifierInfo *II) { + return isInterestingIdentifier(II, 0); + } + std::pair<unsigned,unsigned> EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) { unsigned KeyLen = II->getLength() + 1; @@ -3148,10 +3169,12 @@ public: if (MacroOffset) DataLen += 4; // MacroDirectives offset. - for (IdentifierResolver::iterator D = IdResolver.begin(II), - DEnd = IdResolver.end(); - D != DEnd; ++D) - DataLen += 4; + if (NeedDecls) { + for (IdentifierResolver::iterator D = IdResolver.begin(II), + DEnd = IdResolver.end(); + D != DEnd; ++D) + DataLen += 4; + } } using namespace llvm::support; endian::Writer<little> LE(Out); @@ -3170,6 +3193,12 @@ public: // Record the location of the key data. This is used when generating // the mapping from persistent IDs to strings. Writer.SetIdentifierOffset(II, Out.tell()); + + // Emit the offset of the key/data length information to the interesting + // identifiers table if necessary. + if (InterestingIdentifierOffsets && isInterestingIdentifier(II)) + InterestingIdentifierOffsets->push_back(Out.tell() - 4); + Out.write(II->getNameStart(), KeyLen); } @@ -3193,6 +3222,7 @@ public: Bits = (Bits << 1) | unsigned(HadMacroDefinition); Bits = (Bits << 1) | unsigned(II->isExtensionToken()); Bits = (Bits << 1) | unsigned(II->isPoisoned()); + Bits = (Bits << 1) | unsigned(II->hasRevertedBuiltin()); Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier()); Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); LE.write<uint16_t>(Bits); @@ -3200,18 +3230,21 @@ public: if (HadMacroDefinition) LE.write<uint32_t>(MacroOffset); - // Emit the declaration IDs in reverse order, because the - // IdentifierResolver provides the declarations as they would be - // visible (e.g., the function "stat" would come before the struct - // "stat"), but the ASTReader adds declarations to the end of the list - // (so we need to see the struct "stat" before the function "stat"). - // Only emit declarations that aren't from a chained PCH, though. - SmallVector<NamedDecl *, 16> Decls(IdResolver.begin(II), IdResolver.end()); - for (SmallVectorImpl<NamedDecl *>::reverse_iterator D = Decls.rbegin(), - DEnd = Decls.rend(); - D != DEnd; ++D) - LE.write<uint32_t>( - Writer.getDeclID(getDeclForLocalLookup(PP.getLangOpts(), *D))); + if (NeedDecls) { + // Emit the declaration IDs in reverse order, because the + // IdentifierResolver provides the declarations as they would be + // visible (e.g., the function "stat" would come before the struct + // "stat"), but the ASTReader adds declarations to the end of the list + // (so we need to see the struct "stat" before the function "stat"). + // Only emit declarations that aren't from a chained PCH, though. + SmallVector<NamedDecl *, 16> Decls(IdResolver.begin(II), + IdResolver.end()); + for (SmallVectorImpl<NamedDecl *>::reverse_iterator D = Decls.rbegin(), + DEnd = Decls.rend(); + D != DEnd; ++D) + LE.write<uint32_t>( + Writer.getDeclID(getDeclForLocalLookup(PP.getLangOpts(), *D))); + } } }; } // end anonymous namespace @@ -3226,11 +3259,15 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, bool IsModule) { using namespace llvm; + RecordData InterestingIdents; + // Create and write out the blob that contains the identifier // strings. { llvm::OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator; - ASTIdentifierTableTrait Trait(*this, PP, IdResolver); + ASTIdentifierTableTrait Trait( + *this, PP, IdResolver, IsModule, + (getLangOpts().CPlusPlus && IsModule) ? &InterestingIdents : nullptr); // Look for any identifiers that were named while processing the // headers, but are otherwise not needed. We add these to the hash @@ -3238,21 +3275,20 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, // where the user adds new macro definitions when building the AST // file. SmallVector<const IdentifierInfo *, 128> IIs; - for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(), - IDEnd = PP.getIdentifierTable().end(); - ID != IDEnd; ++ID) - IIs.push_back(ID->second); + for (const auto &ID : PP.getIdentifierTable()) + IIs.push_back(ID.second); // Sort the identifiers lexicographically before getting them references so // that their order is stable. std::sort(IIs.begin(), IIs.end(), llvm::less_ptr<IdentifierInfo>()); for (const IdentifierInfo *II : IIs) - getIdentifierRef(II); + if (Trait.isInterestingNonMacroIdentifier(II)) + getIdentifierRef(II); // Create the on-disk hash table representation. We only store offsets // for identifiers that appear here for the first time. IdentifierOffsets.resize(NextIdentID - FirstIdentID); for (auto IdentIDPair : IdentifierIDs) { - IdentifierInfo *II = const_cast<IdentifierInfo *>(IdentIDPair.first); + auto *II = const_cast<IdentifierInfo *>(IdentIDPair.first); IdentID ID = IdentIDPair.second; assert(II && "NULL identifier in identifier table"); if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization()) @@ -3271,21 +3307,19 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, } // Create a blob abbreviation - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_TABLE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev); // Write the identifier table - RecordData Record; - Record.push_back(IDENTIFIER_TABLE); - Record.push_back(BucketOffset); + RecordData::value_type Record[] = {IDENTIFIER_TABLE, BucketOffset}; Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable); } // Write the offsets table for identifier IDs. - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID @@ -3296,13 +3330,17 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, 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()); - Record.push_back(FirstIdentID - NUM_PREDEF_IDENT_IDS); + + RecordData::value_type Record[] = {IDENTIFIER_OFFSET, + IdentifierOffsets.size(), + FirstIdentID - NUM_PREDEF_IDENT_IDS}; Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record, bytes(IdentifierOffsets)); + + // In C++, write the list of interesting identifiers (those that are + // defined as macros, poisoned, or similar unusual things). + if (!InterestingIdents.empty()) + Stream.EmitRecord(INTERESTING_IDENTIFIERS, InterestingIdents); } //===----------------------------------------------------------------------===// @@ -3313,12 +3351,14 @@ namespace { // Trait used for the on-disk hash table used in the method pool. class ASTDeclContextNameLookupTrait { ASTWriter &Writer; + llvm::SmallVector<DeclID, 64> DeclIDs; public: - typedef DeclarationName key_type; + typedef DeclarationNameKey key_type; typedef key_type key_type_ref; - typedef DeclContext::lookup_result data_type; + /// A start and end index into DeclIDs, representing a sequence of decls. + typedef std::pair<unsigned, unsigned> data_type; typedef const data_type& data_type_ref; typedef unsigned hash_value_type; @@ -3326,42 +3366,47 @@ public: explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { } - hash_value_type ComputeHash(DeclarationName Name) { - llvm::FoldingSetNodeID ID; - ID.AddInteger(Name.getNameKind()); - - switch (Name.getNameKind()) { - case DeclarationName::Identifier: - ID.AddString(Name.getAsIdentifierInfo()->getName()); - break; - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - ID.AddInteger(serialization::ComputeHash(Name.getObjCSelector())); - break; - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - break; - case DeclarationName::CXXOperatorName: - ID.AddInteger(Name.getCXXOverloadedOperator()); - break; - case DeclarationName::CXXLiteralOperatorName: - ID.AddString(Name.getCXXLiteralIdentifier()->getName()); - case DeclarationName::CXXUsingDirective: - break; + template<typename Coll> + data_type getData(const Coll &Decls) { + unsigned Start = DeclIDs.size(); + for (NamedDecl *D : Decls) { + DeclIDs.push_back( + Writer.GetDeclRef(getDeclForLocalLookup(Writer.getLangOpts(), D))); } + return std::make_pair(Start, DeclIDs.size()); + } - return ID.ComputeHash(); + data_type ImportData(const reader::ASTDeclContextNameLookupTrait::data_type &FromReader) { + unsigned Start = DeclIDs.size(); + for (auto ID : FromReader) + DeclIDs.push_back(ID); + return std::make_pair(Start, DeclIDs.size()); } - std::pair<unsigned,unsigned> - EmitKeyDataLength(raw_ostream& Out, DeclarationName Name, - data_type_ref Lookup) { + static bool EqualKey(key_type_ref a, key_type_ref b) { + return a == b; + } + + hash_value_type ComputeHash(DeclarationNameKey Name) { + return Name.getHash(); + } + + void EmitFileRef(raw_ostream &Out, ModuleFile *F) const { + assert(Writer.hasChain() && + "have reference to loaded module file but no chain?"); + + using namespace llvm::support; + endian::Writer<little>(Out) + .write<uint32_t>(Writer.getChain()->getModuleFileID(F)); + } + + std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &Out, + DeclarationNameKey Name, + data_type_ref Lookup) { using namespace llvm::support; endian::Writer<little> LE(Out); unsigned KeyLen = 1; - switch (Name.getNameKind()) { + switch (Name.getKind()) { case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: @@ -3380,33 +3425,33 @@ public: } LE.write<uint16_t>(KeyLen); - // 2 bytes for num of decls and 4 for each DeclID. - unsigned DataLen = 2 + 4 * Lookup.size(); + // 4 bytes for each DeclID. + unsigned DataLen = 4 * (Lookup.second - Lookup.first); + assert(uint16_t(DataLen) == DataLen && + "too many decls for serialized lookup result"); LE.write<uint16_t>(DataLen); return std::make_pair(KeyLen, DataLen); } - void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) { + void EmitKey(raw_ostream &Out, DeclarationNameKey Name, unsigned) { using namespace llvm::support; endian::Writer<little> LE(Out); - LE.write<uint8_t>(Name.getNameKind()); - switch (Name.getNameKind()) { + LE.write<uint8_t>(Name.getKind()); + switch (Name.getKind()) { case DeclarationName::Identifier: - LE.write<uint32_t>(Writer.getIdentifierRef(Name.getAsIdentifierInfo())); + case DeclarationName::CXXLiteralOperatorName: + LE.write<uint32_t>(Writer.getIdentifierRef(Name.getIdentifier())); return; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - LE.write<uint32_t>(Writer.getSelectorRef(Name.getObjCSelector())); + LE.write<uint32_t>(Writer.getSelectorRef(Name.getSelector())); return; case DeclarationName::CXXOperatorName: - assert(Name.getCXXOverloadedOperator() < NUM_OVERLOADED_OPERATORS && + assert(Name.getOperatorKind() < NUM_OVERLOADED_OPERATORS && "Invalid operator?"); - LE.write<uint8_t>(Name.getCXXOverloadedOperator()); - return; - case DeclarationName::CXXLiteralOperatorName: - LE.write<uint32_t>(Writer.getIdentifierRef(Name.getCXXLiteralIdentifier())); + LE.write<uint8_t>(Name.getOperatorKind()); return; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: @@ -3418,17 +3463,13 @@ public: llvm_unreachable("Invalid name kind?"); } - void EmitData(raw_ostream& Out, key_type_ref, - data_type Lookup, unsigned DataLen) { + 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; - LE.write<uint16_t>(Lookup.size()); - for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end(); - I != E; ++I) - LE.write<uint32_t>( - Writer.GetDeclRef(getDeclForLocalLookup(Writer.getLangOpts(), *I))); - + for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) + LE.write<uint32_t>(DeclIDs[I]); assert(Out.tell() - Start == DataLen && "Data length is wrong"); } }; @@ -3448,7 +3489,7 @@ bool ASTWriter::isLookupResultEntirelyExternal(StoredDeclsList &Result, return true; } -uint32_t +void ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC, llvm::SmallVectorImpl<char> &LookupTable) { assert(!ConstDC->HasLazyLocalLexicalLookups && @@ -3456,12 +3497,12 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC, "must call buildLookups first"); // FIXME: We need to build the lookups table, which is logically const. - DeclContext *DC = const_cast<DeclContext*>(ConstDC); + auto *DC = const_cast<DeclContext*>(ConstDC); assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table"); // Create the on-disk hash table representation. - llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> - Generator; + MultiOnDiskHashTableGenerator<reader::ASTDeclContextNameLookupTrait, + ASTDeclContextNameLookupTrait> Generator; ASTDeclContextNameLookupTrait Trait(*this); // The first step is to collect the declaration names which we need to @@ -3477,11 +3518,11 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC, auto &Name = Lookup.first; auto &Result = Lookup.second; - // If there are no local declarations in our lookup result, we don't - // need to write an entry for the name at all unless we're rewriting - // the decl context. If we can't write out a lookup set without - // performing more deserialization, just skip this entry. - if (isLookupResultExternal(Result, DC) && !isRewritten(cast<Decl>(DC)) && + // If there are no local declarations in our lookup result, we + // don't need to write an entry for the name at all. If we can't + // write out a lookup set without performing more deserialization, + // just skip this entry. + if (isLookupResultExternal(Result, DC) && isLookupResultEntirelyExternal(Result, DC)) continue; @@ -3596,7 +3637,7 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC, switch (Name.getNameKind()) { default: - Generator.insert(Name, Result, Trait); + Generator.insert(Name, Trait.getData(Result), Trait); break; case DeclarationName::CXXConstructorName: @@ -3614,17 +3655,15 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC, // the key, only the kind of name is used. if (!ConstructorDecls.empty()) Generator.insert(ConstructorDecls.front()->getDeclName(), - DeclContext::lookup_result(ConstructorDecls), Trait); + Trait.getData(ConstructorDecls), Trait); if (!ConversionDecls.empty()) Generator.insert(ConversionDecls.front()->getDeclName(), - DeclContext::lookup_result(ConversionDecls), Trait); + Trait.getData(ConversionDecls), 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); + // Create the on-disk hash table. Also emit the existing imported and + // merged table if there is one. + auto *Lookups = Chain ? Chain->getLoadedLookupTables(DC) : nullptr; + Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr); } /// \brief Write the block containing all of the declaration IDs @@ -3640,7 +3679,7 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, if (isa<NamespaceDecl>(DC) && Chain && Chain->getKeyDeclaration(cast<Decl>(DC))->isFromASTFile()) { // Only do this once, for the first local declaration of the namespace. - for (NamespaceDecl *Prev = cast<NamespaceDecl>(DC)->getPreviousDecl(); Prev; + for (auto *Prev = cast<NamespaceDecl>(DC)->getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) if (!Prev->isFromASTFile()) return 0; @@ -3707,12 +3746,10 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, // Create the on-disk hash table in a buffer. SmallString<4096> LookupTable; - uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable); + GenerateNameLookupTable(DC, LookupTable); // Write the lookup table - RecordData Record; - Record.push_back(DECL_CONTEXT_VISIBLE); - Record.push_back(BucketOffset); + RecordData::value_type Record[] = {DECL_CONTEXT_VISIBLE}; Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record, LookupTable); ++NumVisibleDeclContexts; @@ -3732,7 +3769,7 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) { // Create the on-disk hash table in a buffer. SmallString<4096> LookupTable; - uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable); + GenerateNameLookupTable(DC, LookupTable); // If we're updating a namespace, select a key declaration as the key for the // update record; those are the only ones that will be checked on reload. @@ -3740,17 +3777,13 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) { DC = cast<DeclContext>(Chain->getKeyDeclaration(cast<Decl>(DC))); // Write the lookup table - RecordData Record; - Record.push_back(UPDATE_VISIBLE); - Record.push_back(getDeclID(cast<Decl>(DC))); - Record.push_back(BucketOffset); + RecordData::value_type Record[] = {UPDATE_VISIBLE, getDeclID(cast<Decl>(DC))}; Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable); } /// \brief Write an FP_PRAGMA_OPTIONS block for the given FPOptions. void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) { - RecordData Record; - Record.push_back(Opts.fp_contract); + RecordData::value_type Record[] = {Opts.fp_contract}; Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record); } @@ -3766,81 +3799,6 @@ void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) { Stream.EmitRecord(OPENCL_EXTENSIONS, Record); } -void ASTWriter::WriteRedeclarations() { - RecordData LocalRedeclChains; - SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclsMap; - - for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) { - const Decl *Key = Redeclarations[I]; - assert((Chain ? Chain->getKeyDeclaration(Key) == Key - : Key->isFirstDecl()) && - "not the key declaration"); - - const Decl *First = Key->getCanonicalDecl(); - const Decl *MostRecent = First->getMostRecentDecl(); - - assert((getDeclID(First) >= NUM_PREDEF_DECL_IDS || First == Key) && - "should not have imported key decls for predefined decl"); - - // If we only have a single declaration, there is no point in storing - // a redeclaration chain. - if (First == MostRecent) - continue; - - unsigned Offset = LocalRedeclChains.size(); - unsigned Size = 0; - LocalRedeclChains.push_back(0); // Placeholder for the size. - - // Collect the set of local redeclarations of this declaration. - for (const Decl *Prev = MostRecent; Prev; - Prev = Prev->getPreviousDecl()) { - if (!Prev->isFromASTFile() && Prev != Key) { - AddDeclRef(Prev, LocalRedeclChains); - ++Size; - } - } - - 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 from the AST to the set of local - // declarations. - LocalRedeclarationsInfo Info = { getDeclID(Key), Offset }; - LocalRedeclsMap.push_back(Info); - - assert(N == Redeclarations.size() && - "Deserialized a declaration we shouldn't have"); - } - - if (LocalRedeclChains.empty()) - return; - - // Sort the local redeclarations map by the first declaration ID, - // since the reader will be performing binary searches on this information. - llvm::array_pod_sort(LocalRedeclsMap.begin(), LocalRedeclsMap.end()); - - // Emit the local redeclarations map. - using namespace llvm; - llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS_MAP)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned AbbrevID = Stream.EmitAbbrev(Abbrev); - - RecordData Record; - Record.push_back(LOCAL_REDECLARATIONS_MAP); - Record.push_back(LocalRedeclsMap.size()); - Stream.EmitRecordWithBlob(AbbrevID, Record, - reinterpret_cast<char*>(LocalRedeclsMap.data()), - LocalRedeclsMap.size() * sizeof(LocalRedeclarationsInfo)); - - // Emit the redeclaration chains. - Stream.EmitRecord(LOCAL_REDECLARATIONS, LocalRedeclChains); -} - void ASTWriter::WriteObjCCategories() { SmallVector<ObjCCategoriesInfo, 2> CategoriesMap; RecordData Categories; @@ -3877,19 +3835,18 @@ void ASTWriter::WriteObjCCategories() { // Emit the categories map. using namespace llvm; - llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(OBJC_CATEGORIES_MAP)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned AbbrevID = Stream.EmitAbbrev(Abbrev); - - RecordData Record; - Record.push_back(OBJC_CATEGORIES_MAP); - Record.push_back(CategoriesMap.size()); - Stream.EmitRecordWithBlob(AbbrevID, Record, - reinterpret_cast<char*>(CategoriesMap.data()), + + RecordData::value_type Record[] = {OBJC_CATEGORIES_MAP, CategoriesMap.size()}; + Stream.EmitRecordWithBlob(AbbrevID, Record, + reinterpret_cast<char *>(CategoriesMap.data()), CategoriesMap.size() * sizeof(ObjCCategoriesInfo)); - + // Emit the category lists. Stream.EmitRecord(OBJC_CATEGORIES, Categories); } @@ -3908,10 +3865,8 @@ void ASTWriter::WriteLateParsedTemplates(Sema &SemaRef) { AddDeclRef(LPT->D, Record); Record.push_back(LPT->Toks.size()); - for (CachedTokens::iterator TokIt = LPT->Toks.begin(), - TokEnd = LPT->Toks.end(); - TokIt != TokEnd; ++TokIt) { - AddToken(*TokIt, Record); + for (const auto &Tok : LPT->Toks) { + AddToken(Tok, Record); } } Stream.EmitRecord(LATE_PARSED_TEMPLATE, Record); @@ -3925,6 +3880,41 @@ void ASTWriter::WriteOptimizePragmaOptions(Sema &SemaRef) { Stream.EmitRecord(OPTIMIZE_PRAGMA_OPTIONS, Record); } +void ASTWriter::WriteModuleFileExtension(Sema &SemaRef, + ModuleFileExtensionWriter &Writer) { + // Enter the extension block. + Stream.EnterSubblock(EXTENSION_BLOCK_ID, 4); + + // Emit the metadata record abbreviation. + auto *Abv = new llvm::BitCodeAbbrev(); + Abv->Add(llvm::BitCodeAbbrevOp(EXTENSION_METADATA)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); + Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); + unsigned Abbrev = Stream.EmitAbbrev(Abv); + + // Emit the metadata record. + RecordData Record; + auto Metadata = Writer.getExtension()->getExtensionMetadata(); + Record.push_back(EXTENSION_METADATA); + Record.push_back(Metadata.MajorVersion); + Record.push_back(Metadata.MinorVersion); + Record.push_back(Metadata.BlockName.size()); + Record.push_back(Metadata.UserInfo.size()); + SmallString<64> Buffer; + Buffer += Metadata.BlockName; + Buffer += Metadata.UserInfo; + Stream.EmitRecordWithBlob(Abbrev, Record, Buffer); + + // Emit the contents of the extension block. + Writer.writeExtensionContents(SemaRef, Stream); + + // Exit the extension block. + Stream.ExitBlock(); +} + //===----------------------------------------------------------------------===// // General Serialization Routines //===----------------------------------------------------------------------===// @@ -3933,9 +3923,7 @@ void ASTWriter::WriteOptimizePragmaOptions(Sema &SemaRef) { void ASTWriter::WriteAttributes(ArrayRef<const Attr*> Attrs, RecordDataImpl &Record) { Record.push_back(Attrs.size()); - for (ArrayRef<const Attr *>::iterator i = Attrs.begin(), - e = Attrs.end(); i != e; ++i){ - const Attr *A = *i; + for (const auto *A : Attrs) { Record.push_back(A->getKind()); // FIXME: stable encoding, target attrs AddSourceRange(A->getRange(), Record); @@ -3986,7 +3974,7 @@ void ASTWriter::AddPath(StringRef Path, RecordDataImpl &Record) { AddString(FilePath, Record); } -void ASTWriter::EmitRecordWithPath(unsigned Abbrev, RecordDataImpl &Record, +void ASTWriter::EmitRecordWithPath(unsigned Abbrev, RecordDataRef Record, StringRef Path) { SmallString<128> FilePath(Path); PreparePathForOutput(FilePath); @@ -4028,28 +4016,35 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) { SelectorOffsets[ID - FirstSelectorID] = Offset; } -ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) +ASTWriter::ASTWriter( + llvm::BitstreamWriter &Stream, + ArrayRef<llvm::IntrusiveRefCntPtr<ModuleFileExtension>> Extensions, + bool IncludeTimestamps) : 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), - FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID), - FirstMacroID(NUM_PREDEF_MACRO_IDS), NextMacroID(FirstMacroID), - FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS), + WritingModule(nullptr), IncludeTimestamps(IncludeTimestamps), + WritingAST(false), DoneWritingDeclsAndTypes(false), + ASTHasCompilerErrors(false), FirstDeclID(NUM_PREDEF_DECL_IDS), + NextDeclID(FirstDeclID), FirstTypeID(NUM_PREDEF_TYPE_IDS), + NextTypeID(FirstTypeID), FirstIdentID(NUM_PREDEF_IDENT_IDS), + NextIdentID(FirstIdentID), FirstMacroID(NUM_PREDEF_MACRO_IDS), + NextMacroID(FirstMacroID), FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS), NextSubmoduleID(FirstSubmoduleID), FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID), CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0), NumVisibleDeclContexts(0), NextCXXBaseSpecifiersID(1), NextCXXCtorInitializersID(1), - TypeExtQualAbbrev(0), - TypeFunctionProtoAbbrev(0), DeclParmVarAbbrev(0), + TypeExtQualAbbrev(0), TypeFunctionProtoAbbrev(0), DeclParmVarAbbrev(0), DeclContextLexicalAbbrev(0), DeclContextVisibleLookupAbbrev(0), UpdateVisibleAbbrev(0), DeclRecordAbbrev(0), DeclTypedefAbbrev(0), DeclVarAbbrev(0), DeclFieldAbbrev(0), DeclEnumAbbrev(0), DeclObjCIvarAbbrev(0), DeclCXXMethodAbbrev(0), DeclRefExprAbbrev(0), CharacterLiteralAbbrev(0), IntegerLiteralAbbrev(0), - ExprImplicitCastAbbrev(0) {} + ExprImplicitCastAbbrev(0) { + for (const auto &Ext : Extensions) { + if (auto Writer = Ext->createExtensionWriter(*this)) + ModuleFileExtensionWriters.push_back(std::move(Writer)); + } +} ASTWriter::~ASTWriter() { llvm::DeleteContainerSeconds(FileDeclIDs); @@ -4060,12 +4055,15 @@ const LangOptions &ASTWriter::getLangOpts() const { return Context->getLangOpts(); } -void ASTWriter::WriteAST(Sema &SemaRef, - const std::string &OutputFile, - Module *WritingModule, StringRef isysroot, - bool hasErrors) { +time_t ASTWriter::getTimestampForOutput(const FileEntry *E) const { + return IncludeTimestamps ? E->getModificationTime() : 0; +} + +uint64_t ASTWriter::WriteAST(Sema &SemaRef, const std::string &OutputFile, + Module *WritingModule, StringRef isysroot, + bool hasErrors) { WritingAST = true; - + ASTHasCompilerErrors = hasErrors; // Emit the file header. @@ -4079,13 +4077,15 @@ void ASTWriter::WriteAST(Sema &SemaRef, Context = &SemaRef.Context; PP = &SemaRef.PP; this->WritingModule = WritingModule; - WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule); + ASTFileSignature Signature = + WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule); Context = nullptr; PP = nullptr; this->WritingModule = nullptr; this->BaseDirectory.clear(); WritingAST = false; + return Signature; } template<typename Vector> @@ -4097,10 +4097,9 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec, } } -void ASTWriter::WriteASTCore(Sema &SemaRef, - StringRef isysroot, - const std::string &OutputFile, - Module *WritingModule) { +uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, + const std::string &OutputFile, + Module *WritingModule) { using namespace llvm; bool isModule = WritingModule != nullptr; @@ -4117,8 +4116,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, if (D) { assert(D->isCanonicalDecl() && "predefined decl is not canonical"); DeclIDs[D] = ID; - if (D->getMostRecentDecl() != D) - Redeclarations.push_back(D); } }; RegisterPredefDecl(Context.getTranslationUnitDecl(), @@ -4133,7 +4130,12 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, RegisterPredefDecl(Context.ObjCInstanceTypeDecl, PREDEF_DECL_OBJC_INSTANCETYPE_ID); RegisterPredefDecl(Context.BuiltinVaListDecl, PREDEF_DECL_BUILTIN_VA_LIST_ID); + RegisterPredefDecl(Context.VaListTagDecl, PREDEF_DECL_VA_LIST_TAG); + RegisterPredefDecl(Context.BuiltinMSVaListDecl, + PREDEF_DECL_BUILTIN_MS_VA_LIST_ID); RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID); + RegisterPredefDecl(Context.MakeIntegerSeqDecl, + PREDEF_DECL_MAKE_INTEGER_SEQ_ID); // Build a record containing all of the tentative definitions in this file, in // TentativeDefinitions order. Generally, this record will be empty for @@ -4187,11 +4189,9 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // Build a record containing all of pending implicit instantiations. RecordData PendingInstantiations; - for (std::deque<Sema::PendingImplicitInstantiation>::iterator - I = SemaRef.PendingInstantiations.begin(), - N = SemaRef.PendingInstantiations.end(); I != N; ++I) { - AddDeclRef(I->first, PendingInstantiations); - AddSourceLocation(I->second, PendingInstantiations); + for (const auto &I : SemaRef.PendingInstantiations) { + AddDeclRef(I.first, PendingInstantiations); + AddSourceLocation(I.second, PendingInstantiations); } assert(SemaRef.PendingLocalImplicitInstantiations.empty() && "There are local ones at end of translation unit!"); @@ -4210,12 +4210,9 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // Build a record containing all of the known namespaces. RecordData KnownNamespaces; - for (llvm::MapVector<NamespaceDecl*, bool>::iterator - I = SemaRef.KnownNamespaces.begin(), - IEnd = SemaRef.KnownNamespaces.end(); - I != IEnd; ++I) { - if (!I->second) - AddDeclRef(I->first, KnownNamespaces); + for (const auto &I : SemaRef.KnownNamespaces) { + if (!I.second) + AddDeclRef(I.first, KnownNamespaces); } // Build a record of all used, undefined objects that require definitions. @@ -4223,10 +4220,9 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, 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); + for (const auto &I : Undefined) { + AddDeclRef(I.first, UndefinedButUsed); + AddSourceLocation(I.second, UndefinedButUsed); } // Build a record containing all delete-expressions that we would like to @@ -4244,41 +4240,43 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, } // Write the control block - WriteControlBlock(PP, Context, isysroot, OutputFile); + uint64_t Signature = WriteControlBlock(PP, Context, isysroot, OutputFile); // Write the remaining AST contents. - 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); + { + RecordData Record = {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(); - SmallVector<KindDeclIDPair, 64> NewGlobalDecls; - for (const auto *I : TU->noload_decls()) { - if (!I->isFromASTFile()) - NewGlobalDecls.push_back(std::make_pair(I->getKind(), GetDeclRef(I))); + SmallVector<uint32_t, 128> NewGlobalKindDeclPairs; + for (const auto *D : TU->noload_decls()) { + if (!D->isFromASTFile()) { + NewGlobalKindDeclPairs.push_back(D->getKind()); + NewGlobalKindDeclPairs.push_back(GetDeclRef(D)); + } } - llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev(); + auto *Abv = new llvm::BitCodeAbbrev(); Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(Abv); - Record.clear(); - Record.push_back(TU_UPDATE_LEXICAL); - Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, - bytes(NewGlobalDecls)); - + { + RecordData::value_type Record[] = {TU_UPDATE_LEXICAL}; + Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, + bytes(NewGlobalKindDeclPairs)); + } + // And a visible updates block for the translation unit. Abv = new llvm::BitCodeAbbrev(); Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); - Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, 32)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv); WriteDeclContextVisibleUpdate(TU); @@ -4310,29 +4308,27 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // Make sure visible decls, added to DeclContexts previously loaded from // an AST file, are registered for serialization. - for (SmallVectorImpl<const Decl *>::iterator - I = UpdatingVisibleDecls.begin(), - E = UpdatingVisibleDecls.end(); I != E; ++I) { - GetDeclRef(*I); + for (const auto *I : UpdatingVisibleDecls) { + GetDeclRef(I); } // Make sure all decls associated with an identifier are registered for - // serialization. - llvm::SmallVector<const IdentifierInfo*, 256> IIs; - for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(), - IDEnd = PP.getIdentifierTable().end(); - ID != IDEnd; ++ID) { - const IdentifierInfo *II = ID->second; - if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization()) - IIs.push_back(II); - } - // Sort the identifiers to visit based on their name. - std::sort(IIs.begin(), IIs.end(), llvm::less_ptr<IdentifierInfo>()); - for (const IdentifierInfo *II : IIs) { - for (IdentifierResolver::iterator D = SemaRef.IdResolver.begin(II), - DEnd = SemaRef.IdResolver.end(); - D != DEnd; ++D) { - GetDeclRef(*D); + // serialization, if we're storing decls with identifiers. + if (!WritingModule || !getLangOpts().CPlusPlus) { + llvm::SmallVector<const IdentifierInfo*, 256> IIs; + for (const auto &ID : PP.getIdentifierTable()) { + const IdentifierInfo *II = ID.second; + if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization()) + IIs.push_back(II); + } + // Sort the identifiers to visit based on their name. + std::sort(IIs.begin(), IIs.end(), llvm::less_ptr<IdentifierInfo>()); + for (const IdentifierInfo *II : IIs) { + for (IdentifierResolver::iterator D = SemaRef.IdResolver.begin(II), + DEnd = SemaRef.IdResolver.end(); + D != DEnd; ++D) { + GetDeclRef(*D); + } } } @@ -4363,7 +4359,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // c++-base-specifiers-id:i32 // type-id:i32) // - llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + auto *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(Abbrev); @@ -4402,8 +4398,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, writeBaseIDOrNone(M->BaseTypeIndex, M->LocalNumTypes); } } - Record.clear(); - Record.push_back(MODULE_OFFSET_MAP); + RecordData::value_type Record[] = {MODULE_OFFSET_MAP}; Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record, Buffer.data(), Buffer.size()); } @@ -4415,10 +4410,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5); WriteTypeAbbrevs(); WriteDeclAbbrevs(); - for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(), - E = DeclsToRewrite.end(); - I != E; ++I) - DeclTypesToEmit.push(const_cast<Decl*>(*I)); do { WriteDeclUpdatesBlocks(DeclUpdatesOffsetsRecord); while (!DeclTypesToEmit.empty()) { @@ -4442,12 +4433,12 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, WriteCXXCtorInitializersOffsets(); WriteFileDeclIDsMap(); WriteSourceManagerBlock(Context.getSourceManager(), PP); - WriteComments(); WritePreprocessor(PP, isModule); WriteHeaderSearch(PP.getHeaderSearchInfo()); WriteSelectors(SemaRef); WriteReferencedSelectorsPool(SemaRef); + WriteLateParsedTemplates(SemaRef); WriteIdentifierTable(PP, SemaRef.IdResolver, isModule); WriteFPPragmaOptions(SemaRef.getFPOptions()); WriteOpenCLExtensions(SemaRef); @@ -4561,20 +4552,21 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, } WriteDeclReplacementsBlock(); - WriteRedeclarations(); WriteObjCCategories(); - WriteLateParsedTemplates(SemaRef); if(!WritingModule) WriteOptimizePragmaOptions(SemaRef); // Some simple statistics - Record.clear(); - Record.push_back(NumStatements); - Record.push_back(NumMacros); - Record.push_back(NumLexicalDeclContexts); - Record.push_back(NumVisibleDeclContexts); + RecordData::value_type Record[] = { + NumStatements, NumMacros, NumLexicalDeclContexts, NumVisibleDeclContexts}; Stream.EmitRecord(STATISTICS, Record); Stream.ExitBlock(); + + // Write the module file extension blocks. + for (const auto &ExtWriter : ModuleFileExtensionWriters) + WriteModuleFileExtension(SemaRef, *ExtWriter); + + return Signature; } void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { @@ -4586,8 +4578,6 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { for (auto &DeclUpdate : LocalUpdates) { const Decl *D = DeclUpdate.first; - if (isRewritten(D)) - continue; // The decl will be written completely,no need to store updates. bool HasUpdatedBody = false; RecordData Record; @@ -4699,7 +4689,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { } if (HasUpdatedBody) { - const FunctionDecl *Def = cast<FunctionDecl>(D); + const auto *Def = cast<FunctionDecl>(D); Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION); Record.push_back(Def->isInlined()); AddSourceLocation(Def->getInnerLocStart(), Record); @@ -4720,11 +4710,10 @@ void ASTWriter::WriteDeclReplacementsBlock() { return; RecordData Record; - for (SmallVectorImpl<ReplacedDeclInfo>::iterator - I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) { - Record.push_back(I->ID); - Record.push_back(I->Offset); - Record.push_back(I->Loc); + for (const auto &I : ReplacedDecls) { + Record.push_back(I.ID); + Record.push_back(I.Offset); + Record.push_back(I.Loc); } Stream.EmitRecord(DECL_REPLACEMENTS, Record); } @@ -5247,9 +5236,8 @@ void ASTWriter::AddTemplateName(TemplateName Name, RecordDataImpl &Record) { case TemplateName::OverloadedTemplate: { OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate(); Record.push_back(OvT->size()); - for (OverloadedTemplateStorage::iterator I = OvT->begin(), E = OvT->end(); - I != E; ++I) - AddDeclRef(*I, Record); + for (const auto &I : *OvT) + AddDeclRef(I, Record); break; } @@ -5339,10 +5327,8 @@ ASTWriter::AddTemplateParameterList(const TemplateParameterList *TemplateParams, AddSourceLocation(TemplateParams->getLAngleLoc(), Record); AddSourceLocation(TemplateParams->getRAngleLoc(), Record); Record.push_back(TemplateParams->size()); - for (TemplateParameterList::const_iterator - P = TemplateParams->begin(), PEnd = TemplateParams->end(); - P != PEnd; ++P) - AddDeclRef(*P, Record); + for (const auto &P : *TemplateParams) + AddDeclRef(P, Record); } /// \brief Emit a template argument list. @@ -5657,7 +5643,7 @@ void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) { void ASTWriter::CompletedTagDefinition(const TagDecl *D) { assert(D->isCompleteDefinition()); assert(!WritingAST && "Already writing the AST!"); - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + if (auto *RD = dyn_cast<CXXRecordDecl>(D)) { // We are interested when a PCH decl is modified. if (RD->isFromASTFile()) { // A forward reference was mutated into a definition. Rewrite it. @@ -5671,26 +5657,52 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) { } } +static bool isImportedDeclContext(ASTReader *Chain, const Decl *D) { + if (D->isFromASTFile()) + return true; + + // If we've not loaded any modules, this can't be imported. + if (!Chain || !Chain->getModuleManager().size()) + return false; + + // The predefined __va_list_tag struct is imported if we imported any decls. + // FIXME: This is a gross hack. + return D == D->getASTContext().getVaListTagDecl(); +} + void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) { // TU and namespaces are handled elsewhere. if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC)) return; - if (!(!D->isFromASTFile() && cast<Decl>(DC)->isFromASTFile())) - return; // Not a source decl added to a DeclContext from PCH. + // We're only interested in cases where a local declaration is added to an + // imported context. + if (D->isFromASTFile() || !isImportedDeclContext(Chain, cast<Decl>(DC))) + return; + assert(DC == DC->getPrimaryContext() && "added to non-primary context"); assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!"); assert(!WritingAST && "Already writing the AST!"); - UpdatedDeclContexts.insert(DC); + if (UpdatedDeclContexts.insert(DC) && !cast<Decl>(DC)->isFromASTFile()) { + // We're adding a visible declaration to a predefined decl context. Ensure + // that we write out all of its lookup results so we don't get a nasty + // surprise when we try to emit its lookup table. + for (auto *Child : DC->decls()) + UpdatingVisibleDecls.push_back(Child); + } UpdatingVisibleDecls.push_back(D); } void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) { assert(D->isImplicit()); - if (!(!D->isFromASTFile() && RD->isFromASTFile())) - return; // Not a source member added to a class from PCH. + + // We're only interested in cases where a local declaration is added to an + // imported context. + if (D->isFromASTFile() || !isImportedDeclContext(Chain, RD)) + return; + if (!isa<CXXMethodDecl>(D)) - return; // We are interested in lazily declared implicit methods. + return; // A decl coming from PCH was modified. assert(RD->isCompleteDefinition()); @@ -5698,42 +5710,6 @@ void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) { DeclUpdates[RD].push_back(DeclUpdate(UPD_CXX_ADDED_IMPLICIT_MEMBER, D)); } -void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, - const ClassTemplateSpecializationDecl *D) { - // The specializations set is kept in the canonical template. - TD = TD->getCanonicalDecl(); - if (!(!D->isFromASTFile() && TD->isFromASTFile())) - return; // Not a source specialization added to a template from PCH. - - assert(!WritingAST && "Already writing the AST!"); - DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, - D)); -} - -void ASTWriter::AddedCXXTemplateSpecialization( - const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) { - // The specializations set is kept in the canonical template. - TD = TD->getCanonicalDecl(); - if (!(!D->isFromASTFile() && TD->isFromASTFile())) - return; // Not a source specialization added to a template from PCH. - - assert(!WritingAST && "Already writing the AST!"); - DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, - D)); -} - -void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, - const FunctionDecl *D) { - // The specializations set is kept in the canonical template. - TD = TD->getCanonicalDecl(); - if (!(!D->isFromASTFile() && TD->isFromASTFile())) - return; // Not a source specialization added to a template from PCH. - - assert(!WritingAST && "Already writing the AST!"); - DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, - D)); -} - void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) { assert(!DoneWritingDeclsAndTypes && "Already done writing updates!"); if (!Chain) return; @@ -5807,21 +5783,6 @@ void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const_cast<ObjCInterfaceDecl *>(IFD->getDefinition())); } - -void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop, - const ObjCPropertyDecl *OrigProp, - const ObjCCategoryDecl *ClassExt) { - const ObjCInterfaceDecl *D = ClassExt->getClassInterface(); - if (!D) - return; - - assert(!WritingAST && "Already writing the AST!"); - if (!D->isFromASTFile()) - return; // Declaration not imported from PCH. - - RewriteDecl(D); -} - void ASTWriter::DeclarationMarkedUsed(const Decl *D) { assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp index fd6708dd5c3f..20ca6d6fd512 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp @@ -159,6 +159,22 @@ namespace clang { Writer.AddStmt(FD->getBody()); } + /// Add to the record the first declaration from each module file that + /// provides a declaration of D. The intent is to provide a sufficient + /// set such that reloading this set will load all current redeclarations. + void AddFirstDeclFromEachModule(const Decl *D, bool IncludeLocal) { + llvm::MapVector<ModuleFile*, const Decl*> Firsts; + // FIXME: We can skip entries that we know are implied by others. + for (const Decl *R = D->getMostRecentDecl(); R; R = R->getPreviousDecl()) { + if (R->isFromASTFile()) + Firsts[Writer.Chain->getOwningModuleFile(R)] = R; + else if (IncludeLocal) + Firsts[nullptr] = R; + } + for (const auto &F : Firsts) + Writer.AddDeclRef(F.second, Record); + } + /// Get the specialization decl from an entry in the specialization list. template <typename EntryType> typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType * @@ -192,22 +208,48 @@ namespace clang { auto &&PartialSpecializations = getPartialSpecializations(Common); ArrayRef<DeclID> LazySpecializations; if (auto *LS = Common->LazySpecializations) - LazySpecializations = ArrayRef<DeclID>(LS + 1, LS + 1 + LS[0]); + LazySpecializations = llvm::makeArrayRef(LS + 1, LS[0]); + + // Add a slot to the record for the number of specializations. + unsigned I = Record.size(); + Record.push_back(0); - Record.push_back(Specializations.size() + - PartialSpecializations.size() + - LazySpecializations.size()); for (auto &Entry : Specializations) { auto *D = getSpecializationDecl(Entry); assert(D->isCanonicalDecl() && "non-canonical decl in set"); - Writer.AddDeclRef(D, Record); + AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); } for (auto &Entry : PartialSpecializations) { auto *D = getSpecializationDecl(Entry); assert(D->isCanonicalDecl() && "non-canonical decl in set"); - Writer.AddDeclRef(D, Record); + AddFirstDeclFromEachModule(D, /*IncludeLocal*/true); } Record.append(LazySpecializations.begin(), LazySpecializations.end()); + + // Update the size entry we added earlier. + Record[I] = Record.size() - I - 1; + } + + /// Ensure that this template specialization is associated with the specified + /// template on reload. + void RegisterTemplateSpecialization(const Decl *Template, + const Decl *Specialization) { + Template = Template->getCanonicalDecl(); + + // If the canonical template is local, we'll write out this specialization + // when we emit it. + // FIXME: We can do the same thing if there is any local declaration of + // the template, to avoid emitting an update record. + if (!Template->isFromASTFile()) + return; + + // We only need to associate the first local declaration of the + // specialization. The other declarations will get pulled in by it. + if (Writer.getFirstLocalDecl(Specialization) != Specialization) + return; + + Writer.DeclUpdates[Template].push_back(ASTWriter::DeclUpdate( + UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, Specialization)); } }; } @@ -218,7 +260,7 @@ void ASTDeclWriter::Visit(Decl *D) { // Source locations require array (variable-length) abbreviations. The // abbreviation infrastructure requires that arrays are encoded last, so // we handle it here in the case of those classes derived from DeclaratorDecl - if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)){ + if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { Writer.AddTypeSourceInfo(DD->getTypeSourceInfo(), Record); } @@ -234,7 +276,10 @@ void ASTDeclWriter::Visit(Decl *D) { void ASTDeclWriter::VisitDecl(Decl *D) { Writer.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()), Record); - Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record); + if (D->getDeclContext() != D->getLexicalDeclContext()) + Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record); + else + Record.push_back(0); Record.push_back(D->isInvalidDecl()); Record.push_back(D->hasAttrs()); if (D->hasAttrs()) @@ -298,7 +343,8 @@ void ASTDeclWriter::VisitTypedefNameDecl(TypedefNameDecl *D) { void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) { VisitTypedefNameDecl(D); - if (!D->hasAttrs() && + if (D->getDeclContext() == D->getLexicalDeclContext() && + !D->hasAttrs() && !D->isImplicit() && D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() && @@ -336,9 +382,6 @@ void ASTDeclWriter::VisitTagDecl(TagDecl *D) { Record.push_back(2); Writer.AddDeclRef(TD, Record); Writer.AddIdentifierRef(TD->getDeclName().getAsIdentifierInfo(), Record); - } else if (auto *DD = D->getDeclaratorForAnonDecl()) { - Record.push_back(3); - Writer.AddDeclRef(DD, Record); } else { Record.push_back(0); } @@ -363,12 +406,12 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) { Writer.AddDeclRef(nullptr, Record); } - if (!D->hasAttrs() && + if (D->getDeclContext() == D->getLexicalDeclContext() && + !D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && !D->hasExtInfo() && !D->getTypedefNameForAnonDecl() && - !D->getDeclaratorForAnonDecl() && D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() && !D->isReferenced() && @@ -392,12 +435,12 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) { Record.push_back(D->hasObjectMember()); Record.push_back(D->hasVolatileMember()); - if (!D->hasAttrs() && + if (D->getDeclContext() == D->getLexicalDeclContext() && + !D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && !D->hasExtInfo() && !D->getTypedefNameForAnonDecl() && - !D->getDeclaratorForAnonDecl() && D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() && !D->isReferenced() && @@ -479,6 +522,9 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { case FunctionDecl::TK_FunctionTemplateSpecialization: { FunctionTemplateSpecializationInfo * FTSInfo = D->getTemplateSpecializationInfo(); + + RegisterTemplateSpecialization(FTSInfo->getTemplate(), D); + Writer.AddDeclRef(FTSInfo->getTemplate(), Record); Record.push_back(FTSInfo->getTemplateSpecializationKind()); @@ -648,7 +694,8 @@ void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) { Record.push_back(D->getAccessControl()); Record.push_back(D->getSynthesize()); - if (!D->hasAttrs() && + if (D->getDeclContext() == D->getLexicalDeclContext() && + !D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && !D->isInvalidDecl() && @@ -780,7 +827,8 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { if (!D->getDeclName()) Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record); - if (!D->hasAttrs() && + if (D->getDeclContext() == D->getLexicalDeclContext() && + !D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && !D->isInvalidDecl() && @@ -854,7 +902,8 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { Record.push_back(VarNotTemplate); } - if (!D->hasAttrs() && + if (D->getDeclContext() == D->getLexicalDeclContext() && + !D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && !D->isInvalidDecl() && @@ -902,7 +951,8 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here // we dynamically check for the properties that we optimize for, but don't // know are true of all PARM_VAR_DECLs. - if (!D->hasAttrs() && + if (D->getDeclContext() == D->getLexicalDeclContext() && + !D->hasAttrs() && !D->hasExtInfo() && !D->isImplicit() && !D->isUsed(false) && @@ -1122,7 +1172,8 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) { Record.push_back(0); } - if (D->getFirstDecl() == D->getMostRecentDecl() && + if (D->getDeclContext() == D->getLexicalDeclContext() && + D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() && !D->hasAttrs() && !D->isTopLevelDeclInObjCContainer() && @@ -1249,6 +1300,8 @@ void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) { void ASTDeclWriter::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D) { + RegisterTemplateSpecialization(D->getSpecializedTemplate(), D); + VisitCXXRecordDecl(D); llvm::PointerUnion<ClassTemplateDecl *, @@ -1308,6 +1361,8 @@ void ASTDeclWriter::VisitVarTemplateDecl(VarTemplateDecl *D) { void ASTDeclWriter::VisitVarTemplateSpecializationDecl( VarTemplateSpecializationDecl *D) { + RegisterTemplateSpecialization(D->getSpecializedTemplate(), D); + VisitVarDecl(D); llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> @@ -1478,48 +1533,77 @@ void ASTDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, Record.push_back(VisibleOffset); } -/// Determine whether D is the first declaration in its redeclaration chain that -/// is not from an AST file. -template <typename T> -static bool isFirstLocalDecl(Redeclarable<T> *D) { - assert(D && !static_cast<T*>(D)->isFromASTFile()); - do - D = D->getPreviousDecl(); - while (D && static_cast<T*>(D)->isFromASTFile()); - return !D; +const Decl *ASTWriter::getFirstLocalDecl(const Decl *D) { + /// \brief Is this a local declaration (that is, one that will be written to + /// our AST file)? This is the case for declarations that are neither imported + /// from another AST file nor predefined. + auto IsLocalDecl = [&](const Decl *D) -> bool { + if (D->isFromASTFile()) + return false; + auto I = DeclIDs.find(D); + return (I == DeclIDs.end() || I->second >= NUM_PREDEF_DECL_IDS); + }; + + assert(IsLocalDecl(D) && "expected a local declaration"); + + const Decl *Canon = D->getCanonicalDecl(); + if (IsLocalDecl(Canon)) + return Canon; + + const Decl *&CacheEntry = FirstLocalDeclCache[Canon]; + if (CacheEntry) + return CacheEntry; + + for (const Decl *Redecl = D; Redecl; Redecl = Redecl->getPreviousDecl()) + if (IsLocalDecl(Redecl)) + D = Redecl; + return CacheEntry = D; } template <typename T> void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) { T *First = D->getFirstDecl(); T *MostRecent = First->getMostRecentDecl(); + T *DAsT = static_cast<T *>(D); if (MostRecent != First) { - assert(isRedeclarableDeclKind(static_cast<T *>(D)->getKind()) && + assert(isRedeclarableDeclKind(DAsT->getKind()) && "Not considered redeclarable?"); Writer.AddDeclRef(First, Record); - // In a modules build, emit a list of all imported key declarations - // (excluding First, if it was imported), so that we can be sure that all - // redeclarations visible to this module are before D in the redecl chain. - unsigned I = Record.size(); - Record.push_back(0); - if (Context.getLangOpts().Modules && Writer.Chain) { - if (isFirstLocalDecl(D)) { - Writer.Chain->forEachImportedKeyDecl(First, [&](const Decl *D) { - if (D != First) - Writer.AddDeclRef(D, Record); - }); - Record[I] = Record.size() - I - 1; - - // Write a redeclaration chain, attached to the first key decl. - Writer.Redeclarations.push_back(Writer.Chain->getKeyDeclaration(First)); + // Write out a list of local redeclarations of this declaration if it's the + // first local declaration in the chain. + const Decl *FirstLocal = Writer.getFirstLocalDecl(DAsT); + if (DAsT == FirstLocal) { + // Emit a list of all imported first declarations so that we can be sure + // that all redeclarations visible to this module are before D in the + // redecl chain. + unsigned I = Record.size(); + Record.push_back(0); + if (Writer.Chain) + AddFirstDeclFromEachModule(DAsT, /*IncludeLocal*/false); + // This is the number of imported first declarations + 1. + Record[I] = Record.size() - I; + + // Collect the set of local redeclarations of this declaration, from + // newest to oldest. + RecordData LocalRedecls; + for (const Decl *Prev = FirstLocal->getMostRecentDecl(); + Prev != FirstLocal; Prev = Prev->getPreviousDecl()) + if (!Prev->isFromASTFile()) + Writer.AddDeclRef(Prev, LocalRedecls); + + // If we have any redecls, write them now as a separate record preceding + // the declaration itself. + if (LocalRedecls.empty()) + Record.push_back(0); + else { + Record.push_back(Writer.Stream.GetCurrentBitNo()); + Writer.Stream.EmitRecord(LOCAL_REDECLARATIONS, LocalRedecls); } - } else if (D == First || D->getPreviousDecl()->isFromASTFile()) { - assert(isFirstLocalDecl(D) && "imported decl after local decl"); - - // Write a redeclaration chain attached to the first decl. - Writer.Redeclarations.push_back(First); + } else { + Record.push_back(0); + Writer.AddDeclRef(FirstLocal, Record); } // Make sure that we serialize both the previous and the most-recent @@ -1558,7 +1642,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(serialization::DECL_FIELD)); // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit @@ -1591,7 +1675,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(serialization::DECL_OBJC_IVAR)); // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit @@ -1629,7 +1713,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit @@ -1677,7 +1761,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit @@ -1720,7 +1804,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit @@ -1767,7 +1851,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit @@ -1796,7 +1880,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit @@ -1842,7 +1926,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // CanonicalDecl // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // Invalid Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Implicit @@ -1977,7 +2061,6 @@ void ASTWriter::WriteDeclAbbrevs() { Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_VISIBLE)); - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); DeclContextVisibleLookupAbbrev = Stream.EmitAbbrev(Abv); } @@ -1994,14 +2077,19 @@ void ASTWriter::WriteDeclAbbrevs() { /// clients to use a separate API call to "realize" the decl. This should be /// relatively painless since they would presumably only do it for top-level /// decls. -static bool isRequiredDecl(const Decl *D, ASTContext &Context) { +static bool isRequiredDecl(const Decl *D, ASTContext &Context, + bool WritingModule) { // An ObjCMethodDecl is never considered as "required" because its // implementation container always is. - // File scoped assembly or obj-c implementation must be seen. ImportDecl is - // used by codegen to determine the set of imported modules to search for - // inputs for automatic linking. - if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D) || isa<ImportDecl>(D)) + // File scoped assembly or obj-c implementation must be seen. + if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D)) + return true; + + // ImportDecl is used by codegen to determine the set of imported modules to + // search for inputs for automatic linking; include it if it has a semantic + // effect. + if (isa<ImportDecl>(D) && !WritingModule) return true; return Context.DeclMustBeEmitted(D); @@ -2016,16 +2104,12 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { // Determine the ID for this declaration. serialization::DeclID ID; - if (D->isFromASTFile()) { - assert(isRewritten(D) && "should not be emitting imported decl"); - ID = getDeclID(D); - } else { - serialization::DeclID &IDR = DeclIDs[D]; - if (IDR == 0) - IDR = NextDeclID++; + assert(!D->isFromASTFile() && "should not be emitting imported decl"); + serialization::DeclID &IDR = DeclIDs[D]; + if (IDR == 0) + IDR = NextDeclID++; - ID= IDR; - } + ID = IDR; bool isReplacingADecl = ID < FirstDeclID; @@ -2050,6 +2134,13 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { VisibleOffset = WriteDeclContextVisibleBlock(Context, DC); } + // Build a record for this declaration + Record.clear(); + W.Code = (serialization::DeclCode)0; + W.AbbrevToUse = 0; + W.Visit(D); + if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); + if (isReplacingADecl) { // We're replacing a decl in a previous file. ReplacedDecls.push_back(ReplacedDeclInfo(ID, Stream.GetCurrentBitNo(), @@ -2066,19 +2157,12 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { DeclOffsets[Index].setLocation(Loc); DeclOffsets[Index].BitOffset = Stream.GetCurrentBitNo(); } - + SourceManager &SM = Context.getSourceManager(); if (Loc.isValid() && SM.isLocalSourceLocation(Loc)) associateDeclWithFile(D, ID); } - // Build and emit a record for this declaration - Record.clear(); - W.Code = (serialization::DeclCode)0; - W.AbbrevToUse = 0; - W.Visit(D); - if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); - if (!W.Code) llvm::report_fatal_error(StringRef("unexpected declaration kind '") + D->getDeclKindName() + "'"); @@ -2090,7 +2174,7 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { // Note declarations that should be deserialized eagerly so that we can add // them to a record in the AST file later. - if (isRequiredDecl(D, Context)) + if (isRequiredDecl(D, Context, WritingModule)) EagerlyDeserializedDecls.push_back(ID); } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp index 0dd809036a3d..e52ed052d3bc 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp @@ -40,7 +40,8 @@ namespace clang { ASTStmtWriter(ASTWriter &Writer, ASTWriter::RecordData &Record) : Writer(Writer), Record(Record) { } - void AddTemplateKWAndArgsInfo(const ASTTemplateKWAndArgsInfo &Args); + void AddTemplateKWAndArgsInfo(const ASTTemplateKWAndArgsInfo &ArgInfo, + const TemplateArgumentLoc *Args); void VisitStmt(Stmt *S); #define STMT(Type, Base) \ @@ -49,13 +50,13 @@ namespace clang { }; } -void ASTStmtWriter:: -AddTemplateKWAndArgsInfo(const ASTTemplateKWAndArgsInfo &Args) { - Writer.AddSourceLocation(Args.getTemplateKeywordLoc(), Record); - Writer.AddSourceLocation(Args.LAngleLoc, Record); - Writer.AddSourceLocation(Args.RAngleLoc, Record); - for (unsigned i=0; i != Args.NumTemplateArgs; ++i) - Writer.AddTemplateArgumentLoc(Args.getTemplateArgs()[i], Record); +void ASTStmtWriter::AddTemplateKWAndArgsInfo( + const ASTTemplateKWAndArgsInfo &ArgInfo, const TemplateArgumentLoc *Args) { + Writer.AddSourceLocation(ArgInfo.TemplateKWLoc, Record); + Writer.AddSourceLocation(ArgInfo.LAngleLoc, Record); + Writer.AddSourceLocation(ArgInfo.RAngleLoc, Record); + for (unsigned i = 0; i != ArgInfo.NumTemplateArgs; ++i) + Writer.AddTemplateArgumentLoc(Args[i], Record); } void ASTStmtWriter::VisitStmt(Stmt *S) { @@ -287,6 +288,26 @@ void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) { Code = serialization::STMT_MSASM; } +void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtWriter::VisitCoreturnStmt(CoreturnStmt *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + +void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); // NumCaptures @@ -366,7 +387,8 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) { Writer.AddDeclRef(E->getFoundDecl(), Record); if (E->hasTemplateKWAndArgsInfo()) - AddTemplateKWAndArgsInfo(*E->getTemplateKWAndArgsInfo()); + AddTemplateKWAndArgsInfo(*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), + E->getTrailingObjects<TemplateArgumentLoc>()); Writer.AddDeclRef(E->getDecl(), Record); Writer.AddSourceLocation(E->getLocation(), Record); @@ -462,24 +484,24 @@ void ASTStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) { Writer.AddSourceLocation(E->getRParenLoc(), Record); Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record); for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { - const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I); + const OffsetOfNode &ON = E->getComponent(I); Record.push_back(ON.getKind()); // FIXME: Stable encoding Writer.AddSourceLocation(ON.getSourceRange().getBegin(), Record); Writer.AddSourceLocation(ON.getSourceRange().getEnd(), Record); switch (ON.getKind()) { - case OffsetOfExpr::OffsetOfNode::Array: + case OffsetOfNode::Array: Record.push_back(ON.getArrayExprIndex()); break; - - case OffsetOfExpr::OffsetOfNode::Field: + + case OffsetOfNode::Field: Writer.AddDeclRef(ON.getField(), Record); break; - - case OffsetOfExpr::OffsetOfNode::Identifier: + + case OffsetOfNode::Identifier: Writer.AddIdentifierRef(ON.getFieldName(), Record); break; - - case OffsetOfExpr::OffsetOfNode::Base: + + case OffsetOfNode::Base: Writer.AddCXXBaseSpecifier(*ON.getBase(), Record); break; } @@ -511,6 +533,16 @@ void ASTStmtWriter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { Code = serialization::EXPR_ARRAY_SUBSCRIPT; } +void ASTStmtWriter::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { + VisitExpr(E); + Writer.AddStmt(E->getBase()); + Writer.AddStmt(E->getLowerBound()); + Writer.AddStmt(E->getLength()); + Writer.AddSourceLocation(E->getColonLoc(), Record); + Writer.AddSourceLocation(E->getRBracketLoc(), Record); + Code = serialization::EXPR_OMP_ARRAY_SECTION; +} + void ASTStmtWriter::VisitCallExpr(CallExpr *E) { VisitExpr(E); Record.push_back(E->getNumArgs()); @@ -761,6 +793,7 @@ void ASTStmtWriter::VisitVAArgExpr(VAArgExpr *E) { Writer.AddTypeSourceInfo(E->getWrittenTypeInfo(), Record); Writer.AddSourceLocation(E->getBuiltinLoc(), Record); Writer.AddSourceLocation(E->getRParenLoc(), Record); + Record.push_back(E->isMicrosoftABI()); Code = serialization::EXPR_VA_ARG; } @@ -1124,6 +1157,7 @@ void ASTStmtWriter::VisitCXXTryStmt(CXXTryStmt *S) { void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { VisitStmt(S); Writer.AddSourceLocation(S->getForLoc(), Record); + Writer.AddSourceLocation(S->getCoawaitLoc(), Record); Writer.AddSourceLocation(S->getColonLoc(), Record); Writer.AddSourceLocation(S->getRParenLoc(), Record); Writer.AddStmt(S->getRangeStmt()); @@ -1408,9 +1442,11 @@ ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ Record.push_back(E->HasTemplateKWAndArgsInfo); if (E->HasTemplateKWAndArgsInfo) { - const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo(); - Record.push_back(Args.NumTemplateArgs); - AddTemplateKWAndArgsInfo(Args); + const ASTTemplateKWAndArgsInfo &ArgInfo = + *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(); + Record.push_back(ArgInfo.NumTemplateArgs); + AddTemplateKWAndArgsInfo(ArgInfo, + E->getTrailingObjects<TemplateArgumentLoc>()); } if (!E->isImplicitAccess()) @@ -1435,9 +1471,11 @@ ASTStmtWriter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { Record.push_back(E->HasTemplateKWAndArgsInfo); if (E->HasTemplateKWAndArgsInfo) { - const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo(); - Record.push_back(Args.NumTemplateArgs); - AddTemplateKWAndArgsInfo(Args); + const ASTTemplateKWAndArgsInfo &ArgInfo = + *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(); + Record.push_back(ArgInfo.NumTemplateArgs); + AddTemplateKWAndArgsInfo(ArgInfo, + E->getTrailingObjects<TemplateArgumentLoc>()); } Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record); @@ -1466,9 +1504,10 @@ void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) { Record.push_back(E->HasTemplateKWAndArgsInfo); if (E->HasTemplateKWAndArgsInfo) { - const ASTTemplateKWAndArgsInfo &Args = *E->getTemplateKWAndArgsInfo(); - Record.push_back(Args.NumTemplateArgs); - AddTemplateKWAndArgsInfo(Args); + const ASTTemplateKWAndArgsInfo &ArgInfo = + *E->getTrailingASTTemplateKWAndArgsInfo(); + Record.push_back(ArgInfo.NumTemplateArgs); + AddTemplateKWAndArgsInfo(ArgInfo, E->getTrailingTemplateArgumentLoc()); } Record.push_back(E->getNumDecls()); @@ -1547,11 +1586,18 @@ void ASTStmtWriter::VisitPackExpansionExpr(PackExpansionExpr *E) { void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) { VisitExpr(E); + Record.push_back(E->isPartiallySubstituted() ? E->getPartialArguments().size() + : 0); Writer.AddSourceLocation(E->OperatorLoc, Record); Writer.AddSourceLocation(E->PackLoc, Record); Writer.AddSourceLocation(E->RParenLoc, Record); - Record.push_back(E->Length); Writer.AddDeclRef(E->Pack, Record); + if (E->isPartiallySubstituted()) { + for (const auto &TA : E->getPartialArguments()) + Writer.AddTemplateArgument(TA, Record); + } else if (!E->isValueDependent()) { + Record.push_back(E->getPackLength()); + } Code = serialization::EXPR_SIZEOF_PACK; } @@ -1650,6 +1696,14 @@ void ASTStmtWriter::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { Code = serialization::EXPR_CXX_PROPERTY_REF_EXPR; } +void ASTStmtWriter::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) { + VisitExpr(E); + Writer.AddStmt(E->getBase()); + Writer.AddStmt(E->getIdx()); + Writer.AddSourceLocation(E->getRBracketLoc(), Record); + Code = serialization::EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR; +} + void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); Writer.AddSourceRange(E->getSourceRange(), Record); @@ -1718,6 +1772,9 @@ void OMPClauseWriter::writeClause(OMPClause *C) { } void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) { + Record.push_back(C->getNameModifier()); + Writer->Writer.AddSourceLocation(C->getNameModifierLoc(), Record); + Writer->Writer.AddSourceLocation(C->getColonLoc(), Record); Writer->Writer.AddStmt(C->getCondition()); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); } @@ -1737,6 +1794,11 @@ void OMPClauseWriter::VisitOMPSafelenClause(OMPSafelenClause *C) { Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); } +void OMPClauseWriter::VisitOMPSimdlenClause(OMPSimdlenClause *C) { + Writer->Writer.AddStmt(C->getSimdlen()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); +} + void OMPClauseWriter::VisitOMPCollapseClause(OMPCollapseClause *C) { Writer->Writer.AddStmt(C->getNumForLoops()); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); @@ -1756,14 +1818,21 @@ void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) { void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) { Record.push_back(C->getScheduleKind()); + Record.push_back(C->getFirstScheduleModifier()); + Record.push_back(C->getSecondScheduleModifier()); Writer->Writer.AddStmt(C->getChunkSize()); Writer->Writer.AddStmt(C->getHelperChunkSize()); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); + Writer->Writer.AddSourceLocation(C->getFirstScheduleModifierLoc(), Record); + Writer->Writer.AddSourceLocation(C->getSecondScheduleModifierLoc(), Record); Writer->Writer.AddSourceLocation(C->getScheduleKindLoc(), Record); Writer->Writer.AddSourceLocation(C->getCommaLoc(), Record); } -void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *) {} +void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *C) { + Writer->Writer.AddStmt(C->getNumForLoops()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); +} void OMPClauseWriter::VisitOMPNowaitClause(OMPNowaitClause *) {} @@ -1781,6 +1850,12 @@ void OMPClauseWriter::VisitOMPCaptureClause(OMPCaptureClause *) {} void OMPClauseWriter::VisitOMPSeqCstClause(OMPSeqCstClause *) {} +void OMPClauseWriter::VisitOMPThreadsClause(OMPThreadsClause *) {} + +void OMPClauseWriter::VisitOMPSIMDClause(OMPSIMDClause *) {} + +void OMPClauseWriter::VisitOMPNogroupClause(OMPNogroupClause *) {} + void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Record.push_back(C->varlist_size()); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); @@ -1836,6 +1911,8 @@ void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) { Writer->Writer.AddDeclarationNameInfo(C->getNameInfo(), Record); for (auto *VE : C->varlists()) Writer->Writer.AddStmt(VE); + for (auto *VE : C->privates()) + Writer->Writer.AddStmt(VE); for (auto *E : C->lhs_exprs()) Writer->Writer.AddStmt(E); for (auto *E : C->rhs_exprs()) @@ -1848,9 +1925,14 @@ void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) { Record.push_back(C->varlist_size()); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); Writer->Writer.AddSourceLocation(C->getColonLoc(), Record); + Record.push_back(C->getModifier()); + Writer->Writer.AddSourceLocation(C->getModifierLoc(), Record); for (auto *VE : C->varlists()) { Writer->Writer.AddStmt(VE); } + for (auto *VE : C->privates()) { + Writer->Writer.AddStmt(VE); + } for (auto *VE : C->inits()) { Writer->Writer.AddStmt(VE); } @@ -1916,6 +1998,52 @@ void OMPClauseWriter::VisitOMPDependClause(OMPDependClause *C) { Writer->Writer.AddStmt(VE); } +void OMPClauseWriter::VisitOMPDeviceClause(OMPDeviceClause *C) { + Writer->Writer.AddStmt(C->getDevice()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); +} + +void OMPClauseWriter::VisitOMPMapClause(OMPMapClause *C) { + Record.push_back(C->varlist_size()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); + Record.push_back(C->getMapTypeModifier()); + Record.push_back(C->getMapType()); + Writer->Writer.AddSourceLocation(C->getMapLoc(), Record); + Writer->Writer.AddSourceLocation(C->getColonLoc(), Record); + for (auto *VE : C->varlists()) + Writer->Writer.AddStmt(VE); +} + +void OMPClauseWriter::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) { + Writer->Writer.AddStmt(C->getNumTeams()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); +} + +void OMPClauseWriter::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) { + Writer->Writer.AddStmt(C->getThreadLimit()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); +} + +void OMPClauseWriter::VisitOMPPriorityClause(OMPPriorityClause *C) { + Writer->Writer.AddStmt(C->getPriority()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); +} + +void OMPClauseWriter::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) { + Writer->Writer.AddStmt(C->getGrainsize()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); +} + +void OMPClauseWriter::VisitOMPNumTasksClause(OMPNumTasksClause *C) { + Writer->Writer.AddStmt(C->getNumTasks()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); +} + +void OMPClauseWriter::VisitOMPHintClause(OMPHintClause *C) { + Writer->Writer.AddStmt(C->getHint()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); +} + //===----------------------------------------------------------------------===// // OpenMP Directives. //===----------------------------------------------------------------------===// @@ -1954,6 +2082,9 @@ void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) { for (auto I : D->counters()) { Writer.AddStmt(I); } + for (auto I : D->private_counters()) { + Writer.AddStmt(I); + } for (auto I : D->inits()) { Writer.AddStmt(I); } @@ -1969,6 +2100,7 @@ void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) { VisitStmt(D); Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); Code = serialization::STMT_OMP_PARALLEL_DIRECTIVE; } @@ -1979,6 +2111,7 @@ void ASTStmtWriter::VisitOMPSimdDirective(OMPSimdDirective *D) { void ASTStmtWriter::VisitOMPForDirective(OMPForDirective *D) { VisitOMPLoopDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); Code = serialization::STMT_OMP_FOR_DIRECTIVE; } @@ -1991,12 +2124,14 @@ void ASTStmtWriter::VisitOMPSectionsDirective(OMPSectionsDirective *D) { VisitStmt(D); Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); Code = serialization::STMT_OMP_SECTIONS_DIRECTIVE; } void ASTStmtWriter::VisitOMPSectionDirective(OMPSectionDirective *D) { VisitStmt(D); VisitOMPExecutableDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); Code = serialization::STMT_OMP_SECTION_DIRECTIVE; } @@ -2015,6 +2150,7 @@ void ASTStmtWriter::VisitOMPMasterDirective(OMPMasterDirective *D) { void ASTStmtWriter::VisitOMPCriticalDirective(OMPCriticalDirective *D) { VisitStmt(D); + Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); Writer.AddDeclarationNameInfo(D->getDirectiveName(), Record); Code = serialization::STMT_OMP_CRITICAL_DIRECTIVE; @@ -2022,6 +2158,7 @@ void ASTStmtWriter::VisitOMPCriticalDirective(OMPCriticalDirective *D) { void ASTStmtWriter::VisitOMPParallelForDirective(OMPParallelForDirective *D) { VisitOMPLoopDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); Code = serialization::STMT_OMP_PARALLEL_FOR_DIRECTIVE; } @@ -2036,6 +2173,7 @@ void ASTStmtWriter::VisitOMPParallelSectionsDirective( VisitStmt(D); Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); Code = serialization::STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE; } @@ -2043,6 +2181,7 @@ void ASTStmtWriter::VisitOMPTaskDirective(OMPTaskDirective *D) { VisitStmt(D); Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); + Record.push_back(D->hasCancel() ? 1 : 0); Code = serialization::STMT_OMP_TASK_DIRECTIVE; } @@ -2066,6 +2205,13 @@ void ASTStmtWriter::VisitOMPTargetDirective(OMPTargetDirective *D) { Code = serialization::STMT_OMP_TARGET_DIRECTIVE; } +void ASTStmtWriter::VisitOMPTargetDataDirective(OMPTargetDataDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_TARGET_DATA_DIRECTIVE; +} + void ASTStmtWriter::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *D) { VisitStmt(D); VisitOMPExecutableDirective(D); @@ -2099,6 +2245,7 @@ void ASTStmtWriter::VisitOMPFlushDirective(OMPFlushDirective *D) { void ASTStmtWriter::VisitOMPOrderedDirective(OMPOrderedDirective *D) { VisitStmt(D); + Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); Code = serialization::STMT_OMP_ORDERED_DIRECTIVE; } @@ -2120,11 +2267,27 @@ void ASTStmtWriter::VisitOMPCancellationPointDirective( void ASTStmtWriter::VisitOMPCancelDirective(OMPCancelDirective *D) { VisitStmt(D); + Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); Record.push_back(D->getCancelRegion()); Code = serialization::STMT_OMP_CANCEL_DIRECTIVE; } +void ASTStmtWriter::VisitOMPTaskLoopDirective(OMPTaskLoopDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_TASKLOOP_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPTaskLoopSimdDirective(OMPTaskLoopSimdDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_TASKLOOP_SIMD_DIRECTIVE; +} + +void ASTStmtWriter::VisitOMPDistributeDirective(OMPDistributeDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_DISTRIBUTE_DIRECTIVE; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp b/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp index c461fe936ee4..4a2255ab6d39 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp @@ -23,12 +23,15 @@ using namespace clang; -PCHGenerator::PCHGenerator(const Preprocessor &PP, StringRef OutputFile, - clang::Module *Module, StringRef isysroot, - std::shared_ptr<PCHBuffer> Buffer, - bool AllowASTWithErrors) +PCHGenerator::PCHGenerator( + const Preprocessor &PP, StringRef OutputFile, + clang::Module *Module, StringRef isysroot, + std::shared_ptr<PCHBuffer> Buffer, + ArrayRef<llvm::IntrusiveRefCntPtr<ModuleFileExtension>> Extensions, + bool AllowASTWithErrors, bool IncludeTimestamps) : PP(PP), OutputFile(OutputFile), Module(Module), isysroot(isysroot.str()), - SemaPtr(nullptr), Buffer(Buffer), Stream(Buffer->Data), Writer(Stream), + SemaPtr(nullptr), Buffer(Buffer), Stream(Buffer->Data), + Writer(Stream, Extensions, IncludeTimestamps), AllowASTWithErrors(AllowASTWithErrors) { Buffer->IsComplete = false; } @@ -47,7 +50,8 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { // Emit the PCH file to the Buffer. assert(SemaPtr && "No Sema?"); - Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot, hasErrors); + Buffer->Signature = + Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot, hasErrors); Buffer->IsComplete = true; } diff --git a/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp b/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp index 17c7914243e7..af5f94a5cdc4 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/GlobalModuleIndex.cpp @@ -757,9 +757,7 @@ void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) { unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev); // Write the identifier table - Record.clear(); - Record.push_back(IDENTIFIER_INDEX); - Record.push_back(BucketOffset); + uint64_t Record[] = {IDENTIFIER_INDEX, BucketOffset}; Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable); } diff --git a/contrib/llvm/tools/clang/lib/Serialization/Module.cpp b/contrib/llvm/tools/clang/lib/Serialization/Module.cpp index 3b237d5529c6..4884f0b09480 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/Module.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/Module.cpp @@ -40,19 +40,11 @@ ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation) LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(nullptr), LocalNumCXXCtorInitializers(0), CXXCtorInitializersOffsets(nullptr), FileSortedDecls(nullptr), NumFileSortedDecls(0), - RedeclarationsMap(nullptr), LocalNumRedeclarationsInMap(0), ObjCCategoriesMap(nullptr), LocalNumObjCCategoriesInMap(0), LocalNumTypes(0), TypeOffsets(nullptr), BaseTypeIndex(0) {} ModuleFile::~ModuleFile() { - for (DeclContextInfosMap::iterator I = DeclContextInfos.begin(), - E = DeclContextInfos.end(); - I != E; ++I) { - if (I->second.NameLookupTableData) - delete I->second.NameLookupTableData; - } - delete static_cast<ASTIdentifierLookupTable *>(IdentifierLookupTable); delete static_cast<HeaderFileInfoLookupTable *>(HeaderFileInfoTable); delete static_cast<ASTSelectorLookupTable *>(SelectorLookupTable); diff --git a/contrib/llvm/tools/clang/lib/Serialization/ModuleFileExtension.cpp b/contrib/llvm/tools/clang/lib/Serialization/ModuleFileExtension.cpp new file mode 100644 index 000000000000..81dcfd60ce8e --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ModuleFileExtension.cpp @@ -0,0 +1,22 @@ +//===-- ModuleFileExtension.cpp - Module File Extensions ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "clang/Serialization/ModuleFileExtension.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +ModuleFileExtension::~ModuleFileExtension() { } + +llvm::hash_code ModuleFileExtension::hashExtension(llvm::hash_code Code) const { + return Code; +} + +ModuleFileExtensionWriter::~ModuleFileExtensionWriter() { } + +ModuleFileExtensionReader::~ModuleFileExtensionReader() { } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp index 271619404d2f..74f75a103f7a 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp @@ -95,6 +95,8 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, New->File = Entry; New->ImportLoc = ImportLoc; Chain.push_back(New); + if (!New->isModule()) + PCHChain.push_back(New); if (!ImportedBy) Roots.push_back(New); NewModule = true; @@ -159,6 +161,8 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, Modules.erase(Entry); assert(Chain.back() == ModuleEntry); Chain.pop_back(); + if (!ModuleEntry->isModule()) + PCHChain.pop_back(); if (Roots.back() == ModuleEntry) Roots.pop_back(); else @@ -190,6 +194,9 @@ void ModuleManager::removeModules( if (first == last) return; + // Explicitly clear VisitOrder since we might not notice it is stale. + VisitOrder.clear(); + // Collect the set of module file pointers that we'll be removing. llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last); @@ -203,6 +210,15 @@ void ModuleManager::removeModules( Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim), Roots.end()); + // Remove the modules from the PCH chain. + for (auto I = first; I != last; ++I) { + if (!(*I)->isModule()) { + PCHChain.erase(std::find(PCHChain.begin(), PCHChain.end(), *I), + PCHChain.end()); + break; + } + } + // Delete the modules and erase them from the various structures. for (ModuleIterator victim = first; victim != last; ++victim) { Modules.erase((*victim)->File); @@ -236,15 +252,6 @@ ModuleManager::addInMemoryBuffer(StringRef FileName, InMemoryBuffers[Entry] = std::move(Buffer); } -bool ModuleManager::addKnownModuleFile(StringRef FileName) { - const FileEntry *File; - if (lookupModuleFile(FileName, 0, 0, File)) - return true; - if (!Modules.count(File)) - AdditionalKnownModuleFiles.insert(File); - return false; -} - ModuleManager::VisitState *ModuleManager::allocateVisitState() { // Fast path: if we have a cached state, use it. if (FirstVisitState) { @@ -281,8 +288,6 @@ void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) { } void ModuleManager::moduleFileAccepted(ModuleFile *MF) { - AdditionalKnownModuleFiles.remove(MF->File); - if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF)) return; @@ -300,10 +305,8 @@ ModuleManager::~ModuleManager() { delete FirstVisitState; } -void -ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), - void *UserData, - llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) { +void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor, + llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) { // If the visitation order vector is the wrong size, recompute the order. if (VisitOrder.size() != Chain.size()) { unsigned N = size(); @@ -316,28 +319,24 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), SmallVector<ModuleFile *, 4> Queue; Queue.reserve(N); llvm::SmallVector<unsigned, 4> UnusedIncomingEdges; - UnusedIncomingEdges.reserve(size()); - for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) { - if (unsigned Size = (*M)->ImportedBy.size()) - UnusedIncomingEdges.push_back(Size); - else { - UnusedIncomingEdges.push_back(0); + UnusedIncomingEdges.resize(size()); + for (auto M = rbegin(), MEnd = rend(); M != MEnd; ++M) { + unsigned Size = (*M)->ImportedBy.size(); + UnusedIncomingEdges[(*M)->Index] = Size; + if (!Size) Queue.push_back(*M); - } } // Traverse the graph, making sure to visit a module before visiting any // of its dependencies. - unsigned QueueStart = 0; - while (QueueStart < Queue.size()) { - ModuleFile *CurrentModule = Queue[QueueStart++]; + while (!Queue.empty()) { + ModuleFile *CurrentModule = Queue.pop_back_val(); VisitOrder.push_back(CurrentModule); // For any module that this module depends on, push it on the // stack (if it hasn't already been marked as visited). - for (llvm::SetVector<ModuleFile *>::iterator - M = CurrentModule->Imports.begin(), - MEnd = CurrentModule->Imports.end(); + for (auto M = CurrentModule->Imports.rbegin(), + MEnd = CurrentModule->Imports.rend(); M != MEnd; ++M) { // Remove our current module as an impediment to visiting the // module we depend on. If we were the last unvisited module @@ -379,7 +378,7 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), // Visit the module. assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1); State->VisitNumber[CurrentModule->Index] = VisitNumber; - if (!Visitor(*CurrentModule, UserData)) + if (!Visitor(*CurrentModule)) continue; // The visitor has requested that cut off visitation of any @@ -410,71 +409,6 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), returnVisitState(State); } -static void markVisitedDepthFirst(ModuleFile &M, - SmallVectorImpl<bool> &Visited) { - for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(), - IMEnd = M.Imports.end(); - IM != IMEnd; ++IM) { - if (Visited[(*IM)->Index]) - continue; - Visited[(*IM)->Index] = true; - if (!M.DirectlyImported) - markVisitedDepthFirst(**IM, Visited); - } -} - -/// \brief Perform a depth-first visit of the current module. -static bool visitDepthFirst( - ModuleFile &M, - ModuleManager::DFSPreorderControl (*PreorderVisitor)(ModuleFile &M, - void *UserData), - bool (*PostorderVisitor)(ModuleFile &M, void *UserData), void *UserData, - SmallVectorImpl<bool> &Visited) { - if (PreorderVisitor) { - switch (PreorderVisitor(M, UserData)) { - case ModuleManager::Abort: - return true; - case ModuleManager::SkipImports: - markVisitedDepthFirst(M, Visited); - return false; - case ModuleManager::Continue: - break; - } - } - - // Visit children - for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(), - IMEnd = M.Imports.end(); - IM != IMEnd; ++IM) { - if (Visited[(*IM)->Index]) - continue; - Visited[(*IM)->Index] = true; - - if (visitDepthFirst(**IM, PreorderVisitor, PostorderVisitor, UserData, Visited)) - return true; - } - - if (PostorderVisitor) - return PostorderVisitor(M, UserData); - - return false; -} - -void ModuleManager::visitDepthFirst( - ModuleManager::DFSPreorderControl (*PreorderVisitor)(ModuleFile &M, - void *UserData), - bool (*PostorderVisitor)(ModuleFile &M, void *UserData), void *UserData) { - SmallVector<bool, 16> Visited(size(), false); - for (unsigned I = 0, N = Roots.size(); I != N; ++I) { - if (Visited[Roots[I]->Index]) - continue; - Visited[Roots[I]->Index] = true; - - if (::visitDepthFirst(*Roots[I], PreorderVisitor, PostorderVisitor, UserData, Visited)) - return; - } -} - bool ModuleManager::lookupModuleFile(StringRef FileName, off_t ExpectedSize, time_t ExpectedModTime, diff --git a/contrib/llvm/tools/clang/lib/Serialization/MultiOnDiskHashTable.h b/contrib/llvm/tools/clang/lib/Serialization/MultiOnDiskHashTable.h new file mode 100644 index 000000000000..04dea831695c --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/MultiOnDiskHashTable.h @@ -0,0 +1,330 @@ +//===--- MultiOnDiskHashTable.h - Merged set of hash tables -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a hash table data structure suitable for incremental and +// distributed storage across a set of files. +// +// Multiple hash tables from different files are implicitly merged to improve +// performance, and on reload the merged table will override those from other +// files. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H +#define LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H + +#include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/OnDiskHashTable.h" + +namespace clang { +namespace serialization { + +class ModuleFile; + +/// \brief A collection of on-disk hash tables, merged when relevant for performance. +template<typename Info> class MultiOnDiskHashTable { +public: + /// A handle to a file, used when overriding tables. + typedef typename Info::file_type file_type; + /// A pointer to an on-disk representation of the hash table. + typedef const unsigned char *storage_type; + + typedef typename Info::external_key_type external_key_type; + typedef typename Info::internal_key_type internal_key_type; + typedef typename Info::data_type data_type; + typedef typename Info::data_type_builder data_type_builder; + typedef unsigned hash_value_type; + +private: + /// \brief A hash table stored on disk. + struct OnDiskTable { + typedef llvm::OnDiskIterableChainedHashTable<Info> HashTable; + + file_type File; + HashTable Table; + + OnDiskTable(file_type File, unsigned NumBuckets, unsigned NumEntries, + storage_type Buckets, storage_type Payload, storage_type Base, + const Info &InfoObj) + : File(File), + Table(NumBuckets, NumEntries, Buckets, Payload, Base, InfoObj) {} + }; + + struct MergedTable { + std::vector<file_type> Files; + llvm::DenseMap<internal_key_type, data_type> Data; + }; + + typedef llvm::PointerUnion<OnDiskTable*, MergedTable*> Table; + typedef llvm::TinyPtrVector<void*> TableVector; + + /// \brief The current set of on-disk and merged tables. + /// We manually store the opaque value of the Table because TinyPtrVector + /// can't cope with holding a PointerUnion directly. + /// There can be at most one MergedTable in this vector, and if present, + /// it is the first table. + TableVector Tables; + + /// \brief Files corresponding to overridden tables that we've not yet + /// discarded. + llvm::TinyPtrVector<file_type> PendingOverrides; + + struct AsOnDiskTable { + typedef OnDiskTable *result_type; + result_type operator()(void *P) const { + return Table::getFromOpaqueValue(P).template get<OnDiskTable *>(); + } + }; + typedef llvm::mapped_iterator<TableVector::iterator, AsOnDiskTable> + table_iterator; + typedef llvm::iterator_range<table_iterator> table_range; + + /// \brief The current set of on-disk tables. + table_range tables() { + auto Begin = Tables.begin(), End = Tables.end(); + if (getMergedTable()) + ++Begin; + return llvm::make_range(llvm::map_iterator(Begin, AsOnDiskTable()), + llvm::map_iterator(End, AsOnDiskTable())); + } + + MergedTable *getMergedTable() const { + // If we already have a merged table, it's the first one. + return Tables.empty() ? nullptr : Table::getFromOpaqueValue(*Tables.begin()) + .template dyn_cast<MergedTable*>(); + } + + /// \brief Delete all our current on-disk tables. + void clear() { + for (auto *T : tables()) + delete T; + if (auto *M = getMergedTable()) + delete M; + Tables.clear(); + } + + void removeOverriddenTables() { + llvm::DenseSet<file_type> Files; + Files.insert(PendingOverrides.begin(), PendingOverrides.end()); + // Explicitly capture Files to work around an MSVC 2015 rejects-valid bug. + auto ShouldRemove = [&Files](void *T) -> bool { + auto *ODT = Table::getFromOpaqueValue(T).template get<OnDiskTable *>(); + bool Remove = Files.count(ODT->File); + if (Remove) + delete ODT; + return Remove; + }; + Tables.erase(std::remove_if(tables().begin().getCurrent(), Tables.end(), + ShouldRemove), + Tables.end()); + PendingOverrides.clear(); + } + + void condense() { + MergedTable *Merged = getMergedTable(); + if (!Merged) + Merged = new MergedTable; + + // Read in all the tables and merge them together. + // FIXME: Be smarter about which tables we merge. + for (auto *ODT : tables()) { + auto &HT = ODT->Table; + Info &InfoObj = HT.getInfoObj(); + + for (auto I = HT.data_begin(), E = HT.data_end(); I != E; ++I) { + auto *LocalPtr = I.getItem(); + + // FIXME: Don't rely on the OnDiskHashTable format here. + auto L = InfoObj.ReadKeyDataLength(LocalPtr); + const internal_key_type &Key = InfoObj.ReadKey(LocalPtr, L.first); + data_type_builder ValueBuilder(Merged->Data[Key]); + InfoObj.ReadDataInto(Key, LocalPtr + L.first, L.second, + ValueBuilder); + } + + Merged->Files.push_back(ODT->File); + delete ODT; + } + + Tables.clear(); + Tables.push_back(Table(Merged).getOpaqueValue()); + } + + /// The generator is permitted to read our merged table. + template<typename ReaderInfo, typename WriterInfo> + friend class MultiOnDiskHashTableGenerator; + +public: + MultiOnDiskHashTable() {} + MultiOnDiskHashTable(MultiOnDiskHashTable &&O) + : Tables(std::move(O.Tables)), + PendingOverrides(std::move(O.PendingOverrides)) { + O.Tables.clear(); + } + MultiOnDiskHashTable &operator=(MultiOnDiskHashTable &&O) { + if (&O == this) + return *this; + clear(); + Tables = std::move(O.Tables); + O.Tables.clear(); + PendingOverrides = std::move(O.PendingOverrides); + return *this; + } + ~MultiOnDiskHashTable() { clear(); } + + /// \brief Add the table \p Data loaded from file \p File. + void add(file_type File, storage_type Data, Info InfoObj = Info()) { + using namespace llvm::support; + storage_type Ptr = Data; + + uint32_t BucketOffset = endian::readNext<uint32_t, little, unaligned>(Ptr); + + // Read the list of overridden files. + uint32_t NumFiles = endian::readNext<uint32_t, little, unaligned>(Ptr); + // FIXME: Add a reserve() to TinyPtrVector so that we don't need to make + // an additional copy. + llvm::SmallVector<file_type, 16> OverriddenFiles; + OverriddenFiles.reserve(NumFiles); + for (/**/; NumFiles != 0; --NumFiles) + OverriddenFiles.push_back(InfoObj.ReadFileRef(Ptr)); + PendingOverrides.insert(PendingOverrides.end(), OverriddenFiles.begin(), + OverriddenFiles.end()); + + // Read the OnDiskChainedHashTable header. + storage_type Buckets = Data + BucketOffset; + auto NumBucketsAndEntries = + OnDiskTable::HashTable::readNumBucketsAndEntries(Buckets); + + // Register the table. + Table NewTable = new OnDiskTable(File, NumBucketsAndEntries.first, + NumBucketsAndEntries.second, + Buckets, Ptr, Data, std::move(InfoObj)); + Tables.push_back(NewTable.getOpaqueValue()); + } + + /// \brief Find and read the lookup results for \p EKey. + data_type find(const external_key_type &EKey) { + data_type Result; + + if (!PendingOverrides.empty()) + removeOverriddenTables(); + + if (Tables.size() > static_cast<unsigned>(Info::MaxTables)) + condense(); + + internal_key_type Key = Info::GetInternalKey(EKey); + auto KeyHash = Info::ComputeHash(Key); + + if (MergedTable *M = getMergedTable()) { + auto It = M->Data.find(Key); + if (It != M->Data.end()) + Result = It->second; + } + + data_type_builder ResultBuilder(Result); + + for (auto *ODT : tables()) { + auto &HT = ODT->Table; + auto It = HT.find_hashed(Key, KeyHash); + if (It != HT.end()) + HT.getInfoObj().ReadDataInto(Key, It.getDataPtr(), It.getDataLen(), + ResultBuilder); + } + + return Result; + } + + /// \brief Read all the lookup results into a single value. This only makes + /// sense if merging values across keys is meaningful. + data_type findAll() { + data_type Result; + data_type_builder ResultBuilder(Result); + + if (!PendingOverrides.empty()) + removeOverriddenTables(); + + if (MergedTable *M = getMergedTable()) { + for (auto &KV : M->Data) + Info::MergeDataInto(KV.second, ResultBuilder); + } + + for (auto *ODT : tables()) { + auto &HT = ODT->Table; + Info &InfoObj = HT.getInfoObj(); + for (auto I = HT.data_begin(), E = HT.data_end(); I != E; ++I) { + auto *LocalPtr = I.getItem(); + + // FIXME: Don't rely on the OnDiskHashTable format here. + auto L = InfoObj.ReadKeyDataLength(LocalPtr); + const internal_key_type &Key = InfoObj.ReadKey(LocalPtr, L.first); + InfoObj.ReadDataInto(Key, LocalPtr + L.first, L.second, ResultBuilder); + } + } + + return Result; + } +}; + +/// \brief Writer for the on-disk hash table. +template<typename ReaderInfo, typename WriterInfo> +class MultiOnDiskHashTableGenerator { + typedef MultiOnDiskHashTable<ReaderInfo> BaseTable; + typedef llvm::OnDiskChainedHashTableGenerator<WriterInfo> Generator; + + Generator Gen; + +public: + MultiOnDiskHashTableGenerator() : Gen() {} + + void insert(typename WriterInfo::key_type_ref Key, + typename WriterInfo::data_type_ref Data, WriterInfo &Info) { + Gen.insert(Key, Data, Info); + } + + void emit(llvm::SmallVectorImpl<char> &Out, WriterInfo &Info, + const BaseTable *Base) { + using namespace llvm::support; + llvm::raw_svector_ostream OutStream(Out); + + // Write our header information. + { + endian::Writer<little> Writer(OutStream); + + // Reserve four bytes for the bucket offset. + Writer.write<uint32_t>(0); + + if (auto *Merged = Base ? Base->getMergedTable() : nullptr) { + // Write list of overridden files. + Writer.write<uint32_t>(Merged->Files.size()); + for (const auto &F : Merged->Files) + Info.EmitFileRef(OutStream, F); + + // Add all merged entries from Base to the generator. + for (auto &KV : Merged->Data) { + if (!Gen.contains(KV.first, Info)) + Gen.insert(KV.first, Info.ImportData(KV.second), Info); + } + } else { + Writer.write<uint32_t>(0); + } + } + + // Write the table itself. + uint32_t BucketOffset = Gen.Emit(OutStream, Info); + + // Replace the first four bytes with the bucket offset. + endian::write32le(Out.data(), BucketOffset); + } +}; + +} // end namespace clang::serialization +} // end namespace clang + + +#endif |