diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:02:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:02:28 +0000 |
commit | 7442d6faa2719e4e7d33a7021c406c5a4facd74d (patch) | |
tree | c72b9241553fc9966179aba84f90f17bfa9235c3 /lib/Serialization | |
parent | b52119637f743680a99710ce5fdb6646da2772af (diff) |
Notes
Diffstat (limited to 'lib/Serialization')
-rw-r--r-- | lib/Serialization/ASTCommon.cpp | 4 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 1362 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 197 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 20 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 386 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterDecl.cpp | 20 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 16 | ||||
-rw-r--r-- | lib/Serialization/GeneratePCH.cpp | 7 | ||||
-rw-r--r-- | lib/Serialization/GlobalModuleIndex.cpp | 76 | ||||
-rw-r--r-- | lib/Serialization/Module.cpp | 22 | ||||
-rw-r--r-- | lib/Serialization/ModuleManager.cpp | 255 |
11 files changed, 1772 insertions, 593 deletions
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index ecd249cc50259..684ec243035e9 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -147,9 +147,6 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { 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; @@ -254,6 +251,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::VarTemplateSpecialization: case Decl::VarTemplatePartialSpecialization: case Decl::Function: + case Decl::CXXDeductionGuide: case Decl::CXXMethod: case Decl::CXXConstructor: case Decl::CXXDestructor: diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 53224e2b493d4..406c4b50d92bc 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -26,6 +26,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/ODRHash.h" #include "clang/AST/RawCommentList.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" @@ -36,6 +37,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/MemoryBufferCache.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/Sanitizers.h" @@ -72,6 +74,7 @@ #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -461,19 +464,9 @@ static bool checkDiagnosticMappings(DiagnosticsEngine &StoredDiags, return checkDiagnosticGroupMappings(StoredDiags, Diags, Complain); } -bool PCHValidator::ReadDiagnosticOptions( - IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) { - DiagnosticsEngine &ExistingDiags = PP.getDiagnostics(); - IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs()); - IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagIDs, DiagOpts.get())); - // This should never fail, because we would have processed these options - // before writing them to an ASTFile. - ProcessWarningOptions(*Diags, *DiagOpts, /*Report*/false); - - ModuleManager &ModuleMgr = Reader.getModuleManager(); - assert(ModuleMgr.size() >= 1 && "what ASTFile is this then"); - +/// Return the top import module if it is implicit, nullptr otherwise. +static Module *getTopImportImplicitModule(ModuleManager &ModuleMgr, + Preprocessor &PP) { // If the original import came from a file explicitly generated by the user, // don't check the diagnostic mappings. // FIXME: currently this is approximated by checking whether this is not a @@ -481,21 +474,41 @@ bool PCHValidator::ReadDiagnosticOptions( // Note: ModuleMgr.rbegin() may not be the current module, but it must be in // the transitive closure of its imports, since unrelated modules cannot be // imported until after this module finishes validation. - ModuleFile *TopImport = *ModuleMgr.rbegin(); + ModuleFile *TopImport = &*ModuleMgr.rbegin(); while (!TopImport->ImportedBy.empty()) TopImport = TopImport->ImportedBy[0]; if (TopImport->Kind != MK_ImplicitModule) - return false; + return nullptr; StringRef ModuleName = TopImport->ModuleName; assert(!ModuleName.empty() && "diagnostic options read before module name"); Module *M = PP.getHeaderSearchInfo().lookupModule(ModuleName); assert(M && "missing module"); + return M; +} + +bool PCHValidator::ReadDiagnosticOptions( + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) { + DiagnosticsEngine &ExistingDiags = PP.getDiagnostics(); + IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs()); + IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagIDs, DiagOpts.get())); + // This should never fail, because we would have processed these options + // before writing them to an ASTFile. + ProcessWarningOptions(*Diags, *DiagOpts, /*Report*/false); + + ModuleManager &ModuleMgr = Reader.getModuleManager(); + assert(ModuleMgr.size() >= 1 && "what ASTFile is this then"); + + Module *TopM = getTopImportImplicitModule(ModuleMgr, PP); + if (!TopM) + return false; // FIXME: if the diagnostics are incompatible, save a DiagnosticOptions that // contains the union of their flags. - return checkDiagnosticMappings(*Diags, ExistingDiags, M->IsSystem, Complain); + return checkDiagnosticMappings(*Diags, ExistingDiags, TopM->IsSystem, + Complain); } /// \brief Collect the macro definitions provided by the given preprocessor @@ -943,6 +956,10 @@ DeclarationNameKey::DeclarationNameKey(DeclarationName Name) case DeclarationName::CXXLiteralOperatorName: Data = (uint64_t)Name.getCXXLiteralIdentifier(); break; + case DeclarationName::CXXDeductionGuideName: + Data = (uint64_t)Name.getCXXDeductionGuideTemplate() + ->getDeclName().getAsIdentifierInfo(); + break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: @@ -959,6 +976,7 @@ unsigned DeclarationNameKey::getHash() const { switch (Kind) { case DeclarationName::Identifier: case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: ID.AddString(((IdentifierInfo*)Data)->getName()); break; case DeclarationName::ObjCZeroArgSelector: @@ -1002,6 +1020,8 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) { uint64_t Data; switch (Kind) { case DeclarationName::Identifier: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: Data = (uint64_t)Reader.getLocalIdentifier( F, endian::readNext<uint32_t, little, unaligned>(d)); break; @@ -1016,10 +1036,6 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) { case DeclarationName::CXXOperatorName: Data = *d++; // OverloadedOperatorKind break; - case DeclarationName::CXXLiteralOperatorName: - Data = (uint64_t)Reader.getLocalIdentifier( - F, endian::readNext<uint32_t, little, unaligned>(d)); - break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: @@ -1103,7 +1119,7 @@ bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M, return false; } -void ASTReader::Error(StringRef Msg) { +void ASTReader::Error(StringRef Msg) const { Error(diag::err_fe_pch_malformed, Msg); if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight() && !PP.getHeaderSearchInfo().getModuleCachePath().empty()) { @@ -1113,7 +1129,7 @@ void ASTReader::Error(StringRef Msg) { } void ASTReader::Error(unsigned DiagID, - StringRef Arg1, StringRef Arg2) { + StringRef Arg1, StringRef Arg2) const { if (Diags.isDiagnosticInFlight()) Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2); else @@ -1278,10 +1294,15 @@ bool ASTReader::ReadSLocEntry(int ID) { unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob); if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) { + if (!llvm::zlib::isAvailable()) { + Error("zlib is not available"); + return nullptr; + } SmallString<0> Uncompressed; - if (llvm::zlib::uncompress(Blob, Uncompressed, Record[0]) != - llvm::zlib::StatusOK) { - Error("could not decompress embedded file contents"); + if (llvm::Error E = + llvm::zlib::uncompress(Blob, Uncompressed, Record[0])) { + Error("could not decompress embedded file contents: " + + llvm::toString(std::move(E))); return nullptr; } return llvm::MemoryBuffer::getMemBufferCopy(Uncompressed, Name); @@ -1575,7 +1596,11 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { } PreprocessedEntityID -ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const { +ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, + unsigned LocalID) const { + if (!M.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(M); + ContinuousRangeMap<uint32_t, int, 2>::const_iterator I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS); assert(I != M.PreprocessedEntityRemap.end() @@ -1707,15 +1732,15 @@ void ASTReader::ReadDefinedMacros() { // Note that we are loading defined macros. Deserializing Macros(this); - for (auto &I : llvm::reverse(ModuleMgr)) { - BitstreamCursor &MacroCursor = I->MacroCursor; + for (ModuleFile &I : llvm::reverse(ModuleMgr)) { + BitstreamCursor &MacroCursor = I.MacroCursor; // If there was no preprocessor block, skip this file. if (MacroCursor.getBitcodeBytes().empty()) continue; BitstreamCursor Cursor = MacroCursor; - Cursor.JumpToBit(I->MacroStartOffset); + Cursor.JumpToBit(I.MacroStartOffset); RecordData Record; while (true) { @@ -1737,7 +1762,7 @@ void ASTReader::ReadDefinedMacros() { case PP_MACRO_OBJECT_LIKE: case PP_MACRO_FUNCTION_LIKE: { - IdentifierInfo *II = getLocalIdentifier(*I, Record[0]); + IdentifierInfo *II = getLocalIdentifier(I, Record[0]); if (II->isOutOfDate()) updateOutOfDateIdentifier(*II); break; @@ -2149,7 +2174,7 @@ static bool isDiagnosedResult(ASTReader::ASTReadResult ARR, unsigned Caps) { ASTReader::ASTReadResult ASTReader::ReadOptionsBlock( BitstreamCursor &Stream, unsigned ClientLoadCapabilities, bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener, - std::string &SuggestedPredefines, bool ValidateDiagnosticOptions) { + std::string &SuggestedPredefines) { if (Stream.EnterSubBlock(OPTIONS_BLOCK_ID)) return Failure; @@ -2191,15 +2216,6 @@ ASTReader::ASTReadResult ASTReader::ReadOptionsBlock( break; } - case DIAGNOSTIC_OPTIONS: { - bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; - if (ValidateDiagnosticOptions && - !AllowCompatibleConfigurationMismatch && - ParseDiagnosticOptions(Record, Complain, Listener)) - return OutOfDate; - break; - } - case FILE_SYSTEM_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (!AllowCompatibleConfigurationMismatch && @@ -2240,6 +2256,23 @@ ASTReader::ReadControlBlock(ModuleFile &F, return Failure; } + // Lambda to read the unhashed control block the first time it's called. + // + // For PCM files, the unhashed control block cannot be read until after the + // MODULE_NAME record. However, PCH files have no MODULE_NAME, and yet still + // need to look ahead before reading the IMPORTS record. For consistency, + // this block is always read somehow (see BitstreamEntry::EndBlock). + bool HasReadUnhashedControlBlock = false; + auto readUnhashedControlBlockOnce = [&]() { + if (!HasReadUnhashedControlBlock) { + HasReadUnhashedControlBlock = true; + if (ASTReadResult Result = + readUnhashedControlBlock(F, ImportedBy, ClientLoadCapabilities)) + return Result; + } + return Success; + }; + // Read all of the records and blocks in the control block. RecordData Record; unsigned NumInputs = 0; @@ -2252,6 +2285,11 @@ ASTReader::ReadControlBlock(ModuleFile &F, Error("malformed block record in AST file"); return Failure; case llvm::BitstreamEntry::EndBlock: { + // Validate the module before returning. This call catches an AST with + // no module name and no imports. + if (ASTReadResult Result = readUnhashedControlBlockOnce()) + return Result; + // Validate input files. const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); @@ -2323,13 +2361,10 @@ ASTReader::ReadControlBlock(ModuleFile &F, // FIXME: Allow this for files explicitly specified with -include-pch. bool AllowCompatibleConfigurationMismatch = F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule; - const HeaderSearchOptions &HSOpts = - PP.getHeaderSearchInfo().getHeaderSearchOpts(); Result = ReadOptionsBlock(Stream, ClientLoadCapabilities, AllowCompatibleConfigurationMismatch, - *Listener, SuggestedPredefines, - HSOpts.ModulesValidateDiagnosticOptions); + *Listener, SuggestedPredefines); if (Result == Failure) { Error("malformed block record in AST file"); return Result; @@ -2403,12 +2438,13 @@ ASTReader::ReadControlBlock(ModuleFile &F, break; } - case SIGNATURE: - assert((!F.Signature || F.Signature == Record[0]) && "signature changed"); - F.Signature = Record[0]; - break; - case IMPORTS: { + // Validate the AST before processing any imports (otherwise, untangling + // them can be error-prone and expensive). A module will have a name and + // will already have been validated, but this catches the PCH case. + if (ASTReadResult Result = readUnhashedControlBlockOnce()) + return Result; + // Load each of the imported PCH files. unsigned Idx = 0, N = Record.size(); while (Idx < N) { @@ -2421,7 +2457,10 @@ ASTReader::ReadControlBlock(ModuleFile &F, ReadUntranslatedSourceLocation(Record[Idx++]); off_t StoredSize = (off_t)Record[Idx++]; time_t StoredModTime = (time_t)Record[Idx++]; - ASTFileSignature StoredSignature = Record[Idx++]; + ASTFileSignature StoredSignature = { + {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++], + (uint32_t)Record[Idx++], (uint32_t)Record[Idx++], + (uint32_t)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 @@ -2473,6 +2512,12 @@ ASTReader::ReadControlBlock(ModuleFile &F, F.ModuleName = Blob; if (Listener) Listener->ReadModuleName(F.ModuleName); + + // Validate the AST as soon as we have a name so we can exit early on + // failure. + if (ASTReadResult Result = readUnhashedControlBlockOnce()) + return Result; + break; case MODULE_DIRECTORY: { @@ -2513,6 +2558,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, F.InputFileOffsets = (const llvm::support::unaligned_uint64_t *)Blob.data(); F.InputFilesLoaded.resize(NumInputs); + F.NumUserInputFiles = NumUserInputs; break; } } @@ -2601,7 +2647,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case SUBMODULE_BLOCK_ID: - if (ASTReadResult Result = ReadSubmoduleBlock(F, ClientLoadCapabilities)) + if (ASTReadResult Result = + ReadSubmoduleBlock(F, ClientLoadCapabilities)) return Result; break; @@ -2766,6 +2813,14 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I])); break; + case MODULAR_CODEGEN_DECLS: + // FIXME: Skip reading this record if our ASTConsumer doesn't care about + // them (ie: if we're not codegenerating this module). + if (F.Kind == MK_MainFile) + for (unsigned I = 0, N = Record.size(); I != N; ++I) + EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I])); + break; + case SPECIAL_TYPES: if (SpecialTypes.empty()) { for (unsigned I = 0, N = Record.size(); I != N; ++I) @@ -2916,80 +2971,9 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; } - case MODULE_OFFSET_MAP: { - // Additional remapping information. - const unsigned char *Data = (const unsigned char*)Blob.data(); - const unsigned char *DataEnd = Data + Blob.size(); - - // If we see this entry before SOURCE_LOCATION_OFFSETS, add placeholders. - if (F.SLocRemap.find(0) == F.SLocRemap.end()) { - F.SLocRemap.insert(std::make_pair(0U, 0)); - F.SLocRemap.insert(std::make_pair(2U, 1)); - } - - // Continuous range maps we may be updating in our module. - typedef ContinuousRangeMap<uint32_t, int, 2>::Builder - RemapBuilder; - RemapBuilder SLocRemap(F.SLocRemap); - RemapBuilder IdentifierRemap(F.IdentifierRemap); - RemapBuilder MacroRemap(F.MacroRemap); - RemapBuilder PreprocessedEntityRemap(F.PreprocessedEntityRemap); - RemapBuilder SubmoduleRemap(F.SubmoduleRemap); - RemapBuilder SelectorRemap(F.SelectorRemap); - RemapBuilder DeclRemap(F.DeclRemap); - RemapBuilder TypeRemap(F.TypeRemap); - - while (Data < DataEnd) { - using namespace llvm::support; - uint16_t Len = endian::readNext<uint16_t, little, unaligned>(Data); - StringRef Name = StringRef((const char*)Data, Len); - Data += Len; - ModuleFile *OM = ModuleMgr.lookup(Name); - if (!OM) { - Error("SourceLocation remap refers to unknown module"); - return Failure; - } - - uint32_t SLocOffset = - endian::readNext<uint32_t, little, unaligned>(Data); - uint32_t IdentifierIDOffset = - endian::readNext<uint32_t, little, unaligned>(Data); - uint32_t MacroIDOffset = - endian::readNext<uint32_t, little, unaligned>(Data); - uint32_t PreprocessedEntityIDOffset = - endian::readNext<uint32_t, little, unaligned>(Data); - uint32_t SubmoduleIDOffset = - endian::readNext<uint32_t, little, unaligned>(Data); - uint32_t SelectorIDOffset = - endian::readNext<uint32_t, little, unaligned>(Data); - uint32_t DeclIDOffset = - endian::readNext<uint32_t, little, unaligned>(Data); - uint32_t TypeIndexOffset = - endian::readNext<uint32_t, little, unaligned>(Data); - - uint32_t None = std::numeric_limits<uint32_t>::max(); - - auto mapOffset = [&](uint32_t Offset, uint32_t BaseOffset, - RemapBuilder &Remap) { - if (Offset != None) - Remap.insert(std::make_pair(Offset, - static_cast<int>(BaseOffset - Offset))); - }; - mapOffset(SLocOffset, OM->SLocEntryBaseOffset, SLocRemap); - mapOffset(IdentifierIDOffset, OM->BaseIdentifierID, IdentifierRemap); - mapOffset(MacroIDOffset, OM->BaseMacroID, MacroRemap); - mapOffset(PreprocessedEntityIDOffset, OM->BasePreprocessedEntityID, - PreprocessedEntityRemap); - mapOffset(SubmoduleIDOffset, OM->BaseSubmoduleID, SubmoduleRemap); - mapOffset(SelectorIDOffset, OM->BaseSelectorID, SelectorRemap); - mapOffset(DeclIDOffset, OM->BaseDeclID, DeclRemap); - mapOffset(TypeIndexOffset, OM->BaseTypeIndex, TypeRemap); - - // Global -> local mappings. - F.GlobalToLocalDeclIDs[OM] = DeclIDOffset; - } + case MODULE_OFFSET_MAP: + F.ModuleOffsetMap = Blob; break; - } case SOURCE_MANAGER_LINE_TABLE: if (ParseLineTable(F, Record)) @@ -3123,14 +3107,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { F.ObjCCategories.swap(Record); break; - case DIAG_PRAGMA_MAPPINGS: - if (F.PragmaDiagMappings.empty()) - F.PragmaDiagMappings.swap(Record); - else - F.PragmaDiagMappings.insert(F.PragmaDiagMappings.end(), - Record.begin(), Record.end()); - break; - case CUDA_SPECIAL_DECL_REFS: // Later tables overwrite earlier ones. // FIXME: Modules will have trouble with this. @@ -3245,8 +3221,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { for (unsigned I = 0, N = Record.size(); I != N; /**/) { unsigned GlobalID = getGlobalSubmoduleID(F, Record[I++]); SourceLocation Loc = ReadSourceLocation(F, Record, I); - if (GlobalID) + if (GlobalID) { ImportedModules.push_back(ImportedSubmodule(GlobalID, Loc)); + if (DeserializationListener) + DeserializationListener->ModuleImportRead(GlobalID, Loc); + } } } break; @@ -3319,10 +3298,113 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } ForceCUDAHostDeviceDepth = Record[0]; break; + + case PACK_PRAGMA_OPTIONS: { + if (Record.size() < 3) { + Error("invalid pragma pack record"); + return Failure; + } + PragmaPackCurrentValue = Record[0]; + PragmaPackCurrentLocation = ReadSourceLocation(F, Record[1]); + unsigned NumStackEntries = Record[2]; + unsigned Idx = 3; + // Reset the stack when importing a new module. + PragmaPackStack.clear(); + for (unsigned I = 0; I < NumStackEntries; ++I) { + PragmaPackStackEntry Entry; + Entry.Value = Record[Idx++]; + Entry.Location = ReadSourceLocation(F, Record[Idx++]); + PragmaPackStrings.push_back(ReadString(Record, Idx)); + Entry.SlotLabel = PragmaPackStrings.back(); + PragmaPackStack.push_back(Entry); + } + break; + } } } } +void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const { + assert(!F.ModuleOffsetMap.empty() && "no module offset map to read"); + + // Additional remapping information. + const unsigned char *Data = (const unsigned char*)F.ModuleOffsetMap.data(); + const unsigned char *DataEnd = Data + F.ModuleOffsetMap.size(); + F.ModuleOffsetMap = StringRef(); + + // If we see this entry before SOURCE_LOCATION_OFFSETS, add placeholders. + if (F.SLocRemap.find(0) == F.SLocRemap.end()) { + F.SLocRemap.insert(std::make_pair(0U, 0)); + F.SLocRemap.insert(std::make_pair(2U, 1)); + } + + // Continuous range maps we may be updating in our module. + typedef ContinuousRangeMap<uint32_t, int, 2>::Builder + RemapBuilder; + RemapBuilder SLocRemap(F.SLocRemap); + RemapBuilder IdentifierRemap(F.IdentifierRemap); + RemapBuilder MacroRemap(F.MacroRemap); + RemapBuilder PreprocessedEntityRemap(F.PreprocessedEntityRemap); + RemapBuilder SubmoduleRemap(F.SubmoduleRemap); + RemapBuilder SelectorRemap(F.SelectorRemap); + RemapBuilder DeclRemap(F.DeclRemap); + RemapBuilder TypeRemap(F.TypeRemap); + + while (Data < DataEnd) { + // FIXME: Looking up dependency modules by filename is horrible. + using namespace llvm::support; + uint16_t Len = endian::readNext<uint16_t, little, unaligned>(Data); + StringRef Name = StringRef((const char*)Data, Len); + Data += Len; + ModuleFile *OM = ModuleMgr.lookup(Name); + if (!OM) { + std::string Msg = + "SourceLocation remap refers to unknown module, cannot find "; + Msg.append(Name); + Error(Msg); + return; + } + + uint32_t SLocOffset = + endian::readNext<uint32_t, little, unaligned>(Data); + uint32_t IdentifierIDOffset = + endian::readNext<uint32_t, little, unaligned>(Data); + uint32_t MacroIDOffset = + endian::readNext<uint32_t, little, unaligned>(Data); + uint32_t PreprocessedEntityIDOffset = + endian::readNext<uint32_t, little, unaligned>(Data); + uint32_t SubmoduleIDOffset = + endian::readNext<uint32_t, little, unaligned>(Data); + uint32_t SelectorIDOffset = + endian::readNext<uint32_t, little, unaligned>(Data); + uint32_t DeclIDOffset = + endian::readNext<uint32_t, little, unaligned>(Data); + uint32_t TypeIndexOffset = + endian::readNext<uint32_t, little, unaligned>(Data); + + uint32_t None = std::numeric_limits<uint32_t>::max(); + + auto mapOffset = [&](uint32_t Offset, uint32_t BaseOffset, + RemapBuilder &Remap) { + if (Offset != None) + Remap.insert(std::make_pair(Offset, + static_cast<int>(BaseOffset - Offset))); + }; + mapOffset(SLocOffset, OM->SLocEntryBaseOffset, SLocRemap); + mapOffset(IdentifierIDOffset, OM->BaseIdentifierID, IdentifierRemap); + mapOffset(MacroIDOffset, OM->BaseMacroID, MacroRemap); + mapOffset(PreprocessedEntityIDOffset, OM->BasePreprocessedEntityID, + PreprocessedEntityRemap); + mapOffset(SubmoduleIDOffset, OM->BaseSubmoduleID, SubmoduleRemap); + mapOffset(SelectorIDOffset, OM->BaseSelectorID, SelectorRemap); + mapOffset(DeclIDOffset, OM->BaseDeclID, DeclRemap); + mapOffset(TypeIndexOffset, OM->BaseTypeIndex, TypeRemap); + + // Global -> local mappings. + F.GlobalToLocalDeclIDs[OM] = DeclIDOffset; + } +} + ASTReader::ASTReadResult ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, const ModuleFile *ImportedBy, @@ -3342,8 +3424,7 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, // usable header search context. assert(!F.ModuleName.empty() && "MODULE_NAME should come before MODULE_MAP_FILE"); - if (F.Kind == MK_ImplicitModule && - (*ModuleMgr.begin())->Kind != MK_MainFile) { + if (F.Kind == MK_ImplicitModule && ModuleMgr.begin()->Kind != MK_MainFile) { // An implicitly-loaded module file should have its module listed in some // module map file that we've already loaded. Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName); @@ -3621,10 +3702,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, unsigned NumModules = ModuleMgr.size(); SmallVector<ImportedModule, 4> Loaded; - switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc, - /*ImportedBy=*/nullptr, Loaded, - 0, 0, 0, - ClientLoadCapabilities)) { + switch (ASTReadResult ReadResult = + ReadASTCore(FileName, Type, ImportLoc, + /*ImportedBy=*/nullptr, Loaded, 0, 0, + ASTFileSignature(), ClientLoadCapabilities)) { case Failure: case Missing: case OutOfDate: @@ -3635,11 +3716,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, for (const ImportedModule &IM : Loaded) LoadedSet.insert(IM.Mod); - ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(), - LoadedSet, + ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, LoadedSet, Context.getLangOpts().Modules - ? &PP.getHeaderSearchInfo().getModuleMap() - : nullptr); + ? &PP.getHeaderSearchInfo().getModuleMap() + : nullptr); // If we find that any modules are unusable, the global index is going // to be out-of-date. Just remove it. @@ -3986,6 +4066,12 @@ ASTReader::ReadASTCore(StringRef FileName, Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc)); return Success; + case UNHASHED_CONTROL_BLOCK_ID: + // This block is handled using look-ahead during ReadControlBlock. We + // shouldn't get here! + Error("malformed block record in AST file"); + return Failure; + default: if (Stream.SkipBlock()) { Error("malformed block record in AST file"); @@ -3998,6 +4084,122 @@ ASTReader::ReadASTCore(StringRef FileName, return Success; } +ASTReader::ASTReadResult +ASTReader::readUnhashedControlBlock(ModuleFile &F, bool WasImportedBy, + unsigned ClientLoadCapabilities) { + const HeaderSearchOptions &HSOpts = + PP.getHeaderSearchInfo().getHeaderSearchOpts(); + bool AllowCompatibleConfigurationMismatch = + F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule; + + ASTReadResult Result = readUnhashedControlBlockImpl( + &F, F.Data, ClientLoadCapabilities, AllowCompatibleConfigurationMismatch, + Listener.get(), + WasImportedBy ? false : HSOpts.ModulesValidateDiagnosticOptions); + + // If F was directly imported by another module, it's implicitly validated by + // the importing module. + if (DisableValidation || WasImportedBy || + (AllowConfigurationMismatch && Result == ConfigurationMismatch)) + return Success; + + if (Result == Failure) { + Error("malformed block record in AST file"); + return Failure; + } + + if (Result == OutOfDate && F.Kind == MK_ImplicitModule) { + // If this module has already been finalized in the PCMCache, we're stuck + // with it; we can only load a single version of each module. + // + // This can happen when a module is imported in two contexts: in one, as a + // user module; in another, as a system module (due to an import from + // another module marked with the [system] flag). It usually indicates a + // bug in the module map: this module should also be marked with [system]. + // + // If -Wno-system-headers (the default), and the first import is as a + // system module, then validation will fail during the as-user import, + // since -Werror flags won't have been validated. However, it's reasonable + // to treat this consistently as a system module. + // + // If -Wsystem-headers, the PCM on disk was built with + // -Wno-system-headers, and the first import is as a user module, then + // validation will fail during the as-system import since the PCM on disk + // doesn't guarantee that -Werror was respected. However, the -Werror + // flags were checked during the initial as-user import. + if (PCMCache.isBufferFinal(F.FileName)) { + Diag(diag::warn_module_system_bit_conflict) << F.FileName; + return Success; + } + } + + return Result; +} + +ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl( + ModuleFile *F, llvm::StringRef StreamData, unsigned ClientLoadCapabilities, + bool AllowCompatibleConfigurationMismatch, ASTReaderListener *Listener, + bool ValidateDiagnosticOptions) { + // Initialize a stream. + BitstreamCursor Stream(StreamData); + + // Sniff for the signature. + if (!startsWithASTFileMagic(Stream)) + return Failure; + + // Scan for the UNHASHED_CONTROL_BLOCK_ID block. + if (SkipCursorToBlock(Stream, UNHASHED_CONTROL_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 ( + (UnhashedControlBlockRecordTypes)Stream.readRecord(Entry.ID, Record)) { + case SIGNATURE: { + if (F) + std::copy(Record.begin(), Record.end(), F->Signature.data()); + break; + } + case DIAGNOSTIC_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; + if (Listener && ValidateDiagnosticOptions && + !AllowCompatibleConfigurationMismatch && + ParseDiagnosticOptions(Record, Complain, *Listener)) + Result = OutOfDate; // Don't return early. Read the signature. + break; + } + case DIAG_PRAGMA_MAPPINGS: + if (!F) + break; + if (F->PragmaDiagMappings.empty()) + F->PragmaDiagMappings.swap(Record); + else + F->PragmaDiagMappings.insert(F->PragmaDiagMappings.end(), + Record.begin(), Record.end()); + break; + } + } +} + /// Parse a record and blob containing module file extension metadata. static bool parseModuleFileExtensionMetadata( const SmallVectorImpl<uint64_t> &Record, @@ -4214,23 +4416,24 @@ void ASTReader::finalizeForWriting() { static ASTFileSignature readASTFileSignature(StringRef PCH) { BitstreamCursor Stream(PCH); if (!startsWithASTFileMagic(Stream)) - return 0; + return ASTFileSignature(); - // Scan for the CONTROL_BLOCK_ID block. - if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) - return 0; + // Scan for the UNHASHED_CONTROL_BLOCK_ID block. + if (SkipCursorToBlock(Stream, UNHASHED_CONTROL_BLOCK_ID)) + return ASTFileSignature(); - // Scan for SIGNATURE inside the control block. + // Scan for SIGNATURE inside the diagnostic options block. ASTReader::RecordData Record; while (true) { llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); if (Entry.Kind != llvm::BitstreamEntry::Record) - return 0; + return ASTFileSignature(); Record.clear(); StringRef Blob; if (SIGNATURE == Stream.readRecord(Entry.ID, Record, &Blob)) - return Record[0]; + return {{{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2], + (uint32_t)Record[3], (uint32_t)Record[4]}}}; } } @@ -4349,7 +4552,8 @@ bool ASTReader::readASTFileControlBlock( } // Initialize the stream - BitstreamCursor Stream(PCHContainerRdr.ExtractPCH(**Buffer)); + StringRef Bytes = PCHContainerRdr.ExtractPCH(**Buffer); + BitstreamCursor Stream(Bytes); // Sniff for the signature. if (!startsWithASTFileMagic(Stream)) @@ -4377,8 +4581,7 @@ bool ASTReader::readASTFileControlBlock( std::string IgnoredSuggestedPredefines; if (ReadOptionsBlock(Stream, ARR_ConfigurationMismatch | ARR_OutOfDate, /*AllowCompatibleConfigurationMismatch*/ false, - Listener, IgnoredSuggestedPredefines, - ValidateDiagnosticOptions) != Success) + Listener, IgnoredSuggestedPredefines) != Success) return true; break; } @@ -4499,6 +4702,7 @@ bool ASTReader::readASTFileControlBlock( // Look for module file extension blocks, if requested. if (FindModuleFileExtensions) { + BitstreamCursor SavedStream = Stream; while (!SkipCursorToBlock(Stream, EXTENSION_BLOCK_ID)) { bool DoneWithExtensionBlock = false; while (!DoneWithExtensionBlock) { @@ -4537,16 +4741,25 @@ bool ASTReader::readASTFileControlBlock( } } } + Stream = SavedStream; } + // Scan for the UNHASHED_CONTROL_BLOCK_ID block. + if (readUnhashedControlBlockImpl( + nullptr, Bytes, ARR_ConfigurationMismatch | ARR_OutOfDate, + /*AllowCompatibleConfigurationMismatch*/ false, &Listener, + ValidateDiagnosticOptions) != Success) + return true; + return false; } -bool ASTReader::isAcceptableASTFile( - StringRef Filename, FileManager &FileMgr, - const PCHContainerReader &PCHContainerRdr, const LangOptions &LangOpts, - const TargetOptions &TargetOpts, const PreprocessorOptions &PPOpts, - std::string ExistingModuleCachePath) { +bool ASTReader::isAcceptableASTFile(StringRef Filename, FileManager &FileMgr, + const PCHContainerReader &PCHContainerRdr, + const LangOptions &LangOpts, + const TargetOptions &TargetOpts, + const PreprocessorOptions &PPOpts, + StringRef ExistingModuleCachePath) { SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, ExistingModuleCachePath, FileMgr); return !readASTFileControlBlock(Filename, FileMgr, PCHContainerRdr, @@ -4628,8 +4841,9 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // Retrieve this (sub)module from the module map, creating it if // necessary. - CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, IsFramework, - IsExplicit).first; + CurrentModule = + ModMap.findOrCreateModule(Name, ParentModule, IsFramework, IsExplicit) + .first; // FIXME: set the definition loc for CurrentModule, or call // ModMap.setInferredModuleAllowedBy() @@ -4696,13 +4910,9 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { if (!CurrentModule->getUmbrellaHeader()) ModMap.setUmbrellaHeader(CurrentModule, Umbrella, Blob); else if (CurrentModule->getUmbrellaHeader().Entry != Umbrella) { - // This can be a spurious difference caused by changing the VFS to - // point to a different copy of the file, and it is too late to - // to rebuild safely. - // FIXME: If we wrote the virtual paths instead of the 'real' paths, - // after input file validation only real problems would remain and we - // could just error. For now, assume it's okay. - break; + if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) + Error("mismatched umbrella headers in submodule"); + return OutOfDate; } } break; @@ -5288,48 +5498,128 @@ HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { } void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { - // FIXME: Make it work properly with modules. - SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates; - for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) { - ModuleFile &F = *(*I); + using DiagState = DiagnosticsEngine::DiagState; + SmallVector<DiagState *, 32> DiagStates; + + for (ModuleFile &F : ModuleMgr) { unsigned Idx = 0; + auto &Record = F.PragmaDiagMappings; + if (Record.empty()) + continue; + DiagStates.clear(); - assert(!Diag.DiagStates.empty()); - DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one. - while (Idx < F.PragmaDiagMappings.size()) { - SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]); - unsigned DiagStateID = F.PragmaDiagMappings[Idx++]; - if (DiagStateID != 0) { - Diag.DiagStatePoints.push_back( - DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1], - FullSourceLoc(Loc, SourceMgr))); - continue; - } - assert(DiagStateID == 0); + auto ReadDiagState = + [&](const DiagState &BasedOn, SourceLocation Loc, + bool IncludeNonPragmaStates) -> DiagnosticsEngine::DiagState * { + unsigned BackrefID = Record[Idx++]; + if (BackrefID != 0) + return DiagStates[BackrefID - 1]; + // A new DiagState was created here. - Diag.DiagStates.push_back(*Diag.GetCurDiagState()); - DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back(); + Diag.DiagStates.push_back(BasedOn); + DiagState *NewState = &Diag.DiagStates.back(); DiagStates.push_back(NewState); - Diag.DiagStatePoints.push_back( - DiagnosticsEngine::DiagStatePoint(NewState, - FullSourceLoc(Loc, SourceMgr))); - while (true) { - assert(Idx < F.PragmaDiagMappings.size() && - "Invalid data, didn't find '-1' marking end of diag/map pairs"); - if (Idx >= F.PragmaDiagMappings.size()) { - break; // Something is messed up but at least avoid infinite loop in - // release build. - } - unsigned DiagID = F.PragmaDiagMappings[Idx++]; - if (DiagID == (unsigned)-1) { - break; // no more diag/map pairs for this location. + unsigned Size = Record[Idx++]; + assert(Idx + Size * 2 <= Record.size() && + "Invalid data, not enough diag/map pairs"); + while (Size--) { + unsigned DiagID = Record[Idx++]; + unsigned SeverityAndUpgradedFromWarning = Record[Idx++]; + bool WasUpgradedFromWarning = + DiagnosticMapping::deserializeUpgradedFromWarning( + SeverityAndUpgradedFromWarning); + DiagnosticMapping NewMapping = + Diag.makeUserMapping(DiagnosticMapping::deserializeSeverity( + SeverityAndUpgradedFromWarning), + Loc); + if (!NewMapping.isPragma() && !IncludeNonPragmaStates) + continue; + + DiagnosticMapping &Mapping = NewState->getOrAddMapping(DiagID); + + // If this mapping was specified as a warning but the severity was + // upgraded due to diagnostic settings, simulate the current diagnostic + // settings (and use a warning). + if (WasUpgradedFromWarning && !Mapping.isErrorOrFatal()) { + Mapping = Diag.makeUserMapping(diag::Severity::Warning, Loc); + continue; } - diag::Severity Map = (diag::Severity)F.PragmaDiagMappings[Idx++]; - DiagnosticMapping Mapping = Diag.makeUserMapping(Map, Loc); - Diag.GetCurDiagState()->setMapping(DiagID, Mapping); + + // Use the deserialized mapping verbatim. + Mapping = NewMapping; + Mapping.setUpgradedFromWarning(WasUpgradedFromWarning); + } + return NewState; + }; + + // Read the first state. + DiagState *FirstState; + if (F.Kind == MK_ImplicitModule) { + // Implicitly-built modules are reused with different diagnostic + // settings. Use the initial diagnostic state from Diag to simulate this + // compilation's diagnostic settings. + FirstState = Diag.DiagStatesByLoc.FirstDiagState; + DiagStates.push_back(FirstState); + + // Skip the initial diagnostic state from the serialized module. + assert(Record[0] == 0 && + "Invalid data, unexpected backref in initial state"); + Idx = 2 + Record[1] * 2; + assert(Idx < Record.size() && + "Invalid data, not enough state change pairs in initial state"); + } else { + FirstState = ReadDiagState( + F.isModule() ? DiagState() : *Diag.DiagStatesByLoc.CurDiagState, + SourceLocation(), F.isModule()); + } + + // Read the state transitions. + unsigned NumLocations = Record[Idx++]; + while (NumLocations--) { + assert(Idx < Record.size() && + "Invalid data, missing pragma diagnostic states"); + SourceLocation Loc = ReadSourceLocation(F, Record[Idx++]); + auto IDAndOffset = SourceMgr.getDecomposedLoc(Loc); + assert(IDAndOffset.second == 0 && "not a start location for a FileID"); + unsigned Transitions = Record[Idx++]; + + // Note that we don't need to set up Parent/ParentOffset here, because + // we won't be changing the diagnostic state within imported FileIDs + // (other than perhaps appending to the main source file, which has no + // parent). + auto &F = Diag.DiagStatesByLoc.Files[IDAndOffset.first]; + F.StateTransitions.reserve(F.StateTransitions.size() + Transitions); + for (unsigned I = 0; I != Transitions; ++I) { + unsigned Offset = Record[Idx++]; + auto *State = + ReadDiagState(*FirstState, Loc.getLocWithOffset(Offset), false); + F.StateTransitions.push_back({State, Offset}); } } + + // Read the final state. + assert(Idx < Record.size() && + "Invalid data, missing final pragma diagnostic state"); + SourceLocation CurStateLoc = + ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]); + auto *CurState = ReadDiagState(*FirstState, CurStateLoc, false); + + if (!F.isModule()) { + Diag.DiagStatesByLoc.CurDiagState = CurState; + Diag.DiagStatesByLoc.CurDiagStateLoc = CurStateLoc; + + // Preserve the property that the imaginary root file describes the + // current state. + auto &T = Diag.DiagStatesByLoc.Files[FileID()].StateTransitions; + if (T.empty()) + T.push_back({CurState, 0}); + else + T[0].State = CurState; + } + + // Don't try to read these mappings again. + Record.clear(); } } @@ -5606,6 +5896,14 @@ QualType ASTReader::readTypeRecord(unsigned Index) { return Context.getAutoType(Deduced, Keyword, IsDependent); } + case TYPE_DEDUCED_TEMPLATE_SPECIALIZATION: { + TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); + QualType Deduced = readType(*Loc.F, Record, Idx); + bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; + return Context.getDeducedTemplateSpecializationType(Name, Deduced, + IsDependent); + } + case TYPE_RECORD: { if (Record.size() != 2) { Error("incorrect encoding of record type"); @@ -5840,6 +6138,17 @@ QualType ASTReader::readTypeRecord(unsigned Index) { return Context.getPipeType(ElementType, ReadOnly); } + case TYPE_DEPENDENT_SIZED_EXT_VECTOR: { + unsigned Idx = 0; + + // DependentSizedExtVectorType + QualType ElementType = readType(*Loc.F, Record, Idx); + Expr *SizeExpr = ReadExpr(*Loc.F); + SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx); + + return Context.getDependentSizedExtVectorType(ElementType, SizeExpr, + AttrLoc); + } } llvm_unreachable("Invalid TypeCode!"); } @@ -6037,6 +6346,11 @@ void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } +void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc( + DeducedTemplateSpecializationTypeLoc TL) { + TL.setTemplateNameLoc(ReadSourceLocation()); +} + void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } @@ -6304,9 +6618,6 @@ QualType ASTReader::GetType(TypeID ID) { 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; @@ -6363,6 +6674,9 @@ ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const { if (LocalIndex < NUM_PREDEF_TYPE_IDS) return LocalID; + if (!F.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(F); + ContinuousRangeMap<uint32_t, int, 2>::iterator I = F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS); assert(I != F.TypeRemap.end() && "Invalid index into type index remap"); @@ -6437,12 +6751,6 @@ Decl *ASTReader::GetExternalDecl(uint32_t ID) { return GetDecl(ID); } -template<typename TemplateSpecializationDecl> -static void completeRedeclChainForTemplateSpecialization(Decl *D) { - if (auto *TSD = dyn_cast<TemplateSpecializationDecl>(D)) - TSD->getSpecializedTemplate()->LoadLazySpecializations(); -} - void ASTReader::CompleteRedeclChain(const Decl *D) { if (NumCurrentElementsDeserializing) { // We arrange to not care about the complete redeclaration chain while we're @@ -6543,6 +6851,9 @@ ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const { if (LocalID < NUM_PREDEF_DECL_IDS) return LocalID; + if (!F.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(F); + ContinuousRangeMap<uint32_t, int, 2>::iterator I = F.DeclRemap.find(LocalID - NUM_PREDEF_DECL_IDS); assert(I != F.DeclRemap.end() && "Invalid index into decl index remap"); @@ -6728,6 +7039,9 @@ Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) { // Offset here is a global offset across the entire chain. RecordLocation Loc = getLocalBitOffset(Offset); Loc.F->DeclsCursor.JumpToBit(Loc.Offset); + assert(NumCurrentElementsDeserializing == 0 && + "should not be called while already deserializing"); + Deserializing D(this); return ReadStmtFromStream(*Loc.F); } @@ -6920,31 +7234,6 @@ static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD, Consumer->HandleInterestingDecl(DeclGroupRef(ImplD)); } -void ASTReader::PassInterestingDeclsToConsumer() { - assert(Consumer); - - if (PassingDeclsToConsumer) - return; - - // Guard variable to avoid recursively redoing the process of passing - // decls to consumer. - SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer, - true); - - // Ensure that we've loaded all potentially-interesting declarations - // that need to be eagerly loaded. - for (auto ID : EagerlyDeserializedDecls) - GetDecl(ID); - EagerlyDeserializedDecls.clear(); - - while (!InterestingDecls.empty()) { - Decl *D = InterestingDecls.front(); - InterestingDecls.pop_front(); - - PassInterestingDeclToConsumer(D); - } -} - void ASTReader::PassInterestingDeclToConsumer(Decl *D) { if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) PassObjCImplDeclToConsumer(ImplD, Consumer); @@ -7062,7 +7351,7 @@ void ASTReader::PrintStats() { } template<typename Key, typename ModuleFile, unsigned InitialCapacity> -static void +LLVM_DUMP_METHOD static void dumpModuleIDMap(StringRef Name, const ContinuousRangeMap<Key, ModuleFile *, InitialCapacity> &Map) { @@ -7092,18 +7381,15 @@ LLVM_DUMP_METHOD void ASTReader::dump() { GlobalPreprocessedEntityMap); llvm::errs() << "\n*** PCH/Modules Loaded:"; - for (ModuleManager::ModuleConstIterator M = ModuleMgr.begin(), - MEnd = ModuleMgr.end(); - M != MEnd; ++M) - (*M)->dump(); + for (ModuleFile &M : ModuleMgr) + M.dump(); } /// Return the amount of memory used by memory buffers, breaking down /// by heap-backed versus mmap'ed memory. void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { - for (ModuleConstIterator I = ModuleMgr.begin(), - E = ModuleMgr.end(); I != E; ++I) { - if (llvm::MemoryBuffer *buf = (*I)->Buffer.get()) { + for (ModuleFile &I : ModuleMgr) { + if (llvm::MemoryBuffer *buf = I.Buffer) { size_t bytes = buf->getBufferSize(); switch (buf->getBufferKind()) { case llvm::MemoryBuffer::MemoryBuffer_Malloc: @@ -7132,7 +7418,7 @@ void ASTReader::InitializeSema(Sema &S) { // FIXME: What happens if these are changed by a module import? if (!FPPragmaOptions.empty()) { assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS"); - SemaObj->FPFeatures.fp_contract = FPPragmaOptions[0]; + SemaObj->FPFeatures = FPOptions(FPPragmaOptions[0]); } SemaObj->OpenCLFeatures.copy(OpenCLExtensions); @@ -7173,6 +7459,34 @@ void ASTReader::UpdateSema() { PointersToMembersPragmaLocation); } SemaObj->ForceCUDAHostDeviceDepth = ForceCUDAHostDeviceDepth; + + if (PragmaPackCurrentValue) { + // The bottom of the stack might have a default value. It must be adjusted + // to the current value to ensure that the packing state is preserved after + // popping entries that were included/imported from a PCH/module. + bool DropFirst = false; + if (!PragmaPackStack.empty() && + PragmaPackStack.front().Location.isInvalid()) { + assert(PragmaPackStack.front().Value == SemaObj->PackStack.DefaultValue && + "Expected a default alignment value"); + SemaObj->PackStack.Stack.emplace_back( + PragmaPackStack.front().SlotLabel, SemaObj->PackStack.CurrentValue, + SemaObj->PackStack.CurrentPragmaLocation); + DropFirst = true; + } + for (const auto &Entry : + llvm::makeArrayRef(PragmaPackStack).drop_front(DropFirst ? 1 : 0)) + SemaObj->PackStack.Stack.emplace_back(Entry.SlotLabel, Entry.Value, + Entry.Location); + if (PragmaPackCurrentLocation.isInvalid()) { + assert(*PragmaPackCurrentValue == SemaObj->PackStack.DefaultValue && + "Expected a default alignment value"); + // Keep the current values. + } else { + SemaObj->PackStack.CurrentValue = *PragmaPackCurrentValue; + SemaObj->PackStack.CurrentPragmaLocation = PragmaPackCurrentLocation; + } + } } IdentifierInfo *ASTReader::get(StringRef Name) { @@ -7720,6 +8034,9 @@ IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) { if (LocalID < NUM_PREDEF_IDENT_IDS) return LocalID; + if (!M.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(M); + ContinuousRangeMap<uint32_t, int, 2>::iterator I = M.IdentifierRemap.find(LocalID - NUM_PREDEF_IDENT_IDS); assert(I != M.IdentifierRemap.end() @@ -7758,6 +8075,9 @@ MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) { if (LocalID < NUM_PREDEF_MACRO_IDS) return LocalID; + if (!M.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(M); + ContinuousRangeMap<uint32_t, int, 2>::iterator I = M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS); assert(I != M.MacroRemap.end() && "Invalid index into macro index remap"); @@ -7770,6 +8090,9 @@ ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) { if (LocalID < NUM_PREDEF_SUBMODULE_IDS) return LocalID; + if (!M.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(M); + ContinuousRangeMap<uint32_t, int, 2>::iterator I = M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS); assert(I != M.SubmoduleRemap.end() @@ -7833,7 +8156,8 @@ ASTReader::getSourceDescriptor(unsigned ID) { // If there is only a single PCH, return it instead. // Chained PCH are not suported. - if (ModuleMgr.size() == 1) { + const auto &PCHChain = ModuleMgr.pch_modules(); + if (std::distance(std::begin(PCHChain), std::end(PCHChain))) { ModuleFile &MF = ModuleMgr.getPrimaryModule(); StringRef ModuleName = llvm::sys::path::filename(MF.OriginalSourceFileName); StringRef FileName = llvm::sys::path::filename(MF.FileName); @@ -7843,6 +8167,13 @@ ASTReader::getSourceDescriptor(unsigned ID) { return None; } +ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(const Decl *FD) { + auto I = BodySource.find(FD); + if (I == BodySource.end()) + return EK_ReplyHazy; + return I->second ? EK_Never : EK_Always; +} + Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) { return DecodeSelector(getGlobalSelectorID(M, LocalID)); } @@ -7886,6 +8217,9 @@ ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const { if (LocalID < NUM_PREDEF_SELECTOR_IDS) return LocalID; + if (!M.ModuleOffsetMap.empty()) + ReadModuleOffsetMap(M); + ContinuousRangeMap<uint32_t, int, 2>::iterator I = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS); assert(I != M.SelectorRemap.end() @@ -7915,6 +8249,10 @@ ASTReader::ReadDeclarationName(ModuleFile &F, return Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(readType(F, Record, Idx))); + case DeclarationName::CXXDeductionGuideName: + return Context.DeclarationNames.getCXXDeductionGuideName( + ReadDeclAs<TemplateDecl>(F, Record, Idx)); + case DeclarationName::CXXConversionFunctionName: return Context.DeclarationNames.getCXXConversionFunctionName( Context.getCanonicalType(readType(F, Record, Idx))); @@ -7962,6 +8300,7 @@ void ASTReader::ReadDeclarationNameLoc(ModuleFile &F, case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: break; } } @@ -8406,11 +8745,11 @@ CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F, return CXXTemporary::Create(Context, Decl); } -DiagnosticBuilder ASTReader::Diag(unsigned DiagID) { +DiagnosticBuilder ASTReader::Diag(unsigned DiagID) const { return Diag(CurrentImportLoc, DiagID); } -DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) { +DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) const { return Diags.Report(Loc, DiagID); } @@ -8493,6 +8832,21 @@ void ASTReader::ReadComments() { } } +void ASTReader::visitInputFiles(serialization::ModuleFile &MF, + bool IncludeSystem, bool Complain, + llvm::function_ref<void(const serialization::InputFile &IF, + bool isSystem)> Visitor) { + unsigned NumUserInputs = MF.NumUserInputFiles; + unsigned NumInputs = MF.InputFilesLoaded.size(); + assert(NumUserInputs <= NumInputs); + unsigned N = IncludeSystem ? NumInputs : NumUserInputs; + for (unsigned I = 0; I < N; ++I) { + bool IsSystem = I >= NumUserInputs; + InputFile IF = getInputFile(MF, I+1, Complain); + Visitor(IF, IsSystem); + } +} + std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) { // If we know the owning module, use it. if (Module *M = D->getImportedOwningModule()) @@ -8651,9 +9005,9 @@ void ASTReader::finishPendingActions() { // FIXME: Check for =delete/=default? // FIXME: Complain about ODR violations here? const FunctionDecl *Defn = nullptr; - if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) + if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) { FD->setLazyBody(PB->second); - else + } else mergeDefinitionVisibility(const_cast<FunctionDecl*>(Defn), FD); continue; } @@ -8789,24 +9143,504 @@ void ASTReader::diagnoseOdrViolations() { continue; bool Diagnosed = false; - for (auto *RD : Merge.second) { + CXXRecordDecl *FirstRecord = Merge.first; + std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord); + for (CXXRecordDecl *SecondRecord : Merge.second) { // Multiple different declarations got merged together; tell the user // where they came from. - if (Merge.first != RD) { - // FIXME: Walk the definition, figure out what's different, - // and diagnose that. - if (!Diagnosed) { - std::string Module = getOwningModuleNameForDiagnostic(Merge.first); - Diag(Merge.first->getLocation(), - diag::err_module_odr_violation_different_definitions) - << Merge.first << Module.empty() << Module; - Diagnosed = true; + if (FirstRecord == SecondRecord) + continue; + + std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord); + using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>; + DeclHashes FirstHashes; + DeclHashes SecondHashes; + ODRHash Hash; + + auto PopulateHashes = [&Hash, FirstRecord](DeclHashes &Hashes, + CXXRecordDecl *Record) { + for (auto *D : Record->decls()) { + // Due to decl merging, the first CXXRecordDecl is the parent of + // Decls in both records. + if (!ODRHash::isWhitelistedDecl(D, FirstRecord)) + continue; + Hash.clear(); + Hash.AddSubDecl(D); + Hashes.emplace_back(D, Hash.CalculateHash()); + } + }; + PopulateHashes(FirstHashes, FirstRecord); + PopulateHashes(SecondHashes, SecondRecord); + + // Used with err_module_odr_violation_mismatch_decl and + // note_module_odr_violation_mismatch_decl + enum { + EndOfClass, + PublicSpecifer, + PrivateSpecifer, + ProtectedSpecifer, + StaticAssert, + Field, + CXXMethod, + Other + } FirstDiffType = Other, + SecondDiffType = Other; + + auto DifferenceSelector = [](Decl *D) { + assert(D && "valid Decl required"); + switch (D->getKind()) { + default: + return Other; + case Decl::AccessSpec: + switch (D->getAccess()) { + case AS_public: + return PublicSpecifer; + case AS_private: + return PrivateSpecifer; + case AS_protected: + return ProtectedSpecifer; + case AS_none: + break; + } + llvm_unreachable("Invalid access specifier"); + case Decl::StaticAssert: + return StaticAssert; + case Decl::Field: + return Field; + case Decl::CXXMethod: + return CXXMethod; + } + }; + + Decl *FirstDecl = nullptr; + Decl *SecondDecl = nullptr; + auto FirstIt = FirstHashes.begin(); + auto SecondIt = SecondHashes.begin(); + + // If there is a diagnoseable difference, FirstDiffType and + // SecondDiffType will not be Other and FirstDecl and SecondDecl will be + // filled in if not EndOfClass. + while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) { + if (FirstIt != FirstHashes.end() && SecondIt != SecondHashes.end() && + FirstIt->second == SecondIt->second) { + ++FirstIt; + ++SecondIt; + continue; } - Diag(RD->getLocation(), + FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first; + SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first; + + FirstDiffType = FirstDecl ? DifferenceSelector(FirstDecl) : EndOfClass; + SecondDiffType = + SecondDecl ? DifferenceSelector(SecondDecl) : EndOfClass; + + break; + } + + if (FirstDiffType == Other || SecondDiffType == Other) { + // Reaching this point means an unexpected Decl was encountered + // or no difference was detected. This causes a generic error + // message to be emitted. + Diag(FirstRecord->getLocation(), + diag::err_module_odr_violation_different_definitions) + << FirstRecord << FirstModule.empty() << FirstModule; + + Diag(SecondRecord->getLocation(), diag::note_module_odr_violation_different_definitions) - << getOwningModuleNameForDiagnostic(RD); + << SecondModule; + Diagnosed = true; + break; + } + + if (FirstDiffType != SecondDiffType) { + SourceLocation FirstLoc; + SourceRange FirstRange; + if (FirstDiffType == EndOfClass) { + FirstLoc = FirstRecord->getBraceRange().getEnd(); + } else { + FirstLoc = FirstIt->first->getLocation(); + FirstRange = FirstIt->first->getSourceRange(); + } + Diag(FirstLoc, diag::err_module_odr_violation_mismatch_decl) + << FirstRecord << FirstModule.empty() << FirstModule << FirstRange + << FirstDiffType; + + SourceLocation SecondLoc; + SourceRange SecondRange; + if (SecondDiffType == EndOfClass) { + SecondLoc = SecondRecord->getBraceRange().getEnd(); + } else { + SecondLoc = SecondDecl->getLocation(); + SecondRange = SecondDecl->getSourceRange(); + } + Diag(SecondLoc, diag::note_module_odr_violation_mismatch_decl) + << SecondModule << SecondRange << SecondDiffType; + Diagnosed = true; + break; + } + + assert(FirstDiffType == SecondDiffType); + + // Used with err_module_odr_violation_mismatch_decl_diff and + // note_module_odr_violation_mismatch_decl_diff + enum ODRDeclDifference{ + StaticAssertCondition, + StaticAssertMessage, + StaticAssertOnlyMessage, + FieldName, + FieldTypeName, + FieldSingleBitField, + FieldDifferentWidthBitField, + FieldSingleMutable, + FieldSingleInitializer, + FieldDifferentInitializers, + MethodName, + MethodDeleted, + MethodVirtual, + MethodStatic, + MethodVolatile, + MethodConst, + MethodInline, + }; + + // These lambdas have the common portions of the ODR diagnostics. This + // has the same return as Diag(), so addition parameters can be passed + // in with operator<< + auto ODRDiagError = [FirstRecord, &FirstModule, this]( + SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) { + return Diag(Loc, diag::err_module_odr_violation_mismatch_decl_diff) + << FirstRecord << FirstModule.empty() << FirstModule << Range + << DiffType; + }; + auto ODRDiagNote = [&SecondModule, this]( + SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) { + return Diag(Loc, diag::note_module_odr_violation_mismatch_decl_diff) + << SecondModule << Range << DiffType; + }; + + auto ComputeODRHash = [&Hash](const Stmt* S) { + assert(S); + Hash.clear(); + Hash.AddStmt(S); + return Hash.CalculateHash(); + }; + + auto ComputeDeclNameODRHash = [&Hash](const DeclarationName Name) { + Hash.clear(); + Hash.AddDeclarationName(Name); + return Hash.CalculateHash(); + }; + + switch (FirstDiffType) { + case Other: + case EndOfClass: + case PublicSpecifer: + case PrivateSpecifer: + case ProtectedSpecifer: + llvm_unreachable("Invalid diff type"); + + case StaticAssert: { + StaticAssertDecl *FirstSA = cast<StaticAssertDecl>(FirstDecl); + StaticAssertDecl *SecondSA = cast<StaticAssertDecl>(SecondDecl); + + Expr *FirstExpr = FirstSA->getAssertExpr(); + Expr *SecondExpr = SecondSA->getAssertExpr(); + unsigned FirstODRHash = ComputeODRHash(FirstExpr); + unsigned SecondODRHash = ComputeODRHash(SecondExpr); + if (FirstODRHash != SecondODRHash) { + ODRDiagError(FirstExpr->getLocStart(), FirstExpr->getSourceRange(), + StaticAssertCondition); + ODRDiagNote(SecondExpr->getLocStart(), + SecondExpr->getSourceRange(), StaticAssertCondition); + Diagnosed = true; + break; + } + + StringLiteral *FirstStr = FirstSA->getMessage(); + StringLiteral *SecondStr = SecondSA->getMessage(); + assert((FirstStr || SecondStr) && "Both messages cannot be empty"); + if ((FirstStr && !SecondStr) || (!FirstStr && SecondStr)) { + SourceLocation FirstLoc, SecondLoc; + SourceRange FirstRange, SecondRange; + if (FirstStr) { + FirstLoc = FirstStr->getLocStart(); + FirstRange = FirstStr->getSourceRange(); + } else { + FirstLoc = FirstSA->getLocStart(); + FirstRange = FirstSA->getSourceRange(); + } + if (SecondStr) { + SecondLoc = SecondStr->getLocStart(); + SecondRange = SecondStr->getSourceRange(); + } else { + SecondLoc = SecondSA->getLocStart(); + SecondRange = SecondSA->getSourceRange(); + } + ODRDiagError(FirstLoc, FirstRange, StaticAssertOnlyMessage) + << (FirstStr == nullptr); + ODRDiagNote(SecondLoc, SecondRange, StaticAssertOnlyMessage) + << (SecondStr == nullptr); + Diagnosed = true; + break; + } + + if (FirstStr && SecondStr && + FirstStr->getString() != SecondStr->getString()) { + ODRDiagError(FirstStr->getLocStart(), FirstStr->getSourceRange(), + StaticAssertMessage); + ODRDiagNote(SecondStr->getLocStart(), SecondStr->getSourceRange(), + StaticAssertMessage); + Diagnosed = true; + break; + } + break; + } + case Field: { + FieldDecl *FirstField = cast<FieldDecl>(FirstDecl); + FieldDecl *SecondField = cast<FieldDecl>(SecondDecl); + IdentifierInfo *FirstII = FirstField->getIdentifier(); + IdentifierInfo *SecondII = SecondField->getIdentifier(); + if (FirstII->getName() != SecondII->getName()) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldName) + << FirstII; + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldName) + << SecondII; + + Diagnosed = true; + break; + } + + assert( + Context.hasSameType(FirstField->getType(), SecondField->getType())); + + QualType FirstType = FirstField->getType(); + QualType SecondType = SecondField->getType(); + const TypedefType *FirstTypedef = dyn_cast<TypedefType>(FirstType); + const TypedefType *SecondTypedef = dyn_cast<TypedefType>(SecondType); + + if ((FirstTypedef && !SecondTypedef) || + (!FirstTypedef && SecondTypedef)) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldTypeName) + << FirstII << FirstType; + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldTypeName) + << SecondII << SecondType; + + Diagnosed = true; + break; + } + + if (FirstTypedef && SecondTypedef) { + unsigned FirstHash = ComputeDeclNameODRHash( + FirstTypedef->getDecl()->getDeclName()); + unsigned SecondHash = ComputeDeclNameODRHash( + SecondTypedef->getDecl()->getDeclName()); + if (FirstHash != SecondHash) { + ODRDiagError(FirstField->getLocation(), + FirstField->getSourceRange(), FieldTypeName) + << FirstII << FirstType; + ODRDiagNote(SecondField->getLocation(), + SecondField->getSourceRange(), FieldTypeName) + << SecondII << SecondType; + + Diagnosed = true; + break; + } + } + + const bool IsFirstBitField = FirstField->isBitField(); + const bool IsSecondBitField = SecondField->isBitField(); + if (IsFirstBitField != IsSecondBitField) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldSingleBitField) + << FirstII << IsFirstBitField; + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldSingleBitField) + << SecondII << IsSecondBitField; + Diagnosed = true; + break; + } + + if (IsFirstBitField && IsSecondBitField) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldDifferentWidthBitField) + << FirstII << FirstField->getBitWidth()->getSourceRange(); + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldDifferentWidthBitField) + << SecondII << SecondField->getBitWidth()->getSourceRange(); + Diagnosed = true; + break; + } + + const bool IsFirstMutable = FirstField->isMutable(); + const bool IsSecondMutable = SecondField->isMutable(); + if (IsFirstMutable != IsSecondMutable) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldSingleMutable) + << FirstII << IsFirstMutable; + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldSingleMutable) + << SecondII << IsSecondMutable; + Diagnosed = true; + break; + } + + const Expr *FirstInitializer = FirstField->getInClassInitializer(); + const Expr *SecondInitializer = SecondField->getInClassInitializer(); + if ((!FirstInitializer && SecondInitializer) || + (FirstInitializer && !SecondInitializer)) { + ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), + FieldSingleInitializer) + << FirstII << (FirstInitializer != nullptr); + ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), + FieldSingleInitializer) + << SecondII << (SecondInitializer != nullptr); + Diagnosed = true; + break; + } + + if (FirstInitializer && SecondInitializer) { + unsigned FirstInitHash = ComputeODRHash(FirstInitializer); + unsigned SecondInitHash = ComputeODRHash(SecondInitializer); + if (FirstInitHash != SecondInitHash) { + ODRDiagError(FirstField->getLocation(), + FirstField->getSourceRange(), + FieldDifferentInitializers) + << FirstII << FirstInitializer->getSourceRange(); + ODRDiagNote(SecondField->getLocation(), + SecondField->getSourceRange(), + FieldDifferentInitializers) + << SecondII << SecondInitializer->getSourceRange(); + Diagnosed = true; + break; + } + } + + break; } + case CXXMethod: { + const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(FirstDecl); + const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(SecondDecl); + auto FirstName = FirstMethod->getDeclName(); + auto SecondName = SecondMethod->getDeclName(); + if (FirstName != SecondName) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodName) + << FirstName; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodName) + << SecondName; + + Diagnosed = true; + break; + } + + const bool FirstDeleted = FirstMethod->isDeleted(); + const bool SecondDeleted = SecondMethod->isDeleted(); + if (FirstDeleted != SecondDeleted) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodDeleted) + << FirstName << FirstDeleted; + + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodDeleted) + << SecondName << SecondDeleted; + Diagnosed = true; + break; + } + + const bool FirstVirtual = FirstMethod->isVirtualAsWritten(); + const bool SecondVirtual = SecondMethod->isVirtualAsWritten(); + const bool FirstPure = FirstMethod->isPure(); + const bool SecondPure = SecondMethod->isPure(); + if ((FirstVirtual || SecondVirtual) && + (FirstVirtual != SecondVirtual || FirstPure != SecondPure)) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodVirtual) + << FirstName << FirstPure << FirstVirtual; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodVirtual) + << SecondName << SecondPure << SecondVirtual; + Diagnosed = true; + break; + } + + // CXXMethodDecl::isStatic uses the canonical Decl. With Decl merging, + // FirstDecl is the canonical Decl of SecondDecl, so the storage + // class needs to be checked instead. + const auto FirstStorage = FirstMethod->getStorageClass(); + const auto SecondStorage = SecondMethod->getStorageClass(); + const bool FirstStatic = FirstStorage == SC_Static; + const bool SecondStatic = SecondStorage == SC_Static; + if (FirstStatic != SecondStatic) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodStatic) + << FirstName << FirstStatic; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodStatic) + << SecondName << SecondStatic; + Diagnosed = true; + break; + } + + const bool FirstVolatile = FirstMethod->isVolatile(); + const bool SecondVolatile = SecondMethod->isVolatile(); + if (FirstVolatile != SecondVolatile) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodVolatile) + << FirstName << FirstVolatile; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodVolatile) + << SecondName << SecondVolatile; + Diagnosed = true; + break; + } + + const bool FirstConst = FirstMethod->isConst(); + const bool SecondConst = SecondMethod->isConst(); + if (FirstConst != SecondConst) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodConst) + << FirstName << FirstConst; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodConst) + << SecondName << SecondConst; + Diagnosed = true; + break; + } + + const bool FirstInline = FirstMethod->isInlineSpecified(); + const bool SecondInline = SecondMethod->isInlineSpecified(); + if (FirstInline != SecondInline) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodInline) + << FirstName << FirstInline; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodInline) + << SecondName << SecondInline; + Diagnosed = true; + break; + } + + break; + } + } + + if (Diagnosed == true) + continue; + + Diag(FirstRecord->getLocation(), + diag::err_module_odr_violation_different_definitions) + << FirstRecord << FirstModule.empty() << FirstModule; + + Diag(SecondRecord->getLocation(), + diag::note_module_odr_violation_different_definitions) + << SecondModule; + Diagnosed = true; } if (!Diagnosed) { @@ -8905,8 +9739,10 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, : cast<ASTReaderListener>(new PCHValidator(PP, *this))), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), PCHContainerRdr(PCHContainerRdr), Diags(PP.getDiagnostics()), PP(PP), - Context(Context), ModuleMgr(PP.getFileManager(), PCHContainerRdr), - DummyIdResolver(PP), ReadTimer(std::move(ReadTimer)), isysroot(isysroot), + Context(Context), + ModuleMgr(PP.getFileManager(), PP.getPCMCache(), PCHContainerRdr), + PCMCache(PP.getPCMCache()), DummyIdResolver(PP), + ReadTimer(std::move(ReadTimer)), isysroot(isysroot), DisableValidation(DisableValidation), AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), AllowConfigurationMismatch(AllowConfigurationMismatch), diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 707a9249dd96d..e0304d22fe50c 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -119,7 +119,8 @@ namespace clang { } void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update); - void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data); + void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data, + const CXXRecordDecl *D); void MergeDefinitionData(CXXRecordDecl *D, struct CXXRecordDecl::DefinitionData &&NewDD); void ReadObjCDefinitionData(struct ObjCInterfaceDecl::DefinitionData &Data); @@ -240,6 +241,7 @@ namespace clang { /// \brief Determine whether this declaration has a pending body. bool hasPendingBody() const { return HasPendingBody; } + void ReadFunctionDefinition(FunctionDecl *FD); void Visit(Decl *D); void UpdateDecl(Decl *D); @@ -292,6 +294,7 @@ namespace clang { void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitDeclaratorDecl(DeclaratorDecl *DD); void VisitFunctionDecl(FunctionDecl *FD); + void VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *GD); void VisitCXXMethodDecl(CXXMethodDecl *D); void VisitCXXConstructorDecl(CXXConstructorDecl *D); void VisitCXXDestructorDecl(CXXDestructorDecl *D); @@ -421,6 +424,19 @@ uint64_t ASTDeclReader::GetCurrentCursorOffset() { return Loc.F->DeclsCursor.GetCurrentBitNo() + Loc.F->GlobalBitOffset; } +void ASTDeclReader::ReadFunctionDefinition(FunctionDecl *FD) { + if (Record.readInt()) + Reader.BodySource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile; + if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) { + CD->NumCtorInitializers = Record.readInt(); + if (CD->NumCtorInitializers) + CD->CtorInitializers = ReadGlobalOffset(); + } + // Store the offset of the body so we can lazily load it later. + Reader.PendingBodies[FD] = GetCurrentCursorOffset(); + HasPendingBody = true; +} + void ASTDeclReader::Visit(Decl *D) { DeclVisitor<ASTDeclReader, void>::Visit(D); @@ -457,15 +473,8 @@ void ASTDeclReader::Visit(Decl *D) { // We only read it if FD doesn't already have a body (e.g., from another // module). // FIXME: Can we diagnose ODR violations somehow? - if (Record.readInt()) { - if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) { - CD->NumCtorInitializers = Record.readInt(); - if (CD->NumCtorInitializers) - CD->CtorInitializers = ReadGlobalOffset(); - } - Reader.PendingBodies[FD] = GetCurrentCursorOffset(); - HasPendingBody = true; - } + if (Record.readInt()) + ReadFunctionDefinition(FD); } } @@ -592,6 +601,11 @@ ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) { TD->setModedTypeSourceInfo(TInfo, modedT); } else TD->setTypeSourceInfo(TInfo); + // Read and discard the declaration for which this is a typedef name for + // linkage, if it exists. We cannot rely on our type to pull in this decl, + // because it might have been merged with a type from another module and + // thus might not refer to our version of the declaration. + ReadDecl(); return Redecl; } @@ -738,6 +752,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->SClass = (StorageClass)Record.readInt(); FD->IsInline = Record.readInt(); FD->IsInlineSpecified = Record.readInt(); + FD->IsExplicitSpecified = Record.readInt(); FD->IsVirtualAsWritten = Record.readInt(); FD->IsPure = Record.readInt(); FD->HasInheritedPrototype = Record.readInt(); @@ -1112,8 +1127,12 @@ void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { (ObjCPropertyDecl::PropertyAttributeKind)Record.readInt()); D->setPropertyImplementation( (ObjCPropertyDecl::PropertyControl)Record.readInt()); - D->setGetterName(Record.readDeclarationName().getObjCSelector()); - D->setSetterName(Record.readDeclarationName().getObjCSelector()); + DeclarationName GetterName = Record.readDeclarationName(); + SourceLocation GetterLoc = ReadSourceLocation(); + D->setGetterName(GetterName.getObjCSelector(), GetterLoc); + DeclarationName SetterName = Record.readDeclarationName(); + SourceLocation SetterLoc = ReadSourceLocation(); + D->setSetterName(SetterName.getObjCSelector(), SetterLoc); D->setGetterMethodDecl(ReadDeclAs<ObjCMethodDecl>()); D->setSetterMethodDecl(ReadDeclAs<ObjCMethodDecl>()); D->setPropertyIvarDecl(ReadDeclAs<ObjCIvarDecl>()); @@ -1126,7 +1145,6 @@ void ASTDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) { void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { VisitObjCImplDecl(D); - D->setIdentifier(Record.getIdentifierInfo()); D->CategoryNameLoc = ReadSourceLocation(); } @@ -1473,7 +1491,7 @@ void ASTDeclReader::VisitUnresolvedUsingTypenameDecl( } void ASTDeclReader::ReadCXXDefinitionData( - struct CXXRecordDecl::DefinitionData &Data) { + struct CXXRecordDecl::DefinitionData &Data, const CXXRecordDecl *D) { // Note: the caller has deserialized the IsLambda bit already. Data.UserDeclaredConstructor = Record.readInt(); Data.UserDeclaredSpecialMembers = Record.readInt(); @@ -1512,10 +1530,19 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.ComputedVisibleConversions = Record.readInt(); Data.UserProvidedDefaultConstructor = Record.readInt(); Data.DeclaredSpecialMembers = Record.readInt(); - Data.ImplicitCopyConstructorHasConstParam = Record.readInt(); + Data.ImplicitCopyConstructorCanHaveConstParamForVBase = Record.readInt(); + Data.ImplicitCopyConstructorCanHaveConstParamForNonVBase = Record.readInt(); Data.ImplicitCopyAssignmentHasConstParam = Record.readInt(); Data.HasDeclaredCopyConstructorWithConstParam = Record.readInt(); Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt(); + Data.ODRHash = Record.readInt(); + Data.HasODRHash = true; + + if (Record.readInt()) { + Reader.BodySource[D] = Loc.F->Kind == ModuleKind::MK_MainFile + ? ExternalASTSource::EK_Never + : ExternalASTSource::EK_Always; + } Data.NumBases = Record.readInt(); if (Data.NumBases) @@ -1641,7 +1668,8 @@ void ASTDeclReader::MergeDefinitionData( // ComputedVisibleConversions is handled below. MATCH_FIELD(UserProvidedDefaultConstructor) OR_FIELD(DeclaredSpecialMembers) - MATCH_FIELD(ImplicitCopyConstructorHasConstParam) + MATCH_FIELD(ImplicitCopyConstructorCanHaveConstParamForVBase) + MATCH_FIELD(ImplicitCopyConstructorCanHaveConstParamForNonVBase) MATCH_FIELD(ImplicitCopyAssignmentHasConstParam) OR_FIELD(HasDeclaredCopyConstructorWithConstParam) OR_FIELD(HasDeclaredCopyAssignmentWithConstParam) @@ -1669,6 +1697,10 @@ void ASTDeclReader::MergeDefinitionData( // when they occur within the body of a function template specialization). } + if (D->getODRHash() != MergeDD.ODRHash) { + DetectedOdrViolation = true; + } + if (DetectedOdrViolation) Reader.PendingOdrMergeFailures[DD.Definition].push_back(MergeDD.Definition); } @@ -1686,7 +1718,7 @@ void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update) { else DD = new (C) struct CXXRecordDecl::DefinitionData(D); - ReadCXXDefinitionData(*DD); + ReadCXXDefinitionData(*DD, D); // We might already have a definition for this record. This can happen either // because we're reading an update record, or because we've already done some @@ -1775,6 +1807,10 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) { return Redecl; } +void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) { + VisitFunctionDecl(D); +} + void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) { VisitFunctionDecl(D); @@ -1804,8 +1840,6 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { } VisitCXXMethodDecl(D); - - D->IsExplicitSpecified = Record.readInt(); } void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { @@ -1821,7 +1855,6 @@ void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) { VisitCXXMethodDecl(D); - D->IsExplicitSpecified = Record.readInt(); } void ASTDeclReader::VisitImportDecl(ImportDecl *D) { @@ -1831,7 +1864,7 @@ void ASTDeclReader::VisitImportDecl(ImportDecl *D) { SourceLocation *StoredLocs = D->getTrailingObjects<SourceLocation>(); for (unsigned I = 0, N = Record.back(); I != N; ++I) StoredLocs[I] = ReadSourceLocation(); - (void)Record.readInt(); // The number of stored source locations. + Record.skipInts(1); // The number of stored source locations. } void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) { @@ -1873,6 +1906,7 @@ DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) { DeclID PatternID = ReadDeclID(); NamedDecl *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID)); TemplateParameterList *TemplateParams = Record.readTemplateParameterList(); + // FIXME handle associated constraints D->init(TemplatedDecl, TemplateParams); return PatternID; @@ -2471,12 +2505,11 @@ void ASTDeclReader::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { //===----------------------------------------------------------------------===// /// \brief Reads attributes from the current stream position. -void ASTReader::ReadAttributes(ModuleFile &F, AttrVec &Attrs, - const RecordData &Record, unsigned &Idx) { - for (unsigned i = 0, e = Record[Idx++]; i != e; ++i) { +void ASTReader::ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs) { + for (unsigned i = 0, e = Record.readInt(); i != e; ++i) { Attr *New = nullptr; - attr::Kind Kind = (attr::Kind)Record[Idx++]; - SourceRange Range = ReadSourceRange(F, Record, Idx); + attr::Kind Kind = (attr::Kind)Record.readInt(); + SourceRange Range = Record.readSourceRange(); #include "clang/Serialization/AttrPCHRead.inc" @@ -2531,7 +2564,11 @@ static bool isConsumerInterestedIn(ASTContext &Ctx, Decl *D, bool HasBody) { Var->isThisDeclarationADefinition() == VarDecl::Definition; if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) return Func->doesThisDeclarationHaveABody() || HasBody; - + + if (auto *ES = D->getASTContext().getExternalSource()) + if (ES->hasExternalDefinitions(D) == ExternalASTSource::EK_Never) + return true; + return false; } @@ -2648,6 +2685,45 @@ static bool isSameTemplateParameterList(const TemplateParameterList *X, return true; } +/// Determine whether the attributes we can overload on are identical for A and +/// B. Will ignore any overloadable attrs represented in the type of A and B. +static bool hasSameOverloadableAttrs(const FunctionDecl *A, + const FunctionDecl *B) { + // Note that pass_object_size attributes are represented in the function's + // ExtParameterInfo, so we don't need to check them here. + + SmallVector<const EnableIfAttr *, 4> AEnableIfs; + // Since this is an equality check, we can ignore that enable_if attrs show up + // in reverse order. + for (const auto *EIA : A->specific_attrs<EnableIfAttr>()) + AEnableIfs.push_back(EIA); + + SmallVector<const EnableIfAttr *, 4> BEnableIfs; + for (const auto *EIA : B->specific_attrs<EnableIfAttr>()) + BEnableIfs.push_back(EIA); + + // Two very common cases: either we have 0 enable_if attrs, or we have an + // unequal number of enable_if attrs. + if (AEnableIfs.empty() && BEnableIfs.empty()) + return true; + + if (AEnableIfs.size() != BEnableIfs.size()) + return false; + + llvm::FoldingSetNodeID Cand1ID, Cand2ID; + for (unsigned I = 0, E = AEnableIfs.size(); I != E; ++I) { + Cand1ID.clear(); + Cand2ID.clear(); + + AEnableIfs[I]->getCond()->Profile(Cand1ID, A->getASTContext(), true); + BEnableIfs[I]->getCond()->Profile(Cand2ID, B->getASTContext(), true); + if (Cand1ID != Cand2ID) + return false; + } + + return true; +} + /// \brief Determine whether the two declarations refer to the same entity. static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!"); @@ -2703,8 +2779,24 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { CtorY->getInheritedConstructor().getConstructor())) return false; } - return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) && - FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType()); + ASTContext &C = FuncX->getASTContext(); + if (!C.hasSameType(FuncX->getType(), FuncY->getType())) { + // We can get functions with different types on the redecl chain in C++17 + // if they have differing exception specifications and at least one of + // the excpetion specs is unresolved. + // FIXME: Do we need to check for C++14 deduced return types here too? + auto *XFPT = FuncX->getType()->getAs<FunctionProtoType>(); + auto *YFPT = FuncY->getType()->getAs<FunctionProtoType>(); + if (C.getLangOpts().CPlusPlus1z && XFPT && YFPT && + (isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) || + isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) && + C.hasSameFunctionTypeIgnoringExceptionSpec(FuncX->getType(), + FuncY->getType())) + return true; + return false; + } + return FuncX->getLinkageInternal() == FuncY->getLinkageInternal() && + hasSameOverloadableAttrs(FuncX, FuncY); } // Variables with the same type and linkage match. @@ -3323,6 +3415,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_CXX_RECORD: D = CXXRecordDecl::CreateDeserialized(Context, ID); break; + case DECL_CXX_DEDUCTION_GUIDE: + D = CXXDeductionGuideDecl::CreateDeserialized(Context, ID); + break; case DECL_CXX_METHOD: D = CXXMethodDecl::CreateDeserialized(Context, ID); break; @@ -3531,12 +3626,37 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { // AST consumer might need to know about, queue it. // We don't pass it to the consumer immediately because we may be in recursive // loading, and some declarations may still be initializing. - if (isConsumerInterestedIn(Context, D, Reader.hasPendingBody())) - InterestingDecls.push_back(D); + PotentiallyInterestingDecls.push_back( + InterestingDecl(D, Reader.hasPendingBody())); return D; } +void ASTReader::PassInterestingDeclsToConsumer() { + assert(Consumer); + + if (PassingDeclsToConsumer) + return; + + // Guard variable to avoid recursively redoing the process of passing + // decls to consumer. + SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer, + true); + + // Ensure that we've loaded all potentially-interesting declarations + // that need to be eagerly loaded. + for (auto ID : EagerlyDeserializedDecls) + GetDecl(ID); + EagerlyDeserializedDecls.clear(); + + while (!PotentiallyInterestingDecls.empty()) { + InterestingDecl D = PotentiallyInterestingDecls.front(); + PotentiallyInterestingDecls.pop_front(); + if (isConsumerInterestedIn(Context, D.getDecl(), D.hasPendingBody())) + PassInterestingDeclToConsumer(D.getDecl()); + } +} + void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) { // 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 @@ -3547,6 +3667,9 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) { auto UpdateOffsets = std::move(UpdI->second); DeclUpdateOffsets.erase(UpdI); + // FIXME: This call to isConsumerInterestedIn is not safe because + // we could be deserializing declarations at the moment. We should + // delay calling this in the same way as done in D30793. bool WasInteresting = isConsumerInterestedIn(Context, D, false); for (auto &FileAndOffset : UpdateOffsets) { ModuleFile *F = FileAndOffset.first; @@ -3568,7 +3691,8 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) { // we need to hand it off to the consumer. if (!WasInteresting && isConsumerInterestedIn(Context, D, Reader.hasPendingBody())) { - InterestingDecls.push_back(D); + PotentiallyInterestingDecls.push_back( + InterestingDecl(D, Reader.hasPendingBody())); WasInteresting = true; } } @@ -3858,14 +3982,7 @@ void ASTDeclReader::UpdateDecl(Decl *D) { }); } FD->setInnerLocStart(ReadSourceLocation()); - if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) { - CD->NumCtorInitializers = Record.readInt(); - if (CD->NumCtorInitializers) - CD->CtorInitializers = ReadGlobalOffset(); - } - // Store the offset of the body so we can lazily load it later. - Reader.PendingBodies[FD] = GetCurrentCursorOffset(); - HasPendingBody = true; + ReadFunctionDefinition(FD); assert(Record.getIdx() == Record.size() && "lazy body must be last"); break; } diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 686a69bbbcd2d..a12fb8cf95a09 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -381,6 +381,11 @@ void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *S) { llvm_unreachable("unimplemented"); } +void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *S) { // FIXME: Implement coroutine serialization. llvm_unreachable("unimplemented"); @@ -665,7 +670,7 @@ void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) { E->setRHS(Record.readSubExpr()); E->setOpcode((BinaryOperator::Opcode)Record.readInt()); E->setOperatorLoc(ReadSourceLocation()); - E->setFPContractable((bool)Record.readInt()); + E->setFPFeatures(FPOptions(Record.readInt())); } void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) { @@ -1220,7 +1225,7 @@ void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { VisitCallExpr(E); E->Operator = (OverloadedOperatorKind)Record.readInt(); E->Range = Record.readSourceRange(); - E->setFPContractable((bool)Record.readInt()); + E->setFPFeatures(FPOptions(Record.readInt())); } void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { @@ -1928,7 +1933,8 @@ OMPClause *OMPClauseReader::readClause() { } void OMPClauseReader::VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C) { - C->setPreInitStmt(Reader->Record.readSubStmt()); + C->setPreInitStmt(Reader->Record.readSubStmt(), + static_cast<OpenMPDirectiveKind>(Reader->Record.readInt())); } void OMPClauseReader::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) { @@ -1937,6 +1943,7 @@ void OMPClauseReader::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) { } void OMPClauseReader::VisitOMPIfClause(OMPIfClause *C) { + VisitOMPClauseWithPreInit(C); C->setNameModifier(static_cast<OpenMPDirectiveKind>(Reader->Record.readInt())); C->setNameModifierLoc(Reader->ReadSourceLocation()); C->setColonLoc(Reader->ReadSourceLocation()); @@ -1950,6 +1957,7 @@ void OMPClauseReader::VisitOMPFinalClause(OMPFinalClause *C) { } void OMPClauseReader::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { + VisitOMPClauseWithPreInit(C); C->setNumThreads(Reader->Record.readSubExpr()); C->setLParenLoc(Reader->ReadSourceLocation()); } @@ -2297,11 +2305,13 @@ void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) { } void OMPClauseReader::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) { + VisitOMPClauseWithPreInit(C); C->setNumTeams(Reader->Record.readSubExpr()); C->setLParenLoc(Reader->ReadSourceLocation()); } void OMPClauseReader::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) { + VisitOMPClauseWithPreInit(C); C->setThreadLimit(Reader->Record.readSubExpr()); C->setLParenLoc(Reader->ReadSourceLocation()); } @@ -2566,6 +2576,8 @@ void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) { if (isOpenMPLoopBoundSharingDirective(D->getDirectiveKind())) { D->setPrevLowerBoundVariable(Record.readSubExpr()); D->setPrevUpperBoundVariable(Record.readSubExpr()); + D->setDistInc(Record.readSubExpr()); + D->setPrevEnsureUpperBound(Record.readSubExpr()); } SmallVector<Expr *, 4> Sub; unsigned CollapsedNum = D->getCollapsedNumber(); @@ -2909,7 +2921,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { llvm::BitstreamCursor &Cursor = F.DeclsCursor; // Map of offset to previously deserialized stmt. The offset points - /// just after the stmt record. + // just after the stmt record. llvm::DenseMap<uint64_t, Stmt *> StmtEntries; #ifndef NDEBUG diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 886523ea94319..bb869077f4cda 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -18,8 +18,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTUnresolvedSet.h" #include "clang/AST/Decl.h" -#include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" @@ -33,8 +33,9 @@ #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemOptions.h" -#include "clang/Basic/LangOptions.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/MemoryBufferCache.h" #include "clang/Basic/Module.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/SourceManager.h" @@ -64,20 +65,22 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitCodes.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" #include "llvm/Support/EndianStream.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/SHA1.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> @@ -348,6 +351,15 @@ void ASTTypeWriter::VisitAutoType(const AutoType *T) { Code = TYPE_AUTO; } +void ASTTypeWriter::VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType *T) { + Record.AddTemplateName(T->getTemplateName()); + Record.AddTypeRef(T->getDeducedType()); + if (T->getDeducedType().isNull()) + Record.push_back(T->isDependentType()); + Code = TYPE_DEDUCED_TEMPLATE_SPECIALIZATION; +} + void ASTTypeWriter::VisitTagType(const TagType *T) { Record.push_back(T->isDependentType()); Record.AddDeclRef(T->getDecl()->getCanonicalDecl()); @@ -414,8 +426,10 @@ ASTTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) { void ASTTypeWriter::VisitDependentSizedExtVectorType( const DependentSizedExtVectorType *T) { - // FIXME: Serialize this type (C++ only) - llvm_unreachable("Cannot serialize dependent sized extended vector types"); + Record.AddTypeRef(T->getElementType()); + Record.AddStmt(T->getSizeExpr()); + Record.AddSourceLocation(T->getAttributeLoc()); + Code = TYPE_DEPENDENT_SIZED_EXT_VECTOR; } void @@ -682,6 +696,11 @@ void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); } +void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc( + DeducedTemplateSpecializationTypeLoc TL) { + Record.AddSourceLocation(TL.getTemplateNameLoc()); +} + void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); } @@ -1001,7 +1020,6 @@ void ASTWriter::WriteBlockInfoBlock() { // Control Block. BLOCK(CONTROL_BLOCK); RECORD(METADATA); - RECORD(SIGNATURE); RECORD(MODULE_NAME); RECORD(MODULE_DIRECTORY); RECORD(MODULE_MAP_FILE); @@ -1014,7 +1032,6 @@ void ASTWriter::WriteBlockInfoBlock() { BLOCK(OPTIONS_BLOCK); RECORD(LANGUAGE_OPTIONS); RECORD(TARGET_OPTIONS); - RECORD(DIAGNOSTIC_OPTIONS); RECORD(FILE_SYSTEM_OPTIONS); RECORD(HEADER_SEARCH_OPTIONS); RECORD(PREPROCESSOR_OPTIONS); @@ -1029,6 +1046,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(IDENTIFIER_OFFSET); RECORD(IDENTIFIER_TABLE); RECORD(EAGERLY_DESERIALIZED_DECLS); + RECORD(MODULAR_CODEGEN_DECLS); RECORD(SPECIAL_TYPES); RECORD(STATISTICS); RECORD(TENTATIVE_DEFINITIONS); @@ -1049,7 +1067,6 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(UPDATE_VISIBLE); RECORD(DECL_UPDATE_OFFSETS); RECORD(DECL_UPDATES); - RECORD(DIAG_PRAGMA_MAPPINGS); RECORD(CUDA_SPECIAL_DECL_REFS); RECORD(HEADER_SEARCH_TABLE); RECORD(FP_PRAGMA_OPTIONS); @@ -1242,6 +1259,11 @@ void ASTWriter::WriteBlockInfoBlock() { BLOCK(EXTENSION_BLOCK); RECORD(EXTENSION_METADATA); + BLOCK(UNHASHED_CONTROL_BLOCK); + RECORD(SIGNATURE); + RECORD(DIAGNOSTIC_OPTIONS); + RECORD(DIAG_PRAGMA_MAPPINGS); + #undef RECORD #undef BLOCK Stream.ExitBlock(); @@ -1304,21 +1326,73 @@ adjustFilenameForRelocatableAST(const char *Filename, StringRef BaseDir) { return Filename + Pos; } -static ASTFileSignature getSignature() { - while (true) { - if (ASTFileSignature S = llvm::sys::Process::GetRandomNumber()) - return S; - // Rely on GetRandomNumber to eventually return non-zero... +ASTFileSignature ASTWriter::createSignature(StringRef Bytes) { + // Calculate the hash till start of UNHASHED_CONTROL_BLOCK. + llvm::SHA1 Hasher; + Hasher.update(ArrayRef<uint8_t>(Bytes.bytes_begin(), Bytes.size())); + auto Hash = Hasher.result(); + + // Convert to an array [5*i32]. + ASTFileSignature Signature; + auto LShift = [&](unsigned char Val, unsigned Shift) { + return (uint32_t)Val << Shift; + }; + for (int I = 0; I != 5; ++I) + Signature[I] = LShift(Hash[I * 4 + 0], 24) | LShift(Hash[I * 4 + 1], 16) | + LShift(Hash[I * 4 + 2], 8) | LShift(Hash[I * 4 + 3], 0); + + return Signature; +} + +ASTFileSignature ASTWriter::writeUnhashedControlBlock(Preprocessor &PP, + ASTContext &Context) { + // Flush first to prepare the PCM hash (signature). + Stream.FlushToWord(); + auto StartOfUnhashedControl = Stream.GetCurrentBitNo() >> 3; + + // Enter the block and prepare to write records. + RecordData Record; + Stream.EnterSubblock(UNHASHED_CONTROL_BLOCK_ID, 5); + + // For implicit modules, write the hash of the PCM as its signature. + ASTFileSignature Signature; + if (WritingModule && + PP.getHeaderSearchInfo().getHeaderSearchOpts().ModulesHashContent) { + Signature = createSignature(StringRef(Buffer.begin(), StartOfUnhashedControl)); + Record.append(Signature.begin(), Signature.end()); + Stream.EmitRecord(SIGNATURE, Record); + Record.clear(); } + + // Diagnostic options. + const auto &Diags = Context.getDiagnostics(); + const DiagnosticOptions &DiagOpts = Diags.getDiagnosticOptions(); +#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name); +#define ENUM_DIAGOPT(Name, Type, Bits, Default) \ + Record.push_back(static_cast<unsigned>(DiagOpts.get##Name())); +#include "clang/Basic/DiagnosticOptions.def" + Record.push_back(DiagOpts.Warnings.size()); + for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I) + AddString(DiagOpts.Warnings[I], Record); + Record.push_back(DiagOpts.Remarks.size()); + for (unsigned I = 0, N = DiagOpts.Remarks.size(); I != N; ++I) + AddString(DiagOpts.Remarks[I], Record); + // Note: we don't serialize the log or serialization file names, because they + // are generally transient files and will almost always be overridden. + Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record); + + // Write out the diagnostic/pragma mappings. + WritePragmaDiagnosticMappings(Diags, /* IsModule = */ WritingModule); + + // Leave the options block. + Stream.ExitBlock(); + return Signature; } /// \brief Write the control block. -uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP, - ASTContext &Context, - StringRef isysroot, - const std::string &OutputFile) { - ASTFileSignature Signature = 0; - +void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, + StringRef isysroot, + const std::string &OutputFile) { using namespace llvm; Stream.EnterSubblock(CONTROL_BLOCK_ID, 5); RecordData Record; @@ -1346,15 +1420,6 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP, 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) { - Signature = getSignature(); - RecordData::value_type Record[] = {Signature}; - Stream.EmitRecord(SIGNATURE, Record); - } // Module name auto Abbrev = std::make_shared<BitCodeAbbrev>(); @@ -1420,17 +1485,23 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP, serialization::ModuleManager &Mgr = Chain->getModuleManager(); Record.clear(); - for (auto *M : Mgr) { + for (ModuleFile &M : Mgr) { // Skip modules that weren't directly imported. - if (!M->isDirectlyImported()) + if (!M.isDirectlyImported()) continue; - Record.push_back((unsigned)M->Kind); // FIXME: Stable encoding - AddSourceLocation(M->ImportLoc, Record); - Record.push_back(M->File->getSize()); - Record.push_back(getTimestampForOutput(M->File)); - Record.push_back(M->Signature); - AddPath(M->FileName, Record); + Record.push_back((unsigned)M.Kind); // FIXME: Stable encoding + AddSourceLocation(M.ImportLoc, Record); + + // If we have calculated signature, there is no need to store + // the size or timestamp. + Record.push_back(M.Signature ? 0 : M.File->getSize()); + Record.push_back(M.Signature ? 0 : getTimestampForOutput(M.File)); + + for (auto I : M.Signature) + Record.push_back(I); + + AddPath(M.FileName, Record); } Stream.EmitRecord(IMPORTS, Record); } @@ -1492,24 +1563,6 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP, } Stream.EmitRecord(TARGET_OPTIONS, Record); - // Diagnostic options. - Record.clear(); - const DiagnosticOptions &DiagOpts - = Context.getDiagnostics().getDiagnosticOptions(); -#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name); -#define ENUM_DIAGOPT(Name, Type, Bits, Default) \ - Record.push_back(static_cast<unsigned>(DiagOpts.get##Name())); -#include "clang/Basic/DiagnosticOptions.def" - Record.push_back(DiagOpts.Warnings.size()); - for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I) - AddString(DiagOpts.Warnings[I], Record); - Record.push_back(DiagOpts.Remarks.size()); - for (unsigned I = 0, N = DiagOpts.Remarks.size(); I != N; ++I) - AddString(DiagOpts.Remarks[I], Record); - // Note: we don't serialize the log or serialization file names, because they - // are generally transient files and will almost always be overridden. - Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record); - // File system options. Record.clear(); const FileSystemOptions &FSOpts = @@ -1623,7 +1676,6 @@ uint64_t ASTWriter::WriteControlBlock(Preprocessor &PP, PP.getHeaderSearchInfo().getHeaderSearchOpts(), PP.getLangOpts().Modules); Stream.ExitBlock(); - return Signature; } namespace { @@ -1986,6 +2038,30 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { free(const_cast<char *>(SavedStrings[I])); } +static void emitBlob(llvm::BitstreamWriter &Stream, StringRef Blob, + unsigned SLocBufferBlobCompressedAbbrv, + unsigned SLocBufferBlobAbbrv) { + typedef ASTWriter::RecordData::value_type RecordDataType; + + // Compress the buffer if possible. We expect that almost all PCM + // consumers will not want its contents. + SmallString<0> CompressedBuffer; + if (llvm::zlib::isAvailable()) { + llvm::Error E = llvm::zlib::compress(Blob.drop_back(1), CompressedBuffer); + if (!E) { + RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, + Blob.size() - 1}; + Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record, + CompressedBuffer); + return; + } + llvm::consumeError(std::move(E)); + } + + RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB}; + Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, Blob); +} + /// \brief Writes the block containing the serialized form of the /// source manager. /// @@ -2094,20 +2170,8 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, const llvm::MemoryBuffer *Buffer = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager()); StringRef Blob(Buffer->getBufferStart(), Buffer->getBufferSize() + 1); - - // Compress the buffer if possible. We expect that almost all PCM - // consumers will not want its contents. - SmallString<0> CompressedBuffer; - if (llvm::zlib::compress(Blob.drop_back(1), CompressedBuffer) == - llvm::zlib::StatusOK) { - RecordData::value_type Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, - Blob.size() - 1}; - Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record, - CompressedBuffer); - } else { - RecordData::value_type Record[] = {SM_SLOC_BUFFER_BLOB}; - Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, Blob); - } + emitBlob(Stream, Blob, SLocBufferBlobCompressedAbbrv, + SLocBufferBlobAbbrv); } } else { // The source location entry is a macro expansion. @@ -2516,7 +2580,8 @@ unsigned ASTWriter::getLocalOrImportedSubmoduleID(Module *Mod) { auto *Top = Mod->getTopLevelModule(); if (Top != WritingModule && - !Top->fullModuleNameIs(StringRef(getLangOpts().CurrentModule))) + (getLangOpts().CompilingPCH || + !Top->fullModuleNameIs(StringRef(getLangOpts().CurrentModule)))) return 0; return SubmoduleIDs[Mod] = NextSubmoduleID++; @@ -2650,11 +2715,17 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { // 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}; + 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); } @@ -2789,43 +2860,68 @@ ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) { void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, bool isModule) { - // Make sure set diagnostic pragmas don't affect the translation unit that - // imports the module. - // FIXME: Make diagnostic pragma sections work properly with modules. - if (isModule) - return; - llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64> DiagStateIDMap; unsigned CurrID = 0; - DiagStateIDMap[&Diag.DiagStates.front()] = ++CurrID; // the command-line one. RecordData Record; - for (DiagnosticsEngine::DiagStatePointsTy::const_iterator - I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end(); - I != E; ++I) { - const DiagnosticsEngine::DiagStatePoint &point = *I; - if (point.Loc.isInvalid()) - continue; - AddSourceLocation(point.Loc, Record); - unsigned &DiagStateID = DiagStateIDMap[point.State]; + auto AddDiagState = [&](const DiagnosticsEngine::DiagState *State, + bool IncludeNonPragmaStates) { + unsigned &DiagStateID = DiagStateIDMap[State]; Record.push_back(DiagStateID); - + if (DiagStateID == 0) { DiagStateID = ++CurrID; - for (const auto &I : *(point.State)) { - if (I.second.isPragma()) { + + // Add a placeholder for the number of mappings. + auto SizeIdx = Record.size(); + Record.emplace_back(); + for (const auto &I : *State) { + if (I.second.isPragma() || IncludeNonPragmaStates) { Record.push_back(I.first); - Record.push_back((unsigned)I.second.getSeverity()); + Record.push_back(I.second.serializeBits()); } } - Record.push_back(-1); // mark the end of the diag/map pairs for this - // location. + // Update the placeholder. + Record[SizeIdx] = (Record.size() - SizeIdx) / 2; + } + }; + + AddDiagState(Diag.DiagStatesByLoc.FirstDiagState, isModule); + + // Reserve a spot for the number of locations with state transitions. + auto NumLocationsIdx = Record.size(); + Record.emplace_back(); + + // Emit the state transitions. + unsigned NumLocations = 0; + for (auto &FileIDAndFile : Diag.DiagStatesByLoc.Files) { + if (!FileIDAndFile.first.isValid() || + !FileIDAndFile.second.HasLocalTransitions) + continue; + ++NumLocations; + AddSourceLocation(Diag.SourceMgr->getLocForStartOfFile(FileIDAndFile.first), + Record); + Record.push_back(FileIDAndFile.second.StateTransitions.size()); + for (auto &StatePoint : FileIDAndFile.second.StateTransitions) { + Record.push_back(StatePoint.Offset); + AddDiagState(StatePoint.State, false); } } - if (!Record.empty()) - Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record); + // Backpatch the number of locations. + Record[NumLocationsIdx] = NumLocations; + + // Emit CurDiagStateLoc. Do it last in order to match source order. + // + // This also protects against a hypothetical corner case with simulating + // -Werror settings for implicit modules in the ASTReader, where reading + // CurDiagState out of context could change whether warning pragmas are + // treated as errors. + AddSourceLocation(Diag.DiagStatesByLoc.CurDiagStateLoc, Record); + AddDiagState(Diag.DiagStatesByLoc.CurDiagState, false); + + Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record); } //===----------------------------------------------------------------------===// @@ -3559,6 +3655,7 @@ public: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: KeyLen += 4; break; case DeclarationName::CXXOperatorName: @@ -3588,6 +3685,7 @@ public: switch (Name.getKind()) { case DeclarationName::Identifier: case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: LE.write<uint32_t>(Writer.getIdentifierRef(Name.getIdentifier())); return; case DeclarationName::ObjCZeroArgSelector: @@ -3931,7 +4029,7 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) { /// \brief Write an FP_PRAGMA_OPTIONS block for the given FPOptions. void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) { - RecordData::value_type Record[] = {Opts.fp_contract}; + RecordData::value_type Record[] = {Opts.getInt()}; Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record); } @@ -4086,6 +4184,25 @@ void ASTWriter::WriteMSPointersToMembersPragmaOptions(Sema &SemaRef) { Stream.EmitRecord(POINTERS_TO_MEMBERS_PRAGMA_OPTIONS, Record); } +/// \brief Write the state of 'pragma pack' at the end of the module. +void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) { + // Don't serialize pragma pack state for modules, since it should only take + // effect on a per-submodule basis. + if (WritingModule) + return; + + RecordData Record; + Record.push_back(SemaRef.PackStack.CurrentValue); + AddSourceLocation(SemaRef.PackStack.CurrentPragmaLocation, Record); + Record.push_back(SemaRef.PackStack.Stack.size()); + for (const auto &StackEntry : SemaRef.PackStack.Stack) { + Record.push_back(StackEntry.Value); + AddSourceLocation(StackEntry.PragmaLocation, Record); + AddString(StackEntry.StackSlotLabel, Record); + } + Stream.EmitRecord(PACK_PRAGMA_OPTIONS, Record); +} + void ASTWriter::WriteModuleFileExtension(Sema &SemaRef, ModuleFileExtensionWriter &Writer) { // Enter the extension block. @@ -4223,9 +4340,11 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) { } ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream, + SmallVectorImpl<char> &Buffer, MemoryBufferCache &PCMCache, ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, bool IncludeTimestamps) - : Stream(Stream), IncludeTimestamps(IncludeTimestamps) { + : Stream(Stream), Buffer(Buffer), PCMCache(PCMCache), + IncludeTimestamps(IncludeTimestamps) { for (const auto &Ext : Extensions) { if (auto Writer = Ext->createExtensionWriter(*this)) ModuleFileExtensionWriters.push_back(std::move(Writer)); @@ -4245,9 +4364,10 @@ 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) { +ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef, + const std::string &OutputFile, + Module *WritingModule, StringRef isysroot, + bool hasErrors) { WritingAST = true; ASTHasCompilerErrors = hasErrors; @@ -4271,6 +4391,12 @@ uint64_t ASTWriter::WriteAST(Sema &SemaRef, const std::string &OutputFile, this->BaseDirectory.clear(); WritingAST = false; + if (SemaRef.Context.getLangOpts().ImplicitModules && WritingModule) { + // Construct MemoryBuffer and update buffer manager. + PCMCache.addBuffer(OutputFile, + llvm::MemoryBuffer::getMemBufferCopy( + StringRef(Buffer.begin(), Buffer.size()))); + } return Signature; } @@ -4283,9 +4409,9 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec, } } -uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, - const std::string &OutputFile, - Module *WritingModule) { +ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, + const std::string &OutputFile, + Module *WritingModule) { using namespace llvm; bool isModule = WritingModule != nullptr; @@ -4433,7 +4559,7 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, } // Write the control block - uint64_t Signature = WriteControlBlock(PP, Context, isysroot, OutputFile); + WriteControlBlock(PP, Context, isysroot, OutputFile); // Write the remaining AST contents. Stream.EnterSubblock(AST_BLOCK_ID, 5); @@ -4573,10 +4699,10 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, SmallString<2048> Buffer; { llvm::raw_svector_ostream Out(Buffer); - for (ModuleFile *M : Chain->ModuleMgr) { + for (ModuleFile &M : Chain->ModuleMgr) { using namespace llvm::support; endian::Writer<little> LE(Out); - StringRef FileName = M->FileName; + StringRef FileName = M.FileName; LE.write<uint16_t>(FileName.size()); Out.write(FileName.data(), FileName.size()); @@ -4594,15 +4720,15 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, // These values should be unique within a chain, since they will be read // as keys into ContinuousRangeMaps. - writeBaseIDOrNone(M->SLocEntryBaseOffset, M->LocalNumSLocEntries); - writeBaseIDOrNone(M->BaseIdentifierID, M->LocalNumIdentifiers); - writeBaseIDOrNone(M->BaseMacroID, M->LocalNumMacros); - writeBaseIDOrNone(M->BasePreprocessedEntityID, - M->NumPreprocessedEntities); - writeBaseIDOrNone(M->BaseSubmoduleID, M->LocalNumSubmodules); - writeBaseIDOrNone(M->BaseSelectorID, M->LocalNumSelectors); - writeBaseIDOrNone(M->BaseDeclID, M->LocalNumDecls); - writeBaseIDOrNone(M->BaseTypeIndex, M->LocalNumTypes); + writeBaseIDOrNone(M.SLocEntryBaseOffset, M.LocalNumSLocEntries); + writeBaseIDOrNone(M.BaseIdentifierID, M.LocalNumIdentifiers); + writeBaseIDOrNone(M.BaseMacroID, M.LocalNumMacros); + writeBaseIDOrNone(M.BasePreprocessedEntityID, + M.NumPreprocessedEntities); + writeBaseIDOrNone(M.BaseSubmoduleID, M.LocalNumSubmodules); + writeBaseIDOrNone(M.BaseSelectorID, M.LocalNumSelectors); + writeBaseIDOrNone(M.BaseDeclID, M.LocalNumDecls); + writeBaseIDOrNone(M.BaseTypeIndex, M.LocalNumTypes); } } RecordData::value_type Record[] = {MODULE_OFFSET_MAP}; @@ -4650,7 +4776,6 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, WriteOpenCLExtensionTypes(SemaRef); WriteOpenCLExtensionDecls(SemaRef); WriteCUDAPragmas(SemaRef); - WritePragmaDiagnosticMappings(Context.getDiagnostics(), isModule); // If we're emitting a module, write out the submodule information. if (WritingModule) @@ -4662,6 +4787,9 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, if (!EagerlyDeserializedDecls.empty()) Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls); + if (!ModularCodegenDecls.empty()) + Stream.EmitRecord(MODULAR_CODEGEN_DECLS, ModularCodegenDecls); + // Write the record containing tentative definitions. if (!TentativeDefinitions.empty()) Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions); @@ -4765,6 +4893,7 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, WriteMSStructPragmaOptions(SemaRef); WriteMSPointersToMembersPragmaOptions(SemaRef); } + WritePackPragmaOptions(SemaRef); // Some simple statistics RecordData::value_type Record[] = { @@ -4776,7 +4905,7 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, for (const auto &ExtWriter : ModuleFileExtensionWriters) WriteModuleFileExtension(SemaRef, *ExtWriter); - return Signature; + return writeUnhashedControlBlock(PP, Context); } void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { @@ -5229,6 +5358,10 @@ void ASTRecordWriter::AddDeclarationName(DeclarationName Name) { AddTypeRef(Name.getCXXNameType()); break; + case DeclarationName::CXXDeductionGuideName: + AddDeclRef(Name.getCXXDeductionGuideTemplate()); + break; + case DeclarationName::CXXOperatorName: Record->push_back(Name.getCXXOverloadedOperator()); break; @@ -5290,6 +5423,7 @@ void ASTRecordWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc, case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: break; } } @@ -5651,10 +5785,20 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { Record->push_back(Data.ComputedVisibleConversions); Record->push_back(Data.UserProvidedDefaultConstructor); Record->push_back(Data.DeclaredSpecialMembers); - Record->push_back(Data.ImplicitCopyConstructorHasConstParam); + Record->push_back(Data.ImplicitCopyConstructorCanHaveConstParamForVBase); + Record->push_back(Data.ImplicitCopyConstructorCanHaveConstParamForNonVBase); Record->push_back(Data.ImplicitCopyAssignmentHasConstParam); Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam); Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam); + + // getODRHash will compute the ODRHash if it has not been previously computed. + Record->push_back(D->getODRHash()); + bool ModulesDebugInfo = Writer->Context->getLangOpts().ModulesDebugInfo && + Writer->WritingModule && !D->isDependentType(); + Record->push_back(ModulesDebugInfo); + if (ModulesDebugInfo) + Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(D)); + // IsLambda bit is already saved. Record->push_back(Data.NumBases); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index d8466e9cbf3ba..812cd9e916d91 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -86,6 +86,7 @@ namespace clang { void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitDeclaratorDecl(DeclaratorDecl *D); void VisitFunctionDecl(FunctionDecl *D); + void VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D); void VisitCXXMethodDecl(CXXMethodDecl *D); void VisitCXXConstructorDecl(CXXConstructorDecl *D); void VisitCXXDestructorDecl(CXXDestructorDecl *D); @@ -368,6 +369,7 @@ void ASTDeclWriter::VisitTypedefNameDecl(TypedefNameDecl *D) { Record.push_back(D->isModed()); if (D->isModed()) Record.AddTypeRef(D->getUnderlyingType()); + Record.AddDeclRef(D->getAnonDeclWithTypedefName(false)); } void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) { @@ -519,6 +521,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back((int)D->SClass); // FIXME: stable encoding Record.push_back(D->IsInline); Record.push_back(D->IsInlineSpecified); + Record.push_back(D->IsExplicitSpecified); Record.push_back(D->IsVirtualAsWritten); Record.push_back(D->IsPure); Record.push_back(D->HasInheritedPrototype); @@ -607,6 +610,11 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Code = serialization::DECL_FUNCTION; } +void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) { + VisitFunctionDecl(D); + Code = serialization::DECL_CXX_DEDUCTION_GUIDE; +} + void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { VisitNamedDecl(D); // FIXME: convert to LazyStmtPtr? @@ -791,7 +799,9 @@ void ASTDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { // FIXME: stable encoding Record.push_back((unsigned)D->getPropertyImplementation()); Record.AddDeclarationName(D->getGetterName()); + Record.AddSourceLocation(D->getGetterNameLoc()); Record.AddDeclarationName(D->getSetterName()); + Record.AddSourceLocation(D->getSetterNameLoc()); Record.AddDeclRef(D->getGetterMethodDecl()); Record.AddDeclRef(D->getSetterMethodDecl()); Record.AddDeclRef(D->getPropertyIvarDecl()); @@ -806,7 +816,6 @@ void ASTDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) { void ASTDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { VisitObjCImplDecl(D); - Record.AddIdentifierRef(D->getIdentifier()); Record.AddSourceLocation(D->getCategoryNameLoc()); Code = serialization::DECL_OBJC_CATEGORY_IMPL; } @@ -1268,8 +1277,6 @@ void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { VisitCXXMethodDecl(D); - Record.push_back(D->IsExplicitSpecified); - Code = D->isInheritingConstructor() ? serialization::DECL_CXX_INHERITED_CONSTRUCTOR : serialization::DECL_CXX_CONSTRUCTOR; @@ -1285,7 +1292,6 @@ void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) { VisitCXXMethodDecl(D); - Record.push_back(D->IsExplicitSpecified); Code = serialization::DECL_CXX_CONVERSION; } @@ -2023,6 +2029,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // StorageClass Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Inline Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InlineSpecified + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ExplicitSpecified Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // VirtualAsWritten Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Pure Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedProto @@ -2221,6 +2228,11 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) { Writer->ClearSwitchCaseIDs(); assert(FD->doesThisDeclarationHaveABody()); + bool ModulesCodegen = Writer->Context->getLangOpts().ModulesCodegen && + Writer->WritingModule && !FD->isDependentContext(); + Record->push_back(ModulesCodegen); + if (ModulesCodegen) + Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(FD)); if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) { Record->push_back(CD->getNumCtorInitializers()); if (CD->getNumCtorInitializers()) diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 01fd98ceadb2c..1a2edac658865 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -315,6 +315,11 @@ void ASTStmtWriter::VisitCoawaitExpr(CoawaitExpr *S) { llvm_unreachable("unimplemented"); } +void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *S) { + // FIXME: Implement coroutine serialization. + llvm_unreachable("unimplemented"); +} + void ASTStmtWriter::VisitCoyieldExpr(CoyieldExpr *S) { // FIXME: Implement coroutine serialization. llvm_unreachable("unimplemented"); @@ -645,7 +650,7 @@ void ASTStmtWriter::VisitBinaryOperator(BinaryOperator *E) { Record.AddStmt(E->getRHS()); Record.push_back(E->getOpcode()); // FIXME: stable encoding Record.AddSourceLocation(E->getOperatorLoc()); - Record.push_back(E->isFPContractable()); + Record.push_back(E->getFPFeatures().getInt()); Code = serialization::EXPR_BINARY_OPERATOR; } @@ -1213,7 +1218,7 @@ void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { VisitCallExpr(E); Record.push_back(E->getOperator()); Record.AddSourceRange(E->Range); - Record.push_back(E->isFPContractable()); + Record.push_back(E->getFPFeatures().getInt()); Code = serialization::EXPR_CXX_OPERATOR_CALL; } @@ -1794,6 +1799,7 @@ void OMPClauseWriter::writeClause(OMPClause *C) { } void OMPClauseWriter::VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C) { + Record.push_back(C->getCaptureRegion()); Record.AddStmt(C->getPreInitStmt()); } @@ -1803,6 +1809,7 @@ void OMPClauseWriter::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) { } void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) { + VisitOMPClauseWithPreInit(C); Record.push_back(C->getNameModifier()); Record.AddSourceLocation(C->getNameModifierLoc()); Record.AddSourceLocation(C->getColonLoc()); @@ -1816,6 +1823,7 @@ void OMPClauseWriter::VisitOMPFinalClause(OMPFinalClause *C) { } void OMPClauseWriter::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { + VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getNumThreads()); Record.AddSourceLocation(C->getLParenLoc()); } @@ -2064,11 +2072,13 @@ void OMPClauseWriter::VisitOMPMapClause(OMPMapClause *C) { } void OMPClauseWriter::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) { + VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getNumTeams()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) { + VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getThreadLimit()); Record.AddSourceLocation(C->getLParenLoc()); } @@ -2236,6 +2246,8 @@ void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) { if (isOpenMPLoopBoundSharingDirective(D->getDirectiveKind())) { Record.AddStmt(D->getPrevLowerBoundVariable()); Record.AddStmt(D->getPrevUpperBoundVariable()); + Record.AddStmt(D->getDistInc()); + Record.AddStmt(D->getPrevEnsureUpperBound()); } for (auto I : D->counters()) { Record.AddStmt(I); diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp index 7f1b75055b455..2e0076521f9c0 100644 --- a/lib/Serialization/GeneratePCH.cpp +++ b/lib/Serialization/GeneratePCH.cpp @@ -27,10 +27,11 @@ PCHGenerator::PCHGenerator( ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, bool AllowASTWithErrors, bool IncludeTimestamps) : PP(PP), OutputFile(OutputFile), isysroot(isysroot.str()), - SemaPtr(nullptr), Buffer(Buffer), Stream(Buffer->Data), - Writer(Stream, Extensions, IncludeTimestamps), + SemaPtr(nullptr), Buffer(std::move(Buffer)), Stream(this->Buffer->Data), + Writer(Stream, this->Buffer->Data, PP.getPCMCache(), Extensions, + IncludeTimestamps), AllowASTWithErrors(AllowASTWithErrors) { - Buffer->IsComplete = false; + this->Buffer->IsComplete = false; } PCHGenerator::~PCHGenerator() { diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp index ae5796ede126e..6978e7e09774f 100644 --- a/lib/Serialization/GlobalModuleIndex.cpp +++ b/lib/Serialization/GlobalModuleIndex.cpp @@ -376,6 +376,15 @@ namespace { /// \brief The set of modules on which this module depends. Each entry is /// a module ID. SmallVector<unsigned, 4> Dependencies; + ASTFileSignature Signature; + }; + + struct ImportedModuleFileInfo { + off_t StoredSize; + time_t StoredModTime; + ASTFileSignature StoredSignature; + ImportedModuleFileInfo(off_t Size, time_t ModTime, ASTFileSignature Sig) + : StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {} }; /// \brief Builder that generates the global module index file. @@ -383,12 +392,20 @@ namespace { FileManager &FileMgr; const PCHContainerReader &PCHContainerRdr; - /// \brief Mapping from files to module file information. + /// Mapping from files to module file information. typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap; - /// \brief Information about each of the known module files. + /// Information about each of the known module files. ModuleFilesMap ModuleFiles; + /// \brief Mapping from the imported module file to the imported + /// information. + typedef std::multimap<const FileEntry *, ImportedModuleFileInfo> + ImportedModuleFilesMap; + + /// \brief Information about each importing of a module file. + ImportedModuleFilesMap ImportedModuleFiles; + /// \brief Mapping from identifiers to the list of module file IDs that /// consider this identifier to be interesting. typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap; @@ -424,7 +441,8 @@ namespace { bool loadModuleFile(const FileEntry *File); /// \brief Write the index to the given bitstream. - void writeIndex(llvm::BitstreamWriter &Stream); + /// \returns true if an error occurred, false otherwise. + bool writeIndex(llvm::BitstreamWriter &Stream); }; } @@ -515,7 +533,7 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { unsigned ID = getModuleFileInfo(File).ID; // Search for the blocks and records we care about. - enum { Other, ControlBlock, ASTBlock } State = Other; + enum { Other, ControlBlock, ASTBlock, DiagnosticOptionsBlock } State = Other; bool Done = false; while (!Done) { llvm::BitstreamEntry Entry = InStream.advance(); @@ -553,6 +571,15 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { continue; } + if (Entry.ID == UNHASHED_CONTROL_BLOCK_ID) { + if (InStream.EnterSubBlock(UNHASHED_CONTROL_BLOCK_ID)) + return true; + + // Found the Diagnostic Options block. + State = DiagnosticOptionsBlock; + continue; + } + if (InStream.SkipBlock()) return true; @@ -587,7 +614,10 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { // Skip the stored signature. // FIXME: we could read the signature out of the import and validate it. - Idx++; + ASTFileSignature StoredSignature = { + {{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++], + (uint32_t)Record[Idx++], (uint32_t)Record[Idx++], + (uint32_t)Record[Idx++]}}}; // Retrieve the imported file name. unsigned Length = Record[Idx++]; @@ -599,11 +629,16 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { const FileEntry *DependsOnFile = FileMgr.getFile(ImportedFile, /*openFile=*/false, /*cacheFailure=*/false); - if (!DependsOnFile || - (StoredSize != DependsOnFile->getSize()) || - (StoredModTime != DependsOnFile->getModificationTime())) + + if (!DependsOnFile) return true; + // Save the information in ImportedModuleFileInfo so we can verify after + // loading all pcms. + ImportedModuleFiles.insert(std::make_pair( + DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime, + StoredSignature))); + // Record the dependency. unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID; getModuleFileInfo(File).Dependencies.push_back(DependsOnID); @@ -632,6 +667,12 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { } } + // Get Signature. + if (State == DiagnosticOptionsBlock && Code == SIGNATURE) + getModuleFileInfo(File).Signature = { + {{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2], + (uint32_t)Record[3], (uint32_t)Record[4]}}}; + // We don't care about this record. } @@ -680,7 +721,20 @@ public: } -void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) { +bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) { + for (auto MapEntry : ImportedModuleFiles) { + auto *File = MapEntry.first; + ImportedModuleFileInfo &Info = MapEntry.second; + if (getModuleFileInfo(File).Signature) { + if (getModuleFileInfo(File).Signature != Info.StoredSignature) + // Verify Signature. + return true; + } else if (Info.StoredSize != File->getSize() || + Info.StoredModTime != File->getModificationTime()) + // Verify Size and ModTime. + return true; + } + using namespace llvm; // Emit the file header. @@ -756,6 +810,7 @@ void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) { } Stream.ExitBlock(); + return false; } GlobalModuleIndex::ErrorCode @@ -816,7 +871,8 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr, SmallVector<char, 16> OutputBuffer; { llvm::BitstreamWriter OutputStream(OutputBuffer); - Builder.writeIndex(OutputStream); + if (Builder.writeIndex(OutputStream)) + return EC_IOError; } // Write the global index file to a temporary file. diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp index 72b08610bb4d3..5a44d26fe3998 100644 --- a/lib/Serialization/Module.cpp +++ b/lib/Serialization/Module.cpp @@ -19,28 +19,6 @@ using namespace clang; using namespace serialization; using namespace reader; -ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation) - : Kind(Kind), File(nullptr), Signature(0), DirectlyImported(false), - Generation(Generation), SizeInBits(0), - LocalNumSLocEntries(0), SLocEntryBaseID(0), - SLocEntryBaseOffset(0), SLocEntryOffsets(nullptr), - LocalNumIdentifiers(0), - IdentifierOffsets(nullptr), BaseIdentifierID(0), - IdentifierTableData(nullptr), IdentifierLookupTable(nullptr), - LocalNumMacros(0), MacroOffsets(nullptr), - BasePreprocessedEntityID(0), - PreprocessedEntityOffsets(nullptr), NumPreprocessedEntities(0), - LocalNumHeaderFileInfos(0), - HeaderFileInfoTableData(nullptr), HeaderFileInfoTable(nullptr), - LocalNumSubmodules(0), BaseSubmoduleID(0), - LocalNumSelectors(0), SelectorOffsets(nullptr), BaseSelectorID(0), - SelectorLookupTableData(nullptr), SelectorLookupTable(nullptr), - LocalNumDecls(0), DeclOffsets(nullptr), BaseDeclID(0), - FileSortedDecls(nullptr), NumFileSortedDecls(0), - ObjCCategoriesMap(nullptr), LocalNumObjCCategoriesInMap(0), - LocalNumTypes(0), TypeOffsets(nullptr), BaseTypeIndex(0) -{} - ModuleFile::~ModuleFile() { delete static_cast<ASTIdentifierLookupTable *>(IdentifierLookupTable); delete static_cast<HeaderFileInfoLookupTable *>(HeaderFileInfoTable); diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp index 722b547e803e4..1dee4d0698616 100644 --- a/lib/Serialization/ModuleManager.cpp +++ b/lib/Serialization/ModuleManager.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// #include "clang/Serialization/ModuleManager.h" +#include "clang/Basic/MemoryBufferCache.h" #include "clang/Frontend/PCHContainerOperations.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/ModuleMap.h" @@ -27,7 +28,7 @@ using namespace clang; using namespace serialization; -ModuleFile *ModuleManager::lookup(StringRef Name) { +ModuleFile *ModuleManager::lookup(StringRef Name) const { const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false, /*cacheFailure=*/false); if (Entry) @@ -36,9 +37,8 @@ ModuleFile *ModuleManager::lookup(StringRef Name) { return nullptr; } -ModuleFile *ModuleManager::lookup(const FileEntry *File) { - llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known - = Modules.find(File); +ModuleFile *ModuleManager::lookup(const FileEntry *File) const { + auto Known = Modules.find(File); if (Known == Modules.end()) return nullptr; @@ -52,6 +52,30 @@ ModuleManager::lookupBuffer(StringRef Name) { return std::move(InMemoryBuffers[Entry]); } +static bool checkSignature(ASTFileSignature Signature, + ASTFileSignature ExpectedSignature, + std::string &ErrorStr) { + if (!ExpectedSignature || Signature == ExpectedSignature) + return false; + + ErrorStr = + Signature ? "signature mismatch" : "could not read module signature"; + return true; +} + +static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy, + SourceLocation ImportLoc) { + if (ImportedBy) { + MF.ImportedBy.insert(ImportedBy); + ImportedBy->Imports.insert(&MF); + } else { + if (!MF.DirectlyImported) + MF.ImportLoc = ImportLoc; + + MF.DirectlyImported = true; + } +} + ModuleManager::AddModuleResult ModuleManager::addModule(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc, ModuleFile *ImportedBy, @@ -84,141 +108,133 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, } // Check whether we already loaded this module, before - ModuleFile *ModuleEntry = Modules[Entry]; - bool NewModule = false; - if (!ModuleEntry) { - // Allocate a new module. - NewModule = true; - ModuleEntry = new ModuleFile(Type, Generation); - ModuleEntry->Index = Chain.size(); - ModuleEntry->FileName = FileName.str(); - ModuleEntry->File = Entry; - ModuleEntry->ImportLoc = ImportLoc; - ModuleEntry->InputFilesValidationTimestamp = 0; - - if (ModuleEntry->Kind == MK_ImplicitModule) { - std::string TimestampFilename = ModuleEntry->getTimestampFilename(); - vfs::Status Status; - // A cached stat value would be fine as well. - if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status)) - ModuleEntry->InputFilesValidationTimestamp = - llvm::sys::toTimeT(Status.getLastModificationTime()); - } - - // Load the contents of the module - if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) { - // The buffer was already provided for us. - ModuleEntry->Buffer = std::move(Buffer); - } else { - // Open the AST file. - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf( - (std::error_code())); - if (FileName == "-") { - Buf = llvm::MemoryBuffer::getSTDIN(); - } else { - // Leave the FileEntry open so if it gets read again by another - // ModuleManager it must be the same underlying file. - // FIXME: Because FileManager::getFile() doesn't guarantee that it will - // give us an open file, this may not be 100% reliable. - Buf = FileMgr.getBufferForFile(ModuleEntry->File, - /*IsVolatile=*/false, - /*ShouldClose=*/false); - } - - if (!Buf) { - ErrorStr = Buf.getError().message(); - delete ModuleEntry; - return Missing; - } - - ModuleEntry->Buffer = std::move(*Buf); - } + if (ModuleFile *ModuleEntry = Modules.lookup(Entry)) { + // Check the stored signature. + if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr)) + return OutOfDate; - // Initialize the stream. - ModuleEntry->Data = PCHContainerRdr.ExtractPCH(*ModuleEntry->Buffer); + Module = ModuleEntry; + updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc); + return AlreadyLoaded; } - if (ExpectedSignature) { - // If we've not read the control block yet, read the signature eagerly now - // so that we can check it. - if (!ModuleEntry->Signature) - ModuleEntry->Signature = ReadSignature(ModuleEntry->Data); + // Allocate a new module. + auto NewModule = llvm::make_unique<ModuleFile>(Type, Generation); + NewModule->Index = Chain.size(); + NewModule->FileName = FileName.str(); + NewModule->File = Entry; + NewModule->ImportLoc = ImportLoc; + NewModule->InputFilesValidationTimestamp = 0; + + if (NewModule->Kind == MK_ImplicitModule) { + std::string TimestampFilename = NewModule->getTimestampFilename(); + vfs::Status Status; + // A cached stat value would be fine as well. + if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status)) + NewModule->InputFilesValidationTimestamp = + llvm::sys::toTimeT(Status.getLastModificationTime()); + } - if (ModuleEntry->Signature != ExpectedSignature) { - ErrorStr = ModuleEntry->Signature ? "signature mismatch" - : "could not read module signature"; + // Load the contents of the module + if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) { + // The buffer was already provided for us. + NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(Buffer)); + } else if (llvm::MemoryBuffer *Buffer = PCMCache->lookupBuffer(FileName)) { + NewModule->Buffer = Buffer; + } else { + // Open the AST file. + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code())); + if (FileName == "-") { + Buf = llvm::MemoryBuffer::getSTDIN(); + } else { + // Leave the FileEntry open so if it gets read again by another + // ModuleManager it must be the same underlying file. + // FIXME: Because FileManager::getFile() doesn't guarantee that it will + // give us an open file, this may not be 100% reliable. + Buf = FileMgr.getBufferForFile(NewModule->File, + /*IsVolatile=*/false, + /*ShouldClose=*/false); + } - if (NewModule) - delete ModuleEntry; - return OutOfDate; + if (!Buf) { + ErrorStr = Buf.getError().message(); + return Missing; } - } - if (ImportedBy) { - ModuleEntry->ImportedBy.insert(ImportedBy); - ImportedBy->Imports.insert(ModuleEntry); - } else { - if (!ModuleEntry->DirectlyImported) - ModuleEntry->ImportLoc = ImportLoc; - - ModuleEntry->DirectlyImported = true; + NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(*Buf)); } - Module = ModuleEntry; + // Initialize the stream. + NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer); + + // Read the signature eagerly now so that we can check it. Avoid calling + // ReadSignature unless there's something to check though. + if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data), + ExpectedSignature, ErrorStr)) { + // Try to remove the buffer. If it can't be removed, then it was already + // validated by this process. + if (!PCMCache->tryToRemoveBuffer(NewModule->FileName)) + FileMgr.invalidateCache(NewModule->File); + return OutOfDate; + } - if (!NewModule) - return AlreadyLoaded; + // We're keeping this module. Store it everywhere. + Module = Modules[Entry] = NewModule.get(); - assert(!Modules[Entry] && "module loaded twice"); - Modules[Entry] = ModuleEntry; + updateModuleImports(*NewModule, ImportedBy, ImportLoc); - Chain.push_back(ModuleEntry); - if (!ModuleEntry->isModule()) - PCHChain.push_back(ModuleEntry); + if (!NewModule->isModule()) + PCHChain.push_back(NewModule.get()); if (!ImportedBy) - Roots.push_back(ModuleEntry); + Roots.push_back(NewModule.get()); + Chain.push_back(std::move(NewModule)); return NewlyLoaded; } void ModuleManager::removeModules( - ModuleIterator first, ModuleIterator last, + ModuleIterator First, llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully, ModuleMap *modMap) { - if (first == last) + auto Last = end(); + 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); + llvm::SmallPtrSet<ModuleFile *, 4> victimSet( + (llvm::pointer_iterator<ModuleIterator>(First)), + (llvm::pointer_iterator<ModuleIterator>(Last))); auto IsVictim = [&](ModuleFile *MF) { return victimSet.count(MF); }; // Remove any references to the now-destroyed modules. - for (unsigned i = 0, n = Chain.size(); i != n; ++i) { - Chain[i]->ImportedBy.remove_if(IsVictim); + for (auto I = begin(); I != First; ++I) { + I->Imports.remove_if(IsVictim); + I->ImportedBy.remove_if(IsVictim); } 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), + 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); + for (ModuleIterator victim = First; victim != Last; ++victim) { + Modules.erase(victim->File); if (modMap) { - StringRef ModuleName = (*victim)->ModuleName; + StringRef ModuleName = victim->ModuleName; if (Module *mod = modMap->findModule(ModuleName)) { mod->setASTFile(nullptr); } @@ -227,14 +243,17 @@ void ModuleManager::removeModules( // Files that didn't make it through ReadASTCore successfully will be // rebuilt (or there was an error). Invalidate them so that we can load the // new files that will be renamed over the old ones. - if (LoadedSuccessfully.count(*victim) == 0) - FileMgr.invalidateCache((*victim)->File); - - delete *victim; + // + // The PCMCache tracks whether the module was successfully loaded in another + // thread/context; in that case, it won't need to be rebuilt (and we can't + // safely invalidate it anyway). + if (LoadedSuccessfully.count(&*victim) == 0 && + !PCMCache->tryToRemoveBuffer(victim->FileName)) + FileMgr.invalidateCache(victim->File); } - // Remove the modules from the chain. - Chain.erase(first, last); + // Delete the modules. + Chain.erase(Chain.begin() + (First - begin()), Chain.end()); } void @@ -274,11 +293,9 @@ void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) { // Notify the global module index about all of the modules we've already // loaded. - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - if (!GlobalIndex->loadedModuleFile(Chain[I])) { - ModulesInCommonWithGlobalIndex.push_back(Chain[I]); - } - } + for (ModuleFile &M : *this) + if (!GlobalIndex->loadedModuleFile(&M)) + ModulesInCommonWithGlobalIndex.push_back(&M); } void ModuleManager::moduleFileAccepted(ModuleFile *MF) { @@ -288,16 +305,12 @@ void ModuleManager::moduleFileAccepted(ModuleFile *MF) { ModulesInCommonWithGlobalIndex.push_back(MF); } -ModuleManager::ModuleManager(FileManager &FileMgr, +ModuleManager::ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache, const PCHContainerReader &PCHContainerRdr) - : FileMgr(FileMgr), PCHContainerRdr(PCHContainerRdr), GlobalIndex(), - FirstVisitState(nullptr) {} + : FileMgr(FileMgr), PCMCache(&PCMCache), PCHContainerRdr(PCHContainerRdr), + GlobalIndex(), FirstVisitState(nullptr) {} -ModuleManager::~ModuleManager() { - for (unsigned i = 0, e = Chain.size(); i != e; ++i) - delete Chain[e - i - 1]; - delete FirstVisitState; -} +ModuleManager::~ModuleManager() { delete FirstVisitState; } void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor, llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) { @@ -314,11 +327,11 @@ void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor, Queue.reserve(N); llvm::SmallVector<unsigned, 4> UnusedIncomingEdges; UnusedIncomingEdges.resize(size()); - for (ModuleFile *M : llvm::reverse(*this)) { - unsigned Size = M->ImportedBy.size(); - UnusedIncomingEdges[M->Index] = Size; + for (ModuleFile &M : llvm::reverse(*this)) { + unsigned Size = M.ImportedBy.size(); + UnusedIncomingEdges[M.Index] = Size; if (!Size) - Queue.push_back(M); + Queue.push_back(&M); } // Traverse the graph, making sure to visit a module before visiting any @@ -433,7 +446,7 @@ namespace llvm { struct GraphTraits<ModuleManager> { typedef ModuleFile *NodeRef; typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType; - typedef ModuleManager::ModuleConstIterator nodes_iterator; + typedef pointer_iterator<ModuleManager::ModuleConstIterator> nodes_iterator; static ChildIteratorType child_begin(NodeRef Node) { return Node->Imports.begin(); @@ -444,11 +457,11 @@ namespace llvm { } static nodes_iterator nodes_begin(const ModuleManager &Manager) { - return Manager.begin(); + return nodes_iterator(Manager.begin()); } static nodes_iterator nodes_end(const ModuleManager &Manager) { - return Manager.end(); + return nodes_iterator(Manager.end()); } }; |