https://github.com/ChuanqiXu9 updated https://github.com/llvm/llvm-project/pull/92511
>From 1a83e2b0f00183c61e7a5303ea7eeb0b279c7e91 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] [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 99ad8524bde80..092d46b41e2cf 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 ef98a49cf491f..aec4e01ea07c0 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -487,14 +487,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 @@ -1420,8 +1412,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); @@ -1533,6 +1525,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. @@ -1881,10 +1878,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. @@ -1906,6 +1904,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 3a0892ee70c7c..59ed4815ae92e 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3355,20 +3355,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; } @@ -4031,7 +4022,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()); @@ -4067,8 +4057,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) { @@ -4083,7 +4071,6 @@ void ASTReader::ReadModuleOffsetMap(ModuleFile &F) const { PreprocessedEntityRemap); mapOffset(SubmoduleIDOffset, OM->BaseSubmoduleID, SubmoduleRemap); mapOffset(SelectorIDOffset, OM->BaseSelectorID, SelectorRemap); - mapOffset(TypeIndexOffset, OM->BaseTypeIndex, TypeRemap); } } @@ -5062,12 +5049,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"); @@ -5088,7 +5075,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"); @@ -5109,7 +5096,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"); @@ -5127,25 +5114,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"); @@ -6630,10 +6616,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); } @@ -6654,10 +6638,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 @@ -7098,14 +7082,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: @@ -7374,10 +7369,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(); @@ -7390,27 +7386,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 @@ -7648,6 +7645,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; @@ -8165,7 +8172,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 8b6fed78f70d7..62a89b9a0e9ce 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3263,17 +3263,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) { @@ -3346,12 +3347,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)); } @@ -5428,7 +5427,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}; @@ -6117,7 +6115,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(); @@ -6619,11 +6617,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; @@ -6652,13 +6648,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>(); _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits