diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp | 1914 |
1 files changed, 1585 insertions, 329 deletions
diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp index 53224e2..50be74f 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp +++ b/contrib/llvm/tools/clang/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" @@ -289,6 +292,33 @@ static bool checkLanguageOptions(const LangOptions &LangOpts, return true; } + // Sanitizer feature mismatches are treated as compatible differences. If + // compatible differences aren't allowed, we still only want to check for + // mismatches of non-modular sanitizers (the only ones which can affect AST + // generation). + if (!AllowCompatibleDifferences) { + SanitizerMask ModularSanitizers = getPPTransparentSanitizers(); + SanitizerSet ExistingSanitizers = ExistingLangOpts.Sanitize; + SanitizerSet ImportedSanitizers = LangOpts.Sanitize; + ExistingSanitizers.clear(ModularSanitizers); + ImportedSanitizers.clear(ModularSanitizers); + if (ExistingSanitizers.Mask != ImportedSanitizers.Mask) { + const std::string Flag = "-fsanitize="; + if (Diags) { +#define SANITIZER(NAME, ID) \ + { \ + bool InExistingModule = ExistingSanitizers.has(SanitizerKind::ID); \ + bool InImportedModule = ImportedSanitizers.has(SanitizerKind::ID); \ + if (InExistingModule != InImportedModule) \ + Diags->Report(diag::err_pch_targetopt_feature_mismatch) \ + << InExistingModule << (Flag + NAME); \ + } +#include "clang/Basic/Sanitizers.def" + } + return true; + } + } + return false; } @@ -461,19 +491,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 +501,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 @@ -816,7 +856,7 @@ static bool isInterestingIdentifier(ASTReader &Reader, IdentifierInfo &II, II.isPoisoned() || (IsModule ? II.hasRevertedBuiltin() : II.getObjCOrBuiltinID()) || II.hasRevertedTokenIDToIdentifier() || - (!(IsModule && Reader.getContext().getLangOpts().CPlusPlus) && + (!(IsModule && Reader.getPreprocessor().getLangOpts().CPlusPlus) && II.getFETokenInfo<void>()); } @@ -943,6 +983,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 +1003,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 +1047,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 +1063,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,9 +1146,9 @@ 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() && + if (PP.getLangOpts().Modules && !Diags.isDiagnosticInFlight() && !PP.getHeaderSearchInfo().getModuleCachePath().empty()) { Diag(diag::note_module_cache_path) << PP.getHeaderSearchInfo().getModuleCachePath(); @@ -1113,7 +1156,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 +1321,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); @@ -1343,15 +1391,14 @@ bool ASTReader::ReadSLocEntry(int ID) { const DeclID *FirstDecl = F->FileSortedDecls + Record[6]; unsigned NumFileDecls = Record[7]; - if (NumFileDecls) { + if (NumFileDecls && ContextObj) { assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?"); FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl, NumFileDecls)); } const SrcMgr::ContentCache *ContentCache - = SourceMgr.getOrCreateContentCache(File, - /*isSystemFile=*/FileCharacter != SrcMgr::C_User); + = SourceMgr.getOrCreateContentCache(File, isSystem(FileCharacter)); if (OverriddenBuffer && !ContentCache->BufferOverridden && ContentCache->ContentsEntry == ContentCache->OrigEntry && !ContentCache->getRawBuffer()) { @@ -1473,7 +1520,7 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { Stream.JumpToBit(Offset); RecordData Record; - SmallVector<IdentifierInfo*, 16> MacroArgs; + SmallVector<IdentifierInfo*, 16> MacroParams; MacroInfo *Macro = nullptr; while (true) { @@ -1513,9 +1560,8 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { return Macro; unsigned NextIndex = 1; // Skip identifier ID. - SubmoduleID SubModID = getGlobalSubmoduleID(F, Record[NextIndex++]); SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex); - MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID); + MacroInfo *MI = PP.AllocateMacroInfo(Loc); MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex)); MI->setIsUsed(Record[NextIndex++]); MI->setUsedForHeaderGuard(Record[NextIndex++]); @@ -1525,17 +1571,17 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { bool isC99VarArgs = Record[NextIndex++]; bool isGNUVarArgs = Record[NextIndex++]; bool hasCommaPasting = Record[NextIndex++]; - MacroArgs.clear(); + MacroParams.clear(); unsigned NumArgs = Record[NextIndex++]; for (unsigned i = 0; i != NumArgs; ++i) - MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++])); + MacroParams.push_back(getLocalIdentifier(F, Record[NextIndex++])); // Install function-like macro info. MI->setIsFunctionLike(); if (isC99VarArgs) MI->setIsC99Varargs(); if (isGNUVarArgs) MI->setIsGNUVarargs(); if (hasCommaPasting) MI->setHasCommaPasting(); - MI->setArgumentList(MacroArgs, PP.getPreprocessorAllocator()); + MI->setParameterList(MacroParams, PP.getPreprocessorAllocator()); } // Remember that we saw this macro last so that we add the tokens that @@ -1575,7 +1621,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() @@ -1646,9 +1696,9 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, HeaderFileInfo HFI; unsigned Flags = *d++; // FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp. - HFI.isImport |= (Flags >> 4) & 0x01; - HFI.isPragmaOnce |= (Flags >> 3) & 0x01; - HFI.DirInfo = (Flags >> 1) & 0x03; + HFI.isImport |= (Flags >> 5) & 0x01; + HFI.isPragmaOnce |= (Flags >> 4) & 0x01; + HFI.DirInfo = (Flags >> 1) & 0x07; HFI.IndexHeaderMapHeader = Flags & 0x01; // FIXME: Find a better way to handle this. Maybe just store a // "has been included" flag? @@ -1707,15 +1757,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 +1787,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; @@ -1978,6 +2028,7 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) { R.StoredTime = static_cast<time_t>(Record[2]); R.Overridden = static_cast<bool>(Record[3]); R.Transient = static_cast<bool>(Record[4]); + R.TopLevelModuleMap = static_cast<bool>(Record[5]); R.Filename = Blob; ResolveImportedPath(F, R.Filename); return R; @@ -2149,7 +2200,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 +2242,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 +2282,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 +2311,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 +2387,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 +2464,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 +2483,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 +2538,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 +2584,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, F.InputFileOffsets = (const llvm::support::unaligned_uint64_t *)Blob.data(); F.InputFilesLoaded.resize(NumInputs); + F.NumUserInputFiles = NumUserInputs; break; } } @@ -2542,10 +2614,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // contains any declarations lexically within it (which it always does!). // This usually has no cost, since we very rarely need the lookup map for // the translation unit outside C++. - DeclContext *DC = Context.getTranslationUnitDecl(); - if (DC->hasExternalLexicalStorage() && - !getContext().getLangOpts().CPlusPlus) - DC->setMustBuildLookupTable(); + if (ASTContext *Ctx = ContextObj) { + DeclContext *DC = Ctx->getTranslationUnitDecl(); + if (DC->hasExternalLexicalStorage() && !Ctx->getLangOpts().CPlusPlus) + DC->setMustBuildLookupTable(); + } return Success; } @@ -2601,7 +2674,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; @@ -2633,7 +2707,33 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // Read and process a record. Record.clear(); StringRef Blob; - switch ((ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) { + auto RecordType = + (ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob); + + // If we're not loading an AST context, we don't care about most records. + if (!ContextObj) { + switch (RecordType) { + case IDENTIFIER_TABLE: + case IDENTIFIER_OFFSET: + case INTERESTING_IDENTIFIERS: + case STATISTICS: + case PP_CONDITIONAL_STACK: + case PP_COUNTER_VALUE: + case SOURCE_LOCATION_OFFSETS: + case MODULE_OFFSET_MAP: + case SOURCE_MANAGER_LINE_TABLE: + case SOURCE_LOCATION_PRELOADS: + case PPD_ENTITIES_OFFSETS: + case HEADER_SEARCH_TABLE: + case IMPORTED_MODULES: + case MACRO_OFFSET: + break; + default: + continue; + } + } + + switch (RecordType) { default: // Default behavior: ignore. break; @@ -2692,7 +2792,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } case TU_UPDATE_LEXICAL: { - DeclContext *TU = Context.getTranslationUnitDecl(); + DeclContext *TU = ContextObj->getTranslationUnitDecl(); LexicalContents Contents( reinterpret_cast<const llvm::support::unaligned_uint32_t *>( Blob.data()), @@ -2710,7 +2810,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // If we've already loaded the decl, perform the updates when we finish // loading this block. if (Decl *D = GetExistingDecl(ID)) - PendingUpdateRecords.push_back(std::make_pair(ID, D)); + PendingUpdateRecords.push_back( + PendingUpdateRecord(ID, D, /*JustLoaded=*/false)); break; } @@ -2766,6 +2867,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) @@ -2870,6 +2979,21 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } break; + case PP_CONDITIONAL_STACK: + if (!Record.empty()) { + SmallVector<PPConditionalInfo, 4> ConditionalStack; + for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) { + auto Loc = ReadSourceLocation(F, Record, Idx); + bool WasSkipping = Record[Idx++]; + bool FoundNonSkip = Record[Idx++]; + bool FoundElse = Record[Idx++]; + ConditionalStack.push_back( + {Loc, WasSkipping, FoundNonSkip, FoundElse}); + } + PP.setReplayablePreambleConditionalStack(ConditionalStack); + } + break; + case PP_COUNTER_VALUE: if (!Record.empty() && Listener) Listener->ReadCounter(F, Record[0]); @@ -2916,80 +3040,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)) @@ -3103,7 +3156,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // If we've already loaded the decl, perform the updates when we finish // loading this block. if (Decl *D = GetExistingDecl(ID)) - PendingUpdateRecords.push_back(std::make_pair(ID, D)); + PendingUpdateRecords.push_back( + PendingUpdateRecord(ID, D, /*JustLoaded=*/false)); } break; } @@ -3123,14 +3177,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 +3291,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,7 +3368,110 @@ 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; } } @@ -3330,20 +3482,13 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, unsigned Idx = 0; F.ModuleMapPath = ReadPath(F, Record, Idx); - if (F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule) { - // For an explicitly-loaded module, we don't care whether the original - // module map file exists or matches. - return Success; - } - // Try to resolve ModuleName in the current header search context and // verify that it is found in the same module map file as we saved. If the // top-level AST file is a main file, skip this check because there is no // 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); @@ -3456,8 +3601,8 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) { assert(Owner->NameVisibility != Module::Hidden && "nothing to make visible?"); for (Decl *D : Names) { - bool wasHidden = D->Hidden; - D->Hidden = false; + bool wasHidden = D->isHidden(); + D->setVisibleDespiteOwningModule(); if (wasHidden && SemaObj) { if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D)) { @@ -3524,7 +3669,7 @@ void ASTReader::mergeDefinitionVisibility(NamedDecl *Def, if (Def->isHidden()) { // If MergedDef is visible or becomes visible, make the definition visible. if (!MergedDef->isHidden()) - Def->Hidden = false; + Def->setVisibleDespiteOwningModule(); else if (getContext().getLangOpts().ModulesLocalVisibility) { getContext().mergeDefinitionIntoModule( Def, MergedDef->getImportedOwningModule(), @@ -3543,7 +3688,7 @@ bool ASTReader::loadGlobalIndex() { return false; if (TriedLoadingGlobalIndex || !UseGlobalIndex || - !Context.getLangOpts().Modules) + !PP.getLangOpts().Modules) return true; // Try to load the global index. @@ -3561,7 +3706,7 @@ bool ASTReader::loadGlobalIndex() { } bool ASTReader::isGlobalIndexUnavailable() const { - return Context.getLangOpts().Modules && UseGlobalIndex && + return PP.getLangOpts().Modules && UseGlobalIndex && !hasGlobalIndex() && TriedLoadingGlobalIndex; } @@ -3573,6 +3718,8 @@ static void updateModuleTimestamp(ModuleFile &MF) { if (EC) return; OS << "Timestamp file\n"; + OS.close(); + OS.clear_error(); // Avoid triggering a fatal error. } /// \brief Given a cursor at the start of an AST file, scan ahead and drop the @@ -3617,14 +3764,16 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, Deserializing AnASTFile(this); // Bump the generation number. - unsigned PreviousGeneration = incrementGeneration(Context); + unsigned PreviousGeneration = 0; + if (ContextObj) + PreviousGeneration = incrementGeneration(*ContextObj); 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 +3784,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, for (const ImportedModule &IM : Loaded) LoadedSet.insert(IM.Mod); - ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(), - LoadedSet, - Context.getLangOpts().Modules - ? &PP.getHeaderSearchInfo().getModuleMap() - : nullptr); + ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, LoadedSet, + PP.getLangOpts().Modules + ? &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. @@ -3685,6 +3833,13 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, SourceMgr.getLoadedSLocEntryByID(Index); } + // Map the original source file ID into the ID space of the current + // compilation. + if (F.OriginalSourceFileID.isValid()) { + F.OriginalSourceFileID = FileID::get( + F.SLocEntryBaseID + F.OriginalSourceFileID.getOpaqueValue() - 1); + } + // Preload all the pending interesting identifiers by marking them out of // date. for (auto Offset : F.PreloadIdentifierOffsets) { @@ -3726,7 +3881,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, F.ImportLoc = TranslateSourceLocation(*M->ImportedBy, M->ImportLoc); } - if (!Context.getLangOpts().CPlusPlus || + if (!PP.getLangOpts().CPlusPlus || (Type != MK_ImplicitModule && Type != MK_ExplicitModule && Type != MK_PrebuiltModule)) { // Mark all of the identifiers in the identifier table as being out of date, @@ -3783,7 +3938,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, // Might be unnecessary as use declarations are only used to build the // module itself. - InitializeContext(); + if (ContextObj) + InitializeContext(); if (SemaObj) UpdateSema(); @@ -3793,10 +3949,6 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule(); if (PrimaryModule.OriginalSourceFileID.isValid()) { - PrimaryModule.OriginalSourceFileID - = FileID::get(PrimaryModule.SLocEntryBaseID - + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1); - // If this AST file is a precompiled preamble, then set the // preamble file ID of the source manager to the file source file // from which the preamble was built. @@ -3809,10 +3961,12 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, // For any Objective-C class definitions we have already loaded, make sure // that we load any additional categories. - for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) { - loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(), - ObjCClassesLoaded[I], - PreviousGeneration); + if (ContextObj) { + for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) { + loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(), + ObjCClassesLoaded[I], + PreviousGeneration); + } } if (PP.getHeaderSearchInfo() @@ -3986,6 +4140,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 +4158,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, @@ -4070,6 +4346,9 @@ ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) { } void ASTReader::InitializeContext() { + assert(ContextObj && "no context to initialize"); + ASTContext &Context = *ContextObj; + // If there's a listener, notify them that we "read" the translation unit. if (DeserializationListener) DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID, @@ -4214,23 +4493,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 +4629,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 +4658,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 +4779,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 +4818,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, @@ -4566,6 +4856,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); bool First = true; Module *CurrentModule = nullptr; + Module::ModuleKind ModuleKind = Module::ModuleMapModule; RecordData Record; while (true) { llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks(); @@ -4628,8 +4919,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() @@ -4655,8 +4947,10 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } CurrentModule->setASTFile(F.File); + CurrentModule->PresumedModuleMapFile = F.ModuleMapPath; } + CurrentModule->Kind = ModuleKind; CurrentModule->Signature = F.Signature; CurrentModule->IsFromModuleFile = true; CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; @@ -4696,13 +4990,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; @@ -4759,6 +5049,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules); } + ModuleKind = (Module::ModuleKind)Record[2]; break; } @@ -4792,8 +5083,8 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; } case SUBMODULE_REQUIRES: { - CurrentModule->addRequirement(Blob, Record[0], Context.getLangOpts(), - Context.getTargetInfo()); + CurrentModule->addRequirement(Blob, Record[0], PP.getLangOpts(), + PP.getTargetInfo()); break; } @@ -4819,10 +5110,12 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } case SUBMODULE_INITIALIZERS: + if (!ContextObj) + break; SmallVector<uint32_t, 16> Inits; for (auto &ID : Record) Inits.push_back(getGlobalDeclID(F, ID)); - Context.addLazyModuleInitializers(CurrentModule, Inits); + ContextObj->addLazyModuleInitializers(CurrentModule, Inits); break; } } @@ -4950,6 +5243,8 @@ bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record, HSOpts.ModuleCachePath = ReadString(Record, Idx); HSOpts.ModuleUserBuildPath = ReadString(Record, Idx); HSOpts.DisableModuleHash = Record[Idx++]; + HSOpts.ImplicitModuleMaps = Record[Idx++]; + HSOpts.ModuleMapFileHomeIsCwd = Record[Idx++]; HSOpts.UseBuiltinIncludes = Record[Idx++]; HSOpts.UseStandardSystemIncludes = Record[Idx++]; HSOpts.UseStandardCXXIncludes = Record[Idx++]; @@ -5288,48 +5583,141 @@ 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++]; + DiagnosticMapping NewMapping = + DiagnosticMapping::deserialize(Record[Idx++]); + 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 (NewMapping.wasUpgradedFromWarning() && !Mapping.isErrorOrFatal()) { + NewMapping.setSeverity(diag::Severity::Warning); + NewMapping.setUpgradedFromWarning(false); } - diag::Severity Map = (diag::Severity)F.PragmaDiagMappings[Idx++]; - DiagnosticMapping Mapping = Diag.makeUserMapping(Map, Loc); - Diag.GetCurDiagState()->setMapping(DiagID, Mapping); + + Mapping = NewMapping; + } + 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[1] == 0 && + "Invalid data, unexpected backref in initial state"); + Idx = 3 + Record[2] * 2; + assert(Idx < Record.size() && + "Invalid data, not enough state change pairs in initial state"); + } else if (F.isModule()) { + // For an explicit module, preserve the flags from the module build + // command line (-w, -Weverything, -Werror, ...) along with any explicit + // -Wblah flags. + unsigned Flags = Record[Idx++]; + DiagState Initial; + Initial.SuppressSystemWarnings = Flags & 1; Flags >>= 1; + Initial.ErrorsAsFatal = Flags & 1; Flags >>= 1; + Initial.WarningsAsErrors = Flags & 1; Flags >>= 1; + Initial.EnableAllWarnings = Flags & 1; Flags >>= 1; + Initial.IgnoreAllWarnings = Flags & 1; Flags >>= 1; + Initial.ExtBehavior = (diag::Severity)Flags; + FirstState = ReadDiagState(Initial, SourceLocation(), true); + + // Set up the root buffer of the module to start with the initial + // diagnostic state of the module itself, to cover files that contain no + // explicit transitions (for which we did not serialize anything). + Diag.DiagStatesByLoc.Files[F.OriginalSourceFileID] + .StateTransitions.push_back({FirstState, 0}); + } else { + // For prefix ASTs, start with whatever the user configured on the + // command line. + Idx++; // Skip flags. + FirstState = ReadDiagState(*Diag.DiagStatesByLoc.CurDiagState, + SourceLocation(), false); + } + + // 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(); } } @@ -5348,6 +5736,8 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) { /// location. It is a helper routine for GetType, which deals with reading type /// IDs. QualType ASTReader::readTypeRecord(unsigned Index) { + assert(ContextObj && "reading type with no AST context"); + ASTContext &Context = *ContextObj; RecordLocation Loc = TypeCursorForIndex(Index); BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor; @@ -5508,13 +5898,13 @@ QualType ASTReader::readTypeRecord(unsigned Index) { } case TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 6) { + if (Record.size() != 7) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = readType(*Loc.F, Record, Idx); FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], - (CallingConv)Record[4], Record[5]); + (CallingConv)Record[4], Record[5], Record[6]); return Context.getFunctionNoProtoType(ResultType, Info); } @@ -5526,9 +5916,10 @@ QualType ASTReader::readTypeRecord(unsigned Index) { /*hasregparm*/ Record[2], /*regparm*/ Record[3], static_cast<CallingConv>(Record[4]), - /*produces*/ Record[5]); + /*produces*/ Record[5], + /*nocallersavedregs*/ Record[6]); - unsigned Idx = 6; + unsigned Idx = 7; EPI.Variadic = Record[Idx++]; EPI.HasTrailingReturn = Record[Idx++]; @@ -5606,6 +5997,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 +6239,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 +6447,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()); } @@ -6179,6 +6594,9 @@ ASTReader::GetTypeSourceInfo(ModuleFile &F, const ASTReader::RecordData &Record, } QualType ASTReader::GetType(TypeID ID) { + assert(ContextObj && "reading type with no AST context"); + ASTContext &Context = *ContextObj; + unsigned FastQuals = ID & Qualifiers::FastMask; unsigned Index = ID >> Qualifiers::FastWidth; @@ -6304,9 +6722,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 +6778,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 +6855,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 @@ -6516,6 +6928,9 @@ ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) { } CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { + assert(ContextObj && "reading base specifiers with no AST context"); + ASTContext &Context = *ContextObj; + RecordLocation Loc = getLocalBitOffset(Offset); BitstreamCursor &Cursor = Loc.F->DeclsCursor; SavedStreamPosition SavedPosition(Cursor); @@ -6543,6 +6958,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"); @@ -6644,8 +7062,9 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) { } Decl *ASTReader::GetExistingDecl(DeclID ID) { + assert(ContextObj && "reading decl with no AST context"); if (ID < NUM_PREDEF_DECL_IDS) { - Decl *D = getPredefinedDecl(Context, (PredefinedDeclIDs)ID); + Decl *D = getPredefinedDecl(*ContextObj, (PredefinedDeclIDs)ID); if (D) { // Track that we have merged the declaration with ID \p ID into the // pre-existing predefined declaration \p D. @@ -6728,6 +7147,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 +7342,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 +7459,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 +7489,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 +7526,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 +7567,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) { @@ -7187,7 +7609,7 @@ IdentifierInfo *ASTReader::get(StringRef Name) { // all interesting declarations, and don't need to use the scope for name // lookups). Perform the lookup in PCH files, though, since we don't build // a complete initial identifier table if we're carrying on from a PCH. - if (Context.getLangOpts().CPlusPlus) { + if (PP.getLangOpts().CPlusPlus) { for (auto F : ModuleMgr.pch_modules()) if (Visitor(*F)) break; @@ -7720,6 +8142,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 +8183,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 +8198,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() @@ -7832,8 +8263,9 @@ ASTReader::getSourceDescriptor(unsigned ID) { return ExternalASTSource::ASTSourceDescriptor(*M); // If there is only a single PCH, return it instead. - // Chained PCH are not suported. - if (ModuleMgr.size() == 1) { + // Chained PCH are not supported. + 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 +8275,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 +8325,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() @@ -7897,6 +8339,7 @@ ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const { DeclarationName ASTReader::ReadDeclarationName(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + ASTContext &Context = getContext(); DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; switch (Kind) { case DeclarationName::Identifier: @@ -7915,6 +8358,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 +8409,7 @@ void ASTReader::ReadDeclarationNameLoc(ModuleFile &F, case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: break; } } @@ -7982,7 +8430,8 @@ void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info, unsigned NumTPLists = Record[Idx++]; Info.NumTemplParamLists = NumTPLists; if (NumTPLists) { - Info.TemplParamLists = new (Context) TemplateParameterList*[NumTPLists]; + Info.TemplParamLists = + new (getContext()) TemplateParameterList *[NumTPLists]; for (unsigned i = 0; i != NumTPLists; ++i) Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx); } @@ -7991,6 +8440,7 @@ void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info, TemplateName ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + ASTContext &Context = getContext(); TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++]; switch (Kind) { case TemplateName::Template: @@ -8051,6 +8501,7 @@ TemplateArgument ASTReader::ReadTemplateArgument(ModuleFile &F, const RecordData &Record, unsigned &Idx, bool Canonicalize) { + ASTContext &Context = getContext(); if (Canonicalize) { // The caller wants a canonical template argument. Sometimes the AST only // wants template arguments in canonical form (particularly as the template @@ -8114,9 +8565,8 @@ ASTReader::ReadTemplateParameterList(ModuleFile &F, Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx)); // TODO: Concepts - TemplateParameterList* TemplateParams = - TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, - Params, RAngleLoc, nullptr); + TemplateParameterList *TemplateParams = TemplateParameterList::Create( + getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, nullptr); return TemplateParams; } @@ -8135,11 +8585,11 @@ ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs, void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set, const RecordData &Record, unsigned &Idx) { unsigned NumDecls = Record[Idx++]; - Set.reserve(Context, NumDecls); + Set.reserve(getContext(), NumDecls); while (NumDecls--) { DeclID ID = ReadDeclID(F, Record, Idx); AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; - Set.addLazyDecl(Context, ID, AS); + Set.addLazyDecl(getContext(), ID, AS); } } @@ -8162,6 +8612,7 @@ ASTReader::ReadCXXBaseSpecifier(ModuleFile &F, CXXCtorInitializer ** ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + ASTContext &Context = getContext(); unsigned NumInitializers = Record[Idx++]; assert(NumInitializers && "wrote ctor initializers but have no inits"); auto **CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers]; @@ -8227,6 +8678,7 @@ ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, NestedNameSpecifier * ASTReader::ReadNestedNameSpecifier(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + ASTContext &Context = getContext(); unsigned N = Record[Idx++]; NestedNameSpecifier *NNS = nullptr, *Prev = nullptr; for (unsigned I = 0; I != N; ++I) { @@ -8282,6 +8734,7 @@ ASTReader::ReadNestedNameSpecifier(ModuleFile &F, NestedNameSpecifierLoc ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + ASTContext &Context = getContext(); unsigned N = Record[Idx++]; NestedNameSpecifierLocBuilder Builder; for (unsigned I = 0; I != N; ++I) { @@ -8403,14 +8856,14 @@ CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F, const RecordData &Record, unsigned &Idx) { CXXDestructorDecl *Decl = ReadDeclAs<CXXDestructorDecl>(F, Record, Idx); - return CXXTemporary::Create(Context, Decl); + return CXXTemporary::Create(getContext(), 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); } @@ -8439,6 +8892,7 @@ void ASTReader::ClearSwitchCaseIDs() { } void ASTReader::ReadComments() { + ASTContext &Context = getContext(); std::vector<RawComment *> Comments; for (SmallVectorImpl<std::pair<BitstreamCursor, serialization::ModuleFile *> >::iterator @@ -8493,6 +8947,34 @@ 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); + } +} + +void ASTReader::visitTopLevelModuleMaps( + serialization::ModuleFile &MF, + llvm::function_ref<void(const FileEntry *FE)> Visitor) { + unsigned NumInputs = MF.InputFilesLoaded.size(); + for (unsigned I = 0; I < NumInputs; ++I) { + InputFileInfo IFI = readInputFileInfo(MF, I + 1); + if (IFI.TopLevelModuleMap) + // FIXME: This unnecessarily re-reads the InputFileInfo. + if (auto *FE = getInputFile(MF, I + 1).getFile()) + Visitor(FE); + } +} + std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) { // If we know the owning module, use it. if (Module *M = D->getImportedOwningModule()) @@ -8583,7 +9065,7 @@ void ASTReader::finishPendingActions() { while (!PendingUpdateRecords.empty()) { auto Update = PendingUpdateRecords.pop_back_val(); ReadingKindTracker ReadingKind(Read_Decl, *this); - loadDeclUpdateRecords(Update.first, Update.second); + loadDeclUpdateRecords(Update); } } @@ -8651,9 +9133,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 +9271,796 @@ 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 + // This list should be the same Decl's as in ODRHash::isWhiteListedDecl + enum { + EndOfClass, + PublicSpecifer, + PrivateSpecifer, + ProtectedSpecifer, + StaticAssert, + Field, + CXXMethod, + TypeAlias, + TypeDef, + Var, + Friend, + 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: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + return CXXMethod; + case Decl::TypeAlias: + return TypeAlias; + case Decl::Typedef: + return TypeDef; + case Decl::Var: + return Var; + case Decl::Friend: + return Friend; } + }; + + 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; + } + + FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first; + SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first; - Diag(RD->getLocation(), + 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; + + if (FirstDecl) { + Diag(FirstDecl->getLocation(), diag::note_first_module_difference) + << FirstRecord << FirstDecl->getSourceRange(); + } + + Diag(SecondRecord->getLocation(), diag::note_module_odr_violation_different_definitions) - << getOwningModuleNameForDiagnostic(RD); + << SecondModule; + + if (SecondDecl) { + Diag(SecondDecl->getLocation(), diag::note_second_module_difference) + << SecondDecl->getSourceRange(); + } + + 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, + MethodNumberParameters, + MethodParameterType, + MethodParameterName, + MethodParameterSingleDefaultArgument, + MethodParameterDifferentDefaultArgument, + TypedefName, + TypedefType, + VarName, + VarType, + VarSingleInitializer, + VarDifferentInitializer, + VarConstexpr, + FriendTypeFunction, + FriendType, + FriendFunction, + }; + + // 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 ComputeQualTypeODRHash = [&Hash](QualType Ty) { + Hash.clear(); + Hash.AddQualType(Ty); + 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(getContext().hasSameType(FirstField->getType(), + SecondField->getType())); + + QualType FirstType = FirstField->getType(); + QualType SecondType = SecondField->getType(); + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { + 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: { + enum { + DiagMethod, + DiagConstructor, + DiagDestructor, + } FirstMethodType, + SecondMethodType; + auto GetMethodTypeForDiagnostics = [](const CXXMethodDecl* D) { + if (isa<CXXConstructorDecl>(D)) return DiagConstructor; + if (isa<CXXDestructorDecl>(D)) return DiagDestructor; + return DiagMethod; + }; + const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(FirstDecl); + const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(SecondDecl); + FirstMethodType = GetMethodTypeForDiagnostics(FirstMethod); + SecondMethodType = GetMethodTypeForDiagnostics(SecondMethod); + auto FirstName = FirstMethod->getDeclName(); + auto SecondName = SecondMethod->getDeclName(); + if (FirstMethodType != SecondMethodType || FirstName != SecondName) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodName) + << FirstMethodType << FirstName; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodName) + << SecondMethodType << SecondName; + + Diagnosed = true; + break; + } + + const bool FirstDeleted = FirstMethod->isDeleted(); + const bool SecondDeleted = SecondMethod->isDeleted(); + if (FirstDeleted != SecondDeleted) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodDeleted) + << FirstMethodType << FirstName << FirstDeleted; + + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodDeleted) + << SecondMethodType << 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) + << FirstMethodType << FirstName << FirstPure << FirstVirtual; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodVirtual) + << SecondMethodType << 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) + << FirstMethodType << FirstName << FirstStatic; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodStatic) + << SecondMethodType << SecondName << SecondStatic; + Diagnosed = true; + break; + } + + const bool FirstVolatile = FirstMethod->isVolatile(); + const bool SecondVolatile = SecondMethod->isVolatile(); + if (FirstVolatile != SecondVolatile) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodVolatile) + << FirstMethodType << FirstName << FirstVolatile; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodVolatile) + << SecondMethodType << SecondName << SecondVolatile; + Diagnosed = true; + break; + } + + const bool FirstConst = FirstMethod->isConst(); + const bool SecondConst = SecondMethod->isConst(); + if (FirstConst != SecondConst) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodConst) + << FirstMethodType << FirstName << FirstConst; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodConst) + << SecondMethodType << SecondName << SecondConst; + Diagnosed = true; + break; + } + + const bool FirstInline = FirstMethod->isInlineSpecified(); + const bool SecondInline = SecondMethod->isInlineSpecified(); + if (FirstInline != SecondInline) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodInline) + << FirstMethodType << FirstName << FirstInline; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodInline) + << SecondMethodType << SecondName << SecondInline; + Diagnosed = true; + break; + } + + const unsigned FirstNumParameters = FirstMethod->param_size(); + const unsigned SecondNumParameters = SecondMethod->param_size(); + if (FirstNumParameters != SecondNumParameters) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodNumberParameters) + << FirstMethodType << FirstName << FirstNumParameters; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodNumberParameters) + << SecondMethodType << SecondName << SecondNumParameters; + Diagnosed = true; + break; + } + + // Need this status boolean to know when break out of the switch. + bool ParameterMismatch = false; + for (unsigned I = 0; I < FirstNumParameters; ++I) { + const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I); + const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I); + + QualType FirstParamType = FirstParam->getType(); + QualType SecondParamType = SecondParam->getType(); + if (FirstParamType != SecondParamType && + ComputeQualTypeODRHash(FirstParamType) != + ComputeQualTypeODRHash(SecondParamType)) { + if (const DecayedType *ParamDecayedType = + FirstParamType->getAs<DecayedType>()) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodParameterType) + << FirstMethodType << FirstName << (I + 1) << FirstParamType + << true << ParamDecayedType->getOriginalType(); + } else { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodParameterType) + << FirstMethodType << FirstName << (I + 1) << FirstParamType + << false; + } + + if (const DecayedType *ParamDecayedType = + SecondParamType->getAs<DecayedType>()) { + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodParameterType) + << SecondMethodType << SecondName << (I + 1) + << SecondParamType << true + << ParamDecayedType->getOriginalType(); + } else { + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodParameterType) + << SecondMethodType << SecondName << (I + 1) + << SecondParamType << false; + } + ParameterMismatch = true; + break; + } + + DeclarationName FirstParamName = FirstParam->getDeclName(); + DeclarationName SecondParamName = SecondParam->getDeclName(); + if (FirstParamName != SecondParamName) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), MethodParameterName) + << FirstMethodType << FirstName << (I + 1) << FirstParamName; + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), MethodParameterName) + << SecondMethodType << SecondName << (I + 1) << SecondParamName; + ParameterMismatch = true; + break; + } + + const Expr *FirstInit = FirstParam->getInit(); + const Expr *SecondInit = SecondParam->getInit(); + if ((FirstInit == nullptr) != (SecondInit == nullptr)) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), + MethodParameterSingleDefaultArgument) + << FirstMethodType << FirstName << (I + 1) + << (FirstInit == nullptr) + << (FirstInit ? FirstInit->getSourceRange() : SourceRange()); + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), + MethodParameterSingleDefaultArgument) + << SecondMethodType << SecondName << (I + 1) + << (SecondInit == nullptr) + << (SecondInit ? SecondInit->getSourceRange() : SourceRange()); + ParameterMismatch = true; + break; + } + + if (FirstInit && SecondInit && + ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + ODRDiagError(FirstMethod->getLocation(), + FirstMethod->getSourceRange(), + MethodParameterDifferentDefaultArgument) + << FirstMethodType << FirstName << (I + 1) + << FirstInit->getSourceRange(); + ODRDiagNote(SecondMethod->getLocation(), + SecondMethod->getSourceRange(), + MethodParameterDifferentDefaultArgument) + << SecondMethodType << SecondName << (I + 1) + << SecondInit->getSourceRange(); + ParameterMismatch = true; + break; + + } + } + + if (ParameterMismatch) { + Diagnosed = true; + break; + } + + break; + } + case TypeAlias: + case TypeDef: { + TypedefNameDecl *FirstTD = cast<TypedefNameDecl>(FirstDecl); + TypedefNameDecl *SecondTD = cast<TypedefNameDecl>(SecondDecl); + auto FirstName = FirstTD->getDeclName(); + auto SecondName = SecondTD->getDeclName(); + if (FirstName != SecondName) { + ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(), + TypedefName) + << (FirstDiffType == TypeAlias) << FirstName; + ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(), + TypedefName) + << (FirstDiffType == TypeAlias) << SecondName; + Diagnosed = true; + break; + } + + QualType FirstType = FirstTD->getUnderlyingType(); + QualType SecondType = SecondTD->getUnderlyingType(); + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { + ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(), + TypedefType) + << (FirstDiffType == TypeAlias) << FirstName << FirstType; + ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(), + TypedefType) + << (FirstDiffType == TypeAlias) << SecondName << SecondType; + Diagnosed = true; + break; + } + break; + } + case Var: { + VarDecl *FirstVD = cast<VarDecl>(FirstDecl); + VarDecl *SecondVD = cast<VarDecl>(SecondDecl); + auto FirstName = FirstVD->getDeclName(); + auto SecondName = SecondVD->getDeclName(); + if (FirstName != SecondName) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarName) + << FirstName; + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarName) + << SecondName; + Diagnosed = true; + break; + } + + QualType FirstType = FirstVD->getType(); + QualType SecondType = SecondVD->getType(); + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarType) + << FirstName << FirstType; + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarType) + << SecondName << SecondType; + Diagnosed = true; + break; + } + + const Expr *FirstInit = FirstVD->getInit(); + const Expr *SecondInit = SecondVD->getInit(); + if ((FirstInit == nullptr) != (SecondInit == nullptr)) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarSingleInitializer) + << FirstName << (FirstInit == nullptr) + << (FirstInit ? FirstInit->getSourceRange(): SourceRange()); + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarSingleInitializer) + << SecondName << (SecondInit == nullptr) + << (SecondInit ? SecondInit->getSourceRange() : SourceRange()); + Diagnosed = true; + break; + } + + if (FirstInit && SecondInit && + ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarDifferentInitializer) + << FirstName << FirstInit->getSourceRange(); + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarDifferentInitializer) + << SecondName << SecondInit->getSourceRange(); + Diagnosed = true; + break; + } + + const bool FirstIsConstexpr = FirstVD->isConstexpr(); + const bool SecondIsConstexpr = SecondVD->isConstexpr(); + if (FirstIsConstexpr != SecondIsConstexpr) { + ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(), + VarConstexpr) + << FirstName << FirstIsConstexpr; + ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(), + VarConstexpr) + << SecondName << SecondIsConstexpr; + Diagnosed = true; + break; + } + break; + } + case Friend: { + FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl); + FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl); + + NamedDecl *FirstND = FirstFriend->getFriendDecl(); + NamedDecl *SecondND = SecondFriend->getFriendDecl(); + + TypeSourceInfo *FirstTSI = FirstFriend->getFriendType(); + TypeSourceInfo *SecondTSI = SecondFriend->getFriendType(); + + if (FirstND && SecondND) { + ODRDiagError(FirstFriend->getFriendLoc(), + FirstFriend->getSourceRange(), FriendFunction) + << FirstND; + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendFunction) + << SecondND; + + Diagnosed = true; + break; + } + + if (FirstTSI && SecondTSI) { + QualType FirstFriendType = FirstTSI->getType(); + QualType SecondFriendType = SecondTSI->getType(); + assert(ComputeQualTypeODRHash(FirstFriendType) != + ComputeQualTypeODRHash(SecondFriendType)); + ODRDiagError(FirstFriend->getFriendLoc(), + FirstFriend->getSourceRange(), FriendType) + << FirstFriendType; + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendType) + << SecondFriendType; + Diagnosed = true; + break; + } + + ODRDiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(), + FriendTypeFunction) + << (FirstTSI == nullptr); + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendTypeFunction) + << (SecondTSI == nullptr); + + Diagnosed = true; + break; + } + } + + if (Diagnosed == true) + continue; + + Diag(FirstDecl->getLocation(), + diag::err_module_odr_violation_mismatch_decl_unknown) + << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType + << FirstDecl->getSourceRange(); + Diag(SecondDecl->getLocation(), + diag::note_module_odr_violation_mismatch_decl_unknown) + << SecondModule << FirstDiffType << SecondDecl->getSourceRange(); + Diagnosed = true; } if (!Diagnosed) { @@ -8847,10 +10101,10 @@ void ASTReader::FinishedDeserializing() { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); auto *FPT = Update.second->getType()->castAs<FunctionProtoType>(); auto ESI = FPT->getExtProtoInfo().ExceptionSpec; - if (auto *Listener = Context.getASTMutationListener()) + if (auto *Listener = getContext().getASTMutationListener()) Listener->ResolvedExceptionSpec(cast<FunctionDecl>(Update.second)); for (auto *Redecl : Update.second->redecls()) - Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); + getContext().adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); } } @@ -8892,7 +10146,7 @@ void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { } } -ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, +ASTReader::ASTReader(Preprocessor &PP, ASTContext *Context, const PCHContainerReader &PCHContainerRdr, ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions, StringRef isysroot, bool DisableValidation, @@ -8905,8 +10159,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), + ContextObj(Context), + ModuleMgr(PP.getFileManager(), PP.getPCMCache(), PCHContainerRdr), + PCMCache(PP.getPCMCache()), DummyIdResolver(PP), + ReadTimer(std::move(ReadTimer)), isysroot(isysroot), DisableValidation(DisableValidation), AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), AllowConfigurationMismatch(AllowConfigurationMismatch), |