https://github.com/ChuanqiXu9 updated https://github.com/llvm/llvm-project/pull/92511
>From 57cfb2b7791666022ee46201b5126ac610c19bdd Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <yedeng...@linux.alibaba.com> Date: Fri, 17 May 2024 14:25:53 +0800 Subject: [PATCH 1/2] [serialization] No transitive type change --- .../include/clang/Serialization/ASTBitCodes.h | 32 ++++-- clang/include/clang/Serialization/ASTReader.h | 23 ++-- .../clang/Serialization/ASTRecordReader.h | 2 +- .../include/clang/Serialization/ModuleFile.h | 3 - clang/lib/Serialization/ASTReader.cpp | 104 +++++++++--------- clang/lib/Serialization/ASTWriter.cpp | 31 +++--- clang/lib/Serialization/ModuleFile.cpp | 1 - .../Modules/no-transitive-decls-change.cppm | 12 +- .../no-transitive-identifier-change.cppm | 3 - .../Modules/no-transitive-type-change.cppm | 68 ++++++++++++ clang/test/Modules/pr59999.cppm | 36 +++--- 11 files changed, 196 insertions(+), 119 deletions(-) create mode 100644 clang/test/Modules/no-transitive-type-change.cppm diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 03bac9be2bf3d..13ee1e4724f1e 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -26,6 +26,7 @@ #include "clang/Serialization/SourceLocationEncoding.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/Bitstream/BitCodes.h" +#include "llvm/Support/MathExtras.h" #include <cassert> #include <cstdint> @@ -70,38 +71,53 @@ using DeclID = DeclIDBase::DeclID; /// An ID number that refers to a type in an AST file. /// -/// The ID of a type is partitioned into two parts: the lower +/// The ID of a type is partitioned into three parts: +/// - the lower /// three bits are used to store the const/volatile/restrict -/// qualifiers (as with QualType) and the upper bits provide a -/// type index. The type index values are partitioned into two +/// qualifiers (as with QualType). +/// - the upper 29 bits provide a type index in the corresponding +/// module file. +/// - the upper 32 bits provide a module file index. +/// +/// The type index values are partitioned into two /// sets. The values below NUM_PREDEF_TYPE_IDs are predefined type /// IDs (based on the PREDEF_TYPE_*_ID constants), with 0 as a /// placeholder for "no type". Values from NUM_PREDEF_TYPE_IDs are /// other types that have serialized representations. -using TypeID = uint32_t; +using TypeID = uint64_t; /// A type index; the type ID with the qualifier bits removed. +/// Keep structure alignment 32-bit since the blob is assumed as 32-bit +/// aligned. class TypeIdx { + uint32_t ModuleFileIndex = 0; uint32_t Idx = 0; public: TypeIdx() = default; - explicit TypeIdx(uint32_t index) : Idx(index) {} + explicit TypeIdx(uint32_t Idx) : ModuleFileIndex(0), Idx(Idx) {} + + explicit TypeIdx(uint32_t ModuleFileIdx, uint32_t Idx) + : ModuleFileIndex(ModuleFileIdx), Idx(Idx) {} + + uint32_t getModuleFileIndex() const { return ModuleFileIndex; } - uint32_t getIndex() const { return Idx; } + uint64_t getValue() const { return ((uint64_t)ModuleFileIndex << 32) | Idx; } TypeID asTypeID(unsigned FastQuals) const { if (Idx == uint32_t(-1)) return TypeID(-1); - return (Idx << Qualifiers::FastWidth) | FastQuals; + unsigned Index = (Idx << Qualifiers::FastWidth) | FastQuals; + return ((uint64_t)ModuleFileIndex << 32) | Index; } static TypeIdx fromTypeID(TypeID ID) { if (ID == TypeID(-1)) return TypeIdx(-1); - return TypeIdx(ID >> Qualifiers::FastWidth); + return TypeIdx(ID >> 32, (ID & llvm::maskTrailingOnes<TypeID>(32)) >> + Qualifiers::FastWidth); } }; diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 3f38a08f0da3a..f4180984eaad3 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -490,14 +490,6 @@ class ASTReader /// ID = (I + 1) << FastQual::Width has already been loaded llvm::PagedVector<QualType> TypesLoaded; - using GlobalTypeMapType = - ContinuousRangeMap<serialization::TypeID, ModuleFile *, 4>; - - /// Mapping from global type IDs to the module in which the - /// type resides along with the offset that should be added to the - /// global type ID to produce a local ID. - GlobalTypeMapType GlobalTypeMap; - /// Declarations that have already been loaded from the chain. /// /// When the pointer at index I is non-NULL, the declaration with ID @@ -1423,8 +1415,8 @@ class ASTReader RecordLocation(ModuleFile *M, uint64_t O) : F(M), Offset(O) {} }; - QualType readTypeRecord(unsigned Index); - RecordLocation TypeCursorForIndex(unsigned Index); + QualType readTypeRecord(serialization::TypeID ID); + RecordLocation TypeCursorForIndex(serialization::TypeID ID); void LoadedDecl(unsigned Index, Decl *D); Decl *ReadDeclRecord(GlobalDeclID ID); void markIncompleteDeclChain(Decl *D); @@ -1536,6 +1528,11 @@ class ASTReader std::pair<ModuleFile *, unsigned> translateIdentifierIDToIndex(serialization::IdentifierID ID) const; + /// Translate an \param TypeID ID to the index of TypesLoaded + /// array and the corresponding module file. + std::pair<ModuleFile *, unsigned> + translateTypeIDToIndex(serialization::TypeID ID) const; + public: /// Load the AST file and validate its contents against the given /// Preprocessor. @@ -1884,10 +1881,11 @@ class ASTReader QualType GetType(serialization::TypeID ID); /// Resolve a local type ID within a given AST file into a type. - QualType getLocalType(ModuleFile &F, unsigned LocalID); + QualType getLocalType(ModuleFile &F, serialization::TypeID LocalID); /// Map a local type ID within a given AST file into a global type ID. - serialization::TypeID getGlobalTypeID(ModuleFile &F, unsigned LocalID) const; + serialization::TypeID getGlobalTypeID(ModuleFile &F, + serialization::TypeID LocalID) const; /// Read a type from the current position in the given record, which /// was read from the given AST file. @@ -1909,6 +1907,7 @@ class ASTReader /// if the declaration is not from a module file. ModuleFile *getOwningModuleFile(const Decl *D) const; ModuleFile *getOwningModuleFile(GlobalDeclID ID) const; + ModuleFile *getOwningModuleFile(serialization::TypeID ID) const; /// Returns the source location for the decl \p ID. SourceLocation getSourceLocationForDeclID(GlobalDeclID ID); diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index d00fb182f05f4..2561418b78ca7 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -163,7 +163,7 @@ class ASTRecordReader void readTypeLoc(TypeLoc TL, LocSeq *Seq = nullptr); /// Map a local type ID within a given AST file to a global type ID. - serialization::TypeID getGlobalTypeID(unsigned LocalID) const { + serialization::TypeID getGlobalTypeID(serialization::TypeID LocalID) const { return Reader->getGlobalTypeID(*F, LocalID); } diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h index 3787f4eeb8a8b..3e920c0f68360 100644 --- a/clang/include/clang/Serialization/ModuleFile.h +++ b/clang/include/clang/Serialization/ModuleFile.h @@ -482,9 +482,6 @@ class ModuleFile { /// the global type ID space. serialization::TypeID BaseTypeIndex = 0; - /// Remapping table for type IDs in this module. - ContinuousRangeMap<uint32_t, int, 2> TypeRemap; - // === Miscellaneous === /// Diagnostic IDs and their mappings that the user changed. diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 29a7fcb2cb507..9d05037b89392 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3357,20 +3357,11 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, "duplicate TYPE_OFFSET record in AST file"); F.TypeOffsets = reinterpret_cast<const UnalignedUInt64 *>(Blob.data()); F.LocalNumTypes = Record[0]; - unsigned LocalBaseTypeIndex = Record[1]; F.BaseTypeIndex = getTotalNumTypes(); - if (F.LocalNumTypes > 0) { - // Introduce the global -> local mapping for types within this module. - GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F)); - - // Introduce the local -> global mapping for types within this module. - F.TypeRemap.insertOrReplace( - std::make_pair(LocalBaseTypeIndex, - F.BaseTypeIndex - LocalBaseTypeIndex)); - + if (F.LocalNumTypes > 0) TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes); - } + break; } @@ -4033,7 +4024,6 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const { RemapBuilder PreprocessedEntityRemap(F.PreprocessedEntityRemap); RemapBuilder SubmoduleRemap(F.SubmoduleRemap); RemapBuilder SelectorRemap(F.SelectorRemap); - RemapBuilder TypeRemap(F.TypeRemap); auto &ImportedModuleVector = F.TransitiveImports; assert(ImportedModuleVector.empty()); @@ -4069,8 +4059,6 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const { endian::readNext<uint32_t, llvm::endianness::little>(Data); uint32_t SelectorIDOffset = endian::readNext<uint32_t, llvm::endianness::little>(Data); - uint32_t TypeIndexOffset = - endian::readNext<uint32_t, llvm::endianness::little>(Data); auto mapOffset = [&](uint32_t Offset, uint32_t BaseOffset, RemapBuilder &Remap) { @@ -4085,7 +4073,6 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const { PreprocessedEntityRemap); mapOffset(SubmoduleIDOffset, OM->BaseSubmoduleID, SubmoduleRemap); mapOffset(SelectorIDOffset, OM->BaseSelectorID, SelectorRemap); - mapOffset(TypeIndexOffset, OM->BaseTypeIndex, TypeRemap); } } @@ -5064,12 +5051,12 @@ void ASTReader::InitializeContext() { // Load the special types. if (SpecialTypes.size() >= NumSpecialTypeIDs) { - if (unsigned String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) { + if (TypeID String = SpecialTypes[SPECIAL_TYPE_CF_CONSTANT_STRING]) { if (!Context.CFConstantStringTypeDecl) Context.setCFConstantStringType(GetType(String)); } - if (unsigned File = SpecialTypes[SPECIAL_TYPE_FILE]) { + if (TypeID File = SpecialTypes[SPECIAL_TYPE_FILE]) { QualType FileType = GetType(File); if (FileType.isNull()) { Error("FILE type is NULL"); @@ -5090,7 +5077,7 @@ void ASTReader::InitializeContext() { } } - if (unsigned Jmp_buf = SpecialTypes[SPECIAL_TYPE_JMP_BUF]) { + 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"); @@ -5111,7 +5098,7 @@ void ASTReader::InitializeContext() { } } - if (unsigned Sigjmp_buf = SpecialTypes[SPECIAL_TYPE_SIGJMP_BUF]) { + 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"); @@ -5129,25 +5116,24 @@ void ASTReader::InitializeContext() { } } - if (unsigned ObjCIdRedef - = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) { + if (TypeID ObjCIdRedef = SpecialTypes[SPECIAL_TYPE_OBJC_ID_REDEFINITION]) { if (Context.ObjCIdRedefinitionType.isNull()) Context.ObjCIdRedefinitionType = GetType(ObjCIdRedef); } - if (unsigned ObjCClassRedef - = SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) { + if (TypeID ObjCClassRedef = + SpecialTypes[SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) { if (Context.ObjCClassRedefinitionType.isNull()) Context.ObjCClassRedefinitionType = GetType(ObjCClassRedef); } - if (unsigned ObjCSelRedef - = SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) { + if (TypeID ObjCSelRedef = + SpecialTypes[SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) { if (Context.ObjCSelRedefinitionType.isNull()) Context.ObjCSelRedefinitionType = GetType(ObjCSelRedef); } - if (unsigned Ucontext_t = SpecialTypes[SPECIAL_TYPE_UCONTEXT_T]) { + 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"); @@ -6632,10 +6618,8 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { } /// Get the correct cursor and offset for loading a type. -ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) { - GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index); - assert(I != GlobalTypeMap.end() && "Corrupted global type map"); - ModuleFile *M = I->second; +ASTReader::RecordLocation ASTReader::TypeCursorForIndex(TypeID ID) { + auto [M, Index] = translateTypeIDToIndex(ID); return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex].get() + M->DeclsBlockStartOffset); } @@ -6656,10 +6640,10 @@ static std::optional<Type::TypeClass> getTypeClassForCode(TypeCode code) { /// 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(unsigned Index) { +QualType ASTReader::readTypeRecord(TypeID ID) { assert(ContextObj && "reading type with no AST context"); ASTContext &Context = *ContextObj; - RecordLocation Loc = TypeCursorForIndex(Index); + RecordLocation Loc = TypeCursorForIndex(ID); BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor; // Keep track of where we are in the stream, then jump back there @@ -7100,14 +7084,25 @@ TypeSourceInfo *ASTRecordReader::readTypeSourceInfo() { return TInfo; } +std::pair<ModuleFile *, unsigned> +ASTReader::translateTypeIDToIndex(serialization::TypeID ID) const { + unsigned Index = + (ID & llvm::maskTrailingOnes<TypeID>(32)) >> Qualifiers::FastWidth; + + ModuleFile *OwningModuleFile = getOwningModuleFile(ID); + assert(OwningModuleFile && + "untranslated type ID or local type ID shouldn't be in TypesLoaded"); + return {OwningModuleFile, OwningModuleFile->BaseTypeIndex + Index}; +} + QualType ASTReader::GetType(TypeID ID) { assert(ContextObj && "reading type with no AST context"); ASTContext &Context = *ContextObj; unsigned FastQuals = ID & Qualifiers::FastMask; - unsigned Index = ID >> Qualifiers::FastWidth; - if (Index < NUM_PREDEF_TYPE_IDS) { + if (uint64_t Index = ID >> Qualifiers::FastWidth; + Index < NUM_PREDEF_TYPE_IDS) { QualType T; switch ((PredefinedTypeIDs)Index) { case PREDEF_TYPE_LAST_ID: @@ -7376,10 +7371,11 @@ QualType ASTReader::GetType(TypeID ID) { return T.withFastQualifiers(FastQuals); } - Index -= NUM_PREDEF_TYPE_IDS; + unsigned Index = translateTypeIDToIndex(ID).second; + assert(Index < TypesLoaded.size() && "Type index out-of-range"); if (TypesLoaded[Index].isNull()) { - TypesLoaded[Index] = readTypeRecord(Index); + TypesLoaded[Index] = readTypeRecord(ID); if (TypesLoaded[Index].isNull()) return QualType(); @@ -7392,27 +7388,28 @@ QualType ASTReader::GetType(TypeID ID) { return TypesLoaded[Index].withFastQualifiers(FastQuals); } -QualType ASTReader::getLocalType(ModuleFile &F, unsigned LocalID) { +QualType ASTReader::getLocalType(ModuleFile &F, TypeID LocalID) { return GetType(getGlobalTypeID(F, LocalID)); } -serialization::TypeID -ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const { - unsigned FastQuals = LocalID & Qualifiers::FastMask; - unsigned LocalIndex = LocalID >> Qualifiers::FastWidth; - - if (LocalIndex < NUM_PREDEF_TYPE_IDS) +serialization::TypeID ASTReader::getGlobalTypeID(ModuleFile &F, + TypeID LocalID) const { + if ((LocalID >> Qualifiers::FastWidth) < NUM_PREDEF_TYPE_IDS) return LocalID; if (!F.ModuleOffsetMap.empty()) ReadModuleOffsetMap(F); - ContinuousRangeMap<uint32_t, int, 2>::iterator I - = F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS); - assert(I != F.TypeRemap.end() && "Invalid index into type index remap"); + unsigned ModuleFileIndex = LocalID >> 32; + LocalID &= llvm::maskTrailingOnes<TypeID>(32); - unsigned GlobalIndex = LocalIndex + I->second; - return (GlobalIndex << Qualifiers::FastWidth) | FastQuals; + 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 @@ -7650,6 +7647,16 @@ ModuleFile *ASTReader::getOwningModuleFile(GlobalDeclID ID) const { return &getModuleManager()[ModuleFileIndex - 1]; } +ModuleFile *ASTReader::getOwningModuleFile(TypeID ID) const { + if (ID < NUM_PREDEF_TYPE_IDS) + return nullptr; + + uint64_t ModuleFileIndex = ID >> 32; + assert(ModuleFileIndex && "Untranslated Local Decl?"); + + return &getModuleManager()[ModuleFileIndex - 1]; +} + ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) const { if (!D->isFromASTFile()) return nullptr; @@ -8167,7 +8174,6 @@ 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 type map", GlobalTypeMap); dumpModuleIDMap("Global macro map", GlobalMacroMap); dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap); dumpModuleIDMap("Global selector map", GlobalSelectorMap); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index dd6c135d54b46..4a20b97de55d3 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3262,17 +3262,18 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, /// Write the representation of a type to the AST stream. void ASTWriter::WriteType(QualType T) { TypeIdx &IdxRef = TypeIdxs[T]; - if (IdxRef.getIndex() == 0) // we haven't seen this type before. + if (IdxRef.getValue() == 0) // we haven't seen this type before. IdxRef = TypeIdx(NextTypeID++); TypeIdx Idx = IdxRef; - assert(Idx.getIndex() >= FirstTypeID && "Re-writing a type from a prior AST"); + 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. - unsigned Index = Idx.getIndex() - FirstTypeID; + uint64_t Index = Idx.getValue() - FirstTypeID; if (TypeOffsets.size() == Index) TypeOffsets.emplace_back(Offset); else if (TypeOffsets.size() < Index) { @@ -3345,12 +3346,10 @@ void ASTWriter::WriteTypeDeclOffsets() { auto Abbrev = std::make_shared<BitCodeAbbrev>(); Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base type index Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(std::move(Abbrev)); { - RecordData::value_type Record[] = {TYPE_OFFSET, TypeOffsets.size(), - FirstTypeID - NUM_PREDEF_TYPE_IDS}; + RecordData::value_type Record[] = {TYPE_OFFSET, TypeOffsets.size()}; Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, bytes(TypeOffsets)); } @@ -5434,7 +5433,6 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, M.NumPreprocessedEntities); writeBaseIDOrNone(M.BaseSubmoduleID, M.LocalNumSubmodules); writeBaseIDOrNone(M.BaseSelectorID, M.LocalNumSelectors); - writeBaseIDOrNone(M.BaseTypeIndex, M.LocalNumTypes); } } RecordData::value_type Record[] = {MODULE_OFFSET_MAP}; @@ -6123,7 +6121,7 @@ TypeID ASTWriter::GetOrCreateTypeID(QualType T) { assert(!T.getLocalFastQualifiers()); TypeIdx &Idx = TypeIdxs[T]; - if (Idx.getIndex() == 0) { + if (Idx.getValue() == 0) { if (DoneWritingDeclsAndTypes) { assert(0 && "New type seen after serializing all the types to emit!"); return TypeIdx(); @@ -6626,11 +6624,9 @@ void ASTWriter::ReaderInitialized(ASTReader *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. - FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes(); FirstMacroID = NUM_PREDEF_MACRO_IDS + Chain->getTotalNumMacros(); FirstSubmoduleID = NUM_PREDEF_SUBMODULE_IDS + Chain->getTotalNumSubmodules(); FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors(); - NextTypeID = FirstTypeID; NextMacroID = FirstMacroID; NextSelectorID = FirstSelectorID; NextSubmoduleID = FirstSubmoduleID; @@ -6659,13 +6655,22 @@ void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) { } void ASTWriter::TypeRead(TypeIdx Idx, QualType T) { - // Always take the highest-numbered type index. This copes with an interesting + // 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 higher-numbered entry so that we can properly write it out to + // keep the just writing entry so that we can properly write it out to // the AST file. TypeIdx &StoredIdx = TypeIdxs[T]; - if (Idx.getIndex() >= StoredIdx.getIndex()) + + // Ignore it if the type comes from the current being written module file. + 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.getValue() >= StoredIdx.getValue()) StoredIdx = Idx; } diff --git a/clang/lib/Serialization/ModuleFile.cpp b/clang/lib/Serialization/ModuleFile.cpp index 7976c28b28671..4858cdbda5545 100644 --- a/clang/lib/Serialization/ModuleFile.cpp +++ b/clang/lib/Serialization/ModuleFile.cpp @@ -84,7 +84,6 @@ LLVM_DUMP_METHOD void ModuleFile::dump() { llvm::errs() << " Base type index: " << BaseTypeIndex << '\n' << " Number of types: " << LocalNumTypes << '\n'; - dumpLocalRemap("Type index local -> global map", TypeRemap); llvm::errs() << " Base decl index: " << BaseDeclIndex << '\n' << " Number of decls: " << LocalNumDecls << '\n'; diff --git a/clang/test/Modules/no-transitive-decls-change.cppm b/clang/test/Modules/no-transitive-decls-change.cppm index 42ac061bc90b3..83594b09ea789 100644 --- a/clang/test/Modules/no-transitive-decls-change.cppm +++ b/clang/test/Modules/no-transitive-decls-change.cppm @@ -44,10 +44,6 @@ export inline int getA() { return 43; } -export inline int getA2(int) { - return 88; -} - //--- m-partA.v1.cppm export module m:partA; @@ -63,7 +59,6 @@ namespace A_Impl { namespace A { using A_Impl::getAImpl; - // Adding a new declaration without introducing a new declaration name. using A_Impl::getA2Impl; } @@ -71,14 +66,9 @@ inline int getA() { return 43; } -inline int getA2(int) { - return 88; -} - -// Now we add a new declaration without introducing new identifier and new types. // The consuming module which didn't use m:partA completely is expected to be // not changed. -inline int getA(int) { +inline int getB(int) { return 88; } diff --git a/clang/test/Modules/no-transitive-identifier-change.cppm b/clang/test/Modules/no-transitive-identifier-change.cppm index 97e8ac4444fdd..35b519236aaed 100644 --- a/clang/test/Modules/no-transitive-identifier-change.cppm +++ b/clang/test/Modules/no-transitive-identifier-change.cppm @@ -57,7 +57,6 @@ export inline int getA() { return 43; } -// Now we add a new declaration without introducing a new type. // The consuming module which didn't use m:partA completely is expected to be // not changed. export inline int getA2() { @@ -67,7 +66,6 @@ export inline int getA2() { export class A { public: int getMem(); - // Now we add a new declaration without introducing a new type. // The consuming module which didn't use m:partA completely is expected to be // not changed. int getMem2(); @@ -77,7 +75,6 @@ export template <typename T> class ATempl { public: T getT(); - // Add a new declaration without introducing a new type. T getT2(); }; diff --git a/clang/test/Modules/no-transitive-type-change.cppm b/clang/test/Modules/no-transitive-type-change.cppm new file mode 100644 index 0000000000000..4d5d42b7c042c --- /dev/null +++ b/clang/test/Modules/no-transitive-type-change.cppm @@ -0,0 +1,68 @@ +// Testing that changing a type in an unused module file won't change +// the BMI of the current module file. +// +// RUN: rm -rf %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/m-partA.cppm -emit-reduced-module-interface -o %t/m-partA.pcm +// RUN: %clang_cc1 -std=c++20 %t/m-partA.v1.cppm -emit-reduced-module-interface -o \ +// RUN: %t/m-partA.v1.pcm +// RUN: %clang_cc1 -std=c++20 %t/m-partB.cppm -emit-reduced-module-interface -o %t/m-partB.pcm +// RUN: %clang_cc1 -std=c++20 %t/m.cppm -emit-reduced-module-interface -o %t/m.pcm \ +// RUN: -fmodule-file=m:partA=%t/m-partA.pcm -fmodule-file=m:partB=%t/m-partB.pcm +// RUN: %clang_cc1 -std=c++20 %t/m.cppm -emit-reduced-module-interface -o %t/m.v1.pcm \ +// RUN: -fmodule-file=m:partA=%t/m-partA.v1.pcm -fmodule-file=m:partB=%t/m-partB.pcm +// +// RUN: %clang_cc1 -std=c++20 %t/useBOnly.cppm -emit-reduced-module-interface -o %t/useBOnly.pcm \ +// RUN: -fmodule-file=m=%t/m.pcm -fmodule-file=m:partA=%t/m-partA.pcm \ +// RUN: -fmodule-file=m:partB=%t/m-partB.pcm +// RUN: %clang_cc1 -std=c++20 %t/useBOnly.cppm -emit-reduced-module-interface -o %t/useBOnly.v1.pcm \ +// RUN: -fmodule-file=m=%t/m.v1.pcm -fmodule-file=m:partA=%t/m-partA.v1.pcm \ +// RUN: -fmodule-file=m:partB=%t/m-partB.pcm +// Since useBOnly only uses partB from module M, the change in partA shouldn't affect +// useBOnly. +// RUN: diff %t/useBOnly.pcm %t/useBOnly.v1.pcm &> /dev/null + +//--- m-partA.cppm +export module m:partA; + +//--- m-partA.v1.cppm +export module m:partA; + +namespace NS { + class A { + public: + int getValue() { + return 43; + } + }; +} + +//--- m-partB.cppm +export module m:partB; + +export inline int getB() { + return 430; +} + +//--- m.cppm +export module m; +export import :partA; +export import :partB; + +//--- useBOnly.cppm +export module useBOnly; +import m; + +export inline int get() { + return getB(); +} + +//--- useAOnly.cppm +export module useAOnly; +import m; + +export inline int get() { + A<int> a; + return a.getValue(); +} diff --git a/clang/test/Modules/pr59999.cppm b/clang/test/Modules/pr59999.cppm index d6e6fff2b7c5e..5405091ad5291 100644 --- a/clang/test/Modules/pr59999.cppm +++ b/clang/test/Modules/pr59999.cppm @@ -12,16 +12,16 @@ // RUN: -fmodule-file=Module=%t/Module.pcm -emit-llvm -o - | FileCheck %t/Object.cppm // Test again with reduced BMI. -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t +// RUNX: rm -rf %t +// RUNX: mkdir -p %t +// RUNX: split-file %s %t // -// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Module.cppm \ -// RUN: -emit-reduced-module-interface -o %t/Module.pcm -// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Object.cppm \ -// RUN: -fmodule-file=Module=%t/Module.pcm -emit-module-interface -o %t/Object.pcm -// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Object.pcm \ -// RUN: -fmodule-file=Module=%t/Module.pcm -emit-llvm -o - | FileCheck %t/Object.cppm +// RUNX: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Module.cppm \ +// RUNX: -emit-reduced-module-interface -o %t/Module.pcm +// RUNX: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Object.cppm \ +// RUNX: -fmodule-file=Module=%t/Module.pcm -emit-module-interface -o %t/Object.pcm +// RUNX: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Object.pcm \ +// RUNX: -fmodule-file=Module=%t/Module.pcm -emit-llvm -o - | FileCheck %t/Object.cppm //--- Module.cppm @@ -29,27 +29,27 @@ export module Module; export template <class ObjectType> bool ModuleRegister() { return true; }; -export struct ModuleEntry { - static const bool bRegistered; -}; +// export struct ModuleEntry { +// static const bool bRegistered; +// }; -const bool ModuleEntry::bRegistered = ModuleRegister<ModuleEntry>(); +// const bool ModuleEntry::bRegistered = ModuleRegister<ModuleEntry>(); //--- Object.cppm export module Object; import Module; -export template <class ObjectType> bool ObjectRegister() { return true; } -export struct NObject { - static const bool bRegistered; -}; +// export template <class ObjectType> bool ObjectRegister() { return true; } +// export struct NObject { +// static const bool bRegistered; +// }; export struct ObjectModuleEntry { static const bool bRegistered; }; // This function is also required for crash -const bool NObject::bRegistered = ObjectRegister<NObject>(); +// const bool NObject::bRegistered = ObjectRegister<NObject>(); // One another function, that helps clang crash const bool ObjectModuleEntry::bRegistered = ModuleRegister<ObjectModuleEntry>(); >From 41291b2bb99802ffcaebd0f83dc6d3361cd3a50e Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <yedeng...@linux.alibaba.com> Date: Thu, 20 Jun 2024 11:06:24 +0800 Subject: [PATCH 2/2] Update --- .../include/clang/Serialization/ASTBitCodes.h | 12 +++---- clang/include/clang/Serialization/ASTReader.h | 3 ++ clang/lib/Serialization/ASTCommon.cpp | 2 +- clang/lib/Serialization/ASTReader.cpp | 28 ++++++++++----- clang/lib/Serialization/ASTWriter.cpp | 13 +++---- clang/test/Modules/pr59999.cppm | 36 +++++++++---------- 6 files changed, 53 insertions(+), 41 deletions(-) diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 13ee1e4724f1e..a8ab8dd3c7acf 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -72,11 +72,10 @@ using DeclID = DeclIDBase::DeclID; /// An ID number that refers to a type in an AST file. /// /// The ID of a type is partitioned into three parts: -/// - the lower -/// three bits are used to store the const/volatile/restrict -/// qualifiers (as with QualType). -/// - the upper 29 bits provide a type index in the corresponding -/// module file. +/// - the lower three bits are used to store the const/volatile/restrict +/// qualifiers (as with QualType). +/// - the next 29 bits provide a type index in the corresponding +/// module file. /// - the upper 32 bits provide a module file index. /// /// The type index values are partitioned into two @@ -95,7 +94,6 @@ class TypeIdx { public: TypeIdx() = default; - explicit TypeIdx(uint32_t Idx) : ModuleFileIndex(0), Idx(Idx) {} explicit TypeIdx(uint32_t ModuleFileIdx, uint32_t Idx) : ModuleFileIndex(ModuleFileIdx), Idx(Idx) {} @@ -114,7 +112,7 @@ class TypeIdx { static TypeIdx fromTypeID(TypeID ID) { if (ID == TypeID(-1)) - return TypeIdx(-1); + return TypeIdx(0, -1); return TypeIdx(ID >> 32, (ID & llvm::maskTrailingOnes<TypeID>(32)) >> Qualifiers::FastWidth); diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index f4180984eaad3..09b96a4563dbb 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -1881,6 +1881,9 @@ class ASTReader QualType GetType(serialization::TypeID ID); /// Resolve a local type ID within a given AST file into a type. + /// + /// A local type ID is only meaningful with the corresponding module file. + /// See the implementation of getGlobalTypeID for details. QualType getLocalType(ModuleFile &F, serialization::TypeID LocalID); /// Map a local type ID within a given AST file into a global type ID. diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index bc662a87a7bf3..e30ceec92ce9b 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -278,7 +278,7 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { break; } - return TypeIdx(ID); + return TypeIdx(0, ID); } unsigned serialization::ComputeHash(Selector Sel) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 9d05037b89392..b3406007fc162 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7084,15 +7084,26 @@ TypeSourceInfo *ASTRecordReader::readTypeSourceInfo() { return TInfo; } +static unsigned getIndexForTypeID(serialization::TypeID ID) { + return (ID & llvm::maskTrailingOnes<TypeID>(32)) >> Qualifiers::FastWidth;; +} + +static unsigned getModuleFileIndexForTypeID(serialization::TypeID ID) { + return ID >> 32; +} + +static bool isPredefinedTypes(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<ModuleFile *, unsigned> ASTReader::translateTypeIDToIndex(serialization::TypeID ID) const { - unsigned Index = - (ID & llvm::maskTrailingOnes<TypeID>(32)) >> Qualifiers::FastWidth; - ModuleFile *OwningModuleFile = getOwningModuleFile(ID); assert(OwningModuleFile && "untranslated type ID or local type ID shouldn't be in TypesLoaded"); - return {OwningModuleFile, OwningModuleFile->BaseTypeIndex + Index}; + return {OwningModuleFile, OwningModuleFile->BaseTypeIndex + getIndexForTypeID(ID)}; } QualType ASTReader::GetType(TypeID ID) { @@ -7101,8 +7112,7 @@ QualType ASTReader::GetType(TypeID ID) { unsigned FastQuals = ID & Qualifiers::FastMask; - if (uint64_t Index = ID >> Qualifiers::FastWidth; - Index < NUM_PREDEF_TYPE_IDS) { + if (isPredefinedTypes(ID)) { QualType T; switch ((PredefinedTypeIDs)Index) { case PREDEF_TYPE_LAST_ID: @@ -7394,13 +7404,13 @@ QualType ASTReader::getLocalType(ModuleFile &F, TypeID LocalID) { serialization::TypeID ASTReader::getGlobalTypeID(ModuleFile &F, TypeID LocalID) const { - if ((LocalID >> Qualifiers::FastWidth) < NUM_PREDEF_TYPE_IDS) + if (isPredefinedTypes(LocalID)) return LocalID; if (!F.ModuleOffsetMap.empty()) ReadModuleOffsetMap(F); - unsigned ModuleFileIndex = LocalID >> 32; + unsigned ModuleFileIndex = getModuleFileIndexForTypeID(LocalID); LocalID &= llvm::maskTrailingOnes<TypeID>(32); if (ModuleFileIndex == 0) @@ -7651,7 +7661,7 @@ ModuleFile *ASTReader::getOwningModuleFile(TypeID ID) const { if (ID < NUM_PREDEF_TYPE_IDS) return nullptr; - uint64_t ModuleFileIndex = ID >> 32; + uint64_t ModuleFileIndex = getModuleFileIndexForTypeID(LocalID); assert(ModuleFileIndex && "Untranslated Local Decl?"); return &getModuleManager()[ModuleFileIndex - 1]; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 4a20b97de55d3..5470cbbf7ffeb 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3263,7 +3263,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag, void ASTWriter::WriteType(QualType T) { TypeIdx &IdxRef = TypeIdxs[T]; if (IdxRef.getValue() == 0) // we haven't seen this type before. - IdxRef = TypeIdx(NextTypeID++); + IdxRef = TypeIdx(0, NextTypeID++); TypeIdx Idx = IdxRef; assert(Idx.getModuleFileIndex() == 0 && "Re-writing a type from a prior AST"); @@ -6106,9 +6106,9 @@ static TypeID MakeTypeID(ASTContext &Context, QualType T, return TypeIdxFromBuiltin(BT).asTypeID(FastQuals); if (T == Context.AutoDeductTy) - return TypeIdx(PREDEF_TYPE_AUTO_DEDUCT).asTypeID(FastQuals); + return TypeIdx(0, PREDEF_TYPE_AUTO_DEDUCT).asTypeID(FastQuals); if (T == Context.AutoRRefDeductTy) - return TypeIdx(PREDEF_TYPE_AUTO_RREF_DEDUCT).asTypeID(FastQuals); + return TypeIdx(0, PREDEF_TYPE_AUTO_RREF_DEDUCT).asTypeID(FastQuals); return IdxForType(T).asTypeID(FastQuals); } @@ -6129,7 +6129,7 @@ TypeID ASTWriter::GetOrCreateTypeID(QualType T) { // We haven't seen this type before. Assign it a new ID and put it // into the queue of types to emit. - Idx = TypeIdx(NextTypeID++); + Idx = TypeIdx(0, NextTypeID++); DeclTypesToEmit.push(T); } return Idx; @@ -6659,18 +6659,19 @@ void ASTWriter::TypeRead(TypeIdx Idx, QualType T) { // 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 just writing entry so that we can properly write it out 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 being written module file 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.getValue() >= StoredIdx.getValue()) + if (Idx.getModuleFileIndex() >= StoredIdx.getModuleFileIndex()) StoredIdx = Idx; } diff --git a/clang/test/Modules/pr59999.cppm b/clang/test/Modules/pr59999.cppm index 5405091ad5291..d6e6fff2b7c5e 100644 --- a/clang/test/Modules/pr59999.cppm +++ b/clang/test/Modules/pr59999.cppm @@ -12,16 +12,16 @@ // RUN: -fmodule-file=Module=%t/Module.pcm -emit-llvm -o - | FileCheck %t/Object.cppm // Test again with reduced BMI. -// RUNX: rm -rf %t -// RUNX: mkdir -p %t -// RUNX: split-file %s %t +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t // -// RUNX: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Module.cppm \ -// RUNX: -emit-reduced-module-interface -o %t/Module.pcm -// RUNX: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Object.cppm \ -// RUNX: -fmodule-file=Module=%t/Module.pcm -emit-module-interface -o %t/Object.pcm -// RUNX: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Object.pcm \ -// RUNX: -fmodule-file=Module=%t/Module.pcm -emit-llvm -o - | FileCheck %t/Object.cppm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Module.cppm \ +// RUN: -emit-reduced-module-interface -o %t/Module.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Object.cppm \ +// RUN: -fmodule-file=Module=%t/Module.pcm -emit-module-interface -o %t/Object.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/Object.pcm \ +// RUN: -fmodule-file=Module=%t/Module.pcm -emit-llvm -o - | FileCheck %t/Object.cppm //--- Module.cppm @@ -29,27 +29,27 @@ export module Module; export template <class ObjectType> bool ModuleRegister() { return true; }; -// export struct ModuleEntry { -// static const bool bRegistered; -// }; +export struct ModuleEntry { + static const bool bRegistered; +}; -// const bool ModuleEntry::bRegistered = ModuleRegister<ModuleEntry>(); +const bool ModuleEntry::bRegistered = ModuleRegister<ModuleEntry>(); //--- Object.cppm export module Object; import Module; -// export template <class ObjectType> bool ObjectRegister() { return true; } -// export struct NObject { -// static const bool bRegistered; -// }; +export template <class ObjectType> bool ObjectRegister() { return true; } +export struct NObject { + static const bool bRegistered; +}; export struct ObjectModuleEntry { static const bool bRegistered; }; // This function is also required for crash -// const bool NObject::bRegistered = ObjectRegister<NObject>(); +const bool NObject::bRegistered = ObjectRegister<NObject>(); // One another function, that helps clang crash const bool ObjectModuleEntry::bRegistered = ModuleRegister<ObjectModuleEntry>(); _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits