diff --git a/contrib/llvm-project/clang/include/clang/Frontend/MultiplexConsumer.h b/contrib/llvm-project/clang/include/clang/Frontend/MultiplexConsumer.h index e49e3392d1f3..3a7670d7a51a 100644 --- a/contrib/llvm-project/clang/include/clang/Frontend/MultiplexConsumer.h +++ b/contrib/llvm-project/clang/include/clang/Frontend/MultiplexConsumer.h @@ -1,90 +1,91 @@ //===-- MultiplexConsumer.h - AST Consumer for PCH Generation ---*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file declares the MultiplexConsumer class, which can be used to // multiplex ASTConsumer and SemaConsumer messages to many consumers. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_FRONTEND_MULTIPLEXCONSUMER_H #define LLVM_CLANG_FRONTEND_MULTIPLEXCONSUMER_H #include "clang/Basic/LLVM.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Serialization/ASTDeserializationListener.h" #include #include namespace clang { class MultiplexASTMutationListener; // This ASTDeserializationListener forwards its notifications to a set of // child listeners. class MultiplexASTDeserializationListener : public ASTDeserializationListener { public: // Does NOT take ownership of the elements in L. MultiplexASTDeserializationListener( const std::vector &L); void ReaderInitialized(ASTReader *Reader) override; void IdentifierRead(serialization::IdentifierID ID, IdentifierInfo *II) override; void MacroRead(serialization::MacroID ID, MacroInfo *MI) override; void TypeRead(serialization::TypeIdx Idx, QualType T) override; void DeclRead(GlobalDeclID ID, const Decl *D) override; + void PredefinedDeclBuilt(PredefinedDeclIDs ID, const Decl *D) override; void SelectorRead(serialization::SelectorID iD, Selector Sel) override; void MacroDefinitionRead(serialization::PreprocessedEntityID, MacroDefinitionRecord *MD) override; void ModuleRead(serialization::SubmoduleID ID, Module *Mod) override; void ModuleImportRead(serialization::SubmoduleID ID, SourceLocation ImportLoc) override; private: std::vector Listeners; }; // Has a list of ASTConsumers and calls each of them. Owns its children. class MultiplexConsumer : public SemaConsumer { public: // Takes ownership of the pointers in C. MultiplexConsumer(std::vector> C); ~MultiplexConsumer() override; // ASTConsumer void Initialize(ASTContext &Context) override; void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override; bool HandleTopLevelDecl(DeclGroupRef D) override; void HandleInlineFunctionDefinition(FunctionDecl *D) override; void HandleInterestingDecl(DeclGroupRef D) override; void HandleTranslationUnit(ASTContext &Ctx) override; void HandleTagDeclDefinition(TagDecl *D) override; void HandleTagDeclRequiredDefinition(const TagDecl *D) override; void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override; void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override; void HandleImplicitImportDecl(ImportDecl *D) override; void CompleteTentativeDefinition(VarDecl *D) override; void CompleteExternalDeclaration(DeclaratorDecl *D) override; void AssignInheritanceModel(CXXRecordDecl *RD) override; void HandleVTable(CXXRecordDecl *RD) override; ASTMutationListener *GetASTMutationListener() override; ASTDeserializationListener *GetASTDeserializationListener() override; void PrintStats() override; bool shouldSkipFunctionBody(Decl *D) override; // SemaConsumer void InitializeSema(Sema &S) override; void ForgetSema() override; private: std::vector> Consumers; // Owns these. std::unique_ptr MutationListener; std::unique_ptr DeserializationListener; }; } // end namespace clang #endif diff --git a/contrib/llvm-project/clang/include/clang/Serialization/ASTDeserializationListener.h b/contrib/llvm-project/clang/include/clang/Serialization/ASTDeserializationListener.h index 1d81a9ae3fe2..ea96faa07c19 100644 --- a/contrib/llvm-project/clang/include/clang/Serialization/ASTDeserializationListener.h +++ b/contrib/llvm-project/clang/include/clang/Serialization/ASTDeserializationListener.h @@ -1,61 +1,63 @@ //===- ASTDeserializationListener.h - Decl/Type PCH Read Events -*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the ASTDeserializationListener class, which is notified // by the ASTReader whenever a type or declaration is deserialized. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SERIALIZATION_ASTDESERIALIZATIONLISTENER_H #define LLVM_CLANG_SERIALIZATION_ASTDESERIALIZATIONLISTENER_H #include "clang/Basic/IdentifierTable.h" #include "clang/Serialization/ASTBitCodes.h" namespace clang { class Decl; class ASTReader; class QualType; class MacroDefinitionRecord; class MacroInfo; class Module; class SourceLocation; class ASTDeserializationListener { public: virtual ~ASTDeserializationListener(); /// The ASTReader was initialized. virtual void ReaderInitialized(ASTReader *Reader) { } /// An identifier was deserialized from the AST file. virtual void IdentifierRead(serialization::IdentifierID ID, IdentifierInfo *II) { } /// A macro was read from the AST file. virtual void MacroRead(serialization::MacroID ID, MacroInfo *MI) { } /// A type was deserialized from the AST file. The ID here has the /// qualifier bits already removed, and T is guaranteed to be locally /// unqualified. virtual void TypeRead(serialization::TypeIdx Idx, QualType T) { } /// A decl was deserialized from the AST file. virtual void DeclRead(GlobalDeclID ID, const Decl *D) {} + /// A predefined decl was built during the serialization. + virtual void PredefinedDeclBuilt(PredefinedDeclIDs ID, const Decl *D) {} /// A selector was read from the AST file. virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) {} /// A macro definition was read from the AST file. virtual void MacroDefinitionRead(serialization::PreprocessedEntityID, MacroDefinitionRecord *MD) {} /// A module definition was read from the AST file. virtual void ModuleRead(serialization::SubmoduleID ID, Module *Mod) {} /// A module import was read from the AST file. virtual void ModuleImportRead(serialization::SubmoduleID ID, SourceLocation ImportLoc) {} }; } #endif diff --git a/contrib/llvm-project/clang/include/clang/Serialization/ASTReader.h b/contrib/llvm-project/clang/include/clang/Serialization/ASTReader.h index 671520a3602b..82f32e843d63 100644 --- a/contrib/llvm-project/clang/include/clang/Serialization/ASTReader.h +++ b/contrib/llvm-project/clang/include/clang/Serialization/ASTReader.h @@ -1,2492 +1,2495 @@ //===- ASTReader.h - AST File Reader ----------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the ASTReader class, which reads AST files. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SERIALIZATION_ASTREADER_H #define LLVM_CLANG_SERIALIZATION_ASTREADER_H #include "clang/AST/Type.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/OpenCLOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Version.h" #include "clang/Lex/ExternalPreprocessorSource.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/Sema.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ContinuousRangeMap.h" #include "clang/Serialization/ModuleFile.h" #include "clang/Serialization/ModuleFileExtension.h" #include "clang/Serialization/ModuleManager.h" #include "clang/Serialization/SourceLocationEncoding.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/PagedVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Timer.h" #include "llvm/Support/VersionTuple.h" #include #include #include #include #include #include #include #include #include #include #include namespace clang { class ASTConsumer; class ASTContext; class ASTDeserializationListener; class ASTReader; class ASTRecordReader; class CXXTemporary; class Decl; class DeclarationName; class DeclaratorDecl; class DeclContext; class EnumDecl; class Expr; class FieldDecl; class FileEntry; class FileManager; class FileSystemOptions; class FunctionDecl; class GlobalModuleIndex; struct HeaderFileInfo; class HeaderSearchOptions; class LangOptions; class MacroInfo; class InMemoryModuleCache; class NamedDecl; class NamespaceDecl; class ObjCCategoryDecl; class ObjCInterfaceDecl; class PCHContainerReader; class Preprocessor; class PreprocessorOptions; class Sema; class SourceManager; class Stmt; class SwitchCase; class TargetOptions; class Token; class TypedefNameDecl; class ValueDecl; class VarDecl; /// Abstract interface for callback invocations by the ASTReader. /// /// While reading an AST file, the ASTReader will call the methods of the /// listener to pass on specific information. Some of the listener methods can /// return true to indicate to the ASTReader that the information (and /// consequently the AST file) is invalid. class ASTReaderListener { public: virtual ~ASTReaderListener(); /// Receives the full Clang version information. /// /// \returns true to indicate that the version is invalid. Subclasses should /// generally defer to this implementation. virtual bool ReadFullVersionInformation(StringRef FullVersion) { return FullVersion != getClangFullRepositoryVersion(); } virtual void ReadModuleName(StringRef ModuleName) {} virtual void ReadModuleMapFile(StringRef ModuleMapPath) {} /// Receives the language options. /// /// \returns true to indicate the options are invalid or false otherwise. virtual bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) { return false; } /// Receives the target options. /// /// \returns true to indicate the target options are invalid, or false /// otherwise. virtual bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, bool AllowCompatibleDifferences) { return false; } /// Receives the diagnostic options. /// /// \returns true to indicate the diagnostic options are invalid, or false /// otherwise. virtual bool ReadDiagnosticOptions(IntrusiveRefCntPtr DiagOpts, bool Complain) { return false; } /// Receives the file system options. /// /// \returns true to indicate the file system options are invalid, or false /// otherwise. virtual bool ReadFileSystemOptions(const FileSystemOptions &FSOpts, bool Complain) { return false; } /// Receives the header search options. /// /// \param HSOpts The read header search options. The following fields are /// missing and are reported in ReadHeaderSearchPaths(): /// UserEntries, SystemHeaderPrefixes, VFSOverlayFiles. /// /// \returns true to indicate the header search options are invalid, or false /// otherwise. virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) { return false; } /// Receives the header search paths. /// /// \param HSOpts The read header search paths. Only the following fields are /// initialized: UserEntries, SystemHeaderPrefixes, /// VFSOverlayFiles. The rest is reported in /// ReadHeaderSearchOptions(). /// /// \returns true to indicate the header search paths are invalid, or false /// otherwise. virtual bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts, bool Complain) { return false; } /// Receives the preprocessor options. /// /// \param SuggestedPredefines Can be filled in with the set of predefines /// that are suggested by the preprocessor options. Typically only used when /// loading a precompiled header. /// /// \returns true to indicate the preprocessor options are invalid, or false /// otherwise. virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool ReadMacros, bool Complain, std::string &SuggestedPredefines) { return false; } /// Receives __COUNTER__ value. virtual void ReadCounter(const serialization::ModuleFile &M, unsigned Value) {} /// This is called for each AST file loaded. virtual void visitModuleFile(StringRef Filename, serialization::ModuleKind Kind) {} /// Returns true if this \c ASTReaderListener wants to receive the /// input files of the AST file via \c visitInputFile, false otherwise. virtual bool needsInputFileVisitation() { return false; } /// Returns true if this \c ASTReaderListener wants to receive the /// system input files of the AST file via \c visitInputFile, false otherwise. virtual bool needsSystemInputFileVisitation() { return false; } /// if \c needsInputFileVisitation returns true, this is called for /// each non-system input file of the AST File. If /// \c needsSystemInputFileVisitation is true, then it is called for all /// system input files as well. /// /// \returns true to continue receiving the next input file, false to stop. virtual bool visitInputFile(StringRef Filename, bool isSystem, bool isOverridden, bool isExplicitModule) { return true; } /// Returns true if this \c ASTReaderListener wants to receive the /// imports of the AST file via \c visitImport, false otherwise. virtual bool needsImportVisitation() const { return false; } /// If needsImportVisitation returns \c true, this is called for each /// AST file imported by this AST file. virtual void visitImport(StringRef ModuleName, StringRef Filename) {} /// Indicates that a particular module file extension has been read. virtual void readModuleFileExtension( const ModuleFileExtensionMetadata &Metadata) {} }; /// Simple wrapper class for chaining listeners. class ChainedASTReaderListener : public ASTReaderListener { std::unique_ptr First; std::unique_ptr Second; public: /// Takes ownership of \p First and \p Second. ChainedASTReaderListener(std::unique_ptr First, std::unique_ptr Second) : First(std::move(First)), Second(std::move(Second)) {} std::unique_ptr takeFirst() { return std::move(First); } std::unique_ptr takeSecond() { return std::move(Second); } bool ReadFullVersionInformation(StringRef FullVersion) override; void ReadModuleName(StringRef ModuleName) override; void ReadModuleMapFile(StringRef ModuleMapPath) override; bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) override; bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, bool AllowCompatibleDifferences) override; bool ReadDiagnosticOptions(IntrusiveRefCntPtr DiagOpts, bool Complain) override; bool ReadFileSystemOptions(const FileSystemOptions &FSOpts, bool Complain) override; bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) override; bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool ReadMacros, bool Complain, std::string &SuggestedPredefines) override; void ReadCounter(const serialization::ModuleFile &M, unsigned Value) override; bool needsInputFileVisitation() override; bool needsSystemInputFileVisitation() override; void visitModuleFile(StringRef Filename, serialization::ModuleKind Kind) override; bool visitInputFile(StringRef Filename, bool isSystem, bool isOverridden, bool isExplicitModule) override; void readModuleFileExtension( const ModuleFileExtensionMetadata &Metadata) override; }; /// ASTReaderListener implementation to validate the information of /// the PCH file against an initialized Preprocessor. class PCHValidator : public ASTReaderListener { Preprocessor &PP; ASTReader &Reader; public: PCHValidator(Preprocessor &PP, ASTReader &Reader) : PP(PP), Reader(Reader) {} bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) override; bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, bool AllowCompatibleDifferences) override; bool ReadDiagnosticOptions(IntrusiveRefCntPtr DiagOpts, bool Complain) override; bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool ReadMacros, bool Complain, std::string &SuggestedPredefines) override; bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) override; void ReadCounter(const serialization::ModuleFile &M, unsigned Value) override; }; /// ASTReaderListenter implementation to set SuggestedPredefines of /// ASTReader which is required to use a pch file. This is the replacement /// of PCHValidator or SimplePCHValidator when using a pch file without /// validating it. class SimpleASTReaderListener : public ASTReaderListener { Preprocessor &PP; public: SimpleASTReaderListener(Preprocessor &PP) : PP(PP) {} bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool ReadMacros, bool Complain, std::string &SuggestedPredefines) override; }; namespace serialization { class ReadMethodPoolVisitor; namespace reader { class ASTIdentifierLookupTrait; /// The on-disk hash table(s) used for DeclContext name lookup. struct DeclContextLookupTable; } // namespace reader } // namespace serialization /// Reads an AST files chain containing the contents of a translation /// unit. /// /// The ASTReader class reads bitstreams (produced by the ASTWriter /// class) containing the serialized representation of a given /// abstract syntax tree and its supporting data structures. An /// instance of the ASTReader can be attached to an ASTContext object, /// which will provide access to the contents of the AST files. /// /// The AST reader provides lazy de-serialization of declarations, as /// required when traversing the AST. Only those AST nodes that are /// actually required will be de-serialized. class ASTReader : public ExternalPreprocessorSource, public ExternalPreprocessingRecordSource, public ExternalHeaderFileInfoSource, public ExternalSemaSource, public IdentifierInfoLookup, public ExternalSLocEntrySource { public: /// Types of AST files. friend class ASTDeclReader; friend class ASTIdentifierIterator; friend class ASTRecordReader; friend class ASTUnit; // ASTUnit needs to remap source locations. friend class ASTWriter; friend class PCHValidator; friend class serialization::reader::ASTIdentifierLookupTrait; friend class serialization::ReadMethodPoolVisitor; friend class TypeLocReader; friend class LocalDeclID; using RecordData = SmallVector; using RecordDataImpl = SmallVectorImpl; /// The result of reading the control block of an AST file, which /// can fail for various reasons. enum ASTReadResult { /// The control block was read successfully. Aside from failures, /// the AST file is safe to read into the current context. Success, /// The AST file itself appears corrupted. Failure, /// The AST file was missing. Missing, /// The AST file is out-of-date relative to its input files, /// and needs to be regenerated. OutOfDate, /// The AST file was written by a different version of Clang. VersionMismatch, /// The AST file was written with a different language/target /// configuration. ConfigurationMismatch, /// The AST file has errors. HadErrors }; using ModuleFile = serialization::ModuleFile; using ModuleKind = serialization::ModuleKind; using ModuleManager = serialization::ModuleManager; using ModuleIterator = ModuleManager::ModuleIterator; using ModuleConstIterator = ModuleManager::ModuleConstIterator; using ModuleReverseIterator = ModuleManager::ModuleReverseIterator; private: using LocSeq = SourceLocationSequence; /// The receiver of some callbacks invoked by ASTReader. std::unique_ptr Listener; /// The receiver of deserialization events. ASTDeserializationListener *DeserializationListener = nullptr; bool OwnsDeserializationListener = false; SourceManager &SourceMgr; FileManager &FileMgr; const PCHContainerReader &PCHContainerRdr; DiagnosticsEngine &Diags; // Sema has duplicate logic, but SemaObj can sometimes be null so ASTReader // has its own version. bool WarnedStackExhausted = false; /// The semantic analysis object that will be processing the /// AST files and the translation unit that uses it. Sema *SemaObj = nullptr; /// The preprocessor that will be loading the source file. Preprocessor &PP; /// The AST context into which we'll read the AST files. ASTContext *ContextObj = nullptr; /// The AST consumer. ASTConsumer *Consumer = nullptr; /// The module manager which manages modules and their dependencies ModuleManager ModuleMgr; /// A dummy identifier resolver used to merge TU-scope declarations in /// C, for the cases where we don't have a Sema object to provide a real /// identifier resolver. IdentifierResolver DummyIdResolver; /// A mapping from extension block names to module file extensions. llvm::StringMap> ModuleFileExtensions; /// A timer used to track the time spent deserializing. std::unique_ptr ReadTimer; /// The location where the module file will be considered as /// imported from. For non-module AST types it should be invalid. SourceLocation CurrentImportLoc; /// The module kind that is currently deserializing. std::optional CurrentDeserializingModuleKind; /// The global module index, if loaded. std::unique_ptr GlobalIndex; /// A map of global bit offsets to the module that stores entities /// at those bit offsets. ContinuousRangeMap GlobalBitOffsetsMap; /// A map of negated SLocEntryIDs to the modules containing them. ContinuousRangeMap GlobalSLocEntryMap; using GlobalSLocOffsetMapType = ContinuousRangeMap; /// A map of reversed (SourceManager::MaxLoadedOffset - SLocOffset) /// SourceLocation offsets to the modules containing them. GlobalSLocOffsetMapType GlobalSLocOffsetMap; /// Types that have already been loaded from the chain. /// /// When the pointer at index I is non-NULL, the type with /// ID = (I + 1) << FastQual::Width has already been loaded llvm::PagedVector TypesLoaded; /// Declarations that have already been loaded from the chain. /// /// When the pointer at index I is non-NULL, the declaration with ID /// = I + 1 has already been loaded. llvm::PagedVector DeclsLoaded; using FileOffset = std::pair; using FileOffsetsTy = SmallVector; using DeclUpdateOffsetsMap = llvm::DenseMap; /// Declarations that have modifications residing in a later file /// in the chain. DeclUpdateOffsetsMap DeclUpdateOffsets; using DelayedNamespaceOffsetMapTy = llvm::DenseMap>; /// Mapping from global declaration IDs to the lexical and visible block /// offset for delayed namespace in reduced BMI. /// /// We can't use the existing DeclUpdate mechanism since the DeclUpdate /// may only be applied in an outer most read. However, we need to know /// whether or not a DeclContext has external storage during the recursive /// reading. So we need to apply the offset immediately after we read the /// namespace as if it is not delayed. DelayedNamespaceOffsetMapTy DelayedNamespaceOffsetMap; struct PendingUpdateRecord { Decl *D; GlobalDeclID ID; // Whether the declaration was just deserialized. bool JustLoaded; PendingUpdateRecord(GlobalDeclID ID, Decl *D, bool JustLoaded) : D(D), ID(ID), JustLoaded(JustLoaded) {} }; /// Declaration updates for already-loaded declarations that we need /// to apply once we finish processing an import. llvm::SmallVector PendingUpdateRecords; enum class PendingFakeDefinitionKind { NotFake, Fake, FakeLoaded }; /// The DefinitionData pointers that we faked up for class definitions /// that we needed but hadn't loaded yet. llvm::DenseMap PendingFakeDefinitionData; /// Exception specification updates that have been loaded but not yet /// propagated across the relevant redeclaration chain. The map key is the /// canonical declaration (used only for deduplication) and the value is a /// declaration that has an exception specification. llvm::SmallMapVector PendingExceptionSpecUpdates; /// Deduced return type updates that have been loaded but not yet propagated /// across the relevant redeclaration chain. The map key is the canonical /// declaration and the value is the deduced return type. llvm::SmallMapVector PendingDeducedTypeUpdates; /// Functions has undededuced return type and we wish we can find the deduced /// return type by iterating the redecls in other modules. llvm::SmallVector PendingUndeducedFunctionDecls; /// Declarations that have been imported and have typedef names for /// linkage purposes. llvm::DenseMap, NamedDecl *> ImportedTypedefNamesForLinkage; /// Mergeable declaration contexts that have anonymous declarations /// within them, and those anonymous declarations. llvm::DenseMap> AnonymousDeclarationsForMerging; /// Map from numbering information for lambdas to the corresponding lambdas. llvm::DenseMap, NamedDecl *> LambdaDeclarationsForMerging; /// Key used to identify LifetimeExtendedTemporaryDecl for merging, /// containing the lifetime-extending declaration and the mangling number. using LETemporaryKey = std::pair; /// Map of already deserialiazed temporaries. llvm::DenseMap LETemporaryForMerging; struct FileDeclsInfo { ModuleFile *Mod = nullptr; ArrayRef Decls; FileDeclsInfo() = default; FileDeclsInfo(ModuleFile *Mod, ArrayRef Decls) : Mod(Mod), Decls(Decls) {} }; /// Map from a FileID to the file-level declarations that it contains. llvm::DenseMap FileDeclIDs; /// An array of lexical contents of a declaration context, as a sequence of /// Decl::Kind, DeclID pairs. using LexicalContents = ArrayRef; /// Map from a DeclContext to its lexical contents. llvm::DenseMap> LexicalDecls; /// Map from the TU to its lexical contents from each module file. std::vector> TULexicalDecls; /// Map from a DeclContext to its lookup tables. llvm::DenseMap Lookups; // Updates for visible decls can occur for other contexts than just the // TU, and when we read those update records, the actual context may not // be available yet, so have this pending map using the ID as a key. It // will be realized when the context is actually loaded. struct PendingVisibleUpdate { ModuleFile *Mod; const unsigned char *Data; }; using DeclContextVisibleUpdates = SmallVector; /// Updates to the visible declarations of declaration contexts that /// haven't been loaded yet. llvm::DenseMap PendingVisibleUpdates; /// The set of C++ or Objective-C classes that have forward /// declarations that have not yet been linked to their definitions. llvm::SmallPtrSet PendingDefinitions; using PendingBodiesMap = llvm::MapVector, SmallVector, 4>>; /// Functions or methods that have bodies that will be attached. PendingBodiesMap PendingBodies; /// Definitions for which we have added merged definitions but not yet /// performed deduplication. llvm::SetVector PendingMergedDefinitionsToDeduplicate; /// Read the record that describes the lexical contents of a DC. bool ReadLexicalDeclContextStorage(ModuleFile &M, llvm::BitstreamCursor &Cursor, uint64_t Offset, DeclContext *DC); /// Read the record that describes the visible contents of a DC. bool ReadVisibleDeclContextStorage(ModuleFile &M, llvm::BitstreamCursor &Cursor, uint64_t Offset, GlobalDeclID ID); /// A vector containing identifiers that have already been /// loaded. /// /// If the pointer at index I is non-NULL, then it refers to the /// IdentifierInfo for the identifier with ID=I+1 that has already /// been loaded. std::vector IdentifiersLoaded; /// A vector containing macros that have already been /// loaded. /// /// If the pointer at index I is non-NULL, then it refers to the /// MacroInfo for the identifier with ID=I+1 that has already /// been loaded. std::vector MacrosLoaded; using LoadedMacroInfo = std::pair; /// A set of #undef directives that we have loaded; used to /// deduplicate the same #undef information coming from multiple module /// files. llvm::DenseSet LoadedUndefs; using GlobalMacroMapType = ContinuousRangeMap; /// Mapping from global macro IDs to the module in which the /// macro resides along with the offset that should be added to the /// global macro ID to produce a local ID. GlobalMacroMapType GlobalMacroMap; /// A vector containing submodules that have already been loaded. /// /// This vector is indexed by the Submodule ID (-1). NULL submodule entries /// indicate that the particular submodule ID has not yet been loaded. SmallVector SubmodulesLoaded; using GlobalSubmoduleMapType = ContinuousRangeMap; /// Mapping from global submodule IDs to the module file in which the /// submodule resides along with the offset that should be added to the /// global submodule ID to produce a local ID. GlobalSubmoduleMapType GlobalSubmoduleMap; /// A set of hidden declarations. using HiddenNames = SmallVector; using HiddenNamesMapType = llvm::DenseMap; /// A mapping from each of the hidden submodules to the deserialized /// declarations in that submodule that could be made visible. HiddenNamesMapType HiddenNamesMap; /// A module import, export, or conflict that hasn't yet been resolved. struct UnresolvedModuleRef { /// The file in which this module resides. ModuleFile *File; /// The module that is importing or exporting. Module *Mod; /// The kind of module reference. enum { Import, Export, Conflict, Affecting } Kind; /// The local ID of the module that is being exported. unsigned ID; /// Whether this is a wildcard export. LLVM_PREFERRED_TYPE(bool) unsigned IsWildcard : 1; /// String data. StringRef String; }; /// The set of module imports and exports that still need to be /// resolved. SmallVector UnresolvedModuleRefs; /// A vector containing selectors that have already been loaded. /// /// This vector is indexed by the Selector ID (-1). NULL selector /// entries indicate that the particular selector ID has not yet /// been loaded. SmallVector SelectorsLoaded; using GlobalSelectorMapType = ContinuousRangeMap; /// Mapping from global selector IDs to the module in which the /// global selector ID to produce a local ID. GlobalSelectorMapType GlobalSelectorMap; /// The generation number of the last time we loaded data from the /// global method pool for this selector. llvm::DenseMap SelectorGeneration; /// Whether a selector is out of date. We mark a selector as out of date /// if we load another module after the method pool entry was pulled in. llvm::DenseMap SelectorOutOfDate; struct PendingMacroInfo { ModuleFile *M; /// Offset relative to ModuleFile::MacroOffsetsBase. uint32_t MacroDirectivesOffset; PendingMacroInfo(ModuleFile *M, uint32_t MacroDirectivesOffset) : M(M), MacroDirectivesOffset(MacroDirectivesOffset) {} }; using PendingMacroIDsMap = llvm::MapVector>; /// Mapping from identifiers that have a macro history to the global /// IDs have not yet been deserialized to the global IDs of those macros. PendingMacroIDsMap PendingMacroIDs; using GlobalPreprocessedEntityMapType = ContinuousRangeMap; /// Mapping from global preprocessing entity IDs to the module in /// which the preprocessed entity resides along with the offset that should be /// added to the global preprocessing entity ID to produce a local ID. GlobalPreprocessedEntityMapType GlobalPreprocessedEntityMap; using GlobalSkippedRangeMapType = ContinuousRangeMap; /// Mapping from global skipped range base IDs to the module in which /// the skipped ranges reside. GlobalSkippedRangeMapType GlobalSkippedRangeMap; /// \name CodeGen-relevant special data /// Fields containing data that is relevant to CodeGen. //@{ /// The IDs of all declarations that fulfill the criteria of /// "interesting" decls. /// /// This contains the data loaded from all EAGERLY_DESERIALIZED_DECLS blocks /// in the chain. The referenced declarations are deserialized and passed to /// the consumer eagerly. SmallVector EagerlyDeserializedDecls; /// The IDs of all vtables to emit. The referenced declarations are passed /// to the consumers' HandleVTable eagerly after passing /// EagerlyDeserializedDecls. SmallVector VTablesToEmit; /// The IDs of all tentative definitions stored in the chain. /// /// Sema keeps track of all tentative definitions in a TU because it has to /// complete them and pass them on to CodeGen. Thus, tentative definitions in /// the PCH chain must be eagerly deserialized. SmallVector TentativeDefinitions; /// The IDs of all CXXRecordDecls stored in the chain whose VTables are /// used. /// /// CodeGen has to emit VTables for these records, so they have to be eagerly /// deserialized. struct VTableUse { GlobalDeclID ID; SourceLocation::UIntTy RawLoc; bool Used; }; SmallVector VTableUses; /// A snapshot of the pending instantiations in the chain. /// /// This record tracks the instantiations that Sema has to perform at the /// end of the TU. It consists of a pair of values for every pending /// instantiation where the first value is the ID of the decl and the second /// is the instantiation location. struct PendingInstantiation { GlobalDeclID ID; SourceLocation::UIntTy RawLoc; }; SmallVector PendingInstantiations; //@} /// \name DiagnosticsEngine-relevant special data /// Fields containing data that is used for generating diagnostics //@{ /// A snapshot of Sema's unused file-scoped variable tracking, for /// generating warnings. SmallVector UnusedFileScopedDecls; /// A list of all the delegating constructors we've seen, to diagnose /// cycles. SmallVector DelegatingCtorDecls; /// Method selectors used in a @selector expression. Used for /// implementation of -Wselector. SmallVector ReferencedSelectorsData; /// A snapshot of Sema's weak undeclared identifier tracking, for /// generating warnings. SmallVector WeakUndeclaredIdentifiers; /// The IDs of type aliases for ext_vectors that exist in the chain. /// /// Used by Sema for finding sugared names for ext_vectors in diagnostics. SmallVector ExtVectorDecls; //@} /// \name Sema-relevant special data /// Fields containing data that is used for semantic analysis //@{ /// The IDs of all potentially unused typedef names in the chain. /// /// Sema tracks these to emit warnings. SmallVector UnusedLocalTypedefNameCandidates; /// Our current depth in #pragma cuda force_host_device begin/end /// macros. unsigned ForceHostDeviceDepth = 0; /// The IDs of the declarations Sema stores directly. /// /// Sema tracks a few important decls, such as namespace std, directly. SmallVector SemaDeclRefs; /// The IDs of the types ASTContext stores directly. /// /// The AST context tracks a few important types, such as va_list, directly. SmallVector SpecialTypes; /// The IDs of CUDA-specific declarations ASTContext stores directly. /// /// The AST context tracks a few important decls, currently cudaConfigureCall, /// directly. SmallVector CUDASpecialDeclRefs; /// The floating point pragma option settings. SmallVector FPPragmaOptions; /// The pragma clang optimize location (if the pragma state is "off"). SourceLocation OptimizeOffPragmaLocation; /// The PragmaMSStructKind pragma ms_struct state if set, or -1. int PragmaMSStructState = -1; /// The PragmaMSPointersToMembersKind pragma pointers_to_members state. int PragmaMSPointersToMembersState = -1; SourceLocation PointersToMembersPragmaLocation; /// The pragma float_control state. std::optional FpPragmaCurrentValue; SourceLocation FpPragmaCurrentLocation; struct FpPragmaStackEntry { FPOptionsOverride Value; SourceLocation Location; SourceLocation PushLocation; StringRef SlotLabel; }; llvm::SmallVector FpPragmaStack; llvm::SmallVector FpPragmaStrings; /// The pragma align/pack state. std::optional PragmaAlignPackCurrentValue; SourceLocation PragmaAlignPackCurrentLocation; struct PragmaAlignPackStackEntry { Sema::AlignPackInfo Value; SourceLocation Location; SourceLocation PushLocation; StringRef SlotLabel; }; llvm::SmallVector PragmaAlignPackStack; llvm::SmallVector PragmaAlignPackStrings; /// The OpenCL extension settings. OpenCLOptions OpenCLExtensions; /// Extensions required by an OpenCL type. llvm::DenseMap> OpenCLTypeExtMap; /// Extensions required by an OpenCL declaration. llvm::DenseMap> OpenCLDeclExtMap; /// A list of the namespaces we've seen. SmallVector KnownNamespaces; /// A list of undefined decls with internal linkage followed by the /// SourceLocation of a matching ODR-use. struct UndefinedButUsedDecl { GlobalDeclID ID; SourceLocation::UIntTy RawLoc; }; SmallVector UndefinedButUsed; /// Delete expressions to analyze at the end of translation unit. SmallVector DelayedDeleteExprs; // A list of late parsed template function data with their module files. SmallVector>, 4> LateParsedTemplates; /// The IDs of all decls to be checked for deferred diags. /// /// Sema tracks these to emit deferred diags. llvm::SmallSetVector DeclsToCheckForDeferredDiags; private: struct ImportedSubmodule { serialization::SubmoduleID ID; SourceLocation ImportLoc; ImportedSubmodule(serialization::SubmoduleID ID, SourceLocation ImportLoc) : ID(ID), ImportLoc(ImportLoc) {} }; /// A list of modules that were imported by precompiled headers or /// any other non-module AST file and have not yet been made visible. If a /// module is made visible in the ASTReader, it will be transfered to /// \c PendingImportedModulesSema. SmallVector PendingImportedModules; /// A list of modules that were imported by precompiled headers or /// any other non-module AST file and have not yet been made visible for Sema. SmallVector PendingImportedModulesSema; //@} /// The system include root to be used when loading the /// precompiled header. std::string isysroot; /// Whether to disable the normal validation performed on precompiled /// headers and module files when they are loaded. DisableValidationForModuleKind DisableValidationKind; /// Whether to accept an AST file with compiler errors. bool AllowASTWithCompilerErrors; /// Whether to accept an AST file that has a different configuration /// from the current compiler instance. bool AllowConfigurationMismatch; /// Whether validate system input files. bool ValidateSystemInputs; /// Whether validate headers and module maps using hash based on contents. bool ValidateASTInputFilesContent; /// Whether we are allowed to use the global module index. bool UseGlobalIndex; /// Whether we have tried loading the global module index yet. bool TriedLoadingGlobalIndex = false; ///Whether we are currently processing update records. bool ProcessingUpdateRecords = false; using SwitchCaseMapTy = llvm::DenseMap; /// Mapping from switch-case IDs in the chain to switch-case statements /// /// Statements usually don't have IDs, but switch cases need them, so that the /// switch statement can refer to them. SwitchCaseMapTy SwitchCaseStmts; SwitchCaseMapTy *CurrSwitchCaseStmts; /// The number of source location entries de-serialized from /// the PCH file. unsigned NumSLocEntriesRead = 0; /// The number of source location entries in the chain. unsigned TotalNumSLocEntries = 0; /// The number of statements (and expressions) de-serialized /// from the chain. unsigned NumStatementsRead = 0; /// The total number of statements (and expressions) stored /// in the chain. unsigned TotalNumStatements = 0; /// The number of macros de-serialized from the chain. unsigned NumMacrosRead = 0; /// The total number of macros stored in the chain. unsigned TotalNumMacros = 0; /// The number of lookups into identifier tables. unsigned NumIdentifierLookups = 0; /// The number of lookups into identifier tables that succeed. unsigned NumIdentifierLookupHits = 0; /// The number of selectors that have been read. unsigned NumSelectorsRead = 0; /// The number of method pool entries that have been read. unsigned NumMethodPoolEntriesRead = 0; /// The number of times we have looked up a selector in the method /// pool. unsigned NumMethodPoolLookups = 0; /// The number of times we have looked up a selector in the method /// pool and found something. unsigned NumMethodPoolHits = 0; /// The number of times we have looked up a selector in the method /// pool within a specific module. unsigned NumMethodPoolTableLookups = 0; /// The number of times we have looked up a selector in the method /// pool within a specific module and found something. unsigned NumMethodPoolTableHits = 0; /// The total number of method pool entries in the selector table. unsigned TotalNumMethodPoolEntries = 0; /// Number of lexical decl contexts read/total. unsigned NumLexicalDeclContextsRead = 0, TotalLexicalDeclContexts = 0; /// Number of visible decl contexts read/total. unsigned NumVisibleDeclContextsRead = 0, TotalVisibleDeclContexts = 0; /// Total size of modules, in bits, currently loaded uint64_t TotalModulesSizeInBits = 0; /// Number of Decl/types that are currently deserializing. unsigned NumCurrentElementsDeserializing = 0; /// Set true while we are in the process of passing deserialized /// "interesting" decls to consumer inside FinishedDeserializing(). /// This is used as a guard to avoid recursively repeating the process of /// passing decls to consumer. bool PassingDeclsToConsumer = false; /// The set of identifiers that were read while the AST reader was /// (recursively) loading declarations. /// /// The declarations on the identifier chain for these identifiers will be /// loaded once the recursive loading has completed. llvm::MapVector> PendingIdentifierInfos; /// The set of lookup results that we have faked in order to support /// merging of partially deserialized decls but that we have not yet removed. llvm::SmallMapVector, 16> PendingFakeLookupResults; /// The generation number of each identifier, which keeps track of /// the last time we loaded information about this identifier. llvm::DenseMap IdentifierGeneration; /// Contains declarations and definitions that could be /// "interesting" to the ASTConsumer, when we get that AST consumer. /// /// "Interesting" declarations are those that have data that may /// need to be emitted, such as inline function definitions or /// Objective-C protocols. std::deque PotentiallyInterestingDecls; /// The list of deduced function types that we have not yet read, because /// they might contain a deduced return type that refers to a local type /// declared within the function. SmallVector, 16> PendingDeducedFunctionTypes; /// The list of deduced variable types that we have not yet read, because /// they might contain a deduced type that refers to a local type declared /// within the variable. SmallVector, 16> PendingDeducedVarTypes; /// The list of redeclaration chains that still need to be /// reconstructed, and the local offset to the corresponding list /// of redeclarations. SmallVector, 16> PendingDeclChains; /// The list of canonical declarations whose redeclaration chains /// need to be marked as incomplete once we're done deserializing things. SmallVector PendingIncompleteDeclChains; /// The Decl IDs for the Sema/Lexical DeclContext of a Decl that has /// been loaded but its DeclContext was not set yet. struct PendingDeclContextInfo { Decl *D; GlobalDeclID SemaDC; GlobalDeclID LexicalDC; }; /// The set of Decls that have been loaded but their DeclContexts are /// not set yet. /// /// The DeclContexts for these Decls will be set once recursive loading has /// been completed. std::deque PendingDeclContextInfos; template using DuplicateObjCDecls = std::pair; /// When resolving duplicate ivars from Objective-C extensions we don't error /// out immediately but check if can merge identical extensions. Not checking /// extensions for equality immediately because ivar deserialization isn't /// over yet at that point. llvm::SmallMapVector, llvm::SmallVector, 4>, 2> PendingObjCExtensionIvarRedeclarations; /// Members that have been added to classes, for which the class has not yet /// been notified. CXXRecordDecl::addedMember will be called for each of /// these once recursive deserialization is complete. SmallVector, 4> PendingAddedClassMembers; /// The set of NamedDecls that have been loaded, but are members of a /// context that has been merged into another context where the corresponding /// declaration is either missing or has not yet been loaded. /// /// We will check whether the corresponding declaration is in fact missing /// once recursing loading has been completed. llvm::SmallVector PendingOdrMergeChecks; using DataPointers = std::pair; using ObjCInterfaceDataPointers = std::pair; using ObjCProtocolDataPointers = std::pair; /// Record definitions in which we found an ODR violation. llvm::SmallDenseMap, 2> PendingOdrMergeFailures; /// C/ObjC record definitions in which we found an ODR violation. llvm::SmallDenseMap, 2> PendingRecordOdrMergeFailures; /// Function definitions in which we found an ODR violation. llvm::SmallDenseMap, 2> PendingFunctionOdrMergeFailures; /// Enum definitions in which we found an ODR violation. llvm::SmallDenseMap, 2> PendingEnumOdrMergeFailures; /// ObjCInterfaceDecl in which we found an ODR violation. llvm::SmallDenseMap, 2> PendingObjCInterfaceOdrMergeFailures; /// ObjCProtocolDecl in which we found an ODR violation. llvm::SmallDenseMap, 2> PendingObjCProtocolOdrMergeFailures; /// DeclContexts in which we have diagnosed an ODR violation. llvm::SmallPtrSet DiagnosedOdrMergeFailures; /// The set of Objective-C categories that have been deserialized /// since the last time the declaration chains were linked. llvm::SmallPtrSet CategoriesDeserialized; /// The set of Objective-C class definitions that have already been /// loaded, for which we will need to check for categories whenever a new /// module is loaded. SmallVector ObjCClassesLoaded; using KeyDeclsMap = llvm::DenseMap>; /// A mapping from canonical declarations to the set of global /// declaration IDs for key declaration that have been merged with that /// canonical declaration. A key declaration is a formerly-canonical /// declaration whose module did not import any other key declaration for that /// entity. These are the IDs that we use as keys when finding redecl chains. KeyDeclsMap KeyDecls; /// A mapping from DeclContexts to the semantic DeclContext that we /// are treating as the definition of the entity. This is used, for instance, /// when merging implicit instantiations of class templates across modules. llvm::DenseMap MergedDeclContexts; /// A mapping from canonical declarations of enums to their canonical /// definitions. Only populated when using modules in C++. llvm::DenseMap EnumDefinitions; /// A mapping from canonical declarations of records to their canonical /// definitions. Doesn't cover CXXRecordDecl. llvm::DenseMap RecordDefinitions; /// When reading a Stmt tree, Stmt operands are placed in this stack. SmallVector StmtStack; /// What kind of records we are reading. enum ReadingKind { Read_None, Read_Decl, Read_Type, Read_Stmt }; /// What kind of records we are reading. ReadingKind ReadingKind = Read_None; /// RAII object to change the reading kind. class ReadingKindTracker { ASTReader &Reader; enum ReadingKind PrevKind; public: ReadingKindTracker(enum ReadingKind newKind, ASTReader &reader) : Reader(reader), PrevKind(Reader.ReadingKind) { Reader.ReadingKind = newKind; } ReadingKindTracker(const ReadingKindTracker &) = delete; ReadingKindTracker &operator=(const ReadingKindTracker &) = delete; ~ReadingKindTracker() { Reader.ReadingKind = PrevKind; } }; /// RAII object to mark the start of processing updates. class ProcessingUpdatesRAIIObj { ASTReader &Reader; bool PrevState; public: ProcessingUpdatesRAIIObj(ASTReader &reader) : Reader(reader), PrevState(Reader.ProcessingUpdateRecords) { Reader.ProcessingUpdateRecords = true; } ProcessingUpdatesRAIIObj(const ProcessingUpdatesRAIIObj &) = delete; ProcessingUpdatesRAIIObj & operator=(const ProcessingUpdatesRAIIObj &) = delete; ~ProcessingUpdatesRAIIObj() { Reader.ProcessingUpdateRecords = PrevState; } }; /// Suggested contents of the predefines buffer, after this /// PCH file has been processed. /// /// In most cases, this string will be empty, because the predefines /// buffer computed to build the PCH file will be identical to the /// predefines buffer computed from the command line. However, when /// there are differences that the PCH reader can work around, this /// predefines buffer may contain additional definitions. std::string SuggestedPredefines; llvm::DenseMap DefinitionSource; bool shouldDisableValidationForFile(const serialization::ModuleFile &M) const; /// Reads a statement from the specified cursor. Stmt *ReadStmtFromStream(ModuleFile &F); /// Retrieve the stored information about an input file. serialization::InputFileInfo getInputFileInfo(ModuleFile &F, unsigned ID); /// Retrieve the file entry and 'overridden' bit for an input /// file in the given module file. serialization::InputFile getInputFile(ModuleFile &F, unsigned ID, bool Complain = true); public: void ResolveImportedPath(ModuleFile &M, std::string &Filename); static void ResolveImportedPath(std::string &Filename, StringRef Prefix); /// Returns the first key declaration for the given declaration. This /// is one that is formerly-canonical (or still canonical) and whose module /// did not import any other key declaration of the entity. Decl *getKeyDeclaration(Decl *D) { D = D->getCanonicalDecl(); if (D->isFromASTFile()) return D; auto I = KeyDecls.find(D); if (I == KeyDecls.end() || I->second.empty()) return D; return GetExistingDecl(I->second[0]); } const Decl *getKeyDeclaration(const Decl *D) { return getKeyDeclaration(const_cast(D)); } /// Run a callback on each imported key declaration of \p D. template void forEachImportedKeyDecl(const Decl *D, Fn Visit) { D = D->getCanonicalDecl(); if (D->isFromASTFile()) Visit(D); auto It = KeyDecls.find(const_cast(D)); if (It != KeyDecls.end()) for (auto ID : It->second) Visit(GetExistingDecl(ID)); } /// Get the loaded lookup tables for \p Primary, if any. const serialization::reader::DeclContextLookupTable * getLoadedLookupTables(DeclContext *Primary) const; private: struct ImportedModule { ModuleFile *Mod; ModuleFile *ImportedBy; SourceLocation ImportLoc; ImportedModule(ModuleFile *Mod, ModuleFile *ImportedBy, SourceLocation ImportLoc) : Mod(Mod), ImportedBy(ImportedBy), ImportLoc(ImportLoc) {} }; ASTReadResult ReadASTCore(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc, ModuleFile *ImportedBy, SmallVectorImpl &Loaded, off_t ExpectedSize, time_t ExpectedModTime, ASTFileSignature ExpectedSignature, unsigned ClientLoadCapabilities); ASTReadResult ReadControlBlock(ModuleFile &F, SmallVectorImpl &Loaded, const ModuleFile *ImportedBy, unsigned ClientLoadCapabilities); static ASTReadResult ReadOptionsBlock( llvm::BitstreamCursor &Stream, unsigned ClientLoadCapabilities, bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener, std::string &SuggestedPredefines); /// Read the unhashed control block. /// /// This has no effect on \c F.Stream, instead creating a fresh cursor from /// \c F.Data and reading ahead. ASTReadResult readUnhashedControlBlock(ModuleFile &F, bool WasImportedBy, unsigned ClientLoadCapabilities); static ASTReadResult readUnhashedControlBlockImpl(ModuleFile *F, llvm::StringRef StreamData, unsigned ClientLoadCapabilities, bool AllowCompatibleConfigurationMismatch, ASTReaderListener *Listener, bool ValidateDiagnosticOptions); llvm::Error ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities); llvm::Error ReadExtensionBlock(ModuleFile &F); void ReadModuleOffsetMap(ModuleFile &F) const; void ParseLineTable(ModuleFile &F, const RecordData &Record); llvm::Error ReadSourceManagerBlock(ModuleFile &F); SourceLocation getImportLocation(ModuleFile *F); ASTReadResult ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, const ModuleFile *ImportedBy, unsigned ClientLoadCapabilities); llvm::Error ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities); static bool ParseLanguageOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener, bool AllowCompatibleDifferences); static bool ParseTargetOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener, bool AllowCompatibleDifferences); static bool ParseDiagnosticOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener); static bool ParseFileSystemOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener); static bool ParseHeaderSearchOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener); static bool ParseHeaderSearchPaths(const RecordData &Record, bool Complain, ASTReaderListener &Listener); static bool ParsePreprocessorOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener, std::string &SuggestedPredefines); struct RecordLocation { ModuleFile *F; uint64_t Offset; RecordLocation(ModuleFile *M, uint64_t O) : F(M), Offset(O) {} }; QualType readTypeRecord(serialization::TypeID ID); RecordLocation TypeCursorForIndex(serialization::TypeID ID); void LoadedDecl(unsigned Index, Decl *D); Decl *ReadDeclRecord(GlobalDeclID ID); void markIncompleteDeclChain(Decl *D); /// Returns the most recent declaration of a declaration (which must be /// of a redeclarable kind) that is either local or has already been loaded /// merged into its redecl chain. Decl *getMostRecentExistingDecl(Decl *D); RecordLocation DeclCursorForID(GlobalDeclID ID, SourceLocation &Location); void loadDeclUpdateRecords(PendingUpdateRecord &Record); void loadPendingDeclChain(Decl *D, uint64_t LocalOffset); void loadObjCCategories(GlobalDeclID ID, ObjCInterfaceDecl *D, unsigned PreviousGeneration = 0); RecordLocation getLocalBitOffset(uint64_t GlobalOffset); uint64_t getGlobalBitOffset(ModuleFile &M, uint64_t LocalOffset); /// Returns the first preprocessed entity ID that begins or ends after /// \arg Loc. serialization::PreprocessedEntityID findPreprocessedEntity(SourceLocation Loc, bool EndsAfter) const; /// Find the next module that contains entities and return the ID /// of the first entry. /// /// \param SLocMapI points at a chunk of a module that contains no /// preprocessed entities or the entities it contains are not the /// ones we are looking for. serialization::PreprocessedEntityID findNextPreprocessedEntity( GlobalSLocOffsetMapType::const_iterator SLocMapI) const; /// Returns (ModuleFile, Local index) pair for \p GlobalIndex of a /// preprocessed entity. std::pair getModulePreprocessedEntity(unsigned GlobalIndex); /// Returns (begin, end) pair for the preprocessed entities of a /// particular module. llvm::iterator_range getModulePreprocessedEntities(ModuleFile &Mod) const; bool canRecoverFromOutOfDate(StringRef ModuleFileName, unsigned ClientLoadCapabilities); public: class ModuleDeclIterator : public llvm::iterator_adaptor_base< ModuleDeclIterator, const serialization::unaligned_decl_id_t *, std::random_access_iterator_tag, const Decl *, ptrdiff_t, const Decl *, const Decl *> { ASTReader *Reader = nullptr; ModuleFile *Mod = nullptr; public: ModuleDeclIterator() : iterator_adaptor_base(nullptr) {} ModuleDeclIterator(ASTReader *Reader, ModuleFile *Mod, const serialization::unaligned_decl_id_t *Pos) : iterator_adaptor_base(Pos), Reader(Reader), Mod(Mod) {} value_type operator*() const { LocalDeclID ID = LocalDeclID::get(*Reader, *Mod, *I); return Reader->GetDecl(Reader->getGlobalDeclID(*Mod, ID)); } value_type operator->() const { return **this; } bool operator==(const ModuleDeclIterator &RHS) const { assert(Reader == RHS.Reader && Mod == RHS.Mod); return I == RHS.I; } }; llvm::iterator_range getModuleFileLevelDecls(ModuleFile &Mod); private: bool isConsumerInterestedIn(Decl *D); void PassInterestingDeclsToConsumer(); void PassInterestingDeclToConsumer(Decl *D); void PassVTableToConsumer(CXXRecordDecl *RD); void finishPendingActions(); void diagnoseOdrViolations(); void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name); void addPendingDeclContextInfo(Decl *D, GlobalDeclID SemaDC, GlobalDeclID LexicalDC) { assert(D); PendingDeclContextInfo Info = { D, SemaDC, LexicalDC }; PendingDeclContextInfos.push_back(Info); } /// Produce an error diagnostic and return true. /// /// This routine should only be used for fatal errors that have to /// do with non-routine failures (e.g., corrupted AST file). void Error(StringRef Msg) const; void Error(unsigned DiagID, StringRef Arg1 = StringRef(), StringRef Arg2 = StringRef(), StringRef Arg3 = StringRef()) const; void Error(llvm::Error &&Err) const; /// Translate a \param GlobalDeclID to the index of DeclsLoaded array. unsigned translateGlobalDeclIDToIndex(GlobalDeclID ID) const; /// Translate an \param IdentifierID ID to the index of IdentifiersLoaded /// array and the corresponding module file. std::pair translateIdentifierIDToIndex(serialization::IdentifierID ID) const; /// Translate an \param TypeID ID to the index of TypesLoaded /// array and the corresponding module file. std::pair translateTypeIDToIndex(serialization::TypeID ID) const; + /// Get a predefined Decl from ASTContext. + Decl *getPredefinedDecl(PredefinedDeclIDs ID); + public: /// Load the AST file and validate its contents against the given /// Preprocessor. /// /// \param PP the preprocessor associated with the context in which this /// precompiled header will be loaded. /// /// \param Context the AST context that this precompiled header will be /// loaded into, if any. /// /// \param PCHContainerRdr the PCHContainerOperations to use for loading and /// creating modules. /// /// \param Extensions the list of module file extensions that can be loaded /// from the AST files. /// /// \param isysroot If non-NULL, the system include path specified by the /// user. This is only used with relocatable PCH files. If non-NULL, /// a relocatable PCH file will use the default path "/". /// /// \param DisableValidationKind If set, the AST reader will suppress most /// of its regular consistency checking, allowing the use of precompiled /// headers and module files that cannot be determined to be compatible. /// /// \param AllowASTWithCompilerErrors If true, the AST reader will accept an /// AST file the was created out of an AST with compiler errors, /// otherwise it will reject it. /// /// \param AllowConfigurationMismatch If true, the AST reader will not check /// for configuration differences between the AST file and the invocation. /// /// \param ValidateSystemInputs If true, the AST reader will validate /// system input files in addition to user input files. This is only /// meaningful if \p DisableValidation is false. /// /// \param UseGlobalIndex If true, the AST reader will try to load and use /// the global module index. /// /// \param ReadTimer If non-null, a timer used to track the time spent /// deserializing. ASTReader(Preprocessor &PP, InMemoryModuleCache &ModuleCache, ASTContext *Context, const PCHContainerReader &PCHContainerRdr, ArrayRef> Extensions, StringRef isysroot = "", DisableValidationForModuleKind DisableValidationKind = DisableValidationForModuleKind::None, bool AllowASTWithCompilerErrors = false, bool AllowConfigurationMismatch = false, bool ValidateSystemInputs = false, bool ValidateASTInputFilesContent = false, bool UseGlobalIndex = true, std::unique_ptr ReadTimer = {}); ASTReader(const ASTReader &) = delete; ASTReader &operator=(const ASTReader &) = delete; ~ASTReader() override; SourceManager &getSourceManager() const { return SourceMgr; } FileManager &getFileManager() const { return FileMgr; } DiagnosticsEngine &getDiags() const { return Diags; } /// Flags that indicate what kind of AST loading failures the client /// of the AST reader can directly handle. /// /// When a client states that it can handle a particular kind of failure, /// the AST reader will not emit errors when producing that kind of failure. enum LoadFailureCapabilities { /// The client can't handle any AST loading failures. ARR_None = 0, /// The client can handle an AST file that cannot load because it /// is missing. ARR_Missing = 0x1, /// The client can handle an AST file that cannot load because it /// is out-of-date relative to its input files. ARR_OutOfDate = 0x2, /// The client can handle an AST file that cannot load because it /// was built with a different version of Clang. ARR_VersionMismatch = 0x4, /// The client can handle an AST file that cannot load because it's /// compiled configuration doesn't match that of the context it was /// loaded into. ARR_ConfigurationMismatch = 0x8, /// If a module file is marked with errors treat it as out-of-date so the /// caller can rebuild it. ARR_TreatModuleWithErrorsAsOutOfDate = 0x10 }; /// Load the AST file designated by the given file name. /// /// \param FileName The name of the AST file to load. /// /// \param Type The kind of AST being loaded, e.g., PCH, module, main file, /// or preamble. /// /// \param ImportLoc the location where the module file will be considered as /// imported from. For non-module AST types it should be invalid. /// /// \param ClientLoadCapabilities The set of client load-failure /// capabilities, represented as a bitset of the enumerators of /// LoadFailureCapabilities. /// /// \param LoadedModuleFile The optional out-parameter refers to the new /// loaded modules. In case the module specified by FileName is already /// loaded, the module file pointer referred by NewLoadedModuleFile wouldn't /// change. Otherwise if the AST file get loaded successfully, /// NewLoadedModuleFile would refer to the address of the new loaded top level /// module. The state of NewLoadedModuleFile is unspecified if the AST file /// isn't loaded successfully. ASTReadResult ReadAST(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc, unsigned ClientLoadCapabilities, ModuleFile **NewLoadedModuleFile = nullptr); /// Make the entities in the given module and any of its (non-explicit) /// submodules visible to name lookup. /// /// \param Mod The module whose names should be made visible. /// /// \param NameVisibility The level of visibility to give the names in the /// module. Visibility can only be increased over time. /// /// \param ImportLoc The location at which the import occurs. void makeModuleVisible(Module *Mod, Module::NameVisibilityKind NameVisibility, SourceLocation ImportLoc); /// Make the names within this set of hidden names visible. void makeNamesVisible(const HiddenNames &Names, Module *Owner); /// Note that MergedDef is a redefinition of the canonical definition /// Def, so Def should be visible whenever MergedDef is. void mergeDefinitionVisibility(NamedDecl *Def, NamedDecl *MergedDef); /// Take the AST callbacks listener. std::unique_ptr takeListener() { return std::move(Listener); } /// Set the AST callbacks listener. void setListener(std::unique_ptr Listener) { this->Listener = std::move(Listener); } /// Add an AST callback listener. /// /// Takes ownership of \p L. void addListener(std::unique_ptr L) { if (Listener) L = std::make_unique(std::move(L), std::move(Listener)); Listener = std::move(L); } /// RAII object to temporarily add an AST callback listener. class ListenerScope { ASTReader &Reader; bool Chained = false; public: ListenerScope(ASTReader &Reader, std::unique_ptr L) : Reader(Reader) { auto Old = Reader.takeListener(); if (Old) { Chained = true; L = std::make_unique(std::move(L), std::move(Old)); } Reader.setListener(std::move(L)); } ~ListenerScope() { auto New = Reader.takeListener(); if (Chained) Reader.setListener(static_cast(New.get()) ->takeSecond()); } }; /// Set the AST deserialization listener. void setDeserializationListener(ASTDeserializationListener *Listener, bool TakeOwnership = false); /// Get the AST deserialization listener. ASTDeserializationListener *getDeserializationListener() { return DeserializationListener; } /// Determine whether this AST reader has a global index. bool hasGlobalIndex() const { return (bool)GlobalIndex; } /// Return global module index. GlobalModuleIndex *getGlobalIndex() { return GlobalIndex.get(); } /// Reset reader for a reload try. void resetForReload() { TriedLoadingGlobalIndex = false; } /// Attempts to load the global index. /// /// \returns true if loading the global index has failed for any reason. bool loadGlobalIndex(); /// Determine whether we tried to load the global index, but failed, /// e.g., because it is out-of-date or does not exist. bool isGlobalIndexUnavailable() const; /// Initializes the ASTContext void InitializeContext(); /// Update the state of Sema after loading some additional modules. void UpdateSema(); /// Add in-memory (virtual file) buffer. void addInMemoryBuffer(StringRef &FileName, std::unique_ptr Buffer) { ModuleMgr.addInMemoryBuffer(FileName, std::move(Buffer)); } /// Finalizes the AST reader's state before writing an AST file to /// disk. /// /// This operation may undo temporary state in the AST that should not be /// emitted. void finalizeForWriting(); /// Retrieve the module manager. ModuleManager &getModuleManager() { return ModuleMgr; } const ModuleManager &getModuleManager() const { return ModuleMgr; } /// Retrieve the preprocessor. Preprocessor &getPreprocessor() const { return PP; } /// Retrieve the name of the original source file name for the primary /// module file. StringRef getOriginalSourceFile() { return ModuleMgr.getPrimaryModule().OriginalSourceFileName; } /// Retrieve the name of the original source file name directly from /// the AST file, without actually loading the AST file. static std::string getOriginalSourceFile(const std::string &ASTFileName, FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr, DiagnosticsEngine &Diags); /// Read the control block for the named AST file. /// /// \returns true if an error occurred, false otherwise. static bool readASTFileControlBlock( StringRef Filename, FileManager &FileMgr, const InMemoryModuleCache &ModuleCache, const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions, ASTReaderListener &Listener, bool ValidateDiagnosticOptions, unsigned ClientLoadCapabilities = ARR_ConfigurationMismatch | ARR_OutOfDate); /// Determine whether the given AST file is acceptable to load into a /// translation unit with the given language and target options. static bool isAcceptableASTFile(StringRef Filename, FileManager &FileMgr, const InMemoryModuleCache &ModuleCache, const PCHContainerReader &PCHContainerRdr, const LangOptions &LangOpts, const TargetOptions &TargetOpts, const PreprocessorOptions &PPOpts, StringRef ExistingModuleCachePath, bool RequireStrictOptionMatches = false); /// Returns the suggested contents of the predefines buffer, /// which contains a (typically-empty) subset of the predefines /// build prior to including the precompiled header. const std::string &getSuggestedPredefines() { return SuggestedPredefines; } /// Read a preallocated preprocessed entity from the external source. /// /// \returns null if an error occurred that prevented the preprocessed /// entity from being loaded. PreprocessedEntity *ReadPreprocessedEntity(unsigned Index) override; /// Returns a pair of [Begin, End) indices of preallocated /// preprocessed entities that \p Range encompasses. std::pair findPreprocessedEntitiesInRange(SourceRange Range) override; /// Optionally returns true or false if the preallocated preprocessed /// entity with index \p Index came from file \p FID. std::optional isPreprocessedEntityInFileID(unsigned Index, FileID FID) override; /// Read a preallocated skipped range from the external source. SourceRange ReadSkippedRange(unsigned Index) override; /// Read the header file information for the given file entry. HeaderFileInfo GetHeaderFileInfo(FileEntryRef FE) override; void ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag); /// Returns the number of source locations found in the chain. unsigned getTotalNumSLocs() const { return TotalNumSLocEntries; } /// Returns the number of identifiers found in the chain. unsigned getTotalNumIdentifiers() const { return static_cast(IdentifiersLoaded.size()); } /// Returns the number of macros found in the chain. unsigned getTotalNumMacros() const { return static_cast(MacrosLoaded.size()); } /// Returns the number of types found in the chain. unsigned getTotalNumTypes() const { return static_cast(TypesLoaded.size()); } /// Returns the number of declarations found in the chain. unsigned getTotalNumDecls() const { return static_cast(DeclsLoaded.size()); } /// Returns the number of submodules known. unsigned getTotalNumSubmodules() const { return static_cast(SubmodulesLoaded.size()); } /// Returns the number of selectors found in the chain. unsigned getTotalNumSelectors() const { return static_cast(SelectorsLoaded.size()); } /// Returns the number of preprocessed entities known to the AST /// reader. unsigned getTotalNumPreprocessedEntities() const { unsigned Result = 0; for (const auto &M : ModuleMgr) Result += M.NumPreprocessedEntities; return Result; } /// Resolve a type ID into a type, potentially building a new /// type. QualType GetType(serialization::TypeID ID); /// Resolve a local type ID within a given AST file into a type. QualType getLocalType(ModuleFile &F, serialization::LocalTypeID LocalID); /// Map a local type ID within a given AST file into a global type ID. serialization::TypeID getGlobalTypeID(ModuleFile &F, serialization::LocalTypeID LocalID) const; /// Read a type from the current position in the given record, which /// was read from the given AST file. QualType readType(ModuleFile &F, const RecordData &Record, unsigned &Idx) { if (Idx >= Record.size()) return {}; return getLocalType(F, Record[Idx++]); } /// Map from a local declaration ID within a given module to a /// global declaration ID. GlobalDeclID getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const; /// Returns true if global DeclID \p ID originated from module \p M. bool isDeclIDFromModule(GlobalDeclID ID, ModuleFile &M) const; /// Retrieve the module file that owns the given declaration, or NULL /// if the declaration is not from a module file. ModuleFile *getOwningModuleFile(const Decl *D) const; ModuleFile *getOwningModuleFile(GlobalDeclID ID) const; /// Returns the source location for the decl \p ID. SourceLocation getSourceLocationForDeclID(GlobalDeclID ID); /// Resolve a declaration ID into a declaration, potentially /// building a new declaration. Decl *GetDecl(GlobalDeclID ID); Decl *GetExternalDecl(GlobalDeclID ID) override; /// Resolve a declaration ID into a declaration. Return 0 if it's not /// been loaded yet. Decl *GetExistingDecl(GlobalDeclID ID); /// Reads a declaration with the given local ID in the given module. Decl *GetLocalDecl(ModuleFile &F, LocalDeclID LocalID) { return GetDecl(getGlobalDeclID(F, LocalID)); } /// Reads a declaration with the given local ID in the given module. /// /// \returns The requested declaration, casted to the given return type. template T *GetLocalDeclAs(ModuleFile &F, LocalDeclID LocalID) { return cast_or_null(GetLocalDecl(F, LocalID)); } /// Map a global declaration ID into the declaration ID used to /// refer to this declaration within the given module fule. /// /// \returns the global ID of the given declaration as known in the given /// module file. LocalDeclID mapGlobalIDToModuleFileGlobalID(ModuleFile &M, GlobalDeclID GlobalID); /// Reads a declaration ID from the given position in a record in the /// given module. /// /// \returns The declaration ID read from the record, adjusted to a global ID. GlobalDeclID ReadDeclID(ModuleFile &F, const RecordDataImpl &Record, unsigned &Idx); /// Reads a declaration from the given position in a record in the /// given module. Decl *ReadDecl(ModuleFile &F, const RecordDataImpl &R, unsigned &I) { return GetDecl(ReadDeclID(F, R, I)); } /// Reads a declaration from the given position in a record in the /// given module. /// /// \returns The declaration read from this location, casted to the given /// result type. template T *ReadDeclAs(ModuleFile &F, const RecordDataImpl &R, unsigned &I) { return cast_or_null(GetDecl(ReadDeclID(F, R, I))); } /// If any redeclarations of \p D have been imported since it was /// last checked, this digs out those redeclarations and adds them to the /// redeclaration chain for \p D. void CompleteRedeclChain(const Decl *D) override; CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) override; /// Resolve the offset of a statement into a statement. /// /// This operation will read a new statement from the external /// source each time it is called, and is meant to be used via a /// LazyOffsetPtr (which is used by Decls for the body of functions, etc). Stmt *GetExternalDeclStmt(uint64_t Offset) override; /// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the /// specified cursor. Read the abbreviations that are at the top of the block /// and then leave the cursor pointing into the block. static llvm::Error ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, unsigned BlockID, uint64_t *StartOfBlockOffset = nullptr); /// Finds all the visible declarations with a given name. /// The current implementation of this method just loads the entire /// lookup table as unmaterialized references. bool FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) override; /// Read all of the declarations lexically stored in a /// declaration context. /// /// \param DC The declaration context whose declarations will be /// read. /// /// \param IsKindWeWant A predicate indicating which declaration kinds /// we are interested in. /// /// \param Decls Vector that will contain the declarations loaded /// from the external source. The caller is responsible for merging /// these declarations with any declarations already stored in the /// declaration context. void FindExternalLexicalDecls(const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Decls) override; /// Get the decls that are contained in a file in the Offset/Length /// range. \p Length can be 0 to indicate a point at \p Offset instead of /// a range. void FindFileRegionDecls(FileID File, unsigned Offset, unsigned Length, SmallVectorImpl &Decls) override; /// Notify ASTReader that we started deserialization of /// a decl or type so until FinishedDeserializing is called there may be /// decls that are initializing. Must be paired with FinishedDeserializing. void StartedDeserializing() override; /// Notify ASTReader that we finished the deserialization of /// a decl or type. Must be paired with StartedDeserializing. void FinishedDeserializing() override; /// Function that will be invoked when we begin parsing a new /// translation unit involving this external AST source. /// /// This function will provide all of the external definitions to /// the ASTConsumer. void StartTranslationUnit(ASTConsumer *Consumer) override; /// Print some statistics about AST usage. void PrintStats() override; /// Dump information about the AST reader to standard error. void dump(); /// Return the amount of memory used by memory buffers, breaking down /// by heap-backed versus mmap'ed memory. void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override; /// Initialize the semantic source with the Sema instance /// being used to perform semantic analysis on the abstract syntax /// tree. void InitializeSema(Sema &S) override; /// Inform the semantic consumer that Sema is no longer available. void ForgetSema() override { SemaObj = nullptr; } /// Retrieve the IdentifierInfo for the named identifier. /// /// This routine builds a new IdentifierInfo for the given identifier. If any /// declarations with this name are visible from translation unit scope, their /// declarations will be deserialized and introduced into the declaration /// chain of the identifier. IdentifierInfo *get(StringRef Name) override; /// Retrieve an iterator into the set of all identifiers /// in all loaded AST files. IdentifierIterator *getIdentifiers() override; /// Load the contents of the global method pool for a given /// selector. void ReadMethodPool(Selector Sel) override; /// Load the contents of the global method pool for a given /// selector if necessary. void updateOutOfDateSelector(Selector Sel) override; /// Load the set of namespaces that are known to the external source, /// which will be used during typo correction. void ReadKnownNamespaces( SmallVectorImpl &Namespaces) override; void ReadUndefinedButUsed( llvm::MapVector &Undefined) override; void ReadMismatchingDeleteExpressions(llvm::MapVector< FieldDecl *, llvm::SmallVector, 4>> & Exprs) override; void ReadTentativeDefinitions( SmallVectorImpl &TentativeDefs) override; void ReadUnusedFileScopedDecls( SmallVectorImpl &Decls) override; void ReadDelegatingConstructors( SmallVectorImpl &Decls) override; void ReadExtVectorDecls(SmallVectorImpl &Decls) override; void ReadUnusedLocalTypedefNameCandidates( llvm::SmallSetVector &Decls) override; void ReadDeclsToCheckForDeferredDiags( llvm::SmallSetVector &Decls) override; void ReadReferencedSelectors( SmallVectorImpl> &Sels) override; void ReadWeakUndeclaredIdentifiers( SmallVectorImpl> &WeakIDs) override; void ReadUsedVTables(SmallVectorImpl &VTables) override; void ReadPendingInstantiations( SmallVectorImpl> &Pending) override; void ReadLateParsedTemplates( llvm::MapVector> &LPTMap) override; void AssignedLambdaNumbering(const CXXRecordDecl *Lambda) override; /// Load a selector from disk, registering its ID if it exists. void LoadSelector(Selector Sel); void SetIdentifierInfo(serialization::IdentifierID ID, IdentifierInfo *II); void SetGloballyVisibleDecls(IdentifierInfo *II, const SmallVectorImpl &DeclIDs, SmallVectorImpl *Decls = nullptr); /// Report a diagnostic. DiagnosticBuilder Diag(unsigned DiagID) const; /// Report a diagnostic. DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const; void warnStackExhausted(SourceLocation Loc); IdentifierInfo *DecodeIdentifierInfo(serialization::IdentifierID ID); IdentifierInfo *readIdentifier(ModuleFile &M, const RecordData &Record, unsigned &Idx) { return DecodeIdentifierInfo(getGlobalIdentifierID(M, Record[Idx++])); } IdentifierInfo *GetIdentifier(serialization::IdentifierID ID) override { // Note that we are loading an identifier. Deserializing AnIdentifier(this); return DecodeIdentifierInfo(ID); } IdentifierInfo *getLocalIdentifier(ModuleFile &M, uint64_t LocalID); serialization::IdentifierID getGlobalIdentifierID(ModuleFile &M, uint64_t LocalID); void resolvePendingMacro(IdentifierInfo *II, const PendingMacroInfo &PMInfo); /// Retrieve the macro with the given ID. MacroInfo *getMacro(serialization::MacroID ID); /// Retrieve the global macro ID corresponding to the given local /// ID within the given module file. serialization::MacroID getGlobalMacroID(ModuleFile &M, unsigned LocalID); /// Read the source location entry with index ID. bool ReadSLocEntry(int ID) override; /// Get the index ID for the loaded SourceLocation offset. int getSLocEntryID(SourceLocation::UIntTy SLocOffset) override; /// Try to read the offset of the SLocEntry at the given index in the given /// module file. llvm::Expected readSLocOffset(ModuleFile *F, unsigned Index); /// Retrieve the module import location and module name for the /// given source manager entry ID. std::pair getModuleImportLoc(int ID) override; /// Retrieve the global submodule ID given a module and its local ID /// number. serialization::SubmoduleID getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) const; /// Retrieve the submodule that corresponds to a global submodule ID. /// Module *getSubmodule(serialization::SubmoduleID GlobalID); /// Retrieve the module that corresponds to the given module ID. /// /// Note: overrides method in ExternalASTSource Module *getModule(unsigned ID) override; /// Retrieve the module file with a given local ID within the specified /// ModuleFile. ModuleFile *getLocalModuleFile(ModuleFile &M, unsigned ID) const; /// Get an ID for the given module file. unsigned getModuleFileID(ModuleFile *M); /// Return a descriptor for the corresponding module. std::optional getSourceDescriptor(unsigned ID) override; ExtKind hasExternalDefinitions(const Decl *D) override; /// Retrieve a selector from the given module with its local ID /// number. Selector getLocalSelector(ModuleFile &M, unsigned LocalID); Selector DecodeSelector(serialization::SelectorID Idx); Selector GetExternalSelector(serialization::SelectorID ID) override; uint32_t GetNumExternalSelectors() override; Selector ReadSelector(ModuleFile &M, const RecordData &Record, unsigned &Idx) { return getLocalSelector(M, Record[Idx++]); } /// Retrieve the global selector ID that corresponds to this /// the local selector ID in a given module. serialization::SelectorID getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const; /// Read the contents of a CXXCtorInitializer array. CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override; /// Read a AlignPackInfo from raw form. Sema::AlignPackInfo ReadAlignPackInfo(uint32_t Raw) const { return Sema::AlignPackInfo::getFromRawEncoding(Raw); } using RawLocEncoding = SourceLocationEncoding::RawLocEncoding; /// Read a source location from raw form and return it in its /// originating module file's source location space. std::pair ReadUntranslatedSourceLocation(RawLocEncoding Raw, LocSeq *Seq = nullptr) const { return SourceLocationEncoding::decode(Raw, Seq); } /// Read a source location from raw form. SourceLocation ReadSourceLocation(ModuleFile &MF, RawLocEncoding Raw, LocSeq *Seq = nullptr) const { if (!MF.ModuleOffsetMap.empty()) ReadModuleOffsetMap(MF); auto [Loc, ModuleFileIndex] = ReadUntranslatedSourceLocation(Raw, Seq); ModuleFile *OwningModuleFile = ModuleFileIndex == 0 ? &MF : MF.TransitiveImports[ModuleFileIndex - 1]; assert(!SourceMgr.isLoadedSourceLocation(Loc) && "Run out source location space"); return TranslateSourceLocation(*OwningModuleFile, Loc); } /// Translate a source location from another module file's source /// location space into ours. SourceLocation TranslateSourceLocation(ModuleFile &ModuleFile, SourceLocation Loc) const { if (Loc.isInvalid()) return Loc; // FIXME: TranslateSourceLocation is not re-enterable. It is problematic // to call TranslateSourceLocation on a translated source location. // We either need a method to know whether or not a source location is // translated or refactor the code to make it clear that // TranslateSourceLocation won't be called with translated source location. return Loc.getLocWithOffset(ModuleFile.SLocEntryBaseOffset - 2); } /// Read a source location. SourceLocation ReadSourceLocation(ModuleFile &ModuleFile, const RecordDataImpl &Record, unsigned &Idx, LocSeq *Seq = nullptr) { return ReadSourceLocation(ModuleFile, Record[Idx++], Seq); } /// Read a FileID. FileID ReadFileID(ModuleFile &F, const RecordDataImpl &Record, unsigned &Idx) const { return TranslateFileID(F, FileID::get(Record[Idx++])); } /// Translate a FileID from another module file's FileID space into ours. FileID TranslateFileID(ModuleFile &F, FileID FID) const { assert(FID.ID >= 0 && "Reading non-local FileID."); return FileID::get(F.SLocEntryBaseID + FID.ID - 1); } /// Read a source range. SourceRange ReadSourceRange(ModuleFile &F, const RecordData &Record, unsigned &Idx, LocSeq *Seq = nullptr); static llvm::BitVector ReadBitVector(const RecordData &Record, const StringRef Blob); // Read a string static std::string ReadString(const RecordDataImpl &Record, unsigned &Idx); // Skip a string static void SkipString(const RecordData &Record, unsigned &Idx) { Idx += Record[Idx] + 1; } // Read a path std::string ReadPath(ModuleFile &F, const RecordData &Record, unsigned &Idx); // Read a path std::string ReadPath(StringRef BaseDirectory, const RecordData &Record, unsigned &Idx); // Skip a path static void SkipPath(const RecordData &Record, unsigned &Idx) { SkipString(Record, Idx); } /// Read a version tuple. static VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx); CXXTemporary *ReadCXXTemporary(ModuleFile &F, const RecordData &Record, unsigned &Idx); /// Reads a statement. Stmt *ReadStmt(ModuleFile &F); /// Reads an expression. Expr *ReadExpr(ModuleFile &F); /// Reads a sub-statement operand during statement reading. Stmt *ReadSubStmt() { assert(ReadingKind == Read_Stmt && "Should be called only during statement reading!"); // Subexpressions are stored from last to first, so the next Stmt we need // is at the back of the stack. assert(!StmtStack.empty() && "Read too many sub-statements!"); return StmtStack.pop_back_val(); } /// Reads a sub-expression operand during statement reading. Expr *ReadSubExpr(); /// Reads a token out of a record. Token ReadToken(ModuleFile &M, const RecordDataImpl &Record, unsigned &Idx); /// Reads the macro record located at the given offset. MacroInfo *ReadMacroRecord(ModuleFile &F, uint64_t Offset); /// Determine the global preprocessed entity ID that corresponds to /// the given local ID within the given module. serialization::PreprocessedEntityID getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const; /// Add a macro to deserialize its macro directive history. /// /// \param II The name of the macro. /// \param M The module file. /// \param MacroDirectivesOffset Offset of the serialized macro directive /// history. void addPendingMacro(IdentifierInfo *II, ModuleFile *M, uint32_t MacroDirectivesOffset); /// Read the set of macros defined by this external macro source. void ReadDefinedMacros() override; /// Update an out-of-date identifier. void updateOutOfDateIdentifier(const IdentifierInfo &II) override; /// Note that this identifier is up-to-date. void markIdentifierUpToDate(const IdentifierInfo *II); /// Load all external visible decls in the given DeclContext. void completeVisibleDeclsMap(const DeclContext *DC) override; /// Retrieve the AST context that this AST reader supplements. ASTContext &getContext() { assert(ContextObj && "requested AST context when not loading AST"); return *ContextObj; } // Contains the IDs for declarations that were requested before we have // access to a Sema object. SmallVector PreloadedDeclIDs; /// Retrieve the semantic analysis object used to analyze the /// translation unit in which the precompiled header is being /// imported. Sema *getSema() { return SemaObj; } /// Get the identifier resolver used for name lookup / updates /// in the translation unit scope. We have one of these even if we don't /// have a Sema object. IdentifierResolver &getIdResolver(); /// Retrieve the identifier table associated with the /// preprocessor. IdentifierTable &getIdentifierTable(); /// Record that the given ID maps to the given switch-case /// statement. void RecordSwitchCaseID(SwitchCase *SC, unsigned ID); /// Retrieve the switch-case statement with the given ID. SwitchCase *getSwitchCaseWithID(unsigned ID); void ClearSwitchCaseIDs(); /// Cursors for comments blocks. SmallVector, 8> CommentsCursors; /// Loads comments ranges. void ReadComments() override; /// Visit all the input file infos of the given module file. void visitInputFileInfos( serialization::ModuleFile &MF, bool IncludeSystem, llvm::function_ref Visitor); /// Visit all the input files of the given module file. void visitInputFiles(serialization::ModuleFile &MF, bool IncludeSystem, bool Complain, llvm::function_ref Visitor); /// Visit all the top-level module maps loaded when building the given module /// file. void visitTopLevelModuleMaps(serialization::ModuleFile &MF, llvm::function_ref Visitor); bool isProcessingUpdateRecords() { return ProcessingUpdateRecords; } }; /// A simple helper class to unpack an integer to bits and consuming /// the bits in order. class BitsUnpacker { constexpr static uint32_t BitsIndexUpbound = 32; public: BitsUnpacker(uint32_t V) { updateValue(V); } BitsUnpacker(const BitsUnpacker &) = delete; BitsUnpacker(BitsUnpacker &&) = delete; BitsUnpacker operator=(const BitsUnpacker &) = delete; BitsUnpacker operator=(BitsUnpacker &&) = delete; ~BitsUnpacker() = default; void updateValue(uint32_t V) { Value = V; CurrentBitsIndex = 0; } void advance(uint32_t BitsWidth) { CurrentBitsIndex += BitsWidth; } bool getNextBit() { assert(isValid()); return Value & (1 << CurrentBitsIndex++); } uint32_t getNextBits(uint32_t Width) { assert(isValid()); assert(Width < BitsIndexUpbound); uint32_t Ret = (Value >> CurrentBitsIndex) & ((1 << Width) - 1); CurrentBitsIndex += Width; return Ret; } bool canGetNextNBits(uint32_t Width) const { return CurrentBitsIndex + Width < BitsIndexUpbound; } private: bool isValid() const { return CurrentBitsIndex < BitsIndexUpbound; } uint32_t Value; uint32_t CurrentBitsIndex = ~0; }; inline bool shouldSkipCheckingODR(const Decl *D) { return D->getASTContext().getLangOpts().SkipODRCheckInGMF && D->isFromExplicitGlobalModule(); } } // namespace clang #endif // LLVM_CLANG_SERIALIZATION_ASTREADER_H diff --git a/contrib/llvm-project/clang/include/clang/Serialization/ASTWriter.h b/contrib/llvm-project/clang/include/clang/Serialization/ASTWriter.h index 700f0ad00111..10a50b711043 100644 --- a/contrib/llvm-project/clang/include/clang/Serialization/ASTWriter.h +++ b/contrib/llvm-project/clang/include/clang/Serialization/ASTWriter.h @@ -1,1042 +1,1043 @@ //===- ASTWriter.h - AST File Writer ----------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the ASTWriter class, which writes an AST file // containing a serialized representation of a translation unit. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SERIALIZATION_ASTWRITER_H #define LLVM_CLANG_SERIALIZATION_ASTWRITER_H #include "clang/AST/ASTMutationListener.h" #include "clang/AST/Decl.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ASTDeserializationListener.h" #include "clang/Serialization/PCHContainerOperations.h" #include "clang/Serialization/SourceLocationEncoding.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitstreamWriter.h" #include #include #include #include #include #include #include #include #include namespace clang { class ASTContext; class ASTReader; class Attr; class CXXRecordDecl; class FileEntry; class FPOptionsOverride; class FunctionDecl; class HeaderSearch; class HeaderSearchOptions; class IdentifierResolver; class LangOptions; class MacroDefinitionRecord; class MacroInfo; class Module; class InMemoryModuleCache; class ModuleFileExtension; class ModuleFileExtensionWriter; class NamedDecl; class ObjCInterfaceDecl; class PreprocessingRecord; class Preprocessor; class RecordDecl; class Sema; class SourceManager; class Stmt; class StoredDeclsList; class SwitchCase; class Token; namespace SrcMgr { class FileInfo; } // namespace SrcMgr /// Writes an AST file containing the contents of a translation unit. /// /// The ASTWriter class produces a bitstream containing the serialized /// representation of a given abstract syntax tree and its supporting /// data structures. This bitstream can be de-serialized via an /// instance of the ASTReader class. class ASTWriter : public ASTDeserializationListener, public ASTMutationListener { public: friend class ASTDeclWriter; friend class ASTRecordWriter; using RecordData = SmallVector; using RecordDataImpl = SmallVectorImpl; using RecordDataRef = ArrayRef; private: /// Map that provides the ID numbers of each type within the /// output stream, plus those deserialized from a chained PCH. /// /// The ID numbers of types are consecutive (in order of discovery) /// and start at 1. 0 is reserved for NULL. When types are actually /// stored in the stream, the ID number is shifted by 2 bits to /// allow for the const/volatile qualifiers. /// /// Keys in the map never have const/volatile qualifiers. using TypeIdxMap = llvm::DenseMap; using LocSeq = SourceLocationSequence; /// The bitstream writer used to emit this precompiled header. llvm::BitstreamWriter &Stream; /// The buffer associated with the bitstream. const SmallVectorImpl &Buffer; /// The PCM manager which manages memory buffers for pcm files. InMemoryModuleCache &ModuleCache; /// The ASTContext we're writing. ASTContext *Context = nullptr; /// The preprocessor we're writing. Preprocessor *PP = nullptr; /// The reader of existing AST files, if we're chaining. ASTReader *Chain = nullptr; /// The module we're currently writing, if any. Module *WritingModule = nullptr; /// The byte range representing all the UNHASHED_CONTROL_BLOCK. std::pair UnhashedControlBlockRange; /// The bit offset of the AST block hash blob. uint64_t ASTBlockHashOffset = 0; /// The bit offset of the signature blob. uint64_t SignatureOffset = 0; /// The bit offset of the first bit inside the AST_BLOCK. uint64_t ASTBlockStartOffset = 0; /// The byte range representing all the AST_BLOCK. std::pair ASTBlockRange; /// The base directory for any relative paths we emit. std::string BaseDirectory; /// Indicates whether timestamps should be written to the produced /// module file. This is the case for files implicitly written to the /// module cache, where we need the timestamps to determine if the module /// file is up to date, but not otherwise. bool IncludeTimestamps; /// Indicates whether the AST file being written is an implicit module. /// If that's the case, we may be able to skip writing some information that /// are guaranteed to be the same in the importer by the context hash. bool BuildingImplicitModule = false; /// Indicates when the AST writing is actively performing /// serialization, rather than just queueing updates. bool WritingAST = false; /// Indicates that we are done serializing the collection of decls /// and types to emit. bool DoneWritingDeclsAndTypes = false; /// Indicates that the AST contained compiler errors. bool ASTHasCompilerErrors = false; /// Indicates that we're going to generate the reduced BMI for C++20 /// named modules. bool GeneratingReducedBMI = false; /// Mapping from input file entries to the index into the /// offset table where information about that input file is stored. llvm::DenseMap InputFileIDs; /// Stores a declaration or a type to be written to the AST file. class DeclOrType { public: DeclOrType(Decl *D) : Stored(D), IsType(false) {} DeclOrType(QualType T) : Stored(T.getAsOpaquePtr()), IsType(true) {} bool isType() const { return IsType; } bool isDecl() const { return !IsType; } QualType getType() const { assert(isType() && "Not a type!"); return QualType::getFromOpaquePtr(Stored); } Decl *getDecl() const { assert(isDecl() && "Not a decl!"); return static_cast(Stored); } private: void *Stored; bool IsType; }; /// The declarations and types to emit. std::queue DeclTypesToEmit; /// The delayed namespace to emit. Only meaningful for reduced BMI. /// /// In reduced BMI, we want to elide the unreachable declarations in /// the global module fragment. However, in ASTWriterDecl, when we see /// a namespace, all the declarations in the namespace would be emitted. /// So the optimization become meaningless. To solve the issue, we /// delay recording all the declarations until we emit all the declarations. /// Then we can safely record the reached declarations only. llvm::SmallVector DelayedNamespace; /// The first ID number we can use for our own declarations. LocalDeclID FirstDeclID = LocalDeclID(clang::NUM_PREDEF_DECL_IDS); /// The decl ID that will be assigned to the next new decl. LocalDeclID NextDeclID = FirstDeclID; /// Map that provides the ID numbers of each declaration within /// the output stream, as well as those deserialized from a chained PCH. /// /// The ID numbers of declarations are consecutive (in order of /// discovery) and start at 2. 1 is reserved for the translation /// unit, while 0 is reserved for NULL. llvm::DenseMap DeclIDs; /// Set of predefined decls. This is a helper data to determine if a decl /// is predefined. It should be more clear and safer to query the set /// instead of comparing the result of `getDeclID()` or `GetDeclRef()`. llvm::SmallPtrSet PredefinedDecls; /// Offset of each declaration in the bitstream, indexed by /// the declaration's ID. std::vector DeclOffsets; /// The offset of the DECLTYPES_BLOCK. The offsets in DeclOffsets /// are relative to this value. uint64_t DeclTypesBlockStartOffset = 0; /// Sorted (by file offset) vector of pairs of file offset/LocalDeclID. using LocDeclIDsTy = SmallVector, 64>; struct DeclIDInFileInfo { LocDeclIDsTy DeclIDs; /// Set when the DeclIDs vectors from all files are joined, this /// indicates the index that this particular vector has in the global one. unsigned FirstDeclIndex; }; using FileDeclIDsTy = llvm::DenseMap>; /// Map from file SLocEntries to info about the file-level declarations /// that it contains. FileDeclIDsTy FileDeclIDs; void associateDeclWithFile(const Decl *D, LocalDeclID); /// The first ID number we can use for our own types. serialization::TypeID FirstTypeID = serialization::NUM_PREDEF_TYPE_IDS; /// The type ID that will be assigned to the next new type. serialization::TypeID NextTypeID = FirstTypeID; /// Map that provides the ID numbers of each type within the /// output stream, plus those deserialized from a chained PCH. /// /// The ID numbers of types are consecutive (in order of discovery) /// and start at 1. 0 is reserved for NULL. When types are actually /// stored in the stream, the ID number is shifted by 2 bits to /// allow for the const/volatile qualifiers. /// /// Keys in the map never have const/volatile qualifiers. TypeIdxMap TypeIdxs; /// Offset of each type in the bitstream, indexed by /// the type's ID. std::vector TypeOffsets; /// The first ID number we can use for our own identifiers. serialization::IdentifierID FirstIdentID = serialization::NUM_PREDEF_IDENT_IDS; /// The identifier ID that will be assigned to the next new identifier. serialization::IdentifierID NextIdentID = FirstIdentID; /// Map that provides the ID numbers of each identifier in /// the output stream. /// /// The ID numbers for identifiers are consecutive (in order of /// discovery), starting at 1. An ID of zero refers to a NULL /// IdentifierInfo. llvm::MapVector IdentifierIDs; /// The first ID number we can use for our own macros. serialization::MacroID FirstMacroID = serialization::NUM_PREDEF_MACRO_IDS; /// The identifier ID that will be assigned to the next new identifier. serialization::MacroID NextMacroID = FirstMacroID; /// Map that provides the ID numbers of each macro. llvm::DenseMap MacroIDs; struct MacroInfoToEmitData { const IdentifierInfo *Name; MacroInfo *MI; serialization::MacroID ID; }; /// The macro infos to emit. std::vector MacroInfosToEmit; llvm::DenseMap IdentMacroDirectivesOffsetMap; /// @name FlushStmt Caches /// @{ /// Set of parent Stmts for the currently serializing sub-stmt. llvm::DenseSet ParentStmts; /// Offsets of sub-stmts already serialized. The offset points /// just after the stmt record. llvm::DenseMap SubStmtEntries; /// @} /// Offsets of each of the identifier IDs into the identifier /// table. std::vector IdentifierOffsets; /// The first ID number we can use for our own submodules. serialization::SubmoduleID FirstSubmoduleID = serialization::NUM_PREDEF_SUBMODULE_IDS; /// The submodule ID that will be assigned to the next new submodule. serialization::SubmoduleID NextSubmoduleID = FirstSubmoduleID; /// The first ID number we can use for our own selectors. serialization::SelectorID FirstSelectorID = serialization::NUM_PREDEF_SELECTOR_IDS; /// The selector ID that will be assigned to the next new selector. serialization::SelectorID NextSelectorID = FirstSelectorID; /// Map that provides the ID numbers of each Selector. llvm::MapVector SelectorIDs; /// Offset of each selector within the method pool/selector /// table, indexed by the Selector ID (-1). std::vector SelectorOffsets; /// Mapping from macro definitions (as they occur in the preprocessing /// record) to the macro IDs. llvm::DenseMap MacroDefinitions; /// Cache of indices of anonymous declarations within their lexical /// contexts. llvm::DenseMap AnonymousDeclarationNumbers; /// The external top level module during the writing process. Used to /// generate signature for the module file being written. /// /// Only meaningful for standard C++ named modules. See the comments in /// createSignatureForNamedModule() for details. llvm::DenseSet TouchedTopLevelModules; /// An update to a Decl. class DeclUpdate { /// A DeclUpdateKind. unsigned Kind; union { const Decl *Dcl; void *Type; SourceLocation::UIntTy Loc; unsigned Val; Module *Mod; const Attr *Attribute; }; public: DeclUpdate(unsigned Kind) : Kind(Kind), Dcl(nullptr) {} DeclUpdate(unsigned Kind, const Decl *Dcl) : Kind(Kind), Dcl(Dcl) {} DeclUpdate(unsigned Kind, QualType Type) : Kind(Kind), Type(Type.getAsOpaquePtr()) {} DeclUpdate(unsigned Kind, SourceLocation Loc) : Kind(Kind), Loc(Loc.getRawEncoding()) {} DeclUpdate(unsigned Kind, unsigned Val) : Kind(Kind), Val(Val) {} DeclUpdate(unsigned Kind, Module *M) : Kind(Kind), Mod(M) {} DeclUpdate(unsigned Kind, const Attr *Attribute) : Kind(Kind), Attribute(Attribute) {} unsigned getKind() const { return Kind; } const Decl *getDecl() const { return Dcl; } QualType getType() const { return QualType::getFromOpaquePtr(Type); } SourceLocation getLoc() const { return SourceLocation::getFromRawEncoding(Loc); } unsigned getNumber() const { return Val; } Module *getModule() const { return Mod; } const Attr *getAttr() const { return Attribute; } }; using UpdateRecord = SmallVector; using DeclUpdateMap = llvm::MapVector; /// Mapping from declarations that came from a chained PCH to the /// record containing modifications to them. DeclUpdateMap DeclUpdates; /// DeclUpdates added during parsing the GMF. We split these from /// DeclUpdates since we want to add these updates in GMF on need. /// Only meaningful for reduced BMI. DeclUpdateMap DeclUpdatesFromGMF; using FirstLatestDeclMap = llvm::DenseMap; /// Map of first declarations from a chained PCH that point to the /// most recent declarations in another PCH. FirstLatestDeclMap FirstLatestDecls; /// Declarations encountered that might be external /// definitions. /// /// We keep track of external definitions and other 'interesting' declarations /// as we are emitting declarations to the AST file. The AST file contains a /// separate record for these declarations, which are provided to the AST /// consumer by the AST reader. This is behavior is required to properly cope with, /// e.g., tentative variable definitions that occur within /// headers. The declarations themselves are stored as declaration /// IDs, since they will be written out to an EAGERLY_DESERIALIZED_DECLS /// record. RecordData EagerlyDeserializedDecls; RecordData ModularCodegenDecls; /// DeclContexts that have received extensions since their serialized /// form. /// /// For namespaces, when we're chaining and encountering a namespace, we check /// if its primary namespace comes from the chain. If it does, we add the /// primary to this set, so that we can write out lexical content updates for /// it. llvm::SmallSetVector UpdatedDeclContexts; /// Keeps track of declarations that we must emit, even though we're /// not guaranteed to be able to find them by walking the AST starting at the /// translation unit. SmallVector DeclsToEmitEvenIfUnreferenced; /// The set of Objective-C class that have categories we /// should serialize. llvm::SetVector ObjCClassesWithCategories; /// The set of declarations that may have redeclaration chains that /// need to be serialized. llvm::SmallVector Redeclarations; /// A cache of the first local declaration for "interesting" /// redeclaration chains. llvm::DenseMap FirstLocalDeclCache; /// Mapping from SwitchCase statements to IDs. llvm::DenseMap SwitchCaseIDs; /// The number of statements written to the AST file. unsigned NumStatements = 0; /// The number of macros written to the AST file. unsigned NumMacros = 0; /// The number of lexical declcontexts written to the AST /// file. unsigned NumLexicalDeclContexts = 0; /// The number of visible declcontexts written to the AST /// file. unsigned NumVisibleDeclContexts = 0; /// A mapping from each known submodule to its ID number, which will /// be a positive integer. llvm::DenseMap SubmoduleIDs; /// A list of the module file extension writers. std::vector> ModuleFileExtensionWriters; /// Mapping from a source location entry to whether it is affecting or not. llvm::BitVector IsSLocAffecting; /// Mapping from \c FileID to an index into the FileID adjustment table. std::vector NonAffectingFileIDs; std::vector NonAffectingFileIDAdjustments; /// Mapping from an offset to an index into the offset adjustment table. std::vector NonAffectingRanges; std::vector NonAffectingOffsetAdjustments; /// A list of classes in named modules which need to emit the VTable in /// the corresponding object file. llvm::SmallVector PendingEmittingVTables; /// Computes input files that didn't affect compilation of the current module, /// and initializes data structures necessary for leaving those files out /// during \c SourceManager serialization. void computeNonAffectingInputFiles(); /// Some affecting files can be included from files that are not affecting. /// This function erases source locations pointing into such files. SourceLocation getAffectingIncludeLoc(const SourceManager &SourceMgr, const SrcMgr::FileInfo &File); /// Returns an adjusted \c FileID, accounting for any non-affecting input /// files. FileID getAdjustedFileID(FileID FID) const; /// Returns an adjusted number of \c FileIDs created within the specified \c /// FileID, accounting for any non-affecting input files. unsigned getAdjustedNumCreatedFIDs(FileID FID) const; /// Returns an adjusted \c SourceLocation, accounting for any non-affecting /// input files. SourceLocation getAdjustedLocation(SourceLocation Loc) const; /// Returns an adjusted \c SourceRange, accounting for any non-affecting input /// files. SourceRange getAdjustedRange(SourceRange Range) const; /// Returns an adjusted \c SourceLocation offset, accounting for any /// non-affecting input files. SourceLocation::UIntTy getAdjustedOffset(SourceLocation::UIntTy Offset) const; /// Returns an adjustment for offset into SourceManager, accounting for any /// non-affecting input files. SourceLocation::UIntTy getAdjustment(SourceLocation::UIntTy Offset) const; /// Retrieve or create a submodule ID for this module. unsigned getSubmoduleID(Module *Mod); /// Write the given subexpression to the bitstream. void WriteSubStmt(Stmt *S); void WriteBlockInfoBlock(); void WriteControlBlock(Preprocessor &PP, ASTContext &Context, StringRef isysroot); /// Write out the signature and diagnostic options, and return the signature. void writeUnhashedControlBlock(Preprocessor &PP, ASTContext &Context); ASTFileSignature backpatchSignature(); /// Calculate hash of the pcm content. std::pair createSignature() const; ASTFileSignature createSignatureForNamedModule() const; void WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts); void WriteSourceManagerBlock(SourceManager &SourceMgr, const Preprocessor &PP); void WritePreprocessor(const Preprocessor &PP, bool IsModule); void WriteHeaderSearch(const HeaderSearch &HS); void WritePreprocessorDetail(PreprocessingRecord &PPRec, uint64_t MacroOffsetsBase); void WriteSubmodules(Module *WritingModule); void WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, bool isModule); unsigned TypeExtQualAbbrev = 0; void WriteTypeAbbrevs(); void WriteType(QualType T); bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC); void GenerateNameLookupTable(const DeclContext *DC, llvm::SmallVectorImpl &LookupTable); uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, const DeclContext *DC); uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC); void WriteTypeDeclOffsets(); void WriteFileDeclIDsMap(); void WriteComments(); void WriteSelectors(Sema &SemaRef); void WriteReferencedSelectorsPool(Sema &SemaRef); void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver, bool IsModule); void WriteDeclAndTypes(ASTContext &Context); void PrepareWritingSpecialDecls(Sema &SemaRef); void WriteSpecialDeclRecords(Sema &SemaRef); void WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord); void WriteDeclContextVisibleUpdate(const DeclContext *DC); void WriteFPPragmaOptions(const FPOptionsOverride &Opts); void WriteOpenCLExtensions(Sema &SemaRef); void WriteCUDAPragmas(Sema &SemaRef); void WriteObjCCategories(); void WriteLateParsedTemplates(Sema &SemaRef); void WriteOptimizePragmaOptions(Sema &SemaRef); void WriteMSStructPragmaOptions(Sema &SemaRef); void WriteMSPointersToMembersPragmaOptions(Sema &SemaRef); void WritePackPragmaOptions(Sema &SemaRef); void WriteFloatControlPragmaOptions(Sema &SemaRef); void WriteModuleFileExtension(Sema &SemaRef, ModuleFileExtensionWriter &Writer); unsigned DeclParmVarAbbrev = 0; unsigned DeclContextLexicalAbbrev = 0; unsigned DeclContextVisibleLookupAbbrev = 0; unsigned UpdateVisibleAbbrev = 0; unsigned DeclRecordAbbrev = 0; unsigned DeclTypedefAbbrev = 0; unsigned DeclVarAbbrev = 0; unsigned DeclFieldAbbrev = 0; unsigned DeclEnumAbbrev = 0; unsigned DeclObjCIvarAbbrev = 0; unsigned DeclCXXMethodAbbrev = 0; unsigned DeclDependentNonTemplateCXXMethodAbbrev = 0; unsigned DeclTemplateCXXMethodAbbrev = 0; unsigned DeclMemberSpecializedCXXMethodAbbrev = 0; unsigned DeclTemplateSpecializedCXXMethodAbbrev = 0; unsigned DeclDependentSpecializationCXXMethodAbbrev = 0; unsigned DeclTemplateTypeParmAbbrev = 0; unsigned DeclUsingShadowAbbrev = 0; unsigned DeclRefExprAbbrev = 0; unsigned CharacterLiteralAbbrev = 0; unsigned IntegerLiteralAbbrev = 0; unsigned ExprImplicitCastAbbrev = 0; unsigned BinaryOperatorAbbrev = 0; unsigned CompoundAssignOperatorAbbrev = 0; unsigned CallExprAbbrev = 0; unsigned CXXOperatorCallExprAbbrev = 0; unsigned CXXMemberCallExprAbbrev = 0; unsigned CompoundStmtAbbrev = 0; void WriteDeclAbbrevs(); void WriteDecl(ASTContext &Context, Decl *D); ASTFileSignature WriteASTCore(Sema &SemaRef, StringRef isysroot, Module *WritingModule); public: /// Create a new precompiled header writer that outputs to /// the given bitstream. ASTWriter(llvm::BitstreamWriter &Stream, SmallVectorImpl &Buffer, InMemoryModuleCache &ModuleCache, ArrayRef> Extensions, bool IncludeTimestamps = true, bool BuildingImplicitModule = false, bool GeneratingReducedBMI = false); ~ASTWriter() override; ASTContext &getASTContext() const { assert(Context && "requested AST context when not writing AST"); return *Context; } const LangOptions &getLangOpts() const; /// Get a timestamp for output into the AST file. The actual timestamp /// of the specified file may be ignored if we have been instructed to not /// include timestamps in the output file. time_t getTimestampForOutput(const FileEntry *E) const; /// Write a precompiled header for the given semantic analysis. /// /// \param SemaRef a reference to the semantic analysis object that processed /// the AST to be written into the precompiled header. /// /// \param WritingModule The module that we are writing. If null, we are /// writing a precompiled header. /// /// \param isysroot if non-empty, write a relocatable file whose headers /// are relative to the given system root. If we're writing a module, its /// build directory will be used in preference to this if both are available. /// /// \return the module signature, which eventually will be a hash of /// the module but currently is merely a random 32-bit number. ASTFileSignature WriteAST(Sema &SemaRef, StringRef OutputFile, Module *WritingModule, StringRef isysroot, bool ShouldCacheASTInMemory = false); /// Emit a token. void AddToken(const Token &Tok, RecordDataImpl &Record); /// Emit a AlignPackInfo. void AddAlignPackInfo(const Sema::AlignPackInfo &Info, RecordDataImpl &Record); /// Emit a FileID. void AddFileID(FileID FID, RecordDataImpl &Record); /// Emit a source location. void AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record, LocSeq *Seq = nullptr); /// Return the raw encodings for source locations. SourceLocationEncoding::RawLocEncoding getRawSourceLocationEncoding(SourceLocation Loc, LocSeq *Seq = nullptr); /// Emit a source range. void AddSourceRange(SourceRange Range, RecordDataImpl &Record, LocSeq *Seq = nullptr); /// Emit a reference to an identifier. void AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record); /// Get the unique number used to refer to the given selector. serialization::SelectorID getSelectorRef(Selector Sel); /// Get the unique number used to refer to the given identifier. serialization::IdentifierID getIdentifierRef(const IdentifierInfo *II); /// Get the unique number used to refer to the given macro. serialization::MacroID getMacroRef(MacroInfo *MI, const IdentifierInfo *Name); /// Determine the ID of an already-emitted macro. serialization::MacroID getMacroID(MacroInfo *MI); uint32_t getMacroDirectivesOffset(const IdentifierInfo *Name); /// Emit a reference to a type. void AddTypeRef(QualType T, RecordDataImpl &Record); /// Force a type to be emitted and get its ID. serialization::TypeID GetOrCreateTypeID(QualType T); /// Find the first local declaration of a given local redeclarable /// decl. const Decl *getFirstLocalDecl(const Decl *D); /// Is this a local declaration (that is, one that will be written to /// our AST file)? This is the case for declarations that are neither imported /// from another AST file nor predefined. bool IsLocalDecl(const Decl *D) { if (D->isFromASTFile()) return false; auto I = DeclIDs.find(D); return (I == DeclIDs.end() || I->second >= clang::NUM_PREDEF_DECL_IDS); }; /// Emit a reference to a declaration. void AddDeclRef(const Decl *D, RecordDataImpl &Record); // Emit a reference to a declaration if the declaration was emitted. void AddEmittedDeclRef(const Decl *D, RecordDataImpl &Record); /// Force a declaration to be emitted and get its local ID to the module file /// been writing. LocalDeclID GetDeclRef(const Decl *D); /// Determine the local declaration ID of an already-emitted /// declaration. LocalDeclID getDeclID(const Decl *D); /// Whether or not the declaration got emitted. If not, it wouldn't be /// emitted. /// /// This may only be called after we've done the job to write the /// declarations (marked by DoneWritingDeclsAndTypes). /// /// A declaration may only be omitted in reduced BMI. bool wasDeclEmitted(const Decl *D) const; unsigned getAnonymousDeclarationNumber(const NamedDecl *D); /// Add a string to the given record. void AddString(StringRef Str, RecordDataImpl &Record); /// Convert a path from this build process into one that is appropriate /// for emission in the module file. bool PreparePathForOutput(SmallVectorImpl &Path); /// Add a path to the given record. void AddPath(StringRef Path, RecordDataImpl &Record); /// Emit the current record with the given path as a blob. void EmitRecordWithPath(unsigned Abbrev, RecordDataRef Record, StringRef Path); /// Add a version tuple to the given record void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record); /// Retrieve or create a submodule ID for this module, or return 0 if /// the submodule is neither local (a submodle of the currently-written module) /// nor from an imported module. unsigned getLocalOrImportedSubmoduleID(const Module *Mod); /// Note that the identifier II occurs at the given offset /// within the identifier table. void SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset); /// Note that the selector Sel occurs at the given offset /// within the method pool/selector table. void SetSelectorOffset(Selector Sel, uint32_t Offset); /// Record an ID for the given switch-case statement. unsigned RecordSwitchCaseID(SwitchCase *S); /// Retrieve the ID for the given switch-case statement. unsigned getSwitchCaseID(SwitchCase *S); void ClearSwitchCaseIDs(); unsigned getTypeExtQualAbbrev() const { return TypeExtQualAbbrev; } unsigned getDeclParmVarAbbrev() const { return DeclParmVarAbbrev; } unsigned getDeclRecordAbbrev() const { return DeclRecordAbbrev; } unsigned getDeclTypedefAbbrev() const { return DeclTypedefAbbrev; } unsigned getDeclVarAbbrev() const { return DeclVarAbbrev; } unsigned getDeclFieldAbbrev() const { return DeclFieldAbbrev; } unsigned getDeclEnumAbbrev() const { return DeclEnumAbbrev; } unsigned getDeclObjCIvarAbbrev() const { return DeclObjCIvarAbbrev; } unsigned getDeclCXXMethodAbbrev(FunctionDecl::TemplatedKind Kind) const { switch (Kind) { case FunctionDecl::TK_NonTemplate: return DeclCXXMethodAbbrev; case FunctionDecl::TK_FunctionTemplate: return DeclTemplateCXXMethodAbbrev; case FunctionDecl::TK_MemberSpecialization: return DeclMemberSpecializedCXXMethodAbbrev; case FunctionDecl::TK_FunctionTemplateSpecialization: return DeclTemplateSpecializedCXXMethodAbbrev; case FunctionDecl::TK_DependentNonTemplate: return DeclDependentNonTemplateCXXMethodAbbrev; case FunctionDecl::TK_DependentFunctionTemplateSpecialization: return DeclDependentSpecializationCXXMethodAbbrev; } llvm_unreachable("Unknwon Template Kind!"); } unsigned getDeclTemplateTypeParmAbbrev() const { return DeclTemplateTypeParmAbbrev; } unsigned getDeclUsingShadowAbbrev() const { return DeclUsingShadowAbbrev; } unsigned getDeclRefExprAbbrev() const { return DeclRefExprAbbrev; } unsigned getCharacterLiteralAbbrev() const { return CharacterLiteralAbbrev; } unsigned getIntegerLiteralAbbrev() const { return IntegerLiteralAbbrev; } unsigned getExprImplicitCastAbbrev() const { return ExprImplicitCastAbbrev; } unsigned getBinaryOperatorAbbrev() const { return BinaryOperatorAbbrev; } unsigned getCompoundAssignOperatorAbbrev() const { return CompoundAssignOperatorAbbrev; } unsigned getCallExprAbbrev() const { return CallExprAbbrev; } unsigned getCXXOperatorCallExprAbbrev() { return CXXOperatorCallExprAbbrev; } unsigned getCXXMemberCallExprAbbrev() { return CXXMemberCallExprAbbrev; } unsigned getCompoundStmtAbbrev() const { return CompoundStmtAbbrev; } bool hasChain() const { return Chain; } ASTReader *getChain() const { return Chain; } bool isWritingModule() const { return WritingModule; } bool isWritingStdCXXNamedModules() const { return WritingModule && WritingModule->isNamedModule(); } bool isGeneratingReducedBMI() const { return GeneratingReducedBMI; } bool getDoneWritingDeclsAndTypes() const { return DoneWritingDeclsAndTypes; } bool isDeclPredefined(const Decl *D) const { return PredefinedDecls.count(D); } void handleVTable(CXXRecordDecl *RD); private: // ASTDeserializationListener implementation void ReaderInitialized(ASTReader *Reader) override; void IdentifierRead(serialization::IdentifierID ID, IdentifierInfo *II) override; void MacroRead(serialization::MacroID ID, MacroInfo *MI) override; void TypeRead(serialization::TypeIdx Idx, QualType T) override; + void PredefinedDeclBuilt(PredefinedDeclIDs ID, const Decl *D) override; void SelectorRead(serialization::SelectorID ID, Selector Sel) override; void MacroDefinitionRead(serialization::PreprocessedEntityID ID, MacroDefinitionRecord *MD) override; void ModuleRead(serialization::SubmoduleID ID, Module *Mod) override; // ASTMutationListener implementation. void CompletedTagDefinition(const TagDecl *D) override; void AddedVisibleDecl(const DeclContext *DC, const Decl *D) override; void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) override; void AddedCXXTemplateSpecialization( const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) override; void AddedCXXTemplateSpecialization( const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) override; void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, const FunctionDecl *D) override; void ResolvedExceptionSpec(const FunctionDecl *FD) override; void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override; void ResolvedOperatorDelete(const CXXDestructorDecl *DD, const FunctionDecl *Delete, Expr *ThisArg) override; void CompletedImplicitDefinition(const FunctionDecl *D) override; void InstantiationRequested(const ValueDecl *D) override; void VariableDefinitionInstantiated(const VarDecl *D) override; void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void DefaultArgumentInstantiated(const ParmVarDecl *D) override; void DefaultMemberInitializerInstantiated(const FieldDecl *D) override; void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) override; void DeclarationMarkedUsed(const Decl *D) override; void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override; void DeclarationMarkedOpenMPDeclareTarget(const Decl *D, const Attr *Attr) override; void DeclarationMarkedOpenMPAllocate(const Decl *D, const Attr *A) override; void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override; void AddedAttributeToRecord(const Attr *Attr, const RecordDecl *Record) override; void EnteringModulePurview() override; void AddedManglingNumber(const Decl *D, unsigned) override; void AddedStaticLocalNumbers(const Decl *D, unsigned) override; void AddedAnonymousNamespace(const TranslationUnitDecl *, NamespaceDecl *AnonNamespace) override; }; /// AST and semantic-analysis consumer that generates a /// precompiled header from the parsed source code. class PCHGenerator : public SemaConsumer { void anchor() override; Preprocessor &PP; std::string OutputFile; std::string isysroot; Sema *SemaPtr; std::shared_ptr Buffer; llvm::BitstreamWriter Stream; ASTWriter Writer; bool AllowASTWithErrors; bool ShouldCacheASTInMemory; protected: ASTWriter &getWriter() { return Writer; } const ASTWriter &getWriter() const { return Writer; } SmallVectorImpl &getPCH() const { return Buffer->Data; } bool isComplete() const { return Buffer->IsComplete; } PCHBuffer *getBufferPtr() { return Buffer.get(); } StringRef getOutputFile() const { return OutputFile; } DiagnosticsEngine &getDiagnostics() const { return SemaPtr->getDiagnostics(); } Preprocessor &getPreprocessor() { return PP; } virtual Module *getEmittingModule(ASTContext &Ctx); public: PCHGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile, StringRef isysroot, std::shared_ptr Buffer, ArrayRef> Extensions, bool AllowASTWithErrors = false, bool IncludeTimestamps = true, bool BuildingImplicitModule = false, bool ShouldCacheASTInMemory = false, bool GeneratingReducedBMI = false); ~PCHGenerator() override; void InitializeSema(Sema &S) override { SemaPtr = &S; } void HandleTranslationUnit(ASTContext &Ctx) override; void HandleVTable(CXXRecordDecl *RD) override { Writer.handleVTable(RD); } ASTMutationListener *GetASTMutationListener() override; ASTDeserializationListener *GetASTDeserializationListener() override; bool hasEmittedPCH() const { return Buffer->IsComplete; } }; class CXX20ModulesGenerator : public PCHGenerator { void anchor() override; protected: virtual Module *getEmittingModule(ASTContext &Ctx) override; CXX20ModulesGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile, bool GeneratingReducedBMI); public: CXX20ModulesGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile) : CXX20ModulesGenerator(PP, ModuleCache, OutputFile, /*GeneratingReducedBMI=*/false) {} void HandleTranslationUnit(ASTContext &Ctx) override; }; class ReducedBMIGenerator : public CXX20ModulesGenerator { void anchor() override; public: ReducedBMIGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile) : CXX20ModulesGenerator(PP, ModuleCache, OutputFile, /*GeneratingReducedBMI=*/true) {} }; /// If we can elide the definition of \param D in reduced BMI. /// /// Generally, we can elide the definition of a declaration if it won't affect /// the ABI. e.g., the non-inline function bodies. bool CanElideDeclDef(const Decl *D); /// A simple helper class to pack several bits in order into (a) 32 bit /// integer(s). class BitsPacker { constexpr static uint32_t BitIndexUpbound = 32u; public: BitsPacker() = default; BitsPacker(const BitsPacker &) = delete; BitsPacker(BitsPacker &&) = delete; BitsPacker operator=(const BitsPacker &) = delete; BitsPacker operator=(BitsPacker &&) = delete; ~BitsPacker() = default; bool canWriteNextNBits(uint32_t BitsWidth) const { return CurrentBitIndex + BitsWidth < BitIndexUpbound; } void reset(uint32_t Value) { UnderlyingValue = Value; CurrentBitIndex = 0; } void addBit(bool Value) { addBits(Value, 1); } void addBits(uint32_t Value, uint32_t BitsWidth) { assert(BitsWidth < BitIndexUpbound); assert((Value < (1u << BitsWidth)) && "Passing narrower bit width!"); assert(canWriteNextNBits(BitsWidth) && "Inserting too much bits into a value!"); UnderlyingValue |= Value << CurrentBitIndex; CurrentBitIndex += BitsWidth; } operator uint32_t() { return UnderlyingValue; } private: uint32_t UnderlyingValue = 0; uint32_t CurrentBitIndex = 0; }; } // namespace clang #endif // LLVM_CLANG_SERIALIZATION_ASTWRITER_H diff --git a/contrib/llvm-project/clang/lib/Frontend/MultiplexConsumer.cpp b/contrib/llvm-project/clang/lib/Frontend/MultiplexConsumer.cpp index 651c55aeed54..2158d176d189 100644 --- a/contrib/llvm-project/clang/lib/Frontend/MultiplexConsumer.cpp +++ b/contrib/llvm-project/clang/lib/Frontend/MultiplexConsumer.cpp @@ -1,405 +1,410 @@ //===- MultiplexConsumer.cpp - AST Consumer for PCH Generation --*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the MultiplexConsumer class. It also declares and defines // MultiplexASTDeserializationListener and MultiplexASTMutationListener, which // are implementation details of MultiplexConsumer. // //===----------------------------------------------------------------------===// #include "clang/Frontend/MultiplexConsumer.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/DeclGroup.h" using namespace clang; namespace clang { class NamespaceDecl; class TranslationUnitDecl; MultiplexASTDeserializationListener::MultiplexASTDeserializationListener( const std::vector& L) : Listeners(L) { } void MultiplexASTDeserializationListener::ReaderInitialized( ASTReader *Reader) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->ReaderInitialized(Reader); } void MultiplexASTDeserializationListener::IdentifierRead( serialization::IdentifierID ID, IdentifierInfo *II) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->IdentifierRead(ID, II); } void MultiplexASTDeserializationListener::MacroRead( serialization::MacroID ID, MacroInfo *MI) { for (auto &Listener : Listeners) Listener->MacroRead(ID, MI); } void MultiplexASTDeserializationListener::TypeRead( serialization::TypeIdx Idx, QualType T) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->TypeRead(Idx, T); } void MultiplexASTDeserializationListener::DeclRead(GlobalDeclID ID, const Decl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DeclRead(ID, D); } +void MultiplexASTDeserializationListener::PredefinedDeclBuilt(PredefinedDeclIDs ID, const Decl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->PredefinedDeclBuilt(ID, D); +} + void MultiplexASTDeserializationListener::SelectorRead( serialization::SelectorID ID, Selector Sel) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->SelectorRead(ID, Sel); } void MultiplexASTDeserializationListener::MacroDefinitionRead( serialization::PreprocessedEntityID ID, MacroDefinitionRecord *MD) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->MacroDefinitionRead(ID, MD); } void MultiplexASTDeserializationListener::ModuleRead( serialization::SubmoduleID ID, Module *Mod) { for (auto &Listener : Listeners) Listener->ModuleRead(ID, Mod); } void MultiplexASTDeserializationListener::ModuleImportRead( serialization::SubmoduleID ID, SourceLocation ImportLoc) { for (auto &Listener : Listeners) Listener->ModuleImportRead(ID, ImportLoc); } // This ASTMutationListener forwards its notifications to a set of // child listeners. class MultiplexASTMutationListener : public ASTMutationListener { public: // Does NOT take ownership of the elements in L. MultiplexASTMutationListener(ArrayRef L); void CompletedTagDefinition(const TagDecl *D) override; void AddedVisibleDecl(const DeclContext *DC, const Decl *D) override; void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) override; void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) override; void AddedCXXTemplateSpecialization(const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) override; void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, const FunctionDecl *D) override; void ResolvedExceptionSpec(const FunctionDecl *FD) override; void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override; void ResolvedOperatorDelete(const CXXDestructorDecl *DD, const FunctionDecl *Delete, Expr *ThisArg) override; void CompletedImplicitDefinition(const FunctionDecl *D) override; void InstantiationRequested(const ValueDecl *D) override; void VariableDefinitionInstantiated(const VarDecl *D) override; void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void DefaultArgumentInstantiated(const ParmVarDecl *D) override; void DefaultMemberInitializerInstantiated(const FieldDecl *D) override; void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) override; void DeclarationMarkedUsed(const Decl *D) override; void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override; void DeclarationMarkedOpenMPAllocate(const Decl *D, const Attr *A) override; void DeclarationMarkedOpenMPDeclareTarget(const Decl *D, const Attr *Attr) override; void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override; void AddedAttributeToRecord(const Attr *Attr, const RecordDecl *Record) override; void EnteringModulePurview() override; void AddedManglingNumber(const Decl *D, unsigned) override; void AddedStaticLocalNumbers(const Decl *D, unsigned) override; void AddedAnonymousNamespace(const TranslationUnitDecl *, NamespaceDecl *AnonNamespace) override; private: std::vector Listeners; }; MultiplexASTMutationListener::MultiplexASTMutationListener( ArrayRef L) : Listeners(L.begin(), L.end()) { } void MultiplexASTMutationListener::CompletedTagDefinition(const TagDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->CompletedTagDefinition(D); } void MultiplexASTMutationListener::AddedVisibleDecl( const DeclContext *DC, const Decl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->AddedVisibleDecl(DC, D); } void MultiplexASTMutationListener::AddedCXXImplicitMember( const CXXRecordDecl *RD, const Decl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->AddedCXXImplicitMember(RD, D); } void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->AddedCXXTemplateSpecialization(TD, D); } void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->AddedCXXTemplateSpecialization(TD, D); } void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( const FunctionTemplateDecl *TD, const FunctionDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->AddedCXXTemplateSpecialization(TD, D); } void MultiplexASTMutationListener::ResolvedExceptionSpec( const FunctionDecl *FD) { for (auto &Listener : Listeners) Listener->ResolvedExceptionSpec(FD); } void MultiplexASTMutationListener::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DeducedReturnType(FD, ReturnType); } void MultiplexASTMutationListener::ResolvedOperatorDelete( const CXXDestructorDecl *DD, const FunctionDecl *Delete, Expr *ThisArg) { for (auto *L : Listeners) L->ResolvedOperatorDelete(DD, Delete, ThisArg); } void MultiplexASTMutationListener::CompletedImplicitDefinition( const FunctionDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->CompletedImplicitDefinition(D); } void MultiplexASTMutationListener::InstantiationRequested(const ValueDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->InstantiationRequested(D); } void MultiplexASTMutationListener::VariableDefinitionInstantiated( const VarDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->VariableDefinitionInstantiated(D); } void MultiplexASTMutationListener::FunctionDefinitionInstantiated( const FunctionDecl *D) { for (auto &Listener : Listeners) Listener->FunctionDefinitionInstantiated(D); } void MultiplexASTMutationListener::DefaultArgumentInstantiated( const ParmVarDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DefaultArgumentInstantiated(D); } void MultiplexASTMutationListener::DefaultMemberInitializerInstantiated( const FieldDecl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DefaultMemberInitializerInstantiated(D); } void MultiplexASTMutationListener::AddedObjCCategoryToInterface( const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->AddedObjCCategoryToInterface(CatD, IFD); } void MultiplexASTMutationListener::DeclarationMarkedUsed(const Decl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DeclarationMarkedUsed(D); } void MultiplexASTMutationListener::DeclarationMarkedOpenMPThreadPrivate( const Decl *D) { for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D); } void MultiplexASTMutationListener::DeclarationMarkedOpenMPAllocate( const Decl *D, const Attr *A) { for (ASTMutationListener *L : Listeners) L->DeclarationMarkedOpenMPAllocate(D, A); } void MultiplexASTMutationListener::DeclarationMarkedOpenMPDeclareTarget( const Decl *D, const Attr *Attr) { for (auto *L : Listeners) L->DeclarationMarkedOpenMPDeclareTarget(D, Attr); } void MultiplexASTMutationListener::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) { for (auto *L : Listeners) L->RedefinedHiddenDefinition(D, M); } void MultiplexASTMutationListener::AddedAttributeToRecord( const Attr *Attr, const RecordDecl *Record) { for (auto *L : Listeners) L->AddedAttributeToRecord(Attr, Record); } void MultiplexASTMutationListener::EnteringModulePurview() { for (auto *L : Listeners) L->EnteringModulePurview(); } void MultiplexASTMutationListener::AddedManglingNumber(const Decl *D, unsigned Number) { for (auto *L : Listeners) L->AddedManglingNumber(D, Number); } void MultiplexASTMutationListener::AddedStaticLocalNumbers(const Decl *D, unsigned Number) { for (auto *L : Listeners) L->AddedStaticLocalNumbers(D, Number); } void MultiplexASTMutationListener::AddedAnonymousNamespace( const TranslationUnitDecl *TU, NamespaceDecl *AnonNamespace) { for (auto *L : Listeners) L->AddedAnonymousNamespace(TU, AnonNamespace); } } // end namespace clang MultiplexConsumer::MultiplexConsumer( std::vector> C) : Consumers(std::move(C)) { // Collect the mutation listeners and deserialization listeners of all // children, and create a multiplex listener each if so. std::vector mutationListeners; std::vector serializationListeners; for (auto &Consumer : Consumers) { if (auto *mutationListener = Consumer->GetASTMutationListener()) mutationListeners.push_back(mutationListener); if (auto *serializationListener = Consumer->GetASTDeserializationListener()) serializationListeners.push_back(serializationListener); } if (!mutationListeners.empty()) { MutationListener = std::make_unique(mutationListeners); } if (!serializationListeners.empty()) { DeserializationListener = std::make_unique( serializationListeners); } } MultiplexConsumer::~MultiplexConsumer() {} void MultiplexConsumer::Initialize(ASTContext &Context) { for (auto &Consumer : Consumers) Consumer->Initialize(Context); } bool MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) { bool Continue = true; for (auto &Consumer : Consumers) Continue = Continue && Consumer->HandleTopLevelDecl(D); return Continue; } void MultiplexConsumer::HandleInlineFunctionDefinition(FunctionDecl *D) { for (auto &Consumer : Consumers) Consumer->HandleInlineFunctionDefinition(D); } void MultiplexConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) { for (auto &Consumer : Consumers) Consumer->HandleCXXStaticMemberVarInstantiation(VD); } void MultiplexConsumer::HandleInterestingDecl(DeclGroupRef D) { for (auto &Consumer : Consumers) Consumer->HandleInterestingDecl(D); } void MultiplexConsumer::HandleTranslationUnit(ASTContext &Ctx) { for (auto &Consumer : Consumers) Consumer->HandleTranslationUnit(Ctx); } void MultiplexConsumer::HandleTagDeclDefinition(TagDecl *D) { for (auto &Consumer : Consumers) Consumer->HandleTagDeclDefinition(D); } void MultiplexConsumer::HandleTagDeclRequiredDefinition(const TagDecl *D) { for (auto &Consumer : Consumers) Consumer->HandleTagDeclRequiredDefinition(D); } void MultiplexConsumer::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D){ for (auto &Consumer : Consumers) Consumer->HandleCXXImplicitFunctionInstantiation(D); } void MultiplexConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) { for (auto &Consumer : Consumers) Consumer->HandleTopLevelDeclInObjCContainer(D); } void MultiplexConsumer::HandleImplicitImportDecl(ImportDecl *D) { for (auto &Consumer : Consumers) Consumer->HandleImplicitImportDecl(D); } void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) { for (auto &Consumer : Consumers) Consumer->CompleteTentativeDefinition(D); } void MultiplexConsumer::CompleteExternalDeclaration(DeclaratorDecl *D) { for (auto &Consumer : Consumers) Consumer->CompleteExternalDeclaration(D); } void MultiplexConsumer::AssignInheritanceModel(CXXRecordDecl *RD) { for (auto &Consumer : Consumers) Consumer->AssignInheritanceModel(RD); } void MultiplexConsumer::HandleVTable(CXXRecordDecl *RD) { for (auto &Consumer : Consumers) Consumer->HandleVTable(RD); } ASTMutationListener *MultiplexConsumer::GetASTMutationListener() { return MutationListener.get(); } ASTDeserializationListener *MultiplexConsumer::GetASTDeserializationListener() { return DeserializationListener.get(); } void MultiplexConsumer::PrintStats() { for (auto &Consumer : Consumers) Consumer->PrintStats(); } bool MultiplexConsumer::shouldSkipFunctionBody(Decl *D) { bool Skip = true; for (auto &Consumer : Consumers) Skip = Skip && Consumer->shouldSkipFunctionBody(D); return Skip; } void MultiplexConsumer::InitializeSema(Sema &S) { for (auto &Consumer : Consumers) if (SemaConsumer *SC = dyn_cast(Consumer.get())) SC->InitializeSema(S); } void MultiplexConsumer::ForgetSema() { for (auto &Consumer : Consumers) if (SemaConsumer *SC = dyn_cast(Consumer.get())) SC->ForgetSema(); } diff --git a/contrib/llvm-project/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm-project/clang/lib/Serialization/ASTReader.cpp index 29aec144aec1..2d8f5a801f0e 100644 --- a/contrib/llvm-project/clang/lib/Serialization/ASTReader.cpp +++ b/contrib/llvm-project/clang/lib/Serialization/ASTReader.cpp @@ -1,12071 +1,12126 @@ //===- ASTReader.cpp - AST File Reader ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the ASTReader class, which reads AST files. // //===----------------------------------------------------------------------===// #include "ASTCommon.h" #include "ASTReaderInternals.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/ASTStructuralEquivalence.h" #include "clang/AST/ASTUnresolvedSet.h" #include "clang/AST/AbstractTypeReader.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclGroup.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/ODRDiagsEmitter.h" #include "clang/AST/OpenACCClause.h" #include "clang/AST/OpenMPClause.h" #include "clang/AST/RawCommentList.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/ASTSourceDescriptor.h" #include "clang/Basic/CommentOptions.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticError.h" #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/PragmaKinds.h" #include "clang/Basic/Sanitizers.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TokenKinds.h" #include "clang/Basic/Version.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/ModuleMap.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/Token.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Scope.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/Weak.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ASTDeserializationListener.h" #include "clang/Serialization/ASTRecordReader.h" #include "clang/Serialization/ContinuousRangeMap.h" #include "clang/Serialization/GlobalModuleIndex.h" #include "clang/Serialization/InMemoryModuleCache.h" #include "clang/Serialization/ModuleFile.h" #include "clang/Serialization/ModuleFileExtension.h" #include "clang/Serialization/ModuleManager.h" #include "clang/Serialization/PCHContainerOperations.h" #include "clang/Serialization/SerializationDiagnostic.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FloatingPointMode.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" #include "llvm/Support/DJB.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/Timer.h" #include "llvm/Support/VersionTuple.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Triple.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace clang; using namespace clang::serialization; using namespace clang::serialization::reader; using llvm::BitstreamCursor; //===----------------------------------------------------------------------===// // ChainedASTReaderListener implementation //===----------------------------------------------------------------------===// bool ChainedASTReaderListener::ReadFullVersionInformation(StringRef FullVersion) { return First->ReadFullVersionInformation(FullVersion) || Second->ReadFullVersionInformation(FullVersion); } void ChainedASTReaderListener::ReadModuleName(StringRef ModuleName) { First->ReadModuleName(ModuleName); Second->ReadModuleName(ModuleName); } void ChainedASTReaderListener::ReadModuleMapFile(StringRef ModuleMapPath) { First->ReadModuleMapFile(ModuleMapPath); Second->ReadModuleMapFile(ModuleMapPath); } bool ChainedASTReaderListener::ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) { return First->ReadLanguageOptions(LangOpts, Complain, AllowCompatibleDifferences) || Second->ReadLanguageOptions(LangOpts, Complain, AllowCompatibleDifferences); } bool ChainedASTReaderListener::ReadTargetOptions( const TargetOptions &TargetOpts, bool Complain, bool AllowCompatibleDifferences) { return First->ReadTargetOptions(TargetOpts, Complain, AllowCompatibleDifferences) || Second->ReadTargetOptions(TargetOpts, Complain, AllowCompatibleDifferences); } bool ChainedASTReaderListener::ReadDiagnosticOptions( IntrusiveRefCntPtr DiagOpts, bool Complain) { return First->ReadDiagnosticOptions(DiagOpts, Complain) || Second->ReadDiagnosticOptions(DiagOpts, Complain); } bool ChainedASTReaderListener::ReadFileSystemOptions(const FileSystemOptions &FSOpts, bool Complain) { return First->ReadFileSystemOptions(FSOpts, Complain) || Second->ReadFileSystemOptions(FSOpts, Complain); } bool ChainedASTReaderListener::ReadHeaderSearchOptions( const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) { return First->ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath, Complain) || Second->ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath, Complain); } bool ChainedASTReaderListener::ReadPreprocessorOptions( const PreprocessorOptions &PPOpts, bool ReadMacros, bool Complain, std::string &SuggestedPredefines) { return First->ReadPreprocessorOptions(PPOpts, ReadMacros, Complain, SuggestedPredefines) || Second->ReadPreprocessorOptions(PPOpts, ReadMacros, Complain, SuggestedPredefines); } void ChainedASTReaderListener::ReadCounter(const serialization::ModuleFile &M, unsigned Value) { First->ReadCounter(M, Value); Second->ReadCounter(M, Value); } bool ChainedASTReaderListener::needsInputFileVisitation() { return First->needsInputFileVisitation() || Second->needsInputFileVisitation(); } bool ChainedASTReaderListener::needsSystemInputFileVisitation() { return First->needsSystemInputFileVisitation() || Second->needsSystemInputFileVisitation(); } void ChainedASTReaderListener::visitModuleFile(StringRef Filename, ModuleKind Kind) { First->visitModuleFile(Filename, Kind); Second->visitModuleFile(Filename, Kind); } bool ChainedASTReaderListener::visitInputFile(StringRef Filename, bool isSystem, bool isOverridden, bool isExplicitModule) { bool Continue = false; if (First->needsInputFileVisitation() && (!isSystem || First->needsSystemInputFileVisitation())) Continue |= First->visitInputFile(Filename, isSystem, isOverridden, isExplicitModule); if (Second->needsInputFileVisitation() && (!isSystem || Second->needsSystemInputFileVisitation())) Continue |= Second->visitInputFile(Filename, isSystem, isOverridden, isExplicitModule); return Continue; } void ChainedASTReaderListener::readModuleFileExtension( const ModuleFileExtensionMetadata &Metadata) { First->readModuleFileExtension(Metadata); Second->readModuleFileExtension(Metadata); } //===----------------------------------------------------------------------===// // PCH validator implementation //===----------------------------------------------------------------------===// ASTReaderListener::~ASTReaderListener() = default; /// Compare the given set of language options against an existing set of /// language options. /// /// \param Diags If non-NULL, diagnostics will be emitted via this engine. /// \param AllowCompatibleDifferences If true, differences between compatible /// language options will be permitted. /// /// \returns true if the languagae options mis-match, false otherwise. static bool checkLanguageOptions(const LangOptions &LangOpts, const LangOptions &ExistingLangOpts, DiagnosticsEngine *Diags, bool AllowCompatibleDifferences = true) { #define LANGOPT(Name, Bits, Default, Description) \ if (ExistingLangOpts.Name != LangOpts.Name) { \ if (Diags) { \ if (Bits == 1) \ Diags->Report(diag::err_pch_langopt_mismatch) \ << Description << LangOpts.Name << ExistingLangOpts.Name; \ else \ Diags->Report(diag::err_pch_langopt_value_mismatch) \ << Description; \ } \ return true; \ } #define VALUE_LANGOPT(Name, Bits, Default, Description) \ if (ExistingLangOpts.Name != LangOpts.Name) { \ if (Diags) \ Diags->Report(diag::err_pch_langopt_value_mismatch) \ << Description; \ return true; \ } #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \ if (Diags) \ Diags->Report(diag::err_pch_langopt_value_mismatch) \ << Description; \ return true; \ } #define COMPATIBLE_LANGOPT(Name, Bits, Default, Description) \ if (!AllowCompatibleDifferences) \ LANGOPT(Name, Bits, Default, Description) #define COMPATIBLE_ENUM_LANGOPT(Name, Bits, Default, Description) \ if (!AllowCompatibleDifferences) \ ENUM_LANGOPT(Name, Bits, Default, Description) #define COMPATIBLE_VALUE_LANGOPT(Name, Bits, Default, Description) \ if (!AllowCompatibleDifferences) \ VALUE_LANGOPT(Name, Bits, Default, Description) #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #define BENIGN_VALUE_LANGOPT(Name, Bits, Default, Description) #include "clang/Basic/LangOptions.def" if (ExistingLangOpts.ModuleFeatures != LangOpts.ModuleFeatures) { if (Diags) Diags->Report(diag::err_pch_langopt_value_mismatch) << "module features"; return true; } if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) { if (Diags) Diags->Report(diag::err_pch_langopt_value_mismatch) << "target Objective-C runtime"; return true; } if (ExistingLangOpts.CommentOpts.BlockCommandNames != LangOpts.CommentOpts.BlockCommandNames) { if (Diags) Diags->Report(diag::err_pch_langopt_value_mismatch) << "block command names"; 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; } /// Compare the given set of target options against an existing set of /// target options. /// /// \param Diags If non-NULL, diagnostics will be emitted via this engine. /// /// \returns true if the target options mis-match, false otherwise. static bool checkTargetOptions(const TargetOptions &TargetOpts, const TargetOptions &ExistingTargetOpts, DiagnosticsEngine *Diags, bool AllowCompatibleDifferences = true) { #define CHECK_TARGET_OPT(Field, Name) \ if (TargetOpts.Field != ExistingTargetOpts.Field) { \ if (Diags) \ Diags->Report(diag::err_pch_targetopt_mismatch) \ << Name << TargetOpts.Field << ExistingTargetOpts.Field; \ return true; \ } // The triple and ABI must match exactly. CHECK_TARGET_OPT(Triple, "target"); CHECK_TARGET_OPT(ABI, "target ABI"); // We can tolerate different CPUs in many cases, notably when one CPU // supports a strict superset of another. When allowing compatible // differences skip this check. if (!AllowCompatibleDifferences) { CHECK_TARGET_OPT(CPU, "target CPU"); CHECK_TARGET_OPT(TuneCPU, "tune CPU"); } #undef CHECK_TARGET_OPT // Compare feature sets. SmallVector ExistingFeatures( ExistingTargetOpts.FeaturesAsWritten.begin(), ExistingTargetOpts.FeaturesAsWritten.end()); SmallVector ReadFeatures(TargetOpts.FeaturesAsWritten.begin(), TargetOpts.FeaturesAsWritten.end()); llvm::sort(ExistingFeatures); llvm::sort(ReadFeatures); // We compute the set difference in both directions explicitly so that we can // diagnose the differences differently. SmallVector UnmatchedExistingFeatures, UnmatchedReadFeatures; std::set_difference( ExistingFeatures.begin(), ExistingFeatures.end(), ReadFeatures.begin(), ReadFeatures.end(), std::back_inserter(UnmatchedExistingFeatures)); std::set_difference(ReadFeatures.begin(), ReadFeatures.end(), ExistingFeatures.begin(), ExistingFeatures.end(), std::back_inserter(UnmatchedReadFeatures)); // If we are allowing compatible differences and the read feature set is // a strict subset of the existing feature set, there is nothing to diagnose. if (AllowCompatibleDifferences && UnmatchedReadFeatures.empty()) return false; if (Diags) { for (StringRef Feature : UnmatchedReadFeatures) Diags->Report(diag::err_pch_targetopt_feature_mismatch) << /* is-existing-feature */ false << Feature; for (StringRef Feature : UnmatchedExistingFeatures) Diags->Report(diag::err_pch_targetopt_feature_mismatch) << /* is-existing-feature */ true << Feature; } return !UnmatchedReadFeatures.empty() || !UnmatchedExistingFeatures.empty(); } bool PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) { const LangOptions &ExistingLangOpts = PP.getLangOpts(); return checkLanguageOptions(LangOpts, ExistingLangOpts, Complain ? &Reader.Diags : nullptr, AllowCompatibleDifferences); } bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, bool AllowCompatibleDifferences) { const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts(); return checkTargetOptions(TargetOpts, ExistingTargetOpts, Complain ? &Reader.Diags : nullptr, AllowCompatibleDifferences); } namespace { using MacroDefinitionsMap = llvm::StringMap>; using DeclsMap = llvm::DenseMap>; } // namespace static bool checkDiagnosticGroupMappings(DiagnosticsEngine &StoredDiags, DiagnosticsEngine &Diags, bool Complain) { using Level = DiagnosticsEngine::Level; // Check current mappings for new -Werror mappings, and the stored mappings // for cases that were explicitly mapped to *not* be errors that are now // errors because of options like -Werror. DiagnosticsEngine *MappingSources[] = { &Diags, &StoredDiags }; for (DiagnosticsEngine *MappingSource : MappingSources) { for (auto DiagIDMappingPair : MappingSource->getDiagnosticMappings()) { diag::kind DiagID = DiagIDMappingPair.first; Level CurLevel = Diags.getDiagnosticLevel(DiagID, SourceLocation()); if (CurLevel < DiagnosticsEngine::Error) continue; // not significant Level StoredLevel = StoredDiags.getDiagnosticLevel(DiagID, SourceLocation()); if (StoredLevel < DiagnosticsEngine::Error) { if (Complain) Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror=" + Diags.getDiagnosticIDs()->getWarningOptionForDiag(DiagID).str(); return true; } } } return false; } static bool isExtHandlingFromDiagsError(DiagnosticsEngine &Diags) { diag::Severity Ext = Diags.getExtensionHandlingBehavior(); if (Ext == diag::Severity::Warning && Diags.getWarningsAsErrors()) return true; return Ext >= diag::Severity::Error; } static bool checkDiagnosticMappings(DiagnosticsEngine &StoredDiags, DiagnosticsEngine &Diags, bool IsSystem, bool SystemHeaderWarningsInModule, bool Complain) { // Top-level options if (IsSystem) { if (Diags.getSuppressSystemWarnings()) return false; // If -Wsystem-headers was not enabled before, and it was not explicit, // be conservative if (StoredDiags.getSuppressSystemWarnings() && !SystemHeaderWarningsInModule) { if (Complain) Diags.Report(diag::err_pch_diagopt_mismatch) << "-Wsystem-headers"; return true; } } if (Diags.getWarningsAsErrors() && !StoredDiags.getWarningsAsErrors()) { if (Complain) Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror"; return true; } if (Diags.getWarningsAsErrors() && Diags.getEnableAllWarnings() && !StoredDiags.getEnableAllWarnings()) { if (Complain) Diags.Report(diag::err_pch_diagopt_mismatch) << "-Weverything -Werror"; return true; } if (isExtHandlingFromDiagsError(Diags) && !isExtHandlingFromDiagsError(StoredDiags)) { if (Complain) Diags.Report(diag::err_pch_diagopt_mismatch) << "-pedantic-errors"; return true; } return checkDiagnosticGroupMappings(StoredDiags, Diags, Complain); } /// 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 // module import of an implicitly-loaded module file. // 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(); while (!TopImport->ImportedBy.empty()) TopImport = TopImport->ImportedBy[0]; if (TopImport->Kind != MK_ImplicitModule) return nullptr; StringRef ModuleName = TopImport->ModuleName; assert(!ModuleName.empty() && "diagnostic options read before module name"); Module *M = PP.getHeaderSearchInfo().lookupModule(ModuleName, TopImport->ImportLoc); assert(M && "missing module"); return M; } bool PCHValidator::ReadDiagnosticOptions( IntrusiveRefCntPtr DiagOpts, bool Complain) { DiagnosticsEngine &ExistingDiags = PP.getDiagnostics(); IntrusiveRefCntPtr DiagIDs(ExistingDiags.getDiagnosticIDs()); IntrusiveRefCntPtr 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; Module *Importer = PP.getCurrentModule(); DiagnosticOptions &ExistingOpts = ExistingDiags.getDiagnosticOptions(); bool SystemHeaderWarningsInModule = Importer && llvm::is_contained(ExistingOpts.SystemHeaderWarningsModules, Importer->Name); // FIXME: if the diagnostics are incompatible, save a DiagnosticOptions that // contains the union of their flags. return checkDiagnosticMappings(*Diags, ExistingDiags, TopM->IsSystem, SystemHeaderWarningsInModule, Complain); } /// Collect the macro definitions provided by the given preprocessor /// options. static void collectMacroDefinitions(const PreprocessorOptions &PPOpts, MacroDefinitionsMap &Macros, SmallVectorImpl *MacroNames = nullptr) { for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) { StringRef Macro = PPOpts.Macros[I].first; bool IsUndef = PPOpts.Macros[I].second; std::pair MacroPair = Macro.split('='); StringRef MacroName = MacroPair.first; StringRef MacroBody = MacroPair.second; // For an #undef'd macro, we only care about the name. if (IsUndef) { if (MacroNames && !Macros.count(MacroName)) MacroNames->push_back(MacroName); Macros[MacroName] = std::make_pair("", true); continue; } // For a #define'd macro, figure out the actual definition. if (MacroName.size() == Macro.size()) MacroBody = "1"; else { // Note: GCC drops anything following an end-of-line character. StringRef::size_type End = MacroBody.find_first_of("\n\r"); MacroBody = MacroBody.substr(0, End); } if (MacroNames && !Macros.count(MacroName)) MacroNames->push_back(MacroName); Macros[MacroName] = std::make_pair(MacroBody, false); } } enum OptionValidation { OptionValidateNone, OptionValidateContradictions, OptionValidateStrictMatches, }; /// Check the preprocessor options deserialized from the control block /// against the preprocessor options in an existing preprocessor. /// /// \param Diags If non-null, produce diagnostics for any mismatches incurred. /// \param Validation If set to OptionValidateNone, ignore differences in /// preprocessor options. If set to OptionValidateContradictions, /// require that options passed both in the AST file and on the command /// line (-D or -U) match, but tolerate options missing in one or the /// other. If set to OptionValidateContradictions, require that there /// are no differences in the options between the two. static bool checkPreprocessorOptions( const PreprocessorOptions &PPOpts, const PreprocessorOptions &ExistingPPOpts, bool ReadMacros, DiagnosticsEngine *Diags, FileManager &FileMgr, std::string &SuggestedPredefines, const LangOptions &LangOpts, OptionValidation Validation = OptionValidateContradictions) { if (ReadMacros) { // Check macro definitions. MacroDefinitionsMap ASTFileMacros; collectMacroDefinitions(PPOpts, ASTFileMacros); MacroDefinitionsMap ExistingMacros; SmallVector ExistingMacroNames; collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames); // Use a line marker to enter the file, as the defines and // undefines here will have come from the command line. SuggestedPredefines += "# 1 \"\" 1\n"; for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) { // Dig out the macro definition in the existing preprocessor options. StringRef MacroName = ExistingMacroNames[I]; std::pair Existing = ExistingMacros[MacroName]; // Check whether we know anything about this macro name or not. llvm::StringMap>::iterator Known = ASTFileMacros.find(MacroName); if (Validation == OptionValidateNone || Known == ASTFileMacros.end()) { if (Validation == OptionValidateStrictMatches) { // If strict matches are requested, don't tolerate any extra defines // on the command line that are missing in the AST file. if (Diags) { Diags->Report(diag::err_pch_macro_def_undef) << MacroName << true; } return true; } // FIXME: Check whether this identifier was referenced anywhere in the // AST file. If so, we should reject the AST file. Unfortunately, this // information isn't in the control block. What shall we do about it? if (Existing.second) { SuggestedPredefines += "#undef "; SuggestedPredefines += MacroName.str(); SuggestedPredefines += '\n'; } else { SuggestedPredefines += "#define "; SuggestedPredefines += MacroName.str(); SuggestedPredefines += ' '; SuggestedPredefines += Existing.first.str(); SuggestedPredefines += '\n'; } continue; } // If the macro was defined in one but undef'd in the other, we have a // conflict. if (Existing.second != Known->second.second) { if (Diags) { Diags->Report(diag::err_pch_macro_def_undef) << MacroName << Known->second.second; } return true; } // If the macro was #undef'd in both, or if the macro bodies are // identical, it's fine. if (Existing.second || Existing.first == Known->second.first) { ASTFileMacros.erase(Known); continue; } // The macro bodies differ; complain. if (Diags) { Diags->Report(diag::err_pch_macro_def_conflict) << MacroName << Known->second.first << Existing.first; } return true; } // Leave the file and return to . SuggestedPredefines += "# 1 \"\" 2\n"; if (Validation == OptionValidateStrictMatches) { // If strict matches are requested, don't tolerate any extra defines in // the AST file that are missing on the command line. for (const auto &MacroName : ASTFileMacros.keys()) { if (Diags) { Diags->Report(diag::err_pch_macro_def_undef) << MacroName << false; } return true; } } } // Check whether we're using predefines. if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines && Validation != OptionValidateNone) { if (Diags) { Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines; } return true; } // Detailed record is important since it is used for the module cache hash. if (LangOpts.Modules && PPOpts.DetailedRecord != ExistingPPOpts.DetailedRecord && Validation != OptionValidateNone) { if (Diags) { Diags->Report(diag::err_pch_pp_detailed_record) << PPOpts.DetailedRecord; } return true; } // Compute the #include and #include_macros lines we need. for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) { StringRef File = ExistingPPOpts.Includes[I]; if (!ExistingPPOpts.ImplicitPCHInclude.empty() && !ExistingPPOpts.PCHThroughHeader.empty()) { // In case the through header is an include, we must add all the includes // to the predefines so the start point can be determined. SuggestedPredefines += "#include \""; SuggestedPredefines += File; SuggestedPredefines += "\"\n"; continue; } if (File == ExistingPPOpts.ImplicitPCHInclude) continue; if (llvm::is_contained(PPOpts.Includes, File)) continue; SuggestedPredefines += "#include \""; SuggestedPredefines += File; SuggestedPredefines += "\"\n"; } for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) { StringRef File = ExistingPPOpts.MacroIncludes[I]; if (llvm::is_contained(PPOpts.MacroIncludes, File)) continue; SuggestedPredefines += "#__include_macros \""; SuggestedPredefines += File; SuggestedPredefines += "\"\n##\n"; } return false; } bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool ReadMacros, bool Complain, std::string &SuggestedPredefines) { const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts(); return checkPreprocessorOptions( PPOpts, ExistingPPOpts, ReadMacros, Complain ? &Reader.Diags : nullptr, PP.getFileManager(), SuggestedPredefines, PP.getLangOpts()); } bool SimpleASTReaderListener::ReadPreprocessorOptions( const PreprocessorOptions &PPOpts, bool ReadMacros, bool Complain, std::string &SuggestedPredefines) { return checkPreprocessorOptions(PPOpts, PP.getPreprocessorOpts(), ReadMacros, nullptr, PP.getFileManager(), SuggestedPredefines, PP.getLangOpts(), OptionValidateNone); } /// Check that the specified and the existing module cache paths are equivalent. /// /// \param Diags If non-null, produce diagnostics for any mismatches incurred. /// \returns true when the module cache paths differ. static bool checkModuleCachePath(llvm::vfs::FileSystem &VFS, StringRef SpecificModuleCachePath, StringRef ExistingModuleCachePath, DiagnosticsEngine *Diags, const LangOptions &LangOpts, const PreprocessorOptions &PPOpts) { if (!LangOpts.Modules || PPOpts.AllowPCHWithDifferentModulesCachePath || SpecificModuleCachePath == ExistingModuleCachePath) return false; auto EqualOrErr = VFS.equivalent(SpecificModuleCachePath, ExistingModuleCachePath); if (EqualOrErr && *EqualOrErr) return false; if (Diags) Diags->Report(diag::err_pch_modulecache_mismatch) << SpecificModuleCachePath << ExistingModuleCachePath; return true; } bool PCHValidator::ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) { return checkModuleCachePath(Reader.getFileManager().getVirtualFileSystem(), SpecificModuleCachePath, PP.getHeaderSearchInfo().getModuleCachePath(), Complain ? &Reader.Diags : nullptr, PP.getLangOpts(), PP.getPreprocessorOpts()); } void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) { PP.setCounterValue(Value); } //===----------------------------------------------------------------------===// // AST reader implementation //===----------------------------------------------------------------------===// static uint64_t readULEB(const unsigned char *&P) { unsigned Length = 0; const char *Error = nullptr; uint64_t Val = llvm::decodeULEB128(P, &Length, nullptr, &Error); if (Error) llvm::report_fatal_error(Error); P += Length; return Val; } /// Read ULEB-encoded key length and data length. static std::pair readULEBKeyDataLength(const unsigned char *&P) { unsigned KeyLen = readULEB(P); if ((unsigned)KeyLen != KeyLen) llvm::report_fatal_error("key too large"); unsigned DataLen = readULEB(P); if ((unsigned)DataLen != DataLen) llvm::report_fatal_error("data too large"); return std::make_pair(KeyLen, DataLen); } void ASTReader::setDeserializationListener(ASTDeserializationListener *Listener, bool TakeOwnership) { DeserializationListener = Listener; OwnsDeserializationListener = TakeOwnership; } unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) { return serialization::ComputeHash(Sel); } LocalDeclID LocalDeclID::get(ASTReader &Reader, ModuleFile &MF, DeclID Value) { LocalDeclID ID(Value); #ifndef NDEBUG if (!MF.ModuleOffsetMap.empty()) Reader.ReadModuleOffsetMap(MF); unsigned ModuleFileIndex = ID.getModuleFileIndex(); unsigned LocalDeclID = ID.getLocalDeclIndex(); assert(ModuleFileIndex <= MF.TransitiveImports.size()); ModuleFile *OwningModuleFile = ModuleFileIndex == 0 ? &MF : MF.TransitiveImports[ModuleFileIndex - 1]; assert(OwningModuleFile); unsigned LocalNumDecls = OwningModuleFile->LocalNumDecls; if (!ModuleFileIndex) LocalNumDecls += NUM_PREDEF_DECL_IDS; assert(LocalDeclID < LocalNumDecls); #endif (void)Reader; (void)MF; return ID; } LocalDeclID LocalDeclID::get(ASTReader &Reader, ModuleFile &MF, unsigned ModuleFileIndex, unsigned LocalDeclID) { DeclID Value = (DeclID)ModuleFileIndex << 32 | (DeclID)LocalDeclID; return LocalDeclID::get(Reader, MF, Value); } std::pair ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) { return readULEBKeyDataLength(d); } ASTSelectorLookupTrait::internal_key_type ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) { using namespace llvm::support; SelectorTable &SelTable = Reader.getContext().Selectors; unsigned N = endian::readNext(d); const IdentifierInfo *FirstII = Reader.getLocalIdentifier( F, endian::readNext(d)); if (N == 0) return SelTable.getNullarySelector(FirstII); else if (N == 1) return SelTable.getUnarySelector(FirstII); SmallVector Args; Args.push_back(FirstII); for (unsigned I = 1; I != N; ++I) Args.push_back(Reader.getLocalIdentifier( F, endian::readNext(d))); return SelTable.getSelector(N, Args.data()); } ASTSelectorLookupTrait::data_type ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d, unsigned DataLen) { using namespace llvm::support; data_type Result; Result.ID = Reader.getGlobalSelectorID( F, endian::readNext(d)); unsigned FullInstanceBits = endian::readNext(d); unsigned FullFactoryBits = endian::readNext(d); Result.InstanceBits = FullInstanceBits & 0x3; Result.InstanceHasMoreThanOneDecl = (FullInstanceBits >> 2) & 0x1; Result.FactoryBits = FullFactoryBits & 0x3; Result.FactoryHasMoreThanOneDecl = (FullFactoryBits >> 2) & 0x1; unsigned NumInstanceMethods = FullInstanceBits >> 3; unsigned NumFactoryMethods = FullFactoryBits >> 3; // Load instance methods for (unsigned I = 0; I != NumInstanceMethods; ++I) { if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs( F, LocalDeclID::get( Reader, F, endian::readNext(d)))) Result.Instance.push_back(Method); } // Load factory methods for (unsigned I = 0; I != NumFactoryMethods; ++I) { if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs( F, LocalDeclID::get( Reader, F, endian::readNext(d)))) Result.Factory.push_back(Method); } return Result; } unsigned ASTIdentifierLookupTraitBase::ComputeHash(const internal_key_type& a) { return llvm::djbHash(a); } std::pair ASTIdentifierLookupTraitBase::ReadKeyDataLength(const unsigned char*& d) { return readULEBKeyDataLength(d); } ASTIdentifierLookupTraitBase::internal_key_type ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) { assert(n >= 2 && d[n-1] == '\0'); return StringRef((const char*) d, n-1); } /// Whether the given identifier is "interesting". static bool isInterestingIdentifier(ASTReader &Reader, const IdentifierInfo &II, bool IsModule) { bool IsInteresting = II.getNotableIdentifierID() != tok::NotableIdentifierKind::not_notable || II.getBuiltinID() != Builtin::ID::NotBuiltin || II.getObjCKeywordID() != tok::ObjCKeywordKind::objc_not_keyword; return II.hadMacroDefinition() || II.isPoisoned() || (!IsModule && IsInteresting) || II.hasRevertedTokenIDToIdentifier() || (!(IsModule && Reader.getPreprocessor().getLangOpts().CPlusPlus) && II.getFETokenInfo()); } static bool readBit(unsigned &Bits) { bool Value = Bits & 0x1; Bits >>= 1; return Value; } IdentifierID ASTIdentifierLookupTrait::ReadIdentifierID(const unsigned char *d) { using namespace llvm::support; IdentifierID RawID = endian::readNext(d); return Reader.getGlobalIdentifierID(F, RawID >> 1); } static void markIdentifierFromAST(ASTReader &Reader, IdentifierInfo &II) { if (!II.isFromAST()) { II.setIsFromAST(); bool IsModule = Reader.getPreprocessor().getCurrentModule() != nullptr; if (isInterestingIdentifier(Reader, II, IsModule)) II.setChangedSinceDeserialization(); } } IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, const unsigned char* d, unsigned DataLen) { using namespace llvm::support; IdentifierID RawID = endian::readNext(d); bool IsInteresting = RawID & 0x01; DataLen -= sizeof(IdentifierID); // Wipe out the "is interesting" bit. RawID = RawID >> 1; // Build the IdentifierInfo and link the identifier ID with it. IdentifierInfo *II = KnownII; if (!II) { II = &Reader.getIdentifierTable().getOwn(k); KnownII = II; } markIdentifierFromAST(Reader, *II); Reader.markIdentifierUpToDate(II); IdentifierID ID = Reader.getGlobalIdentifierID(F, RawID); if (!IsInteresting) { // For uninteresting identifiers, there's nothing else to do. Just notify // the reader that we've finished loading this identifier. Reader.SetIdentifierInfo(ID, II); return II; } unsigned ObjCOrBuiltinID = endian::readNext(d); unsigned Bits = endian::readNext(d); bool CPlusPlusOperatorKeyword = readBit(Bits); bool HasRevertedTokenIDToIdentifier = readBit(Bits); bool Poisoned = readBit(Bits); bool ExtensionToken = readBit(Bits); bool HadMacroDefinition = readBit(Bits); assert(Bits == 0 && "Extra bits in the identifier?"); DataLen -= sizeof(uint16_t) * 2; // Set or check the various bits in the IdentifierInfo structure. // Token IDs are read-only. if (HasRevertedTokenIDToIdentifier && II->getTokenID() != tok::identifier) II->revertTokenIDToIdentifier(); if (!F.isModule()) II->setObjCOrBuiltinID(ObjCOrBuiltinID); assert(II->isExtensionToken() == ExtensionToken && "Incorrect extension token flag"); (void)ExtensionToken; if (Poisoned) II->setIsPoisoned(true); assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword && "Incorrect C++ operator keyword flag"); (void)CPlusPlusOperatorKeyword; // If this identifier is a macro, deserialize the macro // definition. if (HadMacroDefinition) { uint32_t MacroDirectivesOffset = endian::readNext(d); DataLen -= 4; Reader.addPendingMacro(II, &F, MacroDirectivesOffset); } Reader.SetIdentifierInfo(ID, II); // Read all of the declarations visible at global scope with this // name. if (DataLen > 0) { SmallVector DeclIDs; for (; DataLen > 0; DataLen -= sizeof(DeclID)) DeclIDs.push_back(Reader.getGlobalDeclID( F, LocalDeclID::get( Reader, F, endian::readNext(d)))); Reader.SetGloballyVisibleDecls(II, DeclIDs); } return II; } DeclarationNameKey::DeclarationNameKey(DeclarationName Name) : Kind(Name.getNameKind()) { switch (Kind) { case DeclarationName::Identifier: Data = (uint64_t)Name.getAsIdentifierInfo(); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); break; case DeclarationName::CXXOperatorName: Data = Name.getCXXOverloadedOperator(); break; 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: case DeclarationName::CXXUsingDirective: Data = 0; break; } } unsigned DeclarationNameKey::getHash() const { llvm::FoldingSetNodeID ID; ID.AddInteger(Kind); switch (Kind) { case DeclarationName::Identifier: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXDeductionGuideName: ID.AddString(((IdentifierInfo*)Data)->getName()); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: ID.AddInteger(serialization::ComputeHash(Selector(Data))); break; case DeclarationName::CXXOperatorName: ID.AddInteger((OverloadedOperatorKind)Data); break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: break; } return ID.computeStableHash(); } ModuleFile * ASTDeclContextNameLookupTrait::ReadFileRef(const unsigned char *&d) { using namespace llvm::support; uint32_t ModuleFileID = endian::readNext(d); return Reader.getLocalModuleFile(F, ModuleFileID); } std::pair ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char *&d) { return readULEBKeyDataLength(d); } ASTDeclContextNameLookupTrait::internal_key_type ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) { using namespace llvm::support; auto Kind = (DeclarationName::NameKind)*d++; uint64_t Data; switch (Kind) { case DeclarationName::Identifier: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXDeductionGuideName: Data = (uint64_t)Reader.getLocalIdentifier( F, endian::readNext(d)); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: Data = (uint64_t)Reader .getLocalSelector( F, endian::readNext(d)) .getAsOpaquePtr(); break; case DeclarationName::CXXOperatorName: Data = *d++; // OverloadedOperatorKind break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: Data = 0; break; } return DeclarationNameKey(Kind, Data); } void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type, const unsigned char *d, unsigned DataLen, data_type_builder &Val) { using namespace llvm::support; for (unsigned NumDecls = DataLen / sizeof(DeclID); NumDecls; --NumDecls) { LocalDeclID ID = LocalDeclID::get( Reader, F, endian::readNext(d)); Val.insert(Reader.getGlobalDeclID(F, ID)); } } bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M, BitstreamCursor &Cursor, uint64_t Offset, DeclContext *DC) { assert(Offset != 0); SavedStreamPosition SavedPosition(Cursor); if (llvm::Error Err = Cursor.JumpToBit(Offset)) { Error(std::move(Err)); return true; } RecordData Record; StringRef Blob; Expected MaybeCode = Cursor.ReadCode(); if (!MaybeCode) { Error(MaybeCode.takeError()); return true; } unsigned Code = MaybeCode.get(); Expected MaybeRecCode = Cursor.readRecord(Code, Record, &Blob); if (!MaybeRecCode) { Error(MaybeRecCode.takeError()); return true; } unsigned RecCode = MaybeRecCode.get(); if (RecCode != DECL_CONTEXT_LEXICAL) { Error("Expected lexical block"); return true; } assert(!isa(DC) && "expected a TU_UPDATE_LEXICAL record for TU"); // If we are handling a C++ class template instantiation, we can see multiple // lexical updates for the same record. It's important that we select only one // of them, so that field numbering works properly. Just pick the first one we // see. auto &Lex = LexicalDecls[DC]; if (!Lex.first) { Lex = std::make_pair( &M, llvm::ArrayRef( reinterpret_cast(Blob.data()), Blob.size() / sizeof(DeclID))); } DC->setHasExternalLexicalStorage(true); return false; } bool ASTReader::ReadVisibleDeclContextStorage(ModuleFile &M, BitstreamCursor &Cursor, uint64_t Offset, GlobalDeclID ID) { assert(Offset != 0); SavedStreamPosition SavedPosition(Cursor); if (llvm::Error Err = Cursor.JumpToBit(Offset)) { Error(std::move(Err)); return true; } RecordData Record; StringRef Blob; Expected MaybeCode = Cursor.ReadCode(); if (!MaybeCode) { Error(MaybeCode.takeError()); return true; } unsigned Code = MaybeCode.get(); Expected MaybeRecCode = Cursor.readRecord(Code, Record, &Blob); if (!MaybeRecCode) { Error(MaybeRecCode.takeError()); return true; } unsigned RecCode = MaybeRecCode.get(); if (RecCode != DECL_CONTEXT_VISIBLE) { Error("Expected visible lookup table block"); return true; } // We can't safely determine the primary context yet, so delay attaching the // lookup table until we're done with recursive deserialization. auto *Data = (const unsigned char*)Blob.data(); PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data}); return false; } void ASTReader::Error(StringRef Msg) const { Error(diag::err_fe_pch_malformed, Msg); if (PP.getLangOpts().Modules && !Diags.isDiagnosticInFlight() && !PP.getHeaderSearchInfo().getModuleCachePath().empty()) { Diag(diag::note_module_cache_path) << PP.getHeaderSearchInfo().getModuleCachePath(); } } void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2, StringRef Arg3) const { if (Diags.isDiagnosticInFlight()) Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2, Arg3); else Diag(DiagID) << Arg1 << Arg2 << Arg3; } void ASTReader::Error(llvm::Error &&Err) const { llvm::Error RemainingErr = handleErrors(std::move(Err), [this](const DiagnosticError &E) { auto Diag = E.getDiagnostic().second; // Ideally we'd just emit it, but have to handle a possible in-flight // diagnostic. Note that the location is currently ignored as well. auto NumArgs = Diag.getStorage()->NumDiagArgs; assert(NumArgs <= 3 && "Can only have up to 3 arguments"); StringRef Arg1, Arg2, Arg3; switch (NumArgs) { case 3: Arg3 = Diag.getStringArg(2); [[fallthrough]]; case 2: Arg2 = Diag.getStringArg(1); [[fallthrough]]; case 1: Arg1 = Diag.getStringArg(0); } Error(Diag.getDiagID(), Arg1, Arg2, Arg3); }); if (RemainingErr) Error(toString(std::move(RemainingErr))); } //===----------------------------------------------------------------------===// // Source Manager Deserialization //===----------------------------------------------------------------------===// /// Read the line table in the source manager block. void ASTReader::ParseLineTable(ModuleFile &F, const RecordData &Record) { unsigned Idx = 0; LineTableInfo &LineTable = SourceMgr.getLineTable(); // Parse the file names std::map FileIDs; FileIDs[-1] = -1; // For unspecified filenames. for (unsigned I = 0; Record[Idx]; ++I) { // Extract the file name auto Filename = ReadPath(F, Record, Idx); FileIDs[I] = LineTable.getLineTableFilenameID(Filename); } ++Idx; // Parse the line entries std::vector Entries; while (Idx < Record.size()) { FileID FID = ReadFileID(F, Record, Idx); // Extract the line entries unsigned NumEntries = Record[Idx++]; assert(NumEntries && "no line entries for file ID"); Entries.clear(); Entries.reserve(NumEntries); for (unsigned I = 0; I != NumEntries; ++I) { unsigned FileOffset = Record[Idx++]; unsigned LineNo = Record[Idx++]; int FilenameID = FileIDs[Record[Idx++]]; SrcMgr::CharacteristicKind FileKind = (SrcMgr::CharacteristicKind)Record[Idx++]; unsigned IncludeOffset = Record[Idx++]; Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID, FileKind, IncludeOffset)); } LineTable.AddEntry(FID, Entries); } } /// Read a source manager block llvm::Error ASTReader::ReadSourceManagerBlock(ModuleFile &F) { using namespace SrcMgr; BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor; // Set the source-location entry cursor to the current position in // the stream. This cursor will be used to read the contents of the // source manager block initially, and then lazily read // source-location entries as needed. SLocEntryCursor = F.Stream; // The stream itself is going to skip over the source manager block. if (llvm::Error Err = F.Stream.SkipBlock()) return Err; // Enter the source manager block. if (llvm::Error Err = SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) return Err; F.SourceManagerBlockStartOffset = SLocEntryCursor.GetCurrentBitNo(); RecordData Record; while (true) { Expected MaybeE = SLocEntryCursor.advanceSkippingSubblocks(); if (!MaybeE) return MaybeE.takeError(); llvm::BitstreamEntry E = MaybeE.get(); switch (E.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: return llvm::createStringError(std::errc::illegal_byte_sequence, "malformed block record in AST file"); case llvm::BitstreamEntry::EndBlock: return llvm::Error::success(); case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); StringRef Blob; Expected MaybeRecord = SLocEntryCursor.readRecord(E.ID, Record, &Blob); if (!MaybeRecord) return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: ignore. break; case SM_SLOC_FILE_ENTRY: case SM_SLOC_BUFFER_ENTRY: case SM_SLOC_EXPANSION_ENTRY: // Once we hit one of the source location entries, we're done. return llvm::Error::success(); } } } llvm::Expected ASTReader::readSLocOffset(ModuleFile *F, unsigned Index) { BitstreamCursor &Cursor = F->SLocEntryCursor; SavedStreamPosition SavedPosition(Cursor); if (llvm::Error Err = Cursor.JumpToBit(F->SLocEntryOffsetsBase + F->SLocEntryOffsets[Index])) return std::move(Err); Expected MaybeEntry = Cursor.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); if (Entry.Kind != llvm::BitstreamEntry::Record) return llvm::createStringError( std::errc::illegal_byte_sequence, "incorrectly-formatted source location entry in AST file"); RecordData Record; StringRef Blob; Expected MaybeSLOC = Cursor.readRecord(Entry.ID, Record, &Blob); if (!MaybeSLOC) return MaybeSLOC.takeError(); switch (MaybeSLOC.get()) { default: return llvm::createStringError( std::errc::illegal_byte_sequence, "incorrectly-formatted source location entry in AST file"); case SM_SLOC_FILE_ENTRY: case SM_SLOC_BUFFER_ENTRY: case SM_SLOC_EXPANSION_ENTRY: return F->SLocEntryBaseOffset + Record[0]; } } int ASTReader::getSLocEntryID(SourceLocation::UIntTy SLocOffset) { auto SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - SLocOffset - 1); assert(SLocMapI != GlobalSLocOffsetMap.end() && "Corrupted global sloc offset map"); ModuleFile *F = SLocMapI->second; bool Invalid = false; auto It = llvm::upper_bound( llvm::index_range(0, F->LocalNumSLocEntries), SLocOffset, [&](SourceLocation::UIntTy Offset, std::size_t LocalIndex) { int ID = F->SLocEntryBaseID + LocalIndex; std::size_t Index = -ID - 2; if (!SourceMgr.SLocEntryOffsetLoaded[Index]) { assert(!SourceMgr.SLocEntryLoaded[Index]); auto MaybeEntryOffset = readSLocOffset(F, LocalIndex); if (!MaybeEntryOffset) { Error(MaybeEntryOffset.takeError()); Invalid = true; return true; } SourceMgr.LoadedSLocEntryTable[Index] = SrcMgr::SLocEntry::getOffsetOnly(*MaybeEntryOffset); SourceMgr.SLocEntryOffsetLoaded[Index] = true; } return Offset < SourceMgr.LoadedSLocEntryTable[Index].getOffset(); }); if (Invalid) return 0; // The iterator points to the first entry with start offset greater than the // offset of interest. The previous entry must contain the offset of interest. return F->SLocEntryBaseID + *std::prev(It); } bool ASTReader::ReadSLocEntry(int ID) { if (ID == 0) return false; if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { Error("source location entry ID out-of-range for AST file"); return true; } // Local helper to read the (possibly-compressed) buffer data following the // entry record. auto ReadBuffer = [this]( BitstreamCursor &SLocEntryCursor, StringRef Name) -> std::unique_ptr { RecordData Record; StringRef Blob; Expected MaybeCode = SLocEntryCursor.ReadCode(); if (!MaybeCode) { Error(MaybeCode.takeError()); return nullptr; } unsigned Code = MaybeCode.get(); Expected MaybeRecCode = SLocEntryCursor.readRecord(Code, Record, &Blob); if (!MaybeRecCode) { Error(MaybeRecCode.takeError()); return nullptr; } unsigned RecCode = MaybeRecCode.get(); if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) { // Inspect the first byte to differentiate zlib (\x78) and zstd // (little-endian 0xFD2FB528). const llvm::compression::Format F = Blob.size() > 0 && Blob.data()[0] == 0x78 ? llvm::compression::Format::Zlib : llvm::compression::Format::Zstd; if (const char *Reason = llvm::compression::getReasonIfUnsupported(F)) { Error(Reason); return nullptr; } SmallVector Decompressed; if (llvm::Error E = llvm::compression::decompress( F, llvm::arrayRefFromStringRef(Blob), Decompressed, Record[0])) { Error("could not decompress embedded file contents: " + llvm::toString(std::move(E))); return nullptr; } return llvm::MemoryBuffer::getMemBufferCopy( llvm::toStringRef(Decompressed), Name); } else if (RecCode == SM_SLOC_BUFFER_BLOB) { return llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name, true); } else { Error("AST record has invalid code"); return nullptr; } }; ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second; if (llvm::Error Err = F->SLocEntryCursor.JumpToBit( F->SLocEntryOffsetsBase + F->SLocEntryOffsets[ID - F->SLocEntryBaseID])) { Error(std::move(Err)); return true; } BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor; SourceLocation::UIntTy BaseOffset = F->SLocEntryBaseOffset; ++NumSLocEntriesRead; Expected MaybeEntry = SLocEntryCursor.advance(); if (!MaybeEntry) { Error(MaybeEntry.takeError()); return true; } llvm::BitstreamEntry Entry = MaybeEntry.get(); if (Entry.Kind != llvm::BitstreamEntry::Record) { Error("incorrectly-formatted source location entry in AST file"); return true; } RecordData Record; StringRef Blob; Expected MaybeSLOC = SLocEntryCursor.readRecord(Entry.ID, Record, &Blob); if (!MaybeSLOC) { Error(MaybeSLOC.takeError()); return true; } switch (MaybeSLOC.get()) { default: Error("incorrectly-formatted source location entry in AST file"); return true; case SM_SLOC_FILE_ENTRY: { // We will detect whether a file changed and return 'Failure' for it, but // we will also try to fail gracefully by setting up the SLocEntry. unsigned InputID = Record[4]; InputFile IF = getInputFile(*F, InputID); OptionalFileEntryRef File = IF.getFile(); bool OverriddenBuffer = IF.isOverridden(); // Note that we only check if a File was returned. If it was out-of-date // we have complained but we will continue creating a FileID to recover // gracefully. if (!File) return true; SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) { // This is the module's main file. IncludeLoc = getImportLocation(F); } SrcMgr::CharacteristicKind FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; FileID FID = SourceMgr.createFileID(*File, IncludeLoc, FileCharacter, ID, BaseOffset + Record[0]); SrcMgr::FileInfo &FileInfo = SourceMgr.getSLocEntry(FID).getFile(); FileInfo.NumCreatedFIDs = Record[5]; if (Record[3]) FileInfo.setHasLineDirectives(); unsigned NumFileDecls = Record[7]; if (NumFileDecls && ContextObj) { const unaligned_decl_id_t *FirstDecl = F->FileSortedDecls + Record[6]; assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?"); FileDeclIDs[FID] = FileDeclsInfo(F, llvm::ArrayRef(FirstDecl, NumFileDecls)); } const SrcMgr::ContentCache &ContentCache = SourceMgr.getOrCreateContentCache(*File, isSystem(FileCharacter)); if (OverriddenBuffer && !ContentCache.BufferOverridden && ContentCache.ContentsEntry == ContentCache.OrigEntry && !ContentCache.getBufferIfLoaded()) { auto Buffer = ReadBuffer(SLocEntryCursor, File->getName()); if (!Buffer) return true; SourceMgr.overrideFileContents(*File, std::move(Buffer)); } break; } case SM_SLOC_BUFFER_ENTRY: { const char *Name = Blob.data(); unsigned Offset = Record[0]; SrcMgr::CharacteristicKind FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); if (IncludeLoc.isInvalid() && F->isModule()) { IncludeLoc = getImportLocation(F); } auto Buffer = ReadBuffer(SLocEntryCursor, Name); if (!Buffer) return true; FileID FID = SourceMgr.createFileID(std::move(Buffer), FileCharacter, ID, BaseOffset + Offset, IncludeLoc); if (Record[3]) { auto &FileInfo = SourceMgr.getSLocEntry(FID).getFile(); FileInfo.setHasLineDirectives(); } break; } case SM_SLOC_EXPANSION_ENTRY: { LocSeq::State Seq; SourceLocation SpellingLoc = ReadSourceLocation(*F, Record[1], Seq); SourceLocation ExpansionBegin = ReadSourceLocation(*F, Record[2], Seq); SourceLocation ExpansionEnd = ReadSourceLocation(*F, Record[3], Seq); SourceMgr.createExpansionLoc(SpellingLoc, ExpansionBegin, ExpansionEnd, Record[5], Record[4], ID, BaseOffset + Record[0]); break; } } return false; } std::pair ASTReader::getModuleImportLoc(int ID) { if (ID == 0) return std::make_pair(SourceLocation(), ""); if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { Error("source location entry ID out-of-range for AST file"); return std::make_pair(SourceLocation(), ""); } // Find which module file this entry lands in. ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second; if (!M->isModule()) return std::make_pair(SourceLocation(), ""); // FIXME: Can we map this down to a particular submodule? That would be // ideal. return std::make_pair(M->ImportLoc, StringRef(M->ModuleName)); } /// Find the location where the module F is imported. SourceLocation ASTReader::getImportLocation(ModuleFile *F) { if (F->ImportLoc.isValid()) return F->ImportLoc; // Otherwise we have a PCH. It's considered to be "imported" at the first // location of its includer. if (F->ImportedBy.empty() || !F->ImportedBy[0]) { // Main file is the importer. assert(SourceMgr.getMainFileID().isValid() && "missing main file"); return SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); } return F->ImportedBy[0]->FirstLoc; } /// Enter a subblock of the specified BlockID with the specified cursor. Read /// the abbreviations that are at the top of the block and then leave the cursor /// pointing into the block. llvm::Error ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID, uint64_t *StartOfBlockOffset) { if (llvm::Error Err = Cursor.EnterSubBlock(BlockID)) return Err; if (StartOfBlockOffset) *StartOfBlockOffset = Cursor.GetCurrentBitNo(); while (true) { uint64_t Offset = Cursor.GetCurrentBitNo(); Expected MaybeCode = Cursor.ReadCode(); if (!MaybeCode) return MaybeCode.takeError(); unsigned Code = MaybeCode.get(); // We expect all abbrevs to be at the start of the block. if (Code != llvm::bitc::DEFINE_ABBREV) { if (llvm::Error Err = Cursor.JumpToBit(Offset)) return Err; return llvm::Error::success(); } if (llvm::Error Err = Cursor.ReadAbbrevRecord()) return Err; } } Token ASTReader::ReadToken(ModuleFile &M, const RecordDataImpl &Record, unsigned &Idx) { Token Tok; Tok.startToken(); Tok.setLocation(ReadSourceLocation(M, Record, Idx)); Tok.setKind((tok::TokenKind)Record[Idx++]); Tok.setFlag((Token::TokenFlags)Record[Idx++]); if (Tok.isAnnotation()) { Tok.setAnnotationEndLoc(ReadSourceLocation(M, Record, Idx)); switch (Tok.getKind()) { case tok::annot_pragma_loop_hint: { auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; Info->PragmaName = ReadToken(M, Record, Idx); Info->Option = ReadToken(M, Record, Idx); unsigned NumTokens = Record[Idx++]; SmallVector Toks; Toks.reserve(NumTokens); for (unsigned I = 0; I < NumTokens; ++I) Toks.push_back(ReadToken(M, Record, Idx)); Info->Toks = llvm::ArrayRef(Toks).copy(PP.getPreprocessorAllocator()); Tok.setAnnotationValue(static_cast(Info)); break; } case tok::annot_pragma_pack: { auto *Info = new (PP.getPreprocessorAllocator()) Sema::PragmaPackInfo; Info->Action = static_cast(Record[Idx++]); auto SlotLabel = ReadString(Record, Idx); Info->SlotLabel = llvm::StringRef(SlotLabel).copy(PP.getPreprocessorAllocator()); Info->Alignment = ReadToken(M, Record, Idx); Tok.setAnnotationValue(static_cast(Info)); break; } // Some annotation tokens do not use the PtrData field. case tok::annot_pragma_openmp: case tok::annot_pragma_openmp_end: case tok::annot_pragma_unused: case tok::annot_pragma_openacc: case tok::annot_pragma_openacc_end: break; default: llvm_unreachable("missing deserialization code for annotation token"); } } else { Tok.setLength(Record[Idx++]); if (IdentifierInfo *II = getLocalIdentifier(M, Record[Idx++])) Tok.setIdentifierInfo(II); } return Tok; } MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { BitstreamCursor &Stream = F.MacroCursor; // Keep track of where we are in the stream, then jump back there // after reading this macro. SavedStreamPosition SavedPosition(Stream); if (llvm::Error Err = Stream.JumpToBit(Offset)) { // FIXME this drops errors on the floor. consumeError(std::move(Err)); return nullptr; } RecordData Record; SmallVector MacroParams; MacroInfo *Macro = nullptr; llvm::MutableArrayRef MacroTokens; while (true) { // Advance to the next record, but if we get to the end of the block, don't // pop it (removing all the abbreviations from the cursor) since we want to // be able to reseek within the block and read entries. unsigned Flags = BitstreamCursor::AF_DontPopBlockAtEnd; Expected MaybeEntry = Stream.advanceSkippingSubblocks(Flags); if (!MaybeEntry) { Error(MaybeEntry.takeError()); return Macro; } llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: Error("malformed block record in AST file"); return Macro; case llvm::BitstreamEntry::EndBlock: return Macro; case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); PreprocessorRecordTypes RecType; if (Expected MaybeRecType = Stream.readRecord(Entry.ID, Record)) RecType = (PreprocessorRecordTypes)MaybeRecType.get(); else { Error(MaybeRecType.takeError()); return Macro; } switch (RecType) { case PP_MODULE_MACRO: case PP_MACRO_DIRECTIVE_HISTORY: return Macro; case PP_MACRO_OBJECT_LIKE: case PP_MACRO_FUNCTION_LIKE: { // If we already have a macro, that means that we've hit the end // of the definition of the macro we were looking for. We're // done. if (Macro) return Macro; unsigned NextIndex = 1; // Skip identifier ID. SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex); MacroInfo *MI = PP.AllocateMacroInfo(Loc); MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex)); MI->setIsUsed(Record[NextIndex++]); MI->setUsedForHeaderGuard(Record[NextIndex++]); MacroTokens = MI->allocateTokens(Record[NextIndex++], PP.getPreprocessorAllocator()); if (RecType == PP_MACRO_FUNCTION_LIKE) { // Decode function-like macro info. bool isC99VarArgs = Record[NextIndex++]; bool isGNUVarArgs = Record[NextIndex++]; bool hasCommaPasting = Record[NextIndex++]; MacroParams.clear(); unsigned NumArgs = Record[NextIndex++]; for (unsigned i = 0; i != NumArgs; ++i) 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->setParameterList(MacroParams, PP.getPreprocessorAllocator()); } // Remember that we saw this macro last so that we add the tokens that // form its body to it. Macro = MI; if (NextIndex + 1 == Record.size() && PP.getPreprocessingRecord() && Record[NextIndex]) { // We have a macro definition. Register the association PreprocessedEntityID GlobalID = getGlobalPreprocessedEntityID(F, Record[NextIndex]); PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); PreprocessingRecord::PPEntityID PPID = PPRec.getPPEntityID(GlobalID - 1, /*isLoaded=*/true); MacroDefinitionRecord *PPDef = cast_or_null( PPRec.getPreprocessedEntity(PPID)); if (PPDef) PPRec.RegisterMacroDefinition(Macro, PPDef); } ++NumMacrosRead; break; } case PP_TOKEN: { // If we see a TOKEN before a PP_MACRO_*, then the file is // erroneous, just pretend we didn't see this. if (!Macro) break; if (MacroTokens.empty()) { Error("unexpected number of macro tokens for a macro in AST file"); return Macro; } unsigned Idx = 0; MacroTokens[0] = ReadToken(F, Record, Idx); MacroTokens = MacroTokens.drop_front(); break; } } } } PreprocessedEntityID ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const { if (!M.ModuleOffsetMap.empty()) ReadModuleOffsetMap(M); ContinuousRangeMap::const_iterator I = M.PreprocessedEntityRemap.find(LocalID - NUM_PREDEF_PP_ENTITY_IDS); assert(I != M.PreprocessedEntityRemap.end() && "Invalid index into preprocessed entity index remap"); return LocalID + I->second; } const FileEntry *HeaderFileInfoTrait::getFile(const internal_key_type &Key) { FileManager &FileMgr = Reader.getFileManager(); if (!Key.Imported) { if (auto File = FileMgr.getFile(Key.Filename)) return *File; return nullptr; } std::string Resolved = std::string(Key.Filename); Reader.ResolveImportedPath(M, Resolved); if (auto File = FileMgr.getFile(Resolved)) return *File; return nullptr; } unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) { uint8_t buf[sizeof(ikey.Size) + sizeof(ikey.ModTime)]; memcpy(buf, &ikey.Size, sizeof(ikey.Size)); memcpy(buf + sizeof(ikey.Size), &ikey.ModTime, sizeof(ikey.ModTime)); return llvm::xxh3_64bits(buf); } HeaderFileInfoTrait::internal_key_type HeaderFileInfoTrait::GetInternalKey(external_key_type ekey) { internal_key_type ikey = {ekey.getSize(), M.HasTimestamps ? ekey.getModificationTime() : 0, ekey.getName(), /*Imported*/ false}; return ikey; } bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) { if (a.Size != b.Size || (a.ModTime && b.ModTime && a.ModTime != b.ModTime)) return false; if (llvm::sys::path::is_absolute(a.Filename) && a.Filename == b.Filename) return true; // Determine whether the actual files are equivalent. const FileEntry *FEA = getFile(a); const FileEntry *FEB = getFile(b); return FEA && FEA == FEB; } std::pair HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) { return readULEBKeyDataLength(d); } HeaderFileInfoTrait::internal_key_type HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) { using namespace llvm::support; internal_key_type ikey; ikey.Size = off_t(endian::readNext(d)); ikey.ModTime = time_t(endian::readNext(d)); ikey.Filename = (const char *)d; ikey.Imported = true; return ikey; } HeaderFileInfoTrait::data_type HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, unsigned DataLen) { using namespace llvm::support; const unsigned char *End = d + DataLen; HeaderFileInfo HFI; unsigned Flags = *d++; bool Included = (Flags >> 6) & 0x01; if (Included) if (const FileEntry *FE = getFile(key)) // Not using \c Preprocessor::markIncluded(), since that would attempt to // deserialize this header file info again. Reader.getPreprocessor().getIncludedFiles().insert(FE); // FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp. HFI.isImport |= (Flags >> 5) & 0x01; HFI.isPragmaOnce |= (Flags >> 4) & 0x01; HFI.DirInfo = (Flags >> 1) & 0x07; HFI.IndexHeaderMapHeader = Flags & 0x01; HFI.LazyControllingMacro = Reader.getGlobalIdentifierID( M, endian::readNext(d)); if (unsigned FrameworkOffset = endian::readNext(d)) { // The framework offset is 1 greater than the actual offset, // since 0 is used as an indicator for "no framework name". StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1); HFI.Framework = HS->getUniqueFrameworkName(FrameworkName); } assert((End - d) % 4 == 0 && "Wrong data length in HeaderFileInfo deserialization"); while (d != End) { uint32_t LocalSMID = endian::readNext(d); auto HeaderRole = static_cast(LocalSMID & 7); LocalSMID >>= 3; // This header is part of a module. Associate it with the module to enable // implicit module import. SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID); Module *Mod = Reader.getSubmodule(GlobalSMID); FileManager &FileMgr = Reader.getFileManager(); ModuleMap &ModMap = Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap(); std::string Filename = std::string(key.Filename); if (key.Imported) Reader.ResolveImportedPath(M, Filename); if (auto FE = FileMgr.getOptionalFileRef(Filename)) { // FIXME: NameAsWritten Module::Header H = {std::string(key.Filename), "", *FE}; ModMap.addHeader(Mod, H, HeaderRole, /*Imported=*/true); } HFI.mergeModuleMembership(HeaderRole); } // This HeaderFileInfo was externally loaded. HFI.External = true; HFI.IsValid = true; return HFI; } void ASTReader::addPendingMacro(IdentifierInfo *II, ModuleFile *M, uint32_t MacroDirectivesOffset) { assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard"); PendingMacroIDs[II].push_back(PendingMacroInfo(M, MacroDirectivesOffset)); } void ASTReader::ReadDefinedMacros() { // Note that we are loading defined macros. Deserializing Macros(this); 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; if (llvm::Error Err = Cursor.JumpToBit(I.MacroStartOffset)) { Error(std::move(Err)); return; } RecordData Record; while (true) { Expected MaybeE = Cursor.advanceSkippingSubblocks(); if (!MaybeE) { Error(MaybeE.takeError()); return; } llvm::BitstreamEntry E = MaybeE.get(); switch (E.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: Error("malformed block record in AST file"); return; case llvm::BitstreamEntry::EndBlock: goto NextCursor; case llvm::BitstreamEntry::Record: { Record.clear(); Expected MaybeRecord = Cursor.readRecord(E.ID, Record); if (!MaybeRecord) { Error(MaybeRecord.takeError()); return; } switch (MaybeRecord.get()) { default: // Default behavior: ignore. break; case PP_MACRO_OBJECT_LIKE: case PP_MACRO_FUNCTION_LIKE: { IdentifierInfo *II = getLocalIdentifier(I, Record[0]); if (II->isOutOfDate()) updateOutOfDateIdentifier(*II); break; } case PP_TOKEN: // Ignore tokens. break; } break; } } } NextCursor: ; } } namespace { /// Visitor class used to look up identifirs in an AST file. class IdentifierLookupVisitor { StringRef Name; unsigned NameHash; unsigned PriorGeneration; unsigned &NumIdentifierLookups; unsigned &NumIdentifierLookupHits; IdentifierInfo *Found = nullptr; public: IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration, unsigned &NumIdentifierLookups, unsigned &NumIdentifierLookupHits) : Name(Name), NameHash(ASTIdentifierLookupTrait::ComputeHash(Name)), PriorGeneration(PriorGeneration), NumIdentifierLookups(NumIdentifierLookups), NumIdentifierLookupHits(NumIdentifierLookupHits) {} bool operator()(ModuleFile &M) { // If we've already searched this module file, skip it now. if (M.Generation <= PriorGeneration) return true; ASTIdentifierLookupTable *IdTable = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; if (!IdTable) return false; ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(), M, Found); ++NumIdentifierLookups; ASTIdentifierLookupTable::iterator Pos = IdTable->find_hashed(Name, NameHash, &Trait); if (Pos == IdTable->end()) return false; // Dereferencing the iterator has the effect of building the // IdentifierInfo node and populating it with the various // declarations it needs. ++NumIdentifierLookupHits; Found = *Pos; return true; } // Retrieve the identifier info found within the module // files. IdentifierInfo *getIdentifierInfo() const { return Found; } }; } // namespace void ASTReader::updateOutOfDateIdentifier(const IdentifierInfo &II) { // Note that we are loading an identifier. Deserializing AnIdentifier(this); unsigned PriorGeneration = 0; if (getContext().getLangOpts().Modules) PriorGeneration = IdentifierGeneration[&II]; // If there is a global index, look there first to determine which modules // provably do not have any results for this identifier. GlobalModuleIndex::HitSet Hits; GlobalModuleIndex::HitSet *HitsPtr = nullptr; if (!loadGlobalIndex()) { if (GlobalIndex->lookupIdentifier(II.getName(), Hits)) { HitsPtr = &Hits; } } IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration, NumIdentifierLookups, NumIdentifierLookupHits); ModuleMgr.visit(Visitor, HitsPtr); markIdentifierUpToDate(&II); } void ASTReader::markIdentifierUpToDate(const IdentifierInfo *II) { if (!II) return; const_cast(II)->setOutOfDate(false); // Update the generation for this identifier. if (getContext().getLangOpts().Modules) IdentifierGeneration[II] = getGeneration(); } void ASTReader::resolvePendingMacro(IdentifierInfo *II, const PendingMacroInfo &PMInfo) { ModuleFile &M = *PMInfo.M; BitstreamCursor &Cursor = M.MacroCursor; SavedStreamPosition SavedPosition(Cursor); if (llvm::Error Err = Cursor.JumpToBit(M.MacroOffsetsBase + PMInfo.MacroDirectivesOffset)) { Error(std::move(Err)); return; } struct ModuleMacroRecord { SubmoduleID SubModID; MacroInfo *MI; SmallVector Overrides; }; llvm::SmallVector ModuleMacros; // We expect to see a sequence of PP_MODULE_MACRO records listing exported // macros, followed by a PP_MACRO_DIRECTIVE_HISTORY record with the complete // macro histroy. RecordData Record; while (true) { Expected MaybeEntry = Cursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd); if (!MaybeEntry) { Error(MaybeEntry.takeError()); return; } llvm::BitstreamEntry Entry = MaybeEntry.get(); if (Entry.Kind != llvm::BitstreamEntry::Record) { Error("malformed block record in AST file"); return; } Record.clear(); Expected MaybePP = Cursor.readRecord(Entry.ID, Record); if (!MaybePP) { Error(MaybePP.takeError()); return; } switch ((PreprocessorRecordTypes)MaybePP.get()) { case PP_MACRO_DIRECTIVE_HISTORY: break; case PP_MODULE_MACRO: { ModuleMacros.push_back(ModuleMacroRecord()); auto &Info = ModuleMacros.back(); Info.SubModID = getGlobalSubmoduleID(M, Record[0]); Info.MI = getMacro(getGlobalMacroID(M, Record[1])); for (int I = 2, N = Record.size(); I != N; ++I) Info.Overrides.push_back(getGlobalSubmoduleID(M, Record[I])); continue; } default: Error("malformed block record in AST file"); return; } // We found the macro directive history; that's the last record // for this macro. break; } // Module macros are listed in reverse dependency order. { std::reverse(ModuleMacros.begin(), ModuleMacros.end()); llvm::SmallVector Overrides; for (auto &MMR : ModuleMacros) { Overrides.clear(); for (unsigned ModID : MMR.Overrides) { Module *Mod = getSubmodule(ModID); auto *Macro = PP.getModuleMacro(Mod, II); assert(Macro && "missing definition for overridden macro"); Overrides.push_back(Macro); } bool Inserted = false; Module *Owner = getSubmodule(MMR.SubModID); PP.addModuleMacro(Owner, II, MMR.MI, Overrides, Inserted); } } // Don't read the directive history for a module; we don't have anywhere // to put it. if (M.isModule()) return; // Deserialize the macro directives history in reverse source-order. MacroDirective *Latest = nullptr, *Earliest = nullptr; unsigned Idx = 0, N = Record.size(); while (Idx < N) { MacroDirective *MD = nullptr; SourceLocation Loc = ReadSourceLocation(M, Record, Idx); MacroDirective::Kind K = (MacroDirective::Kind)Record[Idx++]; switch (K) { case MacroDirective::MD_Define: { MacroInfo *MI = getMacro(getGlobalMacroID(M, Record[Idx++])); MD = PP.AllocateDefMacroDirective(MI, Loc); break; } case MacroDirective::MD_Undefine: MD = PP.AllocateUndefMacroDirective(Loc); break; case MacroDirective::MD_Visibility: bool isPublic = Record[Idx++]; MD = PP.AllocateVisibilityMacroDirective(Loc, isPublic); break; } if (!Latest) Latest = MD; if (Earliest) Earliest->setPrevious(MD); Earliest = MD; } if (Latest) PP.setLoadedMacroDirective(II, Earliest, Latest); } bool ASTReader::shouldDisableValidationForFile( const serialization::ModuleFile &M) const { if (DisableValidationKind == DisableValidationForModuleKind::None) return false; // If a PCH is loaded and validation is disabled for PCH then disable // validation for the PCH and the modules it loads. ModuleKind K = CurrentDeserializingModuleKind.value_or(M.Kind); switch (K) { case MK_MainFile: case MK_Preamble: case MK_PCH: return bool(DisableValidationKind & DisableValidationForModuleKind::PCH); case MK_ImplicitModule: case MK_ExplicitModule: case MK_PrebuiltModule: return bool(DisableValidationKind & DisableValidationForModuleKind::Module); } return false; } InputFileInfo ASTReader::getInputFileInfo(ModuleFile &F, unsigned ID) { // If this ID is bogus, just return an empty input file. if (ID == 0 || ID > F.InputFileInfosLoaded.size()) return InputFileInfo(); // If we've already loaded this input file, return it. if (!F.InputFileInfosLoaded[ID - 1].Filename.empty()) return F.InputFileInfosLoaded[ID - 1]; // Go find this input file. BitstreamCursor &Cursor = F.InputFilesCursor; SavedStreamPosition SavedPosition(Cursor); if (llvm::Error Err = Cursor.JumpToBit(F.InputFilesOffsetBase + F.InputFileOffsets[ID - 1])) { // FIXME this drops errors on the floor. consumeError(std::move(Err)); } Expected MaybeCode = Cursor.ReadCode(); if (!MaybeCode) { // FIXME this drops errors on the floor. consumeError(MaybeCode.takeError()); } unsigned Code = MaybeCode.get(); RecordData Record; StringRef Blob; if (Expected Maybe = Cursor.readRecord(Code, Record, &Blob)) assert(static_cast(Maybe.get()) == INPUT_FILE && "invalid record type for input file"); else { // FIXME this drops errors on the floor. consumeError(Maybe.takeError()); } assert(Record[0] == ID && "Bogus stored ID or offset"); InputFileInfo R; R.StoredSize = static_cast(Record[1]); R.StoredTime = static_cast(Record[2]); R.Overridden = static_cast(Record[3]); R.Transient = static_cast(Record[4]); R.TopLevel = static_cast(Record[5]); R.ModuleMap = static_cast(Record[6]); std::tie(R.FilenameAsRequested, R.Filename) = [&]() { uint16_t AsRequestedLength = Record[7]; std::string NameAsRequested = Blob.substr(0, AsRequestedLength).str(); std::string Name = Blob.substr(AsRequestedLength).str(); ResolveImportedPath(F, NameAsRequested); ResolveImportedPath(F, Name); if (Name.empty()) Name = NameAsRequested; return std::make_pair(std::move(NameAsRequested), std::move(Name)); }(); Expected MaybeEntry = Cursor.advance(); if (!MaybeEntry) // FIXME this drops errors on the floor. consumeError(MaybeEntry.takeError()); llvm::BitstreamEntry Entry = MaybeEntry.get(); assert(Entry.Kind == llvm::BitstreamEntry::Record && "expected record type for input file hash"); Record.clear(); if (Expected Maybe = Cursor.readRecord(Entry.ID, Record)) assert(static_cast(Maybe.get()) == INPUT_FILE_HASH && "invalid record type for input file hash"); else { // FIXME this drops errors on the floor. consumeError(Maybe.takeError()); } R.ContentHash = (static_cast(Record[1]) << 32) | static_cast(Record[0]); // Note that we've loaded this input file info. F.InputFileInfosLoaded[ID - 1] = R; return R; } static unsigned moduleKindForDiagnostic(ModuleKind Kind); InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { // If this ID is bogus, just return an empty input file. if (ID == 0 || ID > F.InputFilesLoaded.size()) return InputFile(); // If we've already loaded this input file, return it. if (F.InputFilesLoaded[ID-1].getFile()) return F.InputFilesLoaded[ID-1]; if (F.InputFilesLoaded[ID-1].isNotFound()) return InputFile(); // Go find this input file. BitstreamCursor &Cursor = F.InputFilesCursor; SavedStreamPosition SavedPosition(Cursor); if (llvm::Error Err = Cursor.JumpToBit(F.InputFilesOffsetBase + F.InputFileOffsets[ID - 1])) { // FIXME this drops errors on the floor. consumeError(std::move(Err)); } InputFileInfo FI = getInputFileInfo(F, ID); off_t StoredSize = FI.StoredSize; time_t StoredTime = FI.StoredTime; bool Overridden = FI.Overridden; bool Transient = FI.Transient; StringRef Filename = FI.FilenameAsRequested; uint64_t StoredContentHash = FI.ContentHash; // For standard C++ modules, we don't need to check the inputs. bool SkipChecks = F.StandardCXXModule; const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); // The option ForceCheckCXX20ModulesInputFiles is only meaningful for C++20 // modules. if (F.StandardCXXModule && HSOpts.ForceCheckCXX20ModulesInputFiles) { SkipChecks = false; Overridden = false; } auto File = FileMgr.getOptionalFileRef(Filename, /*OpenFile=*/false); // For an overridden file, create a virtual file with the stored // size/timestamp. if ((Overridden || Transient || SkipChecks) && !File) File = FileMgr.getVirtualFileRef(Filename, StoredSize, StoredTime); if (!File) { if (Complain) { std::string ErrorStr = "could not find file '"; ErrorStr += Filename; ErrorStr += "' referenced by AST file '"; ErrorStr += F.FileName; ErrorStr += "'"; Error(ErrorStr); } // Record that we didn't find the file. F.InputFilesLoaded[ID-1] = InputFile::getNotFound(); return InputFile(); } // Check if there was a request to override the contents of the file // that was part of the precompiled header. Overriding such a file // can lead to problems when lexing using the source locations from the // PCH. SourceManager &SM = getSourceManager(); // FIXME: Reject if the overrides are different. if ((!Overridden && !Transient) && !SkipChecks && SM.isFileOverridden(*File)) { if (Complain) Error(diag::err_fe_pch_file_overridden, Filename); // After emitting the diagnostic, bypass the overriding file to recover // (this creates a separate FileEntry). File = SM.bypassFileContentsOverride(*File); if (!File) { F.InputFilesLoaded[ID - 1] = InputFile::getNotFound(); return InputFile(); } } struct Change { enum ModificationKind { Size, ModTime, Content, None, } Kind; std::optional Old = std::nullopt; std::optional New = std::nullopt; }; auto HasInputContentChanged = [&](Change OriginalChange) { assert(ValidateASTInputFilesContent && "We should only check the content of the inputs with " "ValidateASTInputFilesContent enabled."); if (StoredContentHash == 0) return OriginalChange; auto MemBuffOrError = FileMgr.getBufferForFile(*File); if (!MemBuffOrError) { if (!Complain) return OriginalChange; std::string ErrorStr = "could not get buffer for file '"; ErrorStr += File->getName(); ErrorStr += "'"; Error(ErrorStr); return OriginalChange; } auto ContentHash = xxh3_64bits(MemBuffOrError.get()->getBuffer()); if (StoredContentHash == static_cast(ContentHash)) return Change{Change::None}; return Change{Change::Content}; }; auto HasInputFileChanged = [&]() { if (StoredSize != File->getSize()) return Change{Change::Size, StoredSize, File->getSize()}; if (!shouldDisableValidationForFile(F) && StoredTime && StoredTime != File->getModificationTime()) { Change MTimeChange = {Change::ModTime, StoredTime, File->getModificationTime()}; // In case the modification time changes but not the content, // accept the cached file as legit. if (ValidateASTInputFilesContent) return HasInputContentChanged(MTimeChange); return MTimeChange; } return Change{Change::None}; }; bool IsOutOfDate = false; auto FileChange = SkipChecks ? Change{Change::None} : HasInputFileChanged(); // When ForceCheckCXX20ModulesInputFiles and ValidateASTInputFilesContent // enabled, it is better to check the contents of the inputs. Since we can't // get correct modified time information for inputs from overriden inputs. if (HSOpts.ForceCheckCXX20ModulesInputFiles && ValidateASTInputFilesContent && F.StandardCXXModule && FileChange.Kind == Change::None) FileChange = HasInputContentChanged(FileChange); // When we have StoredTime equal to zero and ValidateASTInputFilesContent, // it is better to check the content of the input files because we cannot rely // on the file modification time, which will be the same (zero) for these // files. if (!StoredTime && ValidateASTInputFilesContent && FileChange.Kind == Change::None) FileChange = HasInputContentChanged(FileChange); // For an overridden file, there is nothing to validate. if (!Overridden && FileChange.Kind != Change::None) { if (Complain && !Diags.isDiagnosticInFlight()) { // Build a list of the PCH imports that got us here (in reverse). SmallVector ImportStack(1, &F); while (!ImportStack.back()->ImportedBy.empty()) ImportStack.push_back(ImportStack.back()->ImportedBy[0]); // The top-level PCH is stale. StringRef TopLevelPCHName(ImportStack.back()->FileName); Diag(diag::err_fe_ast_file_modified) << Filename << moduleKindForDiagnostic(ImportStack.back()->Kind) << TopLevelPCHName << FileChange.Kind << (FileChange.Old && FileChange.New) << llvm::itostr(FileChange.Old.value_or(0)) << llvm::itostr(FileChange.New.value_or(0)); // Print the import stack. if (ImportStack.size() > 1) { Diag(diag::note_pch_required_by) << Filename << ImportStack[0]->FileName; for (unsigned I = 1; I < ImportStack.size(); ++I) Diag(diag::note_pch_required_by) << ImportStack[I-1]->FileName << ImportStack[I]->FileName; } Diag(diag::note_pch_rebuild_required) << TopLevelPCHName; } IsOutOfDate = true; } // FIXME: If the file is overridden and we've already opened it, // issue an error (or split it into a separate FileEntry). InputFile IF = InputFile(*File, Overridden || Transient, IsOutOfDate); // Note that we've loaded this input file. F.InputFilesLoaded[ID-1] = IF; return IF; } /// If we are loading a relocatable PCH or module file, and the filename /// is not an absolute path, add the system or module root to the beginning of /// the file name. void ASTReader::ResolveImportedPath(ModuleFile &M, std::string &Filename) { // Resolve relative to the base directory, if we have one. if (!M.BaseDirectory.empty()) return ResolveImportedPath(Filename, M.BaseDirectory); } void ASTReader::ResolveImportedPath(std::string &Filename, StringRef Prefix) { if (Filename.empty() || llvm::sys::path::is_absolute(Filename) || Filename == "" || Filename == "") return; SmallString<128> Buffer; llvm::sys::path::append(Buffer, Prefix, Filename); Filename.assign(Buffer.begin(), Buffer.end()); } static bool isDiagnosedResult(ASTReader::ASTReadResult ARR, unsigned Caps) { switch (ARR) { case ASTReader::Failure: return true; case ASTReader::Missing: return !(Caps & ASTReader::ARR_Missing); case ASTReader::OutOfDate: return !(Caps & ASTReader::ARR_OutOfDate); case ASTReader::VersionMismatch: return !(Caps & ASTReader::ARR_VersionMismatch); case ASTReader::ConfigurationMismatch: return !(Caps & ASTReader::ARR_ConfigurationMismatch); case ASTReader::HadErrors: return true; case ASTReader::Success: return false; } llvm_unreachable("unknown ASTReadResult"); } ASTReader::ASTReadResult ASTReader::ReadOptionsBlock( BitstreamCursor &Stream, unsigned ClientLoadCapabilities, bool AllowCompatibleConfigurationMismatch, ASTReaderListener &Listener, std::string &SuggestedPredefines) { if (llvm::Error Err = Stream.EnterSubBlock(OPTIONS_BLOCK_ID)) { // FIXME this drops errors on the floor. consumeError(std::move(Err)); return Failure; } // Read all of the records in the options block. RecordData Record; ASTReadResult Result = Success; while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) { // FIXME this drops errors on the floor. consumeError(MaybeEntry.takeError()); return Failure; } llvm::BitstreamEntry Entry = MaybeEntry.get(); 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(); Expected MaybeRecordType = Stream.readRecord(Entry.ID, Record); if (!MaybeRecordType) { // FIXME this drops errors on the floor. consumeError(MaybeRecordType.takeError()); return Failure; } switch ((OptionsRecordTypes)MaybeRecordType.get()) { case LANGUAGE_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (ParseLanguageOptions(Record, Complain, Listener, AllowCompatibleConfigurationMismatch)) Result = ConfigurationMismatch; break; } case TARGET_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (ParseTargetOptions(Record, Complain, Listener, AllowCompatibleConfigurationMismatch)) Result = ConfigurationMismatch; break; } case FILE_SYSTEM_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (!AllowCompatibleConfigurationMismatch && ParseFileSystemOptions(Record, Complain, Listener)) Result = ConfigurationMismatch; break; } case HEADER_SEARCH_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (!AllowCompatibleConfigurationMismatch && ParseHeaderSearchOptions(Record, Complain, Listener)) Result = ConfigurationMismatch; break; } case PREPROCESSOR_OPTIONS: bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (!AllowCompatibleConfigurationMismatch && ParsePreprocessorOptions(Record, Complain, Listener, SuggestedPredefines)) Result = ConfigurationMismatch; break; } } } ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F, SmallVectorImpl &Loaded, const ModuleFile *ImportedBy, unsigned ClientLoadCapabilities) { BitstreamCursor &Stream = F.Stream; if (llvm::Error Err = Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { Error(std::move(Err)); 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; }; bool DisableValidation = shouldDisableValidationForFile(F); // Read all of the records and blocks in the control block. RecordData Record; unsigned NumInputs = 0; unsigned NumUserInputs = 0; StringRef BaseDirectoryAsWritten; while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) { Error(MaybeEntry.takeError()); return Failure; } llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: 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(); // All user input files reside at the index range [0, NumUserInputs), and // system input files reside at [NumUserInputs, NumInputs). For explicitly // loaded module files, ignore missing inputs. if (!DisableValidation && F.Kind != MK_ExplicitModule && F.Kind != MK_PrebuiltModule) { bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; // If we are reading a module, we will create a verification timestamp, // so we verify all input files. Otherwise, verify only user input // files. unsigned N = ValidateSystemInputs ? NumInputs : NumUserInputs; if (HSOpts.ModulesValidateOncePerBuildSession && F.InputFilesValidationTimestamp > HSOpts.BuildSessionTimestamp && F.Kind == MK_ImplicitModule) N = NumUserInputs; for (unsigned I = 0; I < N; ++I) { InputFile IF = getInputFile(F, I+1, Complain); if (!IF.getFile() || IF.isOutOfDate()) return OutOfDate; } } if (Listener) Listener->visitModuleFile(F.FileName, F.Kind); if (Listener && Listener->needsInputFileVisitation()) { unsigned N = Listener->needsSystemInputFileVisitation() ? NumInputs : NumUserInputs; for (unsigned I = 0; I < N; ++I) { bool IsSystem = I >= NumUserInputs; InputFileInfo FI = getInputFileInfo(F, I + 1); Listener->visitInputFile( FI.FilenameAsRequested, IsSystem, FI.Overridden, F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule); } } return Success; } case llvm::BitstreamEntry::SubBlock: switch (Entry.ID) { case INPUT_FILES_BLOCK_ID: F.InputFilesCursor = Stream; if (llvm::Error Err = Stream.SkipBlock()) { Error(std::move(Err)); return Failure; } if (ReadBlockAbbrevs(F.InputFilesCursor, INPUT_FILES_BLOCK_ID)) { Error("malformed block record in AST file"); return Failure; } F.InputFilesOffsetBase = F.InputFilesCursor.GetCurrentBitNo(); continue; case OPTIONS_BLOCK_ID: // If we're reading the first module for this group, check its options // are compatible with ours. For modules it imports, no further checking // is required, because we checked them when we built it. if (Listener && !ImportedBy) { // Should we allow the configuration of the module file to differ from // the configuration of the current translation unit in a compatible // way? // // FIXME: Allow this for files explicitly specified with -include-pch. bool AllowCompatibleConfigurationMismatch = F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule; ASTReadResult Result = ReadOptionsBlock(Stream, ClientLoadCapabilities, AllowCompatibleConfigurationMismatch, *Listener, SuggestedPredefines); if (Result == Failure) { Error("malformed block record in AST file"); return Result; } if (DisableValidation || (AllowConfigurationMismatch && Result == ConfigurationMismatch)) Result = Success; // If we can't load the module, exit early since we likely // will rebuild the module anyway. The stream may be in the // middle of a block. if (Result != Success) return Result; } else if (llvm::Error Err = Stream.SkipBlock()) { Error(std::move(Err)); return Failure; } continue; default: if (llvm::Error Err = Stream.SkipBlock()) { Error(std::move(Err)); return Failure; } continue; } case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read and process a record. Record.clear(); StringRef Blob; Expected MaybeRecordType = Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecordType) { Error(MaybeRecordType.takeError()); return Failure; } switch ((ControlRecordTypes)MaybeRecordType.get()) { case METADATA: { if (Record[0] != VERSION_MAJOR && !DisableValidation) { if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) Diag(Record[0] < VERSION_MAJOR? diag::err_pch_version_too_old : diag::err_pch_version_too_new); return VersionMismatch; } bool hasErrors = Record[7]; if (hasErrors && !DisableValidation) { // If requested by the caller and the module hasn't already been read // or compiled, mark modules on error as out-of-date. if ((ClientLoadCapabilities & ARR_TreatModuleWithErrorsAsOutOfDate) && canRecoverFromOutOfDate(F.FileName, ClientLoadCapabilities)) return OutOfDate; if (!AllowASTWithCompilerErrors) { Diag(diag::err_pch_with_compiler_errors); return HadErrors; } } if (hasErrors) { Diags.ErrorOccurred = true; Diags.UncompilableErrorOccurred = true; Diags.UnrecoverableErrorOccurred = true; } F.RelocatablePCH = Record[4]; // Relative paths in a relocatable PCH are relative to our sysroot. if (F.RelocatablePCH) F.BaseDirectory = isysroot.empty() ? "/" : isysroot; F.StandardCXXModule = Record[5]; F.HasTimestamps = Record[6]; const std::string &CurBranch = getClangFullRepositoryVersion(); StringRef ASTBranch = Blob; if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) Diag(diag::err_pch_different_branch) << ASTBranch << CurBranch; return VersionMismatch; } 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) { // Read information about the AST file. ModuleKind ImportedKind = (ModuleKind)Record[Idx++]; // Whether we're importing a standard c++ module. bool IsImportingStdCXXModule = Record[Idx++]; // The import location will be the local one for now; we will adjust // all import locations of module imports after the global source // location info are setup, in ReadAST. auto [ImportLoc, ImportModuleFileIndex] = ReadUntranslatedSourceLocation(Record[Idx++]); // The import location must belong to the current module file itself. assert(ImportModuleFileIndex == 0); off_t StoredSize = !IsImportingStdCXXModule ? (off_t)Record[Idx++] : 0; time_t StoredModTime = !IsImportingStdCXXModule ? (time_t)Record[Idx++] : 0; ASTFileSignature StoredSignature; if (!IsImportingStdCXXModule) { auto FirstSignatureByte = Record.begin() + Idx; StoredSignature = ASTFileSignature::create( FirstSignatureByte, FirstSignatureByte + ASTFileSignature::size); Idx += ASTFileSignature::size; } std::string ImportedName = ReadString(Record, Idx); std::string ImportedFile; // For prebuilt and explicit modules first consult the file map for // an override. Note that here we don't search prebuilt module // directories if we're not importing standard c++ module, only the // explicit name to file mappings. Also, we will still verify the // size/signature making sure it is essentially the same file but // perhaps in a different location. if (ImportedKind == MK_PrebuiltModule || ImportedKind == MK_ExplicitModule) ImportedFile = PP.getHeaderSearchInfo().getPrebuiltModuleFileName( ImportedName, /*FileMapOnly*/ !IsImportingStdCXXModule); // For C++20 Modules, we won't record the path to the imported modules // in the BMI if (!IsImportingStdCXXModule) { if (ImportedFile.empty()) { // Use BaseDirectoryAsWritten to ensure we use the same path in the // ModuleCache as when writing. ImportedFile = ReadPath(BaseDirectoryAsWritten, Record, Idx); } else SkipPath(Record, Idx); } else if (ImportedFile.empty()) { Diag(clang::diag::err_failed_to_find_module_file) << ImportedName; return Missing; } // If our client can't cope with us being out of date, we can't cope with // our dependency being missing. unsigned Capabilities = ClientLoadCapabilities; if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Capabilities &= ~ARR_Missing; // Load the AST file. auto Result = ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded, StoredSize, StoredModTime, StoredSignature, Capabilities); // If we diagnosed a problem, produce a backtrace. bool recompilingFinalized = Result == OutOfDate && (Capabilities & ARR_OutOfDate) && getModuleManager().getModuleCache().isPCMFinal(F.FileName); if (isDiagnosedResult(Result, Capabilities) || recompilingFinalized) Diag(diag::note_module_file_imported_by) << F.FileName << !F.ModuleName.empty() << F.ModuleName; if (recompilingFinalized) Diag(diag::note_module_file_conflict); switch (Result) { case Failure: return Failure; // If we have to ignore the dependency, we'll have to ignore this too. case Missing: case OutOfDate: return OutOfDate; case VersionMismatch: return VersionMismatch; case ConfigurationMismatch: return ConfigurationMismatch; case HadErrors: return HadErrors; case Success: break; } } break; } case ORIGINAL_FILE: F.OriginalSourceFileID = FileID::get(Record[0]); F.ActualOriginalSourceFileName = std::string(Blob); F.OriginalSourceFileName = F.ActualOriginalSourceFileName; ResolveImportedPath(F, F.OriginalSourceFileName); break; case ORIGINAL_FILE_ID: F.OriginalSourceFileID = FileID::get(Record[0]); break; case MODULE_NAME: F.ModuleName = std::string(Blob); Diag(diag::remark_module_import) << F.ModuleName << F.FileName << (ImportedBy ? true : false) << (ImportedBy ? StringRef(ImportedBy->ModuleName) : StringRef()); 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: { // Save the BaseDirectory as written in the PCM for computing the module // filename for the ModuleCache. BaseDirectoryAsWritten = Blob; assert(!F.ModuleName.empty() && "MODULE_DIRECTORY found before MODULE_NAME"); F.BaseDirectory = std::string(Blob); if (!PP.getPreprocessorOpts().ModulesCheckRelocated) break; // If we've already loaded a module map file covering this module, we may // have a better path for it (relative to the current build). Module *M = PP.getHeaderSearchInfo().lookupModule( F.ModuleName, SourceLocation(), /*AllowSearch*/ true, /*AllowExtraModuleMapSearch*/ true); if (M && M->Directory) { // If we're implicitly loading a module, the base directory can't // change between the build and use. // Don't emit module relocation error if we have -fno-validate-pch if (!bool(PP.getPreprocessorOpts().DisablePCHOrModuleValidation & DisableValidationForModuleKind::Module) && F.Kind != MK_ExplicitModule && F.Kind != MK_PrebuiltModule) { auto BuildDir = PP.getFileManager().getOptionalDirectoryRef(Blob); if (!BuildDir || *BuildDir != M->Directory) { if (!canRecoverFromOutOfDate(F.FileName, ClientLoadCapabilities)) Diag(diag::err_imported_module_relocated) << F.ModuleName << Blob << M->Directory->getName(); return OutOfDate; } } F.BaseDirectory = std::string(M->Directory->getName()); } break; } case MODULE_MAP_FILE: if (ASTReadResult Result = ReadModuleMapFileBlock(Record, F, ImportedBy, ClientLoadCapabilities)) return Result; break; case INPUT_FILE_OFFSETS: NumInputs = Record[0]; NumUserInputs = Record[1]; F.InputFileOffsets = (const llvm::support::unaligned_uint64_t *)Blob.data(); F.InputFilesLoaded.resize(NumInputs); F.InputFileInfosLoaded.resize(NumInputs); F.NumUserInputFiles = NumUserInputs; break; } } } llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { BitstreamCursor &Stream = F.Stream; if (llvm::Error Err = Stream.EnterSubBlock(AST_BLOCK_ID)) return Err; F.ASTBlockStartOffset = Stream.GetCurrentBitNo(); // Read all of the records and blocks for the AST file. RecordData Record; while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: return llvm::createStringError( std::errc::illegal_byte_sequence, "error at end of module block in AST file"); case llvm::BitstreamEntry::EndBlock: // Outside of C++, we do not store a lookup map for the translation unit. // Instead, mark it as needing a lookup map to be built if this module // 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++. if (ASTContext *Ctx = ContextObj) { DeclContext *DC = Ctx->getTranslationUnitDecl(); if (DC->hasExternalLexicalStorage() && !Ctx->getLangOpts().CPlusPlus) DC->setMustBuildLookupTable(); } return llvm::Error::success(); case llvm::BitstreamEntry::SubBlock: switch (Entry.ID) { case DECLTYPES_BLOCK_ID: // We lazily load the decls block, but we want to set up the // DeclsCursor cursor to point into it. Clone our current bitcode // cursor to it, enter the block and read the abbrevs in that block. // With the main cursor, we just skip over it. F.DeclsCursor = Stream; if (llvm::Error Err = Stream.SkipBlock()) return Err; if (llvm::Error Err = ReadBlockAbbrevs( F.DeclsCursor, DECLTYPES_BLOCK_ID, &F.DeclsBlockStartOffset)) return Err; break; case PREPROCESSOR_BLOCK_ID: F.MacroCursor = Stream; if (!PP.getExternalSource()) PP.setExternalSource(this); if (llvm::Error Err = Stream.SkipBlock()) return Err; if (llvm::Error Err = ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) return Err; F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo(); break; case PREPROCESSOR_DETAIL_BLOCK_ID: F.PreprocessorDetailCursor = Stream; if (llvm::Error Err = Stream.SkipBlock()) { return Err; } if (llvm::Error Err = ReadBlockAbbrevs(F.PreprocessorDetailCursor, PREPROCESSOR_DETAIL_BLOCK_ID)) return Err; F.PreprocessorDetailStartOffset = F.PreprocessorDetailCursor.GetCurrentBitNo(); if (!PP.getPreprocessingRecord()) PP.createPreprocessingRecord(); if (!PP.getPreprocessingRecord()->getExternalSource()) PP.getPreprocessingRecord()->SetExternalSource(*this); break; case SOURCE_MANAGER_BLOCK_ID: if (llvm::Error Err = ReadSourceManagerBlock(F)) return Err; break; case SUBMODULE_BLOCK_ID: if (llvm::Error Err = ReadSubmoduleBlock(F, ClientLoadCapabilities)) return Err; break; case COMMENTS_BLOCK_ID: { BitstreamCursor C = Stream; if (llvm::Error Err = Stream.SkipBlock()) return Err; if (llvm::Error Err = ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) return Err; CommentsCursors.push_back(std::make_pair(C, &F)); break; } default: if (llvm::Error Err = Stream.SkipBlock()) return Err; break; } continue; case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read and process a record. Record.clear(); StringRef Blob; Expected MaybeRecordType = Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecordType) return MaybeRecordType.takeError(); ASTRecordTypes RecordType = (ASTRecordTypes)MaybeRecordType.get(); // 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_ASSUME_NONNULL_LOC: case PP_CONDITIONAL_STACK: case PP_COUNTER_VALUE: case SOURCE_LOCATION_OFFSETS: case MODULE_OFFSET_MAP: case SOURCE_MANAGER_LINE_TABLE: case PPD_ENTITIES_OFFSETS: case HEADER_SEARCH_TABLE: case IMPORTED_MODULES: case MACRO_OFFSET: break; default: continue; } } switch (RecordType) { default: // Default behavior: ignore. break; case TYPE_OFFSET: { if (F.LocalNumTypes != 0) return llvm::createStringError( std::errc::illegal_byte_sequence, "duplicate TYPE_OFFSET record in AST file"); F.TypeOffsets = reinterpret_cast(Blob.data()); F.LocalNumTypes = Record[0]; F.BaseTypeIndex = getTotalNumTypes(); if (F.LocalNumTypes > 0) TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes); break; } case DECL_OFFSET: { if (F.LocalNumDecls != 0) return llvm::createStringError( std::errc::illegal_byte_sequence, "duplicate DECL_OFFSET record in AST file"); F.DeclOffsets = (const DeclOffset *)Blob.data(); F.LocalNumDecls = Record[0]; F.BaseDeclIndex = getTotalNumDecls(); if (F.LocalNumDecls > 0) DeclsLoaded.resize(DeclsLoaded.size() + F.LocalNumDecls); break; } case TU_UPDATE_LEXICAL: { DeclContext *TU = ContextObj->getTranslationUnitDecl(); LexicalContents Contents( reinterpret_cast(Blob.data()), static_cast(Blob.size() / sizeof(DeclID))); TULexicalDecls.push_back(std::make_pair(&F, Contents)); TU->setHasExternalLexicalStorage(true); break; } case UPDATE_VISIBLE: { unsigned Idx = 0; GlobalDeclID ID = ReadDeclID(F, Record, Idx); auto *Data = (const unsigned char*)Blob.data(); PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data}); // If we've already loaded the decl, perform the updates when we finish // loading this block. if (Decl *D = GetExistingDecl(ID)) PendingUpdateRecords.push_back( PendingUpdateRecord(ID, D, /*JustLoaded=*/false)); break; } case IDENTIFIER_TABLE: F.IdentifierTableData = reinterpret_cast(Blob.data()); if (Record[0]) { F.IdentifierLookupTable = ASTIdentifierLookupTable::Create( F.IdentifierTableData + Record[0], F.IdentifierTableData + sizeof(uint32_t), F.IdentifierTableData, ASTIdentifierLookupTrait(*this, F)); PP.getIdentifierTable().setExternalIdentifierLookup(this); } break; case IDENTIFIER_OFFSET: { if (F.LocalNumIdentifiers != 0) return llvm::createStringError( std::errc::illegal_byte_sequence, "duplicate IDENTIFIER_OFFSET record in AST file"); F.IdentifierOffsets = (const uint32_t *)Blob.data(); F.LocalNumIdentifiers = Record[0]; F.BaseIdentifierID = getTotalNumIdentifiers(); if (F.LocalNumIdentifiers > 0) IdentifiersLoaded.resize(IdentifiersLoaded.size() + F.LocalNumIdentifiers); break; } case INTERESTING_IDENTIFIERS: F.PreloadIdentifierOffsets.assign(Record.begin(), Record.end()); break; case EAGERLY_DESERIALIZED_DECLS: // FIXME: Skip reading this record if our ASTConsumer doesn't care // about "interesting" decls (for instance, if we're building a module). for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) EagerlyDeserializedDecls.push_back(ReadDeclID(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 || getContext().getLangOpts().BuildingPCHWithObjectFile) for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) EagerlyDeserializedDecls.push_back(ReadDeclID(F, Record, I)); break; case SPECIAL_TYPES: if (SpecialTypes.empty()) { for (unsigned I = 0, N = Record.size(); I != N; ++I) SpecialTypes.push_back(getGlobalTypeID(F, Record[I])); break; } if (SpecialTypes.size() != Record.size()) return llvm::createStringError(std::errc::illegal_byte_sequence, "invalid special-types record"); for (unsigned I = 0, N = Record.size(); I != N; ++I) { serialization::TypeID ID = getGlobalTypeID(F, Record[I]); if (!SpecialTypes[I]) SpecialTypes[I] = ID; // FIXME: If ID && SpecialTypes[I] != ID, do we need a separate // merge step? } break; case STATISTICS: TotalNumStatements += Record[0]; TotalNumMacros += Record[1]; TotalLexicalDeclContexts += Record[2]; TotalVisibleDeclContexts += Record[3]; break; case UNUSED_FILESCOPED_DECLS: for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) UnusedFileScopedDecls.push_back(ReadDeclID(F, Record, I)); break; case DELEGATING_CTORS: for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) DelegatingCtorDecls.push_back(ReadDeclID(F, Record, I)); break; case WEAK_UNDECLARED_IDENTIFIERS: if (Record.size() % 3 != 0) return llvm::createStringError(std::errc::illegal_byte_sequence, "invalid weak identifiers record"); // FIXME: Ignore weak undeclared identifiers from non-original PCH // files. This isn't the way to do it :) WeakUndeclaredIdentifiers.clear(); // Translate the weak, undeclared identifiers into global IDs. for (unsigned I = 0, N = Record.size(); I < N; /* in loop */) { WeakUndeclaredIdentifiers.push_back( getGlobalIdentifierID(F, Record[I++])); WeakUndeclaredIdentifiers.push_back( getGlobalIdentifierID(F, Record[I++])); WeakUndeclaredIdentifiers.push_back( ReadSourceLocation(F, Record, I).getRawEncoding()); } break; case SELECTOR_OFFSETS: { F.SelectorOffsets = (const uint32_t *)Blob.data(); F.LocalNumSelectors = Record[0]; unsigned LocalBaseSelectorID = Record[1]; F.BaseSelectorID = getTotalNumSelectors(); if (F.LocalNumSelectors > 0) { // Introduce the global -> local mapping for selectors within this // module. GlobalSelectorMap.insert(std::make_pair(getTotalNumSelectors()+1, &F)); // Introduce the local -> global mapping for selectors within this // module. F.SelectorRemap.insertOrReplace( std::make_pair(LocalBaseSelectorID, F.BaseSelectorID - LocalBaseSelectorID)); SelectorsLoaded.resize(SelectorsLoaded.size() + F.LocalNumSelectors); } break; } case METHOD_POOL: F.SelectorLookupTableData = (const unsigned char *)Blob.data(); if (Record[0]) F.SelectorLookupTable = ASTSelectorLookupTable::Create( F.SelectorLookupTableData + Record[0], F.SelectorLookupTableData, ASTSelectorLookupTrait(*this, F)); TotalNumMethodPoolEntries += Record[1]; break; case REFERENCED_SELECTOR_POOL: if (!Record.empty()) { for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) { ReferencedSelectorsData.push_back(getGlobalSelectorID(F, Record[Idx++])); ReferencedSelectorsData.push_back(ReadSourceLocation(F, Record, Idx). getRawEncoding()); } } break; case PP_ASSUME_NONNULL_LOC: { unsigned Idx = 0; if (!Record.empty()) PP.setPreambleRecordedPragmaAssumeNonNullLoc( ReadSourceLocation(F, Record, Idx)); break; } case PP_UNSAFE_BUFFER_USAGE: { if (!Record.empty()) { SmallVector SrcLocs; unsigned Idx = 0; while (Idx < Record.size()) SrcLocs.push_back(ReadSourceLocation(F, Record, Idx)); PP.setDeserializedSafeBufferOptOutMap(SrcLocs); } break; } case PP_CONDITIONAL_STACK: if (!Record.empty()) { unsigned Idx = 0, End = Record.size() - 1; bool ReachedEOFWhileSkipping = Record[Idx++]; std::optional SkipInfo; if (ReachedEOFWhileSkipping) { SourceLocation HashToken = ReadSourceLocation(F, Record, Idx); SourceLocation IfTokenLoc = ReadSourceLocation(F, Record, Idx); bool FoundNonSkipPortion = Record[Idx++]; bool FoundElse = Record[Idx++]; SourceLocation ElseLoc = ReadSourceLocation(F, Record, Idx); SkipInfo.emplace(HashToken, IfTokenLoc, FoundNonSkipPortion, FoundElse, ElseLoc); } SmallVector ConditionalStack; while (Idx < End) { 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, SkipInfo); } break; case PP_COUNTER_VALUE: if (!Record.empty() && Listener) Listener->ReadCounter(F, Record[0]); break; case FILE_SORTED_DECLS: F.FileSortedDecls = (const unaligned_decl_id_t *)Blob.data(); F.NumFileSortedDecls = Record[0]; break; case SOURCE_LOCATION_OFFSETS: { F.SLocEntryOffsets = (const uint32_t *)Blob.data(); F.LocalNumSLocEntries = Record[0]; SourceLocation::UIntTy SLocSpaceSize = Record[1]; F.SLocEntryOffsetsBase = Record[2] + F.SourceManagerBlockStartOffset; std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) = SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries, SLocSpaceSize); if (!F.SLocEntryBaseID) { if (!Diags.isDiagnosticInFlight()) { Diags.Report(SourceLocation(), diag::remark_sloc_usage); SourceMgr.noteSLocAddressSpaceUsage(Diags); } return llvm::createStringError(std::errc::invalid_argument, "ran out of source locations"); } // Make our entry in the range map. BaseID is negative and growing, so // we invert it. Because we invert it, though, we need the other end of // the range. unsigned RangeStart = unsigned(-F.SLocEntryBaseID) - F.LocalNumSLocEntries + 1; GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F)); F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset); // SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing. assert((F.SLocEntryBaseOffset & SourceLocation::MacroIDBit) == 0); GlobalSLocOffsetMap.insert( std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset - SLocSpaceSize,&F)); TotalNumSLocEntries += F.LocalNumSLocEntries; break; } case MODULE_OFFSET_MAP: F.ModuleOffsetMap = Blob; break; case SOURCE_MANAGER_LINE_TABLE: ParseLineTable(F, Record); break; case EXT_VECTOR_DECLS: for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) ExtVectorDecls.push_back(ReadDeclID(F, Record, I)); break; case VTABLE_USES: if (Record.size() % 3 != 0) return llvm::createStringError(std::errc::illegal_byte_sequence, "Invalid VTABLE_USES record"); // Later tables overwrite earlier ones. // FIXME: Modules will have some trouble with this. This is clearly not // the right way to do this. VTableUses.clear(); for (unsigned Idx = 0, N = Record.size(); Idx != N; /* In loop */) { VTableUses.push_back( {ReadDeclID(F, Record, Idx), ReadSourceLocation(F, Record, Idx).getRawEncoding(), (bool)Record[Idx++]}); } break; case PENDING_IMPLICIT_INSTANTIATIONS: if (Record.size() % 2 != 0) return llvm::createStringError( std::errc::illegal_byte_sequence, "Invalid PENDING_IMPLICIT_INSTANTIATIONS block"); for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { PendingInstantiations.push_back( {ReadDeclID(F, Record, I), ReadSourceLocation(F, Record, I).getRawEncoding()}); } break; case SEMA_DECL_REFS: if (Record.size() != 3) return llvm::createStringError(std::errc::illegal_byte_sequence, "Invalid SEMA_DECL_REFS block"); for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) SemaDeclRefs.push_back(ReadDeclID(F, Record, I)); break; case PPD_ENTITIES_OFFSETS: { F.PreprocessedEntityOffsets = (const PPEntityOffset *)Blob.data(); assert(Blob.size() % sizeof(PPEntityOffset) == 0); F.NumPreprocessedEntities = Blob.size() / sizeof(PPEntityOffset); unsigned LocalBasePreprocessedEntityID = Record[0]; unsigned StartingID; if (!PP.getPreprocessingRecord()) PP.createPreprocessingRecord(); if (!PP.getPreprocessingRecord()->getExternalSource()) PP.getPreprocessingRecord()->SetExternalSource(*this); StartingID = PP.getPreprocessingRecord() ->allocateLoadedEntities(F.NumPreprocessedEntities); F.BasePreprocessedEntityID = StartingID; if (F.NumPreprocessedEntities > 0) { // Introduce the global -> local mapping for preprocessed entities in // this module. GlobalPreprocessedEntityMap.insert(std::make_pair(StartingID, &F)); // Introduce the local -> global mapping for preprocessed entities in // this module. F.PreprocessedEntityRemap.insertOrReplace( std::make_pair(LocalBasePreprocessedEntityID, F.BasePreprocessedEntityID - LocalBasePreprocessedEntityID)); } break; } case PPD_SKIPPED_RANGES: { F.PreprocessedSkippedRangeOffsets = (const PPSkippedRange*)Blob.data(); assert(Blob.size() % sizeof(PPSkippedRange) == 0); F.NumPreprocessedSkippedRanges = Blob.size() / sizeof(PPSkippedRange); if (!PP.getPreprocessingRecord()) PP.createPreprocessingRecord(); if (!PP.getPreprocessingRecord()->getExternalSource()) PP.getPreprocessingRecord()->SetExternalSource(*this); F.BasePreprocessedSkippedRangeID = PP.getPreprocessingRecord() ->allocateSkippedRanges(F.NumPreprocessedSkippedRanges); if (F.NumPreprocessedSkippedRanges > 0) GlobalSkippedRangeMap.insert( std::make_pair(F.BasePreprocessedSkippedRangeID, &F)); break; } case DECL_UPDATE_OFFSETS: if (Record.size() % 2 != 0) return llvm::createStringError( std::errc::illegal_byte_sequence, "invalid DECL_UPDATE_OFFSETS block in AST file"); for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) { GlobalDeclID ID = ReadDeclID(F, Record, I); DeclUpdateOffsets[ID].push_back(std::make_pair(&F, Record[I++])); // If we've already loaded the decl, perform the updates when we finish // loading this block. if (Decl *D = GetExistingDecl(ID)) PendingUpdateRecords.push_back( PendingUpdateRecord(ID, D, /*JustLoaded=*/false)); } break; case DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD: { if (Record.size() % 3 != 0) return llvm::createStringError( std::errc::illegal_byte_sequence, "invalid DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD block in AST " "file"); for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) { GlobalDeclID ID = ReadDeclID(F, Record, I); uint64_t BaseOffset = F.DeclsBlockStartOffset; assert(BaseOffset && "Invalid DeclsBlockStartOffset for module file!"); uint64_t LocalLexicalOffset = Record[I++]; uint64_t LexicalOffset = LocalLexicalOffset ? BaseOffset + LocalLexicalOffset : 0; uint64_t LocalVisibleOffset = Record[I++]; uint64_t VisibleOffset = LocalVisibleOffset ? BaseOffset + LocalVisibleOffset : 0; DelayedNamespaceOffsetMap[ID] = {LexicalOffset, VisibleOffset}; assert(!GetExistingDecl(ID) && "We shouldn't load the namespace in the front of delayed " "namespace lexical and visible block"); } break; } case OBJC_CATEGORIES_MAP: if (F.LocalNumObjCCategoriesInMap != 0) return llvm::createStringError( std::errc::illegal_byte_sequence, "duplicate OBJC_CATEGORIES_MAP record in AST file"); F.LocalNumObjCCategoriesInMap = Record[0]; F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)Blob.data(); break; case OBJC_CATEGORIES: F.ObjCCategories.swap(Record); break; case CUDA_SPECIAL_DECL_REFS: // Later tables overwrite earlier ones. // FIXME: Modules will have trouble with this. CUDASpecialDeclRefs.clear(); for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) CUDASpecialDeclRefs.push_back(ReadDeclID(F, Record, I)); break; case HEADER_SEARCH_TABLE: F.HeaderFileInfoTableData = Blob.data(); F.LocalNumHeaderFileInfos = Record[1]; if (Record[0]) { F.HeaderFileInfoTable = HeaderFileInfoLookupTable::Create( (const unsigned char *)F.HeaderFileInfoTableData + Record[0], (const unsigned char *)F.HeaderFileInfoTableData, HeaderFileInfoTrait(*this, F, &PP.getHeaderSearchInfo(), Blob.data() + Record[2])); PP.getHeaderSearchInfo().SetExternalSource(this); if (!PP.getHeaderSearchInfo().getExternalLookup()) PP.getHeaderSearchInfo().SetExternalLookup(this); } break; case FP_PRAGMA_OPTIONS: // Later tables overwrite earlier ones. FPPragmaOptions.swap(Record); break; case OPENCL_EXTENSIONS: for (unsigned I = 0, E = Record.size(); I != E; ) { auto Name = ReadString(Record, I); auto &OptInfo = OpenCLExtensions.OptMap[Name]; OptInfo.Supported = Record[I++] != 0; OptInfo.Enabled = Record[I++] != 0; OptInfo.WithPragma = Record[I++] != 0; OptInfo.Avail = Record[I++]; OptInfo.Core = Record[I++]; OptInfo.Opt = Record[I++]; } break; case TENTATIVE_DEFINITIONS: for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) TentativeDefinitions.push_back(ReadDeclID(F, Record, I)); break; case KNOWN_NAMESPACES: for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) KnownNamespaces.push_back(ReadDeclID(F, Record, I)); break; case UNDEFINED_BUT_USED: if (Record.size() % 2 != 0) return llvm::createStringError(std::errc::illegal_byte_sequence, "invalid undefined-but-used record"); for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { UndefinedButUsed.push_back( {ReadDeclID(F, Record, I), ReadSourceLocation(F, Record, I).getRawEncoding()}); } break; case DELETE_EXPRS_TO_ANALYZE: for (unsigned I = 0, N = Record.size(); I != N;) { DelayedDeleteExprs.push_back(ReadDeclID(F, Record, I).getRawValue()); const uint64_t Count = Record[I++]; DelayedDeleteExprs.push_back(Count); for (uint64_t C = 0; C < Count; ++C) { DelayedDeleteExprs.push_back(ReadSourceLocation(F, Record, I).getRawEncoding()); bool IsArrayForm = Record[I++] == 1; DelayedDeleteExprs.push_back(IsArrayForm); } } break; case VTABLES_TO_EMIT: if (F.Kind == MK_MainFile || getContext().getLangOpts().BuildingPCHWithObjectFile) for (unsigned I = 0, N = Record.size(); I != N;) VTablesToEmit.push_back(ReadDeclID(F, Record, I)); break; case IMPORTED_MODULES: if (!F.isModule()) { // If we aren't loading a module (which has its own exports), make // all of the imported modules visible. // FIXME: Deal with macros-only imports. for (unsigned I = 0, N = Record.size(); I != N; /**/) { unsigned GlobalID = getGlobalSubmoduleID(F, Record[I++]); SourceLocation Loc = ReadSourceLocation(F, Record, I); if (GlobalID) { PendingImportedModules.push_back(ImportedSubmodule(GlobalID, Loc)); if (DeserializationListener) DeserializationListener->ModuleImportRead(GlobalID, Loc); } } } break; case MACRO_OFFSET: { if (F.LocalNumMacros != 0) return llvm::createStringError( std::errc::illegal_byte_sequence, "duplicate MACRO_OFFSET record in AST file"); F.MacroOffsets = (const uint32_t *)Blob.data(); F.LocalNumMacros = Record[0]; unsigned LocalBaseMacroID = Record[1]; F.MacroOffsetsBase = Record[2] + F.ASTBlockStartOffset; F.BaseMacroID = getTotalNumMacros(); if (F.LocalNumMacros > 0) { // Introduce the global -> local mapping for macros within this module. GlobalMacroMap.insert(std::make_pair(getTotalNumMacros() + 1, &F)); // Introduce the local -> global mapping for macros within this module. F.MacroRemap.insertOrReplace( std::make_pair(LocalBaseMacroID, F.BaseMacroID - LocalBaseMacroID)); MacrosLoaded.resize(MacrosLoaded.size() + F.LocalNumMacros); } break; } case LATE_PARSED_TEMPLATE: LateParsedTemplates.emplace_back( std::piecewise_construct, std::forward_as_tuple(&F), std::forward_as_tuple(Record.begin(), Record.end())); break; case OPTIMIZE_PRAGMA_OPTIONS: if (Record.size() != 1) return llvm::createStringError(std::errc::illegal_byte_sequence, "invalid pragma optimize record"); OptimizeOffPragmaLocation = ReadSourceLocation(F, Record[0]); break; case MSSTRUCT_PRAGMA_OPTIONS: if (Record.size() != 1) return llvm::createStringError(std::errc::illegal_byte_sequence, "invalid pragma ms_struct record"); PragmaMSStructState = Record[0]; break; case POINTERS_TO_MEMBERS_PRAGMA_OPTIONS: if (Record.size() != 2) return llvm::createStringError( std::errc::illegal_byte_sequence, "invalid pragma pointers to members record"); PragmaMSPointersToMembersState = Record[0]; PointersToMembersPragmaLocation = ReadSourceLocation(F, Record[1]); break; case UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES: for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) UnusedLocalTypedefNameCandidates.push_back(ReadDeclID(F, Record, I)); break; case CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH: if (Record.size() != 1) return llvm::createStringError(std::errc::illegal_byte_sequence, "invalid cuda pragma options record"); ForceHostDeviceDepth = Record[0]; break; case ALIGN_PACK_PRAGMA_OPTIONS: { if (Record.size() < 3) return llvm::createStringError(std::errc::illegal_byte_sequence, "invalid pragma pack record"); PragmaAlignPackCurrentValue = ReadAlignPackInfo(Record[0]); PragmaAlignPackCurrentLocation = ReadSourceLocation(F, Record[1]); unsigned NumStackEntries = Record[2]; unsigned Idx = 3; // Reset the stack when importing a new module. PragmaAlignPackStack.clear(); for (unsigned I = 0; I < NumStackEntries; ++I) { PragmaAlignPackStackEntry Entry; Entry.Value = ReadAlignPackInfo(Record[Idx++]); Entry.Location = ReadSourceLocation(F, Record[Idx++]); Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]); PragmaAlignPackStrings.push_back(ReadString(Record, Idx)); Entry.SlotLabel = PragmaAlignPackStrings.back(); PragmaAlignPackStack.push_back(Entry); } break; } case FLOAT_CONTROL_PRAGMA_OPTIONS: { if (Record.size() < 3) return llvm::createStringError(std::errc::illegal_byte_sequence, "invalid pragma float control record"); FpPragmaCurrentValue = FPOptionsOverride::getFromOpaqueInt(Record[0]); FpPragmaCurrentLocation = ReadSourceLocation(F, Record[1]); unsigned NumStackEntries = Record[2]; unsigned Idx = 3; // Reset the stack when importing a new module. FpPragmaStack.clear(); for (unsigned I = 0; I < NumStackEntries; ++I) { FpPragmaStackEntry Entry; Entry.Value = FPOptionsOverride::getFromOpaqueInt(Record[Idx++]); Entry.Location = ReadSourceLocation(F, Record[Idx++]); Entry.PushLocation = ReadSourceLocation(F, Record[Idx++]); FpPragmaStrings.push_back(ReadString(Record, Idx)); Entry.SlotLabel = FpPragmaStrings.back(); FpPragmaStack.push_back(Entry); } break; } case DECLS_TO_CHECK_FOR_DEFERRED_DIAGS: for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/) DeclsToCheckForDeferredDiags.insert(ReadDeclID(F, Record, I)); 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(); using RemapBuilder = ContinuousRangeMap::Builder; RemapBuilder MacroRemap(F.MacroRemap); RemapBuilder PreprocessedEntityRemap(F.PreprocessedEntityRemap); RemapBuilder SubmoduleRemap(F.SubmoduleRemap); RemapBuilder SelectorRemap(F.SelectorRemap); auto &ImportedModuleVector = F.TransitiveImports; assert(ImportedModuleVector.empty()); while (Data < DataEnd) { // FIXME: Looking up dependency modules by filename is horrible. Let's // start fixing this with prebuilt, explicit and implicit modules and see // how it goes... using namespace llvm::support; ModuleKind Kind = static_cast( endian::readNext(Data)); uint16_t Len = endian::readNext(Data); StringRef Name = StringRef((const char*)Data, Len); Data += Len; ModuleFile *OM = (Kind == MK_PrebuiltModule || Kind == MK_ExplicitModule || Kind == MK_ImplicitModule ? ModuleMgr.lookupByModuleName(Name) : ModuleMgr.lookupByFileName(Name)); if (!OM) { std::string Msg = "refers to unknown module, cannot find "; Msg.append(std::string(Name)); Error(Msg); return; } ImportedModuleVector.push_back(OM); uint32_t MacroIDOffset = endian::readNext(Data); uint32_t PreprocessedEntityIDOffset = endian::readNext(Data); uint32_t SubmoduleIDOffset = endian::readNext(Data); uint32_t SelectorIDOffset = endian::readNext(Data); auto mapOffset = [&](uint32_t Offset, uint32_t BaseOffset, RemapBuilder &Remap) { constexpr uint32_t None = std::numeric_limits::max(); if (Offset != None) Remap.insert(std::make_pair(Offset, static_cast(BaseOffset - Offset))); }; mapOffset(MacroIDOffset, OM->BaseMacroID, MacroRemap); mapOffset(PreprocessedEntityIDOffset, OM->BasePreprocessedEntityID, PreprocessedEntityRemap); mapOffset(SubmoduleIDOffset, OM->BaseSubmoduleID, SubmoduleRemap); mapOffset(SelectorIDOffset, OM->BaseSelectorID, SelectorRemap); } } ASTReader::ASTReadResult ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, const ModuleFile *ImportedBy, unsigned ClientLoadCapabilities) { unsigned Idx = 0; F.ModuleMapPath = ReadPath(F, Record, Idx); // 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 (PP.getPreprocessorOpts().ModulesCheckRelocated && 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, F.ImportLoc); auto &Map = PP.getHeaderSearchInfo().getModuleMap(); OptionalFileEntryRef ModMap = M ? Map.getModuleMapFileForUniquing(M) : std::nullopt; // Don't emit module relocation error if we have -fno-validate-pch if (!bool(PP.getPreprocessorOpts().DisablePCHOrModuleValidation & DisableValidationForModuleKind::Module) && !ModMap) { if (!canRecoverFromOutOfDate(F.FileName, ClientLoadCapabilities)) { if (auto ASTFE = M ? M->getASTFile() : std::nullopt) { // This module was defined by an imported (explicit) module. Diag(diag::err_module_file_conflict) << F.ModuleName << F.FileName << ASTFE->getName(); } else { // This module was built with a different module map. Diag(diag::err_imported_module_not_found) << F.ModuleName << F.FileName << (ImportedBy ? ImportedBy->FileName : "") << F.ModuleMapPath << !ImportedBy; // In case it was imported by a PCH, there's a chance the user is // just missing to include the search path to the directory containing // the modulemap. if (ImportedBy && ImportedBy->Kind == MK_PCH) Diag(diag::note_imported_by_pch_module_not_found) << llvm::sys::path::parent_path(F.ModuleMapPath); } } return OutOfDate; } assert(M && M->Name == F.ModuleName && "found module with different name"); // Check the primary module map file. auto StoredModMap = FileMgr.getFile(F.ModuleMapPath); if (!StoredModMap || *StoredModMap != ModMap) { assert(ModMap && "found module is missing module map file"); assert((ImportedBy || F.Kind == MK_ImplicitModule) && "top-level import should be verified"); bool NotImported = F.Kind == MK_ImplicitModule && !ImportedBy; if (!canRecoverFromOutOfDate(F.FileName, ClientLoadCapabilities)) Diag(diag::err_imported_module_modmap_changed) << F.ModuleName << (NotImported ? F.FileName : ImportedBy->FileName) << ModMap->getName() << F.ModuleMapPath << NotImported; return OutOfDate; } ModuleMap::AdditionalModMapsSet AdditionalStoredMaps; for (unsigned I = 0, N = Record[Idx++]; I < N; ++I) { // FIXME: we should use input files rather than storing names. std::string Filename = ReadPath(F, Record, Idx); auto SF = FileMgr.getOptionalFileRef(Filename, false, false); if (!SF) { if (!canRecoverFromOutOfDate(F.FileName, ClientLoadCapabilities)) Error("could not find file '" + Filename +"' referenced by AST file"); return OutOfDate; } AdditionalStoredMaps.insert(*SF); } // Check any additional module map files (e.g. module.private.modulemap) // that are not in the pcm. if (auto *AdditionalModuleMaps = Map.getAdditionalModuleMapFiles(M)) { for (FileEntryRef ModMap : *AdditionalModuleMaps) { // Remove files that match // Note: SmallPtrSet::erase is really remove if (!AdditionalStoredMaps.erase(ModMap)) { if (!canRecoverFromOutOfDate(F.FileName, ClientLoadCapabilities)) Diag(diag::err_module_different_modmap) << F.ModuleName << /*new*/0 << ModMap.getName(); return OutOfDate; } } } // Check any additional module map files that are in the pcm, but not // found in header search. Cases that match are already removed. for (FileEntryRef ModMap : AdditionalStoredMaps) { if (!canRecoverFromOutOfDate(F.FileName, ClientLoadCapabilities)) Diag(diag::err_module_different_modmap) << F.ModuleName << /*not new*/1 << ModMap.getName(); return OutOfDate; } } if (Listener) Listener->ReadModuleMapFile(F.ModuleMapPath); return Success; } /// Move the given method to the back of the global list of methods. static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { // Find the entry for this selector in the method pool. SemaObjC::GlobalMethodPool::iterator Known = S.ObjC().MethodPool.find(Method->getSelector()); if (Known == S.ObjC().MethodPool.end()) return; // Retrieve the appropriate method list. ObjCMethodList &Start = Method->isInstanceMethod()? Known->second.first : Known->second.second; bool Found = false; for (ObjCMethodList *List = &Start; List; List = List->getNext()) { if (!Found) { if (List->getMethod() == Method) { Found = true; } else { // Keep searching. continue; } } if (List->getNext()) List->setMethod(List->getNext()->getMethod()); else List->setMethod(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->isUnconditionallyVisible(); D->setVisibleDespiteOwningModule(); if (wasHidden && SemaObj) { if (ObjCMethodDecl *Method = dyn_cast(D)) { moveMethodToBackOfGlobalList(*SemaObj, Method); } } } } void ASTReader::makeModuleVisible(Module *Mod, Module::NameVisibilityKind NameVisibility, SourceLocation ImportLoc) { llvm::SmallPtrSet Visited; SmallVector Stack; Stack.push_back(Mod); while (!Stack.empty()) { Mod = Stack.pop_back_val(); if (NameVisibility <= Mod->NameVisibility) { // This module already has this level of visibility (or greater), so // there is nothing more to do. continue; } if (Mod->isUnimportable()) { // Modules that aren't importable cannot be made visible. continue; } // Update the module's name visibility. Mod->NameVisibility = NameVisibility; // If we've already deserialized any names from this module, // mark them as visible. HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod); if (Hidden != HiddenNamesMap.end()) { auto HiddenNames = std::move(*Hidden); HiddenNamesMap.erase(Hidden); makeNamesVisible(HiddenNames.second, HiddenNames.first); assert(!HiddenNamesMap.contains(Mod) && "making names visible added hidden names"); } // Push any exported modules onto the stack to be marked as visible. SmallVector Exports; Mod->getExportedModules(Exports); for (SmallVectorImpl::iterator I = Exports.begin(), E = Exports.end(); I != E; ++I) { Module *Exported = *I; if (Visited.insert(Exported).second) Stack.push_back(Exported); } } } /// We've merged the definition \p MergedDef into the existing definition /// \p Def. Ensure that \p Def is made visible whenever \p MergedDef is made /// visible. void ASTReader::mergeDefinitionVisibility(NamedDecl *Def, NamedDecl *MergedDef) { if (!Def->isUnconditionallyVisible()) { // If MergedDef is visible or becomes visible, make the definition visible. if (MergedDef->isUnconditionallyVisible()) Def->setVisibleDespiteOwningModule(); else { getContext().mergeDefinitionIntoModule( Def, MergedDef->getImportedOwningModule(), /*NotifyListeners*/ false); PendingMergedDefinitionsToDeduplicate.insert(Def); } } } bool ASTReader::loadGlobalIndex() { if (GlobalIndex) return false; if (TriedLoadingGlobalIndex || !UseGlobalIndex || !PP.getLangOpts().Modules) return true; // Try to load the global index. TriedLoadingGlobalIndex = true; StringRef ModuleCachePath = getPreprocessor().getHeaderSearchInfo().getModuleCachePath(); std::pair Result = GlobalModuleIndex::readIndex(ModuleCachePath); if (llvm::Error Err = std::move(Result.second)) { assert(!Result.first); consumeError(std::move(Err)); // FIXME this drops errors on the floor. return true; } GlobalIndex.reset(Result.first); ModuleMgr.setGlobalIndex(GlobalIndex.get()); return false; } bool ASTReader::isGlobalIndexUnavailable() const { return PP.getLangOpts().Modules && UseGlobalIndex && !hasGlobalIndex() && TriedLoadingGlobalIndex; } static void updateModuleTimestamp(ModuleFile &MF) { // Overwrite the timestamp file contents so that file's mtime changes. std::string TimestampFilename = MF.getTimestampFilename(); std::error_code EC; llvm::raw_fd_ostream OS(TimestampFilename, EC, llvm::sys::fs::OF_TextWithCRLF); if (EC) return; OS << "Timestamp file\n"; OS.close(); OS.clear_error(); // Avoid triggering a fatal error. } /// Given a cursor at the start of an AST file, scan ahead and drop the /// cursor into the start of the given block ID, returning false on success and /// true on failure. static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) { while (true) { Expected MaybeEntry = Cursor.advance(); if (!MaybeEntry) { // FIXME this drops errors on the floor. consumeError(MaybeEntry.takeError()); return true; } llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: case llvm::BitstreamEntry::EndBlock: return true; case llvm::BitstreamEntry::Record: // Ignore top-level records. if (Expected Skipped = Cursor.skipRecord(Entry.ID)) break; else { // FIXME this drops errors on the floor. consumeError(Skipped.takeError()); return true; } case llvm::BitstreamEntry::SubBlock: if (Entry.ID == BlockID) { if (llvm::Error Err = Cursor.EnterSubBlock(BlockID)) { // FIXME this drops the error on the floor. consumeError(std::move(Err)); return true; } // Found it! return false; } if (llvm::Error Err = Cursor.SkipBlock()) { // FIXME this drops the error on the floor. consumeError(std::move(Err)); return true; } } } } ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc, unsigned ClientLoadCapabilities, ModuleFile **NewLoadedModuleFile) { llvm::TimeTraceScope scope("ReadAST", FileName); llvm::SaveAndRestore SetCurImportLocRAII(CurrentImportLoc, ImportLoc); llvm::SaveAndRestore> SetCurModuleKindRAII( CurrentDeserializingModuleKind, Type); // Defer any pending actions until we get to the end of reading the AST file. Deserializing AnASTFile(this); // Bump the generation number. unsigned PreviousGeneration = 0; if (ContextObj) PreviousGeneration = incrementGeneration(*ContextObj); unsigned NumModules = ModuleMgr.size(); SmallVector Loaded; if (ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc, /*ImportedBy=*/nullptr, Loaded, 0, 0, ASTFileSignature(), ClientLoadCapabilities)) { ModuleMgr.removeModules(ModuleMgr.begin() + NumModules); // If we find that any modules are unusable, the global index is going // to be out-of-date. Just remove it. GlobalIndex.reset(); ModuleMgr.setGlobalIndex(nullptr); return ReadResult; } if (NewLoadedModuleFile && !Loaded.empty()) *NewLoadedModuleFile = Loaded.back().Mod; // Here comes stuff that we only do once the entire chain is loaded. Do *not* // remove modules from this point. Various fields are updated during reading // the AST block and removing the modules would result in dangling pointers. // They are generally only incidentally dereferenced, ie. a binary search // runs over `GlobalSLocEntryMap`, which could cause an invalid module to // be dereferenced but it wouldn't actually be used. // Load the AST blocks of all of the modules that we loaded. We can still // hit errors parsing the ASTs at this point. for (ImportedModule &M : Loaded) { ModuleFile &F = *M.Mod; llvm::TimeTraceScope Scope2("Read Loaded AST", F.ModuleName); // Read the AST block. if (llvm::Error Err = ReadASTBlock(F, ClientLoadCapabilities)) { Error(std::move(Err)); return Failure; } // The AST block should always have a definition for the main module. if (F.isModule() && !F.DidReadTopLevelSubmodule) { Error(diag::err_module_file_missing_top_level_submodule, F.FileName); return Failure; } // Read the extension blocks. while (!SkipCursorToBlock(F.Stream, EXTENSION_BLOCK_ID)) { if (llvm::Error Err = ReadExtensionBlock(F)) { Error(std::move(Err)); return Failure; } } // Once read, set the ModuleFile bit base offset and update the size in // bits of all files we've seen. F.GlobalBitOffset = TotalModulesSizeInBits; TotalModulesSizeInBits += F.SizeInBits; GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F)); } // Preload source locations and interesting indentifiers. for (ImportedModule &M : Loaded) { ModuleFile &F = *M.Mod; // Map the original source file ID into the ID space of the current // compilation. if (F.OriginalSourceFileID.isValid()) F.OriginalSourceFileID = TranslateFileID(F, F.OriginalSourceFileID); for (auto Offset : F.PreloadIdentifierOffsets) { const unsigned char *Data = F.IdentifierTableData + Offset; ASTIdentifierLookupTrait Trait(*this, F); auto KeyDataLen = Trait.ReadKeyDataLength(Data); auto Key = Trait.ReadKey(Data, KeyDataLen.first); IdentifierInfo *II; if (!PP.getLangOpts().CPlusPlus) { // Identifiers present in both the module file and the importing // instance are marked out-of-date so that they can be deserialized // on next use via ASTReader::updateOutOfDateIdentifier(). // Identifiers present in the module file but not in the importing // instance are ignored for now, preventing growth of the identifier // table. They will be deserialized on first use via ASTReader::get(). auto It = PP.getIdentifierTable().find(Key); if (It == PP.getIdentifierTable().end()) continue; II = It->second; } else { // With C++ modules, not many identifiers are considered interesting. // All identifiers in the module file can be placed into the identifier // table of the importing instance and marked as out-of-date. This makes // ASTReader::get() a no-op, and deserialization will take place on // first/next use via ASTReader::updateOutOfDateIdentifier(). II = &PP.getIdentifierTable().getOwn(Key); } II->setOutOfDate(true); // Mark this identifier as being from an AST file so that we can track // whether we need to serialize it. markIdentifierFromAST(*this, *II); // Associate the ID with the identifier so that the writer can reuse it. auto ID = Trait.ReadIdentifierID(Data + KeyDataLen.first); SetIdentifierInfo(ID, II); } } // Builtins and library builtins have already been initialized. Mark all // identifiers as out-of-date, so that they are deserialized on first use. if (Type == MK_PCH || Type == MK_Preamble || Type == MK_MainFile) for (auto &Id : PP.getIdentifierTable()) Id.second->setOutOfDate(true); // Mark selectors as out of date. for (const auto &Sel : SelectorGeneration) SelectorOutOfDate[Sel.first] = true; // Setup the import locations and notify the module manager that we've // committed to these module files. for (ImportedModule &M : Loaded) { ModuleFile &F = *M.Mod; ModuleMgr.moduleFileAccepted(&F); // Set the import location. F.DirectImportLoc = ImportLoc; // FIXME: We assume that locations from PCH / preamble do not need // any translation. if (!M.ImportedBy) F.ImportLoc = M.ImportLoc; else F.ImportLoc = TranslateSourceLocation(*M.ImportedBy, M.ImportLoc); } // Resolve any unresolved module exports. for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) { UnresolvedModuleRef &Unresolved = UnresolvedModuleRefs[I]; SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID); Module *ResolvedMod = getSubmodule(GlobalID); switch (Unresolved.Kind) { case UnresolvedModuleRef::Conflict: if (ResolvedMod) { Module::Conflict Conflict; Conflict.Other = ResolvedMod; Conflict.Message = Unresolved.String.str(); Unresolved.Mod->Conflicts.push_back(Conflict); } continue; case UnresolvedModuleRef::Import: if (ResolvedMod) Unresolved.Mod->Imports.insert(ResolvedMod); continue; case UnresolvedModuleRef::Affecting: if (ResolvedMod) Unresolved.Mod->AffectingClangModules.insert(ResolvedMod); continue; case UnresolvedModuleRef::Export: if (ResolvedMod || Unresolved.IsWildcard) Unresolved.Mod->Exports.push_back( Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard)); continue; } } UnresolvedModuleRefs.clear(); // FIXME: How do we load the 'use'd modules? They may not be submodules. // Might be unnecessary as use declarations are only used to build the // module itself. if (ContextObj) InitializeContext(); if (SemaObj) UpdateSema(); if (DeserializationListener) DeserializationListener->ReaderInitialized(this); ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule(); if (PrimaryModule.OriginalSourceFileID.isValid()) { // 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. if (Type == MK_Preamble) { SourceMgr.setPreambleFileID(PrimaryModule.OriginalSourceFileID); } else if (Type == MK_MainFile) { SourceMgr.setMainFileID(PrimaryModule.OriginalSourceFileID); } } // For any Objective-C class definitions we have already loaded, make sure // that we load any additional categories. if (ContextObj) { for (unsigned I = 0, N = ObjCClassesLoaded.size(); I != N; ++I) { loadObjCCategories(ObjCClassesLoaded[I]->getGlobalID(), ObjCClassesLoaded[I], PreviousGeneration); } } HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); if (HSOpts.ModulesValidateOncePerBuildSession) { // Now we are certain that the module and all modules it depends on are // up-to-date. For implicitly-built module files, ensure the corresponding // timestamp files are up-to-date in this build session. for (unsigned I = 0, N = Loaded.size(); I != N; ++I) { ImportedModule &M = Loaded[I]; if (M.Mod->Kind == MK_ImplicitModule && M.Mod->InputFilesValidationTimestamp < HSOpts.BuildSessionTimestamp) updateModuleTimestamp(*M.Mod); } } return Success; } static ASTFileSignature readASTFileSignature(StringRef PCH); /// Whether \p Stream doesn't start with the AST/PCH file magic number 'CPCH'. static llvm::Error doesntStartWithASTFileMagic(BitstreamCursor &Stream) { // FIXME checking magic headers is done in other places such as // SerializedDiagnosticReader and GlobalModuleIndex, but error handling isn't // always done the same. Unify it all with a helper. if (!Stream.canSkipToPos(4)) return llvm::createStringError(std::errc::illegal_byte_sequence, "file too small to contain AST file magic"); for (unsigned C : {'C', 'P', 'C', 'H'}) if (Expected Res = Stream.Read(8)) { if (Res.get() != C) return llvm::createStringError( std::errc::illegal_byte_sequence, "file doesn't start with AST file magic"); } else return Res.takeError(); return llvm::Error::success(); } static unsigned moduleKindForDiagnostic(ModuleKind Kind) { switch (Kind) { case MK_PCH: return 0; // PCH case MK_ImplicitModule: case MK_ExplicitModule: case MK_PrebuiltModule: return 1; // module case MK_MainFile: case MK_Preamble: return 2; // main source file } llvm_unreachable("unknown module kind"); } ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc, ModuleFile *ImportedBy, SmallVectorImpl &Loaded, off_t ExpectedSize, time_t ExpectedModTime, ASTFileSignature ExpectedSignature, unsigned ClientLoadCapabilities) { ModuleFile *M; std::string ErrorStr; ModuleManager::AddModuleResult AddResult = ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy, getGeneration(), ExpectedSize, ExpectedModTime, ExpectedSignature, readASTFileSignature, M, ErrorStr); switch (AddResult) { case ModuleManager::AlreadyLoaded: Diag(diag::remark_module_import) << M->ModuleName << M->FileName << (ImportedBy ? true : false) << (ImportedBy ? StringRef(ImportedBy->ModuleName) : StringRef()); return Success; case ModuleManager::NewlyLoaded: // Load module file below. break; case ModuleManager::Missing: // The module file was missing; if the client can handle that, return // it. if (ClientLoadCapabilities & ARR_Missing) return Missing; // Otherwise, return an error. Diag(diag::err_ast_file_not_found) << moduleKindForDiagnostic(Type) << FileName << !ErrorStr.empty() << ErrorStr; return Failure; case ModuleManager::OutOfDate: // We couldn't load the module file because it is out-of-date. If the // client can handle out-of-date, return it. if (ClientLoadCapabilities & ARR_OutOfDate) return OutOfDate; // Otherwise, return an error. Diag(diag::err_ast_file_out_of_date) << moduleKindForDiagnostic(Type) << FileName << !ErrorStr.empty() << ErrorStr; return Failure; } assert(M && "Missing module file"); bool ShouldFinalizePCM = false; auto FinalizeOrDropPCM = llvm::make_scope_exit([&]() { auto &MC = getModuleManager().getModuleCache(); if (ShouldFinalizePCM) MC.finalizePCM(FileName); else MC.tryToDropPCM(FileName); }); ModuleFile &F = *M; BitstreamCursor &Stream = F.Stream; Stream = BitstreamCursor(PCHContainerRdr.ExtractPCH(*F.Buffer)); F.SizeInBits = F.Buffer->getBufferSize() * 8; // Sniff for the signature. if (llvm::Error Err = doesntStartWithASTFileMagic(Stream)) { Diag(diag::err_ast_file_invalid) << moduleKindForDiagnostic(Type) << FileName << std::move(Err); return Failure; } // This is used for compatibility with older PCH formats. bool HaveReadControlBlock = false; while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) { Error(MaybeEntry.takeError()); return Failure; } llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: case llvm::BitstreamEntry::Record: case llvm::BitstreamEntry::EndBlock: Error("invalid record at top-level of AST file"); return Failure; case llvm::BitstreamEntry::SubBlock: break; } switch (Entry.ID) { case CONTROL_BLOCK_ID: HaveReadControlBlock = true; switch (ReadControlBlock(F, Loaded, ImportedBy, ClientLoadCapabilities)) { case Success: // Check that we didn't try to load a non-module AST file as a module. // // FIXME: Should we also perform the converse check? Loading a module as // a PCH file sort of works, but it's a bit wonky. if ((Type == MK_ImplicitModule || Type == MK_ExplicitModule || Type == MK_PrebuiltModule) && F.ModuleName.empty()) { auto Result = (Type == MK_ImplicitModule) ? OutOfDate : Failure; if (Result != OutOfDate || (ClientLoadCapabilities & ARR_OutOfDate) == 0) Diag(diag::err_module_file_not_module) << FileName; return Result; } break; case Failure: return Failure; case Missing: return Missing; case OutOfDate: return OutOfDate; case VersionMismatch: return VersionMismatch; case ConfigurationMismatch: return ConfigurationMismatch; case HadErrors: return HadErrors; } break; case AST_BLOCK_ID: if (!HaveReadControlBlock) { if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) Diag(diag::err_pch_version_too_old); return VersionMismatch; } // Record that we've loaded this module. Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc)); ShouldFinalizePCM = true; return Success; default: if (llvm::Error Err = Stream.SkipBlock()) { Error(std::move(Err)); return Failure; } break; } } llvm_unreachable("unexpected break; expected return"); } 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; bool DisableValidation = shouldDisableValidationForFile(F); 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 ModuleCache, 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 (getModuleManager().getModuleCache().isPCMFinal(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 (llvm::Error Err = doesntStartWithASTFileMagic(Stream)) { // FIXME this drops the error on the floor. consumeError(std::move(Err)); 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 (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) { // FIXME this drops the error on the floor. consumeError(MaybeEntry.takeError()); return Failure; } llvm::BitstreamEntry Entry = MaybeEntry.get(); 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(); StringRef Blob; Expected MaybeRecordType = Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecordType) { // FIXME this drops the error. return Failure; } switch ((UnhashedControlBlockRecordTypes)MaybeRecordType.get()) { case SIGNATURE: if (F) { F->Signature = ASTFileSignature::create(Blob.begin(), Blob.end()); assert(F->Signature != ASTFileSignature::createDummy() && "Dummy AST file signature not backpatched in ASTWriter."); } break; case AST_BLOCK_HASH: if (F) { F->ASTBlockHash = ASTFileSignature::create(Blob.begin(), Blob.end()); assert(F->ASTBlockHash != ASTFileSignature::createDummy() && "Dummy AST block hash not backpatched in ASTWriter."); } 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 HEADER_SEARCH_PATHS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; if (Listener && !AllowCompatibleConfigurationMismatch && ParseHeaderSearchPaths(Record, Complain, *Listener)) Result = ConfigurationMismatch; 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; case HEADER_SEARCH_ENTRY_USAGE: if (F) F->SearchPathUsage = ReadBitVector(Record, Blob); break; case VFS_USAGE: if (F) F->VFSUsage = ReadBitVector(Record, Blob); break; } } } /// Parse a record and blob containing module file extension metadata. static bool parseModuleFileExtensionMetadata( const SmallVectorImpl &Record, StringRef Blob, ModuleFileExtensionMetadata &Metadata) { if (Record.size() < 4) return true; Metadata.MajorVersion = Record[0]; Metadata.MinorVersion = Record[1]; unsigned BlockNameLen = Record[2]; unsigned UserInfoLen = Record[3]; if (BlockNameLen + UserInfoLen > Blob.size()) return true; Metadata.BlockName = std::string(Blob.data(), Blob.data() + BlockNameLen); Metadata.UserInfo = std::string(Blob.data() + BlockNameLen, Blob.data() + BlockNameLen + UserInfoLen); return false; } llvm::Error ASTReader::ReadExtensionBlock(ModuleFile &F) { BitstreamCursor &Stream = F.Stream; RecordData Record; while (true) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: if (llvm::Error Err = Stream.SkipBlock()) return Err; continue; case llvm::BitstreamEntry::EndBlock: return llvm::Error::success(); case llvm::BitstreamEntry::Error: return llvm::createStringError(std::errc::illegal_byte_sequence, "malformed block record in AST file"); case llvm::BitstreamEntry::Record: break; } Record.clear(); StringRef Blob; Expected MaybeRecCode = Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecCode) return MaybeRecCode.takeError(); switch (MaybeRecCode.get()) { case EXTENSION_METADATA: { ModuleFileExtensionMetadata Metadata; if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) return llvm::createStringError( std::errc::illegal_byte_sequence, "malformed EXTENSION_METADATA in AST file"); // Find a module file extension with this block name. auto Known = ModuleFileExtensions.find(Metadata.BlockName); if (Known == ModuleFileExtensions.end()) break; // Form a reader. if (auto Reader = Known->second->createExtensionReader(Metadata, *this, F, Stream)) { F.ExtensionReaders.push_back(std::move(Reader)); } break; } } } return llvm::Error::success(); } 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( GlobalDeclID(PREDEF_DECL_TRANSLATION_UNIT_ID), Context.getTranslationUnitDecl()); // FIXME: Find a better way to deal with collisions between these // built-in types. Right now, we just ignore the problem. // Load the special types. if (SpecialTypes.size() >= NumSpecialTypeIDs) { if (TypeID String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) { if (!Context.CFConstantStringTypeDecl) Context.setCFConstantStringType(GetType(String)); } if (TypeID File = SpecialTypes[SPECIAL_TYPE_FILE]) { QualType FileType = GetType(File); if (FileType.isNull()) { Error("FILE type is NULL"); return; } if (!Context.FILEDecl) { if (const TypedefType *Typedef = FileType->getAs()) Context.setFILEDecl(Typedef->getDecl()); else { const TagType *Tag = FileType->getAs(); if (!Tag) { Error("Invalid FILE type in AST file"); return; } Context.setFILEDecl(Tag->getDecl()); } } } if (TypeID Jmp_buf = SpecialTypes[SPECIAL_TYPE_JMP_BUF]) { QualType Jmp_bufType = GetType(Jmp_buf); if (Jmp_bufType.isNull()) { Error("jmp_buf type is NULL"); return; } if (!Context.jmp_bufDecl) { if (const TypedefType *Typedef = Jmp_bufType->getAs()) Context.setjmp_bufDecl(Typedef->getDecl()); else { const TagType *Tag = Jmp_bufType->getAs(); if (!Tag) { Error("Invalid jmp_buf type in AST file"); return; } Context.setjmp_bufDecl(Tag->getDecl()); } } } if (TypeID Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_SIGJMP_BUF]) { QualType Sigjmp_bufType = GetType(Sigjmp_buf); if (Sigjmp_bufType.isNull()) { Error("sigjmp_buf type is NULL"); return; } if (!Context.sigjmp_bufDecl) { if (const TypedefType *Typedef = Sigjmp_bufType->getAs()) Context.setsigjmp_bufDecl(Typedef->getDecl()); else { const TagType *Tag = Sigjmp_bufType->getAs(); assert(Tag && "Invalid sigjmp_buf type in AST file"); Context.setsigjmp_bufDecl(Tag->getDecl()); } } } if (TypeID ObjCIdRedef = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) { if (Context.ObjCIdRedefinitionType.isNull()) Context.ObjCIdRedefinitionType = GetType(ObjCIdRedef); } if (TypeID ObjCClassRedef = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) { if (Context.ObjCClassRedefinitionType.isNull()) Context.ObjCClassRedefinitionType = GetType(ObjCClassRedef); } if (TypeID ObjCSelRedef = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) { if (Context.ObjCSelRedefinitionType.isNull()) Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef); } if (TypeID Ucontext_t = SpecialTypes[SPECIAL_TYPE_UCONTEXT_T]) { QualType Ucontext_tType = GetType(Ucontext_t); if (Ucontext_tType.isNull()) { Error("ucontext_t type is NULL"); return; } if (!Context.ucontext_tDecl) { if (const TypedefType *Typedef = Ucontext_tType->getAs()) Context.setucontext_tDecl(Typedef->getDecl()); else { const TagType *Tag = Ucontext_tType->getAs(); assert(Tag && "Invalid ucontext_t type in AST file"); Context.setucontext_tDecl(Tag->getDecl()); } } } } ReadPragmaDiagnosticMappings(Context.getDiagnostics()); // If there were any CUDA special declarations, deserialize them. if (!CUDASpecialDeclRefs.empty()) { assert(CUDASpecialDeclRefs.size() == 1 && "More decl refs than expected!"); Context.setcudaConfigureCallDecl( cast(GetDecl(CUDASpecialDeclRefs[0]))); } // Re-export any modules that were imported by a non-module AST file. // FIXME: This does not make macro-only imports visible again. for (auto &Import : PendingImportedModules) { if (Module *Imported = getSubmodule(Import.ID)) { makeModuleVisible(Imported, Module::AllVisible, /*ImportLoc=*/Import.ImportLoc); if (Import.ImportLoc.isValid()) PP.makeModuleVisible(Imported, Import.ImportLoc); // This updates visibility for Preprocessor only. For Sema, which can be // nullptr here, we do the same later, in UpdateSema(). } } // Hand off these modules to Sema. PendingImportedModulesSema.append(PendingImportedModules); PendingImportedModules.clear(); } void ASTReader::finalizeForWriting() { // Nothing to do for now. } /// Reads and return the signature record from \p PCH's control block, or /// else returns 0. static ASTFileSignature readASTFileSignature(StringRef PCH) { BitstreamCursor Stream(PCH); if (llvm::Error Err = doesntStartWithASTFileMagic(Stream)) { // FIXME this drops the error on the floor. consumeError(std::move(Err)); return ASTFileSignature(); } // Scan for the UNHASHED_CONTROL_BLOCK_ID block. if (SkipCursorToBlock(Stream, UNHASHED_CONTROL_BLOCK_ID)) return ASTFileSignature(); // Scan for SIGNATURE inside the diagnostic options block. ASTReader::RecordData Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) { // FIXME this drops the error on the floor. consumeError(MaybeEntry.takeError()); return ASTFileSignature(); } llvm::BitstreamEntry Entry = MaybeEntry.get(); if (Entry.Kind != llvm::BitstreamEntry::Record) return ASTFileSignature(); Record.clear(); StringRef Blob; Expected MaybeRecord = Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecord) { // FIXME this drops the error on the floor. consumeError(MaybeRecord.takeError()); return ASTFileSignature(); } if (SIGNATURE == MaybeRecord.get()) { auto Signature = ASTFileSignature::create(Blob.begin(), Blob.end()); assert(Signature != ASTFileSignature::createDummy() && "Dummy AST file signature not backpatched in ASTWriter."); return Signature; } } } /// Retrieve the name of the original source file name /// directly from the AST file, without actually loading the AST /// file. std::string ASTReader::getOriginalSourceFile( const std::string &ASTFileName, FileManager &FileMgr, const PCHContainerReader &PCHContainerRdr, DiagnosticsEngine &Diags) { // Open the AST file. auto Buffer = FileMgr.getBufferForFile(ASTFileName, /*IsVolatile=*/false, /*RequiresNullTerminator=*/false); if (!Buffer) { Diags.Report(diag::err_fe_unable_to_read_pch_file) << ASTFileName << Buffer.getError().message(); return std::string(); } // Initialize the stream BitstreamCursor Stream(PCHContainerRdr.ExtractPCH(**Buffer)); // Sniff for the signature. if (llvm::Error Err = doesntStartWithASTFileMagic(Stream)) { Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName << std::move(Err); return std::string(); } // Scan for the CONTROL_BLOCK_ID block. if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) { Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; return std::string(); } // Scan for ORIGINAL_FILE inside the control block. RecordData Record; while (true) { Expected MaybeEntry = Stream.advanceSkippingSubblocks(); if (!MaybeEntry) { // FIXME this drops errors on the floor. consumeError(MaybeEntry.takeError()); return std::string(); } llvm::BitstreamEntry Entry = MaybeEntry.get(); if (Entry.Kind == llvm::BitstreamEntry::EndBlock) return std::string(); if (Entry.Kind != llvm::BitstreamEntry::Record) { Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; return std::string(); } Record.clear(); StringRef Blob; Expected MaybeRecord = Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecord) { // FIXME this drops the errors on the floor. consumeError(MaybeRecord.takeError()); return std::string(); } if (ORIGINAL_FILE == MaybeRecord.get()) return Blob.str(); } } namespace { class SimplePCHValidator : public ASTReaderListener { const LangOptions &ExistingLangOpts; const TargetOptions &ExistingTargetOpts; const PreprocessorOptions &ExistingPPOpts; std::string ExistingModuleCachePath; FileManager &FileMgr; bool StrictOptionMatches; public: SimplePCHValidator(const LangOptions &ExistingLangOpts, const TargetOptions &ExistingTargetOpts, const PreprocessorOptions &ExistingPPOpts, StringRef ExistingModuleCachePath, FileManager &FileMgr, bool StrictOptionMatches) : ExistingLangOpts(ExistingLangOpts), ExistingTargetOpts(ExistingTargetOpts), ExistingPPOpts(ExistingPPOpts), ExistingModuleCachePath(ExistingModuleCachePath), FileMgr(FileMgr), StrictOptionMatches(StrictOptionMatches) {} bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, bool AllowCompatibleDifferences) override { return checkLanguageOptions(ExistingLangOpts, LangOpts, nullptr, AllowCompatibleDifferences); } bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain, bool AllowCompatibleDifferences) override { return checkTargetOptions(ExistingTargetOpts, TargetOpts, nullptr, AllowCompatibleDifferences); } bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts, StringRef SpecificModuleCachePath, bool Complain) override { return checkModuleCachePath( FileMgr.getVirtualFileSystem(), SpecificModuleCachePath, ExistingModuleCachePath, nullptr, ExistingLangOpts, ExistingPPOpts); } bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool ReadMacros, bool Complain, std::string &SuggestedPredefines) override { return checkPreprocessorOptions( PPOpts, ExistingPPOpts, ReadMacros, /*Diags=*/nullptr, FileMgr, SuggestedPredefines, ExistingLangOpts, StrictOptionMatches ? OptionValidateStrictMatches : OptionValidateContradictions); } }; } // namespace bool ASTReader::readASTFileControlBlock( StringRef Filename, FileManager &FileMgr, const InMemoryModuleCache &ModuleCache, const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions, ASTReaderListener &Listener, bool ValidateDiagnosticOptions, unsigned ClientLoadCapabilities) { // Open the AST file. std::unique_ptr OwnedBuffer; llvm::MemoryBuffer *Buffer = ModuleCache.lookupPCM(Filename); if (!Buffer) { // FIXME: We should add the pcm to the InMemoryModuleCache if it could be // read again later, but we do not have the context here to determine if it // is safe to change the result of InMemoryModuleCache::getPCMState(). // FIXME: This allows use of the VFS; we do not allow use of the // VFS when actually loading a module. auto BufferOrErr = FileMgr.getBufferForFile(Filename); if (!BufferOrErr) return true; OwnedBuffer = std::move(*BufferOrErr); Buffer = OwnedBuffer.get(); } // Initialize the stream StringRef Bytes = PCHContainerRdr.ExtractPCH(*Buffer); BitstreamCursor Stream(Bytes); // Sniff for the signature. if (llvm::Error Err = doesntStartWithASTFileMagic(Stream)) { consumeError(std::move(Err)); // FIXME this drops errors on the floor. return true; } // Scan for the CONTROL_BLOCK_ID block. if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) return true; bool NeedsInputFiles = Listener.needsInputFileVisitation(); bool NeedsSystemInputFiles = Listener.needsSystemInputFileVisitation(); bool NeedsImports = Listener.needsImportVisitation(); BitstreamCursor InputFilesCursor; uint64_t InputFilesOffsetBase = 0; RecordData Record; std::string ModuleDir; bool DoneWithControlBlock = false; while (!DoneWithControlBlock) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) { // FIXME this drops the error on the floor. consumeError(MaybeEntry.takeError()); return true; } llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: { switch (Entry.ID) { case OPTIONS_BLOCK_ID: { std::string IgnoredSuggestedPredefines; if (ReadOptionsBlock(Stream, ClientLoadCapabilities, /*AllowCompatibleConfigurationMismatch*/ false, Listener, IgnoredSuggestedPredefines) != Success) return true; break; } case INPUT_FILES_BLOCK_ID: InputFilesCursor = Stream; if (llvm::Error Err = Stream.SkipBlock()) { // FIXME this drops the error on the floor. consumeError(std::move(Err)); return true; } if (NeedsInputFiles && ReadBlockAbbrevs(InputFilesCursor, INPUT_FILES_BLOCK_ID)) return true; InputFilesOffsetBase = InputFilesCursor.GetCurrentBitNo(); break; default: if (llvm::Error Err = Stream.SkipBlock()) { // FIXME this drops the error on the floor. consumeError(std::move(Err)); return true; } break; } continue; } case llvm::BitstreamEntry::EndBlock: DoneWithControlBlock = true; break; case llvm::BitstreamEntry::Error: return true; case llvm::BitstreamEntry::Record: break; } if (DoneWithControlBlock) break; Record.clear(); StringRef Blob; Expected MaybeRecCode = Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecCode) { // FIXME this drops the error. return Failure; } switch ((ControlRecordTypes)MaybeRecCode.get()) { case METADATA: if (Record[0] != VERSION_MAJOR) return true; if (Listener.ReadFullVersionInformation(Blob)) return true; break; case MODULE_NAME: Listener.ReadModuleName(Blob); break; case MODULE_DIRECTORY: ModuleDir = std::string(Blob); break; case MODULE_MAP_FILE: { unsigned Idx = 0; auto Path = ReadString(Record, Idx); ResolveImportedPath(Path, ModuleDir); Listener.ReadModuleMapFile(Path); break; } case INPUT_FILE_OFFSETS: { if (!NeedsInputFiles) break; unsigned NumInputFiles = Record[0]; unsigned NumUserFiles = Record[1]; const llvm::support::unaligned_uint64_t *InputFileOffs = (const llvm::support::unaligned_uint64_t *)Blob.data(); for (unsigned I = 0; I != NumInputFiles; ++I) { // Go find this input file. bool isSystemFile = I >= NumUserFiles; if (isSystemFile && !NeedsSystemInputFiles) break; // the rest are system input files BitstreamCursor &Cursor = InputFilesCursor; SavedStreamPosition SavedPosition(Cursor); if (llvm::Error Err = Cursor.JumpToBit(InputFilesOffsetBase + InputFileOffs[I])) { // FIXME this drops errors on the floor. consumeError(std::move(Err)); } Expected MaybeCode = Cursor.ReadCode(); if (!MaybeCode) { // FIXME this drops errors on the floor. consumeError(MaybeCode.takeError()); } unsigned Code = MaybeCode.get(); RecordData Record; StringRef Blob; bool shouldContinue = false; Expected MaybeRecordType = Cursor.readRecord(Code, Record, &Blob); if (!MaybeRecordType) { // FIXME this drops errors on the floor. consumeError(MaybeRecordType.takeError()); } switch ((InputFileRecordTypes)MaybeRecordType.get()) { case INPUT_FILE_HASH: break; case INPUT_FILE: bool Overridden = static_cast(Record[3]); std::string Filename = std::string(Blob); ResolveImportedPath(Filename, ModuleDir); shouldContinue = Listener.visitInputFile( Filename, isSystemFile, Overridden, /*IsExplicitModule*/false); break; } if (!shouldContinue) break; } break; } case IMPORTS: { if (!NeedsImports) break; unsigned Idx = 0, N = Record.size(); while (Idx < N) { // Read information about the AST file. // Skip Kind Idx++; bool IsStandardCXXModule = Record[Idx++]; // Skip ImportLoc Idx++; // In C++20 Modules, we don't record the path to imported // modules in the BMI files. if (IsStandardCXXModule) { std::string ModuleName = ReadString(Record, Idx); Listener.visitImport(ModuleName, /*Filename=*/""); continue; } // Skip Size, ModTime and Signature Idx += 1 + 1 + ASTFileSignature::size; std::string ModuleName = ReadString(Record, Idx); std::string Filename = ReadString(Record, Idx); ResolveImportedPath(Filename, ModuleDir); Listener.visitImport(ModuleName, Filename); } break; } default: // No other validation to perform. break; } } // Look for module file extension blocks, if requested. if (FindModuleFileExtensions) { BitstreamCursor SavedStream = Stream; while (!SkipCursorToBlock(Stream, EXTENSION_BLOCK_ID)) { bool DoneWithExtensionBlock = false; while (!DoneWithExtensionBlock) { Expected MaybeEntry = Stream.advance(); if (!MaybeEntry) { // FIXME this drops the error. return true; } llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: if (llvm::Error Err = Stream.SkipBlock()) { // FIXME this drops the error on the floor. consumeError(std::move(Err)); return true; } continue; case llvm::BitstreamEntry::EndBlock: DoneWithExtensionBlock = true; continue; case llvm::BitstreamEntry::Error: return true; case llvm::BitstreamEntry::Record: break; } Record.clear(); StringRef Blob; Expected MaybeRecCode = Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecCode) { // FIXME this drops the error. return true; } switch (MaybeRecCode.get()) { case EXTENSION_METADATA: { ModuleFileExtensionMetadata Metadata; if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) return true; Listener.readModuleFileExtension(Metadata); break; } } } } Stream = SavedStream; } // Scan for the UNHASHED_CONTROL_BLOCK_ID block. if (readUnhashedControlBlockImpl( nullptr, Bytes, ClientLoadCapabilities, /*AllowCompatibleConfigurationMismatch*/ false, &Listener, ValidateDiagnosticOptions) != Success) return true; return false; } bool ASTReader::isAcceptableASTFile(StringRef Filename, FileManager &FileMgr, const InMemoryModuleCache &ModuleCache, const PCHContainerReader &PCHContainerRdr, const LangOptions &LangOpts, const TargetOptions &TargetOpts, const PreprocessorOptions &PPOpts, StringRef ExistingModuleCachePath, bool RequireStrictOptionMatches) { SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, ExistingModuleCachePath, FileMgr, RequireStrictOptionMatches); return !readASTFileControlBlock(Filename, FileMgr, ModuleCache, PCHContainerRdr, /*FindModuleFileExtensions=*/false, validator, /*ValidateDiagnosticOptions=*/true); } llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // Enter the submodule block. if (llvm::Error Err = F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) return Err; ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); bool First = true; Module *CurrentModule = nullptr; RecordData Record; while (true) { Expected MaybeEntry = F.Stream.advanceSkippingSubblocks(); if (!MaybeEntry) return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: return llvm::createStringError(std::errc::illegal_byte_sequence, "malformed block record in AST file"); case llvm::BitstreamEntry::EndBlock: return llvm::Error::success(); case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read a record. StringRef Blob; Record.clear(); Expected MaybeKind = F.Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeKind) return MaybeKind.takeError(); unsigned Kind = MaybeKind.get(); if ((Kind == SUBMODULE_METADATA) != First) return llvm::createStringError( std::errc::illegal_byte_sequence, "submodule metadata record should be at beginning of block"); First = false; // Submodule information is only valid if we have a current module. // FIXME: Should we error on these cases? if (!CurrentModule && Kind != SUBMODULE_METADATA && Kind != SUBMODULE_DEFINITION) continue; switch (Kind) { default: // Default behavior: ignore. break; case SUBMODULE_DEFINITION: { if (Record.size() < 13) return llvm::createStringError(std::errc::illegal_byte_sequence, "malformed module definition"); StringRef Name = Blob; unsigned Idx = 0; SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[Idx++]); SubmoduleID Parent = getGlobalSubmoduleID(F, Record[Idx++]); Module::ModuleKind Kind = (Module::ModuleKind)Record[Idx++]; SourceLocation DefinitionLoc = ReadSourceLocation(F, Record[Idx++]); bool IsFramework = Record[Idx++]; bool IsExplicit = Record[Idx++]; bool IsSystem = Record[Idx++]; bool IsExternC = Record[Idx++]; bool InferSubmodules = Record[Idx++]; bool InferExplicitSubmodules = Record[Idx++]; bool InferExportWildcard = Record[Idx++]; bool ConfigMacrosExhaustive = Record[Idx++]; bool ModuleMapIsPrivate = Record[Idx++]; bool NamedModuleHasInit = Record[Idx++]; Module *ParentModule = nullptr; if (Parent) ParentModule = getSubmodule(Parent); // Retrieve this (sub)module from the module map, creating it if // necessary. CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, IsFramework, IsExplicit) .first; // FIXME: Call ModMap.setInferredModuleAllowedBy() SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS; if (GlobalIndex >= SubmodulesLoaded.size() || SubmodulesLoaded[GlobalIndex]) return llvm::createStringError(std::errc::invalid_argument, "too many submodules"); if (!ParentModule) { if (OptionalFileEntryRef CurFile = CurrentModule->getASTFile()) { // Don't emit module relocation error if we have -fno-validate-pch if (!bool(PP.getPreprocessorOpts().DisablePCHOrModuleValidation & DisableValidationForModuleKind::Module) && CurFile != F.File) { auto ConflictError = PartialDiagnostic(diag::err_module_file_conflict, ContextObj->DiagAllocator) << CurrentModule->getTopLevelModuleName() << CurFile->getName() << F.File.getName(); return DiagnosticError::create(CurrentImportLoc, ConflictError); } } F.DidReadTopLevelSubmodule = true; CurrentModule->setASTFile(F.File); CurrentModule->PresumedModuleMapFile = F.ModuleMapPath; } CurrentModule->Kind = Kind; CurrentModule->DefinitionLoc = DefinitionLoc; CurrentModule->Signature = F.Signature; CurrentModule->IsFromModuleFile = true; CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; CurrentModule->IsExternC = IsExternC; CurrentModule->InferSubmodules = InferSubmodules; CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules; CurrentModule->InferExportWildcard = InferExportWildcard; CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive; CurrentModule->ModuleMapIsPrivate = ModuleMapIsPrivate; CurrentModule->NamedModuleHasInit = NamedModuleHasInit; if (DeserializationListener) DeserializationListener->ModuleRead(GlobalID, CurrentModule); SubmodulesLoaded[GlobalIndex] = CurrentModule; // Clear out data that will be replaced by what is in the module file. CurrentModule->LinkLibraries.clear(); CurrentModule->ConfigMacros.clear(); CurrentModule->UnresolvedConflicts.clear(); CurrentModule->Conflicts.clear(); // The module is available unless it's missing a requirement; relevant // requirements will be (re-)added by SUBMODULE_REQUIRES records. // Missing headers that were present when the module was built do not // make it unavailable -- if we got this far, this must be an explicitly // imported module file. CurrentModule->Requirements.clear(); CurrentModule->MissingHeaders.clear(); CurrentModule->IsUnimportable = ParentModule && ParentModule->IsUnimportable; CurrentModule->IsAvailable = !CurrentModule->IsUnimportable; break; } case SUBMODULE_UMBRELLA_HEADER: { // FIXME: This doesn't work for framework modules as `Filename` is the // name as written in the module file and does not include // `Headers/`, so this path will never exist. std::string Filename = std::string(Blob); ResolveImportedPath(F, Filename); if (auto Umbrella = PP.getFileManager().getOptionalFileRef(Filename)) { if (!CurrentModule->getUmbrellaHeaderAsWritten()) { // FIXME: NameAsWritten ModMap.setUmbrellaHeaderAsWritten(CurrentModule, *Umbrella, Blob, ""); } // Note that it's too late at this point to return out of date if the // name from the PCM doesn't match up with the one in the module map, // but also quite unlikely since we will have already checked the // modification time and size of the module map file itself. } break; } case SUBMODULE_HEADER: case SUBMODULE_EXCLUDED_HEADER: case SUBMODULE_PRIVATE_HEADER: // We lazily associate headers with their modules via the HeaderInfo table. // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead // of complete filenames or remove it entirely. break; case SUBMODULE_TEXTUAL_HEADER: case SUBMODULE_PRIVATE_TEXTUAL_HEADER: // FIXME: Textual headers are not marked in the HeaderInfo table. Load // them here. break; case SUBMODULE_TOPHEADER: { std::string HeaderName(Blob); ResolveImportedPath(F, HeaderName); CurrentModule->addTopHeaderFilename(HeaderName); break; } case SUBMODULE_UMBRELLA_DIR: { // See comments in SUBMODULE_UMBRELLA_HEADER std::string Dirname = std::string(Blob); ResolveImportedPath(F, Dirname); if (auto Umbrella = PP.getFileManager().getOptionalDirectoryRef(Dirname)) { if (!CurrentModule->getUmbrellaDirAsWritten()) { // FIXME: NameAsWritten ModMap.setUmbrellaDirAsWritten(CurrentModule, *Umbrella, Blob, ""); } } break; } case SUBMODULE_METADATA: { F.BaseSubmoduleID = getTotalNumSubmodules(); F.LocalNumSubmodules = Record[0]; unsigned LocalBaseSubmoduleID = Record[1]; if (F.LocalNumSubmodules > 0) { // Introduce the global -> local mapping for submodules within this // module. GlobalSubmoduleMap.insert(std::make_pair(getTotalNumSubmodules()+1,&F)); // Introduce the local -> global mapping for submodules within this // module. F.SubmoduleRemap.insertOrReplace( std::make_pair(LocalBaseSubmoduleID, F.BaseSubmoduleID - LocalBaseSubmoduleID)); SubmodulesLoaded.resize(SubmodulesLoaded.size() + F.LocalNumSubmodules); } break; } case SUBMODULE_IMPORTS: for (unsigned Idx = 0; Idx != Record.size(); ++Idx) { UnresolvedModuleRef Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[Idx]; Unresolved.Kind = UnresolvedModuleRef::Import; Unresolved.IsWildcard = false; UnresolvedModuleRefs.push_back(Unresolved); } break; case SUBMODULE_AFFECTING_MODULES: for (unsigned Idx = 0; Idx != Record.size(); ++Idx) { UnresolvedModuleRef Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[Idx]; Unresolved.Kind = UnresolvedModuleRef::Affecting; Unresolved.IsWildcard = false; UnresolvedModuleRefs.push_back(Unresolved); } break; case SUBMODULE_EXPORTS: for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) { UnresolvedModuleRef Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[Idx]; Unresolved.Kind = UnresolvedModuleRef::Export; Unresolved.IsWildcard = Record[Idx + 1]; UnresolvedModuleRefs.push_back(Unresolved); } // Once we've loaded the set of exports, there's no reason to keep // the parsed, unresolved exports around. CurrentModule->UnresolvedExports.clear(); break; case SUBMODULE_REQUIRES: CurrentModule->addRequirement(Blob, Record[0], PP.getLangOpts(), PP.getTargetInfo()); break; case SUBMODULE_LINK_LIBRARY: ModMap.resolveLinkAsDependencies(CurrentModule); CurrentModule->LinkLibraries.push_back( Module::LinkLibrary(std::string(Blob), Record[0])); break; case SUBMODULE_CONFIG_MACRO: CurrentModule->ConfigMacros.push_back(Blob.str()); break; case SUBMODULE_CONFLICT: { UnresolvedModuleRef Unresolved; Unresolved.File = &F; Unresolved.Mod = CurrentModule; Unresolved.ID = Record[0]; Unresolved.Kind = UnresolvedModuleRef::Conflict; Unresolved.IsWildcard = false; Unresolved.String = Blob; UnresolvedModuleRefs.push_back(Unresolved); break; } case SUBMODULE_INITIALIZERS: { if (!ContextObj) break; SmallVector Inits; for (unsigned I = 0; I < Record.size(); /*in loop*/) Inits.push_back(ReadDeclID(F, Record, I)); ContextObj->addLazyModuleInitializers(CurrentModule, Inits); break; } case SUBMODULE_EXPORT_AS: CurrentModule->ExportAsModule = Blob.str(); ModMap.addLinkAsDependency(CurrentModule); break; } } } /// Parse the record that corresponds to a LangOptions data /// structure. /// /// This routine parses the language options from the AST file and then gives /// them to the AST listener if one is set. /// /// \returns true if the listener deems the file unacceptable, false otherwise. bool ASTReader::ParseLanguageOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener, bool AllowCompatibleDifferences) { LangOptions LangOpts; unsigned Idx = 0; #define LANGOPT(Name, Bits, Default, Description) \ LangOpts.Name = Record[Idx++]; #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ LangOpts.set##Name(static_cast(Record[Idx++])); #include "clang/Basic/LangOptions.def" #define SANITIZER(NAME, ID) \ LangOpts.Sanitize.set(SanitizerKind::ID, Record[Idx++]); #include "clang/Basic/Sanitizers.def" for (unsigned N = Record[Idx++]; N; --N) LangOpts.ModuleFeatures.push_back(ReadString(Record, Idx)); ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++]; VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx); LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion); LangOpts.CurrentModule = ReadString(Record, Idx); // Comment options. for (unsigned N = Record[Idx++]; N; --N) { LangOpts.CommentOpts.BlockCommandNames.push_back( ReadString(Record, Idx)); } LangOpts.CommentOpts.ParseAllComments = Record[Idx++]; // OpenMP offloading options. for (unsigned N = Record[Idx++]; N; --N) { LangOpts.OMPTargetTriples.push_back(llvm::Triple(ReadString(Record, Idx))); } LangOpts.OMPHostIRFile = ReadString(Record, Idx); return Listener.ReadLanguageOptions(LangOpts, Complain, AllowCompatibleDifferences); } bool ASTReader::ParseTargetOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener, bool AllowCompatibleDifferences) { unsigned Idx = 0; TargetOptions TargetOpts; TargetOpts.Triple = ReadString(Record, Idx); TargetOpts.CPU = ReadString(Record, Idx); TargetOpts.TuneCPU = ReadString(Record, Idx); TargetOpts.ABI = ReadString(Record, Idx); for (unsigned N = Record[Idx++]; N; --N) { TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx)); } for (unsigned N = Record[Idx++]; N; --N) { TargetOpts.Features.push_back(ReadString(Record, Idx)); } return Listener.ReadTargetOptions(TargetOpts, Complain, AllowCompatibleDifferences); } bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener) { IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions); unsigned Idx = 0; #define DIAGOPT(Name, Bits, Default) DiagOpts->Name = Record[Idx++]; #define ENUM_DIAGOPT(Name, Type, Bits, Default) \ DiagOpts->set##Name(static_cast(Record[Idx++])); #include "clang/Basic/DiagnosticOptions.def" for (unsigned N = Record[Idx++]; N; --N) DiagOpts->Warnings.push_back(ReadString(Record, Idx)); for (unsigned N = Record[Idx++]; N; --N) DiagOpts->Remarks.push_back(ReadString(Record, Idx)); return Listener.ReadDiagnosticOptions(DiagOpts, Complain); } bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener) { FileSystemOptions FSOpts; unsigned Idx = 0; FSOpts.WorkingDir = ReadString(Record, Idx); return Listener.ReadFileSystemOptions(FSOpts, Complain); } bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener) { HeaderSearchOptions HSOpts; unsigned Idx = 0; HSOpts.Sysroot = ReadString(Record, Idx); HSOpts.ResourceDir = ReadString(Record, Idx); HSOpts.ModuleCachePath = ReadString(Record, Idx); HSOpts.ModuleUserBuildPath = ReadString(Record, Idx); HSOpts.DisableModuleHash = Record[Idx++]; HSOpts.ImplicitModuleMaps = Record[Idx++]; HSOpts.ModuleMapFileHomeIsCwd = Record[Idx++]; HSOpts.EnablePrebuiltImplicitModules = Record[Idx++]; HSOpts.UseBuiltinIncludes = Record[Idx++]; HSOpts.UseStandardSystemIncludes = Record[Idx++]; HSOpts.UseStandardCXXIncludes = Record[Idx++]; HSOpts.UseLibcxx = Record[Idx++]; std::string SpecificModuleCachePath = ReadString(Record, Idx); return Listener.ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath, Complain); } bool ASTReader::ParseHeaderSearchPaths(const RecordData &Record, bool Complain, ASTReaderListener &Listener) { HeaderSearchOptions HSOpts; unsigned Idx = 0; // Include entries. for (unsigned N = Record[Idx++]; N; --N) { std::string Path = ReadString(Record, Idx); frontend::IncludeDirGroup Group = static_cast(Record[Idx++]); bool IsFramework = Record[Idx++]; bool IgnoreSysRoot = Record[Idx++]; HSOpts.UserEntries.emplace_back(std::move(Path), Group, IsFramework, IgnoreSysRoot); } // System header prefixes. for (unsigned N = Record[Idx++]; N; --N) { std::string Prefix = ReadString(Record, Idx); bool IsSystemHeader = Record[Idx++]; HSOpts.SystemHeaderPrefixes.emplace_back(std::move(Prefix), IsSystemHeader); } // VFS overlay files. for (unsigned N = Record[Idx++]; N; --N) { std::string VFSOverlayFile = ReadString(Record, Idx); HSOpts.VFSOverlayFiles.emplace_back(std::move(VFSOverlayFile)); } return Listener.ReadHeaderSearchPaths(HSOpts, Complain); } bool ASTReader::ParsePreprocessorOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener, std::string &SuggestedPredefines) { PreprocessorOptions PPOpts; unsigned Idx = 0; // Macro definitions/undefs bool ReadMacros = Record[Idx++]; if (ReadMacros) { for (unsigned N = Record[Idx++]; N; --N) { std::string Macro = ReadString(Record, Idx); bool IsUndef = Record[Idx++]; PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef)); } } // Includes for (unsigned N = Record[Idx++]; N; --N) { PPOpts.Includes.push_back(ReadString(Record, Idx)); } // Macro Includes for (unsigned N = Record[Idx++]; N; --N) { PPOpts.MacroIncludes.push_back(ReadString(Record, Idx)); } PPOpts.UsePredefines = Record[Idx++]; PPOpts.DetailedRecord = Record[Idx++]; PPOpts.ImplicitPCHInclude = ReadString(Record, Idx); PPOpts.ObjCXXARCStandardLibrary = static_cast(Record[Idx++]); SuggestedPredefines.clear(); return Listener.ReadPreprocessorOptions(PPOpts, ReadMacros, Complain, SuggestedPredefines); } std::pair ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) { GlobalPreprocessedEntityMapType::iterator I = GlobalPreprocessedEntityMap.find(GlobalIndex); assert(I != GlobalPreprocessedEntityMap.end() && "Corrupted global preprocessed entity map"); ModuleFile *M = I->second; unsigned LocalIndex = GlobalIndex - M->BasePreprocessedEntityID; return std::make_pair(M, LocalIndex); } llvm::iterator_range ASTReader::getModulePreprocessedEntities(ModuleFile &Mod) const { if (PreprocessingRecord *PPRec = PP.getPreprocessingRecord()) return PPRec->getIteratorsForLoadedRange(Mod.BasePreprocessedEntityID, Mod.NumPreprocessedEntities); return llvm::make_range(PreprocessingRecord::iterator(), PreprocessingRecord::iterator()); } bool ASTReader::canRecoverFromOutOfDate(StringRef ModuleFileName, unsigned int ClientLoadCapabilities) { return ClientLoadCapabilities & ARR_OutOfDate && !getModuleManager().getModuleCache().isPCMFinal(ModuleFileName); } llvm::iterator_range ASTReader::getModuleFileLevelDecls(ModuleFile &Mod) { return llvm::make_range( ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls), ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls + Mod.NumFileSortedDecls)); } SourceRange ASTReader::ReadSkippedRange(unsigned GlobalIndex) { auto I = GlobalSkippedRangeMap.find(GlobalIndex); assert(I != GlobalSkippedRangeMap.end() && "Corrupted global skipped range map"); ModuleFile *M = I->second; unsigned LocalIndex = GlobalIndex - M->BasePreprocessedSkippedRangeID; assert(LocalIndex < M->NumPreprocessedSkippedRanges); PPSkippedRange RawRange = M->PreprocessedSkippedRangeOffsets[LocalIndex]; SourceRange Range(ReadSourceLocation(*M, RawRange.getBegin()), ReadSourceLocation(*M, RawRange.getEnd())); assert(Range.isValid()); return Range; } PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { PreprocessedEntityID PPID = Index+1; std::pair PPInfo = getModulePreprocessedEntity(Index); ModuleFile &M = *PPInfo.first; unsigned LocalIndex = PPInfo.second; const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex]; if (!PP.getPreprocessingRecord()) { Error("no preprocessing record"); return nullptr; } SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor); if (llvm::Error Err = M.PreprocessorDetailCursor.JumpToBit( M.MacroOffsetsBase + PPOffs.getOffset())) { Error(std::move(Err)); return nullptr; } Expected MaybeEntry = M.PreprocessorDetailCursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd); if (!MaybeEntry) { Error(MaybeEntry.takeError()); return nullptr; } llvm::BitstreamEntry Entry = MaybeEntry.get(); if (Entry.Kind != llvm::BitstreamEntry::Record) return nullptr; // Read the record. SourceRange Range(ReadSourceLocation(M, PPOffs.getBegin()), ReadSourceLocation(M, PPOffs.getEnd())); PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); StringRef Blob; RecordData Record; Expected MaybeRecType = M.PreprocessorDetailCursor.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecType) { Error(MaybeRecType.takeError()); return nullptr; } switch ((PreprocessorDetailRecordTypes)MaybeRecType.get()) { case PPD_MACRO_EXPANSION: { bool isBuiltin = Record[0]; IdentifierInfo *Name = nullptr; MacroDefinitionRecord *Def = nullptr; if (isBuiltin) Name = getLocalIdentifier(M, Record[1]); else { PreprocessedEntityID GlobalID = getGlobalPreprocessedEntityID(M, Record[1]); Def = cast( PPRec.getLoadedPreprocessedEntity(GlobalID - 1)); } MacroExpansion *ME; if (isBuiltin) ME = new (PPRec) MacroExpansion(Name, Range); else ME = new (PPRec) MacroExpansion(Def, Range); return ME; } case PPD_MACRO_DEFINITION: { // Decode the identifier info and then check again; if the macro is // still defined and associated with the identifier, IdentifierInfo *II = getLocalIdentifier(M, Record[0]); MacroDefinitionRecord *MD = new (PPRec) MacroDefinitionRecord(II, Range); if (DeserializationListener) DeserializationListener->MacroDefinitionRead(PPID, MD); return MD; } case PPD_INCLUSION_DIRECTIVE: { const char *FullFileNameStart = Blob.data() + Record[0]; StringRef FullFileName(FullFileNameStart, Blob.size() - Record[0]); OptionalFileEntryRef File; if (!FullFileName.empty()) File = PP.getFileManager().getOptionalFileRef(FullFileName); // FIXME: Stable encoding InclusionDirective::InclusionKind Kind = static_cast(Record[2]); InclusionDirective *ID = new (PPRec) InclusionDirective(PPRec, Kind, StringRef(Blob.data(), Record[0]), Record[1], Record[3], File, Range); return ID; } } llvm_unreachable("Invalid PreprocessorDetailRecordTypes"); } /// Find the next module that contains entities and return the ID /// of the first entry. /// /// \param SLocMapI points at a chunk of a module that contains no /// preprocessed entities or the entities it contains are not the ones we are /// looking for. PreprocessedEntityID ASTReader::findNextPreprocessedEntity( GlobalSLocOffsetMapType::const_iterator SLocMapI) const { ++SLocMapI; for (GlobalSLocOffsetMapType::const_iterator EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) { ModuleFile &M = *SLocMapI->second; if (M.NumPreprocessedEntities) return M.BasePreprocessedEntityID; } return getTotalNumPreprocessedEntities(); } namespace { struct PPEntityComp { const ASTReader &Reader; ModuleFile &M; PPEntityComp(const ASTReader &Reader, ModuleFile &M) : Reader(Reader), M(M) {} bool operator()(const PPEntityOffset &L, const PPEntityOffset &R) const { SourceLocation LHS = getLoc(L); SourceLocation RHS = getLoc(R); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } bool operator()(const PPEntityOffset &L, SourceLocation RHS) const { SourceLocation LHS = getLoc(L); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } bool operator()(SourceLocation LHS, const PPEntityOffset &R) const { SourceLocation RHS = getLoc(R); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } SourceLocation getLoc(const PPEntityOffset &PPE) const { return Reader.ReadSourceLocation(M, PPE.getBegin()); } }; } // namespace PreprocessedEntityID ASTReader::findPreprocessedEntity(SourceLocation Loc, bool EndsAfter) const { if (SourceMgr.isLocalSourceLocation(Loc)) return getTotalNumPreprocessedEntities(); GlobalSLocOffsetMapType::const_iterator SLocMapI = GlobalSLocOffsetMap.find( SourceManager::MaxLoadedOffset - Loc.getOffset() - 1); assert(SLocMapI != GlobalSLocOffsetMap.end() && "Corrupted global sloc offset map"); if (SLocMapI->second->NumPreprocessedEntities == 0) return findNextPreprocessedEntity(SLocMapI); ModuleFile &M = *SLocMapI->second; using pp_iterator = const PPEntityOffset *; pp_iterator pp_begin = M.PreprocessedEntityOffsets; pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities; size_t Count = M.NumPreprocessedEntities; size_t Half; pp_iterator First = pp_begin; pp_iterator PPI; if (EndsAfter) { PPI = std::upper_bound(pp_begin, pp_end, Loc, PPEntityComp(*this, M)); } else { // Do a binary search manually instead of using std::lower_bound because // The end locations of entities may be unordered (when a macro expansion // is inside another macro argument), but for this case it is not important // whether we get the first macro expansion or its containing macro. while (Count > 0) { Half = Count / 2; PPI = First; std::advance(PPI, Half); if (SourceMgr.isBeforeInTranslationUnit( ReadSourceLocation(M, PPI->getEnd()), Loc)) { First = PPI; ++First; Count = Count - Half - 1; } else Count = Half; } } if (PPI == pp_end) return findNextPreprocessedEntity(SLocMapI); return M.BasePreprocessedEntityID + (PPI - pp_begin); } /// Returns a pair of [Begin, End) indices of preallocated /// preprocessed entities that \arg Range encompasses. std::pair ASTReader::findPreprocessedEntitiesInRange(SourceRange Range) { if (Range.isInvalid()) return std::make_pair(0,0); assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); PreprocessedEntityID BeginID = findPreprocessedEntity(Range.getBegin(), false); PreprocessedEntityID EndID = findPreprocessedEntity(Range.getEnd(), true); return std::make_pair(BeginID, EndID); } /// Optionally returns true or false if the preallocated preprocessed /// entity with index \arg Index came from file \arg FID. std::optional ASTReader::isPreprocessedEntityInFileID(unsigned Index, FileID FID) { if (FID.isInvalid()) return false; std::pair PPInfo = getModulePreprocessedEntity(Index); ModuleFile &M = *PPInfo.first; unsigned LocalIndex = PPInfo.second; const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex]; SourceLocation Loc = ReadSourceLocation(M, PPOffs.getBegin()); if (Loc.isInvalid()) return false; if (SourceMgr.isInFileID(SourceMgr.getFileLoc(Loc), FID)) return true; else return false; } namespace { /// Visitor used to search for information about a header file. class HeaderFileInfoVisitor { FileEntryRef FE; std::optional HFI; public: explicit HeaderFileInfoVisitor(FileEntryRef FE) : FE(FE) {} bool operator()(ModuleFile &M) { HeaderFileInfoLookupTable *Table = static_cast(M.HeaderFileInfoTable); if (!Table) return false; // Look in the on-disk hash table for an entry for this file name. HeaderFileInfoLookupTable::iterator Pos = Table->find(FE); if (Pos == Table->end()) return false; HFI = *Pos; return true; } std::optional getHeaderFileInfo() const { return HFI; } }; } // namespace HeaderFileInfo ASTReader::GetHeaderFileInfo(FileEntryRef FE) { HeaderFileInfoVisitor Visitor(FE); ModuleMgr.visit(Visitor); if (std::optional HFI = Visitor.getHeaderFileInfo()) return *HFI; return HeaderFileInfo(); } void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { using DiagState = DiagnosticsEngine::DiagState; SmallVector DiagStates; for (ModuleFile &F : ModuleMgr) { unsigned Idx = 0; auto &Record = F.PragmaDiagMappings; if (Record.empty()) continue; DiagStates.clear(); auto ReadDiagState = [&](const DiagState &BasedOn, bool IncludeNonPragmaStates) { unsigned BackrefID = Record[Idx++]; if (BackrefID != 0) return DiagStates[BackrefID - 1]; // A new DiagState was created here. Diag.DiagStates.push_back(BasedOn); DiagState *NewState = &Diag.DiagStates.back(); DiagStates.push_back(NewState); 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); } 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, true); assert(F.OriginalSourceFileID.isValid()); // 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, false); } // Read the state transitions. unsigned NumLocations = Record[Idx++]; while (NumLocations--) { assert(Idx < Record.size() && "Invalid data, missing pragma diagnostic states"); FileID FID = ReadFileID(F, Record, Idx); assert(FID.isValid() && "invalid FileID for transition"); 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[FID]; F.StateTransitions.reserve(F.StateTransitions.size() + Transitions); for (unsigned I = 0; I != Transitions; ++I) { unsigned Offset = Record[Idx++]; auto *State = ReadDiagState(*FirstState, 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, Record[Idx++]); auto *CurState = ReadDiagState(*FirstState, false); if (!F.isModule()) { Diag.DiagStatesByLoc.CurDiagState = CurState; Diag.DiagStatesByLoc.CurDiagStateLoc = CurStateLoc; // Preserve the property that the imaginary root file describes the // current state. FileID NullFile; auto &T = Diag.DiagStatesByLoc.Files[NullFile].StateTransitions; if (T.empty()) T.push_back({CurState, 0}); else T[0].State = CurState; } // Don't try to read these mappings again. Record.clear(); } } /// Get the correct cursor and offset for loading a type. ASTReader::RecordLocation ASTReader::TypeCursorForIndex(TypeID ID) { auto [M, Index] = translateTypeIDToIndex(ID); return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex].get() + M->DeclsBlockStartOffset); } static std::optional getTypeClassForCode(TypeCode code) { switch (code) { #define TYPE_BIT_CODE(CLASS_ID, CODE_ID, CODE_VALUE) \ case TYPE_##CODE_ID: return Type::CLASS_ID; #include "clang/Serialization/TypeBitCodes.def" default: return std::nullopt; } } /// Read and return the type with the given index.. /// /// The index is the type ID, shifted and minus the number of predefs. This /// routine actually reads the record corresponding to the type at the given /// location. It is a helper routine for GetType, which deals with reading type /// IDs. QualType ASTReader::readTypeRecord(TypeID ID) { assert(ContextObj && "reading type with no AST context"); ASTContext &Context = *ContextObj; RecordLocation Loc = TypeCursorForIndex(ID); BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor; // Keep track of where we are in the stream, then jump back there // after reading this type. SavedStreamPosition SavedPosition(DeclsCursor); ReadingKindTracker ReadingKind(Read_Type, *this); // Note that we are loading a type record. Deserializing AType(this); if (llvm::Error Err = DeclsCursor.JumpToBit(Loc.Offset)) { Error(std::move(Err)); return QualType(); } Expected RawCode = DeclsCursor.ReadCode(); if (!RawCode) { Error(RawCode.takeError()); return QualType(); } ASTRecordReader Record(*this, *Loc.F); Expected Code = Record.readRecord(DeclsCursor, RawCode.get()); if (!Code) { Error(Code.takeError()); return QualType(); } if (Code.get() == TYPE_EXT_QUAL) { QualType baseType = Record.readQualType(); Qualifiers quals = Record.readQualifiers(); return Context.getQualifiedType(baseType, quals); } auto maybeClass = getTypeClassForCode((TypeCode) Code.get()); if (!maybeClass) { Error("Unexpected code for type"); return QualType(); } serialization::AbstractTypeReader TypeReader(Record); return TypeReader.read(*maybeClass); } namespace clang { class TypeLocReader : public TypeLocVisitor { using LocSeq = SourceLocationSequence; ASTRecordReader &Reader; LocSeq *Seq; SourceLocation readSourceLocation() { return Reader.readSourceLocation(Seq); } SourceRange readSourceRange() { return Reader.readSourceRange(Seq); } TypeSourceInfo *GetTypeSourceInfo() { return Reader.readTypeSourceInfo(); } NestedNameSpecifierLoc ReadNestedNameSpecifierLoc() { return Reader.readNestedNameSpecifierLoc(); } Attr *ReadAttr() { return Reader.readAttr(); } public: TypeLocReader(ASTRecordReader &Reader, LocSeq *Seq) : Reader(Reader), Seq(Seq) {} // We want compile-time assurance that we've enumerated all of // these, so unfortunately we have to declare them first, then // define them out-of-line. #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); #include "clang/AST/TypeLocNodes.def" void VisitFunctionTypeLoc(FunctionTypeLoc); void VisitArrayTypeLoc(ArrayTypeLoc); }; } // namespace clang void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { // nothing to do } void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { TL.setBuiltinLoc(readSourceLocation()); if (TL.needsExtraLocalData()) { TL.setWrittenTypeSpec(static_cast(Reader.readInt())); TL.setWrittenSignSpec(static_cast(Reader.readInt())); TL.setWrittenWidthSpec(static_cast(Reader.readInt())); TL.setModeAttr(Reader.readInt()); } } void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { TL.setStarLoc(readSourceLocation()); } void TypeLocReader::VisitDecayedTypeLoc(DecayedTypeLoc TL) { // nothing to do } void TypeLocReader::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { // nothing to do } void TypeLocReader::VisitArrayParameterTypeLoc(ArrayParameterTypeLoc TL) { // nothing to do } void TypeLocReader::VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) { TL.setExpansionLoc(readSourceLocation()); } void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { TL.setCaretLoc(readSourceLocation()); } void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { TL.setAmpLoc(readSourceLocation()); } void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { TL.setAmpAmpLoc(readSourceLocation()); } void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { TL.setStarLoc(readSourceLocation()); TL.setClassTInfo(GetTypeSourceInfo()); } void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { TL.setLBracketLoc(readSourceLocation()); TL.setRBracketLoc(readSourceLocation()); if (Reader.readBool()) TL.setSizeExpr(Reader.readExpr()); else TL.setSizeExpr(nullptr); } void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocReader::VisitDependentSizedArrayTypeLoc( DependentSizedArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocReader::VisitDependentAddressSpaceTypeLoc( DependentAddressSpaceTypeLoc TL) { TL.setAttrNameLoc(readSourceLocation()); TL.setAttrOperandParensRange(readSourceRange()); TL.setAttrExprOperand(Reader.readExpr()); } void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( DependentSizedExtVectorTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitDependentVectorTypeLoc( DependentVectorTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitConstantMatrixTypeLoc(ConstantMatrixTypeLoc TL) { TL.setAttrNameLoc(readSourceLocation()); TL.setAttrOperandParensRange(readSourceRange()); TL.setAttrRowOperand(Reader.readExpr()); TL.setAttrColumnOperand(Reader.readExpr()); } void TypeLocReader::VisitDependentSizedMatrixTypeLoc( DependentSizedMatrixTypeLoc TL) { TL.setAttrNameLoc(readSourceLocation()); TL.setAttrOperandParensRange(readSourceRange()); TL.setAttrRowOperand(Reader.readExpr()); TL.setAttrColumnOperand(Reader.readExpr()); } void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { TL.setLocalRangeBegin(readSourceLocation()); TL.setLParenLoc(readSourceLocation()); TL.setRParenLoc(readSourceLocation()); TL.setExceptionSpecRange(readSourceRange()); TL.setLocalRangeEnd(readSourceLocation()); for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) { TL.setParam(i, Reader.readDeclAs()); } } void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitUsingTypeLoc(UsingTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { TL.setTypeofLoc(readSourceLocation()); TL.setLParenLoc(readSourceLocation()); TL.setRParenLoc(readSourceLocation()); } void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { TL.setTypeofLoc(readSourceLocation()); TL.setLParenLoc(readSourceLocation()); TL.setRParenLoc(readSourceLocation()); TL.setUnmodifiedTInfo(GetTypeSourceInfo()); } void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { TL.setDecltypeLoc(readSourceLocation()); TL.setRParenLoc(readSourceLocation()); } void TypeLocReader::VisitPackIndexingTypeLoc(PackIndexingTypeLoc TL) { TL.setEllipsisLoc(readSourceLocation()); } void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { TL.setKWLoc(readSourceLocation()); TL.setLParenLoc(readSourceLocation()); TL.setRParenLoc(readSourceLocation()); TL.setUnderlyingTInfo(GetTypeSourceInfo()); } ConceptReference *ASTRecordReader::readConceptReference() { auto NNS = readNestedNameSpecifierLoc(); auto TemplateKWLoc = readSourceLocation(); auto ConceptNameLoc = readDeclarationNameInfo(); auto FoundDecl = readDeclAs(); auto NamedConcept = readDeclAs(); auto *CR = ConceptReference::Create( getContext(), NNS, TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept, (readBool() ? readASTTemplateArgumentListInfo() : nullptr)); return CR; } void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { TL.setNameLoc(readSourceLocation()); if (Reader.readBool()) TL.setConceptReference(Reader.readConceptReference()); if (Reader.readBool()) TL.setRParenLoc(readSourceLocation()); } void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc( DeducedTemplateSpecializationTypeLoc TL) { TL.setTemplateNameLoc(readSourceLocation()); } void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) { TL.setAttr(ReadAttr()); } void TypeLocReader::VisitCountAttributedTypeLoc(CountAttributedTypeLoc TL) { // Nothing to do } void TypeLocReader::VisitBTFTagAttributedTypeLoc(BTFTagAttributedTypeLoc TL) { // Nothing to do. } void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( SubstTemplateTypeParmTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc( SubstTemplateTypeParmPackTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { TL.setTemplateKeywordLoc(readSourceLocation()); TL.setTemplateNameLoc(readSourceLocation()); TL.setLAngleLoc(readSourceLocation()); TL.setRAngleLoc(readSourceLocation()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) TL.setArgLocInfo(i, Reader.readTemplateArgumentLocInfo( TL.getTypePtr()->template_arguments()[i].getKind())); } void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) { TL.setLParenLoc(readSourceLocation()); TL.setRParenLoc(readSourceLocation()); } void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { TL.setElaboratedKeywordLoc(readSourceLocation()); TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); } void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { TL.setElaboratedKeywordLoc(readSourceLocation()); TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL) { TL.setElaboratedKeywordLoc(readSourceLocation()); TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); TL.setTemplateKeywordLoc(readSourceLocation()); TL.setTemplateNameLoc(readSourceLocation()); TL.setLAngleLoc(readSourceLocation()); TL.setRAngleLoc(readSourceLocation()); for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) TL.setArgLocInfo(I, Reader.readTemplateArgumentLocInfo( TL.getTypePtr()->template_arguments()[I].getKind())); } void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { TL.setEllipsisLoc(readSourceLocation()); } void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { TL.setNameLoc(readSourceLocation()); TL.setNameEndLoc(readSourceLocation()); } void TypeLocReader::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) { if (TL.getNumProtocols()) { TL.setProtocolLAngleLoc(readSourceLocation()); TL.setProtocolRAngleLoc(readSourceLocation()); } for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) TL.setProtocolLoc(i, readSourceLocation()); } void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { TL.setHasBaseTypeAsWritten(Reader.readBool()); TL.setTypeArgsLAngleLoc(readSourceLocation()); TL.setTypeArgsRAngleLoc(readSourceLocation()); for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) TL.setTypeArgTInfo(i, GetTypeSourceInfo()); TL.setProtocolLAngleLoc(readSourceLocation()); TL.setProtocolRAngleLoc(readSourceLocation()); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) TL.setProtocolLoc(i, readSourceLocation()); } void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { TL.setStarLoc(readSourceLocation()); } void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) { TL.setKWLoc(readSourceLocation()); TL.setLParenLoc(readSourceLocation()); TL.setRParenLoc(readSourceLocation()); } void TypeLocReader::VisitPipeTypeLoc(PipeTypeLoc TL) { TL.setKWLoc(readSourceLocation()); } void TypeLocReader::VisitBitIntTypeLoc(clang::BitIntTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitDependentBitIntTypeLoc( clang::DependentBitIntTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } void ASTRecordReader::readTypeLoc(TypeLoc TL, LocSeq *ParentSeq) { LocSeq::State Seq(ParentSeq); TypeLocReader TLR(*this, Seq); for (; !TL.isNull(); TL = TL.getNextTypeLoc()) TLR.Visit(TL); } TypeSourceInfo *ASTRecordReader::readTypeSourceInfo() { QualType InfoTy = readType(); if (InfoTy.isNull()) return nullptr; TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy); readTypeLoc(TInfo->getTypeLoc()); return TInfo; } static unsigned getIndexForTypeID(serialization::TypeID ID) { return (ID & llvm::maskTrailingOnes(32)) >> Qualifiers::FastWidth; } static unsigned getModuleFileIndexForTypeID(serialization::TypeID ID) { return ID >> 32; } static bool isPredefinedType(serialization::TypeID ID) { // We don't need to erase the higher bits since if these bits are not 0, // it must be larger than NUM_PREDEF_TYPE_IDS. return (ID >> Qualifiers::FastWidth) < NUM_PREDEF_TYPE_IDS; } std::pair ASTReader::translateTypeIDToIndex(serialization::TypeID ID) const { assert(!isPredefinedType(ID) && "Predefined type shouldn't be in TypesLoaded"); unsigned ModuleFileIndex = getModuleFileIndexForTypeID(ID); assert(ModuleFileIndex && "Untranslated Local Decl?"); ModuleFile *OwningModuleFile = &getModuleManager()[ModuleFileIndex - 1]; assert(OwningModuleFile && "untranslated type ID or local type ID shouldn't be in TypesLoaded"); return {OwningModuleFile, OwningModuleFile->BaseTypeIndex + getIndexForTypeID(ID)}; } QualType ASTReader::GetType(TypeID ID) { assert(ContextObj && "reading type with no AST context"); ASTContext &Context = *ContextObj; unsigned FastQuals = ID & Qualifiers::FastMask; if (isPredefinedType(ID)) { QualType T; unsigned Index = getIndexForTypeID(ID); switch ((PredefinedTypeIDs)Index) { case PREDEF_TYPE_LAST_ID: // We should never use this one. llvm_unreachable("Invalid predefined type"); break; case PREDEF_TYPE_NULL_ID: return QualType(); case PREDEF_TYPE_VOID_ID: T = Context.VoidTy; break; case PREDEF_TYPE_BOOL_ID: T = Context.BoolTy; break; case PREDEF_TYPE_CHAR_U_ID: case PREDEF_TYPE_CHAR_S_ID: // FIXME: Check that the signedness of CharTy is correct! T = Context.CharTy; break; case PREDEF_TYPE_UCHAR_ID: T = Context.UnsignedCharTy; break; case PREDEF_TYPE_USHORT_ID: T = Context.UnsignedShortTy; break; case PREDEF_TYPE_UINT_ID: T = Context.UnsignedIntTy; break; case PREDEF_TYPE_ULONG_ID: T = Context.UnsignedLongTy; break; case PREDEF_TYPE_ULONGLONG_ID: T = Context.UnsignedLongLongTy; break; case PREDEF_TYPE_UINT128_ID: T = Context.UnsignedInt128Ty; break; case PREDEF_TYPE_SCHAR_ID: T = Context.SignedCharTy; break; case PREDEF_TYPE_WCHAR_ID: T = Context.WCharTy; break; case PREDEF_TYPE_SHORT_ID: T = Context.ShortTy; break; case PREDEF_TYPE_INT_ID: T = Context.IntTy; break; case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break; case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break; case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break; case PREDEF_TYPE_BFLOAT16_ID: T = Context.BFloat16Ty; break; case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break; case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break; case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break; case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; case PREDEF_TYPE_SHORT_ACCUM_ID: T = Context.ShortAccumTy; break; case PREDEF_TYPE_ACCUM_ID: T = Context.AccumTy; break; case PREDEF_TYPE_LONG_ACCUM_ID: T = Context.LongAccumTy; break; case PREDEF_TYPE_USHORT_ACCUM_ID: T = Context.UnsignedShortAccumTy; break; case PREDEF_TYPE_UACCUM_ID: T = Context.UnsignedAccumTy; break; case PREDEF_TYPE_ULONG_ACCUM_ID: T = Context.UnsignedLongAccumTy; break; case PREDEF_TYPE_SHORT_FRACT_ID: T = Context.ShortFractTy; break; case PREDEF_TYPE_FRACT_ID: T = Context.FractTy; break; case PREDEF_TYPE_LONG_FRACT_ID: T = Context.LongFractTy; break; case PREDEF_TYPE_USHORT_FRACT_ID: T = Context.UnsignedShortFractTy; break; case PREDEF_TYPE_UFRACT_ID: T = Context.UnsignedFractTy; break; case PREDEF_TYPE_ULONG_FRACT_ID: T = Context.UnsignedLongFractTy; break; case PREDEF_TYPE_SAT_SHORT_ACCUM_ID: T = Context.SatShortAccumTy; break; case PREDEF_TYPE_SAT_ACCUM_ID: T = Context.SatAccumTy; break; case PREDEF_TYPE_SAT_LONG_ACCUM_ID: T = Context.SatLongAccumTy; break; case PREDEF_TYPE_SAT_USHORT_ACCUM_ID: T = Context.SatUnsignedShortAccumTy; break; case PREDEF_TYPE_SAT_UACCUM_ID: T = Context.SatUnsignedAccumTy; break; case PREDEF_TYPE_SAT_ULONG_ACCUM_ID: T = Context.SatUnsignedLongAccumTy; break; case PREDEF_TYPE_SAT_SHORT_FRACT_ID: T = Context.SatShortFractTy; break; case PREDEF_TYPE_SAT_FRACT_ID: T = Context.SatFractTy; break; case PREDEF_TYPE_SAT_LONG_FRACT_ID: T = Context.SatLongFractTy; break; case PREDEF_TYPE_SAT_USHORT_FRACT_ID: T = Context.SatUnsignedShortFractTy; break; case PREDEF_TYPE_SAT_UFRACT_ID: T = Context.SatUnsignedFractTy; break; case PREDEF_TYPE_SAT_ULONG_FRACT_ID: T = Context.SatUnsignedLongFractTy; break; case PREDEF_TYPE_FLOAT16_ID: T = Context.Float16Ty; break; case PREDEF_TYPE_FLOAT128_ID: T = Context.Float128Ty; break; case PREDEF_TYPE_IBM128_ID: T = Context.Ibm128Ty; break; case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break; case PREDEF_TYPE_UNRESOLVED_TEMPLATE: T = Context.UnresolvedTemplateTy; break; case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break; case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break; case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break; case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break; case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break; case PREDEF_TYPE_CHAR8_ID: T = Context.Char8Ty; break; case PREDEF_TYPE_CHAR16_ID: T = Context.Char16Ty; break; case PREDEF_TYPE_CHAR32_ID: T = Context.Char32Ty; break; case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break; case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break; case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break; #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case PREDEF_TYPE_##Id##_ID: \ T = Context.SingletonId; \ break; #include "clang/Basic/OpenCLImageTypes.def" #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case PREDEF_TYPE_##Id##_ID: \ T = Context.Id##Ty; \ break; #include "clang/Basic/OpenCLExtensionTypes.def" case PREDEF_TYPE_SAMPLER_ID: T = Context.OCLSamplerTy; break; case PREDEF_TYPE_EVENT_ID: T = Context.OCLEventTy; break; case PREDEF_TYPE_CLK_EVENT_ID: T = Context.OCLClkEventTy; break; case PREDEF_TYPE_QUEUE_ID: T = Context.OCLQueueTy; break; case PREDEF_TYPE_RESERVE_ID_ID: T = Context.OCLReserveIDTy; break; case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break; case PREDEF_TYPE_AUTO_RREF_DEDUCT: T = Context.getAutoRRefDeductType(); break; case PREDEF_TYPE_ARC_UNBRIDGED_CAST: T = Context.ARCUnbridgedCastTy; break; case PREDEF_TYPE_BUILTIN_FN: T = Context.BuiltinFnTy; break; case PREDEF_TYPE_INCOMPLETE_MATRIX_IDX: T = Context.IncompleteMatrixIdxTy; break; case PREDEF_TYPE_ARRAY_SECTION: T = Context.ArraySectionTy; break; case PREDEF_TYPE_OMP_ARRAY_SHAPING: T = Context.OMPArrayShapingTy; break; case PREDEF_TYPE_OMP_ITERATOR: T = Context.OMPIteratorTy; break; #define SVE_TYPE(Name, Id, SingletonId) \ case PREDEF_TYPE_##Id##_ID: \ T = Context.SingletonId; \ break; #include "clang/Basic/AArch64SVEACLETypes.def" #define PPC_VECTOR_TYPE(Name, Id, Size) \ case PREDEF_TYPE_##Id##_ID: \ T = Context.Id##Ty; \ break; #include "clang/Basic/PPCTypes.def" #define RVV_TYPE(Name, Id, SingletonId) \ case PREDEF_TYPE_##Id##_ID: \ T = Context.SingletonId; \ break; #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) \ case PREDEF_TYPE_##Id##_ID: \ T = Context.SingletonId; \ break; #include "clang/Basic/WebAssemblyReferenceTypes.def" #define AMDGPU_TYPE(Name, Id, SingletonId) \ case PREDEF_TYPE_##Id##_ID: \ T = Context.SingletonId; \ break; #include "clang/Basic/AMDGPUTypes.def" } assert(!T.isNull() && "Unknown predefined type"); return T.withFastQualifiers(FastQuals); } unsigned Index = translateTypeIDToIndex(ID).second; assert(Index < TypesLoaded.size() && "Type index out-of-range"); if (TypesLoaded[Index].isNull()) { TypesLoaded[Index] = readTypeRecord(ID); if (TypesLoaded[Index].isNull()) return QualType(); TypesLoaded[Index]->setFromAST(); if (DeserializationListener) DeserializationListener->TypeRead(TypeIdx::fromTypeID(ID), TypesLoaded[Index]); } return TypesLoaded[Index].withFastQualifiers(FastQuals); } QualType ASTReader::getLocalType(ModuleFile &F, LocalTypeID LocalID) { return GetType(getGlobalTypeID(F, LocalID)); } serialization::TypeID ASTReader::getGlobalTypeID(ModuleFile &F, LocalTypeID LocalID) const { if (isPredefinedType(LocalID)) return LocalID; if (!F.ModuleOffsetMap.empty()) ReadModuleOffsetMap(F); unsigned ModuleFileIndex = getModuleFileIndexForTypeID(LocalID); LocalID &= llvm::maskTrailingOnes(32); if (ModuleFileIndex == 0) LocalID -= NUM_PREDEF_TYPE_IDS << Qualifiers::FastWidth; ModuleFile &MF = ModuleFileIndex ? *F.TransitiveImports[ModuleFileIndex - 1] : F; ModuleFileIndex = MF.Index + 1; return ((uint64_t)ModuleFileIndex << 32) | LocalID; } TemplateArgumentLocInfo ASTRecordReader::readTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind) { switch (Kind) { case TemplateArgument::Expression: return readExpr(); case TemplateArgument::Type: return readTypeSourceInfo(); case TemplateArgument::Template: { NestedNameSpecifierLoc QualifierLoc = readNestedNameSpecifierLoc(); SourceLocation TemplateNameLoc = readSourceLocation(); return TemplateArgumentLocInfo(getASTContext(), QualifierLoc, TemplateNameLoc, SourceLocation()); } case TemplateArgument::TemplateExpansion: { NestedNameSpecifierLoc QualifierLoc = readNestedNameSpecifierLoc(); SourceLocation TemplateNameLoc = readSourceLocation(); SourceLocation EllipsisLoc = readSourceLocation(); return TemplateArgumentLocInfo(getASTContext(), QualifierLoc, TemplateNameLoc, EllipsisLoc); } case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: case TemplateArgument::NullPtr: case TemplateArgument::StructuralValue: case TemplateArgument::Pack: // FIXME: Is this right? return TemplateArgumentLocInfo(); } llvm_unreachable("unexpected template argument loc"); } TemplateArgumentLoc ASTRecordReader::readTemplateArgumentLoc() { TemplateArgument Arg = readTemplateArgument(); if (Arg.getKind() == TemplateArgument::Expression) { if (readBool()) // bool InfoHasSameExpr. return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr())); } return TemplateArgumentLoc(Arg, readTemplateArgumentLocInfo(Arg.getKind())); } void ASTRecordReader::readTemplateArgumentListInfo( TemplateArgumentListInfo &Result) { Result.setLAngleLoc(readSourceLocation()); Result.setRAngleLoc(readSourceLocation()); unsigned NumArgsAsWritten = readInt(); for (unsigned i = 0; i != NumArgsAsWritten; ++i) Result.addArgument(readTemplateArgumentLoc()); } const ASTTemplateArgumentListInfo * ASTRecordReader::readASTTemplateArgumentListInfo() { TemplateArgumentListInfo Result; readTemplateArgumentListInfo(Result); return ASTTemplateArgumentListInfo::Create(getContext(), Result); } Decl *ASTReader::GetExternalDecl(GlobalDeclID ID) { return GetDecl(ID); } void ASTReader::CompleteRedeclChain(const Decl *D) { if (NumCurrentElementsDeserializing) { // We arrange to not care about the complete redeclaration chain while we're // deserializing. Just remember that the AST has marked this one as complete // but that it's not actually complete yet, so we know we still need to // complete it later. PendingIncompleteDeclChains.push_back(const_cast(D)); return; } if (!D->getDeclContext()) { assert(isa(D) && "Not a TU?"); return; } const DeclContext *DC = D->getDeclContext()->getRedeclContext(); // If this is a named declaration, complete it by looking it up // within its context. // // FIXME: Merging a function definition should merge // all mergeable entities within it. if (isa(DC)) { if (DeclarationName Name = cast(D)->getDeclName()) { if (!getContext().getLangOpts().CPlusPlus && isa(DC)) { // Outside of C++, we don't have a lookup table for the TU, so update // the identifier instead. (For C++ modules, we don't store decls // in the serialized identifier table, so we do the lookup in the TU.) auto *II = Name.getAsIdentifierInfo(); assert(II && "non-identifier name in C?"); if (II->isOutOfDate()) updateOutOfDateIdentifier(*II); } else DC->lookup(Name); } else if (needsAnonymousDeclarationNumber(cast(D))) { // Find all declarations of this kind from the relevant context. for (auto *DCDecl : cast(D->getLexicalDeclContext())->redecls()) { auto *DC = cast(DCDecl); SmallVector Decls; FindExternalLexicalDecls( DC, [&](Decl::Kind K) { return K == D->getKind(); }, Decls); } } } if (auto *CTSD = dyn_cast(D)) CTSD->getSpecializedTemplate()->LoadLazySpecializations(); if (auto *VTSD = dyn_cast(D)) VTSD->getSpecializedTemplate()->LoadLazySpecializations(); if (auto *FD = dyn_cast(D)) { if (auto *Template = FD->getPrimaryTemplate()) Template->LoadLazySpecializations(); } } CXXCtorInitializer ** ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) { RecordLocation Loc = getLocalBitOffset(Offset); BitstreamCursor &Cursor = Loc.F->DeclsCursor; SavedStreamPosition SavedPosition(Cursor); if (llvm::Error Err = Cursor.JumpToBit(Loc.Offset)) { Error(std::move(Err)); return nullptr; } ReadingKindTracker ReadingKind(Read_Decl, *this); Deserializing D(this); Expected MaybeCode = Cursor.ReadCode(); if (!MaybeCode) { Error(MaybeCode.takeError()); return nullptr; } unsigned Code = MaybeCode.get(); ASTRecordReader Record(*this, *Loc.F); Expected MaybeRecCode = Record.readRecord(Cursor, Code); if (!MaybeRecCode) { Error(MaybeRecCode.takeError()); return nullptr; } if (MaybeRecCode.get() != DECL_CXX_CTOR_INITIALIZERS) { Error("malformed AST file: missing C++ ctor initializers"); return nullptr; } return Record.readCXXCtorInitializers(); } 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); if (llvm::Error Err = Cursor.JumpToBit(Loc.Offset)) { Error(std::move(Err)); return nullptr; } ReadingKindTracker ReadingKind(Read_Decl, *this); Deserializing D(this); Expected MaybeCode = Cursor.ReadCode(); if (!MaybeCode) { Error(MaybeCode.takeError()); return nullptr; } unsigned Code = MaybeCode.get(); ASTRecordReader Record(*this, *Loc.F); Expected MaybeRecCode = Record.readRecord(Cursor, Code); if (!MaybeRecCode) { Error(MaybeCode.takeError()); return nullptr; } unsigned RecCode = MaybeRecCode.get(); if (RecCode != DECL_CXX_BASE_SPECIFIERS) { Error("malformed AST file: missing C++ base specifiers"); return nullptr; } unsigned NumBases = Record.readInt(); void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases); CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases]; for (unsigned I = 0; I != NumBases; ++I) Bases[I] = Record.readCXXBaseSpecifier(); return Bases; } GlobalDeclID ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const { if (LocalID < NUM_PREDEF_DECL_IDS) return GlobalDeclID(LocalID.getRawValue()); unsigned OwningModuleFileIndex = LocalID.getModuleFileIndex(); DeclID ID = LocalID.getLocalDeclIndex(); if (!F.ModuleOffsetMap.empty()) ReadModuleOffsetMap(F); ModuleFile *OwningModuleFile = OwningModuleFileIndex == 0 ? &F : F.TransitiveImports[OwningModuleFileIndex - 1]; if (OwningModuleFileIndex == 0) ID -= NUM_PREDEF_DECL_IDS; uint64_t NewModuleFileIndex = OwningModuleFile->Index + 1; return GlobalDeclID(NewModuleFileIndex, ID); } bool ASTReader::isDeclIDFromModule(GlobalDeclID ID, ModuleFile &M) const { // Predefined decls aren't from any module. if (ID < NUM_PREDEF_DECL_IDS) return false; unsigned ModuleFileIndex = ID.getModuleFileIndex(); return M.Index == ModuleFileIndex - 1; } ModuleFile *ASTReader::getOwningModuleFile(GlobalDeclID ID) const { // Predefined decls aren't from any module. if (ID < NUM_PREDEF_DECL_IDS) return nullptr; uint64_t ModuleFileIndex = ID.getModuleFileIndex(); assert(ModuleFileIndex && "Untranslated Local Decl?"); return &getModuleManager()[ModuleFileIndex - 1]; } ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) const { if (!D->isFromASTFile()) return nullptr; return getOwningModuleFile(D->getGlobalID()); } SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) { if (ID < NUM_PREDEF_DECL_IDS) return SourceLocation(); if (Decl *D = GetExistingDecl(ID)) return D->getLocation(); SourceLocation Loc; DeclCursorForID(ID, Loc); return Loc; } -static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) { +Decl *ASTReader::getPredefinedDecl(PredefinedDeclIDs ID) { + assert(ContextObj && "reading predefined decl without AST context"); + ASTContext &Context = *ContextObj; + Decl *NewLoaded = nullptr; switch (ID) { case PREDEF_DECL_NULL_ID: return nullptr; case PREDEF_DECL_TRANSLATION_UNIT_ID: return Context.getTranslationUnitDecl(); case PREDEF_DECL_OBJC_ID_ID: - return Context.getObjCIdDecl(); + if (Context.ObjCIdDecl) + return Context.ObjCIdDecl; + NewLoaded = Context.getObjCIdDecl(); + break; case PREDEF_DECL_OBJC_SEL_ID: - return Context.getObjCSelDecl(); + if (Context.ObjCSelDecl) + return Context.ObjCSelDecl; + NewLoaded = Context.getObjCSelDecl(); + break; case PREDEF_DECL_OBJC_CLASS_ID: - return Context.getObjCClassDecl(); + if (Context.ObjCClassDecl) + return Context.ObjCClassDecl; + NewLoaded = Context.getObjCClassDecl(); + break; case PREDEF_DECL_OBJC_PROTOCOL_ID: - return Context.getObjCProtocolDecl(); + if (Context.ObjCProtocolClassDecl) + return Context.ObjCProtocolClassDecl; + NewLoaded = Context.getObjCProtocolDecl(); + break; case PREDEF_DECL_INT_128_ID: - return Context.getInt128Decl(); + if (Context.Int128Decl) + return Context.Int128Decl; + NewLoaded = Context.getInt128Decl(); + break; case PREDEF_DECL_UNSIGNED_INT_128_ID: - return Context.getUInt128Decl(); + if (Context.UInt128Decl) + return Context.UInt128Decl; + NewLoaded = Context.getUInt128Decl(); + break; case PREDEF_DECL_OBJC_INSTANCETYPE_ID: - return Context.getObjCInstanceTypeDecl(); + if (Context.ObjCInstanceTypeDecl) + return Context.ObjCInstanceTypeDecl; + NewLoaded = Context.getObjCInstanceTypeDecl(); + break; case PREDEF_DECL_BUILTIN_VA_LIST_ID: - return Context.getBuiltinVaListDecl(); + if (Context.BuiltinVaListDecl) + return Context.BuiltinVaListDecl; + NewLoaded = Context.getBuiltinVaListDecl(); + break; case PREDEF_DECL_VA_LIST_TAG: - return Context.getVaListTagDecl(); + if (Context.VaListTagDecl) + return Context.VaListTagDecl; + NewLoaded = Context.getVaListTagDecl(); + break; case PREDEF_DECL_BUILTIN_MS_VA_LIST_ID: - return Context.getBuiltinMSVaListDecl(); + if (Context.BuiltinMSVaListDecl) + return Context.BuiltinMSVaListDecl; + NewLoaded = Context.getBuiltinMSVaListDecl(); + break; case PREDEF_DECL_BUILTIN_MS_GUID_ID: + // ASTContext::getMSGuidTagDecl won't create MSGuidTagDecl conditionally. return Context.getMSGuidTagDecl(); case PREDEF_DECL_EXTERN_C_CONTEXT_ID: - return Context.getExternCContextDecl(); + if (Context.ExternCContext) + return Context.ExternCContext; + NewLoaded = Context.getExternCContextDecl(); + break; case PREDEF_DECL_MAKE_INTEGER_SEQ_ID: - return Context.getMakeIntegerSeqDecl(); + if (Context.MakeIntegerSeqDecl) + return Context.MakeIntegerSeqDecl; + NewLoaded = Context.getMakeIntegerSeqDecl(); + break; case PREDEF_DECL_CF_CONSTANT_STRING_ID: - return Context.getCFConstantStringDecl(); + if (Context.CFConstantStringTypeDecl) + return Context.CFConstantStringTypeDecl; + NewLoaded = Context.getCFConstantStringDecl(); + break; case PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID: - return Context.getCFConstantStringTagDecl(); + if (Context.CFConstantStringTagDecl) + return Context.CFConstantStringTagDecl; + NewLoaded = Context.getCFConstantStringTagDecl(); + break; case PREDEF_DECL_TYPE_PACK_ELEMENT_ID: - return Context.getTypePackElementDecl(); + if (Context.TypePackElementDecl) + return Context.TypePackElementDecl; + NewLoaded = Context.getTypePackElementDecl(); + break; } - llvm_unreachable("PredefinedDeclIDs unknown enum value"); + + assert(NewLoaded && "Failed to load predefined decl?"); + + if (DeserializationListener) + DeserializationListener->PredefinedDeclBuilt(ID, NewLoaded); + + return NewLoaded; } unsigned ASTReader::translateGlobalDeclIDToIndex(GlobalDeclID GlobalID) const { ModuleFile *OwningModuleFile = getOwningModuleFile(GlobalID); if (!OwningModuleFile) { assert(GlobalID < NUM_PREDEF_DECL_IDS && "Untransalted Global ID?"); return GlobalID.getRawValue(); } return OwningModuleFile->BaseDeclIndex + GlobalID.getLocalDeclIndex(); } Decl *ASTReader::GetExistingDecl(GlobalDeclID ID) { assert(ContextObj && "reading decl with no AST context"); if (ID < NUM_PREDEF_DECL_IDS) { - Decl *D = getPredefinedDecl(*ContextObj, (PredefinedDeclIDs)ID); + Decl *D = getPredefinedDecl((PredefinedDeclIDs)ID); if (D) { // Track that we have merged the declaration with ID \p ID into the // pre-existing predefined declaration \p D. auto &Merged = KeyDecls[D->getCanonicalDecl()]; if (Merged.empty()) Merged.push_back(ID); } return D; } unsigned Index = translateGlobalDeclIDToIndex(ID); if (Index >= DeclsLoaded.size()) { assert(0 && "declaration ID out-of-range for AST file"); Error("declaration ID out-of-range for AST file"); return nullptr; } return DeclsLoaded[Index]; } Decl *ASTReader::GetDecl(GlobalDeclID ID) { if (ID < NUM_PREDEF_DECL_IDS) return GetExistingDecl(ID); unsigned Index = translateGlobalDeclIDToIndex(ID); if (Index >= DeclsLoaded.size()) { assert(0 && "declaration ID out-of-range for AST file"); Error("declaration ID out-of-range for AST file"); return nullptr; } if (!DeclsLoaded[Index]) { ReadDeclRecord(ID); if (DeserializationListener) DeserializationListener->DeclRead(ID, DeclsLoaded[Index]); } return DeclsLoaded[Index]; } LocalDeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M, GlobalDeclID GlobalID) { if (GlobalID < NUM_PREDEF_DECL_IDS) return LocalDeclID::get(*this, M, GlobalID.getRawValue()); if (!M.ModuleOffsetMap.empty()) ReadModuleOffsetMap(M); ModuleFile *Owner = getOwningModuleFile(GlobalID); DeclID ID = GlobalID.getLocalDeclIndex(); if (Owner == &M) { ID += NUM_PREDEF_DECL_IDS; return LocalDeclID::get(*this, M, ID); } uint64_t OrignalModuleFileIndex = 0; for (unsigned I = 0; I < M.TransitiveImports.size(); I++) if (M.TransitiveImports[I] == Owner) { OrignalModuleFileIndex = I + 1; break; } if (!OrignalModuleFileIndex) return LocalDeclID(); return LocalDeclID::get(*this, M, OrignalModuleFileIndex, ID); } GlobalDeclID ASTReader::ReadDeclID(ModuleFile &F, const RecordDataImpl &Record, unsigned &Idx) { if (Idx >= Record.size()) { Error("Corrupted AST file"); return GlobalDeclID(0); } return getGlobalDeclID(F, LocalDeclID::get(*this, F, Record[Idx++])); } /// Resolve the offset of a statement into a statement. /// /// This operation will read a new statement from the external /// source each time it is called, and is meant to be used via a /// LazyOffsetPtr (which is used by Decls for the body of functions, etc). Stmt *ASTReader::GetExternalDeclStmt(uint64_t Offset) { // Switch case IDs are per Decl. ClearSwitchCaseIDs(); // Offset here is a global offset across the entire chain. RecordLocation Loc = getLocalBitOffset(Offset); if (llvm::Error Err = Loc.F->DeclsCursor.JumpToBit(Loc.Offset)) { Error(std::move(Err)); return nullptr; } assert(NumCurrentElementsDeserializing == 0 && "should not be called while already deserializing"); Deserializing D(this); return ReadStmtFromStream(*Loc.F); } void ASTReader::FindExternalLexicalDecls( const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Decls) { bool PredefsVisited[NUM_PREDEF_DECL_IDS] = {}; auto Visit = [&] (ModuleFile *M, LexicalContents LexicalDecls) { assert(LexicalDecls.size() % 2 == 0 && "expected an even number of entries"); for (int I = 0, N = LexicalDecls.size(); I != N; I += 2) { auto K = (Decl::Kind)+LexicalDecls[I]; if (!IsKindWeWant(K)) continue; auto ID = (DeclID) + LexicalDecls[I + 1]; // Don't add predefined declarations to the lexical context more // than once. if (ID < NUM_PREDEF_DECL_IDS) { if (PredefsVisited[ID]) continue; PredefsVisited[ID] = true; } if (Decl *D = GetLocalDecl(*M, LocalDeclID::get(*this, *M, ID))) { assert(D->getKind() == K && "wrong kind for lexical decl"); if (!DC->isDeclInLexicalTraversal(D)) Decls.push_back(D); } } }; if (isa(DC)) { for (const auto &Lexical : TULexicalDecls) Visit(Lexical.first, Lexical.second); } else { auto I = LexicalDecls.find(DC); if (I != LexicalDecls.end()) Visit(I->second.first, I->second.second); } ++NumLexicalDeclContextsRead; } namespace { class UnalignedDeclIDComp { ASTReader &Reader; ModuleFile &Mod; public: UnalignedDeclIDComp(ASTReader &Reader, ModuleFile &M) : Reader(Reader), Mod(M) {} bool operator()(unaligned_decl_id_t L, unaligned_decl_id_t R) const { SourceLocation LHS = getLocation(L); SourceLocation RHS = getLocation(R); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } bool operator()(SourceLocation LHS, unaligned_decl_id_t R) const { SourceLocation RHS = getLocation(R); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } bool operator()(unaligned_decl_id_t L, SourceLocation RHS) const { SourceLocation LHS = getLocation(L); return Reader.getSourceManager().isBeforeInTranslationUnit(LHS, RHS); } SourceLocation getLocation(unaligned_decl_id_t ID) const { return Reader.getSourceManager().getFileLoc( Reader.getSourceLocationForDeclID( Reader.getGlobalDeclID(Mod, LocalDeclID::get(Reader, Mod, ID)))); } }; } // namespace void ASTReader::FindFileRegionDecls(FileID File, unsigned Offset, unsigned Length, SmallVectorImpl &Decls) { SourceManager &SM = getSourceManager(); llvm::DenseMap::iterator I = FileDeclIDs.find(File); if (I == FileDeclIDs.end()) return; FileDeclsInfo &DInfo = I->second; if (DInfo.Decls.empty()) return; SourceLocation BeginLoc = SM.getLocForStartOfFile(File).getLocWithOffset(Offset); SourceLocation EndLoc = BeginLoc.getLocWithOffset(Length); UnalignedDeclIDComp DIDComp(*this, *DInfo.Mod); ArrayRef::iterator BeginIt = llvm::lower_bound(DInfo.Decls, BeginLoc, DIDComp); if (BeginIt != DInfo.Decls.begin()) --BeginIt; // If we are pointing at a top-level decl inside an objc container, we need // to backtrack until we find it otherwise we will fail to report that the // region overlaps with an objc container. while (BeginIt != DInfo.Decls.begin() && GetDecl(getGlobalDeclID(*DInfo.Mod, LocalDeclID::get(*this, *DInfo.Mod, *BeginIt))) ->isTopLevelDeclInObjCContainer()) --BeginIt; ArrayRef::iterator EndIt = llvm::upper_bound(DInfo.Decls, EndLoc, DIDComp); if (EndIt != DInfo.Decls.end()) ++EndIt; for (ArrayRef::iterator DIt = BeginIt; DIt != EndIt; ++DIt) Decls.push_back(GetDecl(getGlobalDeclID( *DInfo.Mod, LocalDeclID::get(*this, *DInfo.Mod, *DIt)))); } bool ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { assert(DC->hasExternalVisibleStorage() && DC == DC->getPrimaryContext() && "DeclContext has no visible decls in storage"); if (!Name) return false; auto It = Lookups.find(DC); if (It == Lookups.end()) return false; Deserializing LookupResults(this); // Load the list of declarations. SmallVector Decls; llvm::SmallPtrSet Found; for (GlobalDeclID ID : It->second.Table.find(Name)) { NamedDecl *ND = cast(GetDecl(ID)); if (ND->getDeclName() == Name && Found.insert(ND).second) Decls.push_back(ND); } ++NumVisibleDeclContextsRead; SetExternalVisibleDeclsForName(DC, Name, Decls); return !Decls.empty(); } void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) { if (!DC->hasExternalVisibleStorage()) return; auto It = Lookups.find(DC); assert(It != Lookups.end() && "have external visible storage but no lookup tables"); DeclsMap Decls; for (GlobalDeclID ID : It->second.Table.findAll()) { NamedDecl *ND = cast(GetDecl(ID)); Decls[ND->getDeclName()].push_back(ND); } ++NumVisibleDeclContextsRead; for (DeclsMap::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) { SetExternalVisibleDeclsForName(DC, I->first, I->second); } const_cast(DC)->setHasExternalVisibleStorage(false); } const serialization::reader::DeclContextLookupTable * ASTReader::getLoadedLookupTables(DeclContext *Primary) const { auto I = Lookups.find(Primary); return I == Lookups.end() ? nullptr : &I->second; } /// Under non-PCH compilation the consumer receives the objc methods /// before receiving the implementation, and codegen depends on this. /// We simulate this by deserializing and passing to consumer the methods of the /// implementation before passing the deserialized implementation decl. static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD, ASTConsumer *Consumer) { assert(ImplD && Consumer); for (auto *I : ImplD->methods()) Consumer->HandleInterestingDecl(DeclGroupRef(I)); Consumer->HandleInterestingDecl(DeclGroupRef(ImplD)); } void ASTReader::PassInterestingDeclToConsumer(Decl *D) { if (ObjCImplDecl *ImplD = dyn_cast(D)) PassObjCImplDeclToConsumer(ImplD, Consumer); else Consumer->HandleInterestingDecl(DeclGroupRef(D)); } void ASTReader::PassVTableToConsumer(CXXRecordDecl *RD) { Consumer->HandleVTable(RD); } void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) { this->Consumer = Consumer; if (Consumer) PassInterestingDeclsToConsumer(); if (DeserializationListener) DeserializationListener->ReaderInitialized(this); } void ASTReader::PrintStats() { std::fprintf(stderr, "*** AST File Statistics:\n"); unsigned NumTypesLoaded = TypesLoaded.size() - llvm::count(TypesLoaded.materialized(), QualType()); unsigned NumDeclsLoaded = DeclsLoaded.size() - llvm::count(DeclsLoaded.materialized(), (Decl *)nullptr); unsigned NumIdentifiersLoaded = IdentifiersLoaded.size() - llvm::count(IdentifiersLoaded, (IdentifierInfo *)nullptr); unsigned NumMacrosLoaded = MacrosLoaded.size() - llvm::count(MacrosLoaded, (MacroInfo *)nullptr); unsigned NumSelectorsLoaded = SelectorsLoaded.size() - llvm::count(SelectorsLoaded, Selector()); if (unsigned TotalNumSLocEntries = getTotalNumSLocs()) std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n", NumSLocEntriesRead, TotalNumSLocEntries, ((float)NumSLocEntriesRead/TotalNumSLocEntries * 100)); if (!TypesLoaded.empty()) std::fprintf(stderr, " %u/%u types read (%f%%)\n", NumTypesLoaded, (unsigned)TypesLoaded.size(), ((float)NumTypesLoaded/TypesLoaded.size() * 100)); if (!DeclsLoaded.empty()) std::fprintf(stderr, " %u/%u declarations read (%f%%)\n", NumDeclsLoaded, (unsigned)DeclsLoaded.size(), ((float)NumDeclsLoaded/DeclsLoaded.size() * 100)); if (!IdentifiersLoaded.empty()) std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n", NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(), ((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100)); if (!MacrosLoaded.empty()) std::fprintf(stderr, " %u/%u macros read (%f%%)\n", NumMacrosLoaded, (unsigned)MacrosLoaded.size(), ((float)NumMacrosLoaded/MacrosLoaded.size() * 100)); if (!SelectorsLoaded.empty()) std::fprintf(stderr, " %u/%u selectors read (%f%%)\n", NumSelectorsLoaded, (unsigned)SelectorsLoaded.size(), ((float)NumSelectorsLoaded/SelectorsLoaded.size() * 100)); if (TotalNumStatements) std::fprintf(stderr, " %u/%u statements read (%f%%)\n", NumStatementsRead, TotalNumStatements, ((float)NumStatementsRead/TotalNumStatements * 100)); if (TotalNumMacros) std::fprintf(stderr, " %u/%u macros read (%f%%)\n", NumMacrosRead, TotalNumMacros, ((float)NumMacrosRead/TotalNumMacros * 100)); if (TotalLexicalDeclContexts) std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n", NumLexicalDeclContextsRead, TotalLexicalDeclContexts, ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts * 100)); if (TotalVisibleDeclContexts) std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n", NumVisibleDeclContextsRead, TotalVisibleDeclContexts, ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts * 100)); if (TotalNumMethodPoolEntries) std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n", NumMethodPoolEntriesRead, TotalNumMethodPoolEntries, ((float)NumMethodPoolEntriesRead/TotalNumMethodPoolEntries * 100)); if (NumMethodPoolLookups) std::fprintf(stderr, " %u/%u method pool lookups succeeded (%f%%)\n", NumMethodPoolHits, NumMethodPoolLookups, ((float)NumMethodPoolHits/NumMethodPoolLookups * 100.0)); if (NumMethodPoolTableLookups) std::fprintf(stderr, " %u/%u method pool table lookups succeeded (%f%%)\n", NumMethodPoolTableHits, NumMethodPoolTableLookups, ((float)NumMethodPoolTableHits/NumMethodPoolTableLookups * 100.0)); if (NumIdentifierLookupHits) std::fprintf(stderr, " %u / %u identifier table lookups succeeded (%f%%)\n", NumIdentifierLookupHits, NumIdentifierLookups, (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups); if (GlobalIndex) { std::fprintf(stderr, "\n"); GlobalIndex->printStats(); } std::fprintf(stderr, "\n"); dump(); std::fprintf(stderr, "\n"); } template LLVM_DUMP_METHOD static void dumpModuleIDMap(StringRef Name, const ContinuousRangeMap &Map) { if (Map.begin() == Map.end()) return; using MapType = ContinuousRangeMap; llvm::errs() << Name << ":\n"; for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end(); I != IEnd; ++I) llvm::errs() << " " << (DeclID)I->first << " -> " << I->second->FileName << "\n"; } LLVM_DUMP_METHOD void ASTReader::dump() { llvm::errs() << "*** PCH/ModuleFile Remappings:\n"; dumpModuleIDMap("Global bit offset map", GlobalBitOffsetsMap); dumpModuleIDMap("Global source location entry map", GlobalSLocEntryMap); dumpModuleIDMap("Global macro map", GlobalMacroMap); dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap); dumpModuleIDMap("Global selector map", GlobalSelectorMap); dumpModuleIDMap("Global preprocessed entity map", GlobalPreprocessedEntityMap); llvm::errs() << "\n*** PCH/Modules Loaded:"; 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 (ModuleFile &I : ModuleMgr) { if (llvm::MemoryBuffer *buf = I.Buffer) { size_t bytes = buf->getBufferSize(); switch (buf->getBufferKind()) { case llvm::MemoryBuffer::MemoryBuffer_Malloc: sizes.malloc_bytes += bytes; break; case llvm::MemoryBuffer::MemoryBuffer_MMap: sizes.mmap_bytes += bytes; break; } } } } void ASTReader::InitializeSema(Sema &S) { SemaObj = &S; S.addExternalSource(this); // Makes sure any declarations that were deserialized "too early" // still get added to the identifier's declaration chains. for (GlobalDeclID ID : PreloadedDeclIDs) { NamedDecl *D = cast(GetDecl(ID)); pushExternalDeclIntoScope(D, D->getDeclName()); } PreloadedDeclIDs.clear(); // FIXME: What happens if these are changed by a module import? if (!FPPragmaOptions.empty()) { assert(FPPragmaOptions.size() == 1 && "Wrong number of FP_PRAGMA_OPTIONS"); FPOptionsOverride NewOverrides = FPOptionsOverride::getFromOpaqueInt(FPPragmaOptions[0]); SemaObj->CurFPFeatures = NewOverrides.applyOverrides(SemaObj->getLangOpts()); } SemaObj->OpenCLFeatures = OpenCLExtensions; UpdateSema(); } void ASTReader::UpdateSema() { assert(SemaObj && "no Sema to update"); // Load the offsets of the declarations that Sema references. // They will be lazily deserialized when needed. if (!SemaDeclRefs.empty()) { assert(SemaDeclRefs.size() % 3 == 0); for (unsigned I = 0; I != SemaDeclRefs.size(); I += 3) { if (!SemaObj->StdNamespace) SemaObj->StdNamespace = SemaDeclRefs[I].getRawValue(); if (!SemaObj->StdBadAlloc) SemaObj->StdBadAlloc = SemaDeclRefs[I + 1].getRawValue(); if (!SemaObj->StdAlignValT) SemaObj->StdAlignValT = SemaDeclRefs[I + 2].getRawValue(); } SemaDeclRefs.clear(); } // Update the state of pragmas. Use the same API as if we had encountered the // pragma in the source. if(OptimizeOffPragmaLocation.isValid()) SemaObj->ActOnPragmaOptimize(/* On = */ false, OptimizeOffPragmaLocation); if (PragmaMSStructState != -1) SemaObj->ActOnPragmaMSStruct((PragmaMSStructKind)PragmaMSStructState); if (PointersToMembersPragmaLocation.isValid()) { SemaObj->ActOnPragmaMSPointersToMembers( (LangOptions::PragmaMSPointersToMembersKind) PragmaMSPointersToMembersState, PointersToMembersPragmaLocation); } SemaObj->CUDA().ForceHostDeviceDepth = ForceHostDeviceDepth; if (PragmaAlignPackCurrentValue) { // 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 (!PragmaAlignPackStack.empty() && PragmaAlignPackStack.front().Location.isInvalid()) { assert(PragmaAlignPackStack.front().Value == SemaObj->AlignPackStack.DefaultValue && "Expected a default alignment value"); SemaObj->AlignPackStack.Stack.emplace_back( PragmaAlignPackStack.front().SlotLabel, SemaObj->AlignPackStack.CurrentValue, SemaObj->AlignPackStack.CurrentPragmaLocation, PragmaAlignPackStack.front().PushLocation); DropFirst = true; } for (const auto &Entry : llvm::ArrayRef(PragmaAlignPackStack).drop_front(DropFirst ? 1 : 0)) { SemaObj->AlignPackStack.Stack.emplace_back( Entry.SlotLabel, Entry.Value, Entry.Location, Entry.PushLocation); } if (PragmaAlignPackCurrentLocation.isInvalid()) { assert(*PragmaAlignPackCurrentValue == SemaObj->AlignPackStack.DefaultValue && "Expected a default align and pack value"); // Keep the current values. } else { SemaObj->AlignPackStack.CurrentValue = *PragmaAlignPackCurrentValue; SemaObj->AlignPackStack.CurrentPragmaLocation = PragmaAlignPackCurrentLocation; } } if (FpPragmaCurrentValue) { // The bottom of the stack might have a default value. It must be adjusted // to the current value to ensure that fp-pragma state is preserved after // popping entries that were included/imported from a PCH/module. bool DropFirst = false; if (!FpPragmaStack.empty() && FpPragmaStack.front().Location.isInvalid()) { assert(FpPragmaStack.front().Value == SemaObj->FpPragmaStack.DefaultValue && "Expected a default pragma float_control value"); SemaObj->FpPragmaStack.Stack.emplace_back( FpPragmaStack.front().SlotLabel, SemaObj->FpPragmaStack.CurrentValue, SemaObj->FpPragmaStack.CurrentPragmaLocation, FpPragmaStack.front().PushLocation); DropFirst = true; } for (const auto &Entry : llvm::ArrayRef(FpPragmaStack).drop_front(DropFirst ? 1 : 0)) SemaObj->FpPragmaStack.Stack.emplace_back( Entry.SlotLabel, Entry.Value, Entry.Location, Entry.PushLocation); if (FpPragmaCurrentLocation.isInvalid()) { assert(*FpPragmaCurrentValue == SemaObj->FpPragmaStack.DefaultValue && "Expected a default pragma float_control value"); // Keep the current values. } else { SemaObj->FpPragmaStack.CurrentValue = *FpPragmaCurrentValue; SemaObj->FpPragmaStack.CurrentPragmaLocation = FpPragmaCurrentLocation; } } // For non-modular AST files, restore visiblity of modules. for (auto &Import : PendingImportedModulesSema) { if (Import.ImportLoc.isInvalid()) continue; if (Module *Imported = getSubmodule(Import.ID)) { SemaObj->makeModuleVisible(Imported, Import.ImportLoc); } } PendingImportedModulesSema.clear(); } IdentifierInfo *ASTReader::get(StringRef Name) { // Note that we are loading an identifier. Deserializing AnIdentifier(this); IdentifierLookupVisitor Visitor(Name, /*PriorGeneration=*/0, NumIdentifierLookups, NumIdentifierLookupHits); // We don't need to do identifier table lookups in C++ modules (we preload // all interesting declarations, and don't need to use the scope for name // lookups). Perform the lookup in PCH files, though, since we don't build // a complete initial identifier table if we're carrying on from a PCH. if (PP.getLangOpts().CPlusPlus) { for (auto *F : ModuleMgr.pch_modules()) if (Visitor(*F)) break; } else { // If there is a global index, look there first to determine which modules // provably do not have any results for this identifier. GlobalModuleIndex::HitSet Hits; GlobalModuleIndex::HitSet *HitsPtr = nullptr; if (!loadGlobalIndex()) { if (GlobalIndex->lookupIdentifier(Name, Hits)) { HitsPtr = &Hits; } } ModuleMgr.visit(Visitor, HitsPtr); } IdentifierInfo *II = Visitor.getIdentifierInfo(); markIdentifierUpToDate(II); return II; } namespace clang { /// An identifier-lookup iterator that enumerates all of the /// identifiers stored within a set of AST files. class ASTIdentifierIterator : public IdentifierIterator { /// The AST reader whose identifiers are being enumerated. const ASTReader &Reader; /// The current index into the chain of AST files stored in /// the AST reader. unsigned Index; /// The current position within the identifier lookup table /// of the current AST file. ASTIdentifierLookupTable::key_iterator Current; /// The end position within the identifier lookup table of /// the current AST file. ASTIdentifierLookupTable::key_iterator End; /// Whether to skip any modules in the ASTReader. bool SkipModules; public: explicit ASTIdentifierIterator(const ASTReader &Reader, bool SkipModules = false); StringRef Next() override; }; } // namespace clang ASTIdentifierIterator::ASTIdentifierIterator(const ASTReader &Reader, bool SkipModules) : Reader(Reader), Index(Reader.ModuleMgr.size()), SkipModules(SkipModules) { } StringRef ASTIdentifierIterator::Next() { while (Current == End) { // If we have exhausted all of our AST files, we're done. if (Index == 0) return StringRef(); --Index; ModuleFile &F = Reader.ModuleMgr[Index]; if (SkipModules && F.isModule()) continue; ASTIdentifierLookupTable *IdTable = (ASTIdentifierLookupTable *)F.IdentifierLookupTable; Current = IdTable->key_begin(); End = IdTable->key_end(); } // We have any identifiers remaining in the current AST file; return // the next one. StringRef Result = *Current; ++Current; return Result; } namespace { /// A utility for appending two IdentifierIterators. class ChainedIdentifierIterator : public IdentifierIterator { std::unique_ptr Current; std::unique_ptr Queued; public: ChainedIdentifierIterator(std::unique_ptr First, std::unique_ptr Second) : Current(std::move(First)), Queued(std::move(Second)) {} StringRef Next() override { if (!Current) return StringRef(); StringRef result = Current->Next(); if (!result.empty()) return result; // Try the queued iterator, which may itself be empty. Current.reset(); std::swap(Current, Queued); return Next(); } }; } // namespace IdentifierIterator *ASTReader::getIdentifiers() { if (!loadGlobalIndex()) { std::unique_ptr ReaderIter( new ASTIdentifierIterator(*this, /*SkipModules=*/true)); std::unique_ptr ModulesIter( GlobalIndex->createIdentifierIterator()); return new ChainedIdentifierIterator(std::move(ReaderIter), std::move(ModulesIter)); } return new ASTIdentifierIterator(*this); } namespace clang { namespace serialization { class ReadMethodPoolVisitor { ASTReader &Reader; Selector Sel; unsigned PriorGeneration; unsigned InstanceBits = 0; unsigned FactoryBits = 0; bool InstanceHasMoreThanOneDecl = false; bool FactoryHasMoreThanOneDecl = false; SmallVector InstanceMethods; SmallVector FactoryMethods; public: ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel, unsigned PriorGeneration) : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) {} bool operator()(ModuleFile &M) { if (!M.SelectorLookupTable) return false; // If we've already searched this module file, skip it now. if (M.Generation <= PriorGeneration) return true; ++Reader.NumMethodPoolTableLookups; ASTSelectorLookupTable *PoolTable = (ASTSelectorLookupTable*)M.SelectorLookupTable; ASTSelectorLookupTable::iterator Pos = PoolTable->find(Sel); if (Pos == PoolTable->end()) return false; ++Reader.NumMethodPoolTableHits; ++Reader.NumSelectorsRead; // FIXME: Not quite happy with the statistics here. We probably should // disable this tracking when called via LoadSelector. // Also, should entries without methods count as misses? ++Reader.NumMethodPoolEntriesRead; ASTSelectorLookupTrait::data_type Data = *Pos; if (Reader.DeserializationListener) Reader.DeserializationListener->SelectorRead(Data.ID, Sel); // Append methods in the reverse order, so that later we can process them // in the order they appear in the source code by iterating through // the vector in the reverse order. InstanceMethods.append(Data.Instance.rbegin(), Data.Instance.rend()); FactoryMethods.append(Data.Factory.rbegin(), Data.Factory.rend()); InstanceBits = Data.InstanceBits; FactoryBits = Data.FactoryBits; InstanceHasMoreThanOneDecl = Data.InstanceHasMoreThanOneDecl; FactoryHasMoreThanOneDecl = Data.FactoryHasMoreThanOneDecl; return false; } /// Retrieve the instance methods found by this visitor. ArrayRef getInstanceMethods() const { return InstanceMethods; } /// Retrieve the instance methods found by this visitor. ArrayRef getFactoryMethods() const { return FactoryMethods; } unsigned getInstanceBits() const { return InstanceBits; } unsigned getFactoryBits() const { return FactoryBits; } bool instanceHasMoreThanOneDecl() const { return InstanceHasMoreThanOneDecl; } bool factoryHasMoreThanOneDecl() const { return FactoryHasMoreThanOneDecl; } }; } // namespace serialization } // namespace clang /// Add the given set of methods to the method list. static void addMethodsToPool(Sema &S, ArrayRef Methods, ObjCMethodList &List) { for (ObjCMethodDecl *M : llvm::reverse(Methods)) S.ObjC().addMethodToGlobalList(&List, M); } void ASTReader::ReadMethodPool(Selector Sel) { // Get the selector generation and update it to the current generation. unsigned &Generation = SelectorGeneration[Sel]; unsigned PriorGeneration = Generation; Generation = getGeneration(); SelectorOutOfDate[Sel] = false; // Search for methods defined with this selector. ++NumMethodPoolLookups; ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration); ModuleMgr.visit(Visitor); if (Visitor.getInstanceMethods().empty() && Visitor.getFactoryMethods().empty()) return; ++NumMethodPoolHits; if (!getSema()) return; Sema &S = *getSema(); SemaObjC::GlobalMethodPool::iterator Pos = S.ObjC() .MethodPool .insert(std::make_pair(Sel, SemaObjC::GlobalMethodPool::Lists())) .first; Pos->second.first.setBits(Visitor.getInstanceBits()); Pos->second.first.setHasMoreThanOneDecl(Visitor.instanceHasMoreThanOneDecl()); Pos->second.second.setBits(Visitor.getFactoryBits()); Pos->second.second.setHasMoreThanOneDecl(Visitor.factoryHasMoreThanOneDecl()); // Add methods to the global pool *after* setting hasMoreThanOneDecl, since // when building a module we keep every method individually and may need to // update hasMoreThanOneDecl as we add the methods. addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first); addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second); } void ASTReader::updateOutOfDateSelector(Selector Sel) { if (SelectorOutOfDate[Sel]) ReadMethodPool(Sel); } void ASTReader::ReadKnownNamespaces( SmallVectorImpl &Namespaces) { Namespaces.clear(); for (unsigned I = 0, N = KnownNamespaces.size(); I != N; ++I) { if (NamespaceDecl *Namespace = dyn_cast_or_null(GetDecl(KnownNamespaces[I]))) Namespaces.push_back(Namespace); } } void ASTReader::ReadUndefinedButUsed( llvm::MapVector &Undefined) { for (unsigned Idx = 0, N = UndefinedButUsed.size(); Idx != N;) { UndefinedButUsedDecl &U = UndefinedButUsed[Idx++]; NamedDecl *D = cast(GetDecl(U.ID)); SourceLocation Loc = SourceLocation::getFromRawEncoding(U.RawLoc); Undefined.insert(std::make_pair(D, Loc)); } UndefinedButUsed.clear(); } void ASTReader::ReadMismatchingDeleteExpressions(llvm::MapVector< FieldDecl *, llvm::SmallVector, 4>> & Exprs) { for (unsigned Idx = 0, N = DelayedDeleteExprs.size(); Idx != N;) { FieldDecl *FD = cast(GetDecl(GlobalDeclID(DelayedDeleteExprs[Idx++]))); uint64_t Count = DelayedDeleteExprs[Idx++]; for (uint64_t C = 0; C < Count; ++C) { SourceLocation DeleteLoc = SourceLocation::getFromRawEncoding(DelayedDeleteExprs[Idx++]); const bool IsArrayForm = DelayedDeleteExprs[Idx++]; Exprs[FD].push_back(std::make_pair(DeleteLoc, IsArrayForm)); } } } void ASTReader::ReadTentativeDefinitions( SmallVectorImpl &TentativeDefs) { for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) { VarDecl *Var = dyn_cast_or_null(GetDecl(TentativeDefinitions[I])); if (Var) TentativeDefs.push_back(Var); } TentativeDefinitions.clear(); } void ASTReader::ReadUnusedFileScopedDecls( SmallVectorImpl &Decls) { for (unsigned I = 0, N = UnusedFileScopedDecls.size(); I != N; ++I) { DeclaratorDecl *D = dyn_cast_or_null(GetDecl(UnusedFileScopedDecls[I])); if (D) Decls.push_back(D); } UnusedFileScopedDecls.clear(); } void ASTReader::ReadDelegatingConstructors( SmallVectorImpl &Decls) { for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) { CXXConstructorDecl *D = dyn_cast_or_null(GetDecl(DelegatingCtorDecls[I])); if (D) Decls.push_back(D); } DelegatingCtorDecls.clear(); } void ASTReader::ReadExtVectorDecls(SmallVectorImpl &Decls) { for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) { TypedefNameDecl *D = dyn_cast_or_null(GetDecl(ExtVectorDecls[I])); if (D) Decls.push_back(D); } ExtVectorDecls.clear(); } void ASTReader::ReadUnusedLocalTypedefNameCandidates( llvm::SmallSetVector &Decls) { for (unsigned I = 0, N = UnusedLocalTypedefNameCandidates.size(); I != N; ++I) { TypedefNameDecl *D = dyn_cast_or_null( GetDecl(UnusedLocalTypedefNameCandidates[I])); if (D) Decls.insert(D); } UnusedLocalTypedefNameCandidates.clear(); } void ASTReader::ReadDeclsToCheckForDeferredDiags( llvm::SmallSetVector &Decls) { for (auto I : DeclsToCheckForDeferredDiags) { auto *D = dyn_cast_or_null(GetDecl(I)); if (D) Decls.insert(D); } DeclsToCheckForDeferredDiags.clear(); } void ASTReader::ReadReferencedSelectors( SmallVectorImpl> &Sels) { if (ReferencedSelectorsData.empty()) return; // If there are @selector references added them to its pool. This is for // implementation of -Wselector. unsigned int DataSize = ReferencedSelectorsData.size()-1; unsigned I = 0; while (I < DataSize) { Selector Sel = DecodeSelector(ReferencedSelectorsData[I++]); SourceLocation SelLoc = SourceLocation::getFromRawEncoding(ReferencedSelectorsData[I++]); Sels.push_back(std::make_pair(Sel, SelLoc)); } ReferencedSelectorsData.clear(); } void ASTReader::ReadWeakUndeclaredIdentifiers( SmallVectorImpl> &WeakIDs) { if (WeakUndeclaredIdentifiers.empty()) return; for (unsigned I = 0, N = WeakUndeclaredIdentifiers.size(); I < N; /*none*/) { IdentifierInfo *WeakId = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]); IdentifierInfo *AliasId = DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]); SourceLocation Loc = SourceLocation::getFromRawEncoding(WeakUndeclaredIdentifiers[I++]); WeakInfo WI(AliasId, Loc); WeakIDs.push_back(std::make_pair(WeakId, WI)); } WeakUndeclaredIdentifiers.clear(); } void ASTReader::ReadUsedVTables(SmallVectorImpl &VTables) { for (unsigned Idx = 0, N = VTableUses.size(); Idx < N; /* In loop */) { ExternalVTableUse VT; VTableUse &TableInfo = VTableUses[Idx++]; VT.Record = dyn_cast_or_null(GetDecl(TableInfo.ID)); VT.Location = SourceLocation::getFromRawEncoding(TableInfo.RawLoc); VT.DefinitionRequired = TableInfo.Used; VTables.push_back(VT); } VTableUses.clear(); } void ASTReader::ReadPendingInstantiations( SmallVectorImpl> &Pending) { for (unsigned Idx = 0, N = PendingInstantiations.size(); Idx < N;) { PendingInstantiation &Inst = PendingInstantiations[Idx++]; ValueDecl *D = cast(GetDecl(Inst.ID)); SourceLocation Loc = SourceLocation::getFromRawEncoding(Inst.RawLoc); Pending.push_back(std::make_pair(D, Loc)); } PendingInstantiations.clear(); } void ASTReader::ReadLateParsedTemplates( llvm::MapVector> &LPTMap) { for (auto &LPT : LateParsedTemplates) { ModuleFile *FMod = LPT.first; RecordDataImpl &LateParsed = LPT.second; for (unsigned Idx = 0, N = LateParsed.size(); Idx < N; /* In loop */) { FunctionDecl *FD = ReadDeclAs(*FMod, LateParsed, Idx); auto LT = std::make_unique(); LT->D = ReadDecl(*FMod, LateParsed, Idx); LT->FPO = FPOptions::getFromOpaqueInt(LateParsed[Idx++]); ModuleFile *F = getOwningModuleFile(LT->D); assert(F && "No module"); unsigned TokN = LateParsed[Idx++]; LT->Toks.reserve(TokN); for (unsigned T = 0; T < TokN; ++T) LT->Toks.push_back(ReadToken(*F, LateParsed, Idx)); LPTMap.insert(std::make_pair(FD, std::move(LT))); } } LateParsedTemplates.clear(); } void ASTReader::AssignedLambdaNumbering(const CXXRecordDecl *Lambda) { if (Lambda->getLambdaContextDecl()) { // Keep track of this lambda so it can be merged with another lambda that // is loaded later. LambdaDeclarationsForMerging.insert( {{Lambda->getLambdaContextDecl()->getCanonicalDecl(), Lambda->getLambdaIndexInContext()}, const_cast(Lambda)}); } } void ASTReader::LoadSelector(Selector Sel) { // It would be complicated to avoid reading the methods anyway. So don't. ReadMethodPool(Sel); } void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) { assert(ID && "Non-zero identifier ID required"); unsigned Index = translateIdentifierIDToIndex(ID).second; assert(Index < IdentifiersLoaded.size() && "identifier ID out of range"); IdentifiersLoaded[Index] = II; if (DeserializationListener) DeserializationListener->IdentifierRead(ID, II); } /// Set the globally-visible declarations associated with the given /// identifier. /// /// If the AST reader is currently in a state where the given declaration IDs /// cannot safely be resolved, they are queued until it is safe to resolve /// them. /// /// \param II an IdentifierInfo that refers to one or more globally-visible /// declarations. /// /// \param DeclIDs the set of declaration IDs with the name @p II that are /// visible at global scope. /// /// \param Decls if non-null, this vector will be populated with the set of /// deserialized declarations. These declarations will not be pushed into /// scope. void ASTReader::SetGloballyVisibleDecls( IdentifierInfo *II, const SmallVectorImpl &DeclIDs, SmallVectorImpl *Decls) { if (NumCurrentElementsDeserializing && !Decls) { PendingIdentifierInfos[II].append(DeclIDs.begin(), DeclIDs.end()); return; } for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) { if (!SemaObj) { // Queue this declaration so that it will be added to the // translation unit scope and identifier's declaration chain // once a Sema object is known. PreloadedDeclIDs.push_back(DeclIDs[I]); continue; } NamedDecl *D = cast(GetDecl(DeclIDs[I])); // If we're simply supposed to record the declarations, do so now. if (Decls) { Decls->push_back(D); continue; } // Introduce this declaration into the translation-unit scope // and add it to the declaration chain for this identifier, so // that (unqualified) name lookup will find it. pushExternalDeclIntoScope(D, II); } } std::pair ASTReader::translateIdentifierIDToIndex(IdentifierID ID) const { if (ID == 0) return {nullptr, 0}; unsigned ModuleFileIndex = ID >> 32; unsigned LocalID = ID & llvm::maskTrailingOnes(32); assert(ModuleFileIndex && "not translating loaded IdentifierID?"); assert(getModuleManager().size() > ModuleFileIndex - 1); ModuleFile &MF = getModuleManager()[ModuleFileIndex - 1]; assert(LocalID < MF.LocalNumIdentifiers); return {&MF, MF.BaseIdentifierID + LocalID}; } IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) { if (ID == 0) return nullptr; if (IdentifiersLoaded.empty()) { Error("no identifier table in AST file"); return nullptr; } auto [M, Index] = translateIdentifierIDToIndex(ID); if (!IdentifiersLoaded[Index]) { assert(M != nullptr && "Untranslated Identifier ID?"); assert(Index >= M->BaseIdentifierID); unsigned LocalIndex = Index - M->BaseIdentifierID; const unsigned char *Data = M->IdentifierTableData + M->IdentifierOffsets[LocalIndex]; ASTIdentifierLookupTrait Trait(*this, *M); auto KeyDataLen = Trait.ReadKeyDataLength(Data); auto Key = Trait.ReadKey(Data, KeyDataLen.first); auto &II = PP.getIdentifierTable().get(Key); IdentifiersLoaded[Index] = &II; markIdentifierFromAST(*this, II); if (DeserializationListener) DeserializationListener->IdentifierRead(ID, &II); } return IdentifiersLoaded[Index]; } IdentifierInfo *ASTReader::getLocalIdentifier(ModuleFile &M, uint64_t LocalID) { return DecodeIdentifierInfo(getGlobalIdentifierID(M, LocalID)); } IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, uint64_t LocalID) { if (LocalID < NUM_PREDEF_IDENT_IDS) return LocalID; if (!M.ModuleOffsetMap.empty()) ReadModuleOffsetMap(M); unsigned ModuleFileIndex = LocalID >> 32; LocalID &= llvm::maskTrailingOnes(32); ModuleFile *MF = ModuleFileIndex ? M.TransitiveImports[ModuleFileIndex - 1] : &M; assert(MF && "malformed identifier ID encoding?"); if (!ModuleFileIndex) LocalID -= NUM_PREDEF_IDENT_IDS; return ((IdentifierID)(MF->Index + 1) << 32) | LocalID; } MacroInfo *ASTReader::getMacro(MacroID ID) { if (ID == 0) return nullptr; if (MacrosLoaded.empty()) { Error("no macro table in AST file"); return nullptr; } ID -= NUM_PREDEF_MACRO_IDS; if (!MacrosLoaded[ID]) { GlobalMacroMapType::iterator I = GlobalMacroMap.find(ID + NUM_PREDEF_MACRO_IDS); assert(I != GlobalMacroMap.end() && "Corrupted global macro map"); ModuleFile *M = I->second; unsigned Index = ID - M->BaseMacroID; MacrosLoaded[ID] = ReadMacroRecord(*M, M->MacroOffsetsBase + M->MacroOffsets[Index]); if (DeserializationListener) DeserializationListener->MacroRead(ID + NUM_PREDEF_MACRO_IDS, MacrosLoaded[ID]); } return MacrosLoaded[ID]; } MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) { if (LocalID < NUM_PREDEF_MACRO_IDS) return LocalID; if (!M.ModuleOffsetMap.empty()) ReadModuleOffsetMap(M); ContinuousRangeMap::iterator I = M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS); assert(I != M.MacroRemap.end() && "Invalid index into macro index remap"); return LocalID + I->second; } serialization::SubmoduleID ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) const { if (LocalID < NUM_PREDEF_SUBMODULE_IDS) return LocalID; if (!M.ModuleOffsetMap.empty()) ReadModuleOffsetMap(M); ContinuousRangeMap::iterator I = M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS); assert(I != M.SubmoduleRemap.end() && "Invalid index into submodule index remap"); return LocalID + I->second; } Module *ASTReader::getSubmodule(SubmoduleID GlobalID) { if (GlobalID < NUM_PREDEF_SUBMODULE_IDS) { assert(GlobalID == 0 && "Unhandled global submodule ID"); return nullptr; } if (GlobalID > SubmodulesLoaded.size()) { Error("submodule ID out of range in AST file"); return nullptr; } return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS]; } Module *ASTReader::getModule(unsigned ID) { return getSubmodule(ID); } ModuleFile *ASTReader::getLocalModuleFile(ModuleFile &M, unsigned ID) const { if (ID & 1) { // It's a module, look it up by submodule ID. auto I = GlobalSubmoduleMap.find(getGlobalSubmoduleID(M, ID >> 1)); return I == GlobalSubmoduleMap.end() ? nullptr : I->second; } else { // It's a prefix (preamble, PCH, ...). Look it up by index. unsigned IndexFromEnd = ID >> 1; assert(IndexFromEnd && "got reference to unknown module file"); return getModuleManager().pch_modules().end()[-IndexFromEnd]; } } unsigned ASTReader::getModuleFileID(ModuleFile *M) { if (!M) return 1; // For a file representing a module, use the submodule ID of the top-level // module as the file ID. For any other kind of file, the number of such // files loaded beforehand will be the same on reload. // FIXME: Is this true even if we have an explicit module file and a PCH? if (M->isModule()) return ((M->BaseSubmoduleID + NUM_PREDEF_SUBMODULE_IDS) << 1) | 1; auto PCHModules = getModuleManager().pch_modules(); auto I = llvm::find(PCHModules, M); assert(I != PCHModules.end() && "emitting reference to unknown file"); return (I - PCHModules.end()) << 1; } std::optional ASTReader::getSourceDescriptor(unsigned ID) { if (Module *M = getSubmodule(ID)) return ASTSourceDescriptor(*M); // If there is only a single PCH, return it instead. // 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); return ASTSourceDescriptor(ModuleName, llvm::sys::path::parent_path(MF.FileName), FileName, MF.Signature); } return std::nullopt; } ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(const Decl *FD) { auto I = DefinitionSource.find(FD); if (I == DefinitionSource.end()) return EK_ReplyHazy; return I->second ? EK_Never : EK_Always; } Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) { return DecodeSelector(getGlobalSelectorID(M, LocalID)); } Selector ASTReader::DecodeSelector(serialization::SelectorID ID) { if (ID == 0) return Selector(); if (ID > SelectorsLoaded.size()) { Error("selector ID out of range in AST file"); return Selector(); } if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == nullptr) { // Load this selector from the selector table. GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID); assert(I != GlobalSelectorMap.end() && "Corrupted global selector map"); ModuleFile &M = *I->second; ASTSelectorLookupTrait Trait(*this, M); unsigned Idx = ID - M.BaseSelectorID - NUM_PREDEF_SELECTOR_IDS; SelectorsLoaded[ID - 1] = Trait.ReadKey(M.SelectorLookupTableData + M.SelectorOffsets[Idx], 0); if (DeserializationListener) DeserializationListener->SelectorRead(ID, SelectorsLoaded[ID - 1]); } return SelectorsLoaded[ID - 1]; } Selector ASTReader::GetExternalSelector(serialization::SelectorID ID) { return DecodeSelector(ID); } uint32_t ASTReader::GetNumExternalSelectors() { // ID 0 (the null selector) is considered an external selector. return getTotalNumSelectors() + 1; } serialization::SelectorID ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const { if (LocalID < NUM_PREDEF_SELECTOR_IDS) return LocalID; if (!M.ModuleOffsetMap.empty()) ReadModuleOffsetMap(M); ContinuousRangeMap::iterator I = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS); assert(I != M.SelectorRemap.end() && "Invalid index into selector index remap"); return LocalID + I->second; } DeclarationNameLoc ASTRecordReader::readDeclarationNameLoc(DeclarationName Name) { switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: return DeclarationNameLoc::makeNamedTypeLoc(readTypeSourceInfo()); case DeclarationName::CXXOperatorName: return DeclarationNameLoc::makeCXXOperatorNameLoc(readSourceRange()); case DeclarationName::CXXLiteralOperatorName: return DeclarationNameLoc::makeCXXLiteralOperatorNameLoc( readSourceLocation()); case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: case DeclarationName::CXXDeductionGuideName: break; } return DeclarationNameLoc(); } DeclarationNameInfo ASTRecordReader::readDeclarationNameInfo() { DeclarationNameInfo NameInfo; NameInfo.setName(readDeclarationName()); NameInfo.setLoc(readSourceLocation()); NameInfo.setInfo(readDeclarationNameLoc(NameInfo.getName())); return NameInfo; } TypeCoupledDeclRefInfo ASTRecordReader::readTypeCoupledDeclRefInfo() { return TypeCoupledDeclRefInfo(readDeclAs(), readBool()); } void ASTRecordReader::readQualifierInfo(QualifierInfo &Info) { Info.QualifierLoc = readNestedNameSpecifierLoc(); unsigned NumTPLists = readInt(); Info.NumTemplParamLists = NumTPLists; if (NumTPLists) { Info.TemplParamLists = new (getContext()) TemplateParameterList *[NumTPLists]; for (unsigned i = 0; i != NumTPLists; ++i) Info.TemplParamLists[i] = readTemplateParameterList(); } } TemplateParameterList * ASTRecordReader::readTemplateParameterList() { SourceLocation TemplateLoc = readSourceLocation(); SourceLocation LAngleLoc = readSourceLocation(); SourceLocation RAngleLoc = readSourceLocation(); unsigned NumParams = readInt(); SmallVector Params; Params.reserve(NumParams); while (NumParams--) Params.push_back(readDeclAs()); bool HasRequiresClause = readBool(); Expr *RequiresClause = HasRequiresClause ? readExpr() : nullptr; TemplateParameterList *TemplateParams = TemplateParameterList::Create( getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause); return TemplateParams; } void ASTRecordReader::readTemplateArgumentList( SmallVectorImpl &TemplArgs, bool Canonicalize) { unsigned NumTemplateArgs = readInt(); TemplArgs.reserve(NumTemplateArgs); while (NumTemplateArgs--) TemplArgs.push_back(readTemplateArgument(Canonicalize)); } /// Read a UnresolvedSet structure. void ASTRecordReader::readUnresolvedSet(LazyASTUnresolvedSet &Set) { unsigned NumDecls = readInt(); Set.reserve(getContext(), NumDecls); while (NumDecls--) { GlobalDeclID ID = readDeclID(); AccessSpecifier AS = (AccessSpecifier) readInt(); Set.addLazyDecl(getContext(), ID, AS); } } CXXBaseSpecifier ASTRecordReader::readCXXBaseSpecifier() { bool isVirtual = readBool(); bool isBaseOfClass = readBool(); AccessSpecifier AS = static_cast(readInt()); bool inheritConstructors = readBool(); TypeSourceInfo *TInfo = readTypeSourceInfo(); SourceRange Range = readSourceRange(); SourceLocation EllipsisLoc = readSourceLocation(); CXXBaseSpecifier Result(Range, isVirtual, isBaseOfClass, AS, TInfo, EllipsisLoc); Result.setInheritConstructors(inheritConstructors); return Result; } CXXCtorInitializer ** ASTRecordReader::readCXXCtorInitializers() { ASTContext &Context = getContext(); unsigned NumInitializers = readInt(); assert(NumInitializers && "wrote ctor initializers but have no inits"); auto **CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers]; for (unsigned i = 0; i != NumInitializers; ++i) { TypeSourceInfo *TInfo = nullptr; bool IsBaseVirtual = false; FieldDecl *Member = nullptr; IndirectFieldDecl *IndirectMember = nullptr; CtorInitializerType Type = (CtorInitializerType) readInt(); switch (Type) { case CTOR_INITIALIZER_BASE: TInfo = readTypeSourceInfo(); IsBaseVirtual = readBool(); break; case CTOR_INITIALIZER_DELEGATING: TInfo = readTypeSourceInfo(); break; case CTOR_INITIALIZER_MEMBER: Member = readDeclAs(); break; case CTOR_INITIALIZER_INDIRECT_MEMBER: IndirectMember = readDeclAs(); break; } SourceLocation MemberOrEllipsisLoc = readSourceLocation(); Expr *Init = readExpr(); SourceLocation LParenLoc = readSourceLocation(); SourceLocation RParenLoc = readSourceLocation(); CXXCtorInitializer *BOMInit; if (Type == CTOR_INITIALIZER_BASE) BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, IsBaseVirtual, LParenLoc, Init, RParenLoc, MemberOrEllipsisLoc); else if (Type == CTOR_INITIALIZER_DELEGATING) BOMInit = new (Context) CXXCtorInitializer(Context, TInfo, LParenLoc, Init, RParenLoc); else if (Member) BOMInit = new (Context) CXXCtorInitializer(Context, Member, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc); else BOMInit = new (Context) CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc); if (/*IsWritten*/readBool()) { unsigned SourceOrder = readInt(); BOMInit->setSourceOrder(SourceOrder); } CtorInitializers[i] = BOMInit; } return CtorInitializers; } NestedNameSpecifierLoc ASTRecordReader::readNestedNameSpecifierLoc() { ASTContext &Context = getContext(); unsigned N = readInt(); NestedNameSpecifierLocBuilder Builder; for (unsigned I = 0; I != N; ++I) { auto Kind = readNestedNameSpecifierKind(); switch (Kind) { case NestedNameSpecifier::Identifier: { IdentifierInfo *II = readIdentifier(); SourceRange Range = readSourceRange(); Builder.Extend(Context, II, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::Namespace: { NamespaceDecl *NS = readDeclAs(); SourceRange Range = readSourceRange(); Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::NamespaceAlias: { NamespaceAliasDecl *Alias = readDeclAs(); SourceRange Range = readSourceRange(); Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { bool Template = readBool(); TypeSourceInfo *T = readTypeSourceInfo(); if (!T) return NestedNameSpecifierLoc(); SourceLocation ColonColonLoc = readSourceLocation(); // FIXME: 'template' keyword location not saved anywhere, so we fake it. Builder.Extend(Context, Template? T->getTypeLoc().getBeginLoc() : SourceLocation(), T->getTypeLoc(), ColonColonLoc); break; } case NestedNameSpecifier::Global: { SourceLocation ColonColonLoc = readSourceLocation(); Builder.MakeGlobal(Context, ColonColonLoc); break; } case NestedNameSpecifier::Super: { CXXRecordDecl *RD = readDeclAs(); SourceRange Range = readSourceRange(); Builder.MakeSuper(Context, RD, Range.getBegin(), Range.getEnd()); break; } } } return Builder.getWithLocInContext(Context); } SourceRange ASTReader::ReadSourceRange(ModuleFile &F, const RecordData &Record, unsigned &Idx, LocSeq *Seq) { SourceLocation beg = ReadSourceLocation(F, Record, Idx, Seq); SourceLocation end = ReadSourceLocation(F, Record, Idx, Seq); return SourceRange(beg, end); } llvm::BitVector ASTReader::ReadBitVector(const RecordData &Record, const StringRef Blob) { unsigned Count = Record[0]; const char *Byte = Blob.data(); llvm::BitVector Ret = llvm::BitVector(Count, false); for (unsigned I = 0; I < Count; ++Byte) for (unsigned Bit = 0; Bit < 8 && I < Count; ++Bit, ++I) if (*Byte & (1 << Bit)) Ret[I] = true; return Ret; } /// Read a floating-point value llvm::APFloat ASTRecordReader::readAPFloat(const llvm::fltSemantics &Sem) { return llvm::APFloat(Sem, readAPInt()); } // Read a string std::string ASTReader::ReadString(const RecordDataImpl &Record, unsigned &Idx) { unsigned Len = Record[Idx++]; std::string Result(Record.data() + Idx, Record.data() + Idx + Len); Idx += Len; return Result; } std::string ASTReader::ReadPath(ModuleFile &F, const RecordData &Record, unsigned &Idx) { std::string Filename = ReadString(Record, Idx); ResolveImportedPath(F, Filename); return Filename; } std::string ASTReader::ReadPath(StringRef BaseDirectory, const RecordData &Record, unsigned &Idx) { std::string Filename = ReadString(Record, Idx); if (!BaseDirectory.empty()) ResolveImportedPath(Filename, BaseDirectory); return Filename; } VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record, unsigned &Idx) { unsigned Major = Record[Idx++]; unsigned Minor = Record[Idx++]; unsigned Subminor = Record[Idx++]; if (Minor == 0) return VersionTuple(Major); if (Subminor == 0) return VersionTuple(Major, Minor - 1); return VersionTuple(Major, Minor - 1, Subminor - 1); } CXXTemporary *ASTReader::ReadCXXTemporary(ModuleFile &F, const RecordData &Record, unsigned &Idx) { CXXDestructorDecl *Decl = ReadDeclAs(F, Record, Idx); return CXXTemporary::Create(getContext(), Decl); } DiagnosticBuilder ASTReader::Diag(unsigned DiagID) const { return Diag(CurrentImportLoc, DiagID); } DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) const { return Diags.Report(Loc, DiagID); } void ASTReader::warnStackExhausted(SourceLocation Loc) { // When Sema is available, avoid duplicate errors. if (SemaObj) { SemaObj->warnStackExhausted(Loc); return; } if (WarnedStackExhausted) return; WarnedStackExhausted = true; Diag(Loc, diag::warn_stack_exhausted); } /// Retrieve the identifier table associated with the /// preprocessor. IdentifierTable &ASTReader::getIdentifierTable() { return PP.getIdentifierTable(); } /// Record that the given ID maps to the given switch-case /// statement. void ASTReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) { assert((*CurrSwitchCaseStmts)[ID] == nullptr && "Already have a SwitchCase with this ID"); (*CurrSwitchCaseStmts)[ID] = SC; } /// Retrieve the switch-case statement with the given ID. SwitchCase *ASTReader::getSwitchCaseWithID(unsigned ID) { assert((*CurrSwitchCaseStmts)[ID] != nullptr && "No SwitchCase with this ID"); return (*CurrSwitchCaseStmts)[ID]; } void ASTReader::ClearSwitchCaseIDs() { CurrSwitchCaseStmts->clear(); } void ASTReader::ReadComments() { ASTContext &Context = getContext(); std::vector Comments; for (SmallVectorImpl>::iterator I = CommentsCursors.begin(), E = CommentsCursors.end(); I != E; ++I) { Comments.clear(); BitstreamCursor &Cursor = I->first; serialization::ModuleFile &F = *I->second; SavedStreamPosition SavedPosition(Cursor); RecordData Record; while (true) { Expected MaybeEntry = Cursor.advanceSkippingSubblocks( BitstreamCursor::AF_DontPopBlockAtEnd); if (!MaybeEntry) { Error(MaybeEntry.takeError()); return; } llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: Error("malformed block record in AST file"); return; case llvm::BitstreamEntry::EndBlock: goto NextCursor; case llvm::BitstreamEntry::Record: // The interesting case. break; } // Read a record. Record.clear(); Expected MaybeComment = Cursor.readRecord(Entry.ID, Record); if (!MaybeComment) { Error(MaybeComment.takeError()); return; } switch ((CommentRecordTypes)MaybeComment.get()) { case COMMENTS_RAW_COMMENT: { unsigned Idx = 0; SourceRange SR = ReadSourceRange(F, Record, Idx); RawComment::CommentKind Kind = (RawComment::CommentKind) Record[Idx++]; bool IsTrailingComment = Record[Idx++]; bool IsAlmostTrailingComment = Record[Idx++]; Comments.push_back(new (Context) RawComment( SR, Kind, IsTrailingComment, IsAlmostTrailingComment)); break; } } } NextCursor: llvm::DenseMap> FileToOffsetToComment; for (RawComment *C : Comments) { SourceLocation CommentLoc = C->getBeginLoc(); if (CommentLoc.isValid()) { std::pair Loc = SourceMgr.getDecomposedLoc(CommentLoc); if (Loc.first.isValid()) Context.Comments.OrderedComments[Loc.first].emplace(Loc.second, C); } } } } void ASTReader::visitInputFileInfos( serialization::ModuleFile &MF, bool IncludeSystem, llvm::function_ref 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; InputFileInfo IFI = getInputFileInfo(MF, I+1); Visitor(IFI, IsSystem); } } void ASTReader::visitInputFiles(serialization::ModuleFile &MF, bool IncludeSystem, bool Complain, llvm::function_ref 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 Visitor) { unsigned NumInputs = MF.InputFilesLoaded.size(); for (unsigned I = 0; I < NumInputs; ++I) { InputFileInfo IFI = getInputFileInfo(MF, I + 1); if (IFI.TopLevel && IFI.ModuleMap) if (auto FE = getInputFile(MF, I + 1).getFile()) Visitor(*FE); } } void ASTReader::finishPendingActions() { while ( !PendingIdentifierInfos.empty() || !PendingDeducedFunctionTypes.empty() || !PendingDeducedVarTypes.empty() || !PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() || !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() || !PendingUpdateRecords.empty() || !PendingObjCExtensionIvarRedeclarations.empty()) { // If any identifiers with corresponding top-level declarations have // been loaded, load those declarations now. using TopLevelDeclsMap = llvm::DenseMap>; TopLevelDeclsMap TopLevelDecls; while (!PendingIdentifierInfos.empty()) { IdentifierInfo *II = PendingIdentifierInfos.back().first; SmallVector DeclIDs = std::move(PendingIdentifierInfos.back().second); PendingIdentifierInfos.pop_back(); SetGloballyVisibleDecls(II, DeclIDs, &TopLevelDecls[II]); } // Load each function type that we deferred loading because it was a // deduced type that might refer to a local type declared within itself. for (unsigned I = 0; I != PendingDeducedFunctionTypes.size(); ++I) { auto *FD = PendingDeducedFunctionTypes[I].first; FD->setType(GetType(PendingDeducedFunctionTypes[I].second)); if (auto *DT = FD->getReturnType()->getContainedDeducedType()) { // If we gave a function a deduced return type, remember that we need to // propagate that along the redeclaration chain. if (DT->isDeduced()) { PendingDeducedTypeUpdates.insert( {FD->getCanonicalDecl(), FD->getReturnType()}); continue; } // The function has undeduced DeduceType return type. We hope we can // find the deduced type by iterating the redecls in other modules // later. PendingUndeducedFunctionDecls.push_back(FD); continue; } } PendingDeducedFunctionTypes.clear(); // Load each variable type that we deferred loading because it was a // deduced type that might refer to a local type declared within itself. for (unsigned I = 0; I != PendingDeducedVarTypes.size(); ++I) { auto *VD = PendingDeducedVarTypes[I].first; VD->setType(GetType(PendingDeducedVarTypes[I].second)); } PendingDeducedVarTypes.clear(); // For each decl chain that we wanted to complete while deserializing, mark // it as "still needs to be completed". for (unsigned I = 0; I != PendingIncompleteDeclChains.size(); ++I) { markIncompleteDeclChain(PendingIncompleteDeclChains[I]); } PendingIncompleteDeclChains.clear(); // Load pending declaration chains. for (unsigned I = 0; I != PendingDeclChains.size(); ++I) loadPendingDeclChain(PendingDeclChains[I].first, PendingDeclChains[I].second); PendingDeclChains.clear(); // Make the most recent of the top-level declarations visible. for (TopLevelDeclsMap::iterator TLD = TopLevelDecls.begin(), TLDEnd = TopLevelDecls.end(); TLD != TLDEnd; ++TLD) { IdentifierInfo *II = TLD->first; for (unsigned I = 0, N = TLD->second.size(); I != N; ++I) { pushExternalDeclIntoScope(cast(TLD->second[I]), II); } } // Load any pending macro definitions. for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) { IdentifierInfo *II = PendingMacroIDs.begin()[I].first; SmallVector GlobalIDs; GlobalIDs.swap(PendingMacroIDs.begin()[I].second); // Initialize the macro history from chained-PCHs ahead of module imports. for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; ++IDIdx) { const PendingMacroInfo &Info = GlobalIDs[IDIdx]; if (!Info.M->isModule()) resolvePendingMacro(II, Info); } // Handle module imports. for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; ++IDIdx) { const PendingMacroInfo &Info = GlobalIDs[IDIdx]; if (Info.M->isModule()) resolvePendingMacro(II, Info); } } PendingMacroIDs.clear(); // Wire up the DeclContexts for Decls that we delayed setting until // recursive loading is completed. while (!PendingDeclContextInfos.empty()) { PendingDeclContextInfo Info = PendingDeclContextInfos.front(); PendingDeclContextInfos.pop_front(); DeclContext *SemaDC = cast(GetDecl(Info.SemaDC)); DeclContext *LexicalDC = cast(GetDecl(Info.LexicalDC)); Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext()); } // Perform any pending declaration updates. while (!PendingUpdateRecords.empty()) { auto Update = PendingUpdateRecords.pop_back_val(); ReadingKindTracker ReadingKind(Read_Decl, *this); loadDeclUpdateRecords(Update); } while (!PendingObjCExtensionIvarRedeclarations.empty()) { auto ExtensionsPair = PendingObjCExtensionIvarRedeclarations.back().first; auto DuplicateIvars = PendingObjCExtensionIvarRedeclarations.back().second; llvm::DenseSet> NonEquivalentDecls; StructuralEquivalenceContext Ctx( ExtensionsPair.first->getASTContext(), ExtensionsPair.second->getASTContext(), NonEquivalentDecls, StructuralEquivalenceKind::Default, /*StrictTypeSpelling =*/false, /*Complain =*/false, /*ErrorOnTagTypeMismatch =*/true); if (Ctx.IsEquivalent(ExtensionsPair.first, ExtensionsPair.second)) { // Merge redeclared ivars with their predecessors. for (auto IvarPair : DuplicateIvars) { ObjCIvarDecl *Ivar = IvarPair.first, *PrevIvar = IvarPair.second; // Change semantic DeclContext but keep the lexical one. Ivar->setDeclContextsImpl(PrevIvar->getDeclContext(), Ivar->getLexicalDeclContext(), getContext()); getContext().setPrimaryMergedDecl(Ivar, PrevIvar->getCanonicalDecl()); } // Invalidate duplicate extension and the cached ivar list. ExtensionsPair.first->setInvalidDecl(); ExtensionsPair.second->getClassInterface() ->getDefinition() ->setIvarList(nullptr); } else { for (auto IvarPair : DuplicateIvars) { Diag(IvarPair.first->getLocation(), diag::err_duplicate_ivar_declaration) << IvarPair.first->getIdentifier(); Diag(IvarPair.second->getLocation(), diag::note_previous_definition); } } PendingObjCExtensionIvarRedeclarations.pop_back(); } } // At this point, all update records for loaded decls are in place, so any // fake class definitions should have become real. assert(PendingFakeDefinitionData.empty() && "faked up a class definition but never saw the real one"); // If we deserialized any C++ or Objective-C class definitions, any // Objective-C protocol definitions, or any redeclarable templates, make sure // that all redeclarations point to the definitions. Note that this can only // happen now, after the redeclaration chains have been fully wired. for (Decl *D : PendingDefinitions) { if (TagDecl *TD = dyn_cast(D)) { if (const TagType *TagT = dyn_cast(TD->getTypeForDecl())) { // Make sure that the TagType points at the definition. const_cast(TagT)->decl = TD; } if (auto RD = dyn_cast(D)) { for (auto *R = getMostRecentExistingDecl(RD); R; R = R->getPreviousDecl()) { assert((R == D) == cast(R)->isThisDeclarationADefinition() && "declaration thinks it's the definition but it isn't"); cast(R)->DefinitionData = RD->DefinitionData; } } continue; } if (auto ID = dyn_cast(D)) { // Make sure that the ObjCInterfaceType points at the definition. const_cast(cast(ID->TypeForDecl)) ->Decl = ID; for (auto *R = getMostRecentExistingDecl(ID); R; R = R->getPreviousDecl()) cast(R)->Data = ID->Data; continue; } if (auto PD = dyn_cast(D)) { for (auto *R = getMostRecentExistingDecl(PD); R; R = R->getPreviousDecl()) cast(R)->Data = PD->Data; continue; } auto RTD = cast(D)->getCanonicalDecl(); for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl()) cast(R)->Common = RTD->Common; } PendingDefinitions.clear(); // Load the bodies of any functions or methods we've encountered. We do // this now (delayed) so that we can be sure that the declaration chains // have been fully wired up (hasBody relies on this). // FIXME: We shouldn't require complete redeclaration chains here. for (PendingBodiesMap::iterator PB = PendingBodies.begin(), PBEnd = PendingBodies.end(); PB != PBEnd; ++PB) { if (FunctionDecl *FD = dyn_cast(PB->first)) { // For a function defined inline within a class template, force the // canonical definition to be the one inside the canonical definition of // the template. This ensures that we instantiate from a correct view // of the template. // // Sadly we can't do this more generally: we can't be sure that all // copies of an arbitrary class definition will have the same members // defined (eg, some member functions may not be instantiated, and some // special members may or may not have been implicitly defined). if (auto *RD = dyn_cast(FD->getLexicalParent())) if (RD->isDependentContext() && !RD->isThisDeclarationADefinition()) continue; // FIXME: Check for =delete/=default? const FunctionDecl *Defn = nullptr; if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) { FD->setLazyBody(PB->second); } else { auto *NonConstDefn = const_cast(Defn); mergeDefinitionVisibility(NonConstDefn, FD); if (!FD->isLateTemplateParsed() && !NonConstDefn->isLateTemplateParsed() && // We only perform ODR checks for decls not in the explicit // global module fragment. !shouldSkipCheckingODR(FD) && !shouldSkipCheckingODR(NonConstDefn) && FD->getODRHash() != NonConstDefn->getODRHash()) { if (!isa(FD)) { PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn); } else if (FD->getLexicalParent()->isFileContext() && NonConstDefn->getLexicalParent()->isFileContext()) { // Only diagnose out-of-line method definitions. If they are // in class definitions, then an error will be generated when // processing the class bodies. PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn); } } } continue; } ObjCMethodDecl *MD = cast(PB->first); if (!getContext().getLangOpts().Modules || !MD->hasBody()) MD->setLazyBody(PB->second); } PendingBodies.clear(); // Inform any classes that had members added that they now have more members. for (auto [RD, MD] : PendingAddedClassMembers) { RD->addedMember(MD); } PendingAddedClassMembers.clear(); // Do some cleanup. for (auto *ND : PendingMergedDefinitionsToDeduplicate) getContext().deduplicateMergedDefinitonsFor(ND); PendingMergedDefinitionsToDeduplicate.clear(); } void ASTReader::diagnoseOdrViolations() { if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty() && PendingRecordOdrMergeFailures.empty() && PendingFunctionOdrMergeFailures.empty() && PendingEnumOdrMergeFailures.empty() && PendingObjCInterfaceOdrMergeFailures.empty() && PendingObjCProtocolOdrMergeFailures.empty()) return; // Trigger the import of the full definition of each class that had any // odr-merging problems, so we can produce better diagnostics for them. // These updates may in turn find and diagnose some ODR failures, so take // ownership of the set first. auto OdrMergeFailures = std::move(PendingOdrMergeFailures); PendingOdrMergeFailures.clear(); for (auto &Merge : OdrMergeFailures) { Merge.first->buildLookup(); Merge.first->decls_begin(); Merge.first->bases_begin(); Merge.first->vbases_begin(); for (auto &RecordPair : Merge.second) { auto *RD = RecordPair.first; RD->decls_begin(); RD->bases_begin(); RD->vbases_begin(); } } // Trigger the import of the full definition of each record in C/ObjC. auto RecordOdrMergeFailures = std::move(PendingRecordOdrMergeFailures); PendingRecordOdrMergeFailures.clear(); for (auto &Merge : RecordOdrMergeFailures) { Merge.first->decls_begin(); for (auto &D : Merge.second) D->decls_begin(); } // Trigger the import of the full interface definition. auto ObjCInterfaceOdrMergeFailures = std::move(PendingObjCInterfaceOdrMergeFailures); PendingObjCInterfaceOdrMergeFailures.clear(); for (auto &Merge : ObjCInterfaceOdrMergeFailures) { Merge.first->decls_begin(); for (auto &InterfacePair : Merge.second) InterfacePair.first->decls_begin(); } // Trigger the import of functions. auto FunctionOdrMergeFailures = std::move(PendingFunctionOdrMergeFailures); PendingFunctionOdrMergeFailures.clear(); for (auto &Merge : FunctionOdrMergeFailures) { Merge.first->buildLookup(); Merge.first->decls_begin(); Merge.first->getBody(); for (auto &FD : Merge.second) { FD->buildLookup(); FD->decls_begin(); FD->getBody(); } } // Trigger the import of enums. auto EnumOdrMergeFailures = std::move(PendingEnumOdrMergeFailures); PendingEnumOdrMergeFailures.clear(); for (auto &Merge : EnumOdrMergeFailures) { Merge.first->decls_begin(); for (auto &Enum : Merge.second) { Enum->decls_begin(); } } // Trigger the import of the full protocol definition. auto ObjCProtocolOdrMergeFailures = std::move(PendingObjCProtocolOdrMergeFailures); PendingObjCProtocolOdrMergeFailures.clear(); for (auto &Merge : ObjCProtocolOdrMergeFailures) { Merge.first->decls_begin(); for (auto &ProtocolPair : Merge.second) ProtocolPair.first->decls_begin(); } // For each declaration from a merged context, check that the canonical // definition of that context also contains a declaration of the same // entity. // // Caution: this loop does things that might invalidate iterators into // PendingOdrMergeChecks. Don't turn this into a range-based for loop! while (!PendingOdrMergeChecks.empty()) { NamedDecl *D = PendingOdrMergeChecks.pop_back_val(); // FIXME: Skip over implicit declarations for now. This matters for things // like implicitly-declared special member functions. This isn't entirely // correct; we can end up with multiple unmerged declarations of the same // implicit entity. if (D->isImplicit()) continue; DeclContext *CanonDef = D->getDeclContext(); bool Found = false; const Decl *DCanon = D->getCanonicalDecl(); for (auto *RI : D->redecls()) { if (RI->getLexicalDeclContext() == CanonDef) { Found = true; break; } } if (Found) continue; // Quick check failed, time to do the slow thing. Note, we can't just // look up the name of D in CanonDef here, because the member that is // in CanonDef might not be found by name lookup (it might have been // replaced by a more recent declaration in the lookup table), and we // can't necessarily find it in the redeclaration chain because it might // be merely mergeable, not redeclarable. llvm::SmallVector Candidates; for (auto *CanonMember : CanonDef->decls()) { if (CanonMember->getCanonicalDecl() == DCanon) { // This can happen if the declaration is merely mergeable and not // actually redeclarable (we looked for redeclarations earlier). // // FIXME: We should be able to detect this more efficiently, without // pulling in all of the members of CanonDef. Found = true; break; } if (auto *ND = dyn_cast(CanonMember)) if (ND->getDeclName() == D->getDeclName()) Candidates.push_back(ND); } if (!Found) { // The AST doesn't like TagDecls becoming invalid after they've been // completed. We only really need to mark FieldDecls as invalid here. if (!isa(D)) D->setInvalidDecl(); // Ensure we don't accidentally recursively enter deserialization while // we're producing our diagnostic. Deserializing RecursionGuard(this); std::string CanonDefModule = ODRDiagsEmitter::getOwningModuleNameForDiagnostic( cast(CanonDef)); Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl) << D << ODRDiagsEmitter::getOwningModuleNameForDiagnostic(D) << CanonDef << CanonDefModule.empty() << CanonDefModule; if (Candidates.empty()) Diag(cast(CanonDef)->getLocation(), diag::note_module_odr_violation_no_possible_decls) << D; else { for (unsigned I = 0, N = Candidates.size(); I != N; ++I) Diag(Candidates[I]->getLocation(), diag::note_module_odr_violation_possible_decl) << Candidates[I]; } DiagnosedOdrMergeFailures.insert(CanonDef); } } if (OdrMergeFailures.empty() && RecordOdrMergeFailures.empty() && FunctionOdrMergeFailures.empty() && EnumOdrMergeFailures.empty() && ObjCInterfaceOdrMergeFailures.empty() && ObjCProtocolOdrMergeFailures.empty()) return; ODRDiagsEmitter DiagsEmitter(Diags, getContext(), getPreprocessor().getLangOpts()); // Issue any pending ODR-failure diagnostics. for (auto &Merge : OdrMergeFailures) { // If we've already pointed out a specific problem with this class, don't // bother issuing a general "something's different" diagnostic. if (!DiagnosedOdrMergeFailures.insert(Merge.first).second) continue; bool Diagnosed = false; CXXRecordDecl *FirstRecord = Merge.first; for (auto &RecordPair : Merge.second) { if (DiagsEmitter.diagnoseMismatch(FirstRecord, RecordPair.first, RecordPair.second)) { Diagnosed = true; break; } } if (!Diagnosed) { // All definitions are updates to the same declaration. This happens if a // module instantiates the declaration of a class template specialization // and two or more other modules instantiate its definition. // // FIXME: Indicate which modules had instantiations of this definition. // FIXME: How can this even happen? Diag(Merge.first->getLocation(), diag::err_module_odr_violation_different_instantiations) << Merge.first; } } // Issue any pending ODR-failure diagnostics for RecordDecl in C/ObjC. Note // that in C++ this is done as a part of CXXRecordDecl ODR checking. for (auto &Merge : RecordOdrMergeFailures) { // If we've already pointed out a specific problem with this class, don't // bother issuing a general "something's different" diagnostic. if (!DiagnosedOdrMergeFailures.insert(Merge.first).second) continue; RecordDecl *FirstRecord = Merge.first; bool Diagnosed = false; for (auto *SecondRecord : Merge.second) { if (DiagsEmitter.diagnoseMismatch(FirstRecord, SecondRecord)) { Diagnosed = true; break; } } (void)Diagnosed; assert(Diagnosed && "Unable to emit ODR diagnostic."); } // Issue ODR failures diagnostics for functions. for (auto &Merge : FunctionOdrMergeFailures) { FunctionDecl *FirstFunction = Merge.first; bool Diagnosed = false; for (auto &SecondFunction : Merge.second) { if (DiagsEmitter.diagnoseMismatch(FirstFunction, SecondFunction)) { Diagnosed = true; break; } } (void)Diagnosed; assert(Diagnosed && "Unable to emit ODR diagnostic."); } // Issue ODR failures diagnostics for enums. for (auto &Merge : EnumOdrMergeFailures) { // If we've already pointed out a specific problem with this enum, don't // bother issuing a general "something's different" diagnostic. if (!DiagnosedOdrMergeFailures.insert(Merge.first).second) continue; EnumDecl *FirstEnum = Merge.first; bool Diagnosed = false; for (auto &SecondEnum : Merge.second) { if (DiagsEmitter.diagnoseMismatch(FirstEnum, SecondEnum)) { Diagnosed = true; break; } } (void)Diagnosed; assert(Diagnosed && "Unable to emit ODR diagnostic."); } for (auto &Merge : ObjCInterfaceOdrMergeFailures) { // If we've already pointed out a specific problem with this interface, // don't bother issuing a general "something's different" diagnostic. if (!DiagnosedOdrMergeFailures.insert(Merge.first).second) continue; bool Diagnosed = false; ObjCInterfaceDecl *FirstID = Merge.first; for (auto &InterfacePair : Merge.second) { if (DiagsEmitter.diagnoseMismatch(FirstID, InterfacePair.first, InterfacePair.second)) { Diagnosed = true; break; } } (void)Diagnosed; assert(Diagnosed && "Unable to emit ODR diagnostic."); } for (auto &Merge : ObjCProtocolOdrMergeFailures) { // If we've already pointed out a specific problem with this protocol, // don't bother issuing a general "something's different" diagnostic. if (!DiagnosedOdrMergeFailures.insert(Merge.first).second) continue; ObjCProtocolDecl *FirstProtocol = Merge.first; bool Diagnosed = false; for (auto &ProtocolPair : Merge.second) { if (DiagsEmitter.diagnoseMismatch(FirstProtocol, ProtocolPair.first, ProtocolPair.second)) { Diagnosed = true; break; } } (void)Diagnosed; assert(Diagnosed && "Unable to emit ODR diagnostic."); } } void ASTReader::StartedDeserializing() { if (++NumCurrentElementsDeserializing == 1 && ReadTimer.get()) ReadTimer->startTimer(); } void ASTReader::FinishedDeserializing() { assert(NumCurrentElementsDeserializing && "FinishedDeserializing not paired with StartedDeserializing"); if (NumCurrentElementsDeserializing == 1) { // We decrease NumCurrentElementsDeserializing only after pending actions // are finished, to avoid recursively re-calling finishPendingActions(). finishPendingActions(); } --NumCurrentElementsDeserializing; if (NumCurrentElementsDeserializing == 0) { // Propagate exception specification and deduced type updates along // redeclaration chains. // // We do this now rather than in finishPendingActions because we want to // be able to walk the complete redeclaration chains of the updated decls. while (!PendingExceptionSpecUpdates.empty() || !PendingDeducedTypeUpdates.empty()) { auto ESUpdates = std::move(PendingExceptionSpecUpdates); PendingExceptionSpecUpdates.clear(); for (auto Update : ESUpdates) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); auto *FPT = Update.second->getType()->castAs(); auto ESI = FPT->getExtProtoInfo().ExceptionSpec; if (auto *Listener = getContext().getASTMutationListener()) Listener->ResolvedExceptionSpec(cast(Update.second)); for (auto *Redecl : Update.second->redecls()) getContext().adjustExceptionSpec(cast(Redecl), ESI); } auto DTUpdates = std::move(PendingDeducedTypeUpdates); PendingDeducedTypeUpdates.clear(); for (auto Update : DTUpdates) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); // FIXME: If the return type is already deduced, check that it matches. getContext().adjustDeducedFunctionResultType(Update.first, Update.second); } auto UDTUpdates = std::move(PendingUndeducedFunctionDecls); PendingUndeducedFunctionDecls.clear(); // We hope we can find the deduced type for the functions by iterating // redeclarations in other modules. for (FunctionDecl *UndeducedFD : UDTUpdates) (void)UndeducedFD->getMostRecentDecl(); } if (ReadTimer) ReadTimer->stopTimer(); diagnoseOdrViolations(); // We are not in recursive loading, so it's safe to pass the "interesting" // decls to the consumer. if (Consumer) PassInterestingDeclsToConsumer(); } } void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { // Remove any fake results before adding any real ones. auto It = PendingFakeLookupResults.find(II); if (It != PendingFakeLookupResults.end()) { for (auto *ND : It->second) SemaObj->IdResolver.RemoveDecl(ND); // FIXME: this works around module+PCH performance issue. // Rather than erase the result from the map, which is O(n), just clear // the vector of NamedDecls. It->second.clear(); } } if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) { SemaObj->TUScope->AddDecl(D); } else if (SemaObj->TUScope) { // Adding the decl to IdResolver may have failed because it was already in // (even though it was not added in scope). If it is already in, make sure // it gets in the scope as well. if (llvm::is_contained(SemaObj->IdResolver.decls(Name), D)) SemaObj->TUScope->AddDecl(D); } } ASTReader::ASTReader(Preprocessor &PP, InMemoryModuleCache &ModuleCache, ASTContext *Context, const PCHContainerReader &PCHContainerRdr, ArrayRef> Extensions, StringRef isysroot, DisableValidationForModuleKind DisableValidationKind, bool AllowASTWithCompilerErrors, bool AllowConfigurationMismatch, bool ValidateSystemInputs, bool ValidateASTInputFilesContent, bool UseGlobalIndex, std::unique_ptr ReadTimer) : Listener(bool(DisableValidationKind &DisableValidationForModuleKind::PCH) ? cast(new SimpleASTReaderListener(PP)) : cast(new PCHValidator(PP, *this))), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), PCHContainerRdr(PCHContainerRdr), Diags(PP.getDiagnostics()), PP(PP), ContextObj(Context), ModuleMgr(PP.getFileManager(), ModuleCache, PCHContainerRdr, PP.getHeaderSearchInfo()), DummyIdResolver(PP), ReadTimer(std::move(ReadTimer)), isysroot(isysroot), DisableValidationKind(DisableValidationKind), AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), AllowConfigurationMismatch(AllowConfigurationMismatch), ValidateSystemInputs(ValidateSystemInputs), ValidateASTInputFilesContent(ValidateASTInputFilesContent), UseGlobalIndex(UseGlobalIndex), CurrSwitchCaseStmts(&SwitchCaseStmts) { SourceMgr.setExternalSLocEntrySource(this); for (const auto &Ext : Extensions) { auto BlockName = Ext->getExtensionMetadata().BlockName; auto Known = ModuleFileExtensions.find(BlockName); if (Known != ModuleFileExtensions.end()) { Diags.Report(diag::warn_duplicate_module_file_extension) << BlockName; continue; } ModuleFileExtensions.insert({BlockName, Ext}); } } ASTReader::~ASTReader() { if (OwnsDeserializationListener) delete DeserializationListener; } IdentifierResolver &ASTReader::getIdResolver() { return SemaObj ? SemaObj->IdResolver : DummyIdResolver; } Expected ASTRecordReader::readRecord(llvm::BitstreamCursor &Cursor, unsigned AbbrevID) { Idx = 0; Record.clear(); return Cursor.readRecord(AbbrevID, Record); } //===----------------------------------------------------------------------===// //// OMPClauseReader implementation ////===----------------------------------------------------------------------===// // This has to be in namespace clang because it's friended by all // of the OMP clauses. namespace clang { class OMPClauseReader : public OMPClauseVisitor { ASTRecordReader &Record; ASTContext &Context; public: OMPClauseReader(ASTRecordReader &Record) : Record(Record), Context(Record.getContext()) {} #define GEN_CLANG_CLAUSE_CLASS #define CLAUSE_CLASS(Enum, Str, Class) void Visit##Class(Class *C); #include "llvm/Frontend/OpenMP/OMP.inc" OMPClause *readClause(); void VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C); void VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C); }; } // end namespace clang OMPClause *ASTRecordReader::readOMPClause() { return OMPClauseReader(*this).readClause(); } OMPClause *OMPClauseReader::readClause() { OMPClause *C = nullptr; switch (llvm::omp::Clause(Record.readInt())) { case llvm::omp::OMPC_if: C = new (Context) OMPIfClause(); break; case llvm::omp::OMPC_final: C = new (Context) OMPFinalClause(); break; case llvm::omp::OMPC_num_threads: C = new (Context) OMPNumThreadsClause(); break; case llvm::omp::OMPC_safelen: C = new (Context) OMPSafelenClause(); break; case llvm::omp::OMPC_simdlen: C = new (Context) OMPSimdlenClause(); break; case llvm::omp::OMPC_sizes: { unsigned NumSizes = Record.readInt(); C = OMPSizesClause::CreateEmpty(Context, NumSizes); break; } case llvm::omp::OMPC_full: C = OMPFullClause::CreateEmpty(Context); break; case llvm::omp::OMPC_partial: C = OMPPartialClause::CreateEmpty(Context); break; case llvm::omp::OMPC_allocator: C = new (Context) OMPAllocatorClause(); break; case llvm::omp::OMPC_collapse: C = new (Context) OMPCollapseClause(); break; case llvm::omp::OMPC_default: C = new (Context) OMPDefaultClause(); break; case llvm::omp::OMPC_proc_bind: C = new (Context) OMPProcBindClause(); break; case llvm::omp::OMPC_schedule: C = new (Context) OMPScheduleClause(); break; case llvm::omp::OMPC_ordered: C = OMPOrderedClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_nowait: C = new (Context) OMPNowaitClause(); break; case llvm::omp::OMPC_untied: C = new (Context) OMPUntiedClause(); break; case llvm::omp::OMPC_mergeable: C = new (Context) OMPMergeableClause(); break; case llvm::omp::OMPC_read: C = new (Context) OMPReadClause(); break; case llvm::omp::OMPC_write: C = new (Context) OMPWriteClause(); break; case llvm::omp::OMPC_update: C = OMPUpdateClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_capture: C = new (Context) OMPCaptureClause(); break; case llvm::omp::OMPC_compare: C = new (Context) OMPCompareClause(); break; case llvm::omp::OMPC_fail: C = new (Context) OMPFailClause(); break; case llvm::omp::OMPC_seq_cst: C = new (Context) OMPSeqCstClause(); break; case llvm::omp::OMPC_acq_rel: C = new (Context) OMPAcqRelClause(); break; case llvm::omp::OMPC_acquire: C = new (Context) OMPAcquireClause(); break; case llvm::omp::OMPC_release: C = new (Context) OMPReleaseClause(); break; case llvm::omp::OMPC_relaxed: C = new (Context) OMPRelaxedClause(); break; case llvm::omp::OMPC_weak: C = new (Context) OMPWeakClause(); break; case llvm::omp::OMPC_threads: C = new (Context) OMPThreadsClause(); break; case llvm::omp::OMPC_simd: C = new (Context) OMPSIMDClause(); break; case llvm::omp::OMPC_nogroup: C = new (Context) OMPNogroupClause(); break; case llvm::omp::OMPC_unified_address: C = new (Context) OMPUnifiedAddressClause(); break; case llvm::omp::OMPC_unified_shared_memory: C = new (Context) OMPUnifiedSharedMemoryClause(); break; case llvm::omp::OMPC_reverse_offload: C = new (Context) OMPReverseOffloadClause(); break; case llvm::omp::OMPC_dynamic_allocators: C = new (Context) OMPDynamicAllocatorsClause(); break; case llvm::omp::OMPC_atomic_default_mem_order: C = new (Context) OMPAtomicDefaultMemOrderClause(); break; case llvm::omp::OMPC_at: C = new (Context) OMPAtClause(); break; case llvm::omp::OMPC_severity: C = new (Context) OMPSeverityClause(); break; case llvm::omp::OMPC_message: C = new (Context) OMPMessageClause(); break; case llvm::omp::OMPC_private: C = OMPPrivateClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_firstprivate: C = OMPFirstprivateClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_lastprivate: C = OMPLastprivateClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_shared: C = OMPSharedClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_reduction: { unsigned N = Record.readInt(); auto Modifier = Record.readEnum(); C = OMPReductionClause::CreateEmpty(Context, N, Modifier); break; } case llvm::omp::OMPC_task_reduction: C = OMPTaskReductionClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_in_reduction: C = OMPInReductionClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_linear: C = OMPLinearClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_aligned: C = OMPAlignedClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_copyin: C = OMPCopyinClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_copyprivate: C = OMPCopyprivateClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_flush: C = OMPFlushClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_depobj: C = OMPDepobjClause::CreateEmpty(Context); break; case llvm::omp::OMPC_depend: { unsigned NumVars = Record.readInt(); unsigned NumLoops = Record.readInt(); C = OMPDependClause::CreateEmpty(Context, NumVars, NumLoops); break; } case llvm::omp::OMPC_device: C = new (Context) OMPDeviceClause(); break; case llvm::omp::OMPC_map: { OMPMappableExprListSizeTy Sizes; Sizes.NumVars = Record.readInt(); Sizes.NumUniqueDeclarations = Record.readInt(); Sizes.NumComponentLists = Record.readInt(); Sizes.NumComponents = Record.readInt(); C = OMPMapClause::CreateEmpty(Context, Sizes); break; } case llvm::omp::OMPC_num_teams: C = new (Context) OMPNumTeamsClause(); break; case llvm::omp::OMPC_thread_limit: C = new (Context) OMPThreadLimitClause(); break; case llvm::omp::OMPC_priority: C = new (Context) OMPPriorityClause(); break; case llvm::omp::OMPC_grainsize: C = new (Context) OMPGrainsizeClause(); break; case llvm::omp::OMPC_num_tasks: C = new (Context) OMPNumTasksClause(); break; case llvm::omp::OMPC_hint: C = new (Context) OMPHintClause(); break; case llvm::omp::OMPC_dist_schedule: C = new (Context) OMPDistScheduleClause(); break; case llvm::omp::OMPC_defaultmap: C = new (Context) OMPDefaultmapClause(); break; case llvm::omp::OMPC_to: { OMPMappableExprListSizeTy Sizes; Sizes.NumVars = Record.readInt(); Sizes.NumUniqueDeclarations = Record.readInt(); Sizes.NumComponentLists = Record.readInt(); Sizes.NumComponents = Record.readInt(); C = OMPToClause::CreateEmpty(Context, Sizes); break; } case llvm::omp::OMPC_from: { OMPMappableExprListSizeTy Sizes; Sizes.NumVars = Record.readInt(); Sizes.NumUniqueDeclarations = Record.readInt(); Sizes.NumComponentLists = Record.readInt(); Sizes.NumComponents = Record.readInt(); C = OMPFromClause::CreateEmpty(Context, Sizes); break; } case llvm::omp::OMPC_use_device_ptr: { OMPMappableExprListSizeTy Sizes; Sizes.NumVars = Record.readInt(); Sizes.NumUniqueDeclarations = Record.readInt(); Sizes.NumComponentLists = Record.readInt(); Sizes.NumComponents = Record.readInt(); C = OMPUseDevicePtrClause::CreateEmpty(Context, Sizes); break; } case llvm::omp::OMPC_use_device_addr: { OMPMappableExprListSizeTy Sizes; Sizes.NumVars = Record.readInt(); Sizes.NumUniqueDeclarations = Record.readInt(); Sizes.NumComponentLists = Record.readInt(); Sizes.NumComponents = Record.readInt(); C = OMPUseDeviceAddrClause::CreateEmpty(Context, Sizes); break; } case llvm::omp::OMPC_is_device_ptr: { OMPMappableExprListSizeTy Sizes; Sizes.NumVars = Record.readInt(); Sizes.NumUniqueDeclarations = Record.readInt(); Sizes.NumComponentLists = Record.readInt(); Sizes.NumComponents = Record.readInt(); C = OMPIsDevicePtrClause::CreateEmpty(Context, Sizes); break; } case llvm::omp::OMPC_has_device_addr: { OMPMappableExprListSizeTy Sizes; Sizes.NumVars = Record.readInt(); Sizes.NumUniqueDeclarations = Record.readInt(); Sizes.NumComponentLists = Record.readInt(); Sizes.NumComponents = Record.readInt(); C = OMPHasDeviceAddrClause::CreateEmpty(Context, Sizes); break; } case llvm::omp::OMPC_allocate: C = OMPAllocateClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_nontemporal: C = OMPNontemporalClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_inclusive: C = OMPInclusiveClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_exclusive: C = OMPExclusiveClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_order: C = new (Context) OMPOrderClause(); break; case llvm::omp::OMPC_init: C = OMPInitClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_use: C = new (Context) OMPUseClause(); break; case llvm::omp::OMPC_destroy: C = new (Context) OMPDestroyClause(); break; case llvm::omp::OMPC_novariants: C = new (Context) OMPNovariantsClause(); break; case llvm::omp::OMPC_nocontext: C = new (Context) OMPNocontextClause(); break; case llvm::omp::OMPC_detach: C = new (Context) OMPDetachClause(); break; case llvm::omp::OMPC_uses_allocators: C = OMPUsesAllocatorsClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_affinity: C = OMPAffinityClause::CreateEmpty(Context, Record.readInt()); break; case llvm::omp::OMPC_filter: C = new (Context) OMPFilterClause(); break; case llvm::omp::OMPC_bind: C = OMPBindClause::CreateEmpty(Context); break; case llvm::omp::OMPC_align: C = new (Context) OMPAlignClause(); break; case llvm::omp::OMPC_ompx_dyn_cgroup_mem: C = new (Context) OMPXDynCGroupMemClause(); break; case llvm::omp::OMPC_doacross: { unsigned NumVars = Record.readInt(); unsigned NumLoops = Record.readInt(); C = OMPDoacrossClause::CreateEmpty(Context, NumVars, NumLoops); break; } case llvm::omp::OMPC_ompx_attribute: C = new (Context) OMPXAttributeClause(); break; case llvm::omp::OMPC_ompx_bare: C = new (Context) OMPXBareClause(); break; #define OMP_CLAUSE_NO_CLASS(Enum, Str) \ case llvm::omp::Enum: \ break; #include "llvm/Frontend/OpenMP/OMPKinds.def" default: break; } assert(C && "Unknown OMPClause type"); Visit(C); C->setLocStart(Record.readSourceLocation()); C->setLocEnd(Record.readSourceLocation()); return C; } void OMPClauseReader::VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C) { C->setPreInitStmt(Record.readSubStmt(), static_cast(Record.readInt())); } void OMPClauseReader::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) { VisitOMPClauseWithPreInit(C); C->setPostUpdateExpr(Record.readSubExpr()); } void OMPClauseReader::VisitOMPIfClause(OMPIfClause *C) { VisitOMPClauseWithPreInit(C); C->setNameModifier(static_cast(Record.readInt())); C->setNameModifierLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); C->setCondition(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPFinalClause(OMPFinalClause *C) { VisitOMPClauseWithPreInit(C); C->setCondition(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { VisitOMPClauseWithPreInit(C); C->setNumThreads(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPSafelenClause(OMPSafelenClause *C) { C->setSafelen(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPSimdlenClause(OMPSimdlenClause *C) { C->setSimdlen(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPSizesClause(OMPSizesClause *C) { for (Expr *&E : C->getSizesRefs()) E = Record.readSubExpr(); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPFullClause(OMPFullClause *C) {} void OMPClauseReader::VisitOMPPartialClause(OMPPartialClause *C) { C->setFactor(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPAllocatorClause(OMPAllocatorClause *C) { C->setAllocator(Record.readExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPCollapseClause(OMPCollapseClause *C) { C->setNumForLoops(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) { C->setDefaultKind(static_cast(Record.readInt())); C->setLParenLoc(Record.readSourceLocation()); C->setDefaultKindKwLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) { C->setProcBindKind(static_cast(Record.readInt())); C->setLParenLoc(Record.readSourceLocation()); C->setProcBindKindKwLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) { VisitOMPClauseWithPreInit(C); C->setScheduleKind( static_cast(Record.readInt())); C->setFirstScheduleModifier( static_cast(Record.readInt())); C->setSecondScheduleModifier( static_cast(Record.readInt())); C->setChunkSize(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); C->setFirstScheduleModifierLoc(Record.readSourceLocation()); C->setSecondScheduleModifierLoc(Record.readSourceLocation()); C->setScheduleKindLoc(Record.readSourceLocation()); C->setCommaLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *C) { C->setNumForLoops(Record.readSubExpr()); for (unsigned I = 0, E = C->NumberOfLoops; I < E; ++I) C->setLoopNumIterations(I, Record.readSubExpr()); for (unsigned I = 0, E = C->NumberOfLoops; I < E; ++I) C->setLoopCounter(I, Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPDetachClause(OMPDetachClause *C) { C->setEventHandler(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPNowaitClause(OMPNowaitClause *) {} void OMPClauseReader::VisitOMPUntiedClause(OMPUntiedClause *) {} void OMPClauseReader::VisitOMPMergeableClause(OMPMergeableClause *) {} void OMPClauseReader::VisitOMPReadClause(OMPReadClause *) {} void OMPClauseReader::VisitOMPWriteClause(OMPWriteClause *) {} void OMPClauseReader::VisitOMPUpdateClause(OMPUpdateClause *C) { if (C->isExtended()) { C->setLParenLoc(Record.readSourceLocation()); C->setArgumentLoc(Record.readSourceLocation()); C->setDependencyKind(Record.readEnum()); } } void OMPClauseReader::VisitOMPCaptureClause(OMPCaptureClause *) {} void OMPClauseReader::VisitOMPCompareClause(OMPCompareClause *) {} // Read the parameter of fail clause. This will have been saved when // OMPClauseWriter is called. void OMPClauseReader::VisitOMPFailClause(OMPFailClause *C) { C->setLParenLoc(Record.readSourceLocation()); SourceLocation FailParameterLoc = Record.readSourceLocation(); C->setFailParameterLoc(FailParameterLoc); OpenMPClauseKind CKind = Record.readEnum(); C->setFailParameter(CKind); } void OMPClauseReader::VisitOMPSeqCstClause(OMPSeqCstClause *) {} void OMPClauseReader::VisitOMPAcqRelClause(OMPAcqRelClause *) {} void OMPClauseReader::VisitOMPAcquireClause(OMPAcquireClause *) {} void OMPClauseReader::VisitOMPReleaseClause(OMPReleaseClause *) {} void OMPClauseReader::VisitOMPRelaxedClause(OMPRelaxedClause *) {} void OMPClauseReader::VisitOMPWeakClause(OMPWeakClause *) {} void OMPClauseReader::VisitOMPThreadsClause(OMPThreadsClause *) {} void OMPClauseReader::VisitOMPSIMDClause(OMPSIMDClause *) {} void OMPClauseReader::VisitOMPNogroupClause(OMPNogroupClause *) {} void OMPClauseReader::VisitOMPInitClause(OMPInitClause *C) { unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); C->setIsTarget(Record.readBool()); C->setIsTargetSync(Record.readBool()); C->setLParenLoc(Record.readSourceLocation()); C->setVarLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPUseClause(OMPUseClause *C) { C->setInteropVar(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); C->setVarLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPDestroyClause(OMPDestroyClause *C) { C->setInteropVar(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); C->setVarLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPNovariantsClause(OMPNovariantsClause *C) { VisitOMPClauseWithPreInit(C); C->setCondition(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPNocontextClause(OMPNocontextClause *C) { VisitOMPClauseWithPreInit(C); C->setCondition(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPUnifiedAddressClause(OMPUnifiedAddressClause *) {} void OMPClauseReader::VisitOMPUnifiedSharedMemoryClause( OMPUnifiedSharedMemoryClause *) {} void OMPClauseReader::VisitOMPReverseOffloadClause(OMPReverseOffloadClause *) {} void OMPClauseReader::VisitOMPDynamicAllocatorsClause(OMPDynamicAllocatorsClause *) { } void OMPClauseReader::VisitOMPAtomicDefaultMemOrderClause( OMPAtomicDefaultMemOrderClause *C) { C->setAtomicDefaultMemOrderKind( static_cast(Record.readInt())); C->setLParenLoc(Record.readSourceLocation()); C->setAtomicDefaultMemOrderKindKwLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPAtClause(OMPAtClause *C) { C->setAtKind(static_cast(Record.readInt())); C->setLParenLoc(Record.readSourceLocation()); C->setAtKindKwLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPSeverityClause(OMPSeverityClause *C) { C->setSeverityKind(static_cast(Record.readInt())); C->setLParenLoc(Record.readSourceLocation()); C->setSeverityKindKwLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPMessageClause(OMPMessageClause *C) { C->setMessageString(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) { C->setLParenLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setPrivateCopies(Vars); } void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { VisitOMPClauseWithPreInit(C); C->setLParenLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setPrivateCopies(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setInits(Vars); } void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) { VisitOMPClauseWithPostUpdate(C); C->setLParenLoc(Record.readSourceLocation()); C->setKind(Record.readEnum()); C->setKindLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setPrivateCopies(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setSourceExprs(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setDestinationExprs(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setAssignmentOps(Vars); } void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) { C->setLParenLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); } void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) { VisitOMPClauseWithPostUpdate(C); C->setLParenLoc(Record.readSourceLocation()); C->setModifierLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc(); DeclarationNameInfo DNI = Record.readDeclarationNameInfo(); C->setQualifierLoc(NNSL); C->setNameInfo(DNI); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setPrivates(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setLHSExprs(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setRHSExprs(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setReductionOps(Vars); if (C->getModifier() == OMPC_REDUCTION_inscan) { Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setInscanCopyOps(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setInscanCopyArrayTemps(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setInscanCopyArrayElems(Vars); } } void OMPClauseReader::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) { VisitOMPClauseWithPostUpdate(C); C->setLParenLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc(); DeclarationNameInfo DNI = Record.readDeclarationNameInfo(); C->setQualifierLoc(NNSL); C->setNameInfo(DNI); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); Vars.clear(); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setPrivates(Vars); Vars.clear(); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setLHSExprs(Vars); Vars.clear(); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setRHSExprs(Vars); Vars.clear(); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setReductionOps(Vars); } void OMPClauseReader::VisitOMPInReductionClause(OMPInReductionClause *C) { VisitOMPClauseWithPostUpdate(C); C->setLParenLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc(); DeclarationNameInfo DNI = Record.readDeclarationNameInfo(); C->setQualifierLoc(NNSL); C->setNameInfo(DNI); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); Vars.clear(); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setPrivates(Vars); Vars.clear(); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setLHSExprs(Vars); Vars.clear(); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setRHSExprs(Vars); Vars.clear(); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setReductionOps(Vars); Vars.clear(); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setTaskgroupDescriptors(Vars); } void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) { VisitOMPClauseWithPostUpdate(C); C->setLParenLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); C->setModifier(static_cast(Record.readInt())); C->setModifierLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setPrivates(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setInits(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setUpdates(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setFinals(Vars); C->setStep(Record.readSubExpr()); C->setCalcStep(Record.readSubExpr()); Vars.clear(); for (unsigned I = 0; I != NumVars + 1; ++I) Vars.push_back(Record.readSubExpr()); C->setUsedExprs(Vars); } void OMPClauseReader::VisitOMPAlignedClause(OMPAlignedClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); C->setAlignment(Record.readSubExpr()); } void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *C) { C->setLParenLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Exprs; Exprs.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Exprs.push_back(Record.readSubExpr()); C->setVarRefs(Exprs); Exprs.clear(); for (unsigned i = 0; i != NumVars; ++i) Exprs.push_back(Record.readSubExpr()); C->setSourceExprs(Exprs); Exprs.clear(); for (unsigned i = 0; i != NumVars; ++i) Exprs.push_back(Record.readSubExpr()); C->setDestinationExprs(Exprs); Exprs.clear(); for (unsigned i = 0; i != NumVars; ++i) Exprs.push_back(Record.readSubExpr()); C->setAssignmentOps(Exprs); } void OMPClauseReader::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) { C->setLParenLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Exprs; Exprs.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Exprs.push_back(Record.readSubExpr()); C->setVarRefs(Exprs); Exprs.clear(); for (unsigned i = 0; i != NumVars; ++i) Exprs.push_back(Record.readSubExpr()); C->setSourceExprs(Exprs); Exprs.clear(); for (unsigned i = 0; i != NumVars; ++i) Exprs.push_back(Record.readSubExpr()); C->setDestinationExprs(Exprs); Exprs.clear(); for (unsigned i = 0; i != NumVars; ++i) Exprs.push_back(Record.readSubExpr()); C->setAssignmentOps(Exprs); } void OMPClauseReader::VisitOMPFlushClause(OMPFlushClause *C) { C->setLParenLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); } void OMPClauseReader::VisitOMPDepobjClause(OMPDepobjClause *C) { C->setDepobj(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPDependClause(OMPDependClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setModifier(Record.readSubExpr()); C->setDependencyKind( static_cast(Record.readInt())); C->setDependencyLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); C->setOmpAllMemoryLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) C->setLoopData(I, Record.readSubExpr()); } void OMPClauseReader::VisitOMPDeviceClause(OMPDeviceClause *C) { VisitOMPClauseWithPreInit(C); C->setModifier(Record.readEnum()); C->setDevice(Record.readSubExpr()); C->setModifierLoc(Record.readSourceLocation()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) { C->setLParenLoc(Record.readSourceLocation()); bool HasIteratorModifier = false; for (unsigned I = 0; I < NumberOfOMPMapClauseModifiers; ++I) { C->setMapTypeModifier( I, static_cast(Record.readInt())); C->setMapTypeModifierLoc(I, Record.readSourceLocation()); if (C->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_iterator) HasIteratorModifier = true; } C->setMapperQualifierLoc(Record.readNestedNameSpecifierLoc()); C->setMapperIdInfo(Record.readDeclarationNameInfo()); C->setMapType( static_cast(Record.readInt())); C->setMapLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); auto NumVars = C->varlist_size(); auto UniqueDecls = C->getUniqueDeclarationsNum(); auto TotalLists = C->getTotalComponentListNum(); auto TotalComponents = C->getTotalComponentsNum(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readExpr()); C->setVarRefs(Vars); SmallVector UDMappers; UDMappers.reserve(NumVars); for (unsigned I = 0; I < NumVars; ++I) UDMappers.push_back(Record.readExpr()); C->setUDMapperRefs(UDMappers); if (HasIteratorModifier) C->setIteratorModifier(Record.readExpr()); SmallVector Decls; Decls.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) Decls.push_back(Record.readDeclAs()); C->setUniqueDecls(Decls); SmallVector ListsPerDecl; ListsPerDecl.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) ListsPerDecl.push_back(Record.readInt()); C->setDeclNumLists(ListsPerDecl); SmallVector ListSizes; ListSizes.reserve(TotalLists); for (unsigned i = 0; i < TotalLists; ++i) ListSizes.push_back(Record.readInt()); C->setComponentListSizes(ListSizes); SmallVector Components; Components.reserve(TotalComponents); for (unsigned i = 0; i < TotalComponents; ++i) { Expr *AssociatedExprPr = Record.readExpr(); auto *AssociatedDecl = Record.readDeclAs(); Components.emplace_back(AssociatedExprPr, AssociatedDecl, /*IsNonContiguous=*/false); } C->setComponents(Components, ListSizes); } void OMPClauseReader::VisitOMPAllocateClause(OMPAllocateClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); C->setAllocator(Record.readSubExpr()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); } void OMPClauseReader::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) { VisitOMPClauseWithPreInit(C); C->setNumTeams(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) { VisitOMPClauseWithPreInit(C); C->setThreadLimit(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPPriorityClause(OMPPriorityClause *C) { VisitOMPClauseWithPreInit(C); C->setPriority(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) { VisitOMPClauseWithPreInit(C); C->setModifier(Record.readEnum()); C->setGrainsize(Record.readSubExpr()); C->setModifierLoc(Record.readSourceLocation()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPNumTasksClause(OMPNumTasksClause *C) { VisitOMPClauseWithPreInit(C); C->setModifier(Record.readEnum()); C->setNumTasks(Record.readSubExpr()); C->setModifierLoc(Record.readSourceLocation()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPHintClause(OMPHintClause *C) { C->setHint(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPDistScheduleClause(OMPDistScheduleClause *C) { VisitOMPClauseWithPreInit(C); C->setDistScheduleKind( static_cast(Record.readInt())); C->setChunkSize(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); C->setDistScheduleKindLoc(Record.readSourceLocation()); C->setCommaLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPDefaultmapClause(OMPDefaultmapClause *C) { C->setDefaultmapKind( static_cast(Record.readInt())); C->setDefaultmapModifier( static_cast(Record.readInt())); C->setLParenLoc(Record.readSourceLocation()); C->setDefaultmapModifierLoc(Record.readSourceLocation()); C->setDefaultmapKindLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPToClause(OMPToClause *C) { C->setLParenLoc(Record.readSourceLocation()); for (unsigned I = 0; I < NumberOfOMPMotionModifiers; ++I) { C->setMotionModifier( I, static_cast(Record.readInt())); C->setMotionModifierLoc(I, Record.readSourceLocation()); } C->setMapperQualifierLoc(Record.readNestedNameSpecifierLoc()); C->setMapperIdInfo(Record.readDeclarationNameInfo()); C->setColonLoc(Record.readSourceLocation()); auto NumVars = C->varlist_size(); auto UniqueDecls = C->getUniqueDeclarationsNum(); auto TotalLists = C->getTotalComponentListNum(); auto TotalComponents = C->getTotalComponentsNum(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); SmallVector UDMappers; UDMappers.reserve(NumVars); for (unsigned I = 0; I < NumVars; ++I) UDMappers.push_back(Record.readSubExpr()); C->setUDMapperRefs(UDMappers); SmallVector Decls; Decls.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) Decls.push_back(Record.readDeclAs()); C->setUniqueDecls(Decls); SmallVector ListsPerDecl; ListsPerDecl.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) ListsPerDecl.push_back(Record.readInt()); C->setDeclNumLists(ListsPerDecl); SmallVector ListSizes; ListSizes.reserve(TotalLists); for (unsigned i = 0; i < TotalLists; ++i) ListSizes.push_back(Record.readInt()); C->setComponentListSizes(ListSizes); SmallVector Components; Components.reserve(TotalComponents); for (unsigned i = 0; i < TotalComponents; ++i) { Expr *AssociatedExprPr = Record.readSubExpr(); bool IsNonContiguous = Record.readBool(); auto *AssociatedDecl = Record.readDeclAs(); Components.emplace_back(AssociatedExprPr, AssociatedDecl, IsNonContiguous); } C->setComponents(Components, ListSizes); } void OMPClauseReader::VisitOMPFromClause(OMPFromClause *C) { C->setLParenLoc(Record.readSourceLocation()); for (unsigned I = 0; I < NumberOfOMPMotionModifiers; ++I) { C->setMotionModifier( I, static_cast(Record.readInt())); C->setMotionModifierLoc(I, Record.readSourceLocation()); } C->setMapperQualifierLoc(Record.readNestedNameSpecifierLoc()); C->setMapperIdInfo(Record.readDeclarationNameInfo()); C->setColonLoc(Record.readSourceLocation()); auto NumVars = C->varlist_size(); auto UniqueDecls = C->getUniqueDeclarationsNum(); auto TotalLists = C->getTotalComponentListNum(); auto TotalComponents = C->getTotalComponentsNum(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); SmallVector UDMappers; UDMappers.reserve(NumVars); for (unsigned I = 0; I < NumVars; ++I) UDMappers.push_back(Record.readSubExpr()); C->setUDMapperRefs(UDMappers); SmallVector Decls; Decls.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) Decls.push_back(Record.readDeclAs()); C->setUniqueDecls(Decls); SmallVector ListsPerDecl; ListsPerDecl.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) ListsPerDecl.push_back(Record.readInt()); C->setDeclNumLists(ListsPerDecl); SmallVector ListSizes; ListSizes.reserve(TotalLists); for (unsigned i = 0; i < TotalLists; ++i) ListSizes.push_back(Record.readInt()); C->setComponentListSizes(ListSizes); SmallVector Components; Components.reserve(TotalComponents); for (unsigned i = 0; i < TotalComponents; ++i) { Expr *AssociatedExprPr = Record.readSubExpr(); bool IsNonContiguous = Record.readBool(); auto *AssociatedDecl = Record.readDeclAs(); Components.emplace_back(AssociatedExprPr, AssociatedDecl, IsNonContiguous); } C->setComponents(Components, ListSizes); } void OMPClauseReader::VisitOMPUseDevicePtrClause(OMPUseDevicePtrClause *C) { C->setLParenLoc(Record.readSourceLocation()); auto NumVars = C->varlist_size(); auto UniqueDecls = C->getUniqueDeclarationsNum(); auto TotalLists = C->getTotalComponentListNum(); auto TotalComponents = C->getTotalComponentsNum(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setPrivateCopies(Vars); Vars.clear(); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setInits(Vars); SmallVector Decls; Decls.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) Decls.push_back(Record.readDeclAs()); C->setUniqueDecls(Decls); SmallVector ListsPerDecl; ListsPerDecl.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) ListsPerDecl.push_back(Record.readInt()); C->setDeclNumLists(ListsPerDecl); SmallVector ListSizes; ListSizes.reserve(TotalLists); for (unsigned i = 0; i < TotalLists; ++i) ListSizes.push_back(Record.readInt()); C->setComponentListSizes(ListSizes); SmallVector Components; Components.reserve(TotalComponents); for (unsigned i = 0; i < TotalComponents; ++i) { auto *AssociatedExprPr = Record.readSubExpr(); auto *AssociatedDecl = Record.readDeclAs(); Components.emplace_back(AssociatedExprPr, AssociatedDecl, /*IsNonContiguous=*/false); } C->setComponents(Components, ListSizes); } void OMPClauseReader::VisitOMPUseDeviceAddrClause(OMPUseDeviceAddrClause *C) { C->setLParenLoc(Record.readSourceLocation()); auto NumVars = C->varlist_size(); auto UniqueDecls = C->getUniqueDeclarationsNum(); auto TotalLists = C->getTotalComponentListNum(); auto TotalComponents = C->getTotalComponentsNum(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); SmallVector Decls; Decls.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) Decls.push_back(Record.readDeclAs()); C->setUniqueDecls(Decls); SmallVector ListsPerDecl; ListsPerDecl.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) ListsPerDecl.push_back(Record.readInt()); C->setDeclNumLists(ListsPerDecl); SmallVector ListSizes; ListSizes.reserve(TotalLists); for (unsigned i = 0; i < TotalLists; ++i) ListSizes.push_back(Record.readInt()); C->setComponentListSizes(ListSizes); SmallVector Components; Components.reserve(TotalComponents); for (unsigned i = 0; i < TotalComponents; ++i) { Expr *AssociatedExpr = Record.readSubExpr(); auto *AssociatedDecl = Record.readDeclAs(); Components.emplace_back(AssociatedExpr, AssociatedDecl, /*IsNonContiguous*/ false); } C->setComponents(Components, ListSizes); } void OMPClauseReader::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { C->setLParenLoc(Record.readSourceLocation()); auto NumVars = C->varlist_size(); auto UniqueDecls = C->getUniqueDeclarationsNum(); auto TotalLists = C->getTotalComponentListNum(); auto TotalComponents = C->getTotalComponentsNum(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); Vars.clear(); SmallVector Decls; Decls.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) Decls.push_back(Record.readDeclAs()); C->setUniqueDecls(Decls); SmallVector ListsPerDecl; ListsPerDecl.reserve(UniqueDecls); for (unsigned i = 0; i < UniqueDecls; ++i) ListsPerDecl.push_back(Record.readInt()); C->setDeclNumLists(ListsPerDecl); SmallVector ListSizes; ListSizes.reserve(TotalLists); for (unsigned i = 0; i < TotalLists; ++i) ListSizes.push_back(Record.readInt()); C->setComponentListSizes(ListSizes); SmallVector Components; Components.reserve(TotalComponents); for (unsigned i = 0; i < TotalComponents; ++i) { Expr *AssociatedExpr = Record.readSubExpr(); auto *AssociatedDecl = Record.readDeclAs(); Components.emplace_back(AssociatedExpr, AssociatedDecl, /*IsNonContiguous=*/false); } C->setComponents(Components, ListSizes); } void OMPClauseReader::VisitOMPHasDeviceAddrClause(OMPHasDeviceAddrClause *C) { C->setLParenLoc(Record.readSourceLocation()); auto NumVars = C->varlist_size(); auto UniqueDecls = C->getUniqueDeclarationsNum(); auto TotalLists = C->getTotalComponentListNum(); auto TotalComponents = C->getTotalComponentsNum(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); Vars.clear(); SmallVector Decls; Decls.reserve(UniqueDecls); for (unsigned I = 0; I < UniqueDecls; ++I) Decls.push_back(Record.readDeclAs()); C->setUniqueDecls(Decls); SmallVector ListsPerDecl; ListsPerDecl.reserve(UniqueDecls); for (unsigned I = 0; I < UniqueDecls; ++I) ListsPerDecl.push_back(Record.readInt()); C->setDeclNumLists(ListsPerDecl); SmallVector ListSizes; ListSizes.reserve(TotalLists); for (unsigned i = 0; i < TotalLists; ++i) ListSizes.push_back(Record.readInt()); C->setComponentListSizes(ListSizes); SmallVector Components; Components.reserve(TotalComponents); for (unsigned I = 0; I < TotalComponents; ++I) { Expr *AssociatedExpr = Record.readSubExpr(); auto *AssociatedDecl = Record.readDeclAs(); Components.emplace_back(AssociatedExpr, AssociatedDecl, /*IsNonContiguous=*/false); } C->setComponents(Components, ListSizes); } void OMPClauseReader::VisitOMPNontemporalClause(OMPNontemporalClause *C) { C->setLParenLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); Vars.clear(); Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setPrivateRefs(Vars); } void OMPClauseReader::VisitOMPInclusiveClause(OMPInclusiveClause *C) { C->setLParenLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); } void OMPClauseReader::VisitOMPExclusiveClause(OMPExclusiveClause *C) { C->setLParenLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); } void OMPClauseReader::VisitOMPUsesAllocatorsClause(OMPUsesAllocatorsClause *C) { C->setLParenLoc(Record.readSourceLocation()); unsigned NumOfAllocators = C->getNumberOfAllocators(); SmallVector Data; Data.reserve(NumOfAllocators); for (unsigned I = 0; I != NumOfAllocators; ++I) { OMPUsesAllocatorsClause::Data &D = Data.emplace_back(); D.Allocator = Record.readSubExpr(); D.AllocatorTraits = Record.readSubExpr(); D.LParenLoc = Record.readSourceLocation(); D.RParenLoc = Record.readSourceLocation(); } C->setAllocatorsData(Data); } void OMPClauseReader::VisitOMPAffinityClause(OMPAffinityClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setModifier(Record.readSubExpr()); C->setColonLoc(Record.readSourceLocation()); unsigned NumOfLocators = C->varlist_size(); SmallVector Locators; Locators.reserve(NumOfLocators); for (unsigned I = 0; I != NumOfLocators; ++I) Locators.push_back(Record.readSubExpr()); C->setVarRefs(Locators); } void OMPClauseReader::VisitOMPOrderClause(OMPOrderClause *C) { C->setKind(Record.readEnum()); C->setModifier(Record.readEnum()); C->setLParenLoc(Record.readSourceLocation()); C->setKindKwLoc(Record.readSourceLocation()); C->setModifierKwLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPFilterClause(OMPFilterClause *C) { VisitOMPClauseWithPreInit(C); C->setThreadID(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPBindClause(OMPBindClause *C) { C->setBindKind(Record.readEnum()); C->setLParenLoc(Record.readSourceLocation()); C->setBindKindLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPAlignClause(OMPAlignClause *C) { C->setAlignment(Record.readExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) { VisitOMPClauseWithPreInit(C); C->setSize(Record.readSubExpr()); C->setLParenLoc(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPDoacrossClause(OMPDoacrossClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setDependenceType( static_cast(Record.readInt())); C->setDependenceLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector Vars; Vars.reserve(NumVars); for (unsigned I = 0; I != NumVars; ++I) Vars.push_back(Record.readSubExpr()); C->setVarRefs(Vars); for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) C->setLoopData(I, Record.readSubExpr()); } void OMPClauseReader::VisitOMPXAttributeClause(OMPXAttributeClause *C) { AttrVec Attrs; Record.readAttributes(Attrs); C->setAttrs(Attrs); C->setLocStart(Record.readSourceLocation()); C->setLParenLoc(Record.readSourceLocation()); C->setLocEnd(Record.readSourceLocation()); } void OMPClauseReader::VisitOMPXBareClause(OMPXBareClause *C) {} OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() { OMPTraitInfo &TI = getContext().getNewOMPTraitInfo(); TI.Sets.resize(readUInt32()); for (auto &Set : TI.Sets) { Set.Kind = readEnum(); Set.Selectors.resize(readUInt32()); for (auto &Selector : Set.Selectors) { Selector.Kind = readEnum(); Selector.ScoreOrCondition = nullptr; if (readBool()) Selector.ScoreOrCondition = readExprRef(); Selector.Properties.resize(readUInt32()); for (auto &Property : Selector.Properties) Property.Kind = readEnum(); } } return &TI; } void ASTRecordReader::readOMPChildren(OMPChildren *Data) { if (!Data) return; if (Reader->ReadingKind == ASTReader::Read_Stmt) { // Skip NumClauses, NumChildren and HasAssociatedStmt fields. skipInts(3); } SmallVector Clauses(Data->getNumClauses()); for (unsigned I = 0, E = Data->getNumClauses(); I < E; ++I) Clauses[I] = readOMPClause(); Data->setClauses(Clauses); if (Data->hasAssociatedStmt()) Data->setAssociatedStmt(readStmt()); for (unsigned I = 0, E = Data->getNumChildren(); I < E; ++I) Data->getChildren()[I] = readStmt(); } SmallVector ASTRecordReader::readOpenACCVarList() { unsigned NumVars = readInt(); llvm::SmallVector VarList; for (unsigned I = 0; I < NumVars; ++I) VarList.push_back(readSubExpr()); return VarList; } SmallVector ASTRecordReader::readOpenACCIntExprList() { unsigned NumExprs = readInt(); llvm::SmallVector ExprList; for (unsigned I = 0; I < NumExprs; ++I) ExprList.push_back(readSubExpr()); return ExprList; } OpenACCClause *ASTRecordReader::readOpenACCClause() { OpenACCClauseKind ClauseKind = readEnum(); SourceLocation BeginLoc = readSourceLocation(); SourceLocation EndLoc = readSourceLocation(); switch (ClauseKind) { case OpenACCClauseKind::Default: { SourceLocation LParenLoc = readSourceLocation(); OpenACCDefaultClauseKind DCK = readEnum(); return OpenACCDefaultClause::Create(getContext(), DCK, BeginLoc, LParenLoc, EndLoc); } case OpenACCClauseKind::If: { SourceLocation LParenLoc = readSourceLocation(); Expr *CondExpr = readSubExpr(); return OpenACCIfClause::Create(getContext(), BeginLoc, LParenLoc, CondExpr, EndLoc); } case OpenACCClauseKind::Self: { SourceLocation LParenLoc = readSourceLocation(); Expr *CondExpr = readBool() ? readSubExpr() : nullptr; return OpenACCSelfClause::Create(getContext(), BeginLoc, LParenLoc, CondExpr, EndLoc); } case OpenACCClauseKind::NumGangs: { SourceLocation LParenLoc = readSourceLocation(); unsigned NumClauses = readInt(); llvm::SmallVector IntExprs; for (unsigned I = 0; I < NumClauses; ++I) IntExprs.push_back(readSubExpr()); return OpenACCNumGangsClause::Create(getContext(), BeginLoc, LParenLoc, IntExprs, EndLoc); } case OpenACCClauseKind::NumWorkers: { SourceLocation LParenLoc = readSourceLocation(); Expr *IntExpr = readSubExpr(); return OpenACCNumWorkersClause::Create(getContext(), BeginLoc, LParenLoc, IntExpr, EndLoc); } case OpenACCClauseKind::VectorLength: { SourceLocation LParenLoc = readSourceLocation(); Expr *IntExpr = readSubExpr(); return OpenACCVectorLengthClause::Create(getContext(), BeginLoc, LParenLoc, IntExpr, EndLoc); } case OpenACCClauseKind::Private: { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector VarList = readOpenACCVarList(); return OpenACCPrivateClause::Create(getContext(), BeginLoc, LParenLoc, VarList, EndLoc); } case OpenACCClauseKind::FirstPrivate: { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector VarList = readOpenACCVarList(); return OpenACCFirstPrivateClause::Create(getContext(), BeginLoc, LParenLoc, VarList, EndLoc); } case OpenACCClauseKind::Attach: { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector VarList = readOpenACCVarList(); return OpenACCAttachClause::Create(getContext(), BeginLoc, LParenLoc, VarList, EndLoc); } case OpenACCClauseKind::DevicePtr: { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector VarList = readOpenACCVarList(); return OpenACCDevicePtrClause::Create(getContext(), BeginLoc, LParenLoc, VarList, EndLoc); } case OpenACCClauseKind::NoCreate: { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector VarList = readOpenACCVarList(); return OpenACCNoCreateClause::Create(getContext(), BeginLoc, LParenLoc, VarList, EndLoc); } case OpenACCClauseKind::Present: { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector VarList = readOpenACCVarList(); return OpenACCPresentClause::Create(getContext(), BeginLoc, LParenLoc, VarList, EndLoc); } case OpenACCClauseKind::PCopy: case OpenACCClauseKind::PresentOrCopy: case OpenACCClauseKind::Copy: { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector VarList = readOpenACCVarList(); return OpenACCCopyClause::Create(getContext(), ClauseKind, BeginLoc, LParenLoc, VarList, EndLoc); } case OpenACCClauseKind::CopyIn: case OpenACCClauseKind::PCopyIn: case OpenACCClauseKind::PresentOrCopyIn: { SourceLocation LParenLoc = readSourceLocation(); bool IsReadOnly = readBool(); llvm::SmallVector VarList = readOpenACCVarList(); return OpenACCCopyInClause::Create(getContext(), ClauseKind, BeginLoc, LParenLoc, IsReadOnly, VarList, EndLoc); } case OpenACCClauseKind::CopyOut: case OpenACCClauseKind::PCopyOut: case OpenACCClauseKind::PresentOrCopyOut: { SourceLocation LParenLoc = readSourceLocation(); bool IsZero = readBool(); llvm::SmallVector VarList = readOpenACCVarList(); return OpenACCCopyOutClause::Create(getContext(), ClauseKind, BeginLoc, LParenLoc, IsZero, VarList, EndLoc); } case OpenACCClauseKind::Create: case OpenACCClauseKind::PCreate: case OpenACCClauseKind::PresentOrCreate: { SourceLocation LParenLoc = readSourceLocation(); bool IsZero = readBool(); llvm::SmallVector VarList = readOpenACCVarList(); return OpenACCCreateClause::Create(getContext(), ClauseKind, BeginLoc, LParenLoc, IsZero, VarList, EndLoc); } case OpenACCClauseKind::Async: { SourceLocation LParenLoc = readSourceLocation(); Expr *AsyncExpr = readBool() ? readSubExpr() : nullptr; return OpenACCAsyncClause::Create(getContext(), BeginLoc, LParenLoc, AsyncExpr, EndLoc); } case OpenACCClauseKind::Wait: { SourceLocation LParenLoc = readSourceLocation(); Expr *DevNumExpr = readBool() ? readSubExpr() : nullptr; SourceLocation QueuesLoc = readSourceLocation(); llvm::SmallVector QueueIdExprs = readOpenACCIntExprList(); return OpenACCWaitClause::Create(getContext(), BeginLoc, LParenLoc, DevNumExpr, QueuesLoc, QueueIdExprs, EndLoc); } case OpenACCClauseKind::DeviceType: case OpenACCClauseKind::DType: { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector Archs; unsigned NumArchs = readInt(); for (unsigned I = 0; I < NumArchs; ++I) { IdentifierInfo *Ident = readBool() ? readIdentifier() : nullptr; SourceLocation Loc = readSourceLocation(); Archs.emplace_back(Ident, Loc); } return OpenACCDeviceTypeClause::Create(getContext(), ClauseKind, BeginLoc, LParenLoc, Archs, EndLoc); } case OpenACCClauseKind::Reduction: { SourceLocation LParenLoc = readSourceLocation(); OpenACCReductionOperator Op = readEnum(); llvm::SmallVector VarList = readOpenACCVarList(); return OpenACCReductionClause::Create(getContext(), BeginLoc, LParenLoc, Op, VarList, EndLoc); } case OpenACCClauseKind::Seq: return OpenACCSeqClause::Create(getContext(), BeginLoc, EndLoc); case OpenACCClauseKind::Independent: return OpenACCIndependentClause::Create(getContext(), BeginLoc, EndLoc); case OpenACCClauseKind::Auto: return OpenACCAutoClause::Create(getContext(), BeginLoc, EndLoc); case OpenACCClauseKind::Finalize: case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::Worker: case OpenACCClauseKind::Vector: case OpenACCClauseKind::NoHost: case OpenACCClauseKind::UseDevice: case OpenACCClauseKind::Delete: case OpenACCClauseKind::Detach: case OpenACCClauseKind::Device: case OpenACCClauseKind::DeviceResident: case OpenACCClauseKind::Host: case OpenACCClauseKind::Link: case OpenACCClauseKind::Collapse: case OpenACCClauseKind::Bind: case OpenACCClauseKind::DeviceNum: case OpenACCClauseKind::DefaultAsync: case OpenACCClauseKind::Tile: case OpenACCClauseKind::Gang: case OpenACCClauseKind::Invalid: llvm_unreachable("Clause serialization not yet implemented"); } llvm_unreachable("Invalid Clause Kind"); } void ASTRecordReader::readOpenACCClauseList( MutableArrayRef Clauses) { for (unsigned I = 0; I < Clauses.size(); ++I) Clauses[I] = readOpenACCClause(); } diff --git a/contrib/llvm-project/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm-project/clang/lib/Serialization/ASTWriter.cpp index cb63dec92e33..e907ddb88949 100644 --- a/contrib/llvm-project/clang/lib/Serialization/ASTWriter.cpp +++ b/contrib/llvm-project/clang/lib/Serialization/ASTWriter.cpp @@ -1,8113 +1,8119 @@ //===- ASTWriter.cpp - AST File Writer ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the ASTWriter class, which writes AST files. // //===----------------------------------------------------------------------===// #include "ASTCommon.h" #include "ASTReaderInternals.h" #include "MultiOnDiskHashTable.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTUnresolvedSet.h" #include "clang/AST/AbstractTypeWriter.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/LambdaCapture.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OpenACCClause.h" #include "clang/AST/OpenMPClause.h" #include "clang/AST/RawCommentList.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/Lambda.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/OpenCLOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/ModuleMap.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/Token.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/Weak.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTRecordWriter.h" #include "clang/Serialization/InMemoryModuleCache.h" #include "clang/Serialization/ModuleFile.h" #include "clang/Serialization/ModuleFileExtension.h" #include "clang/Serialization/SerializationDiagnostic.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitCodes.h" #include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" #include "llvm/Support/DJB.h" #include "llvm/Support/Endian.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" #include "llvm/Support/Path.h" #include "llvm/Support/SHA1.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/VersionTuple.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace clang; using namespace clang::serialization; template static StringRef bytes(const std::vector &v) { if (v.empty()) return StringRef(); return StringRef(reinterpret_cast(&v[0]), sizeof(T) * v.size()); } template static StringRef bytes(const SmallVectorImpl &v) { return StringRef(reinterpret_cast(v.data()), sizeof(T) * v.size()); } static std::string bytes(const std::vector &V) { std::string Str; Str.reserve(V.size() / 8); for (unsigned I = 0, E = V.size(); I < E;) { char Byte = 0; for (unsigned Bit = 0; Bit < 8 && I < E; ++Bit, ++I) Byte |= V[I] << Bit; Str += Byte; } return Str; } //===----------------------------------------------------------------------===// // Type serialization //===----------------------------------------------------------------------===// static TypeCode getTypeCodeForTypeClass(Type::TypeClass id) { switch (id) { #define TYPE_BIT_CODE(CLASS_ID, CODE_ID, CODE_VALUE) \ case Type::CLASS_ID: return TYPE_##CODE_ID; #include "clang/Serialization/TypeBitCodes.def" case Type::Builtin: llvm_unreachable("shouldn't be serializing a builtin type this way"); } llvm_unreachable("bad type kind"); } namespace { std::optional> GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) { if (!PP.getHeaderSearchInfo() .getHeaderSearchOpts() .ModulesPruneNonAffectingModuleMaps) return std::nullopt; const HeaderSearch &HS = PP.getHeaderSearchInfo(); const ModuleMap &MM = HS.getModuleMap(); std::set ModuleMaps; std::set ProcessedModules; auto CollectModuleMapsForHierarchy = [&](const Module *M) { M = M->getTopLevelModule(); if (!ProcessedModules.insert(M).second) return; std::queue Q; Q.push(M); while (!Q.empty()) { const Module *Mod = Q.front(); Q.pop(); // The containing module map is affecting, because it's being pointed // into by Module::DefinitionLoc. if (auto FE = MM.getContainingModuleMapFile(Mod)) ModuleMaps.insert(*FE); // For inferred modules, the module map that allowed inferring is not // related to the virtual containing module map file. It did affect the // compilation, though. if (auto FE = MM.getModuleMapFileForUniquing(Mod)) ModuleMaps.insert(*FE); for (auto *SubM : Mod->submodules()) Q.push(SubM); } }; // Handle all the affecting modules referenced from the root module. CollectModuleMapsForHierarchy(RootModule); std::queue Q; Q.push(RootModule); while (!Q.empty()) { const Module *CurrentModule = Q.front(); Q.pop(); for (const Module *ImportedModule : CurrentModule->Imports) CollectModuleMapsForHierarchy(ImportedModule); for (const Module *UndeclaredModule : CurrentModule->UndeclaredUses) CollectModuleMapsForHierarchy(UndeclaredModule); for (auto *M : CurrentModule->submodules()) Q.push(M); } // Handle textually-included headers that belong to other modules. SmallVector FilesByUID; HS.getFileMgr().GetUniqueIDMapping(FilesByUID); if (FilesByUID.size() > HS.header_file_size()) FilesByUID.resize(HS.header_file_size()); for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) { OptionalFileEntryRef File = FilesByUID[UID]; if (!File) continue; const HeaderFileInfo *HFI = HS.getExistingLocalFileInfo(*File); if (!HFI) continue; // We have no information on this being a header file. if (!HFI->isCompilingModuleHeader && HFI->isModuleHeader) continue; // Modular header, handled in the above module-based loop. if (!HFI->isCompilingModuleHeader && !HFI->IsLocallyIncluded) continue; // Non-modular header not included locally is not affecting. for (const auto &KH : HS.findResolvedModulesForHeader(*File)) if (const Module *M = KH.getModule()) CollectModuleMapsForHierarchy(M); } // FIXME: This algorithm is not correct for module map hierarchies where // module map file defining a (sub)module of a top-level module X includes // a module map file that defines a (sub)module of another top-level module Y. // Whenever X is affecting and Y is not, "replaying" this PCM file will fail // when parsing module map files for X due to not knowing about the `extern` // module map for Y. // // We don't have a good way to fix it here. We could mark all children of // affecting module map files as being affecting as well, but that's // expensive. SourceManager does not model the edge from parent to child // SLocEntries, so instead, we would need to iterate over leaf module map // files, walk up their include hierarchy and check whether we arrive at an // affecting module map. // // Instead of complicating and slowing down this function, we should probably // just ban module map hierarchies where module map defining a (sub)module X // includes a module map defining a module that's not a submodule of X. return ModuleMaps; } class ASTTypeWriter { ASTWriter &Writer; ASTWriter::RecordData Record; ASTRecordWriter BasicWriter; public: ASTTypeWriter(ASTWriter &Writer) : Writer(Writer), BasicWriter(Writer, Record) {} uint64_t write(QualType T) { if (T.hasLocalNonFastQualifiers()) { Qualifiers Qs = T.getLocalQualifiers(); BasicWriter.writeQualType(T.getLocalUnqualifiedType()); BasicWriter.writeQualifiers(Qs); return BasicWriter.Emit(TYPE_EXT_QUAL, Writer.getTypeExtQualAbbrev()); } const Type *typePtr = T.getTypePtr(); serialization::AbstractTypeWriter atw(BasicWriter); atw.write(typePtr); return BasicWriter.Emit(getTypeCodeForTypeClass(typePtr->getTypeClass()), /*abbrev*/ 0); } }; class TypeLocWriter : public TypeLocVisitor { using LocSeq = SourceLocationSequence; ASTRecordWriter &Record; LocSeq *Seq; void addSourceLocation(SourceLocation Loc) { Record.AddSourceLocation(Loc, Seq); } void addSourceRange(SourceRange Range) { Record.AddSourceRange(Range, Seq); } public: TypeLocWriter(ASTRecordWriter &Record, LocSeq *Seq) : Record(Record), Seq(Seq) {} #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); #include "clang/AST/TypeLocNodes.def" void VisitArrayTypeLoc(ArrayTypeLoc TyLoc); void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc); }; } // namespace void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { // nothing to do } void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { addSourceLocation(TL.getBuiltinLoc()); if (TL.needsExtraLocalData()) { Record.push_back(TL.getWrittenTypeSpec()); Record.push_back(static_cast(TL.getWrittenSignSpec())); Record.push_back(static_cast(TL.getWrittenWidthSpec())); Record.push_back(TL.hasModeAttr()); } } void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) { addSourceLocation(TL.getStarLoc()); } void TypeLocWriter::VisitDecayedTypeLoc(DecayedTypeLoc TL) { // nothing to do } void TypeLocWriter::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { // nothing to do } void TypeLocWriter::VisitArrayParameterTypeLoc(ArrayParameterTypeLoc TL) { // nothing to do } void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { addSourceLocation(TL.getCaretLoc()); } void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { addSourceLocation(TL.getAmpLoc()); } void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { addSourceLocation(TL.getAmpAmpLoc()); } void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { addSourceLocation(TL.getStarLoc()); Record.AddTypeSourceInfo(TL.getClassTInfo()); } void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) { addSourceLocation(TL.getLBracketLoc()); addSourceLocation(TL.getRBracketLoc()); Record.push_back(TL.getSizeExpr() ? 1 : 0); if (TL.getSizeExpr()) Record.AddStmt(TL.getSizeExpr()); } void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocWriter::VisitDependentSizedArrayTypeLoc( DependentSizedArrayTypeLoc TL) { VisitArrayTypeLoc(TL); } void TypeLocWriter::VisitDependentAddressSpaceTypeLoc( DependentAddressSpaceTypeLoc TL) { addSourceLocation(TL.getAttrNameLoc()); SourceRange range = TL.getAttrOperandParensRange(); addSourceLocation(range.getBegin()); addSourceLocation(range.getEnd()); Record.AddStmt(TL.getAttrExprOperand()); } void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc( DependentSizedExtVectorTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitDependentVectorTypeLoc( DependentVectorTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitConstantMatrixTypeLoc(ConstantMatrixTypeLoc TL) { addSourceLocation(TL.getAttrNameLoc()); SourceRange range = TL.getAttrOperandParensRange(); addSourceLocation(range.getBegin()); addSourceLocation(range.getEnd()); Record.AddStmt(TL.getAttrRowOperand()); Record.AddStmt(TL.getAttrColumnOperand()); } void TypeLocWriter::VisitDependentSizedMatrixTypeLoc( DependentSizedMatrixTypeLoc TL) { addSourceLocation(TL.getAttrNameLoc()); SourceRange range = TL.getAttrOperandParensRange(); addSourceLocation(range.getBegin()); addSourceLocation(range.getEnd()); Record.AddStmt(TL.getAttrRowOperand()); Record.AddStmt(TL.getAttrColumnOperand()); } void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { addSourceLocation(TL.getLocalRangeBegin()); addSourceLocation(TL.getLParenLoc()); addSourceLocation(TL.getRParenLoc()); addSourceRange(TL.getExceptionSpecRange()); addSourceLocation(TL.getLocalRangeEnd()); for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) Record.AddDeclRef(TL.getParam(i)); } void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitUsingTypeLoc(UsingTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) { if (TL.getNumProtocols()) { addSourceLocation(TL.getProtocolLAngleLoc()); addSourceLocation(TL.getProtocolRAngleLoc()); } for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) addSourceLocation(TL.getProtocolLoc(i)); } void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { addSourceLocation(TL.getTypeofLoc()); addSourceLocation(TL.getLParenLoc()); addSourceLocation(TL.getRParenLoc()); } void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { addSourceLocation(TL.getTypeofLoc()); addSourceLocation(TL.getLParenLoc()); addSourceLocation(TL.getRParenLoc()); Record.AddTypeSourceInfo(TL.getUnmodifiedTInfo()); } void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { addSourceLocation(TL.getDecltypeLoc()); addSourceLocation(TL.getRParenLoc()); } void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { addSourceLocation(TL.getKWLoc()); addSourceLocation(TL.getLParenLoc()); addSourceLocation(TL.getRParenLoc()); Record.AddTypeSourceInfo(TL.getUnderlyingTInfo()); } void ASTRecordWriter::AddConceptReference(const ConceptReference *CR) { assert(CR); AddNestedNameSpecifierLoc(CR->getNestedNameSpecifierLoc()); AddSourceLocation(CR->getTemplateKWLoc()); AddDeclarationNameInfo(CR->getConceptNameInfo()); AddDeclRef(CR->getFoundDecl()); AddDeclRef(CR->getNamedConcept()); push_back(CR->getTemplateArgsAsWritten() != nullptr); if (CR->getTemplateArgsAsWritten()) AddASTTemplateArgumentListInfo(CR->getTemplateArgsAsWritten()); } void TypeLocWriter::VisitPackIndexingTypeLoc(PackIndexingTypeLoc TL) { addSourceLocation(TL.getEllipsisLoc()); } void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) { addSourceLocation(TL.getNameLoc()); auto *CR = TL.getConceptReference(); Record.push_back(TL.isConstrained() && CR); if (TL.isConstrained() && CR) Record.AddConceptReference(CR); Record.push_back(TL.isDecltypeAuto()); if (TL.isDecltypeAuto()) addSourceLocation(TL.getRParenLoc()); } void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc( DeducedTemplateSpecializationTypeLoc TL) { addSourceLocation(TL.getTemplateNameLoc()); } void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitAttributedTypeLoc(AttributedTypeLoc TL) { Record.AddAttr(TL.getAttr()); } void TypeLocWriter::VisitCountAttributedTypeLoc(CountAttributedTypeLoc TL) { // Nothing to do } void TypeLocWriter::VisitBTFTagAttributedTypeLoc(BTFTagAttributedTypeLoc TL) { // Nothing to do. } void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( SubstTemplateTypeParmTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitSubstTemplateTypeParmPackTypeLoc( SubstTemplateTypeParmPackTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { addSourceLocation(TL.getTemplateKeywordLoc()); addSourceLocation(TL.getTemplateNameLoc()); addSourceLocation(TL.getLAngleLoc()); addSourceLocation(TL.getRAngleLoc()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) Record.AddTemplateArgumentLocInfo(TL.getArgLoc(i).getArgument().getKind(), TL.getArgLoc(i).getLocInfo()); } void TypeLocWriter::VisitParenTypeLoc(ParenTypeLoc TL) { addSourceLocation(TL.getLParenLoc()); addSourceLocation(TL.getRParenLoc()); } void TypeLocWriter::VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) { addSourceLocation(TL.getExpansionLoc()); } void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { addSourceLocation(TL.getElaboratedKeywordLoc()); Record.AddNestedNameSpecifierLoc(TL.getQualifierLoc()); } void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { addSourceLocation(TL.getElaboratedKeywordLoc()); Record.AddNestedNameSpecifierLoc(TL.getQualifierLoc()); addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL) { addSourceLocation(TL.getElaboratedKeywordLoc()); Record.AddNestedNameSpecifierLoc(TL.getQualifierLoc()); addSourceLocation(TL.getTemplateKeywordLoc()); addSourceLocation(TL.getTemplateNameLoc()); addSourceLocation(TL.getLAngleLoc()); addSourceLocation(TL.getRAngleLoc()); for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) Record.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(), TL.getArgLoc(I).getLocInfo()); } void TypeLocWriter::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { addSourceLocation(TL.getEllipsisLoc()); } void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { addSourceLocation(TL.getNameLoc()); addSourceLocation(TL.getNameEndLoc()); } void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { Record.push_back(TL.hasBaseTypeAsWritten()); addSourceLocation(TL.getTypeArgsLAngleLoc()); addSourceLocation(TL.getTypeArgsRAngleLoc()); for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) Record.AddTypeSourceInfo(TL.getTypeArgTInfo(i)); addSourceLocation(TL.getProtocolLAngleLoc()); addSourceLocation(TL.getProtocolRAngleLoc()); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) addSourceLocation(TL.getProtocolLoc(i)); } void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { addSourceLocation(TL.getStarLoc()); } void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) { addSourceLocation(TL.getKWLoc()); addSourceLocation(TL.getLParenLoc()); addSourceLocation(TL.getRParenLoc()); } void TypeLocWriter::VisitPipeTypeLoc(PipeTypeLoc TL) { addSourceLocation(TL.getKWLoc()); } void TypeLocWriter::VisitBitIntTypeLoc(clang::BitIntTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void TypeLocWriter::VisitDependentBitIntTypeLoc( clang::DependentBitIntTypeLoc TL) { addSourceLocation(TL.getNameLoc()); } void ASTWriter::WriteTypeAbbrevs() { using namespace llvm; std::shared_ptr Abv; // Abbreviation for TYPE_EXT_QUAL Abv = std::make_shared(); Abv->Add(BitCodeAbbrevOp(serialization::TYPE_EXT_QUAL)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 3)); // Quals TypeExtQualAbbrev = Stream.EmitAbbrev(std::move(Abv)); } //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// static void EmitBlockID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, ASTWriter::RecordDataImpl &Record) { Record.clear(); Record.push_back(ID); Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); // Emit the block name if present. if (!Name || Name[0] == 0) return; Record.clear(); while (*Name) Record.push_back(*Name++); Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); } static void EmitRecordID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, ASTWriter::RecordDataImpl &Record) { Record.clear(); Record.push_back(ID); while (*Name) Record.push_back(*Name++); Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); } static void AddStmtsExprs(llvm::BitstreamWriter &Stream, ASTWriter::RecordDataImpl &Record) { #define RECORD(X) EmitRecordID(X, #X, Stream, Record) RECORD(STMT_STOP); RECORD(STMT_NULL_PTR); RECORD(STMT_REF_PTR); RECORD(STMT_NULL); RECORD(STMT_COMPOUND); RECORD(STMT_CASE); RECORD(STMT_DEFAULT); RECORD(STMT_LABEL); RECORD(STMT_ATTRIBUTED); RECORD(STMT_IF); RECORD(STMT_SWITCH); RECORD(STMT_WHILE); RECORD(STMT_DO); RECORD(STMT_FOR); RECORD(STMT_GOTO); RECORD(STMT_INDIRECT_GOTO); RECORD(STMT_CONTINUE); RECORD(STMT_BREAK); RECORD(STMT_RETURN); RECORD(STMT_DECL); RECORD(STMT_GCCASM); RECORD(STMT_MSASM); RECORD(EXPR_PREDEFINED); RECORD(EXPR_DECL_REF); RECORD(EXPR_INTEGER_LITERAL); RECORD(EXPR_FIXEDPOINT_LITERAL); RECORD(EXPR_FLOATING_LITERAL); RECORD(EXPR_IMAGINARY_LITERAL); RECORD(EXPR_STRING_LITERAL); RECORD(EXPR_CHARACTER_LITERAL); RECORD(EXPR_PAREN); RECORD(EXPR_PAREN_LIST); RECORD(EXPR_UNARY_OPERATOR); RECORD(EXPR_SIZEOF_ALIGN_OF); RECORD(EXPR_ARRAY_SUBSCRIPT); RECORD(EXPR_CALL); RECORD(EXPR_MEMBER); RECORD(EXPR_BINARY_OPERATOR); RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR); RECORD(EXPR_CONDITIONAL_OPERATOR); RECORD(EXPR_IMPLICIT_CAST); RECORD(EXPR_CSTYLE_CAST); RECORD(EXPR_COMPOUND_LITERAL); RECORD(EXPR_EXT_VECTOR_ELEMENT); RECORD(EXPR_INIT_LIST); RECORD(EXPR_DESIGNATED_INIT); RECORD(EXPR_DESIGNATED_INIT_UPDATE); RECORD(EXPR_IMPLICIT_VALUE_INIT); RECORD(EXPR_NO_INIT); RECORD(EXPR_VA_ARG); RECORD(EXPR_ADDR_LABEL); RECORD(EXPR_STMT); RECORD(EXPR_CHOOSE); RECORD(EXPR_GNU_NULL); RECORD(EXPR_SHUFFLE_VECTOR); RECORD(EXPR_BLOCK); RECORD(EXPR_GENERIC_SELECTION); RECORD(EXPR_OBJC_STRING_LITERAL); RECORD(EXPR_OBJC_BOXED_EXPRESSION); RECORD(EXPR_OBJC_ARRAY_LITERAL); RECORD(EXPR_OBJC_DICTIONARY_LITERAL); RECORD(EXPR_OBJC_ENCODE); RECORD(EXPR_OBJC_SELECTOR_EXPR); RECORD(EXPR_OBJC_PROTOCOL_EXPR); RECORD(EXPR_OBJC_IVAR_REF_EXPR); RECORD(EXPR_OBJC_PROPERTY_REF_EXPR); RECORD(EXPR_OBJC_KVC_REF_EXPR); RECORD(EXPR_OBJC_MESSAGE_EXPR); RECORD(STMT_OBJC_FOR_COLLECTION); RECORD(STMT_OBJC_CATCH); RECORD(STMT_OBJC_FINALLY); RECORD(STMT_OBJC_AT_TRY); RECORD(STMT_OBJC_AT_SYNCHRONIZED); RECORD(STMT_OBJC_AT_THROW); RECORD(EXPR_OBJC_BOOL_LITERAL); RECORD(STMT_CXX_CATCH); RECORD(STMT_CXX_TRY); RECORD(STMT_CXX_FOR_RANGE); RECORD(EXPR_CXX_OPERATOR_CALL); RECORD(EXPR_CXX_MEMBER_CALL); RECORD(EXPR_CXX_REWRITTEN_BINARY_OPERATOR); RECORD(EXPR_CXX_CONSTRUCT); RECORD(EXPR_CXX_TEMPORARY_OBJECT); RECORD(EXPR_CXX_STATIC_CAST); RECORD(EXPR_CXX_DYNAMIC_CAST); RECORD(EXPR_CXX_REINTERPRET_CAST); RECORD(EXPR_CXX_CONST_CAST); RECORD(EXPR_CXX_ADDRSPACE_CAST); RECORD(EXPR_CXX_FUNCTIONAL_CAST); RECORD(EXPR_USER_DEFINED_LITERAL); RECORD(EXPR_CXX_STD_INITIALIZER_LIST); RECORD(EXPR_CXX_BOOL_LITERAL); RECORD(EXPR_CXX_PAREN_LIST_INIT); RECORD(EXPR_CXX_NULL_PTR_LITERAL); RECORD(EXPR_CXX_TYPEID_EXPR); RECORD(EXPR_CXX_TYPEID_TYPE); RECORD(EXPR_CXX_THIS); RECORD(EXPR_CXX_THROW); RECORD(EXPR_CXX_DEFAULT_ARG); RECORD(EXPR_CXX_DEFAULT_INIT); RECORD(EXPR_CXX_BIND_TEMPORARY); RECORD(EXPR_CXX_SCALAR_VALUE_INIT); RECORD(EXPR_CXX_NEW); RECORD(EXPR_CXX_DELETE); RECORD(EXPR_CXX_PSEUDO_DESTRUCTOR); RECORD(EXPR_EXPR_WITH_CLEANUPS); RECORD(EXPR_CXX_DEPENDENT_SCOPE_MEMBER); RECORD(EXPR_CXX_DEPENDENT_SCOPE_DECL_REF); RECORD(EXPR_CXX_UNRESOLVED_CONSTRUCT); RECORD(EXPR_CXX_UNRESOLVED_MEMBER); RECORD(EXPR_CXX_UNRESOLVED_LOOKUP); RECORD(EXPR_CXX_EXPRESSION_TRAIT); RECORD(EXPR_CXX_NOEXCEPT); RECORD(EXPR_OPAQUE_VALUE); RECORD(EXPR_BINARY_CONDITIONAL_OPERATOR); RECORD(EXPR_TYPE_TRAIT); RECORD(EXPR_ARRAY_TYPE_TRAIT); RECORD(EXPR_PACK_EXPANSION); RECORD(EXPR_SIZEOF_PACK); RECORD(EXPR_PACK_INDEXING); RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM); RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK); RECORD(EXPR_FUNCTION_PARM_PACK); RECORD(EXPR_MATERIALIZE_TEMPORARY); RECORD(EXPR_CUDA_KERNEL_CALL); RECORD(EXPR_CXX_UUIDOF_EXPR); RECORD(EXPR_CXX_UUIDOF_TYPE); RECORD(EXPR_LAMBDA); #undef RECORD } void ASTWriter::WriteBlockInfoBlock() { RecordData Record; Stream.EnterBlockInfoBlock(); #define BLOCK(X) EmitBlockID(X ## _ID, #X, Stream, Record) #define RECORD(X) EmitRecordID(X, #X, Stream, Record) // Control Block. BLOCK(CONTROL_BLOCK); RECORD(METADATA); RECORD(MODULE_NAME); RECORD(MODULE_DIRECTORY); RECORD(MODULE_MAP_FILE); RECORD(IMPORTS); RECORD(ORIGINAL_FILE); RECORD(ORIGINAL_FILE_ID); RECORD(INPUT_FILE_OFFSETS); BLOCK(OPTIONS_BLOCK); RECORD(LANGUAGE_OPTIONS); RECORD(TARGET_OPTIONS); RECORD(FILE_SYSTEM_OPTIONS); RECORD(HEADER_SEARCH_OPTIONS); RECORD(PREPROCESSOR_OPTIONS); BLOCK(INPUT_FILES_BLOCK); RECORD(INPUT_FILE); RECORD(INPUT_FILE_HASH); // AST Top-Level Block. BLOCK(AST_BLOCK); RECORD(TYPE_OFFSET); RECORD(DECL_OFFSET); RECORD(IDENTIFIER_OFFSET); RECORD(IDENTIFIER_TABLE); RECORD(EAGERLY_DESERIALIZED_DECLS); RECORD(MODULAR_CODEGEN_DECLS); RECORD(SPECIAL_TYPES); RECORD(STATISTICS); RECORD(TENTATIVE_DEFINITIONS); RECORD(SELECTOR_OFFSETS); RECORD(METHOD_POOL); RECORD(PP_COUNTER_VALUE); RECORD(SOURCE_LOCATION_OFFSETS); RECORD(EXT_VECTOR_DECLS); RECORD(UNUSED_FILESCOPED_DECLS); RECORD(PPD_ENTITIES_OFFSETS); RECORD(VTABLE_USES); RECORD(PPD_SKIPPED_RANGES); RECORD(REFERENCED_SELECTOR_POOL); RECORD(TU_UPDATE_LEXICAL); RECORD(SEMA_DECL_REFS); RECORD(WEAK_UNDECLARED_IDENTIFIERS); RECORD(PENDING_IMPLICIT_INSTANTIATIONS); RECORD(UPDATE_VISIBLE); RECORD(DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD); RECORD(DECL_UPDATE_OFFSETS); RECORD(DECL_UPDATES); RECORD(CUDA_SPECIAL_DECL_REFS); RECORD(HEADER_SEARCH_TABLE); RECORD(FP_PRAGMA_OPTIONS); RECORD(OPENCL_EXTENSIONS); RECORD(OPENCL_EXTENSION_TYPES); RECORD(OPENCL_EXTENSION_DECLS); RECORD(DELEGATING_CTORS); RECORD(KNOWN_NAMESPACES); RECORD(MODULE_OFFSET_MAP); RECORD(SOURCE_MANAGER_LINE_TABLE); RECORD(OBJC_CATEGORIES_MAP); RECORD(FILE_SORTED_DECLS); RECORD(IMPORTED_MODULES); RECORD(OBJC_CATEGORIES); RECORD(MACRO_OFFSET); RECORD(INTERESTING_IDENTIFIERS); RECORD(UNDEFINED_BUT_USED); RECORD(LATE_PARSED_TEMPLATE); RECORD(OPTIMIZE_PRAGMA_OPTIONS); RECORD(MSSTRUCT_PRAGMA_OPTIONS); RECORD(POINTERS_TO_MEMBERS_PRAGMA_OPTIONS); RECORD(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES); RECORD(DELETE_EXPRS_TO_ANALYZE); RECORD(CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH); RECORD(PP_CONDITIONAL_STACK); RECORD(DECLS_TO_CHECK_FOR_DEFERRED_DIAGS); RECORD(PP_ASSUME_NONNULL_LOC); RECORD(PP_UNSAFE_BUFFER_USAGE); RECORD(VTABLES_TO_EMIT); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); RECORD(SM_SLOC_FILE_ENTRY); RECORD(SM_SLOC_BUFFER_ENTRY); RECORD(SM_SLOC_BUFFER_BLOB); RECORD(SM_SLOC_BUFFER_BLOB_COMPRESSED); RECORD(SM_SLOC_EXPANSION_ENTRY); // Preprocessor Block. BLOCK(PREPROCESSOR_BLOCK); RECORD(PP_MACRO_DIRECTIVE_HISTORY); RECORD(PP_MACRO_FUNCTION_LIKE); RECORD(PP_MACRO_OBJECT_LIKE); RECORD(PP_MODULE_MACRO); RECORD(PP_TOKEN); // Submodule Block. BLOCK(SUBMODULE_BLOCK); RECORD(SUBMODULE_METADATA); RECORD(SUBMODULE_DEFINITION); RECORD(SUBMODULE_UMBRELLA_HEADER); RECORD(SUBMODULE_HEADER); RECORD(SUBMODULE_TOPHEADER); RECORD(SUBMODULE_UMBRELLA_DIR); RECORD(SUBMODULE_IMPORTS); RECORD(SUBMODULE_AFFECTING_MODULES); RECORD(SUBMODULE_EXPORTS); RECORD(SUBMODULE_REQUIRES); RECORD(SUBMODULE_EXCLUDED_HEADER); RECORD(SUBMODULE_LINK_LIBRARY); RECORD(SUBMODULE_CONFIG_MACRO); RECORD(SUBMODULE_CONFLICT); RECORD(SUBMODULE_PRIVATE_HEADER); RECORD(SUBMODULE_TEXTUAL_HEADER); RECORD(SUBMODULE_PRIVATE_TEXTUAL_HEADER); RECORD(SUBMODULE_INITIALIZERS); RECORD(SUBMODULE_EXPORT_AS); // Comments Block. BLOCK(COMMENTS_BLOCK); RECORD(COMMENTS_RAW_COMMENT); // Decls and Types block. BLOCK(DECLTYPES_BLOCK); RECORD(TYPE_EXT_QUAL); RECORD(TYPE_COMPLEX); RECORD(TYPE_POINTER); RECORD(TYPE_BLOCK_POINTER); RECORD(TYPE_LVALUE_REFERENCE); RECORD(TYPE_RVALUE_REFERENCE); RECORD(TYPE_MEMBER_POINTER); RECORD(TYPE_CONSTANT_ARRAY); RECORD(TYPE_INCOMPLETE_ARRAY); RECORD(TYPE_VARIABLE_ARRAY); RECORD(TYPE_VECTOR); RECORD(TYPE_EXT_VECTOR); RECORD(TYPE_FUNCTION_NO_PROTO); RECORD(TYPE_FUNCTION_PROTO); RECORD(TYPE_TYPEDEF); RECORD(TYPE_TYPEOF_EXPR); RECORD(TYPE_TYPEOF); RECORD(TYPE_RECORD); RECORD(TYPE_ENUM); RECORD(TYPE_OBJC_INTERFACE); RECORD(TYPE_OBJC_OBJECT_POINTER); RECORD(TYPE_DECLTYPE); RECORD(TYPE_ELABORATED); RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM); RECORD(TYPE_UNRESOLVED_USING); RECORD(TYPE_INJECTED_CLASS_NAME); RECORD(TYPE_OBJC_OBJECT); RECORD(TYPE_TEMPLATE_TYPE_PARM); RECORD(TYPE_TEMPLATE_SPECIALIZATION); RECORD(TYPE_DEPENDENT_NAME); RECORD(TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION); RECORD(TYPE_DEPENDENT_SIZED_ARRAY); RECORD(TYPE_PAREN); RECORD(TYPE_MACRO_QUALIFIED); RECORD(TYPE_PACK_EXPANSION); RECORD(TYPE_ATTRIBUTED); RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK); RECORD(TYPE_AUTO); RECORD(TYPE_UNARY_TRANSFORM); RECORD(TYPE_ATOMIC); RECORD(TYPE_DECAYED); RECORD(TYPE_ADJUSTED); RECORD(TYPE_OBJC_TYPE_PARAM); RECORD(LOCAL_REDECLARATIONS); RECORD(DECL_TYPEDEF); RECORD(DECL_TYPEALIAS); RECORD(DECL_ENUM); RECORD(DECL_RECORD); RECORD(DECL_ENUM_CONSTANT); RECORD(DECL_FUNCTION); RECORD(DECL_OBJC_METHOD); RECORD(DECL_OBJC_INTERFACE); RECORD(DECL_OBJC_PROTOCOL); RECORD(DECL_OBJC_IVAR); RECORD(DECL_OBJC_AT_DEFS_FIELD); RECORD(DECL_OBJC_CATEGORY); RECORD(DECL_OBJC_CATEGORY_IMPL); RECORD(DECL_OBJC_IMPLEMENTATION); RECORD(DECL_OBJC_COMPATIBLE_ALIAS); RECORD(DECL_OBJC_PROPERTY); RECORD(DECL_OBJC_PROPERTY_IMPL); RECORD(DECL_FIELD); RECORD(DECL_MS_PROPERTY); RECORD(DECL_VAR); RECORD(DECL_IMPLICIT_PARAM); RECORD(DECL_PARM_VAR); RECORD(DECL_FILE_SCOPE_ASM); RECORD(DECL_BLOCK); RECORD(DECL_CONTEXT_LEXICAL); RECORD(DECL_CONTEXT_VISIBLE); RECORD(DECL_NAMESPACE); RECORD(DECL_NAMESPACE_ALIAS); RECORD(DECL_USING); RECORD(DECL_USING_SHADOW); RECORD(DECL_USING_DIRECTIVE); RECORD(DECL_UNRESOLVED_USING_VALUE); RECORD(DECL_UNRESOLVED_USING_TYPENAME); RECORD(DECL_LINKAGE_SPEC); RECORD(DECL_EXPORT); RECORD(DECL_CXX_RECORD); RECORD(DECL_CXX_METHOD); RECORD(DECL_CXX_CONSTRUCTOR); RECORD(DECL_CXX_DESTRUCTOR); RECORD(DECL_CXX_CONVERSION); RECORD(DECL_ACCESS_SPEC); RECORD(DECL_FRIEND); RECORD(DECL_FRIEND_TEMPLATE); RECORD(DECL_CLASS_TEMPLATE); RECORD(DECL_CLASS_TEMPLATE_SPECIALIZATION); RECORD(DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION); RECORD(DECL_VAR_TEMPLATE); RECORD(DECL_VAR_TEMPLATE_SPECIALIZATION); RECORD(DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION); RECORD(DECL_FUNCTION_TEMPLATE); RECORD(DECL_TEMPLATE_TYPE_PARM); RECORD(DECL_NON_TYPE_TEMPLATE_PARM); RECORD(DECL_TEMPLATE_TEMPLATE_PARM); RECORD(DECL_CONCEPT); RECORD(DECL_REQUIRES_EXPR_BODY); RECORD(DECL_TYPE_ALIAS_TEMPLATE); RECORD(DECL_STATIC_ASSERT); RECORD(DECL_CXX_BASE_SPECIFIERS); RECORD(DECL_CXX_CTOR_INITIALIZERS); RECORD(DECL_INDIRECTFIELD); RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK); RECORD(DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK); RECORD(DECL_IMPORT); RECORD(DECL_OMP_THREADPRIVATE); RECORD(DECL_EMPTY); RECORD(DECL_OBJC_TYPE_PARAM); RECORD(DECL_OMP_CAPTUREDEXPR); RECORD(DECL_PRAGMA_COMMENT); RECORD(DECL_PRAGMA_DETECT_MISMATCH); RECORD(DECL_OMP_DECLARE_REDUCTION); RECORD(DECL_OMP_ALLOCATE); RECORD(DECL_HLSL_BUFFER); // Statements and Exprs can occur in the Decls and Types block. AddStmtsExprs(Stream, Record); BLOCK(PREPROCESSOR_DETAIL_BLOCK); RECORD(PPD_MACRO_EXPANSION); RECORD(PPD_MACRO_DEFINITION); RECORD(PPD_INCLUSION_DIRECTIVE); // Decls and Types block. BLOCK(EXTENSION_BLOCK); RECORD(EXTENSION_METADATA); BLOCK(UNHASHED_CONTROL_BLOCK); RECORD(SIGNATURE); RECORD(AST_BLOCK_HASH); RECORD(DIAGNOSTIC_OPTIONS); RECORD(HEADER_SEARCH_PATHS); RECORD(DIAG_PRAGMA_MAPPINGS); #undef RECORD #undef BLOCK Stream.ExitBlock(); } /// Prepares a path for being written to an AST file by converting it /// to an absolute path and removing nested './'s. /// /// \return \c true if the path was changed. static bool cleanPathForOutput(FileManager &FileMgr, SmallVectorImpl &Path) { bool Changed = FileMgr.makeAbsolutePath(Path); return Changed | llvm::sys::path::remove_dots(Path); } /// Adjusts the given filename to only write out the portion of the /// filename that is not part of the system root directory. /// /// \param Filename the file name to adjust. /// /// \param BaseDir When non-NULL, the PCH file is a relocatable AST file and /// the returned filename will be adjusted by this root directory. /// /// \returns either the original filename (if it needs no adjustment) or the /// adjusted filename (which points into the @p Filename parameter). static const char * adjustFilenameForRelocatableAST(const char *Filename, StringRef BaseDir) { assert(Filename && "No file name to adjust?"); if (BaseDir.empty()) return Filename; // Verify that the filename and the system root have the same prefix. unsigned Pos = 0; for (; Filename[Pos] && Pos < BaseDir.size(); ++Pos) if (Filename[Pos] != BaseDir[Pos]) return Filename; // Prefixes don't match. // We hit the end of the filename before we hit the end of the system root. if (!Filename[Pos]) return Filename; // If there's not a path separator at the end of the base directory nor // immediately after it, then this isn't within the base directory. if (!llvm::sys::path::is_separator(Filename[Pos])) { if (!llvm::sys::path::is_separator(BaseDir.back())) return Filename; } else { // If the file name has a '/' at the current position, skip over the '/'. // We distinguish relative paths from absolute paths by the // absence of '/' at the beginning of relative paths. // // FIXME: This is wrong. We distinguish them by asking if the path is // absolute, which isn't the same thing. And there might be multiple '/'s // in a row. Use a better mechanism to indicate whether we have emitted an // absolute or relative path. ++Pos; } return Filename + Pos; } std::pair ASTWriter::createSignature() const { StringRef AllBytes(Buffer.data(), Buffer.size()); llvm::SHA1 Hasher; Hasher.update(AllBytes.slice(ASTBlockRange.first, ASTBlockRange.second)); ASTFileSignature ASTBlockHash = ASTFileSignature::create(Hasher.result()); // Add the remaining bytes: // 1. Before the unhashed control block. Hasher.update(AllBytes.slice(0, UnhashedControlBlockRange.first)); // 2. Between the unhashed control block and the AST block. Hasher.update( AllBytes.slice(UnhashedControlBlockRange.second, ASTBlockRange.first)); // 3. After the AST block. Hasher.update(AllBytes.slice(ASTBlockRange.second, StringRef::npos)); ASTFileSignature Signature = ASTFileSignature::create(Hasher.result()); return std::make_pair(ASTBlockHash, Signature); } ASTFileSignature ASTWriter::createSignatureForNamedModule() const { llvm::SHA1 Hasher; Hasher.update(StringRef(Buffer.data(), Buffer.size())); assert(WritingModule); assert(WritingModule->isNamedModule()); // We need to combine all the export imported modules no matter // we used it or not. for (auto [ExportImported, _] : WritingModule->Exports) Hasher.update(ExportImported->Signature); // We combine all the used modules to make sure the signature is precise. // Consider the case like: // // // a.cppm // export module a; // export inline int a() { ... } // // // b.cppm // export module b; // import a; // export inline int b() { return a(); } // // Since both `a()` and `b()` are inline, we need to make sure the BMI of // `b.pcm` will change after the implementation of `a()` changes. We can't // get that naturally since we won't record the body of `a()` during the // writing process. We can't reuse ODRHash here since ODRHash won't calculate // the called function recursively. So ODRHash will be problematic if `a()` // calls other inline functions. // // Probably we can solve this by a new hash mechanism. But the safety and // efficiency may a problem too. Here we just combine the hash value of the // used modules conservatively. for (Module *M : TouchedTopLevelModules) Hasher.update(M->Signature); return ASTFileSignature::create(Hasher.result()); } static void BackpatchSignatureAt(llvm::BitstreamWriter &Stream, const ASTFileSignature &S, uint64_t BitNo) { for (uint8_t Byte : S) { Stream.BackpatchByte(BitNo, Byte); BitNo += 8; } } ASTFileSignature ASTWriter::backpatchSignature() { if (isWritingStdCXXNamedModules()) { ASTFileSignature Signature = createSignatureForNamedModule(); BackpatchSignatureAt(Stream, Signature, SignatureOffset); return Signature; } if (!WritingModule || !PP->getHeaderSearchInfo().getHeaderSearchOpts().ModulesHashContent) return {}; // For implicit modules, write the hash of the PCM as its signature. ASTFileSignature ASTBlockHash; ASTFileSignature Signature; std::tie(ASTBlockHash, Signature) = createSignature(); BackpatchSignatureAt(Stream, ASTBlockHash, ASTBlockHashOffset); BackpatchSignatureAt(Stream, Signature, SignatureOffset); return Signature; } void ASTWriter::writeUnhashedControlBlock(Preprocessor &PP, ASTContext &Context) { using namespace llvm; // Flush first to prepare the PCM hash (signature). Stream.FlushToWord(); UnhashedControlBlockRange.first = Stream.GetCurrentBitNo() >> 3; // Enter the block and prepare to write records. RecordData Record; Stream.EnterSubblock(UNHASHED_CONTROL_BLOCK_ID, 5); // For implicit modules and C++20 named modules, write the hash of the PCM as // its signature. if (isWritingStdCXXNamedModules() || (WritingModule && PP.getHeaderSearchInfo().getHeaderSearchOpts().ModulesHashContent)) { // At this point, we don't know the actual signature of the file or the AST // block - we're only able to compute those at the end of the serialization // process. Let's store dummy signatures for now, and replace them with the // real ones later on. // The bitstream VBR-encodes record elements, which makes backpatching them // really difficult. Let's store the signatures as blobs instead - they are // guaranteed to be word-aligned, and we control their format/encoding. auto Dummy = ASTFileSignature::createDummy(); SmallString<128> Blob{Dummy.begin(), Dummy.end()}; // We don't need AST Block hash in named modules. if (!isWritingStdCXXNamedModules()) { auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(AST_BLOCK_HASH)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned ASTBlockHashAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Record.push_back(AST_BLOCK_HASH); Stream.EmitRecordWithBlob(ASTBlockHashAbbrev, Record, Blob); ASTBlockHashOffset = Stream.GetCurrentBitNo() - Blob.size() * 8; Record.clear(); } auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SIGNATURE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned SignatureAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Record.push_back(SIGNATURE); Stream.EmitRecordWithBlob(SignatureAbbrev, Record, Blob); SignatureOffset = Stream.GetCurrentBitNo() - Blob.size() * 8; Record.clear(); } const auto &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); // Diagnostic options. const auto &Diags = Context.getDiagnostics(); const DiagnosticOptions &DiagOpts = Diags.getDiagnosticOptions(); if (!HSOpts.ModulesSkipDiagnosticOptions) { #define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name); #define ENUM_DIAGOPT(Name, Type, Bits, Default) \ Record.push_back(static_cast(DiagOpts.get##Name())); #include "clang/Basic/DiagnosticOptions.def" Record.push_back(DiagOpts.Warnings.size()); for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I) AddString(DiagOpts.Warnings[I], Record); Record.push_back(DiagOpts.Remarks.size()); for (unsigned I = 0, N = DiagOpts.Remarks.size(); I != N; ++I) AddString(DiagOpts.Remarks[I], Record); // Note: we don't serialize the log or serialization file names, because // they are generally transient files and will almost always be overridden. Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record); Record.clear(); } // Header search paths. if (!HSOpts.ModulesSkipHeaderSearchPaths) { // Include entries. Record.push_back(HSOpts.UserEntries.size()); for (unsigned I = 0, N = HSOpts.UserEntries.size(); I != N; ++I) { const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I]; AddString(Entry.Path, Record); Record.push_back(static_cast(Entry.Group)); Record.push_back(Entry.IsFramework); Record.push_back(Entry.IgnoreSysRoot); } // System header prefixes. Record.push_back(HSOpts.SystemHeaderPrefixes.size()); for (unsigned I = 0, N = HSOpts.SystemHeaderPrefixes.size(); I != N; ++I) { AddString(HSOpts.SystemHeaderPrefixes[I].Prefix, Record); Record.push_back(HSOpts.SystemHeaderPrefixes[I].IsSystemHeader); } // VFS overlay files. Record.push_back(HSOpts.VFSOverlayFiles.size()); for (StringRef VFSOverlayFile : HSOpts.VFSOverlayFiles) AddString(VFSOverlayFile, Record); Stream.EmitRecord(HEADER_SEARCH_PATHS, Record); } if (!HSOpts.ModulesSkipPragmaDiagnosticMappings) WritePragmaDiagnosticMappings(Diags, /* isModule = */ WritingModule); // Header search entry usage. { auto HSEntryUsage = PP.getHeaderSearchInfo().computeUserEntryUsage(); auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_ENTRY_USAGE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Number of bits. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Bit vector. unsigned HSUsageAbbrevCode = Stream.EmitAbbrev(std::move(Abbrev)); RecordData::value_type Record[] = {HEADER_SEARCH_ENTRY_USAGE, HSEntryUsage.size()}; Stream.EmitRecordWithBlob(HSUsageAbbrevCode, Record, bytes(HSEntryUsage)); } // VFS usage. { auto VFSUsage = PP.getHeaderSearchInfo().collectVFSUsageAndClear(); auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(VFS_USAGE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Number of bits. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Bit vector. unsigned VFSUsageAbbrevCode = Stream.EmitAbbrev(std::move(Abbrev)); RecordData::value_type Record[] = {VFS_USAGE, VFSUsage.size()}; Stream.EmitRecordWithBlob(VFSUsageAbbrevCode, Record, bytes(VFSUsage)); } // Leave the options block. Stream.ExitBlock(); UnhashedControlBlockRange.second = Stream.GetCurrentBitNo() >> 3; } /// Write the control block. void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, StringRef isysroot) { using namespace llvm; Stream.EnterSubblock(CONTROL_BLOCK_ID, 5); RecordData Record; // Metadata auto MetadataAbbrev = std::make_shared(); MetadataAbbrev->Add(BitCodeAbbrevOp(METADATA)); MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Major MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Minor MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang maj. MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang min. MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable // Standard C++ module MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Timestamps MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Errors MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag unsigned MetadataAbbrevCode = Stream.EmitAbbrev(std::move(MetadataAbbrev)); assert((!WritingModule || isysroot.empty()) && "writing module as a relocatable PCH?"); { RecordData::value_type Record[] = {METADATA, VERSION_MAJOR, VERSION_MINOR, CLANG_VERSION_MAJOR, CLANG_VERSION_MINOR, !isysroot.empty(), isWritingStdCXXNamedModules(), IncludeTimestamps, ASTHasCompilerErrors}; Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record, getClangFullRepositoryVersion()); } if (WritingModule) { // Module name auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev)); RecordData::value_type Record[] = {MODULE_NAME}; Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name); } if (WritingModule && WritingModule->Directory) { SmallString<128> BaseDir; if (PP.getHeaderSearchInfo().getHeaderSearchOpts().ModuleFileHomeIsCwd) { // Use the current working directory as the base path for all inputs. auto CWD = Context.getSourceManager().getFileManager().getOptionalDirectoryRef( "."); BaseDir.assign(CWD->getName()); } else { BaseDir.assign(WritingModule->Directory->getName()); } cleanPathForOutput(Context.getSourceManager().getFileManager(), BaseDir); // If the home of the module is the current working directory, then we // want to pick up the cwd of the build process loading the module, not // our cwd, when we load this module. if (!PP.getHeaderSearchInfo().getHeaderSearchOpts().ModuleFileHomeIsCwd && (!PP.getHeaderSearchInfo() .getHeaderSearchOpts() .ModuleMapFileHomeIsCwd || WritingModule->Directory->getName() != ".")) { // Module directory. auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(MODULE_DIRECTORY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Directory unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev)); RecordData::value_type Record[] = {MODULE_DIRECTORY}; Stream.EmitRecordWithBlob(AbbrevCode, Record, BaseDir); } // Write out all other paths relative to the base directory if possible. BaseDirectory.assign(BaseDir.begin(), BaseDir.end()); } else if (!isysroot.empty()) { // Write out paths relative to the sysroot if possible. BaseDirectory = std::string(isysroot); } // Module map file if (WritingModule && WritingModule->Kind == Module::ModuleMapModule) { Record.clear(); auto &Map = PP.getHeaderSearchInfo().getModuleMap(); AddPath(WritingModule->PresumedModuleMapFile.empty() ? Map.getModuleMapFileForUniquing(WritingModule) ->getNameAsRequested() : StringRef(WritingModule->PresumedModuleMapFile), Record); // Additional module map files. if (auto *AdditionalModMaps = Map.getAdditionalModuleMapFiles(WritingModule)) { Record.push_back(AdditionalModMaps->size()); SmallVector ModMaps(AdditionalModMaps->begin(), AdditionalModMaps->end()); llvm::sort(ModMaps, [](FileEntryRef A, FileEntryRef B) { return A.getName() < B.getName(); }); for (FileEntryRef F : ModMaps) AddPath(F.getName(), Record); } else { Record.push_back(0); } Stream.EmitRecord(MODULE_MAP_FILE, Record); } // Imports if (Chain) { serialization::ModuleManager &Mgr = Chain->getModuleManager(); Record.clear(); for (ModuleFile &M : Mgr) { // Skip modules that weren't directly imported. if (!M.isDirectlyImported()) continue; Record.push_back((unsigned)M.Kind); // FIXME: Stable encoding Record.push_back(M.StandardCXXModule); AddSourceLocation(M.ImportLoc, Record); // We don't want to hard code the information about imported modules // in the C++20 named modules. if (!M.StandardCXXModule) { // If we have calculated signature, there is no need to store // the size or timestamp. Record.push_back(M.Signature ? 0 : M.File.getSize()); Record.push_back(M.Signature ? 0 : getTimestampForOutput(M.File)); llvm::append_range(Record, M.Signature); } AddString(M.ModuleName, Record); if (!M.StandardCXXModule) AddPath(M.FileName, Record); } Stream.EmitRecord(IMPORTS, Record); } // Write the options block. Stream.EnterSubblock(OPTIONS_BLOCK_ID, 4); // Language options. Record.clear(); const LangOptions &LangOpts = Context.getLangOpts(); #define LANGOPT(Name, Bits, Default, Description) \ Record.push_back(LangOpts.Name); #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ Record.push_back(static_cast(LangOpts.get##Name())); #include "clang/Basic/LangOptions.def" #define SANITIZER(NAME, ID) \ Record.push_back(LangOpts.Sanitize.has(SanitizerKind::ID)); #include "clang/Basic/Sanitizers.def" Record.push_back(LangOpts.ModuleFeatures.size()); for (StringRef Feature : LangOpts.ModuleFeatures) AddString(Feature, Record); Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind()); AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record); AddString(LangOpts.CurrentModule, Record); // Comment options. Record.push_back(LangOpts.CommentOpts.BlockCommandNames.size()); for (const auto &I : LangOpts.CommentOpts.BlockCommandNames) { AddString(I, Record); } Record.push_back(LangOpts.CommentOpts.ParseAllComments); // OpenMP offloading options. Record.push_back(LangOpts.OMPTargetTriples.size()); for (auto &T : LangOpts.OMPTargetTriples) AddString(T.getTriple(), Record); AddString(LangOpts.OMPHostIRFile, Record); Stream.EmitRecord(LANGUAGE_OPTIONS, Record); // Target options. Record.clear(); const TargetInfo &Target = Context.getTargetInfo(); const TargetOptions &TargetOpts = Target.getTargetOpts(); AddString(TargetOpts.Triple, Record); AddString(TargetOpts.CPU, Record); AddString(TargetOpts.TuneCPU, Record); AddString(TargetOpts.ABI, Record); Record.push_back(TargetOpts.FeaturesAsWritten.size()); for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); I != N; ++I) { AddString(TargetOpts.FeaturesAsWritten[I], Record); } Record.push_back(TargetOpts.Features.size()); for (unsigned I = 0, N = TargetOpts.Features.size(); I != N; ++I) { AddString(TargetOpts.Features[I], Record); } Stream.EmitRecord(TARGET_OPTIONS, Record); // File system options. Record.clear(); const FileSystemOptions &FSOpts = Context.getSourceManager().getFileManager().getFileSystemOpts(); AddString(FSOpts.WorkingDir, Record); Stream.EmitRecord(FILE_SYSTEM_OPTIONS, Record); // Header search options. Record.clear(); const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); AddString(HSOpts.Sysroot, Record); AddString(HSOpts.ResourceDir, Record); AddString(HSOpts.ModuleCachePath, Record); AddString(HSOpts.ModuleUserBuildPath, Record); Record.push_back(HSOpts.DisableModuleHash); Record.push_back(HSOpts.ImplicitModuleMaps); Record.push_back(HSOpts.ModuleMapFileHomeIsCwd); Record.push_back(HSOpts.EnablePrebuiltImplicitModules); Record.push_back(HSOpts.UseBuiltinIncludes); Record.push_back(HSOpts.UseStandardSystemIncludes); Record.push_back(HSOpts.UseStandardCXXIncludes); Record.push_back(HSOpts.UseLibcxx); // Write out the specific module cache path that contains the module files. AddString(PP.getHeaderSearchInfo().getModuleCachePath(), Record); Stream.EmitRecord(HEADER_SEARCH_OPTIONS, Record); // Preprocessor options. Record.clear(); const PreprocessorOptions &PPOpts = PP.getPreprocessorOpts(); // If we're building an implicit module with a context hash, the importer is // guaranteed to have the same macros defined on the command line. Skip // writing them. bool SkipMacros = BuildingImplicitModule && !HSOpts.DisableModuleHash; bool WriteMacros = !SkipMacros; Record.push_back(WriteMacros); if (WriteMacros) { // Macro definitions. Record.push_back(PPOpts.Macros.size()); for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) { AddString(PPOpts.Macros[I].first, Record); Record.push_back(PPOpts.Macros[I].second); } } // Includes Record.push_back(PPOpts.Includes.size()); for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I) AddString(PPOpts.Includes[I], Record); // Macro includes Record.push_back(PPOpts.MacroIncludes.size()); for (unsigned I = 0, N = PPOpts.MacroIncludes.size(); I != N; ++I) AddString(PPOpts.MacroIncludes[I], Record); Record.push_back(PPOpts.UsePredefines); // Detailed record is important since it is used for the module cache hash. Record.push_back(PPOpts.DetailedRecord); AddString(PPOpts.ImplicitPCHInclude, Record); Record.push_back(static_cast(PPOpts.ObjCXXARCStandardLibrary)); Stream.EmitRecord(PREPROCESSOR_OPTIONS, Record); // Leave the options block. Stream.ExitBlock(); // Original file name and file ID SourceManager &SM = Context.getSourceManager(); if (auto MainFile = SM.getFileEntryRefForID(SM.getMainFileID())) { auto FileAbbrev = std::make_shared(); FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE)); FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // File ID FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name unsigned FileAbbrevCode = Stream.EmitAbbrev(std::move(FileAbbrev)); Record.clear(); Record.push_back(ORIGINAL_FILE); AddFileID(SM.getMainFileID(), Record); EmitRecordWithPath(FileAbbrevCode, Record, MainFile->getName()); } Record.clear(); AddFileID(SM.getMainFileID(), Record); Stream.EmitRecord(ORIGINAL_FILE_ID, Record); WriteInputFiles(Context.SourceMgr, PP.getHeaderSearchInfo().getHeaderSearchOpts()); Stream.ExitBlock(); } namespace { /// An input file. struct InputFileEntry { FileEntryRef File; bool IsSystemFile; bool IsTransient; bool BufferOverridden; bool IsTopLevel; bool IsModuleMap; uint32_t ContentHash[2]; InputFileEntry(FileEntryRef File) : File(File) {} }; } // namespace SourceLocation ASTWriter::getAffectingIncludeLoc(const SourceManager &SourceMgr, const SrcMgr::FileInfo &File) { SourceLocation IncludeLoc = File.getIncludeLoc(); if (IncludeLoc.isValid()) { FileID IncludeFID = SourceMgr.getFileID(IncludeLoc); assert(IncludeFID.isValid() && "IncludeLoc in invalid file"); if (!IsSLocAffecting[IncludeFID.ID]) IncludeLoc = SourceLocation(); } return IncludeLoc; } void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts) { using namespace llvm; Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4); // Create input-file abbreviation. auto IFAbbrev = std::make_shared(); IFAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE)); IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Transient IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Top-level IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Module map IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // Name as req. len IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name as req. + name unsigned IFAbbrevCode = Stream.EmitAbbrev(std::move(IFAbbrev)); // Create input file hash abbreviation. auto IFHAbbrev = std::make_shared(); IFHAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_HASH)); IFHAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); IFHAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); unsigned IFHAbbrevCode = Stream.EmitAbbrev(std::move(IFHAbbrev)); uint64_t InputFilesOffsetBase = Stream.GetCurrentBitNo(); // Get all ContentCache objects for files. std::vector UserFiles; std::vector SystemFiles; for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) { // Get this source location entry. const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I); assert(&SourceMgr.getSLocEntry(FileID::get(I)) == SLoc); // We only care about file entries that were not overridden. if (!SLoc->isFile()) continue; const SrcMgr::FileInfo &File = SLoc->getFile(); const SrcMgr::ContentCache *Cache = &File.getContentCache(); if (!Cache->OrigEntry) continue; // Do not emit input files that do not affect current module. if (!IsSLocAffecting[I]) continue; InputFileEntry Entry(*Cache->OrigEntry); Entry.IsSystemFile = isSystem(File.getFileCharacteristic()); Entry.IsTransient = Cache->IsTransient; Entry.BufferOverridden = Cache->BufferOverridden; Entry.IsTopLevel = getAffectingIncludeLoc(SourceMgr, File).isInvalid(); Entry.IsModuleMap = isModuleMap(File.getFileCharacteristic()); uint64_t ContentHash = 0; if (PP->getHeaderSearchInfo() .getHeaderSearchOpts() .ValidateASTInputFilesContent) { auto MemBuff = Cache->getBufferIfLoaded(); if (MemBuff) ContentHash = xxh3_64bits(MemBuff->getBuffer()); else PP->Diag(SourceLocation(), diag::err_module_unable_to_hash_content) << Entry.File.getName(); } Entry.ContentHash[0] = uint32_t(ContentHash); Entry.ContentHash[1] = uint32_t(ContentHash >> 32); if (Entry.IsSystemFile) SystemFiles.push_back(Entry); else UserFiles.push_back(Entry); } // User files go at the front, system files at the back. auto SortedFiles = llvm::concat(std::move(UserFiles), std::move(SystemFiles)); unsigned UserFilesNum = 0; // Write out all of the input files. std::vector InputFileOffsets; for (const auto &Entry : SortedFiles) { uint32_t &InputFileID = InputFileIDs[Entry.File]; if (InputFileID != 0) continue; // already recorded this file. // Record this entry's offset. InputFileOffsets.push_back(Stream.GetCurrentBitNo() - InputFilesOffsetBase); InputFileID = InputFileOffsets.size(); if (!Entry.IsSystemFile) ++UserFilesNum; // Emit size/modification time for this file. // And whether this file was overridden. { SmallString<128> NameAsRequested = Entry.File.getNameAsRequested(); SmallString<128> Name = Entry.File.getName(); PreparePathForOutput(NameAsRequested); PreparePathForOutput(Name); if (Name == NameAsRequested) Name.clear(); RecordData::value_type Record[] = { INPUT_FILE, InputFileOffsets.size(), (uint64_t)Entry.File.getSize(), (uint64_t)getTimestampForOutput(Entry.File), Entry.BufferOverridden, Entry.IsTransient, Entry.IsTopLevel, Entry.IsModuleMap, NameAsRequested.size()}; Stream.EmitRecordWithBlob(IFAbbrevCode, Record, (NameAsRequested + Name).str()); } // Emit content hash for this file. { RecordData::value_type Record[] = {INPUT_FILE_HASH, Entry.ContentHash[0], Entry.ContentHash[1]}; Stream.EmitRecordWithAbbrev(IFHAbbrevCode, Record); } } Stream.ExitBlock(); // Create input file offsets abbreviation. auto OffsetsAbbrev = std::make_shared(); OffsetsAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_OFFSETS)); OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # input files OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # non-system // input files OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Array unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(std::move(OffsetsAbbrev)); // Write input file offsets. RecordData::value_type Record[] = {INPUT_FILE_OFFSETS, InputFileOffsets.size(), UserFilesNum}; Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, bytes(InputFileOffsets)); } //===----------------------------------------------------------------------===// // Source Manager Serialization //===----------------------------------------------------------------------===// /// Create an abbreviation for the SLocEntry that refers to a /// file. static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { using namespace llvm; auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives // FileEntry fields. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Input File ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 24)); // FirstDeclIndex Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumDecls return Stream.EmitAbbrev(std::move(Abbrev)); } /// Create an abbreviation for the SLocEntry that refers to a /// buffer. static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) { using namespace llvm; auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob return Stream.EmitAbbrev(std::move(Abbrev)); } /// Create an abbreviation for the SLocEntry that refers to a /// buffer's blob. static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream, bool Compressed) { using namespace llvm; auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(Compressed ? SM_SLOC_BUFFER_BLOB_COMPRESSED : SM_SLOC_BUFFER_BLOB)); if (Compressed) Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Uncompressed size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob return Stream.EmitAbbrev(std::move(Abbrev)); } /// Create an abbreviation for the SLocEntry that refers to a macro /// expansion. static unsigned CreateSLocExpansionAbbrev(llvm::BitstreamWriter &Stream) { using namespace llvm; auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_EXPANSION_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Start location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // End location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Is token range Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Token length return Stream.EmitAbbrev(std::move(Abbrev)); } /// Emit key length and data length as ULEB-encoded data, and return them as a /// pair. static std::pair emitULEBKeyDataLength(unsigned KeyLen, unsigned DataLen, raw_ostream &Out) { llvm::encodeULEB128(KeyLen, Out); llvm::encodeULEB128(DataLen, Out); return std::make_pair(KeyLen, DataLen); } namespace { // Trait used for the on-disk hash table of header search information. class HeaderFileInfoTrait { ASTWriter &Writer; // Keep track of the framework names we've used during serialization. SmallString<128> FrameworkStringData; llvm::StringMap FrameworkNameOffset; public: HeaderFileInfoTrait(ASTWriter &Writer) : Writer(Writer) {} struct key_type { StringRef Filename; off_t Size; time_t ModTime; }; using key_type_ref = const key_type &; using UnresolvedModule = llvm::PointerIntPair; struct data_type { data_type(const HeaderFileInfo &HFI, bool AlreadyIncluded, ArrayRef KnownHeaders, UnresolvedModule Unresolved) : HFI(HFI), AlreadyIncluded(AlreadyIncluded), KnownHeaders(KnownHeaders), Unresolved(Unresolved) {} HeaderFileInfo HFI; bool AlreadyIncluded; SmallVector KnownHeaders; UnresolvedModule Unresolved; }; using data_type_ref = const data_type &; using hash_value_type = unsigned; using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref key) { // The hash is based only on size/time of the file, so that the reader can // match even when symlinking or excess path elements ("foo/../", "../") // change the form of the name. However, complete path is still the key. uint8_t buf[sizeof(key.Size) + sizeof(key.ModTime)]; memcpy(buf, &key.Size, sizeof(key.Size)); memcpy(buf + sizeof(key.Size), &key.ModTime, sizeof(key.ModTime)); return llvm::xxh3_64bits(buf); } std::pair EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) { unsigned KeyLen = key.Filename.size() + 1 + 8 + 8; unsigned DataLen = 1 + sizeof(IdentifierID) + 4; for (auto ModInfo : Data.KnownHeaders) if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule())) DataLen += 4; if (Data.Unresolved.getPointer()) DataLen += 4; return emitULEBKeyDataLength(KeyLen, DataLen, Out); } void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) { using namespace llvm::support; endian::Writer LE(Out, llvm::endianness::little); LE.write(key.Size); KeyLen -= 8; LE.write(key.ModTime); KeyLen -= 8; Out.write(key.Filename.data(), KeyLen); } void EmitData(raw_ostream &Out, key_type_ref key, data_type_ref Data, unsigned DataLen) { using namespace llvm::support; endian::Writer LE(Out, llvm::endianness::little); uint64_t Start = Out.tell(); (void)Start; unsigned char Flags = (Data.AlreadyIncluded << 6) | (Data.HFI.isImport << 5) | (Writer.isWritingStdCXXNamedModules() ? 0 : Data.HFI.isPragmaOnce << 4) | (Data.HFI.DirInfo << 1) | Data.HFI.IndexHeaderMapHeader; LE.write(Flags); if (Data.HFI.LazyControllingMacro.isID()) LE.write(Data.HFI.LazyControllingMacro.getID()); else LE.write( Writer.getIdentifierRef(Data.HFI.LazyControllingMacro.getPtr())); unsigned Offset = 0; if (!Data.HFI.Framework.empty()) { // If this header refers into a framework, save the framework name. llvm::StringMap::iterator Pos = FrameworkNameOffset.find(Data.HFI.Framework); if (Pos == FrameworkNameOffset.end()) { Offset = FrameworkStringData.size() + 1; FrameworkStringData.append(Data.HFI.Framework); FrameworkStringData.push_back(0); FrameworkNameOffset[Data.HFI.Framework] = Offset; } else Offset = Pos->second; } LE.write(Offset); auto EmitModule = [&](Module *M, ModuleMap::ModuleHeaderRole Role) { if (uint32_t ModID = Writer.getLocalOrImportedSubmoduleID(M)) { uint32_t Value = (ModID << 3) | (unsigned)Role; assert((Value >> 3) == ModID && "overflow in header module info"); LE.write(Value); } }; for (auto ModInfo : Data.KnownHeaders) EmitModule(ModInfo.getModule(), ModInfo.getRole()); if (Data.Unresolved.getPointer()) EmitModule(Data.Unresolved.getPointer(), Data.Unresolved.getInt()); assert(Out.tell() - Start == DataLen && "Wrong data length"); } const char *strings_begin() const { return FrameworkStringData.begin(); } const char *strings_end() const { return FrameworkStringData.end(); } }; } // namespace /// Write the header search block for the list of files that /// /// \param HS The header search structure to save. void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { HeaderFileInfoTrait GeneratorTrait(*this); llvm::OnDiskChainedHashTableGenerator Generator; SmallVector SavedStrings; unsigned NumHeaderSearchEntries = 0; // Find all unresolved headers for the current module. We generally will // have resolved them before we get here, but not necessarily: we might be // compiling a preprocessed module, where there is no requirement for the // original files to exist any more. const HeaderFileInfo Empty; // So we can take a reference. if (WritingModule) { llvm::SmallVector Worklist(1, WritingModule); while (!Worklist.empty()) { Module *M = Worklist.pop_back_val(); // We don't care about headers in unimportable submodules. if (M->isUnimportable()) continue; // Map to disk files where possible, to pick up any missing stat // information. This also means we don't need to check the unresolved // headers list when emitting resolved headers in the first loop below. // FIXME: It'd be preferable to avoid doing this if we were given // sufficient stat information in the module map. HS.getModuleMap().resolveHeaderDirectives(M, /*File=*/std::nullopt); // If the file didn't exist, we can still create a module if we were given // enough information in the module map. for (const auto &U : M->MissingHeaders) { // Check that we were given enough information to build a module // without this file existing on disk. if (!U.Size || (!U.ModTime && IncludeTimestamps)) { PP->Diag(U.FileNameLoc, diag::err_module_no_size_mtime_for_header) << WritingModule->getFullModuleName() << U.Size.has_value() << U.FileName; continue; } // Form the effective relative pathname for the file. SmallString<128> Filename(M->Directory->getName()); llvm::sys::path::append(Filename, U.FileName); PreparePathForOutput(Filename); StringRef FilenameDup = strdup(Filename.c_str()); SavedStrings.push_back(FilenameDup.data()); HeaderFileInfoTrait::key_type Key = { FilenameDup, *U.Size, IncludeTimestamps ? *U.ModTime : 0}; HeaderFileInfoTrait::data_type Data = { Empty, false, {}, {M, ModuleMap::headerKindToRole(U.Kind)}}; // FIXME: Deal with cases where there are multiple unresolved header // directives in different submodules for the same header. Generator.insert(Key, Data, GeneratorTrait); ++NumHeaderSearchEntries; } auto SubmodulesRange = M->submodules(); Worklist.append(SubmodulesRange.begin(), SubmodulesRange.end()); } } SmallVector FilesByUID; HS.getFileMgr().GetUniqueIDMapping(FilesByUID); if (FilesByUID.size() > HS.header_file_size()) FilesByUID.resize(HS.header_file_size()); for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) { OptionalFileEntryRef File = FilesByUID[UID]; if (!File) continue; const HeaderFileInfo *HFI = HS.getExistingLocalFileInfo(*File); if (!HFI) continue; // We have no information on this being a header file. if (!HFI->isCompilingModuleHeader && HFI->isModuleHeader) continue; // Header file info is tracked by the owning module file. if (!HFI->isCompilingModuleHeader && !PP->alreadyIncluded(*File)) continue; // Non-modular header not included is not needed. // Massage the file path into an appropriate form. StringRef Filename = File->getName(); SmallString<128> FilenameTmp(Filename); if (PreparePathForOutput(FilenameTmp)) { // If we performed any translation on the file name at all, we need to // save this string, since the generator will refer to it later. Filename = StringRef(strdup(FilenameTmp.c_str())); SavedStrings.push_back(Filename.data()); } bool Included = PP->alreadyIncluded(*File); HeaderFileInfoTrait::key_type Key = { Filename, File->getSize(), getTimestampForOutput(*File) }; HeaderFileInfoTrait::data_type Data = { *HFI, Included, HS.getModuleMap().findResolvedModulesForHeader(*File), {} }; Generator.insert(Key, Data, GeneratorTrait); ++NumHeaderSearchEntries; } // Create the on-disk hash table in a buffer. SmallString<4096> TableData; uint32_t BucketOffset; { using namespace llvm::support; llvm::raw_svector_ostream Out(TableData); // Make sure that no bucket is at offset 0 endian::write(Out, 0, llvm::endianness::little); BucketOffset = Generator.Emit(Out, GeneratorTrait); } // Create a blob abbreviation using namespace llvm; auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_TABLE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned TableAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); // Write the header search table RecordData::value_type Record[] = {HEADER_SEARCH_TABLE, BucketOffset, NumHeaderSearchEntries, TableData.size()}; TableData.append(GeneratorTrait.strings_begin(),GeneratorTrait.strings_end()); Stream.EmitRecordWithBlob(TableAbbrev, Record, TableData); // Free all of the strings we had to duplicate. for (unsigned I = 0, N = SavedStrings.size(); I != N; ++I) free(const_cast(SavedStrings[I])); } static void emitBlob(llvm::BitstreamWriter &Stream, StringRef Blob, unsigned SLocBufferBlobCompressedAbbrv, unsigned SLocBufferBlobAbbrv) { using RecordDataType = ASTWriter::RecordData::value_type; // Compress the buffer if possible. We expect that almost all PCM // consumers will not want its contents. SmallVector CompressedBuffer; if (llvm::compression::zstd::isAvailable()) { llvm::compression::zstd::compress( llvm::arrayRefFromStringRef(Blob.drop_back(1)), CompressedBuffer, 9); RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, Blob.size() - 1}; Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record, llvm::toStringRef(CompressedBuffer)); return; } if (llvm::compression::zlib::isAvailable()) { llvm::compression::zlib::compress( llvm::arrayRefFromStringRef(Blob.drop_back(1)), CompressedBuffer); RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, Blob.size() - 1}; Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record, llvm::toStringRef(CompressedBuffer)); return; } RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB}; Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, Blob); } /// Writes the block containing the serialized form of the /// source manager. /// /// TODO: We should probably use an on-disk hash table (stored in a /// blob), indexed based on the file name, so that we only create /// entries for files that we actually need. In the common case (no /// errors), we probably won't have to create file entries for any of /// the files in the AST. void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, const Preprocessor &PP) { RecordData Record; // Enter the source manager block. Stream.EnterSubblock(SOURCE_MANAGER_BLOCK_ID, 4); const uint64_t SourceManagerBlockOffset = Stream.GetCurrentBitNo(); // Abbreviations for the various kinds of source-location entries. unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream); unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream); unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream, false); unsigned SLocBufferBlobCompressedAbbrv = CreateSLocBufferBlobAbbrev(Stream, true); unsigned SLocExpansionAbbrv = CreateSLocExpansionAbbrev(Stream); // Write out the source location entry table. We skip the first // entry, which is always the same dummy entry. std::vector SLocEntryOffsets; uint64_t SLocEntryOffsetsBase = Stream.GetCurrentBitNo(); SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1); for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) { // Get this source location entry. const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I); FileID FID = FileID::get(I); assert(&SourceMgr.getSLocEntry(FID) == SLoc); // Record the offset of this source-location entry. uint64_t Offset = Stream.GetCurrentBitNo() - SLocEntryOffsetsBase; assert((Offset >> 32) == 0 && "SLocEntry offset too large"); // Figure out which record code to use. unsigned Code; if (SLoc->isFile()) { const SrcMgr::ContentCache *Cache = &SLoc->getFile().getContentCache(); if (Cache->OrigEntry) { Code = SM_SLOC_FILE_ENTRY; } else Code = SM_SLOC_BUFFER_ENTRY; } else Code = SM_SLOC_EXPANSION_ENTRY; Record.clear(); Record.push_back(Code); if (SLoc->isFile()) { const SrcMgr::FileInfo &File = SLoc->getFile(); const SrcMgr::ContentCache *Content = &File.getContentCache(); // Do not emit files that were not listed as inputs. if (!IsSLocAffecting[I]) continue; SLocEntryOffsets.push_back(Offset); // Starting offset of this entry within this module, so skip the dummy. Record.push_back(getAdjustedOffset(SLoc->getOffset()) - 2); AddSourceLocation(getAffectingIncludeLoc(SourceMgr, File), Record); Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding Record.push_back(File.hasLineDirectives()); bool EmitBlob = false; if (Content->OrigEntry) { assert(Content->OrigEntry == Content->ContentsEntry && "Writing to AST an overridden file is not supported"); // The source location entry is a file. Emit input file ID. assert(InputFileIDs[*Content->OrigEntry] != 0 && "Missed file entry"); Record.push_back(InputFileIDs[*Content->OrigEntry]); Record.push_back(getAdjustedNumCreatedFIDs(FID)); FileDeclIDsTy::iterator FDI = FileDeclIDs.find(FID); if (FDI != FileDeclIDs.end()) { Record.push_back(FDI->second->FirstDeclIndex); Record.push_back(FDI->second->DeclIDs.size()); } else { Record.push_back(0); Record.push_back(0); } Stream.EmitRecordWithAbbrev(SLocFileAbbrv, Record); if (Content->BufferOverridden || Content->IsTransient) EmitBlob = true; } else { // The source location entry is a buffer. The blob associated // with this entry contains the contents of the buffer. // We add one to the size so that we capture the trailing NULL // that is required by llvm::MemoryBuffer::getMemBuffer (on // the reader side). std::optional Buffer = Content->getBufferOrNone(PP.getDiagnostics(), PP.getFileManager()); StringRef Name = Buffer ? Buffer->getBufferIdentifier() : ""; Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, StringRef(Name.data(), Name.size() + 1)); EmitBlob = true; } if (EmitBlob) { // Include the implicit terminating null character in the on-disk buffer // if we're writing it uncompressed. std::optional Buffer = Content->getBufferOrNone(PP.getDiagnostics(), PP.getFileManager()); if (!Buffer) Buffer = llvm::MemoryBufferRef("<<>>", ""); StringRef Blob(Buffer->getBufferStart(), Buffer->getBufferSize() + 1); emitBlob(Stream, Blob, SLocBufferBlobCompressedAbbrv, SLocBufferBlobAbbrv); } } else { // The source location entry is a macro expansion. const SrcMgr::ExpansionInfo &Expansion = SLoc->getExpansion(); SLocEntryOffsets.push_back(Offset); // Starting offset of this entry within this module, so skip the dummy. Record.push_back(getAdjustedOffset(SLoc->getOffset()) - 2); LocSeq::State Seq; AddSourceLocation(Expansion.getSpellingLoc(), Record, Seq); AddSourceLocation(Expansion.getExpansionLocStart(), Record, Seq); AddSourceLocation(Expansion.isMacroArgExpansion() ? SourceLocation() : Expansion.getExpansionLocEnd(), Record, Seq); Record.push_back(Expansion.isExpansionTokenRange()); // Compute the token length for this macro expansion. SourceLocation::UIntTy NextOffset = SourceMgr.getNextLocalOffset(); if (I + 1 != N) NextOffset = SourceMgr.getLocalSLocEntry(I + 1).getOffset(); Record.push_back(getAdjustedOffset(NextOffset - SLoc->getOffset()) - 1); Stream.EmitRecordWithAbbrev(SLocExpansionAbbrv, Record); } } Stream.ExitBlock(); if (SLocEntryOffsets.empty()) return; // Write the source-location offsets table into the AST block. This // table is used for lazily loading source-location information. using namespace llvm; auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SOURCE_LOCATION_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // total size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // base offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); { RecordData::value_type Record[] = { SOURCE_LOCATION_OFFSETS, SLocEntryOffsets.size(), getAdjustedOffset(SourceMgr.getNextLocalOffset()) - 1 /* skip dummy */, SLocEntryOffsetsBase - SourceManagerBlockOffset}; Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, bytes(SLocEntryOffsets)); } // Write the line table. It depends on remapping working, so it must come // after the source location offsets. if (SourceMgr.hasLineTable()) { LineTableInfo &LineTable = SourceMgr.getLineTable(); Record.clear(); // Emit the needed file names. llvm::DenseMap FilenameMap; FilenameMap[-1] = -1; // For unspecified filenames. for (const auto &L : LineTable) { if (L.first.ID < 0) continue; for (auto &LE : L.second) { if (FilenameMap.insert(std::make_pair(LE.FilenameID, FilenameMap.size() - 1)).second) AddPath(LineTable.getFilename(LE.FilenameID), Record); } } Record.push_back(0); // Emit the line entries for (const auto &L : LineTable) { // Only emit entries for local files. if (L.first.ID < 0) continue; AddFileID(L.first, Record); // Emit the line entries Record.push_back(L.second.size()); for (const auto &LE : L.second) { Record.push_back(LE.FileOffset); Record.push_back(LE.LineNo); Record.push_back(FilenameMap[LE.FilenameID]); Record.push_back((unsigned)LE.FileKind); Record.push_back(LE.IncludeOffset); } } Stream.EmitRecord(SOURCE_MANAGER_LINE_TABLE, Record); } } //===----------------------------------------------------------------------===// // Preprocessor Serialization //===----------------------------------------------------------------------===// static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule, const Preprocessor &PP) { if (MacroInfo *MI = MD->getMacroInfo()) if (MI->isBuiltinMacro()) return true; if (IsModule) { SourceLocation Loc = MD->getLocation(); if (Loc.isInvalid()) return true; if (PP.getSourceManager().getFileID(Loc) == PP.getPredefinesFileID()) return true; } return false; } /// Writes the block containing the serialized form of the /// preprocessor. void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { uint64_t MacroOffsetsBase = Stream.GetCurrentBitNo(); PreprocessingRecord *PPRec = PP.getPreprocessingRecord(); if (PPRec) WritePreprocessorDetail(*PPRec, MacroOffsetsBase); RecordData Record; RecordData ModuleMacroRecord; // If the preprocessor __COUNTER__ value has been bumped, remember it. if (PP.getCounterValue() != 0) { RecordData::value_type Record[] = {PP.getCounterValue()}; Stream.EmitRecord(PP_COUNTER_VALUE, Record); } // If we have a recorded #pragma assume_nonnull, remember it so it can be // replayed when the preamble terminates into the main file. SourceLocation AssumeNonNullLoc = PP.getPreambleRecordedPragmaAssumeNonNullLoc(); if (AssumeNonNullLoc.isValid()) { assert(PP.isRecordingPreamble()); AddSourceLocation(AssumeNonNullLoc, Record); Stream.EmitRecord(PP_ASSUME_NONNULL_LOC, Record); Record.clear(); } if (PP.isRecordingPreamble() && PP.hasRecordedPreamble()) { assert(!IsModule); auto SkipInfo = PP.getPreambleSkipInfo(); if (SkipInfo) { Record.push_back(true); AddSourceLocation(SkipInfo->HashTokenLoc, Record); AddSourceLocation(SkipInfo->IfTokenLoc, Record); Record.push_back(SkipInfo->FoundNonSkipPortion); Record.push_back(SkipInfo->FoundElse); AddSourceLocation(SkipInfo->ElseLoc, Record); } else { Record.push_back(false); } for (const auto &Cond : PP.getPreambleConditionalStack()) { AddSourceLocation(Cond.IfLoc, Record); Record.push_back(Cond.WasSkipping); Record.push_back(Cond.FoundNonSkip); Record.push_back(Cond.FoundElse); } Stream.EmitRecord(PP_CONDITIONAL_STACK, Record); Record.clear(); } // Write the safe buffer opt-out region map in PP for (SourceLocation &S : PP.serializeSafeBufferOptOutMap()) AddSourceLocation(S, Record); Stream.EmitRecord(PP_UNSAFE_BUFFER_USAGE, Record); Record.clear(); // Enter the preprocessor block. Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3); // If the AST file contains __DATE__ or __TIME__ emit a warning about this. // FIXME: Include a location for the use, and say which one was used. if (PP.SawDateOrTime()) PP.Diag(SourceLocation(), diag::warn_module_uses_date_time) << IsModule; // Loop over all the macro directives that are live at the end of the file, // emitting each to the PP section. // Construct the list of identifiers with macro directives that need to be // serialized. SmallVector MacroIdentifiers; // It is meaningless to emit macros for named modules. It only wastes times // and spaces. if (!isWritingStdCXXNamedModules()) for (auto &Id : PP.getIdentifierTable()) if (Id.second->hadMacroDefinition() && (!Id.second->isFromAST() || Id.second->hasChangedSinceDeserialization())) MacroIdentifiers.push_back(Id.second); // Sort the set of macro definitions that need to be serialized by the // name of the macro, to provide a stable ordering. llvm::sort(MacroIdentifiers, llvm::deref>()); // Emit the macro directives as a list and associate the offset with the // identifier they belong to. for (const IdentifierInfo *Name : MacroIdentifiers) { MacroDirective *MD = PP.getLocalMacroDirectiveHistory(Name); uint64_t StartOffset = Stream.GetCurrentBitNo() - MacroOffsetsBase; assert((StartOffset >> 32) == 0 && "Macro identifiers offset too large"); // Write out any exported module macros. bool EmittedModuleMacros = false; // C+=20 Header Units are compiled module interfaces, but they preserve // macros that are live (i.e. have a defined value) at the end of the // compilation. So when writing a header unit, we preserve only the final // value of each macro (and discard any that are undefined). Header units // do not have sub-modules (although they might import other header units). // PCH files, conversely, retain the history of each macro's define/undef // and of leaf macros in sub modules. if (IsModule && WritingModule->isHeaderUnit()) { // This is for the main TU when it is a C++20 header unit. // We preserve the final state of defined macros, and we do not emit ones // that are undefined. if (!MD || shouldIgnoreMacro(MD, IsModule, PP) || MD->getKind() == MacroDirective::MD_Undefine) continue; AddSourceLocation(MD->getLocation(), Record); Record.push_back(MD->getKind()); if (auto *DefMD = dyn_cast(MD)) { Record.push_back(getMacroRef(DefMD->getInfo(), Name)); } else if (auto *VisMD = dyn_cast(MD)) { Record.push_back(VisMD->isPublic()); } ModuleMacroRecord.push_back(getSubmoduleID(WritingModule)); ModuleMacroRecord.push_back(getMacroRef(MD->getMacroInfo(), Name)); Stream.EmitRecord(PP_MODULE_MACRO, ModuleMacroRecord); ModuleMacroRecord.clear(); EmittedModuleMacros = true; } else { // Emit the macro directives in reverse source order. for (; MD; MD = MD->getPrevious()) { // Once we hit an ignored macro, we're done: the rest of the chain // will all be ignored macros. if (shouldIgnoreMacro(MD, IsModule, PP)) break; AddSourceLocation(MD->getLocation(), Record); Record.push_back(MD->getKind()); if (auto *DefMD = dyn_cast(MD)) { Record.push_back(getMacroRef(DefMD->getInfo(), Name)); } else if (auto *VisMD = dyn_cast(MD)) { Record.push_back(VisMD->isPublic()); } } // We write out exported module macros for PCH as well. auto Leafs = PP.getLeafModuleMacros(Name); SmallVector Worklist(Leafs.begin(), Leafs.end()); llvm::DenseMap Visits; while (!Worklist.empty()) { auto *Macro = Worklist.pop_back_val(); // Emit a record indicating this submodule exports this macro. ModuleMacroRecord.push_back(getSubmoduleID(Macro->getOwningModule())); ModuleMacroRecord.push_back(getMacroRef(Macro->getMacroInfo(), Name)); for (auto *M : Macro->overrides()) ModuleMacroRecord.push_back(getSubmoduleID(M->getOwningModule())); Stream.EmitRecord(PP_MODULE_MACRO, ModuleMacroRecord); ModuleMacroRecord.clear(); // Enqueue overridden macros once we've visited all their ancestors. for (auto *M : Macro->overrides()) if (++Visits[M] == M->getNumOverridingMacros()) Worklist.push_back(M); EmittedModuleMacros = true; } } if (Record.empty() && !EmittedModuleMacros) continue; IdentMacroDirectivesOffsetMap[Name] = StartOffset; Stream.EmitRecord(PP_MACRO_DIRECTIVE_HISTORY, Record); Record.clear(); } /// Offsets of each of the macros into the bitstream, indexed by /// the local macro ID /// /// For each identifier that is associated with a macro, this map /// provides the offset into the bitstream where that macro is /// defined. std::vector MacroOffsets; for (unsigned I = 0, N = MacroInfosToEmit.size(); I != N; ++I) { const IdentifierInfo *Name = MacroInfosToEmit[I].Name; MacroInfo *MI = MacroInfosToEmit[I].MI; MacroID ID = MacroInfosToEmit[I].ID; if (ID < FirstMacroID) { assert(0 && "Loaded MacroInfo entered MacroInfosToEmit ?"); continue; } // Record the local offset of this macro. unsigned Index = ID - FirstMacroID; if (Index >= MacroOffsets.size()) MacroOffsets.resize(Index + 1); uint64_t Offset = Stream.GetCurrentBitNo() - MacroOffsetsBase; assert((Offset >> 32) == 0 && "Macro offset too large"); MacroOffsets[Index] = Offset; AddIdentifierRef(Name, Record); AddSourceLocation(MI->getDefinitionLoc(), Record); AddSourceLocation(MI->getDefinitionEndLoc(), Record); Record.push_back(MI->isUsed()); Record.push_back(MI->isUsedForHeaderGuard()); Record.push_back(MI->getNumTokens()); unsigned Code; if (MI->isObjectLike()) { Code = PP_MACRO_OBJECT_LIKE; } else { Code = PP_MACRO_FUNCTION_LIKE; Record.push_back(MI->isC99Varargs()); Record.push_back(MI->isGNUVarargs()); Record.push_back(MI->hasCommaPasting()); Record.push_back(MI->getNumParams()); for (const IdentifierInfo *Param : MI->params()) AddIdentifierRef(Param, Record); } // If we have a detailed preprocessing record, record the macro definition // ID that corresponds to this macro. if (PPRec) Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]); Stream.EmitRecord(Code, Record); Record.clear(); // Emit the tokens array. for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) { // Note that we know that the preprocessor does not have any annotation // tokens in it because they are created by the parser, and thus can't // be in a macro definition. const Token &Tok = MI->getReplacementToken(TokNo); AddToken(Tok, Record); Stream.EmitRecord(PP_TOKEN, Record); Record.clear(); } ++NumMacros; } Stream.ExitBlock(); // Write the offsets table for macro IDs. using namespace llvm; auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // base offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned MacroOffsetAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); { RecordData::value_type Record[] = {MACRO_OFFSET, MacroOffsets.size(), FirstMacroID - NUM_PREDEF_MACRO_IDS, MacroOffsetsBase - ASTBlockStartOffset}; Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record, bytes(MacroOffsets)); } } void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec, uint64_t MacroOffsetsBase) { if (PPRec.local_begin() == PPRec.local_end()) return; SmallVector PreprocessedEntityOffsets; // Enter the preprocessor block. Stream.EnterSubblock(PREPROCESSOR_DETAIL_BLOCK_ID, 3); // If the preprocessor has a preprocessing record, emit it. unsigned NumPreprocessingRecords = 0; using namespace llvm; // Set up the abbreviation for unsigned InclusionAbbrev = 0; { auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(PPD_INCLUSION_DIRECTIVE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // imported module Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); InclusionAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); } unsigned FirstPreprocessorEntityID = (Chain ? PPRec.getNumLoadedPreprocessedEntities() : 0) + NUM_PREDEF_PP_ENTITY_IDS; unsigned NextPreprocessorEntityID = FirstPreprocessorEntityID; RecordData Record; for (PreprocessingRecord::iterator E = PPRec.local_begin(), EEnd = PPRec.local_end(); E != EEnd; (void)++E, ++NumPreprocessingRecords, ++NextPreprocessorEntityID) { Record.clear(); uint64_t Offset = Stream.GetCurrentBitNo() - MacroOffsetsBase; assert((Offset >> 32) == 0 && "Preprocessed entity offset too large"); SourceRange R = getAdjustedRange((*E)->getSourceRange()); PreprocessedEntityOffsets.emplace_back( getRawSourceLocationEncoding(R.getBegin()), getRawSourceLocationEncoding(R.getEnd()), Offset); if (auto *MD = dyn_cast(*E)) { // Record this macro definition's ID. MacroDefinitions[MD] = NextPreprocessorEntityID; AddIdentifierRef(MD->getName(), Record); Stream.EmitRecord(PPD_MACRO_DEFINITION, Record); continue; } if (auto *ME = dyn_cast(*E)) { Record.push_back(ME->isBuiltinMacro()); if (ME->isBuiltinMacro()) AddIdentifierRef(ME->getName(), Record); else Record.push_back(MacroDefinitions[ME->getDefinition()]); Stream.EmitRecord(PPD_MACRO_EXPANSION, Record); continue; } if (auto *ID = dyn_cast(*E)) { Record.push_back(PPD_INCLUSION_DIRECTIVE); Record.push_back(ID->getFileName().size()); Record.push_back(ID->wasInQuotes()); Record.push_back(static_cast(ID->getKind())); Record.push_back(ID->importedModule()); SmallString<64> Buffer; Buffer += ID->getFileName(); // Check that the FileEntry is not null because it was not resolved and // we create a PCH even with compiler errors. if (ID->getFile()) Buffer += ID->getFile()->getName(); Stream.EmitRecordWithBlob(InclusionAbbrev, Record, Buffer); continue; } llvm_unreachable("Unhandled PreprocessedEntity in ASTWriter"); } Stream.ExitBlock(); // Write the offsets table for the preprocessing record. if (NumPreprocessingRecords > 0) { assert(PreprocessedEntityOffsets.size() == NumPreprocessingRecords); // Write the offsets table for identifier IDs. using namespace llvm; auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(PPD_ENTITIES_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first pp entity Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned PPEOffsetAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); RecordData::value_type Record[] = {PPD_ENTITIES_OFFSETS, FirstPreprocessorEntityID - NUM_PREDEF_PP_ENTITY_IDS}; Stream.EmitRecordWithBlob(PPEOffsetAbbrev, Record, bytes(PreprocessedEntityOffsets)); } // Write the skipped region table for the preprocessing record. ArrayRef SkippedRanges = PPRec.getSkippedRanges(); if (SkippedRanges.size() > 0) { std::vector SerializedSkippedRanges; SerializedSkippedRanges.reserve(SkippedRanges.size()); for (auto const& Range : SkippedRanges) SerializedSkippedRanges.emplace_back( getRawSourceLocationEncoding(Range.getBegin()), getRawSourceLocationEncoding(Range.getEnd())); using namespace llvm; auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(PPD_SKIPPED_RANGES)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned PPESkippedRangeAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Record.clear(); Record.push_back(PPD_SKIPPED_RANGES); Stream.EmitRecordWithBlob(PPESkippedRangeAbbrev, Record, bytes(SerializedSkippedRanges)); } } unsigned ASTWriter::getLocalOrImportedSubmoduleID(const Module *Mod) { if (!Mod) return 0; auto Known = SubmoduleIDs.find(Mod); if (Known != SubmoduleIDs.end()) return Known->second; auto *Top = Mod->getTopLevelModule(); if (Top != WritingModule && (getLangOpts().CompilingPCH || !Top->fullModuleNameIs(StringRef(getLangOpts().CurrentModule)))) return 0; return SubmoduleIDs[Mod] = NextSubmoduleID++; } unsigned ASTWriter::getSubmoduleID(Module *Mod) { unsigned ID = getLocalOrImportedSubmoduleID(Mod); // FIXME: This can easily happen, if we have a reference to a submodule that // did not result in us loading a module file for that submodule. For // instance, a cross-top-level-module 'conflict' declaration will hit this. // assert((ID || !Mod) && // "asked for module ID for non-local, non-imported module"); return ID; } /// Compute the number of modules within the given tree (including the /// given module). static unsigned getNumberOfModules(Module *Mod) { unsigned ChildModules = 0; for (auto *Submodule : Mod->submodules()) ChildModules += getNumberOfModules(Submodule); return ChildModules + 1; } void ASTWriter::WriteSubmodules(Module *WritingModule) { // Enter the submodule description block. Stream.EnterSubblock(SUBMODULE_BLOCK_ID, /*bits for abbreviations*/5); // Write the abbreviations needed for the submodules block. using namespace llvm; auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // Kind Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Definition location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExternC Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ModuleMapIsPriv... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // NamedModuleHasN... Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned DefinitionAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_HEADER)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned UmbrellaAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_HEADER)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned HeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TOPHEADER)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned TopHeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_REQUIRES)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // State Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature unsigned RequiresAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXCLUDED_HEADER)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TEXTUAL_HEADER)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned TextualHeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_PRIVATE_HEADER)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned PrivateHeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_PRIVATE_TEXTUAL_HEADER)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned PrivateTextualHeaderAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned LinkLibraryAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFIG_MACRO)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name unsigned ConfigMacroAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFLICT)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Other module Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message unsigned ConflictAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXPORT_AS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name unsigned ExportAsAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); // Write the submodule metadata block. RecordData::value_type Record[] = { getNumberOfModules(WritingModule), FirstSubmoduleID - NUM_PREDEF_SUBMODULE_IDS}; Stream.EmitRecord(SUBMODULE_METADATA, Record); // Write all of the submodules. std::queue Q; Q.push(WritingModule); while (!Q.empty()) { Module *Mod = Q.front(); Q.pop(); unsigned ID = getSubmoduleID(Mod); uint64_t ParentID = 0; if (Mod->Parent) { assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?"); ParentID = SubmoduleIDs[Mod->Parent]; } SourceLocationEncoding::RawLocEncoding DefinitionLoc = getRawSourceLocationEncoding(getAdjustedLocation(Mod->DefinitionLoc)); // Emit the definition of the block. { RecordData::value_type Record[] = {SUBMODULE_DEFINITION, ID, ParentID, (RecordData::value_type)Mod->Kind, DefinitionLoc, Mod->IsFramework, Mod->IsExplicit, Mod->IsSystem, Mod->IsExternC, Mod->InferSubmodules, Mod->InferExplicitSubmodules, Mod->InferExportWildcard, Mod->ConfigMacrosExhaustive, Mod->ModuleMapIsPrivate, Mod->NamedModuleHasInit}; Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name); } // Emit the requirements. for (const auto &R : Mod->Requirements) { RecordData::value_type Record[] = {SUBMODULE_REQUIRES, R.RequiredState}; Stream.EmitRecordWithBlob(RequiresAbbrev, Record, R.FeatureName); } // Emit the umbrella header, if there is one. if (std::optional UmbrellaHeader = Mod->getUmbrellaHeaderAsWritten()) { RecordData::value_type Record[] = {SUBMODULE_UMBRELLA_HEADER}; Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record, UmbrellaHeader->NameAsWritten); } else if (std::optional UmbrellaDir = Mod->getUmbrellaDirAsWritten()) { RecordData::value_type Record[] = {SUBMODULE_UMBRELLA_DIR}; Stream.EmitRecordWithBlob(UmbrellaDirAbbrev, Record, UmbrellaDir->NameAsWritten); } // Emit the headers. struct { unsigned RecordKind; unsigned Abbrev; Module::HeaderKind HeaderKind; } HeaderLists[] = { {SUBMODULE_HEADER, HeaderAbbrev, Module::HK_Normal}, {SUBMODULE_TEXTUAL_HEADER, TextualHeaderAbbrev, Module::HK_Textual}, {SUBMODULE_PRIVATE_HEADER, PrivateHeaderAbbrev, Module::HK_Private}, {SUBMODULE_PRIVATE_TEXTUAL_HEADER, PrivateTextualHeaderAbbrev, Module::HK_PrivateTextual}, {SUBMODULE_EXCLUDED_HEADER, ExcludedHeaderAbbrev, Module::HK_Excluded} }; for (auto &HL : HeaderLists) { RecordData::value_type Record[] = {HL.RecordKind}; for (auto &H : Mod->Headers[HL.HeaderKind]) Stream.EmitRecordWithBlob(HL.Abbrev, Record, H.NameAsWritten); } // Emit the top headers. { RecordData::value_type Record[] = {SUBMODULE_TOPHEADER}; for (FileEntryRef H : Mod->getTopHeaders(PP->getFileManager())) { SmallString<128> HeaderName(H.getName()); PreparePathForOutput(HeaderName); Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record, HeaderName); } } // Emit the imports. if (!Mod->Imports.empty()) { RecordData Record; for (auto *I : Mod->Imports) Record.push_back(getSubmoduleID(I)); Stream.EmitRecord(SUBMODULE_IMPORTS, Record); } // Emit the modules affecting compilation that were not imported. if (!Mod->AffectingClangModules.empty()) { RecordData Record; for (auto *I : Mod->AffectingClangModules) Record.push_back(getSubmoduleID(I)); Stream.EmitRecord(SUBMODULE_AFFECTING_MODULES, Record); } // Emit the exports. if (!Mod->Exports.empty()) { RecordData Record; for (const auto &E : Mod->Exports) { // FIXME: This may fail; we don't require that all exported modules // are local or imported. Record.push_back(getSubmoduleID(E.getPointer())); Record.push_back(E.getInt()); } Stream.EmitRecord(SUBMODULE_EXPORTS, Record); } //FIXME: How do we emit the 'use'd modules? They may not be submodules. // Might be unnecessary as use declarations are only used to build the // module itself. // TODO: Consider serializing undeclared uses of modules. // Emit the link libraries. for (const auto &LL : Mod->LinkLibraries) { RecordData::value_type Record[] = {SUBMODULE_LINK_LIBRARY, LL.IsFramework}; Stream.EmitRecordWithBlob(LinkLibraryAbbrev, Record, LL.Library); } // Emit the conflicts. for (const auto &C : Mod->Conflicts) { // FIXME: This may fail; we don't require that all conflicting modules // are local or imported. RecordData::value_type Record[] = {SUBMODULE_CONFLICT, getSubmoduleID(C.Other)}; Stream.EmitRecordWithBlob(ConflictAbbrev, Record, C.Message); } // Emit the configuration macros. for (const auto &CM : Mod->ConfigMacros) { RecordData::value_type Record[] = {SUBMODULE_CONFIG_MACRO}; Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record, CM); } // Emit the reachable initializers. // The initializer may only be unreachable in reduced BMI. RecordData Inits; for (Decl *D : Context->getModuleInitializers(Mod)) if (wasDeclEmitted(D)) AddDeclRef(D, Inits); if (!Inits.empty()) Stream.EmitRecord(SUBMODULE_INITIALIZERS, Inits); // Emit the name of the re-exported module, if any. if (!Mod->ExportAsModule.empty()) { RecordData::value_type Record[] = {SUBMODULE_EXPORT_AS}; Stream.EmitRecordWithBlob(ExportAsAbbrev, Record, Mod->ExportAsModule); } // Queue up the submodules of this module. for (auto *M : Mod->submodules()) Q.push(M); } Stream.ExitBlock(); assert((NextSubmoduleID - FirstSubmoduleID == getNumberOfModules(WritingModule)) && "Wrong # of submodules; found a reference to a non-local, " "non-imported submodule?"); } void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, bool isModule) { llvm::SmallDenseMap DiagStateIDMap; unsigned CurrID = 0; RecordData Record; auto EncodeDiagStateFlags = [](const DiagnosticsEngine::DiagState *DS) -> unsigned { unsigned Result = (unsigned)DS->ExtBehavior; for (unsigned Val : {(unsigned)DS->IgnoreAllWarnings, (unsigned)DS->EnableAllWarnings, (unsigned)DS->WarningsAsErrors, (unsigned)DS->ErrorsAsFatal, (unsigned)DS->SuppressSystemWarnings}) Result = (Result << 1) | Val; return Result; }; unsigned Flags = EncodeDiagStateFlags(Diag.DiagStatesByLoc.FirstDiagState); Record.push_back(Flags); auto AddDiagState = [&](const DiagnosticsEngine::DiagState *State, bool IncludeNonPragmaStates) { // Ensure that the diagnostic state wasn't modified since it was created. // We will not correctly round-trip this information otherwise. assert(Flags == EncodeDiagStateFlags(State) && "diag state flags vary in single AST file"); // If we ever serialize non-pragma mappings outside the initial state, the // code below will need to consider more than getDefaultMapping. assert(!IncludeNonPragmaStates || State == Diag.DiagStatesByLoc.FirstDiagState); unsigned &DiagStateID = DiagStateIDMap[State]; Record.push_back(DiagStateID); if (DiagStateID == 0) { DiagStateID = ++CurrID; SmallVector> Mappings; // Add a placeholder for the number of mappings. auto SizeIdx = Record.size(); Record.emplace_back(); for (const auto &I : *State) { // Maybe skip non-pragmas. if (!I.second.isPragma() && !IncludeNonPragmaStates) continue; // Skip default mappings. We have a mapping for every diagnostic ever // emitted, regardless of whether it was customized. if (!I.second.isPragma() && I.second == DiagnosticIDs::getDefaultMapping(I.first)) continue; Mappings.push_back(I); } // Sort by diag::kind for deterministic output. llvm::sort(Mappings, llvm::less_first()); for (const auto &I : Mappings) { Record.push_back(I.first); Record.push_back(I.second.serialize()); } // Update the placeholder. Record[SizeIdx] = (Record.size() - SizeIdx) / 2; } }; AddDiagState(Diag.DiagStatesByLoc.FirstDiagState, isModule); // Reserve a spot for the number of locations with state transitions. auto NumLocationsIdx = Record.size(); Record.emplace_back(); // Emit the state transitions. unsigned NumLocations = 0; for (auto &FileIDAndFile : Diag.DiagStatesByLoc.Files) { if (!FileIDAndFile.first.isValid() || !FileIDAndFile.second.HasLocalTransitions) continue; ++NumLocations; AddFileID(FileIDAndFile.first, Record); Record.push_back(FileIDAndFile.second.StateTransitions.size()); for (auto &StatePoint : FileIDAndFile.second.StateTransitions) { Record.push_back(getAdjustedOffset(StatePoint.Offset)); AddDiagState(StatePoint.State, false); } } // Backpatch the number of locations. Record[NumLocationsIdx] = NumLocations; // Emit CurDiagStateLoc. Do it last in order to match source order. // // This also protects against a hypothetical corner case with simulating // -Werror settings for implicit modules in the ASTReader, where reading // CurDiagState out of context could change whether warning pragmas are // treated as errors. AddSourceLocation(Diag.DiagStatesByLoc.CurDiagStateLoc, Record); AddDiagState(Diag.DiagStatesByLoc.CurDiagState, false); Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record); } //===----------------------------------------------------------------------===// // Type Serialization //===----------------------------------------------------------------------===// /// Write the representation of a type to the AST stream. void ASTWriter::WriteType(QualType T) { TypeIdx &IdxRef = TypeIdxs[T]; if (IdxRef.getValue() == 0) // we haven't seen this type before. IdxRef = TypeIdx(0, NextTypeID++); TypeIdx Idx = IdxRef; assert(Idx.getModuleFileIndex() == 0 && "Re-writing a type from a prior AST"); assert(Idx.getValue() >= FirstTypeID && "Writing predefined type"); // Emit the type's representation. uint64_t Offset = ASTTypeWriter(*this).write(T) - DeclTypesBlockStartOffset; // Record the offset for this type. uint64_t Index = Idx.getValue() - FirstTypeID; if (TypeOffsets.size() == Index) TypeOffsets.emplace_back(Offset); else if (TypeOffsets.size() < Index) { TypeOffsets.resize(Index + 1); TypeOffsets[Index].set(Offset); } else { llvm_unreachable("Types emitted in wrong order"); } } //===----------------------------------------------------------------------===// // Declaration Serialization //===----------------------------------------------------------------------===// static bool IsInternalDeclFromFileContext(const Decl *D) { auto *ND = dyn_cast(D); if (!ND) return false; if (!D->getDeclContext()->getRedeclContext()->isFileContext()) return false; return ND->getFormalLinkage() == Linkage::Internal; } /// Write the block containing all of the declaration IDs /// lexically declared within the given DeclContext. /// /// \returns the offset of the DECL_CONTEXT_LEXICAL block within the /// bitstream, or 0 if no block was written. uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context, const DeclContext *DC) { if (DC->decls_empty()) return 0; // In reduced BMI, we don't care the declarations in functions. if (GeneratingReducedBMI && DC->isFunctionOrMethod()) return 0; uint64_t Offset = Stream.GetCurrentBitNo(); SmallVector KindDeclPairs; for (const auto *D : DC->decls()) { if (DoneWritingDeclsAndTypes && !wasDeclEmitted(D)) continue; // We don't need to write decls with internal linkage into reduced BMI. // If such decls gets emitted due to it get used from inline functions, // the program illegal. However, there are too many use of static inline // functions in the global module fragment and it will be breaking change // to forbid that. So we have to allow to emit such declarations from GMF. if (GeneratingReducedBMI && !D->isFromExplicitGlobalModule() && IsInternalDeclFromFileContext(D)) continue; KindDeclPairs.push_back(D->getKind()); KindDeclPairs.push_back(GetDeclRef(D).getRawValue()); } ++NumLexicalDeclContexts; RecordData::value_type Record[] = {DECL_CONTEXT_LEXICAL}; Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, bytes(KindDeclPairs)); return Offset; } void ASTWriter::WriteTypeDeclOffsets() { using namespace llvm; // Write the type offsets array auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); { RecordData::value_type Record[] = {TYPE_OFFSET, TypeOffsets.size()}; Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, bytes(TypeOffsets)); } // Write the declaration offsets array Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(DECL_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); { RecordData::value_type Record[] = {DECL_OFFSET, DeclOffsets.size()}; Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, bytes(DeclOffsets)); } } void ASTWriter::WriteFileDeclIDsMap() { using namespace llvm; SmallVector, 64> SortedFileDeclIDs; SortedFileDeclIDs.reserve(FileDeclIDs.size()); for (const auto &P : FileDeclIDs) SortedFileDeclIDs.push_back(std::make_pair(P.first, P.second.get())); llvm::sort(SortedFileDeclIDs, llvm::less_first()); // Join the vectors of DeclIDs from all files. SmallVector FileGroupedDeclIDs; for (auto &FileDeclEntry : SortedFileDeclIDs) { DeclIDInFileInfo &Info = *FileDeclEntry.second; Info.FirstDeclIndex = FileGroupedDeclIDs.size(); llvm::stable_sort(Info.DeclIDs); for (auto &LocDeclEntry : Info.DeclIDs) FileGroupedDeclIDs.push_back(LocDeclEntry.second.getRawValue()); } auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev)); RecordData::value_type Record[] = {FILE_SORTED_DECLS, FileGroupedDeclIDs.size()}; Stream.EmitRecordWithBlob(AbbrevCode, Record, bytes(FileGroupedDeclIDs)); } void ASTWriter::WriteComments() { Stream.EnterSubblock(COMMENTS_BLOCK_ID, 3); auto _ = llvm::make_scope_exit([this] { Stream.ExitBlock(); }); if (!PP->getPreprocessorOpts().WriteCommentListToPCH) return; // Don't write comments to BMI to reduce the size of BMI. // If language services (e.g., clangd) want such abilities, // we can offer a special option then. if (isWritingStdCXXNamedModules()) return; RecordData Record; for (const auto &FO : Context->Comments.OrderedComments) { for (const auto &OC : FO.second) { const RawComment *I = OC.second; Record.clear(); AddSourceRange(I->getSourceRange(), Record); Record.push_back(I->getKind()); Record.push_back(I->isTrailingComment()); Record.push_back(I->isAlmostTrailingComment()); Stream.EmitRecord(COMMENTS_RAW_COMMENT, Record); } } } //===----------------------------------------------------------------------===// // Global Method Pool and Selector Serialization //===----------------------------------------------------------------------===// namespace { // Trait used for the on-disk hash table used in the method pool. class ASTMethodPoolTrait { ASTWriter &Writer; public: using key_type = Selector; using key_type_ref = key_type; struct data_type { SelectorID ID; ObjCMethodList Instance, Factory; }; using data_type_ref = const data_type &; using hash_value_type = unsigned; using offset_type = unsigned; explicit ASTMethodPoolTrait(ASTWriter &Writer) : Writer(Writer) {} static hash_value_type ComputeHash(Selector Sel) { return serialization::ComputeHash(Sel); } std::pair EmitKeyDataLength(raw_ostream& Out, Selector Sel, data_type_ref Methods) { unsigned KeyLen = 2 + (Sel.getNumArgs() ? Sel.getNumArgs() * sizeof(IdentifierID) : sizeof(IdentifierID)); unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->getNext()) if (ShouldWriteMethodListNode(Method)) DataLen += sizeof(DeclID); for (const ObjCMethodList *Method = &Methods.Factory; Method; Method = Method->getNext()) if (ShouldWriteMethodListNode(Method)) DataLen += sizeof(DeclID); return emitULEBKeyDataLength(KeyLen, DataLen, Out); } void EmitKey(raw_ostream& Out, Selector Sel, unsigned) { using namespace llvm::support; endian::Writer LE(Out, llvm::endianness::little); uint64_t Start = Out.tell(); assert((Start >> 32) == 0 && "Selector key offset too large"); Writer.SetSelectorOffset(Sel, Start); unsigned N = Sel.getNumArgs(); LE.write(N); if (N == 0) N = 1; for (unsigned I = 0; I != N; ++I) LE.write( Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I))); } void EmitData(raw_ostream& Out, key_type_ref, data_type_ref Methods, unsigned DataLen) { using namespace llvm::support; endian::Writer LE(Out, llvm::endianness::little); uint64_t Start = Out.tell(); (void)Start; LE.write(Methods.ID); unsigned NumInstanceMethods = 0; for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->getNext()) if (ShouldWriteMethodListNode(Method)) ++NumInstanceMethods; unsigned NumFactoryMethods = 0; for (const ObjCMethodList *Method = &Methods.Factory; Method; Method = Method->getNext()) if (ShouldWriteMethodListNode(Method)) ++NumFactoryMethods; unsigned InstanceBits = Methods.Instance.getBits(); assert(InstanceBits < 4); unsigned InstanceHasMoreThanOneDeclBit = Methods.Instance.hasMoreThanOneDecl(); unsigned FullInstanceBits = (NumInstanceMethods << 3) | (InstanceHasMoreThanOneDeclBit << 2) | InstanceBits; unsigned FactoryBits = Methods.Factory.getBits(); assert(FactoryBits < 4); unsigned FactoryHasMoreThanOneDeclBit = Methods.Factory.hasMoreThanOneDecl(); unsigned FullFactoryBits = (NumFactoryMethods << 3) | (FactoryHasMoreThanOneDeclBit << 2) | FactoryBits; LE.write(FullInstanceBits); LE.write(FullFactoryBits); for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->getNext()) if (ShouldWriteMethodListNode(Method)) LE.write((DeclID)Writer.getDeclID(Method->getMethod())); for (const ObjCMethodList *Method = &Methods.Factory; Method; Method = Method->getNext()) if (ShouldWriteMethodListNode(Method)) LE.write((DeclID)Writer.getDeclID(Method->getMethod())); assert(Out.tell() - Start == DataLen && "Data length is wrong"); } private: static bool ShouldWriteMethodListNode(const ObjCMethodList *Node) { return (Node->getMethod() && !Node->getMethod()->isFromASTFile()); } }; } // namespace /// Write ObjC data: selectors and the method pool. /// /// The method pool contains both instance and factory methods, stored /// in an on-disk hash table indexed by the selector. The hash table also /// contains an empty entry for every other selector known to Sema. void ASTWriter::WriteSelectors(Sema &SemaRef) { using namespace llvm; // Do we have to do anything at all? if (SemaRef.ObjC().MethodPool.empty() && SelectorIDs.empty()) return; unsigned NumTableEntries = 0; // Create and write out the blob that contains selectors and the method pool. { llvm::OnDiskChainedHashTableGenerator Generator; ASTMethodPoolTrait Trait(*this); // Create the on-disk hash table representation. We walk through every // selector we've seen and look it up in the method pool. SelectorOffsets.resize(NextSelectorID - FirstSelectorID); for (auto &SelectorAndID : SelectorIDs) { Selector S = SelectorAndID.first; SelectorID ID = SelectorAndID.second; SemaObjC::GlobalMethodPool::iterator F = SemaRef.ObjC().MethodPool.find(S); ASTMethodPoolTrait::data_type Data = { ID, ObjCMethodList(), ObjCMethodList() }; if (F != SemaRef.ObjC().MethodPool.end()) { Data.Instance = F->second.first; Data.Factory = F->second.second; } // Only write this selector if it's not in an existing AST or something // changed. if (Chain && ID < FirstSelectorID) { // Selector already exists. Did it change? bool changed = false; for (ObjCMethodList *M = &Data.Instance; M && M->getMethod(); M = M->getNext()) { if (!M->getMethod()->isFromASTFile()) { changed = true; Data.Instance = *M; break; } } for (ObjCMethodList *M = &Data.Factory; M && M->getMethod(); M = M->getNext()) { if (!M->getMethod()->isFromASTFile()) { changed = true; Data.Factory = *M; break; } } if (!changed) continue; } else if (Data.Instance.getMethod() || Data.Factory.getMethod()) { // A new method pool entry. ++NumTableEntries; } Generator.insert(S, Data, Trait); } // Create the on-disk hash table in a buffer. SmallString<4096> MethodPool; uint32_t BucketOffset; { using namespace llvm::support; ASTMethodPoolTrait Trait(*this); llvm::raw_svector_ostream Out(MethodPool); // Make sure that no bucket is at offset 0 endian::write(Out, 0, llvm::endianness::little); BucketOffset = Generator.Emit(Out, Trait); } // Create a blob abbreviation auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(METHOD_POOL)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned MethodPoolAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); // Write the method pool { RecordData::value_type Record[] = {METHOD_POOL, BucketOffset, NumTableEntries}; Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool); } // Create a blob abbreviation for the selector table offsets. Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(SELECTOR_OFFSETS)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); // Write the selector offsets table. { RecordData::value_type Record[] = { SELECTOR_OFFSETS, SelectorOffsets.size(), FirstSelectorID - NUM_PREDEF_SELECTOR_IDS}; Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, bytes(SelectorOffsets)); } } } /// Write the selectors referenced in @selector expression into AST file. void ASTWriter::WriteReferencedSelectorsPool(Sema &SemaRef) { using namespace llvm; if (SemaRef.ObjC().ReferencedSelectors.empty()) return; RecordData Record; ASTRecordWriter Writer(*this, Record); // Note: this writes out all references even for a dependent AST. But it is // very tricky to fix, and given that @selector shouldn't really appear in // headers, probably not worth it. It's not a correctness issue. for (auto &SelectorAndLocation : SemaRef.ObjC().ReferencedSelectors) { Selector Sel = SelectorAndLocation.first; SourceLocation Loc = SelectorAndLocation.second; Writer.AddSelectorRef(Sel); Writer.AddSourceLocation(Loc); } Writer.Emit(REFERENCED_SELECTOR_POOL); } //===----------------------------------------------------------------------===// // Identifier Table Serialization //===----------------------------------------------------------------------===// /// Determine the declaration that should be put into the name lookup table to /// represent the given declaration in this module. This is usually D itself, /// but if D was imported and merged into a local declaration, we want the most /// recent local declaration instead. The chosen declaration will be the most /// recent declaration in any module that imports this one. static NamedDecl *getDeclForLocalLookup(const LangOptions &LangOpts, NamedDecl *D) { if (!LangOpts.Modules || !D->isFromASTFile()) return D; if (Decl *Redecl = D->getPreviousDecl()) { // For Redeclarable decls, a prior declaration might be local. for (; Redecl; Redecl = Redecl->getPreviousDecl()) { // If we find a local decl, we're done. if (!Redecl->isFromASTFile()) { // Exception: in very rare cases (for injected-class-names), not all // redeclarations are in the same semantic context. Skip ones in a // different context. They don't go in this lookup table at all. if (!Redecl->getDeclContext()->getRedeclContext()->Equals( D->getDeclContext()->getRedeclContext())) continue; return cast(Redecl); } // If we find a decl from a (chained-)PCH stop since we won't find a // local one. if (Redecl->getOwningModuleID() == 0) break; } } else if (Decl *First = D->getCanonicalDecl()) { // For Mergeable decls, the first decl might be local. if (!First->isFromASTFile()) return cast(First); } // All declarations are imported. Our most recent declaration will also be // the most recent one in anyone who imports us. return D; } namespace { bool IsInterestingIdentifier(const IdentifierInfo *II, uint64_t MacroOffset, bool IsModule, bool IsCPlusPlus) { bool NeedDecls = !IsModule || !IsCPlusPlus; bool IsInteresting = II->getNotableIdentifierID() != tok::NotableIdentifierKind::not_notable || II->getBuiltinID() != Builtin::ID::NotBuiltin || II->getObjCKeywordID() != tok::ObjCKeywordKind::objc_not_keyword; if (MacroOffset || II->isPoisoned() || (!IsModule && IsInteresting) || II->hasRevertedTokenIDToIdentifier() || (NeedDecls && II->getFETokenInfo())) return true; return false; } bool IsInterestingNonMacroIdentifier(const IdentifierInfo *II, ASTWriter &Writer) { bool IsModule = Writer.isWritingModule(); bool IsCPlusPlus = Writer.getLangOpts().CPlusPlus; return IsInterestingIdentifier(II, /*MacroOffset=*/0, IsModule, IsCPlusPlus); } class ASTIdentifierTableTrait { ASTWriter &Writer; Preprocessor &PP; IdentifierResolver &IdResolver; bool IsModule; bool NeedDecls; ASTWriter::RecordData *InterestingIdentifierOffsets; /// Determines whether this is an "interesting" identifier that needs a /// full IdentifierInfo structure written into the hash table. Notably, this /// doesn't check whether the name has macros defined; use PublicMacroIterator /// to check that. bool isInterestingIdentifier(const IdentifierInfo *II, uint64_t MacroOffset) { return IsInterestingIdentifier(II, MacroOffset, IsModule, Writer.getLangOpts().CPlusPlus); } public: using key_type = const IdentifierInfo *; using key_type_ref = key_type; using data_type = IdentifierID; using data_type_ref = data_type; using hash_value_type = unsigned; using offset_type = unsigned; ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, IdentifierResolver &IdResolver, bool IsModule, ASTWriter::RecordData *InterestingIdentifierOffsets) : Writer(Writer), PP(PP), IdResolver(IdResolver), IsModule(IsModule), NeedDecls(!IsModule || !Writer.getLangOpts().CPlusPlus), InterestingIdentifierOffsets(InterestingIdentifierOffsets) {} bool needDecls() const { return NeedDecls; } static hash_value_type ComputeHash(const IdentifierInfo* II) { return llvm::djbHash(II->getName()); } bool isInterestingIdentifier(const IdentifierInfo *II) { auto MacroOffset = Writer.getMacroDirectivesOffset(II); return isInterestingIdentifier(II, MacroOffset); } std::pair EmitKeyDataLength(raw_ostream &Out, const IdentifierInfo *II, IdentifierID ID) { // Record the location of the identifier data. This is used when generating // the mapping from persistent IDs to strings. Writer.SetIdentifierOffset(II, Out.tell()); auto MacroOffset = Writer.getMacroDirectivesOffset(II); // Emit the offset of the key/data length information to the interesting // identifiers table if necessary. if (InterestingIdentifierOffsets && isInterestingIdentifier(II, MacroOffset)) InterestingIdentifierOffsets->push_back(Out.tell()); unsigned KeyLen = II->getLength() + 1; unsigned DataLen = sizeof(IdentifierID); // bytes for the persistent ID << 1 if (isInterestingIdentifier(II, MacroOffset)) { DataLen += 2; // 2 bytes for builtin ID DataLen += 2; // 2 bytes for flags if (MacroOffset) DataLen += 4; // MacroDirectives offset. if (NeedDecls) DataLen += std::distance(IdResolver.begin(II), IdResolver.end()) * sizeof(DeclID); } return emitULEBKeyDataLength(KeyLen, DataLen, Out); } void EmitKey(raw_ostream &Out, const IdentifierInfo *II, unsigned KeyLen) { Out.write(II->getNameStart(), KeyLen); } void EmitData(raw_ostream &Out, const IdentifierInfo *II, IdentifierID ID, unsigned) { using namespace llvm::support; endian::Writer LE(Out, llvm::endianness::little); auto MacroOffset = Writer.getMacroDirectivesOffset(II); if (!isInterestingIdentifier(II, MacroOffset)) { LE.write(ID << 1); return; } LE.write((ID << 1) | 0x01); uint32_t Bits = (uint32_t)II->getObjCOrBuiltinID(); assert((Bits & 0xffff) == Bits && "ObjCOrBuiltinID too big for ASTReader."); LE.write(Bits); Bits = 0; bool HadMacroDefinition = MacroOffset != 0; Bits = (Bits << 1) | unsigned(HadMacroDefinition); Bits = (Bits << 1) | unsigned(II->isExtensionToken()); Bits = (Bits << 1) | unsigned(II->isPoisoned()); Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier()); Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); LE.write(Bits); if (HadMacroDefinition) LE.write(MacroOffset); if (NeedDecls) { // Emit the declaration IDs in reverse order, because the // IdentifierResolver provides the declarations as they would be // visible (e.g., the function "stat" would come before the struct // "stat"), but the ASTReader adds declarations to the end of the list // (so we need to see the struct "stat" before the function "stat"). // Only emit declarations that aren't from a chained PCH, though. SmallVector Decls(IdResolver.decls(II)); for (NamedDecl *D : llvm::reverse(Decls)) LE.write((DeclID)Writer.getDeclID( getDeclForLocalLookup(PP.getLangOpts(), D))); } } }; } // namespace /// If the \param IdentifierID ID is a local Identifier ID. If the higher /// bits of ID is 0, it implies that the ID doesn't come from AST files. static bool isLocalIdentifierID(IdentifierID ID) { return !(ID >> 32); } /// Write the identifier table into the AST file. /// /// The identifier table consists of a blob containing string data /// (the actual identifiers themselves) and a separate "offsets" index /// that maps identifier IDs to locations within the blob. void ASTWriter::WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver, bool IsModule) { using namespace llvm; RecordData InterestingIdents; // Create and write out the blob that contains the identifier // strings. { llvm::OnDiskChainedHashTableGenerator Generator; ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule, IsModule ? &InterestingIdents : nullptr); // Create the on-disk hash table representation. We only store offsets // for identifiers that appear here for the first time. IdentifierOffsets.resize(NextIdentID - FirstIdentID); for (auto IdentIDPair : IdentifierIDs) { const IdentifierInfo *II = IdentIDPair.first; IdentifierID ID = IdentIDPair.second; assert(II && "NULL identifier in identifier table"); // Write out identifiers if either the ID is local or the identifier has // changed since it was loaded. if (isLocalIdentifierID(ID) || II->hasChangedSinceDeserialization() || (Trait.needDecls() && II->hasFETokenInfoChangedSinceDeserialization())) Generator.insert(II, ID, Trait); } // Create the on-disk hash table in a buffer. SmallString<4096> IdentifierTable; uint32_t BucketOffset; { using namespace llvm::support; llvm::raw_svector_ostream Out(IdentifierTable); // Make sure that no bucket is at offset 0 endian::write(Out, 0, llvm::endianness::little); BucketOffset = Generator.Emit(Out, Trait); } // Create a blob abbreviation auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_TABLE)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned IDTableAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); // Write the identifier table RecordData::value_type Record[] = {IDENTIFIER_TABLE, BucketOffset}; Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable); } // Write the offsets table for identifier IDs. auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); #ifndef NDEBUG for (unsigned I = 0, N = IdentifierOffsets.size(); I != N; ++I) assert(IdentifierOffsets[I] && "Missing identifier offset?"); #endif RecordData::value_type Record[] = {IDENTIFIER_OFFSET, IdentifierOffsets.size()}; Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record, bytes(IdentifierOffsets)); // In C++, write the list of interesting identifiers (those that are // defined as macros, poisoned, or similar unusual things). if (!InterestingIdents.empty()) Stream.EmitRecord(INTERESTING_IDENTIFIERS, InterestingIdents); } void ASTWriter::handleVTable(CXXRecordDecl *RD) { if (!RD->isInNamedModule()) return; PendingEmittingVTables.push_back(RD); } //===----------------------------------------------------------------------===// // DeclContext's Name Lookup Table Serialization //===----------------------------------------------------------------------===// namespace { // Trait used for the on-disk hash table used in the method pool. class ASTDeclContextNameLookupTrait { ASTWriter &Writer; llvm::SmallVector DeclIDs; public: using key_type = DeclarationNameKey; using key_type_ref = key_type; /// A start and end index into DeclIDs, representing a sequence of decls. using data_type = std::pair; using data_type_ref = const data_type &; using hash_value_type = unsigned; using offset_type = unsigned; explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) {} template data_type getData(const Coll &Decls) { unsigned Start = DeclIDs.size(); for (NamedDecl *D : Decls) { NamedDecl *DeclForLocalLookup = getDeclForLocalLookup(Writer.getLangOpts(), D); if (Writer.getDoneWritingDeclsAndTypes() && !Writer.wasDeclEmitted(DeclForLocalLookup)) continue; // Try to avoid writing internal decls to reduced BMI. // See comments in ASTWriter::WriteDeclContextLexicalBlock for details. if (Writer.isGeneratingReducedBMI() && !DeclForLocalLookup->isFromExplicitGlobalModule() && IsInternalDeclFromFileContext(DeclForLocalLookup)) continue; DeclIDs.push_back(Writer.GetDeclRef(DeclForLocalLookup)); } return std::make_pair(Start, DeclIDs.size()); } data_type ImportData(const reader::ASTDeclContextNameLookupTrait::data_type &FromReader) { unsigned Start = DeclIDs.size(); DeclIDs.insert( DeclIDs.end(), DeclIDIterator(FromReader.begin()), DeclIDIterator(FromReader.end())); return std::make_pair(Start, DeclIDs.size()); } static bool EqualKey(key_type_ref a, key_type_ref b) { return a == b; } hash_value_type ComputeHash(DeclarationNameKey Name) { return Name.getHash(); } void EmitFileRef(raw_ostream &Out, ModuleFile *F) const { assert(Writer.hasChain() && "have reference to loaded module file but no chain?"); using namespace llvm::support; endian::write(Out, Writer.getChain()->getModuleFileID(F), llvm::endianness::little); } std::pair EmitKeyDataLength(raw_ostream &Out, DeclarationNameKey Name, data_type_ref Lookup) { unsigned KeyLen = 1; switch (Name.getKind()) { case DeclarationName::Identifier: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXDeductionGuideName: KeyLen += sizeof(IdentifierID); break; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: KeyLen += 4; break; case DeclarationName::CXXOperatorName: KeyLen += 1; break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: break; } // length of DeclIDs. unsigned DataLen = sizeof(DeclID) * (Lookup.second - Lookup.first); return emitULEBKeyDataLength(KeyLen, DataLen, Out); } void EmitKey(raw_ostream &Out, DeclarationNameKey Name, unsigned) { using namespace llvm::support; endian::Writer LE(Out, llvm::endianness::little); LE.write(Name.getKind()); switch (Name.getKind()) { case DeclarationName::Identifier: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXDeductionGuideName: LE.write(Writer.getIdentifierRef(Name.getIdentifier())); return; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: LE.write(Writer.getSelectorRef(Name.getSelector())); return; case DeclarationName::CXXOperatorName: assert(Name.getOperatorKind() < NUM_OVERLOADED_OPERATORS && "Invalid operator?"); LE.write(Name.getOperatorKind()); return; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: return; } llvm_unreachable("Invalid name kind?"); } void EmitData(raw_ostream &Out, key_type_ref, data_type Lookup, unsigned DataLen) { using namespace llvm::support; endian::Writer LE(Out, llvm::endianness::little); uint64_t Start = Out.tell(); (void)Start; for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I) LE.write((DeclID)DeclIDs[I]); assert(Out.tell() - Start == DataLen && "Data length is wrong"); } }; } // namespace bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC) { return Result.hasExternalDecls() && DC->hasNeedToReconcileExternalVisibleStorage(); } /// Returns ture if all of the lookup result are either external, not emitted or /// predefined. In such cases, the lookup result is not interesting and we don't /// need to record the result in the current being written module. Return false /// otherwise. static bool isLookupResultNotInteresting(ASTWriter &Writer, StoredDeclsList &Result) { for (auto *D : Result.getLookupResult()) { auto *LocalD = getDeclForLocalLookup(Writer.getLangOpts(), D); if (LocalD->isFromASTFile()) continue; // We can only be sure whether the local declaration is reachable // after we done writing the declarations and types. if (Writer.getDoneWritingDeclsAndTypes() && !Writer.wasDeclEmitted(LocalD)) continue; // We don't need to emit the predefined decls. if (Writer.isDeclPredefined(LocalD)) continue; return false; } return true; } void ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC, llvm::SmallVectorImpl &LookupTable) { assert(!ConstDC->hasLazyLocalLexicalLookups() && !ConstDC->hasLazyExternalLexicalLookups() && "must call buildLookups first"); // FIXME: We need to build the lookups table, which is logically const. auto *DC = const_cast(ConstDC); assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table"); // Create the on-disk hash table representation. MultiOnDiskHashTableGenerator Generator; ASTDeclContextNameLookupTrait Trait(*this); // The first step is to collect the declaration names which we need to // serialize into the name lookup table, and to collect them in a stable // order. SmallVector Names; // We also build up small sets of the constructor and conversion function // names which are visible. llvm::SmallPtrSet ConstructorNameSet, ConversionNameSet; for (auto &Lookup : *DC->buildLookup()) { auto &Name = Lookup.first; auto &Result = Lookup.second; // If there are no local declarations in our lookup result, we // don't need to write an entry for the name at all. If we can't // write out a lookup set without performing more deserialization, // just skip this entry. // // Also in reduced BMI, we'd like to avoid writing unreachable // declarations in GMF, so we need to avoid writing declarations // that entirely external or unreachable. // // FIMXE: It looks sufficient to test // isLookupResultNotInteresting here. But due to bug we have // to test isLookupResultExternal here. See // https://github.com/llvm/llvm-project/issues/61065 for details. if ((GeneratingReducedBMI || isLookupResultExternal(Result, DC)) && isLookupResultNotInteresting(*this, Result)) continue; // We also skip empty results. If any of the results could be external and // the currently available results are empty, then all of the results are // external and we skip it above. So the only way we get here with an empty // results is when no results could have been external *and* we have // external results. // // FIXME: While we might want to start emitting on-disk entries for negative // lookups into a decl context as an optimization, today we *have* to skip // them because there are names with empty lookup results in decl contexts // which we can't emit in any stable ordering: we lookup constructors and // conversion functions in the enclosing namespace scope creating empty // results for them. This in almost certainly a bug in Clang's name lookup, // but that is likely to be hard or impossible to fix and so we tolerate it // here by omitting lookups with empty results. if (Lookup.second.getLookupResult().empty()) continue; switch (Lookup.first.getNameKind()) { default: Names.push_back(Lookup.first); break; case DeclarationName::CXXConstructorName: assert(isa(DC) && "Cannot have a constructor name outside of a class!"); ConstructorNameSet.insert(Name); break; case DeclarationName::CXXConversionFunctionName: assert(isa(DC) && "Cannot have a conversion function name outside of a class!"); ConversionNameSet.insert(Name); break; } } // Sort the names into a stable order. llvm::sort(Names); if (auto *D = dyn_cast(DC)) { // We need to establish an ordering of constructor and conversion function // names, and they don't have an intrinsic ordering. // First we try the easy case by forming the current context's constructor // name and adding that name first. This is a very useful optimization to // avoid walking the lexical declarations in many cases, and it also // handles the only case where a constructor name can come from some other // lexical context -- when that name is an implicit constructor merged from // another declaration in the redecl chain. Any non-implicit constructor or // conversion function which doesn't occur in all the lexical contexts // would be an ODR violation. auto ImplicitCtorName = Context->DeclarationNames.getCXXConstructorName( Context->getCanonicalType(Context->getRecordType(D))); if (ConstructorNameSet.erase(ImplicitCtorName)) Names.push_back(ImplicitCtorName); // If we still have constructors or conversion functions, we walk all the // names in the decl and add the constructors and conversion functions // which are visible in the order they lexically occur within the context. if (!ConstructorNameSet.empty() || !ConversionNameSet.empty()) for (Decl *ChildD : cast(DC)->decls()) if (auto *ChildND = dyn_cast(ChildD)) { auto Name = ChildND->getDeclName(); switch (Name.getNameKind()) { default: continue; case DeclarationName::CXXConstructorName: if (ConstructorNameSet.erase(Name)) Names.push_back(Name); break; case DeclarationName::CXXConversionFunctionName: if (ConversionNameSet.erase(Name)) Names.push_back(Name); break; } if (ConstructorNameSet.empty() && ConversionNameSet.empty()) break; } assert(ConstructorNameSet.empty() && "Failed to find all of the visible " "constructors by walking all the " "lexical members of the context."); assert(ConversionNameSet.empty() && "Failed to find all of the visible " "conversion functions by walking all " "the lexical members of the context."); } // Next we need to do a lookup with each name into this decl context to fully // populate any results from external sources. We don't actually use the // results of these lookups because we only want to use the results after all // results have been loaded and the pointers into them will be stable. for (auto &Name : Names) DC->lookup(Name); // Now we need to insert the results for each name into the hash table. For // constructor names and conversion function names, we actually need to merge // all of the results for them into one list of results each and insert // those. SmallVector ConstructorDecls; SmallVector ConversionDecls; // Now loop over the names, either inserting them or appending for the two // special cases. for (auto &Name : Names) { DeclContext::lookup_result Result = DC->noload_lookup(Name); switch (Name.getNameKind()) { default: Generator.insert(Name, Trait.getData(Result), Trait); break; case DeclarationName::CXXConstructorName: ConstructorDecls.append(Result.begin(), Result.end()); break; case DeclarationName::CXXConversionFunctionName: ConversionDecls.append(Result.begin(), Result.end()); break; } } // Handle our two special cases if we ended up having any. We arbitrarily use // the first declaration's name here because the name itself isn't part of // the key, only the kind of name is used. if (!ConstructorDecls.empty()) Generator.insert(ConstructorDecls.front()->getDeclName(), Trait.getData(ConstructorDecls), Trait); if (!ConversionDecls.empty()) Generator.insert(ConversionDecls.front()->getDeclName(), Trait.getData(ConversionDecls), Trait); // Create the on-disk hash table. Also emit the existing imported and // merged table if there is one. auto *Lookups = Chain ? Chain->getLoadedLookupTables(DC) : nullptr; Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr); } /// Write the block containing all of the declaration IDs /// visible from the given DeclContext. /// /// \returns the offset of the DECL_CONTEXT_VISIBLE block within the /// bitstream, or 0 if no block was written. uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC) { // If we imported a key declaration of this namespace, write the visible // lookup results as an update record for it rather than including them // on this declaration. We will only look at key declarations on reload. if (isa(DC) && Chain && Chain->getKeyDeclaration(cast(DC))->isFromASTFile()) { // Only do this once, for the first local declaration of the namespace. for (auto *Prev = cast(DC)->getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) if (!Prev->isFromASTFile()) return 0; // Note that we need to emit an update record for the primary context. UpdatedDeclContexts.insert(DC->getPrimaryContext()); // Make sure all visible decls are written. They will be recorded later. We // do this using a side data structure so we can sort the names into // a deterministic order. StoredDeclsMap *Map = DC->getPrimaryContext()->buildLookup(); SmallVector, 16> LookupResults; if (Map) { LookupResults.reserve(Map->size()); for (auto &Entry : *Map) LookupResults.push_back( std::make_pair(Entry.first, Entry.second.getLookupResult())); } llvm::sort(LookupResults, llvm::less_first()); for (auto &NameAndResult : LookupResults) { DeclarationName Name = NameAndResult.first; DeclContext::lookup_result Result = NameAndResult.second; if (Name.getNameKind() == DeclarationName::CXXConstructorName || Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { // We have to work around a name lookup bug here where negative lookup // results for these names get cached in namespace lookup tables (these // names should never be looked up in a namespace). assert(Result.empty() && "Cannot have a constructor or conversion " "function name in a namespace!"); continue; } for (NamedDecl *ND : Result) { if (ND->isFromASTFile()) continue; if (DoneWritingDeclsAndTypes && !wasDeclEmitted(ND)) continue; // We don't need to force emitting internal decls into reduced BMI. // See comments in ASTWriter::WriteDeclContextLexicalBlock for details. if (GeneratingReducedBMI && !ND->isFromExplicitGlobalModule() && IsInternalDeclFromFileContext(ND)) continue; GetDeclRef(ND); } } return 0; } if (DC->getPrimaryContext() != DC) return 0; // Skip contexts which don't support name lookup. if (!DC->isLookupContext()) return 0; // If not in C++, we perform name lookup for the translation unit via the // IdentifierInfo chains, don't bother to build a visible-declarations table. if (DC->isTranslationUnit() && !Context.getLangOpts().CPlusPlus) return 0; // Serialize the contents of the mapping used for lookup. Note that, // although we have two very different code paths, the serialized // representation is the same for both cases: a declaration name, // followed by a size, followed by references to the visible // declarations that have that name. uint64_t Offset = Stream.GetCurrentBitNo(); StoredDeclsMap *Map = DC->buildLookup(); if (!Map || Map->empty()) return 0; // Create the on-disk hash table in a buffer. SmallString<4096> LookupTable; GenerateNameLookupTable(DC, LookupTable); // Write the lookup table RecordData::value_type Record[] = {DECL_CONTEXT_VISIBLE}; Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record, LookupTable); ++NumVisibleDeclContexts; return Offset; } /// Write an UPDATE_VISIBLE block for the given context. /// /// UPDATE_VISIBLE blocks contain the declarations that are added to an existing /// DeclContext in a dependent AST file. As such, they only exist for the TU /// (in C++), for namespaces, and for classes with forward-declared unscoped /// enumeration members (in C++11). void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) { StoredDeclsMap *Map = DC->getLookupPtr(); if (!Map || Map->empty()) return; // Create the on-disk hash table in a buffer. SmallString<4096> LookupTable; GenerateNameLookupTable(DC, LookupTable); // If we're updating a namespace, select a key declaration as the key for the // update record; those are the only ones that will be checked on reload. if (isa(DC)) DC = cast(Chain->getKeyDeclaration(cast(DC))); // Write the lookup table RecordData::value_type Record[] = {UPDATE_VISIBLE, getDeclID(cast(DC)).getRawValue()}; Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable); } /// Write an FP_PRAGMA_OPTIONS block for the given FPOptions. void ASTWriter::WriteFPPragmaOptions(const FPOptionsOverride &Opts) { RecordData::value_type Record[] = {Opts.getAsOpaqueInt()}; Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record); } /// Write an OPENCL_EXTENSIONS block for the given OpenCLOptions. void ASTWriter::WriteOpenCLExtensions(Sema &SemaRef) { if (!SemaRef.Context.getLangOpts().OpenCL) return; const OpenCLOptions &Opts = SemaRef.getOpenCLOptions(); RecordData Record; for (const auto &I:Opts.OptMap) { AddString(I.getKey(), Record); auto V = I.getValue(); Record.push_back(V.Supported ? 1 : 0); Record.push_back(V.Enabled ? 1 : 0); Record.push_back(V.WithPragma ? 1 : 0); Record.push_back(V.Avail); Record.push_back(V.Core); Record.push_back(V.Opt); } Stream.EmitRecord(OPENCL_EXTENSIONS, Record); } void ASTWriter::WriteCUDAPragmas(Sema &SemaRef) { if (SemaRef.CUDA().ForceHostDeviceDepth > 0) { RecordData::value_type Record[] = {SemaRef.CUDA().ForceHostDeviceDepth}; Stream.EmitRecord(CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH, Record); } } void ASTWriter::WriteObjCCategories() { SmallVector CategoriesMap; RecordData Categories; for (unsigned I = 0, N = ObjCClassesWithCategories.size(); I != N; ++I) { unsigned Size = 0; unsigned StartIndex = Categories.size(); ObjCInterfaceDecl *Class = ObjCClassesWithCategories[I]; // Allocate space for the size. Categories.push_back(0); // Add the categories. for (ObjCInterfaceDecl::known_categories_iterator Cat = Class->known_categories_begin(), CatEnd = Class->known_categories_end(); Cat != CatEnd; ++Cat, ++Size) { assert(getDeclID(*Cat).isValid() && "Bogus category"); AddDeclRef(*Cat, Categories); } // Update the size. Categories[StartIndex] = Size; // Record this interface -> category map. ObjCCategoriesInfo CatInfo = { getDeclID(Class), StartIndex }; CategoriesMap.push_back(CatInfo); } // Sort the categories map by the definition ID, since the reader will be // performing binary searches on this information. llvm::array_pod_sort(CategoriesMap.begin(), CategoriesMap.end()); // Emit the categories map. using namespace llvm; auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(OBJC_CATEGORIES_MAP)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned AbbrevID = Stream.EmitAbbrev(std::move(Abbrev)); RecordData::value_type Record[] = {OBJC_CATEGORIES_MAP, CategoriesMap.size()}; Stream.EmitRecordWithBlob(AbbrevID, Record, reinterpret_cast(CategoriesMap.data()), CategoriesMap.size() * sizeof(ObjCCategoriesInfo)); // Emit the category lists. Stream.EmitRecord(OBJC_CATEGORIES, Categories); } void ASTWriter::WriteLateParsedTemplates(Sema &SemaRef) { Sema::LateParsedTemplateMapT &LPTMap = SemaRef.LateParsedTemplateMap; if (LPTMap.empty()) return; RecordData Record; for (auto &LPTMapEntry : LPTMap) { const FunctionDecl *FD = LPTMapEntry.first; LateParsedTemplate &LPT = *LPTMapEntry.second; AddDeclRef(FD, Record); AddDeclRef(LPT.D, Record); Record.push_back(LPT.FPO.getAsOpaqueInt()); Record.push_back(LPT.Toks.size()); for (const auto &Tok : LPT.Toks) { AddToken(Tok, Record); } } Stream.EmitRecord(LATE_PARSED_TEMPLATE, Record); } /// Write the state of 'pragma clang optimize' at the end of the module. void ASTWriter::WriteOptimizePragmaOptions(Sema &SemaRef) { RecordData Record; SourceLocation PragmaLoc = SemaRef.getOptimizeOffPragmaLocation(); AddSourceLocation(PragmaLoc, Record); Stream.EmitRecord(OPTIMIZE_PRAGMA_OPTIONS, Record); } /// Write the state of 'pragma ms_struct' at the end of the module. void ASTWriter::WriteMSStructPragmaOptions(Sema &SemaRef) { RecordData Record; Record.push_back(SemaRef.MSStructPragmaOn ? PMSST_ON : PMSST_OFF); Stream.EmitRecord(MSSTRUCT_PRAGMA_OPTIONS, Record); } /// Write the state of 'pragma pointers_to_members' at the end of the //module. void ASTWriter::WriteMSPointersToMembersPragmaOptions(Sema &SemaRef) { RecordData Record; Record.push_back(SemaRef.MSPointerToMemberRepresentationMethod); AddSourceLocation(SemaRef.ImplicitMSInheritanceAttrLoc, Record); Stream.EmitRecord(POINTERS_TO_MEMBERS_PRAGMA_OPTIONS, Record); } /// Write the state of 'pragma align/pack' at the end of the module. void ASTWriter::WritePackPragmaOptions(Sema &SemaRef) { // Don't serialize pragma align/pack state for modules, since it should only // take effect on a per-submodule basis. if (WritingModule) return; RecordData Record; AddAlignPackInfo(SemaRef.AlignPackStack.CurrentValue, Record); AddSourceLocation(SemaRef.AlignPackStack.CurrentPragmaLocation, Record); Record.push_back(SemaRef.AlignPackStack.Stack.size()); for (const auto &StackEntry : SemaRef.AlignPackStack.Stack) { AddAlignPackInfo(StackEntry.Value, Record); AddSourceLocation(StackEntry.PragmaLocation, Record); AddSourceLocation(StackEntry.PragmaPushLocation, Record); AddString(StackEntry.StackSlotLabel, Record); } Stream.EmitRecord(ALIGN_PACK_PRAGMA_OPTIONS, Record); } /// Write the state of 'pragma float_control' at the end of the module. void ASTWriter::WriteFloatControlPragmaOptions(Sema &SemaRef) { // Don't serialize pragma float_control state for modules, // since it should only take effect on a per-submodule basis. if (WritingModule) return; RecordData Record; Record.push_back(SemaRef.FpPragmaStack.CurrentValue.getAsOpaqueInt()); AddSourceLocation(SemaRef.FpPragmaStack.CurrentPragmaLocation, Record); Record.push_back(SemaRef.FpPragmaStack.Stack.size()); for (const auto &StackEntry : SemaRef.FpPragmaStack.Stack) { Record.push_back(StackEntry.Value.getAsOpaqueInt()); AddSourceLocation(StackEntry.PragmaLocation, Record); AddSourceLocation(StackEntry.PragmaPushLocation, Record); AddString(StackEntry.StackSlotLabel, Record); } Stream.EmitRecord(FLOAT_CONTROL_PRAGMA_OPTIONS, Record); } void ASTWriter::WriteModuleFileExtension(Sema &SemaRef, ModuleFileExtensionWriter &Writer) { // Enter the extension block. Stream.EnterSubblock(EXTENSION_BLOCK_ID, 4); // Emit the metadata record abbreviation. auto Abv = std::make_shared(); Abv->Add(llvm::BitCodeAbbrevOp(EXTENSION_METADATA)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); unsigned Abbrev = Stream.EmitAbbrev(std::move(Abv)); // Emit the metadata record. RecordData Record; auto Metadata = Writer.getExtension()->getExtensionMetadata(); Record.push_back(EXTENSION_METADATA); Record.push_back(Metadata.MajorVersion); Record.push_back(Metadata.MinorVersion); Record.push_back(Metadata.BlockName.size()); Record.push_back(Metadata.UserInfo.size()); SmallString<64> Buffer; Buffer += Metadata.BlockName; Buffer += Metadata.UserInfo; Stream.EmitRecordWithBlob(Abbrev, Record, Buffer); // Emit the contents of the extension block. Writer.writeExtensionContents(SemaRef, Stream); // Exit the extension block. Stream.ExitBlock(); } //===----------------------------------------------------------------------===// // General Serialization Routines //===----------------------------------------------------------------------===// void ASTRecordWriter::AddAttr(const Attr *A) { auto &Record = *this; // FIXME: Clang can't handle the serialization/deserialization of // preferred_name properly now. See // https://github.com/llvm/llvm-project/issues/56490 for example. if (!A || (isa(A) && Writer->isWritingStdCXXNamedModules())) return Record.push_back(0); Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs Record.AddIdentifierRef(A->getAttrName()); Record.AddIdentifierRef(A->getScopeName()); Record.AddSourceRange(A->getRange()); Record.AddSourceLocation(A->getScopeLoc()); Record.push_back(A->getParsedKind()); Record.push_back(A->getSyntax()); Record.push_back(A->getAttributeSpellingListIndexRaw()); Record.push_back(A->isRegularKeywordAttribute()); #include "clang/Serialization/AttrPCHWrite.inc" } /// Emit the list of attributes to the specified record. void ASTRecordWriter::AddAttributes(ArrayRef Attrs) { push_back(Attrs.size()); for (const auto *A : Attrs) AddAttr(A); } void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) { AddSourceLocation(Tok.getLocation(), Record); // FIXME: Should translate token kind to a stable encoding. Record.push_back(Tok.getKind()); // FIXME: Should translate token flags to a stable encoding. Record.push_back(Tok.getFlags()); if (Tok.isAnnotation()) { AddSourceLocation(Tok.getAnnotationEndLoc(), Record); switch (Tok.getKind()) { case tok::annot_pragma_loop_hint: { auto *Info = static_cast(Tok.getAnnotationValue()); AddToken(Info->PragmaName, Record); AddToken(Info->Option, Record); Record.push_back(Info->Toks.size()); for (const auto &T : Info->Toks) AddToken(T, Record); break; } case tok::annot_pragma_pack: { auto *Info = static_cast(Tok.getAnnotationValue()); Record.push_back(static_cast(Info->Action)); AddString(Info->SlotLabel, Record); AddToken(Info->Alignment, Record); break; } // Some annotation tokens do not use the PtrData field. case tok::annot_pragma_openmp: case tok::annot_pragma_openmp_end: case tok::annot_pragma_unused: case tok::annot_pragma_openacc: case tok::annot_pragma_openacc_end: break; default: llvm_unreachable("missing serialization code for annotation token"); } } else { Record.push_back(Tok.getLength()); // FIXME: When reading literal tokens, reconstruct the literal pointer if it // is needed. AddIdentifierRef(Tok.getIdentifierInfo(), Record); } } void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) { Record.push_back(Str.size()); Record.insert(Record.end(), Str.begin(), Str.end()); } bool ASTWriter::PreparePathForOutput(SmallVectorImpl &Path) { assert(Context && "should have context when outputting path"); // Leave special file names as they are. StringRef PathStr(Path.data(), Path.size()); if (PathStr == "" || PathStr == "") return false; bool Changed = cleanPathForOutput(Context->getSourceManager().getFileManager(), Path); // Remove a prefix to make the path relative, if relevant. const char *PathBegin = Path.data(); const char *PathPtr = adjustFilenameForRelocatableAST(PathBegin, BaseDirectory); if (PathPtr != PathBegin) { Path.erase(Path.begin(), Path.begin() + (PathPtr - PathBegin)); Changed = true; } return Changed; } void ASTWriter::AddPath(StringRef Path, RecordDataImpl &Record) { SmallString<128> FilePath(Path); PreparePathForOutput(FilePath); AddString(FilePath, Record); } void ASTWriter::EmitRecordWithPath(unsigned Abbrev, RecordDataRef Record, StringRef Path) { SmallString<128> FilePath(Path); PreparePathForOutput(FilePath); Stream.EmitRecordWithBlob(Abbrev, Record, FilePath); } void ASTWriter::AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record) { Record.push_back(Version.getMajor()); if (std::optional Minor = Version.getMinor()) Record.push_back(*Minor + 1); else Record.push_back(0); if (std::optional Subminor = Version.getSubminor()) Record.push_back(*Subminor + 1); else Record.push_back(0); } /// Note that the identifier II occurs at the given offset /// within the identifier table. void ASTWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) { IdentifierID ID = IdentifierIDs[II]; // Only store offsets new to this AST file. Other identifier names are looked // up earlier in the chain and thus don't need an offset. if (!isLocalIdentifierID(ID)) return; // For local identifiers, the module file index must be 0. assert(ID != 0); ID -= NUM_PREDEF_IDENT_IDS; assert(ID < IdentifierOffsets.size()); IdentifierOffsets[ID] = Offset; } /// Note that the selector Sel occurs at the given offset /// within the method pool/selector table. void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) { unsigned ID = SelectorIDs[Sel]; assert(ID && "Unknown selector"); // Don't record offsets for selectors that are also available in a different // file. if (ID < FirstSelectorID) return; SelectorOffsets[ID - FirstSelectorID] = Offset; } ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream, SmallVectorImpl &Buffer, InMemoryModuleCache &ModuleCache, ArrayRef> Extensions, bool IncludeTimestamps, bool BuildingImplicitModule, bool GeneratingReducedBMI) : Stream(Stream), Buffer(Buffer), ModuleCache(ModuleCache), IncludeTimestamps(IncludeTimestamps), BuildingImplicitModule(BuildingImplicitModule), GeneratingReducedBMI(GeneratingReducedBMI) { for (const auto &Ext : Extensions) { if (auto Writer = Ext->createExtensionWriter(*this)) ModuleFileExtensionWriters.push_back(std::move(Writer)); } } ASTWriter::~ASTWriter() = default; const LangOptions &ASTWriter::getLangOpts() const { assert(WritingAST && "can't determine lang opts when not writing AST"); return Context->getLangOpts(); } time_t ASTWriter::getTimestampForOutput(const FileEntry *E) const { return IncludeTimestamps ? E->getModificationTime() : 0; } ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef, StringRef OutputFile, Module *WritingModule, StringRef isysroot, bool ShouldCacheASTInMemory) { llvm::TimeTraceScope scope("WriteAST", OutputFile); WritingAST = true; ASTHasCompilerErrors = SemaRef.PP.getDiagnostics().hasUncompilableErrorOccurred(); // Emit the file header. Stream.Emit((unsigned)'C', 8); Stream.Emit((unsigned)'P', 8); Stream.Emit((unsigned)'C', 8); Stream.Emit((unsigned)'H', 8); WriteBlockInfoBlock(); Context = &SemaRef.Context; PP = &SemaRef.PP; this->WritingModule = WritingModule; ASTFileSignature Signature = WriteASTCore(SemaRef, isysroot, WritingModule); Context = nullptr; PP = nullptr; this->WritingModule = nullptr; this->BaseDirectory.clear(); WritingAST = false; if (ShouldCacheASTInMemory) { // Construct MemoryBuffer and update buffer manager. ModuleCache.addBuiltPCM(OutputFile, llvm::MemoryBuffer::getMemBufferCopy( StringRef(Buffer.begin(), Buffer.size()))); } return Signature; } template static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec) { for (typename Vector::iterator I = Vec.begin(nullptr, true), E = Vec.end(); I != E; ++I) { Writer.GetDeclRef(*I); } } template static void AddLazyVectorEmiitedDecls(ASTWriter &Writer, Vector &Vec, ASTWriter::RecordData &Record) { for (typename Vector::iterator I = Vec.begin(nullptr, true), E = Vec.end(); I != E; ++I) { Writer.AddEmittedDeclRef(*I, Record); } } void ASTWriter::computeNonAffectingInputFiles() { SourceManager &SrcMgr = PP->getSourceManager(); unsigned N = SrcMgr.local_sloc_entry_size(); IsSLocAffecting.resize(N, true); if (!WritingModule) return; auto AffectingModuleMaps = GetAffectingModuleMaps(*PP, WritingModule); unsigned FileIDAdjustment = 0; unsigned OffsetAdjustment = 0; NonAffectingFileIDAdjustments.reserve(N); NonAffectingOffsetAdjustments.reserve(N); NonAffectingFileIDAdjustments.push_back(FileIDAdjustment); NonAffectingOffsetAdjustments.push_back(OffsetAdjustment); for (unsigned I = 1; I != N; ++I) { const SrcMgr::SLocEntry *SLoc = &SrcMgr.getLocalSLocEntry(I); FileID FID = FileID::get(I); assert(&SrcMgr.getSLocEntry(FID) == SLoc); if (!SLoc->isFile()) continue; const SrcMgr::FileInfo &File = SLoc->getFile(); const SrcMgr::ContentCache *Cache = &File.getContentCache(); if (!Cache->OrigEntry) continue; // Don't prune anything other than module maps. if (!isModuleMap(File.getFileCharacteristic())) continue; // Don't prune module maps if all are guaranteed to be affecting. if (!AffectingModuleMaps) continue; // Don't prune module maps that are affecting. if (llvm::is_contained(*AffectingModuleMaps, *Cache->OrigEntry)) continue; IsSLocAffecting[I] = false; FileIDAdjustment += 1; // Even empty files take up one element in the offset table. OffsetAdjustment += SrcMgr.getFileIDSize(FID) + 1; // If the previous file was non-affecting as well, just extend its entry // with our information. if (!NonAffectingFileIDs.empty() && NonAffectingFileIDs.back().ID == FID.ID - 1) { NonAffectingFileIDs.back() = FID; NonAffectingRanges.back().setEnd(SrcMgr.getLocForEndOfFile(FID)); NonAffectingFileIDAdjustments.back() = FileIDAdjustment; NonAffectingOffsetAdjustments.back() = OffsetAdjustment; continue; } NonAffectingFileIDs.push_back(FID); NonAffectingRanges.emplace_back(SrcMgr.getLocForStartOfFile(FID), SrcMgr.getLocForEndOfFile(FID)); NonAffectingFileIDAdjustments.push_back(FileIDAdjustment); NonAffectingOffsetAdjustments.push_back(OffsetAdjustment); } if (!PP->getHeaderSearchInfo().getHeaderSearchOpts().ModulesIncludeVFSUsage) return; FileManager &FileMgr = PP->getFileManager(); FileMgr.trackVFSUsage(true); // Lookup the paths in the VFS to trigger `-ivfsoverlay` usage tracking. for (StringRef Path : PP->getHeaderSearchInfo().getHeaderSearchOpts().VFSOverlayFiles) FileMgr.getVirtualFileSystem().exists(Path); for (unsigned I = 1; I != N; ++I) { if (IsSLocAffecting[I]) { const SrcMgr::SLocEntry *SLoc = &SrcMgr.getLocalSLocEntry(I); if (!SLoc->isFile()) continue; const SrcMgr::FileInfo &File = SLoc->getFile(); const SrcMgr::ContentCache *Cache = &File.getContentCache(); if (!Cache->OrigEntry) continue; FileMgr.getVirtualFileSystem().exists( Cache->OrigEntry->getNameAsRequested()); } } FileMgr.trackVFSUsage(false); } void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) { ASTContext &Context = SemaRef.Context; bool isModule = WritingModule != nullptr; // Set up predefined declaration IDs. auto RegisterPredefDecl = [&] (Decl *D, PredefinedDeclIDs ID) { if (D) { assert(D->isCanonicalDecl() && "predefined decl is not canonical"); DeclIDs[D] = ID; PredefinedDecls.insert(D); } }; RegisterPredefDecl(Context.getTranslationUnitDecl(), PREDEF_DECL_TRANSLATION_UNIT_ID); RegisterPredefDecl(Context.ObjCIdDecl, PREDEF_DECL_OBJC_ID_ID); RegisterPredefDecl(Context.ObjCSelDecl, PREDEF_DECL_OBJC_SEL_ID); RegisterPredefDecl(Context.ObjCClassDecl, PREDEF_DECL_OBJC_CLASS_ID); RegisterPredefDecl(Context.ObjCProtocolClassDecl, PREDEF_DECL_OBJC_PROTOCOL_ID); RegisterPredefDecl(Context.Int128Decl, PREDEF_DECL_INT_128_ID); RegisterPredefDecl(Context.UInt128Decl, PREDEF_DECL_UNSIGNED_INT_128_ID); RegisterPredefDecl(Context.ObjCInstanceTypeDecl, PREDEF_DECL_OBJC_INSTANCETYPE_ID); RegisterPredefDecl(Context.BuiltinVaListDecl, PREDEF_DECL_BUILTIN_VA_LIST_ID); RegisterPredefDecl(Context.VaListTagDecl, PREDEF_DECL_VA_LIST_TAG); RegisterPredefDecl(Context.BuiltinMSVaListDecl, PREDEF_DECL_BUILTIN_MS_VA_LIST_ID); RegisterPredefDecl(Context.MSGuidTagDecl, PREDEF_DECL_BUILTIN_MS_GUID_ID); RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID); RegisterPredefDecl(Context.MakeIntegerSeqDecl, PREDEF_DECL_MAKE_INTEGER_SEQ_ID); RegisterPredefDecl(Context.CFConstantStringTypeDecl, PREDEF_DECL_CF_CONSTANT_STRING_ID); RegisterPredefDecl(Context.CFConstantStringTagDecl, PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID); RegisterPredefDecl(Context.TypePackElementDecl, PREDEF_DECL_TYPE_PACK_ELEMENT_ID); const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); // Force all top level declarations to be emitted. // // We start emitting top level declarations from the module purview to // implement the eliding unreachable declaration feature. for (const auto *D : TU->noload_decls()) { if (D->isFromASTFile()) continue; if (GeneratingReducedBMI) { if (D->isFromExplicitGlobalModule()) continue; // Don't force emitting static entities. // // Technically, all static entities shouldn't be in reduced BMI. The // language also specifies that the program exposes TU-local entities // is ill-formed. However, in practice, there are a lot of projects // uses `static inline` in the headers. So we can't get rid of all // static entities in reduced BMI now. if (IsInternalDeclFromFileContext(D)) continue; } // If we're writing C++ named modules, don't emit declarations which are // not from modules by default. They may be built in declarations (be // handled above) or implcit declarations (see the implementation of // `Sema::Initialize()` for example). if (isWritingStdCXXNamedModules() && !D->getOwningModule() && D->isImplicit()) continue; GetDeclRef(D); } if (GeneratingReducedBMI) return; // Writing all of the tentative definitions in this file, in // TentativeDefinitions order. Generally, this record will be empty for // headers. RecordData TentativeDefinitions; AddLazyVectorDecls(*this, SemaRef.TentativeDefinitions); // Writing all of the file scoped decls in this file. if (!isModule) AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls); // Writing all of the delegating constructors we still need // to resolve. if (!isModule) AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls); // Writing all of the ext_vector declarations. AddLazyVectorDecls(*this, SemaRef.ExtVectorDecls); // Writing all of the VTable uses information. if (!SemaRef.VTableUses.empty()) for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) GetDeclRef(SemaRef.VTableUses[I].first); // Writing all of the UnusedLocalTypedefNameCandidates. for (const TypedefNameDecl *TD : SemaRef.UnusedLocalTypedefNameCandidates) GetDeclRef(TD); // Writing all of pending implicit instantiations. for (const auto &I : SemaRef.PendingInstantiations) GetDeclRef(I.first); assert(SemaRef.PendingLocalImplicitInstantiations.empty() && "There are local ones at end of translation unit!"); // Writing some declaration references. if (SemaRef.StdNamespace || SemaRef.StdBadAlloc || SemaRef.StdAlignValT) { GetDeclRef(SemaRef.getStdNamespace()); GetDeclRef(SemaRef.getStdBadAlloc()); GetDeclRef(SemaRef.getStdAlignValT()); } if (Context.getcudaConfigureCallDecl()) GetDeclRef(Context.getcudaConfigureCallDecl()); // Writing all of the known namespaces. for (const auto &I : SemaRef.KnownNamespaces) if (!I.second) GetDeclRef(I.first); // Writing all used, undefined objects that require definitions. SmallVector, 16> Undefined; SemaRef.getUndefinedButUsed(Undefined); for (const auto &I : Undefined) GetDeclRef(I.first); // Writing all delete-expressions that we would like to // analyze later in AST. if (!isModule) for (const auto &DeleteExprsInfo : SemaRef.getMismatchingDeleteExpressions()) GetDeclRef(DeleteExprsInfo.first); // Make sure visible decls, added to DeclContexts previously loaded from // an AST file, are registered for serialization. Likewise for template // specializations added to imported templates. for (const auto *I : DeclsToEmitEvenIfUnreferenced) GetDeclRef(I); DeclsToEmitEvenIfUnreferenced.clear(); // Make sure all decls associated with an identifier are registered for // serialization, if we're storing decls with identifiers. if (!WritingModule || !getLangOpts().CPlusPlus) { llvm::SmallVector IIs; for (const auto &ID : SemaRef.PP.getIdentifierTable()) { const IdentifierInfo *II = ID.second; if (!Chain || !II->isFromAST() || II->hasChangedSinceDeserialization()) IIs.push_back(II); } // Sort the identifiers to visit based on their name. llvm::sort(IIs, llvm::deref>()); for (const IdentifierInfo *II : IIs) for (const Decl *D : SemaRef.IdResolver.decls(II)) GetDeclRef(D); } // Write all of the DeclsToCheckForDeferredDiags. for (auto *D : SemaRef.DeclsToCheckForDeferredDiags) GetDeclRef(D); // Write all classes that need to emit the vtable definitions if required. if (isWritingStdCXXNamedModules()) for (CXXRecordDecl *RD : PendingEmittingVTables) GetDeclRef(RD); else PendingEmittingVTables.clear(); } void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) { ASTContext &Context = SemaRef.Context; bool isModule = WritingModule != nullptr; // Write the record containing external, unnamed definitions. if (!EagerlyDeserializedDecls.empty()) Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls); if (!ModularCodegenDecls.empty()) Stream.EmitRecord(MODULAR_CODEGEN_DECLS, ModularCodegenDecls); // Write the record containing tentative definitions. RecordData TentativeDefinitions; AddLazyVectorEmiitedDecls(*this, SemaRef.TentativeDefinitions, TentativeDefinitions); if (!TentativeDefinitions.empty()) Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions); // Write the record containing unused file scoped decls. RecordData UnusedFileScopedDecls; if (!isModule) AddLazyVectorEmiitedDecls(*this, SemaRef.UnusedFileScopedDecls, UnusedFileScopedDecls); if (!UnusedFileScopedDecls.empty()) Stream.EmitRecord(UNUSED_FILESCOPED_DECLS, UnusedFileScopedDecls); // Write the record containing ext_vector type names. RecordData ExtVectorDecls; AddLazyVectorEmiitedDecls(*this, SemaRef.ExtVectorDecls, ExtVectorDecls); if (!ExtVectorDecls.empty()) Stream.EmitRecord(EXT_VECTOR_DECLS, ExtVectorDecls); // Write the record containing VTable uses information. RecordData VTableUses; if (!SemaRef.VTableUses.empty()) { for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) { CXXRecordDecl *D = SemaRef.VTableUses[I].first; if (!wasDeclEmitted(D)) continue; AddDeclRef(D, VTableUses); AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses); VTableUses.push_back(SemaRef.VTablesUsed[D]); } Stream.EmitRecord(VTABLE_USES, VTableUses); } // Write the record containing potentially unused local typedefs. RecordData UnusedLocalTypedefNameCandidates; for (const TypedefNameDecl *TD : SemaRef.UnusedLocalTypedefNameCandidates) AddEmittedDeclRef(TD, UnusedLocalTypedefNameCandidates); if (!UnusedLocalTypedefNameCandidates.empty()) Stream.EmitRecord(UNUSED_LOCAL_TYPEDEF_NAME_CANDIDATES, UnusedLocalTypedefNameCandidates); // Write the record containing pending implicit instantiations. RecordData PendingInstantiations; for (const auto &I : SemaRef.PendingInstantiations) { if (!wasDeclEmitted(I.first)) continue; AddDeclRef(I.first, PendingInstantiations); AddSourceLocation(I.second, PendingInstantiations); } if (!PendingInstantiations.empty()) Stream.EmitRecord(PENDING_IMPLICIT_INSTANTIATIONS, PendingInstantiations); // Write the record containing declaration references of Sema. RecordData SemaDeclRefs; if (SemaRef.StdNamespace || SemaRef.StdBadAlloc || SemaRef.StdAlignValT) { auto AddEmittedDeclRefOrZero = [this, &SemaDeclRefs](Decl *D) { if (!D || !wasDeclEmitted(D)) SemaDeclRefs.push_back(0); else AddDeclRef(D, SemaDeclRefs); }; AddEmittedDeclRefOrZero(SemaRef.getStdNamespace()); AddEmittedDeclRefOrZero(SemaRef.getStdBadAlloc()); AddEmittedDeclRefOrZero(SemaRef.getStdAlignValT()); } if (!SemaDeclRefs.empty()) Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs); // Write the record containing decls to be checked for deferred diags. RecordData DeclsToCheckForDeferredDiags; for (auto *D : SemaRef.DeclsToCheckForDeferredDiags) if (wasDeclEmitted(D)) AddDeclRef(D, DeclsToCheckForDeferredDiags); if (!DeclsToCheckForDeferredDiags.empty()) Stream.EmitRecord(DECLS_TO_CHECK_FOR_DEFERRED_DIAGS, DeclsToCheckForDeferredDiags); // Write the record containing CUDA-specific declaration references. RecordData CUDASpecialDeclRefs; if (auto *CudaCallDecl = Context.getcudaConfigureCallDecl(); CudaCallDecl && wasDeclEmitted(CudaCallDecl)) { AddDeclRef(CudaCallDecl, CUDASpecialDeclRefs); Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs); } // Write the delegating constructors. RecordData DelegatingCtorDecls; if (!isModule) AddLazyVectorEmiitedDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls); if (!DelegatingCtorDecls.empty()) Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls); // Write the known namespaces. RecordData KnownNamespaces; for (const auto &I : SemaRef.KnownNamespaces) { if (!I.second && wasDeclEmitted(I.first)) AddDeclRef(I.first, KnownNamespaces); } if (!KnownNamespaces.empty()) Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces); // Write the undefined internal functions and variables, and inline functions. RecordData UndefinedButUsed; SmallVector, 16> Undefined; SemaRef.getUndefinedButUsed(Undefined); for (const auto &I : Undefined) { if (!wasDeclEmitted(I.first)) continue; AddDeclRef(I.first, UndefinedButUsed); AddSourceLocation(I.second, UndefinedButUsed); } if (!UndefinedButUsed.empty()) Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed); // Write all delete-expressions that we would like to // analyze later in AST. RecordData DeleteExprsToAnalyze; if (!isModule) { for (const auto &DeleteExprsInfo : SemaRef.getMismatchingDeleteExpressions()) { if (!wasDeclEmitted(DeleteExprsInfo.first)) continue; AddDeclRef(DeleteExprsInfo.first, DeleteExprsToAnalyze); DeleteExprsToAnalyze.push_back(DeleteExprsInfo.second.size()); for (const auto &DeleteLoc : DeleteExprsInfo.second) { AddSourceLocation(DeleteLoc.first, DeleteExprsToAnalyze); DeleteExprsToAnalyze.push_back(DeleteLoc.second); } } } if (!DeleteExprsToAnalyze.empty()) Stream.EmitRecord(DELETE_EXPRS_TO_ANALYZE, DeleteExprsToAnalyze); RecordData VTablesToEmit; for (CXXRecordDecl *RD : PendingEmittingVTables) { if (!wasDeclEmitted(RD)) continue; AddDeclRef(RD, VTablesToEmit); } if (!VTablesToEmit.empty()) Stream.EmitRecord(VTABLES_TO_EMIT, VTablesToEmit); } ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, Module *WritingModule) { using namespace llvm; bool isModule = WritingModule != nullptr; // Make sure that the AST reader knows to finalize itself. if (Chain) Chain->finalizeForWriting(); ASTContext &Context = SemaRef.Context; Preprocessor &PP = SemaRef.PP; // This needs to be done very early, since everything that writes // SourceLocations or FileIDs depends on it. computeNonAffectingInputFiles(); writeUnhashedControlBlock(PP, Context); // Don't reuse type ID and Identifier ID from readers for C++ standard named // modules since we want to support no-transitive-change model for named // modules. The theory for no-transitive-change model is, // for a user of a named module, the user can only access the indirectly // imported decls via the directly imported module. So that it is possible to // control what matters to the users when writing the module. It would be // problematic if the users can reuse the type IDs and identifier IDs from // indirectly imported modules arbitrarily. So we choose to clear these ID // here. if (isWritingStdCXXNamedModules()) { TypeIdxs.clear(); IdentifierIDs.clear(); } // Look for any identifiers that were named while processing the // headers, but are otherwise not needed. We add these to the hash // table to enable checking of the predefines buffer in the case // where the user adds new macro definitions when building the AST // file. // // We do this before emitting any Decl and Types to make sure the // Identifier ID is stable. SmallVector IIs; for (const auto &ID : PP.getIdentifierTable()) if (IsInterestingNonMacroIdentifier(ID.second, *this)) IIs.push_back(ID.second); // Sort the identifiers lexicographically before getting the references so // that their order is stable. llvm::sort(IIs, llvm::deref>()); for (const IdentifierInfo *II : IIs) getIdentifierRef(II); // Write the set of weak, undeclared identifiers. We always write the // entire table, since later PCH files in a PCH chain are only interested in // the results at the end of the chain. RecordData WeakUndeclaredIdentifiers; for (const auto &WeakUndeclaredIdentifierList : SemaRef.WeakUndeclaredIdentifiers) { const IdentifierInfo *const II = WeakUndeclaredIdentifierList.first; for (const auto &WI : WeakUndeclaredIdentifierList.second) { AddIdentifierRef(II, WeakUndeclaredIdentifiers); AddIdentifierRef(WI.getAlias(), WeakUndeclaredIdentifiers); AddSourceLocation(WI.getLocation(), WeakUndeclaredIdentifiers); } } // Form the record of special types. RecordData SpecialTypes; AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes); AddTypeRef(Context.getFILEType(), SpecialTypes); AddTypeRef(Context.getjmp_bufType(), SpecialTypes); AddTypeRef(Context.getsigjmp_bufType(), SpecialTypes); AddTypeRef(Context.ObjCIdRedefinitionType, SpecialTypes); AddTypeRef(Context.ObjCClassRedefinitionType, SpecialTypes); AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes); AddTypeRef(Context.getucontext_tType(), SpecialTypes); PrepareWritingSpecialDecls(SemaRef); // Write the control block WriteControlBlock(PP, Context, isysroot); // Write the remaining AST contents. Stream.FlushToWord(); ASTBlockRange.first = Stream.GetCurrentBitNo() >> 3; Stream.EnterSubblock(AST_BLOCK_ID, 5); ASTBlockStartOffset = Stream.GetCurrentBitNo(); // This is so that older clang versions, before the introduction // of the control block, can read and reject the newer PCH format. { RecordData Record = {VERSION_MAJOR}; Stream.EmitRecord(METADATA_OLD_FORMAT, Record); } // For method pool in the module, if it contains an entry for a selector, // the entry should be complete, containing everything introduced by that // module and all modules it imports. It's possible that the entry is out of // date, so we need to pull in the new content here. // It's possible that updateOutOfDateSelector can update SelectorIDs. To be // safe, we copy all selectors out. llvm::SmallVector AllSelectors; for (auto &SelectorAndID : SelectorIDs) AllSelectors.push_back(SelectorAndID.first); for (auto &Selector : AllSelectors) SemaRef.ObjC().updateOutOfDateSelector(Selector); if (Chain) { // Write the mapping information describing our module dependencies and how // each of those modules were mapped into our own offset/ID space, so that // the reader can build the appropriate mapping to its own offset/ID space. // The map consists solely of a blob with the following format: // *(module-kind:i8 // module-name-len:i16 module-name:len*i8 // source-location-offset:i32 // identifier-id:i32 // preprocessed-entity-id:i32 // macro-definition-id:i32 // submodule-id:i32 // selector-id:i32 // declaration-id:i32 // c++-base-specifiers-id:i32 // type-id:i32) // // module-kind is the ModuleKind enum value. If it is MK_PrebuiltModule, // MK_ExplicitModule or MK_ImplicitModule, then the module-name is the // module name. Otherwise, it is the module file name. auto Abbrev = std::make_shared(); Abbrev->Add(BitCodeAbbrevOp(MODULE_OFFSET_MAP)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned ModuleOffsetMapAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); SmallString<2048> Buffer; { llvm::raw_svector_ostream Out(Buffer); for (ModuleFile &M : Chain->ModuleMgr) { using namespace llvm::support; endian::Writer LE(Out, llvm::endianness::little); LE.write(static_cast(M.Kind)); StringRef Name = M.isModule() ? M.ModuleName : M.FileName; LE.write(Name.size()); Out.write(Name.data(), Name.size()); // Note: if a base ID was uint max, it would not be possible to load // another module after it or have more than one entity inside it. uint32_t None = std::numeric_limits::max(); auto writeBaseIDOrNone = [&](auto BaseID, bool ShouldWrite) { assert(BaseID < std::numeric_limits::max() && "base id too high"); if (ShouldWrite) LE.write(BaseID); else LE.write(None); }; // These values should be unique within a chain, since they will be read // as keys into ContinuousRangeMaps. writeBaseIDOrNone(M.BaseMacroID, M.LocalNumMacros); writeBaseIDOrNone(M.BasePreprocessedEntityID, M.NumPreprocessedEntities); writeBaseIDOrNone(M.BaseSubmoduleID, M.LocalNumSubmodules); writeBaseIDOrNone(M.BaseSelectorID, M.LocalNumSelectors); } } RecordData::value_type Record[] = {MODULE_OFFSET_MAP}; Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record, Buffer.data(), Buffer.size()); } WriteDeclAndTypes(Context); WriteFileDeclIDsMap(); WriteSourceManagerBlock(Context.getSourceManager(), PP); WriteComments(); WritePreprocessor(PP, isModule); WriteHeaderSearch(PP.getHeaderSearchInfo()); WriteSelectors(SemaRef); WriteReferencedSelectorsPool(SemaRef); WriteLateParsedTemplates(SemaRef); WriteIdentifierTable(PP, SemaRef.IdResolver, isModule); WriteFPPragmaOptions(SemaRef.CurFPFeatureOverrides()); WriteOpenCLExtensions(SemaRef); WriteCUDAPragmas(SemaRef); // If we're emitting a module, write out the submodule information. if (WritingModule) WriteSubmodules(WritingModule); Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes); WriteSpecialDeclRecords(SemaRef); // Write the record containing weak undeclared identifiers. if (!WeakUndeclaredIdentifiers.empty()) Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS, WeakUndeclaredIdentifiers); if (!WritingModule) { // Write the submodules that were imported, if any. struct ModuleInfo { uint64_t ID; Module *M; ModuleInfo(uint64_t ID, Module *M) : ID(ID), M(M) {} }; llvm::SmallVector Imports; for (const auto *I : Context.local_imports()) { assert(SubmoduleIDs.contains(I->getImportedModule())); Imports.push_back(ModuleInfo(SubmoduleIDs[I->getImportedModule()], I->getImportedModule())); } if (!Imports.empty()) { auto Cmp = [](const ModuleInfo &A, const ModuleInfo &B) { return A.ID < B.ID; }; auto Eq = [](const ModuleInfo &A, const ModuleInfo &B) { return A.ID == B.ID; }; // Sort and deduplicate module IDs. llvm::sort(Imports, Cmp); Imports.erase(std::unique(Imports.begin(), Imports.end(), Eq), Imports.end()); RecordData ImportedModules; for (const auto &Import : Imports) { ImportedModules.push_back(Import.ID); // FIXME: If the module has macros imported then later has declarations // imported, this location won't be the right one as a location for the // declaration imports. AddSourceLocation(PP.getModuleImportLoc(Import.M), ImportedModules); } Stream.EmitRecord(IMPORTED_MODULES, ImportedModules); } } WriteObjCCategories(); if(!WritingModule) { WriteOptimizePragmaOptions(SemaRef); WriteMSStructPragmaOptions(SemaRef); WriteMSPointersToMembersPragmaOptions(SemaRef); } WritePackPragmaOptions(SemaRef); WriteFloatControlPragmaOptions(SemaRef); // Some simple statistics RecordData::value_type Record[] = { NumStatements, NumMacros, NumLexicalDeclContexts, NumVisibleDeclContexts}; Stream.EmitRecord(STATISTICS, Record); Stream.ExitBlock(); Stream.FlushToWord(); ASTBlockRange.second = Stream.GetCurrentBitNo() >> 3; // Write the module file extension blocks. for (const auto &ExtWriter : ModuleFileExtensionWriters) WriteModuleFileExtension(SemaRef, *ExtWriter); return backpatchSignature(); } void ASTWriter::EnteringModulePurview() { // In C++20 named modules, all entities before entering the module purview // lives in the GMF. if (GeneratingReducedBMI) DeclUpdatesFromGMF.swap(DeclUpdates); } // Add update records for all mangling numbers and static local numbers. // These aren't really update records, but this is a convenient way of // tagging this rare extra data onto the declarations. void ASTWriter::AddedManglingNumber(const Decl *D, unsigned Number) { if (D->isFromASTFile()) return; DeclUpdates[D].push_back(DeclUpdate(UPD_MANGLING_NUMBER, Number)); } void ASTWriter::AddedStaticLocalNumbers(const Decl *D, unsigned Number) { if (D->isFromASTFile()) return; DeclUpdates[D].push_back(DeclUpdate(UPD_STATIC_LOCAL_NUMBER, Number)); } void ASTWriter::AddedAnonymousNamespace(const TranslationUnitDecl *TU, NamespaceDecl *AnonNamespace) { // If the translation unit has an anonymous namespace, and we don't already // have an update block for it, write it as an update block. // FIXME: Why do we not do this if there's already an update block? if (NamespaceDecl *NS = TU->getAnonymousNamespace()) { ASTWriter::UpdateRecord &Record = DeclUpdates[TU]; if (Record.empty()) Record.push_back(DeclUpdate(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, NS)); } } void ASTWriter::WriteDeclAndTypes(ASTContext &Context) { // Keep writing types, declarations, and declaration update records // until we've emitted all of them. RecordData DeclUpdatesOffsetsRecord; Stream.EnterSubblock(DECLTYPES_BLOCK_ID, /*bits for abbreviations*/5); DeclTypesBlockStartOffset = Stream.GetCurrentBitNo(); WriteTypeAbbrevs(); WriteDeclAbbrevs(); do { WriteDeclUpdatesBlocks(DeclUpdatesOffsetsRecord); while (!DeclTypesToEmit.empty()) { DeclOrType DOT = DeclTypesToEmit.front(); DeclTypesToEmit.pop(); if (DOT.isType()) WriteType(DOT.getType()); else WriteDecl(Context, DOT.getDecl()); } } while (!DeclUpdates.empty()); DoneWritingDeclsAndTypes = true; // DelayedNamespace is only meaningful in reduced BMI. // See the comments of DelayedNamespace for details. assert(DelayedNamespace.empty() || GeneratingReducedBMI); RecordData DelayedNamespaceRecord; for (NamespaceDecl *NS : DelayedNamespace) { uint64_t LexicalOffset = WriteDeclContextLexicalBlock(Context, NS); uint64_t VisibleOffset = WriteDeclContextVisibleBlock(Context, NS); // Write the offset relative to current block. if (LexicalOffset) LexicalOffset -= DeclTypesBlockStartOffset; if (VisibleOffset) VisibleOffset -= DeclTypesBlockStartOffset; AddDeclRef(NS, DelayedNamespaceRecord); DelayedNamespaceRecord.push_back(LexicalOffset); DelayedNamespaceRecord.push_back(VisibleOffset); } // The process of writing lexical and visible block for delayed namespace // shouldn't introduce any new decls, types or update to emit. assert(DeclTypesToEmit.empty()); assert(DeclUpdates.empty()); Stream.ExitBlock(); // These things can only be done once we've written out decls and types. WriteTypeDeclOffsets(); if (!DeclUpdatesOffsetsRecord.empty()) Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord); if (!DelayedNamespaceRecord.empty()) Stream.EmitRecord(DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD, DelayedNamespaceRecord); const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); // Create a lexical update block containing all of the declarations in the // translation unit that do not come from other AST files. SmallVector NewGlobalKindDeclPairs; for (const auto *D : TU->noload_decls()) { if (D->isFromASTFile()) continue; // In reduced BMI, skip unreached declarations. if (!wasDeclEmitted(D)) continue; NewGlobalKindDeclPairs.push_back(D->getKind()); NewGlobalKindDeclPairs.push_back(GetDeclRef(D).getRawValue()); } auto Abv = std::make_shared(); Abv->Add(llvm::BitCodeAbbrevOp(TU_UPDATE_LEXICAL)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); unsigned TuUpdateLexicalAbbrev = Stream.EmitAbbrev(std::move(Abv)); RecordData::value_type Record[] = {TU_UPDATE_LEXICAL}; Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, bytes(NewGlobalKindDeclPairs)); Abv = std::make_shared(); Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6)); Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)); UpdateVisibleAbbrev = Stream.EmitAbbrev(std::move(Abv)); // And a visible updates block for the translation unit. WriteDeclContextVisibleUpdate(TU); // If we have any extern "C" names, write out a visible update for them. if (Context.ExternCContext) WriteDeclContextVisibleUpdate(Context.ExternCContext); // Write the visible updates to DeclContexts. for (auto *DC : UpdatedDeclContexts) WriteDeclContextVisibleUpdate(DC); } void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { if (DeclUpdates.empty()) return; DeclUpdateMap LocalUpdates; LocalUpdates.swap(DeclUpdates); for (auto &DeclUpdate : LocalUpdates) { const Decl *D = DeclUpdate.first; bool HasUpdatedBody = false; bool HasAddedVarDefinition = false; RecordData RecordData; ASTRecordWriter Record(*this, RecordData); for (auto &Update : DeclUpdate.second) { DeclUpdateKind Kind = (DeclUpdateKind)Update.getKind(); // An updated body is emitted last, so that the reader doesn't need // to skip over the lazy body to reach statements for other records. if (Kind == UPD_CXX_ADDED_FUNCTION_DEFINITION) HasUpdatedBody = true; else if (Kind == UPD_CXX_ADDED_VAR_DEFINITION) HasAddedVarDefinition = true; else Record.push_back(Kind); switch (Kind) { case UPD_CXX_ADDED_IMPLICIT_MEMBER: case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: assert(Update.getDecl() && "no decl to add?"); Record.AddDeclRef(Update.getDecl()); break; case UPD_CXX_ADDED_FUNCTION_DEFINITION: case UPD_CXX_ADDED_VAR_DEFINITION: break; case UPD_CXX_POINT_OF_INSTANTIATION: // FIXME: Do we need to also save the template specialization kind here? Record.AddSourceLocation(Update.getLoc()); break; case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: Record.writeStmtRef( cast(Update.getDecl())->getDefaultArg()); break; case UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER: Record.AddStmt( cast(Update.getDecl())->getInClassInitializer()); break; case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: { auto *RD = cast(D); UpdatedDeclContexts.insert(RD->getPrimaryContext()); Record.push_back(RD->isParamDestroyedInCallee()); Record.push_back(llvm::to_underlying(RD->getArgPassingRestrictions())); Record.AddCXXDefinitionData(RD); Record.AddOffset(WriteDeclContextLexicalBlock(*Context, RD)); // This state is sometimes updated by template instantiation, when we // switch from the specialization referring to the template declaration // to it referring to the template definition. if (auto *MSInfo = RD->getMemberSpecializationInfo()) { Record.push_back(MSInfo->getTemplateSpecializationKind()); Record.AddSourceLocation(MSInfo->getPointOfInstantiation()); } else { auto *Spec = cast(RD); Record.push_back(Spec->getTemplateSpecializationKind()); Record.AddSourceLocation(Spec->getPointOfInstantiation()); // The instantiation might have been resolved to a partial // specialization. If so, record which one. auto From = Spec->getInstantiatedFrom(); if (auto PartialSpec = From.dyn_cast()) { Record.push_back(true); Record.AddDeclRef(PartialSpec); Record.AddTemplateArgumentList( &Spec->getTemplateInstantiationArgs()); } else { Record.push_back(false); } } Record.push_back(llvm::to_underlying(RD->getTagKind())); Record.AddSourceLocation(RD->getLocation()); Record.AddSourceLocation(RD->getBeginLoc()); Record.AddSourceRange(RD->getBraceRange()); // Instantiation may change attributes; write them all out afresh. Record.push_back(D->hasAttrs()); if (D->hasAttrs()) Record.AddAttributes(D->getAttrs()); // FIXME: Ensure we don't get here for explicit instantiations. break; } case UPD_CXX_RESOLVED_DTOR_DELETE: Record.AddDeclRef(Update.getDecl()); Record.AddStmt(cast(D)->getOperatorDeleteThisArg()); break; case UPD_CXX_RESOLVED_EXCEPTION_SPEC: { auto prototype = cast(D)->getType()->castAs(); Record.writeExceptionSpecInfo(prototype->getExceptionSpecInfo()); break; } case UPD_CXX_DEDUCED_RETURN_TYPE: Record.push_back(GetOrCreateTypeID(Update.getType())); break; case UPD_DECL_MARKED_USED: break; case UPD_MANGLING_NUMBER: case UPD_STATIC_LOCAL_NUMBER: Record.push_back(Update.getNumber()); break; case UPD_DECL_MARKED_OPENMP_THREADPRIVATE: Record.AddSourceRange( D->getAttr()->getRange()); break; case UPD_DECL_MARKED_OPENMP_ALLOCATE: { auto *A = D->getAttr(); Record.push_back(A->getAllocatorType()); Record.AddStmt(A->getAllocator()); Record.AddStmt(A->getAlignment()); Record.AddSourceRange(A->getRange()); break; } case UPD_DECL_MARKED_OPENMP_DECLARETARGET: Record.push_back(D->getAttr()->getMapType()); Record.AddSourceRange( D->getAttr()->getRange()); break; case UPD_DECL_EXPORTED: Record.push_back(getSubmoduleID(Update.getModule())); break; case UPD_ADDED_ATTR_TO_RECORD: Record.AddAttributes(llvm::ArrayRef(Update.getAttr())); break; } } // Add a trailing update record, if any. These must go last because we // lazily load their attached statement. if (!GeneratingReducedBMI || !CanElideDeclDef(D)) { if (HasUpdatedBody) { const auto *Def = cast(D); Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION); Record.push_back(Def->isInlined()); Record.AddSourceLocation(Def->getInnerLocStart()); Record.AddFunctionDefinition(Def); } else if (HasAddedVarDefinition) { const auto *VD = cast(D); Record.push_back(UPD_CXX_ADDED_VAR_DEFINITION); Record.push_back(VD->isInline()); Record.push_back(VD->isInlineSpecified()); Record.AddVarDeclInit(VD); } } AddDeclRef(D, OffsetsRecord); OffsetsRecord.push_back(Record.Emit(DECL_UPDATES)); } } void ASTWriter::AddAlignPackInfo(const Sema::AlignPackInfo &Info, RecordDataImpl &Record) { uint32_t Raw = Sema::AlignPackInfo::getRawEncoding(Info); Record.push_back(Raw); } FileID ASTWriter::getAdjustedFileID(FileID FID) const { if (FID.isInvalid() || PP->getSourceManager().isLoadedFileID(FID) || NonAffectingFileIDs.empty()) return FID; auto It = llvm::lower_bound(NonAffectingFileIDs, FID); unsigned Idx = std::distance(NonAffectingFileIDs.begin(), It); unsigned Offset = NonAffectingFileIDAdjustments[Idx]; return FileID::get(FID.getOpaqueValue() - Offset); } unsigned ASTWriter::getAdjustedNumCreatedFIDs(FileID FID) const { unsigned NumCreatedFIDs = PP->getSourceManager() .getLocalSLocEntry(FID.ID) .getFile() .NumCreatedFIDs; unsigned AdjustedNumCreatedFIDs = 0; for (unsigned I = FID.ID, N = I + NumCreatedFIDs; I != N; ++I) if (IsSLocAffecting[I]) ++AdjustedNumCreatedFIDs; return AdjustedNumCreatedFIDs; } SourceLocation ASTWriter::getAdjustedLocation(SourceLocation Loc) const { if (Loc.isInvalid()) return Loc; return Loc.getLocWithOffset(-getAdjustment(Loc.getOffset())); } SourceRange ASTWriter::getAdjustedRange(SourceRange Range) const { return SourceRange(getAdjustedLocation(Range.getBegin()), getAdjustedLocation(Range.getEnd())); } SourceLocation::UIntTy ASTWriter::getAdjustedOffset(SourceLocation::UIntTy Offset) const { return Offset - getAdjustment(Offset); } SourceLocation::UIntTy ASTWriter::getAdjustment(SourceLocation::UIntTy Offset) const { if (NonAffectingRanges.empty()) return 0; if (PP->getSourceManager().isLoadedOffset(Offset)) return 0; if (Offset > NonAffectingRanges.back().getEnd().getOffset()) return NonAffectingOffsetAdjustments.back(); if (Offset < NonAffectingRanges.front().getBegin().getOffset()) return 0; auto Contains = [](const SourceRange &Range, SourceLocation::UIntTy Offset) { return Range.getEnd().getOffset() < Offset; }; auto It = llvm::lower_bound(NonAffectingRanges, Offset, Contains); unsigned Idx = std::distance(NonAffectingRanges.begin(), It); return NonAffectingOffsetAdjustments[Idx]; } void ASTWriter::AddFileID(FileID FID, RecordDataImpl &Record) { Record.push_back(getAdjustedFileID(FID).getOpaqueValue()); } SourceLocationEncoding::RawLocEncoding ASTWriter::getRawSourceLocationEncoding(SourceLocation Loc, LocSeq *Seq) { unsigned BaseOffset = 0; unsigned ModuleFileIndex = 0; // See SourceLocationEncoding.h for the encoding details. if (Context->getSourceManager().isLoadedSourceLocation(Loc) && Loc.isValid()) { assert(getChain()); auto SLocMapI = getChain()->GlobalSLocOffsetMap.find( SourceManager::MaxLoadedOffset - Loc.getOffset() - 1); assert(SLocMapI != getChain()->GlobalSLocOffsetMap.end() && "Corrupted global sloc offset map"); ModuleFile *F = SLocMapI->second; BaseOffset = F->SLocEntryBaseOffset - 2; // 0 means the location is not loaded. So we need to add 1 to the index to // make it clear. ModuleFileIndex = F->Index + 1; assert(&getChain()->getModuleManager()[F->Index] == F); } return SourceLocationEncoding::encode(Loc, BaseOffset, ModuleFileIndex, Seq); } void ASTWriter::AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record, SourceLocationSequence *Seq) { Loc = getAdjustedLocation(Loc); Record.push_back(getRawSourceLocationEncoding(Loc, Seq)); } void ASTWriter::AddSourceRange(SourceRange Range, RecordDataImpl &Record, SourceLocationSequence *Seq) { AddSourceLocation(Range.getBegin(), Record, Seq); AddSourceLocation(Range.getEnd(), Record, Seq); } void ASTRecordWriter::AddAPFloat(const llvm::APFloat &Value) { AddAPInt(Value.bitcastToAPInt()); } void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record) { Record.push_back(getIdentifierRef(II)); } IdentifierID ASTWriter::getIdentifierRef(const IdentifierInfo *II) { if (!II) return 0; IdentifierID &ID = IdentifierIDs[II]; if (ID == 0) ID = NextIdentID++; return ID; } MacroID ASTWriter::getMacroRef(MacroInfo *MI, const IdentifierInfo *Name) { // Don't emit builtin macros like __LINE__ to the AST file unless they // have been redefined by the header (in which case they are not // isBuiltinMacro). if (!MI || MI->isBuiltinMacro()) return 0; MacroID &ID = MacroIDs[MI]; if (ID == 0) { ID = NextMacroID++; MacroInfoToEmitData Info = { Name, MI, ID }; MacroInfosToEmit.push_back(Info); } return ID; } MacroID ASTWriter::getMacroID(MacroInfo *MI) { if (!MI || MI->isBuiltinMacro()) return 0; assert(MacroIDs.contains(MI) && "Macro not emitted!"); return MacroIDs[MI]; } uint32_t ASTWriter::getMacroDirectivesOffset(const IdentifierInfo *Name) { return IdentMacroDirectivesOffsetMap.lookup(Name); } void ASTRecordWriter::AddSelectorRef(const Selector SelRef) { Record->push_back(Writer->getSelectorRef(SelRef)); } SelectorID ASTWriter::getSelectorRef(Selector Sel) { if (Sel.getAsOpaquePtr() == nullptr) { return 0; } SelectorID SID = SelectorIDs[Sel]; if (SID == 0 && Chain) { // This might trigger a ReadSelector callback, which will set the ID for // this selector. Chain->LoadSelector(Sel); SID = SelectorIDs[Sel]; } if (SID == 0) { SID = NextSelectorID++; SelectorIDs[Sel] = SID; } return SID; } void ASTRecordWriter::AddCXXTemporary(const CXXTemporary *Temp) { AddDeclRef(Temp->getDestructor()); } void ASTRecordWriter::AddTemplateArgumentLocInfo( TemplateArgument::ArgKind Kind, const TemplateArgumentLocInfo &Arg) { switch (Kind) { case TemplateArgument::Expression: AddStmt(Arg.getAsExpr()); break; case TemplateArgument::Type: AddTypeSourceInfo(Arg.getAsTypeSourceInfo()); break; case TemplateArgument::Template: AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc()); AddSourceLocation(Arg.getTemplateNameLoc()); break; case TemplateArgument::TemplateExpansion: AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc()); AddSourceLocation(Arg.getTemplateNameLoc()); AddSourceLocation(Arg.getTemplateEllipsisLoc()); break; case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: case TemplateArgument::NullPtr: case TemplateArgument::StructuralValue: case TemplateArgument::Pack: // FIXME: Is this right? break; } } void ASTRecordWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg) { AddTemplateArgument(Arg.getArgument()); if (Arg.getArgument().getKind() == TemplateArgument::Expression) { bool InfoHasSameExpr = Arg.getArgument().getAsExpr() == Arg.getLocInfo().getAsExpr(); Record->push_back(InfoHasSameExpr); if (InfoHasSameExpr) return; // Avoid storing the same expr twice. } AddTemplateArgumentLocInfo(Arg.getArgument().getKind(), Arg.getLocInfo()); } void ASTRecordWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo) { if (!TInfo) { AddTypeRef(QualType()); return; } AddTypeRef(TInfo->getType()); AddTypeLoc(TInfo->getTypeLoc()); } void ASTRecordWriter::AddTypeLoc(TypeLoc TL, LocSeq *OuterSeq) { LocSeq::State Seq(OuterSeq); TypeLocWriter TLW(*this, Seq); for (; !TL.isNull(); TL = TL.getNextTypeLoc()) TLW.Visit(TL); } void ASTWriter::AddTypeRef(QualType T, RecordDataImpl &Record) { Record.push_back(GetOrCreateTypeID(T)); } template static TypeID MakeTypeID(ASTContext &Context, QualType T, IdxForTypeTy IdxForType) { if (T.isNull()) return PREDEF_TYPE_NULL_ID; unsigned FastQuals = T.getLocalFastQualifiers(); T.removeLocalFastQualifiers(); if (T.hasLocalNonFastQualifiers()) return IdxForType(T).asTypeID(FastQuals); assert(!T.hasLocalQualifiers()); if (const BuiltinType *BT = dyn_cast(T.getTypePtr())) return TypeIdxFromBuiltin(BT).asTypeID(FastQuals); if (T == Context.AutoDeductTy) return TypeIdx(0, PREDEF_TYPE_AUTO_DEDUCT).asTypeID(FastQuals); if (T == Context.AutoRRefDeductTy) return TypeIdx(0, PREDEF_TYPE_AUTO_RREF_DEDUCT).asTypeID(FastQuals); return IdxForType(T).asTypeID(FastQuals); } TypeID ASTWriter::GetOrCreateTypeID(QualType T) { assert(Context); return MakeTypeID(*Context, T, [&](QualType T) -> TypeIdx { if (T.isNull()) return TypeIdx(); assert(!T.getLocalFastQualifiers()); TypeIdx &Idx = TypeIdxs[T]; if (Idx.getValue() == 0) { if (DoneWritingDeclsAndTypes) { assert(0 && "New type seen after serializing all the types to emit!"); return TypeIdx(); } // We haven't seen this type before. Assign it a new ID and put it // into the queue of types to emit. Idx = TypeIdx(0, NextTypeID++); DeclTypesToEmit.push(T); } return Idx; }); } void ASTWriter::AddEmittedDeclRef(const Decl *D, RecordDataImpl &Record) { if (!wasDeclEmitted(D)) return; AddDeclRef(D, Record); } void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) { Record.push_back(GetDeclRef(D).getRawValue()); } LocalDeclID ASTWriter::GetDeclRef(const Decl *D) { assert(WritingAST && "Cannot request a declaration ID before AST writing"); if (!D) { return LocalDeclID(); } // If the DeclUpdate from the GMF gets touched, emit it. if (auto *Iter = DeclUpdatesFromGMF.find(D); Iter != DeclUpdatesFromGMF.end()) { for (DeclUpdate &Update : Iter->second) DeclUpdates[D].push_back(Update); DeclUpdatesFromGMF.erase(Iter); } // If D comes from an AST file, its declaration ID is already known and // fixed. if (D->isFromASTFile()) { if (isWritingStdCXXNamedModules() && D->getOwningModule()) TouchedTopLevelModules.insert(D->getOwningModule()->getTopLevelModule()); return LocalDeclID(D->getGlobalID()); } assert(!(reinterpret_cast(D) & 0x01) && "Invalid decl pointer"); LocalDeclID &ID = DeclIDs[D]; if (ID.isInvalid()) { if (DoneWritingDeclsAndTypes) { assert(0 && "New decl seen after serializing all the decls to emit!"); return LocalDeclID(); } // We haven't seen this declaration before. Give it a new ID and // enqueue it in the list of declarations to emit. ID = NextDeclID++; DeclTypesToEmit.push(const_cast(D)); } return ID; } LocalDeclID ASTWriter::getDeclID(const Decl *D) { if (!D) return LocalDeclID(); // If D comes from an AST file, its declaration ID is already known and // fixed. if (D->isFromASTFile()) return LocalDeclID(D->getGlobalID()); assert(DeclIDs.contains(D) && "Declaration not emitted!"); return DeclIDs[D]; } bool ASTWriter::wasDeclEmitted(const Decl *D) const { assert(D); assert(DoneWritingDeclsAndTypes && "wasDeclEmitted should only be called after writing declarations"); if (D->isFromASTFile()) return true; bool Emitted = DeclIDs.contains(D); assert((Emitted || (!D->getOwningModule() && isWritingStdCXXNamedModules()) || GeneratingReducedBMI) && "The declaration within modules can only be omitted in reduced BMI."); return Emitted; } void ASTWriter::associateDeclWithFile(const Decl *D, LocalDeclID ID) { assert(ID.isValid()); assert(D); SourceLocation Loc = D->getLocation(); if (Loc.isInvalid()) return; // We only keep track of the file-level declarations of each file. if (!D->getLexicalDeclContext()->isFileContext()) return; // FIXME: ParmVarDecls that are part of a function type of a parameter of // a function/objc method, should not have TU as lexical context. // TemplateTemplateParmDecls that are part of an alias template, should not // have TU as lexical context. if (isa(D)) return; SourceManager &SM = Context->getSourceManager(); SourceLocation FileLoc = SM.getFileLoc(Loc); assert(SM.isLocalSourceLocation(FileLoc)); FileID FID; unsigned Offset; std::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc); if (FID.isInvalid()) return; assert(SM.getSLocEntry(FID).isFile()); assert(IsSLocAffecting[FID.ID]); std::unique_ptr &Info = FileDeclIDs[FID]; if (!Info) Info = std::make_unique(); std::pair LocDecl(Offset, ID); LocDeclIDsTy &Decls = Info->DeclIDs; Decls.push_back(LocDecl); } unsigned ASTWriter::getAnonymousDeclarationNumber(const NamedDecl *D) { assert(needsAnonymousDeclarationNumber(D) && "expected an anonymous declaration"); // Number the anonymous declarations within this context, if we've not // already done so. auto It = AnonymousDeclarationNumbers.find(D); if (It == AnonymousDeclarationNumbers.end()) { auto *DC = D->getLexicalDeclContext(); numberAnonymousDeclsWithin(DC, [&](const NamedDecl *ND, unsigned Number) { AnonymousDeclarationNumbers[ND] = Number; }); It = AnonymousDeclarationNumbers.find(D); assert(It != AnonymousDeclarationNumbers.end() && "declaration not found within its lexical context"); } return It->second; } void ASTRecordWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc, DeclarationName Name) { switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: AddTypeSourceInfo(DNLoc.getNamedTypeInfo()); break; case DeclarationName::CXXOperatorName: AddSourceRange(DNLoc.getCXXOperatorNameRange()); break; case DeclarationName::CXXLiteralOperatorName: AddSourceLocation(DNLoc.getCXXLiteralOperatorNameLoc()); break; case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: case DeclarationName::CXXDeductionGuideName: break; } } void ASTRecordWriter::AddDeclarationNameInfo( const DeclarationNameInfo &NameInfo) { AddDeclarationName(NameInfo.getName()); AddSourceLocation(NameInfo.getLoc()); AddDeclarationNameLoc(NameInfo.getInfo(), NameInfo.getName()); } void ASTRecordWriter::AddQualifierInfo(const QualifierInfo &Info) { AddNestedNameSpecifierLoc(Info.QualifierLoc); Record->push_back(Info.NumTemplParamLists); for (unsigned i = 0, e = Info.NumTemplParamLists; i != e; ++i) AddTemplateParameterList(Info.TemplParamLists[i]); } void ASTRecordWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { // Nested name specifiers usually aren't too long. I think that 8 would // typically accommodate the vast majority. SmallVector NestedNames; // Push each of the nested-name-specifiers's onto a stack for // serialization in reverse order. while (NNS) { NestedNames.push_back(NNS); NNS = NNS.getPrefix(); } Record->push_back(NestedNames.size()); while(!NestedNames.empty()) { NNS = NestedNames.pop_back_val(); NestedNameSpecifier::SpecifierKind Kind = NNS.getNestedNameSpecifier()->getKind(); Record->push_back(Kind); switch (Kind) { case NestedNameSpecifier::Identifier: AddIdentifierRef(NNS.getNestedNameSpecifier()->getAsIdentifier()); AddSourceRange(NNS.getLocalSourceRange()); break; case NestedNameSpecifier::Namespace: AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespace()); AddSourceRange(NNS.getLocalSourceRange()); break; case NestedNameSpecifier::NamespaceAlias: AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespaceAlias()); AddSourceRange(NNS.getLocalSourceRange()); break; case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: Record->push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate); AddTypeRef(NNS.getTypeLoc().getType()); AddTypeLoc(NNS.getTypeLoc()); AddSourceLocation(NNS.getLocalSourceRange().getEnd()); break; case NestedNameSpecifier::Global: AddSourceLocation(NNS.getLocalSourceRange().getEnd()); break; case NestedNameSpecifier::Super: AddDeclRef(NNS.getNestedNameSpecifier()->getAsRecordDecl()); AddSourceRange(NNS.getLocalSourceRange()); break; } } } void ASTRecordWriter::AddTemplateParameterList( const TemplateParameterList *TemplateParams) { assert(TemplateParams && "No TemplateParams!"); AddSourceLocation(TemplateParams->getTemplateLoc()); AddSourceLocation(TemplateParams->getLAngleLoc()); AddSourceLocation(TemplateParams->getRAngleLoc()); Record->push_back(TemplateParams->size()); for (const auto &P : *TemplateParams) AddDeclRef(P); if (const Expr *RequiresClause = TemplateParams->getRequiresClause()) { Record->push_back(true); writeStmtRef(RequiresClause); } else { Record->push_back(false); } } /// Emit a template argument list. void ASTRecordWriter::AddTemplateArgumentList( const TemplateArgumentList *TemplateArgs) { assert(TemplateArgs && "No TemplateArgs!"); Record->push_back(TemplateArgs->size()); for (int i = 0, e = TemplateArgs->size(); i != e; ++i) AddTemplateArgument(TemplateArgs->get(i)); } void ASTRecordWriter::AddASTTemplateArgumentListInfo( const ASTTemplateArgumentListInfo *ASTTemplArgList) { assert(ASTTemplArgList && "No ASTTemplArgList!"); AddSourceLocation(ASTTemplArgList->LAngleLoc); AddSourceLocation(ASTTemplArgList->RAngleLoc); Record->push_back(ASTTemplArgList->NumTemplateArgs); const TemplateArgumentLoc *TemplArgs = ASTTemplArgList->getTemplateArgs(); for (int i = 0, e = ASTTemplArgList->NumTemplateArgs; i != e; ++i) AddTemplateArgumentLoc(TemplArgs[i]); } void ASTRecordWriter::AddUnresolvedSet(const ASTUnresolvedSet &Set) { Record->push_back(Set.size()); for (ASTUnresolvedSet::const_iterator I = Set.begin(), E = Set.end(); I != E; ++I) { AddDeclRef(I.getDecl()); Record->push_back(I.getAccess()); } } // FIXME: Move this out of the main ASTRecordWriter interface. void ASTRecordWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base) { Record->push_back(Base.isVirtual()); Record->push_back(Base.isBaseOfClass()); Record->push_back(Base.getAccessSpecifierAsWritten()); Record->push_back(Base.getInheritConstructors()); AddTypeSourceInfo(Base.getTypeSourceInfo()); AddSourceRange(Base.getSourceRange()); AddSourceLocation(Base.isPackExpansion()? Base.getEllipsisLoc() : SourceLocation()); } static uint64_t EmitCXXBaseSpecifiers(ASTWriter &W, ArrayRef Bases) { ASTWriter::RecordData Record; ASTRecordWriter Writer(W, Record); Writer.push_back(Bases.size()); for (auto &Base : Bases) Writer.AddCXXBaseSpecifier(Base); return Writer.Emit(serialization::DECL_CXX_BASE_SPECIFIERS); } // FIXME: Move this out of the main ASTRecordWriter interface. void ASTRecordWriter::AddCXXBaseSpecifiers(ArrayRef Bases) { AddOffset(EmitCXXBaseSpecifiers(*Writer, Bases)); } static uint64_t EmitCXXCtorInitializers(ASTWriter &W, ArrayRef CtorInits) { ASTWriter::RecordData Record; ASTRecordWriter Writer(W, Record); Writer.push_back(CtorInits.size()); for (auto *Init : CtorInits) { if (Init->isBaseInitializer()) { Writer.push_back(CTOR_INITIALIZER_BASE); Writer.AddTypeSourceInfo(Init->getTypeSourceInfo()); Writer.push_back(Init->isBaseVirtual()); } else if (Init->isDelegatingInitializer()) { Writer.push_back(CTOR_INITIALIZER_DELEGATING); Writer.AddTypeSourceInfo(Init->getTypeSourceInfo()); } else if (Init->isMemberInitializer()){ Writer.push_back(CTOR_INITIALIZER_MEMBER); Writer.AddDeclRef(Init->getMember()); } else { Writer.push_back(CTOR_INITIALIZER_INDIRECT_MEMBER); Writer.AddDeclRef(Init->getIndirectMember()); } Writer.AddSourceLocation(Init->getMemberLocation()); Writer.AddStmt(Init->getInit()); Writer.AddSourceLocation(Init->getLParenLoc()); Writer.AddSourceLocation(Init->getRParenLoc()); Writer.push_back(Init->isWritten()); if (Init->isWritten()) Writer.push_back(Init->getSourceOrder()); } return Writer.Emit(serialization::DECL_CXX_CTOR_INITIALIZERS); } // FIXME: Move this out of the main ASTRecordWriter interface. void ASTRecordWriter::AddCXXCtorInitializers( ArrayRef CtorInits) { AddOffset(EmitCXXCtorInitializers(*Writer, CtorInits)); } void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { auto &Data = D->data(); Record->push_back(Data.IsLambda); BitsPacker DefinitionBits; #define FIELD(Name, Width, Merge) \ if (!DefinitionBits.canWriteNextNBits(Width)) { \ Record->push_back(DefinitionBits); \ DefinitionBits.reset(0); \ } \ DefinitionBits.addBits(Data.Name, Width); #include "clang/AST/CXXRecordDeclDefinitionBits.def" #undef FIELD Record->push_back(DefinitionBits); // getODRHash will compute the ODRHash if it has not been previously // computed. Record->push_back(D->getODRHash()); bool ModulesCodegen = !D->isDependentType() && (Writer->Context->getLangOpts().ModulesDebugInfo || D->isInNamedModule()); Record->push_back(ModulesCodegen); if (ModulesCodegen) Writer->AddDeclRef(D, Writer->ModularCodegenDecls); // IsLambda bit is already saved. AddUnresolvedSet(Data.Conversions.get(*Writer->Context)); Record->push_back(Data.ComputedVisibleConversions); if (Data.ComputedVisibleConversions) AddUnresolvedSet(Data.VisibleConversions.get(*Writer->Context)); // Data.Definition is the owning decl, no need to write it. if (!Data.IsLambda) { Record->push_back(Data.NumBases); if (Data.NumBases > 0) AddCXXBaseSpecifiers(Data.bases()); // FIXME: Make VBases lazily computed when needed to avoid storing them. Record->push_back(Data.NumVBases); if (Data.NumVBases > 0) AddCXXBaseSpecifiers(Data.vbases()); AddDeclRef(D->getFirstFriend()); } else { auto &Lambda = D->getLambdaData(); BitsPacker LambdaBits; LambdaBits.addBits(Lambda.DependencyKind, /*Width=*/2); LambdaBits.addBit(Lambda.IsGenericLambda); LambdaBits.addBits(Lambda.CaptureDefault, /*Width=*/2); LambdaBits.addBits(Lambda.NumCaptures, /*Width=*/15); LambdaBits.addBit(Lambda.HasKnownInternalLinkage); Record->push_back(LambdaBits); Record->push_back(Lambda.NumExplicitCaptures); Record->push_back(Lambda.ManglingNumber); Record->push_back(D->getDeviceLambdaManglingNumber()); // The lambda context declaration and index within the context are provided // separately, so that they can be used for merging. AddTypeSourceInfo(Lambda.MethodTyInfo); for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { const LambdaCapture &Capture = Lambda.Captures.front()[I]; AddSourceLocation(Capture.getLocation()); BitsPacker CaptureBits; CaptureBits.addBit(Capture.isImplicit()); CaptureBits.addBits(Capture.getCaptureKind(), /*Width=*/3); Record->push_back(CaptureBits); switch (Capture.getCaptureKind()) { case LCK_StarThis: case LCK_This: case LCK_VLAType: break; case LCK_ByCopy: case LCK_ByRef: ValueDecl *Var = Capture.capturesVariable() ? Capture.getCapturedVar() : nullptr; AddDeclRef(Var); AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc() : SourceLocation()); break; } } } } void ASTRecordWriter::AddVarDeclInit(const VarDecl *VD) { const Expr *Init = VD->getInit(); if (!Init) { push_back(0); return; } uint64_t Val = 1; if (EvaluatedStmt *ES = VD->getEvaluatedStmt()) { Val |= (ES->HasConstantInitialization ? 2 : 0); Val |= (ES->HasConstantDestruction ? 4 : 0); APValue *Evaluated = VD->getEvaluatedValue(); // If the evaluated result is constant, emit it. if (Evaluated && (Evaluated->isInt() || Evaluated->isFloat())) Val |= 8; } push_back(Val); if (Val & 8) { AddAPValue(*VD->getEvaluatedValue()); } writeStmtRef(Init); } void ASTWriter::ReaderInitialized(ASTReader *Reader) { assert(Reader && "Cannot remove chain"); assert((!Chain || Chain == Reader) && "Cannot replace chain"); assert(FirstDeclID == NextDeclID && FirstTypeID == NextTypeID && FirstIdentID == NextIdentID && FirstMacroID == NextMacroID && FirstSubmoduleID == NextSubmoduleID && FirstSelectorID == NextSelectorID && "Setting chain after writing has started."); Chain = Reader; // Note, this will get called multiple times, once one the reader starts up // and again each time it's done reading a PCH or module. FirstMacroID = NUM_PREDEF_MACRO_IDS + Chain->getTotalNumMacros(); FirstSubmoduleID = NUM_PREDEF_SUBMODULE_IDS + Chain->getTotalNumSubmodules(); FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors(); NextMacroID = FirstMacroID; NextSelectorID = FirstSelectorID; NextSubmoduleID = FirstSubmoduleID; } void ASTWriter::IdentifierRead(IdentifierID ID, IdentifierInfo *II) { // Don't reuse Type ID from external modules for named modules. See the // comments in WriteASTCore for details. if (isWritingStdCXXNamedModules()) return; IdentifierID &StoredID = IdentifierIDs[II]; unsigned OriginalModuleFileIndex = StoredID >> 32; // Always keep the local identifier ID. See \p TypeRead() for more // information. if (OriginalModuleFileIndex == 0 && StoredID) return; // Otherwise, keep the highest ID since the module file comes later has // higher module file indexes. if (ID > StoredID) StoredID = ID; } void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) { // Always keep the highest ID. See \p TypeRead() for more information. MacroID &StoredID = MacroIDs[MI]; if (ID > StoredID) StoredID = ID; } void ASTWriter::TypeRead(TypeIdx Idx, QualType T) { // Don't reuse Type ID from external modules for named modules. See the // comments in WriteASTCore for details. if (isWritingStdCXXNamedModules()) return; // Always take the type index that comes in later module files. // This copes with an interesting // case for chained AST writing where we schedule writing the type and then, // later, deserialize the type from another AST. In this case, we want to // keep the entry from a later module so that we can properly write it out to // the AST file. TypeIdx &StoredIdx = TypeIdxs[T]; // Ignore it if the type comes from the current being written module file. // Since the current module file being written logically has the highest // index. unsigned ModuleFileIndex = StoredIdx.getModuleFileIndex(); if (ModuleFileIndex == 0 && StoredIdx.getValue()) return; // Otherwise, keep the highest ID since the module file comes later has // higher module file indexes. if (Idx.getModuleFileIndex() >= StoredIdx.getModuleFileIndex()) StoredIdx = Idx; } +void ASTWriter::PredefinedDeclBuilt(PredefinedDeclIDs ID, const Decl *D) { + assert(D->isCanonicalDecl() && "predefined decl is not canonical"); + DeclIDs[D] = LocalDeclID(ID); + PredefinedDecls.insert(D); +} + void ASTWriter::SelectorRead(SelectorID ID, Selector S) { // Always keep the highest ID. See \p TypeRead() for more information. SelectorID &StoredID = SelectorIDs[S]; if (ID > StoredID) StoredID = ID; } void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID, MacroDefinitionRecord *MD) { assert(!MacroDefinitions.contains(MD)); MacroDefinitions[MD] = ID; } void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) { assert(!SubmoduleIDs.contains(Mod)); SubmoduleIDs[Mod] = ID; } void ASTWriter::CompletedTagDefinition(const TagDecl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(D->isCompleteDefinition()); assert(!WritingAST && "Already writing the AST!"); if (auto *RD = dyn_cast(D)) { // We are interested when a PCH decl is modified. if (RD->isFromASTFile()) { // A forward reference was mutated into a definition. Rewrite it. // FIXME: This happens during template instantiation, should we // have created a new definition decl instead ? assert(isTemplateInstantiation(RD->getTemplateSpecializationKind()) && "completed a tag from another module but not by instantiation?"); DeclUpdates[RD].push_back( DeclUpdate(UPD_CXX_INSTANTIATED_CLASS_DEFINITION)); } } } static bool isImportedDeclContext(ASTReader *Chain, const Decl *D) { if (D->isFromASTFile()) return true; // The predefined __va_list_tag struct is imported if we imported any decls. // FIXME: This is a gross hack. return D == D->getASTContext().getVaListTagDecl(); } void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(DC->isLookupContext() && "Should not add lookup results to non-lookup contexts!"); // TU is handled elsewhere. if (isa(DC)) return; // Namespaces are handled elsewhere, except for template instantiations of // FunctionTemplateDecls in namespaces. We are interested in cases where the // local instantiations are added to an imported context. Only happens when // adding ADL lookup candidates, for example templated friends. if (isa(DC) && D->getFriendObjectKind() == Decl::FOK_None && !isa(D)) return; // We're only interested in cases where a local declaration is added to an // imported context. if (D->isFromASTFile() || !isImportedDeclContext(Chain, cast(DC))) return; assert(DC == DC->getPrimaryContext() && "added to non-primary context"); assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!"); assert(!WritingAST && "Already writing the AST!"); if (UpdatedDeclContexts.insert(DC) && !cast(DC)->isFromASTFile()) { // We're adding a visible declaration to a predefined decl context. Ensure // that we write out all of its lookup results so we don't get a nasty // surprise when we try to emit its lookup table. llvm::append_range(DeclsToEmitEvenIfUnreferenced, DC->decls()); } DeclsToEmitEvenIfUnreferenced.push_back(D); } void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(D->isImplicit()); // We're only interested in cases where a local declaration is added to an // imported context. if (D->isFromASTFile() || !isImportedDeclContext(Chain, RD)) return; if (!isa(D)) return; // A decl coming from PCH was modified. assert(RD->isCompleteDefinition()); assert(!WritingAST && "Already writing the AST!"); DeclUpdates[RD].push_back(DeclUpdate(UPD_CXX_ADDED_IMPLICIT_MEMBER, D)); } void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!DoneWritingDeclsAndTypes && "Already done writing updates!"); if (!Chain) return; Chain->forEachImportedKeyDecl(FD, [&](const Decl *D) { // If we don't already know the exception specification for this redecl // chain, add an update record for it. if (isUnresolvedExceptionSpec(cast(D) ->getType() ->castAs() ->getExceptionSpecType())) DeclUpdates[D].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC); }); } void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!Chain) return; Chain->forEachImportedKeyDecl(FD, [&](const Decl *D) { DeclUpdates[D].push_back( DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType)); }); } void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD, const FunctionDecl *Delete, Expr *ThisArg) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); assert(Delete && "Not given an operator delete"); if (!Chain) return; Chain->forEachImportedKeyDecl(DD, [&](const Decl *D) { DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete)); }); } void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; // Declaration not imported from PCH. // Implicit function decl from a PCH was defined. DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); } void ASTWriter::VariableDefinitionInstantiated(const VarDecl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_VAR_DEFINITION)); } void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION)); } void ASTWriter::InstantiationRequested(const ValueDecl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; // Since the actual instantiation is delayed, this really means that we need // to update the instantiation location. SourceLocation POI; if (auto *VD = dyn_cast(D)) POI = VD->getPointOfInstantiation(); else POI = cast(D)->getPointOfInstantiation(); DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_POINT_OF_INSTANTIATION, POI)); } void ASTWriter::DefaultArgumentInstantiated(const ParmVarDecl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; DeclUpdates[D].push_back( DeclUpdate(UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT, D)); } void ASTWriter::DefaultMemberInitializerInstantiated(const FieldDecl *D) { assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; DeclUpdates[D].push_back( DeclUpdate(UPD_CXX_INSTANTIATED_DEFAULT_MEMBER_INITIALIZER, D)); } void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, const ObjCInterfaceDecl *IFD) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!IFD->isFromASTFile()) return; // Declaration not imported from PCH. assert(IFD->getDefinition() && "Category on a class without a definition?"); ObjCClassesWithCategories.insert( const_cast(IFD->getDefinition())); } void ASTWriter::DeclarationMarkedUsed(const Decl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); // If there is *any* declaration of the entity that's not from an AST file, // we can skip writing the update record. We make sure that isUsed() triggers // completion of the redeclaration chain of the entity. for (auto Prev = D->getMostRecentDecl(); Prev; Prev = Prev->getPreviousDecl()) if (IsLocalDecl(Prev)) return; DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_USED)); } void ASTWriter::DeclarationMarkedOpenMPThreadPrivate(const Decl *D) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE)); } void ASTWriter::DeclarationMarkedOpenMPAllocate(const Decl *D, const Attr *A) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_ALLOCATE, A)); } void ASTWriter::DeclarationMarkedOpenMPDeclareTarget(const Decl *D, const Attr *Attr) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!D->isFromASTFile()) return; DeclUpdates[D].push_back( DeclUpdate(UPD_DECL_MARKED_OPENMP_DECLARETARGET, Attr)); } void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); assert(!D->isUnconditionallyVisible() && "expected a hidden declaration"); DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_EXPORTED, M)); } void ASTWriter::AddedAttributeToRecord(const Attr *Attr, const RecordDecl *Record) { if (Chain && Chain->isProcessingUpdateRecords()) return; assert(!WritingAST && "Already writing the AST!"); if (!Record->isFromASTFile()) return; DeclUpdates[Record].push_back(DeclUpdate(UPD_ADDED_ATTR_TO_RECORD, Attr)); } void ASTWriter::AddedCXXTemplateSpecialization( const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) { assert(!WritingAST && "Already writing the AST!"); if (!TD->getFirstDecl()->isFromASTFile()) return; if (Chain && Chain->isProcessingUpdateRecords()) return; DeclsToEmitEvenIfUnreferenced.push_back(D); } void ASTWriter::AddedCXXTemplateSpecialization( const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) { assert(!WritingAST && "Already writing the AST!"); if (!TD->getFirstDecl()->isFromASTFile()) return; if (Chain && Chain->isProcessingUpdateRecords()) return; DeclsToEmitEvenIfUnreferenced.push_back(D); } void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, const FunctionDecl *D) { assert(!WritingAST && "Already writing the AST!"); if (!TD->getFirstDecl()->isFromASTFile()) return; if (Chain && Chain->isProcessingUpdateRecords()) return; DeclsToEmitEvenIfUnreferenced.push_back(D); } //===----------------------------------------------------------------------===// //// OMPClause Serialization ////===----------------------------------------------------------------------===// namespace { class OMPClauseWriter : public OMPClauseVisitor { ASTRecordWriter &Record; public: OMPClauseWriter(ASTRecordWriter &Record) : Record(Record) {} #define GEN_CLANG_CLAUSE_CLASS #define CLAUSE_CLASS(Enum, Str, Class) void Visit##Class(Class *S); #include "llvm/Frontend/OpenMP/OMP.inc" void writeClause(OMPClause *C); void VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C); void VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C); }; } void ASTRecordWriter::writeOMPClause(OMPClause *C) { OMPClauseWriter(*this).writeClause(C); } void OMPClauseWriter::writeClause(OMPClause *C) { Record.push_back(unsigned(C->getClauseKind())); Visit(C); Record.AddSourceLocation(C->getBeginLoc()); Record.AddSourceLocation(C->getEndLoc()); } void OMPClauseWriter::VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C) { Record.push_back(uint64_t(C->getCaptureRegion())); Record.AddStmt(C->getPreInitStmt()); } void OMPClauseWriter::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) { VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getPostUpdateExpr()); } void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) { VisitOMPClauseWithPreInit(C); Record.push_back(uint64_t(C->getNameModifier())); Record.AddSourceLocation(C->getNameModifierLoc()); Record.AddSourceLocation(C->getColonLoc()); Record.AddStmt(C->getCondition()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPFinalClause(OMPFinalClause *C) { VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getCondition()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getNumThreads()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPSafelenClause(OMPSafelenClause *C) { Record.AddStmt(C->getSafelen()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPSimdlenClause(OMPSimdlenClause *C) { Record.AddStmt(C->getSimdlen()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPSizesClause(OMPSizesClause *C) { Record.push_back(C->getNumSizes()); for (Expr *Size : C->getSizesRefs()) Record.AddStmt(Size); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPFullClause(OMPFullClause *C) {} void OMPClauseWriter::VisitOMPPartialClause(OMPPartialClause *C) { Record.AddStmt(C->getFactor()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPAllocatorClause(OMPAllocatorClause *C) { Record.AddStmt(C->getAllocator()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPCollapseClause(OMPCollapseClause *C) { Record.AddStmt(C->getNumForLoops()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPDetachClause(OMPDetachClause *C) { Record.AddStmt(C->getEventHandler()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) { Record.push_back(unsigned(C->getDefaultKind())); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getDefaultKindKwLoc()); } void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) { Record.push_back(unsigned(C->getProcBindKind())); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getProcBindKindKwLoc()); } void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) { VisitOMPClauseWithPreInit(C); Record.push_back(C->getScheduleKind()); Record.push_back(C->getFirstScheduleModifier()); Record.push_back(C->getSecondScheduleModifier()); Record.AddStmt(C->getChunkSize()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getFirstScheduleModifierLoc()); Record.AddSourceLocation(C->getSecondScheduleModifierLoc()); Record.AddSourceLocation(C->getScheduleKindLoc()); Record.AddSourceLocation(C->getCommaLoc()); } void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *C) { Record.push_back(C->getLoopNumIterations().size()); Record.AddStmt(C->getNumForLoops()); for (Expr *NumIter : C->getLoopNumIterations()) Record.AddStmt(NumIter); for (unsigned I = 0, E = C->getLoopNumIterations().size(); I getLoopCounter(I)); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPNowaitClause(OMPNowaitClause *) {} void OMPClauseWriter::VisitOMPUntiedClause(OMPUntiedClause *) {} void OMPClauseWriter::VisitOMPMergeableClause(OMPMergeableClause *) {} void OMPClauseWriter::VisitOMPReadClause(OMPReadClause *) {} void OMPClauseWriter::VisitOMPWriteClause(OMPWriteClause *) {} void OMPClauseWriter::VisitOMPUpdateClause(OMPUpdateClause *C) { Record.push_back(C->isExtended() ? 1 : 0); if (C->isExtended()) { Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getArgumentLoc()); Record.writeEnum(C->getDependencyKind()); } } void OMPClauseWriter::VisitOMPCaptureClause(OMPCaptureClause *) {} void OMPClauseWriter::VisitOMPCompareClause(OMPCompareClause *) {} // Save the parameter of fail clause. void OMPClauseWriter::VisitOMPFailClause(OMPFailClause *C) { Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getFailParameterLoc()); Record.writeEnum(C->getFailParameter()); } void OMPClauseWriter::VisitOMPSeqCstClause(OMPSeqCstClause *) {} void OMPClauseWriter::VisitOMPAcqRelClause(OMPAcqRelClause *) {} void OMPClauseWriter::VisitOMPAcquireClause(OMPAcquireClause *) {} void OMPClauseWriter::VisitOMPReleaseClause(OMPReleaseClause *) {} void OMPClauseWriter::VisitOMPRelaxedClause(OMPRelaxedClause *) {} void OMPClauseWriter::VisitOMPWeakClause(OMPWeakClause *) {} void OMPClauseWriter::VisitOMPThreadsClause(OMPThreadsClause *) {} void OMPClauseWriter::VisitOMPSIMDClause(OMPSIMDClause *) {} void OMPClauseWriter::VisitOMPNogroupClause(OMPNogroupClause *) {} void OMPClauseWriter::VisitOMPInitClause(OMPInitClause *C) { Record.push_back(C->varlist_size()); for (Expr *VE : C->varlists()) Record.AddStmt(VE); Record.writeBool(C->getIsTarget()); Record.writeBool(C->getIsTargetSync()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getVarLoc()); } void OMPClauseWriter::VisitOMPUseClause(OMPUseClause *C) { Record.AddStmt(C->getInteropVar()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getVarLoc()); } void OMPClauseWriter::VisitOMPDestroyClause(OMPDestroyClause *C) { Record.AddStmt(C->getInteropVar()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getVarLoc()); } void OMPClauseWriter::VisitOMPNovariantsClause(OMPNovariantsClause *C) { VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getCondition()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPNocontextClause(OMPNocontextClause *C) { VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getCondition()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPFilterClause(OMPFilterClause *C) { VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getThreadID()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPAlignClause(OMPAlignClause *C) { Record.AddStmt(C->getAlignment()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *VE : C->varlists()) { Record.AddStmt(VE); } for (auto *VE : C->private_copies()) { Record.AddStmt(VE); } } void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { Record.push_back(C->varlist_size()); VisitOMPClauseWithPreInit(C); Record.AddSourceLocation(C->getLParenLoc()); for (auto *VE : C->varlists()) { Record.AddStmt(VE); } for (auto *VE : C->private_copies()) { Record.AddStmt(VE); } for (auto *VE : C->inits()) { Record.AddStmt(VE); } } void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) { Record.push_back(C->varlist_size()); VisitOMPClauseWithPostUpdate(C); Record.AddSourceLocation(C->getLParenLoc()); Record.writeEnum(C->getKind()); Record.AddSourceLocation(C->getKindLoc()); Record.AddSourceLocation(C->getColonLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); for (auto *E : C->private_copies()) Record.AddStmt(E); for (auto *E : C->source_exprs()) Record.AddStmt(E); for (auto *E : C->destination_exprs()) Record.AddStmt(E); for (auto *E : C->assignment_ops()) Record.AddStmt(E); } void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); } void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) { Record.push_back(C->varlist_size()); Record.writeEnum(C->getModifier()); VisitOMPClauseWithPostUpdate(C); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getModifierLoc()); Record.AddSourceLocation(C->getColonLoc()); Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); Record.AddDeclarationNameInfo(C->getNameInfo()); for (auto *VE : C->varlists()) Record.AddStmt(VE); for (auto *VE : C->privates()) Record.AddStmt(VE); for (auto *E : C->lhs_exprs()) Record.AddStmt(E); for (auto *E : C->rhs_exprs()) Record.AddStmt(E); for (auto *E : C->reduction_ops()) Record.AddStmt(E); if (C->getModifier() == clang::OMPC_REDUCTION_inscan) { for (auto *E : C->copy_ops()) Record.AddStmt(E); for (auto *E : C->copy_array_temps()) Record.AddStmt(E); for (auto *E : C->copy_array_elems()) Record.AddStmt(E); } } void OMPClauseWriter::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) { Record.push_back(C->varlist_size()); VisitOMPClauseWithPostUpdate(C); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getColonLoc()); Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); Record.AddDeclarationNameInfo(C->getNameInfo()); for (auto *VE : C->varlists()) Record.AddStmt(VE); for (auto *VE : C->privates()) Record.AddStmt(VE); for (auto *E : C->lhs_exprs()) Record.AddStmt(E); for (auto *E : C->rhs_exprs()) Record.AddStmt(E); for (auto *E : C->reduction_ops()) Record.AddStmt(E); } void OMPClauseWriter::VisitOMPInReductionClause(OMPInReductionClause *C) { Record.push_back(C->varlist_size()); VisitOMPClauseWithPostUpdate(C); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getColonLoc()); Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); Record.AddDeclarationNameInfo(C->getNameInfo()); for (auto *VE : C->varlists()) Record.AddStmt(VE); for (auto *VE : C->privates()) Record.AddStmt(VE); for (auto *E : C->lhs_exprs()) Record.AddStmt(E); for (auto *E : C->rhs_exprs()) Record.AddStmt(E); for (auto *E : C->reduction_ops()) Record.AddStmt(E); for (auto *E : C->taskgroup_descriptors()) Record.AddStmt(E); } void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) { Record.push_back(C->varlist_size()); VisitOMPClauseWithPostUpdate(C); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getColonLoc()); Record.push_back(C->getModifier()); Record.AddSourceLocation(C->getModifierLoc()); for (auto *VE : C->varlists()) { Record.AddStmt(VE); } for (auto *VE : C->privates()) { Record.AddStmt(VE); } for (auto *VE : C->inits()) { Record.AddStmt(VE); } for (auto *VE : C->updates()) { Record.AddStmt(VE); } for (auto *VE : C->finals()) { Record.AddStmt(VE); } Record.AddStmt(C->getStep()); Record.AddStmt(C->getCalcStep()); for (auto *VE : C->used_expressions()) Record.AddStmt(VE); } void OMPClauseWriter::VisitOMPAlignedClause(OMPAlignedClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getColonLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); Record.AddStmt(C->getAlignment()); } void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); for (auto *E : C->source_exprs()) Record.AddStmt(E); for (auto *E : C->destination_exprs()) Record.AddStmt(E); for (auto *E : C->assignment_ops()) Record.AddStmt(E); } void OMPClauseWriter::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); for (auto *E : C->source_exprs()) Record.AddStmt(E); for (auto *E : C->destination_exprs()) Record.AddStmt(E); for (auto *E : C->assignment_ops()) Record.AddStmt(E); } void OMPClauseWriter::VisitOMPFlushClause(OMPFlushClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); } void OMPClauseWriter::VisitOMPDepobjClause(OMPDepobjClause *C) { Record.AddStmt(C->getDepobj()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPDependClause(OMPDependClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getNumLoops()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddStmt(C->getModifier()); Record.push_back(C->getDependencyKind()); Record.AddSourceLocation(C->getDependencyLoc()); Record.AddSourceLocation(C->getColonLoc()); Record.AddSourceLocation(C->getOmpAllMemoryLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) Record.AddStmt(C->getLoopData(I)); } void OMPClauseWriter::VisitOMPDeviceClause(OMPDeviceClause *C) { VisitOMPClauseWithPreInit(C); Record.writeEnum(C->getModifier()); Record.AddStmt(C->getDevice()); Record.AddSourceLocation(C->getModifierLoc()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPMapClause(OMPMapClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getUniqueDeclarationsNum()); Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); bool HasIteratorModifier = false; for (unsigned I = 0; I < NumberOfOMPMapClauseModifiers; ++I) { Record.push_back(C->getMapTypeModifier(I)); Record.AddSourceLocation(C->getMapTypeModifierLoc(I)); if (C->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_iterator) HasIteratorModifier = true; } Record.AddNestedNameSpecifierLoc(C->getMapperQualifierLoc()); Record.AddDeclarationNameInfo(C->getMapperIdInfo()); Record.push_back(C->getMapType()); Record.AddSourceLocation(C->getMapLoc()); Record.AddSourceLocation(C->getColonLoc()); for (auto *E : C->varlists()) Record.AddStmt(E); for (auto *E : C->mapperlists()) Record.AddStmt(E); if (HasIteratorModifier) Record.AddStmt(C->getIteratorModifier()); for (auto *D : C->all_decls()) Record.AddDeclRef(D); for (auto N : C->all_num_lists()) Record.push_back(N); for (auto N : C->all_lists_sizes()) Record.push_back(N); for (auto &M : C->all_components()) { Record.AddStmt(M.getAssociatedExpression()); Record.AddDeclRef(M.getAssociatedDeclaration()); } } void OMPClauseWriter::VisitOMPAllocateClause(OMPAllocateClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getColonLoc()); Record.AddStmt(C->getAllocator()); for (auto *VE : C->varlists()) Record.AddStmt(VE); } void OMPClauseWriter::VisitOMPNumTeamsClause(OMPNumTeamsClause *C) { VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getNumTeams()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) { VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getThreadLimit()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPPriorityClause(OMPPriorityClause *C) { VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getPriority()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) { VisitOMPClauseWithPreInit(C); Record.writeEnum(C->getModifier()); Record.AddStmt(C->getGrainsize()); Record.AddSourceLocation(C->getModifierLoc()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPNumTasksClause(OMPNumTasksClause *C) { VisitOMPClauseWithPreInit(C); Record.writeEnum(C->getModifier()); Record.AddStmt(C->getNumTasks()); Record.AddSourceLocation(C->getModifierLoc()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPHintClause(OMPHintClause *C) { Record.AddStmt(C->getHint()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPDistScheduleClause(OMPDistScheduleClause *C) { VisitOMPClauseWithPreInit(C); Record.push_back(C->getDistScheduleKind()); Record.AddStmt(C->getChunkSize()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getDistScheduleKindLoc()); Record.AddSourceLocation(C->getCommaLoc()); } void OMPClauseWriter::VisitOMPDefaultmapClause(OMPDefaultmapClause *C) { Record.push_back(C->getDefaultmapKind()); Record.push_back(C->getDefaultmapModifier()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getDefaultmapModifierLoc()); Record.AddSourceLocation(C->getDefaultmapKindLoc()); } void OMPClauseWriter::VisitOMPToClause(OMPToClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getUniqueDeclarationsNum()); Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); for (unsigned I = 0; I < NumberOfOMPMotionModifiers; ++I) { Record.push_back(C->getMotionModifier(I)); Record.AddSourceLocation(C->getMotionModifierLoc(I)); } Record.AddNestedNameSpecifierLoc(C->getMapperQualifierLoc()); Record.AddDeclarationNameInfo(C->getMapperIdInfo()); Record.AddSourceLocation(C->getColonLoc()); for (auto *E : C->varlists()) Record.AddStmt(E); for (auto *E : C->mapperlists()) Record.AddStmt(E); for (auto *D : C->all_decls()) Record.AddDeclRef(D); for (auto N : C->all_num_lists()) Record.push_back(N); for (auto N : C->all_lists_sizes()) Record.push_back(N); for (auto &M : C->all_components()) { Record.AddStmt(M.getAssociatedExpression()); Record.writeBool(M.isNonContiguous()); Record.AddDeclRef(M.getAssociatedDeclaration()); } } void OMPClauseWriter::VisitOMPFromClause(OMPFromClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getUniqueDeclarationsNum()); Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); for (unsigned I = 0; I < NumberOfOMPMotionModifiers; ++I) { Record.push_back(C->getMotionModifier(I)); Record.AddSourceLocation(C->getMotionModifierLoc(I)); } Record.AddNestedNameSpecifierLoc(C->getMapperQualifierLoc()); Record.AddDeclarationNameInfo(C->getMapperIdInfo()); Record.AddSourceLocation(C->getColonLoc()); for (auto *E : C->varlists()) Record.AddStmt(E); for (auto *E : C->mapperlists()) Record.AddStmt(E); for (auto *D : C->all_decls()) Record.AddDeclRef(D); for (auto N : C->all_num_lists()) Record.push_back(N); for (auto N : C->all_lists_sizes()) Record.push_back(N); for (auto &M : C->all_components()) { Record.AddStmt(M.getAssociatedExpression()); Record.writeBool(M.isNonContiguous()); Record.AddDeclRef(M.getAssociatedDeclaration()); } } void OMPClauseWriter::VisitOMPUseDevicePtrClause(OMPUseDevicePtrClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getUniqueDeclarationsNum()); Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *E : C->varlists()) Record.AddStmt(E); for (auto *VE : C->private_copies()) Record.AddStmt(VE); for (auto *VE : C->inits()) Record.AddStmt(VE); for (auto *D : C->all_decls()) Record.AddDeclRef(D); for (auto N : C->all_num_lists()) Record.push_back(N); for (auto N : C->all_lists_sizes()) Record.push_back(N); for (auto &M : C->all_components()) { Record.AddStmt(M.getAssociatedExpression()); Record.AddDeclRef(M.getAssociatedDeclaration()); } } void OMPClauseWriter::VisitOMPUseDeviceAddrClause(OMPUseDeviceAddrClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getUniqueDeclarationsNum()); Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *E : C->varlists()) Record.AddStmt(E); for (auto *D : C->all_decls()) Record.AddDeclRef(D); for (auto N : C->all_num_lists()) Record.push_back(N); for (auto N : C->all_lists_sizes()) Record.push_back(N); for (auto &M : C->all_components()) { Record.AddStmt(M.getAssociatedExpression()); Record.AddDeclRef(M.getAssociatedDeclaration()); } } void OMPClauseWriter::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getUniqueDeclarationsNum()); Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *E : C->varlists()) Record.AddStmt(E); for (auto *D : C->all_decls()) Record.AddDeclRef(D); for (auto N : C->all_num_lists()) Record.push_back(N); for (auto N : C->all_lists_sizes()) Record.push_back(N); for (auto &M : C->all_components()) { Record.AddStmt(M.getAssociatedExpression()); Record.AddDeclRef(M.getAssociatedDeclaration()); } } void OMPClauseWriter::VisitOMPHasDeviceAddrClause(OMPHasDeviceAddrClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getUniqueDeclarationsNum()); Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *E : C->varlists()) Record.AddStmt(E); for (auto *D : C->all_decls()) Record.AddDeclRef(D); for (auto N : C->all_num_lists()) Record.push_back(N); for (auto N : C->all_lists_sizes()) Record.push_back(N); for (auto &M : C->all_components()) { Record.AddStmt(M.getAssociatedExpression()); Record.AddDeclRef(M.getAssociatedDeclaration()); } } void OMPClauseWriter::VisitOMPUnifiedAddressClause(OMPUnifiedAddressClause *) {} void OMPClauseWriter::VisitOMPUnifiedSharedMemoryClause( OMPUnifiedSharedMemoryClause *) {} void OMPClauseWriter::VisitOMPReverseOffloadClause(OMPReverseOffloadClause *) {} void OMPClauseWriter::VisitOMPDynamicAllocatorsClause(OMPDynamicAllocatorsClause *) { } void OMPClauseWriter::VisitOMPAtomicDefaultMemOrderClause( OMPAtomicDefaultMemOrderClause *C) { Record.push_back(C->getAtomicDefaultMemOrderKind()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getAtomicDefaultMemOrderKindKwLoc()); } void OMPClauseWriter::VisitOMPAtClause(OMPAtClause *C) { Record.push_back(C->getAtKind()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getAtKindKwLoc()); } void OMPClauseWriter::VisitOMPSeverityClause(OMPSeverityClause *C) { Record.push_back(C->getSeverityKind()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getSeverityKindKwLoc()); } void OMPClauseWriter::VisitOMPMessageClause(OMPMessageClause *C) { Record.AddStmt(C->getMessageString()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPNontemporalClause(OMPNontemporalClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); for (auto *E : C->private_refs()) Record.AddStmt(E); } void OMPClauseWriter::VisitOMPInclusiveClause(OMPInclusiveClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); } void OMPClauseWriter::VisitOMPExclusiveClause(OMPExclusiveClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); } void OMPClauseWriter::VisitOMPOrderClause(OMPOrderClause *C) { Record.writeEnum(C->getKind()); Record.writeEnum(C->getModifier()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getKindKwLoc()); Record.AddSourceLocation(C->getModifierKwLoc()); } void OMPClauseWriter::VisitOMPUsesAllocatorsClause(OMPUsesAllocatorsClause *C) { Record.push_back(C->getNumberOfAllocators()); Record.AddSourceLocation(C->getLParenLoc()); for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) { OMPUsesAllocatorsClause::Data Data = C->getAllocatorData(I); Record.AddStmt(Data.Allocator); Record.AddStmt(Data.AllocatorTraits); Record.AddSourceLocation(Data.LParenLoc); Record.AddSourceLocation(Data.RParenLoc); } } void OMPClauseWriter::VisitOMPAffinityClause(OMPAffinityClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddStmt(C->getModifier()); Record.AddSourceLocation(C->getColonLoc()); for (Expr *E : C->varlists()) Record.AddStmt(E); } void OMPClauseWriter::VisitOMPBindClause(OMPBindClause *C) { Record.writeEnum(C->getBindKind()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getBindKindLoc()); } void OMPClauseWriter::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) { VisitOMPClauseWithPreInit(C); Record.AddStmt(C->getSize()); Record.AddSourceLocation(C->getLParenLoc()); } void OMPClauseWriter::VisitOMPDoacrossClause(OMPDoacrossClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getNumLoops()); Record.AddSourceLocation(C->getLParenLoc()); Record.push_back(C->getDependenceType()); Record.AddSourceLocation(C->getDependenceLoc()); Record.AddSourceLocation(C->getColonLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) Record.AddStmt(C->getLoopData(I)); } void OMPClauseWriter::VisitOMPXAttributeClause(OMPXAttributeClause *C) { Record.AddAttributes(C->getAttrs()); Record.AddSourceLocation(C->getBeginLoc()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getEndLoc()); } void OMPClauseWriter::VisitOMPXBareClause(OMPXBareClause *C) {} void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo *TI) { writeUInt32(TI->Sets.size()); for (const auto &Set : TI->Sets) { writeEnum(Set.Kind); writeUInt32(Set.Selectors.size()); for (const auto &Selector : Set.Selectors) { writeEnum(Selector.Kind); writeBool(Selector.ScoreOrCondition); if (Selector.ScoreOrCondition) writeExprRef(Selector.ScoreOrCondition); writeUInt32(Selector.Properties.size()); for (const auto &Property : Selector.Properties) writeEnum(Property.Kind); } } } void ASTRecordWriter::writeOMPChildren(OMPChildren *Data) { if (!Data) return; writeUInt32(Data->getNumClauses()); writeUInt32(Data->getNumChildren()); writeBool(Data->hasAssociatedStmt()); for (unsigned I = 0, E = Data->getNumClauses(); I < E; ++I) writeOMPClause(Data->getClauses()[I]); if (Data->hasAssociatedStmt()) AddStmt(Data->getAssociatedStmt()); for (unsigned I = 0, E = Data->getNumChildren(); I < E; ++I) AddStmt(Data->getChildren()[I]); } void ASTRecordWriter::writeOpenACCVarList(const OpenACCClauseWithVarList *C) { writeUInt32(C->getVarList().size()); for (Expr *E : C->getVarList()) AddStmt(E); } void ASTRecordWriter::writeOpenACCIntExprList(ArrayRef Exprs) { writeUInt32(Exprs.size()); for (Expr *E : Exprs) AddStmt(E); } void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { writeEnum(C->getClauseKind()); writeSourceLocation(C->getBeginLoc()); writeSourceLocation(C->getEndLoc()); switch (C->getClauseKind()) { case OpenACCClauseKind::Default: { const auto *DC = cast(C); writeSourceLocation(DC->getLParenLoc()); writeEnum(DC->getDefaultClauseKind()); return; } case OpenACCClauseKind::If: { const auto *IC = cast(C); writeSourceLocation(IC->getLParenLoc()); AddStmt(const_cast(IC->getConditionExpr())); return; } case OpenACCClauseKind::Self: { const auto *SC = cast(C); writeSourceLocation(SC->getLParenLoc()); writeBool(SC->hasConditionExpr()); if (SC->hasConditionExpr()) AddStmt(const_cast(SC->getConditionExpr())); return; } case OpenACCClauseKind::NumGangs: { const auto *NGC = cast(C); writeSourceLocation(NGC->getLParenLoc()); writeUInt32(NGC->getIntExprs().size()); for (Expr *E : NGC->getIntExprs()) AddStmt(E); return; } case OpenACCClauseKind::NumWorkers: { const auto *NWC = cast(C); writeSourceLocation(NWC->getLParenLoc()); AddStmt(const_cast(NWC->getIntExpr())); return; } case OpenACCClauseKind::VectorLength: { const auto *NWC = cast(C); writeSourceLocation(NWC->getLParenLoc()); AddStmt(const_cast(NWC->getIntExpr())); return; } case OpenACCClauseKind::Private: { const auto *PC = cast(C); writeSourceLocation(PC->getLParenLoc()); writeOpenACCVarList(PC); return; } case OpenACCClauseKind::FirstPrivate: { const auto *FPC = cast(C); writeSourceLocation(FPC->getLParenLoc()); writeOpenACCVarList(FPC); return; } case OpenACCClauseKind::Attach: { const auto *AC = cast(C); writeSourceLocation(AC->getLParenLoc()); writeOpenACCVarList(AC); return; } case OpenACCClauseKind::DevicePtr: { const auto *DPC = cast(C); writeSourceLocation(DPC->getLParenLoc()); writeOpenACCVarList(DPC); return; } case OpenACCClauseKind::NoCreate: { const auto *NCC = cast(C); writeSourceLocation(NCC->getLParenLoc()); writeOpenACCVarList(NCC); return; } case OpenACCClauseKind::Present: { const auto *PC = cast(C); writeSourceLocation(PC->getLParenLoc()); writeOpenACCVarList(PC); return; } case OpenACCClauseKind::Copy: case OpenACCClauseKind::PCopy: case OpenACCClauseKind::PresentOrCopy: { const auto *CC = cast(C); writeSourceLocation(CC->getLParenLoc()); writeOpenACCVarList(CC); return; } case OpenACCClauseKind::CopyIn: case OpenACCClauseKind::PCopyIn: case OpenACCClauseKind::PresentOrCopyIn: { const auto *CIC = cast(C); writeSourceLocation(CIC->getLParenLoc()); writeBool(CIC->isReadOnly()); writeOpenACCVarList(CIC); return; } case OpenACCClauseKind::CopyOut: case OpenACCClauseKind::PCopyOut: case OpenACCClauseKind::PresentOrCopyOut: { const auto *COC = cast(C); writeSourceLocation(COC->getLParenLoc()); writeBool(COC->isZero()); writeOpenACCVarList(COC); return; } case OpenACCClauseKind::Create: case OpenACCClauseKind::PCreate: case OpenACCClauseKind::PresentOrCreate: { const auto *CC = cast(C); writeSourceLocation(CC->getLParenLoc()); writeBool(CC->isZero()); writeOpenACCVarList(CC); return; } case OpenACCClauseKind::Async: { const auto *AC = cast(C); writeSourceLocation(AC->getLParenLoc()); writeBool(AC->hasIntExpr()); if (AC->hasIntExpr()) AddStmt(const_cast(AC->getIntExpr())); return; } case OpenACCClauseKind::Wait: { const auto *WC = cast(C); writeSourceLocation(WC->getLParenLoc()); writeBool(WC->getDevNumExpr()); if (Expr *DNE = WC->getDevNumExpr()) AddStmt(DNE); writeSourceLocation(WC->getQueuesLoc()); writeOpenACCIntExprList(WC->getQueueIdExprs()); return; } case OpenACCClauseKind::DeviceType: case OpenACCClauseKind::DType: { const auto *DTC = cast(C); writeSourceLocation(DTC->getLParenLoc()); writeUInt32(DTC->getArchitectures().size()); for (const DeviceTypeArgument &Arg : DTC->getArchitectures()) { writeBool(Arg.first); if (Arg.first) AddIdentifierRef(Arg.first); writeSourceLocation(Arg.second); } return; } case OpenACCClauseKind::Reduction: { const auto *RC = cast(C); writeSourceLocation(RC->getLParenLoc()); writeEnum(RC->getReductionOp()); writeOpenACCVarList(RC); return; } case OpenACCClauseKind::Seq: case OpenACCClauseKind::Independent: case OpenACCClauseKind::Auto: // Nothing to do here, there is no additional information beyond the // begin/end loc and clause kind. return; case OpenACCClauseKind::Finalize: case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::Worker: case OpenACCClauseKind::Vector: case OpenACCClauseKind::NoHost: case OpenACCClauseKind::UseDevice: case OpenACCClauseKind::Delete: case OpenACCClauseKind::Detach: case OpenACCClauseKind::Device: case OpenACCClauseKind::DeviceResident: case OpenACCClauseKind::Host: case OpenACCClauseKind::Link: case OpenACCClauseKind::Collapse: case OpenACCClauseKind::Bind: case OpenACCClauseKind::DeviceNum: case OpenACCClauseKind::DefaultAsync: case OpenACCClauseKind::Tile: case OpenACCClauseKind::Gang: case OpenACCClauseKind::Invalid: llvm_unreachable("Clause serialization not yet implemented"); } llvm_unreachable("Invalid Clause Kind"); } void ASTRecordWriter::writeOpenACCClauseList( ArrayRef Clauses) { for (const OpenACCClause *Clause : Clauses) writeOpenACCClause(Clause); }