diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 1c4025f7482d9..867d0c96abca7 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -928,8 +928,6 @@ class ASTWriter : public ASTDeserializationListener, void handleVTable(CXXRecordDecl *RD); - void addTouchedModuleFile(serialization::ModuleFile *); - private: // ASTDeserializationListener implementation void ReaderInitialized(ASTReader *Reader) override; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 3e10bbfedfe65..17a1a75f166b7 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4084,10 +4084,6 @@ void ASTWriter::handleVTable(CXXRecordDecl *RD) { PendingEmittingVTables.push_back(RD); } -void ASTWriter::addTouchedModuleFile(serialization::ModuleFile *MF) { - TouchedModuleFiles.insert(MF); -} - //===----------------------------------------------------------------------===// // DeclContext's Name Lookup Table Serialization //===----------------------------------------------------------------------===// @@ -4132,7 +4128,6 @@ class ASTDeclContextNameLookupTraitBase { "have reference to loaded module file but no chain?"); using namespace llvm::support; - Writer.addTouchedModuleFile(F); endian::write(Out, Writer.getChain()->getModuleFileID(F), llvm::endianness::little); } @@ -4330,6 +4325,14 @@ static bool isTULocalInNamedModules(NamedDecl *D) { return D->getLinkageInternal() == Linkage::Internal; } +static NamedDecl *getLocalRedecl(NamedDecl *D) { + for (auto *RD : D->redecls()) + if (!RD->isFromASTFile()) + return cast(RD); + + return D; +} + class ASTDeclContextNameLookupTrait : public ASTDeclContextNameTrivialLookupTrait { public: @@ -4403,6 +4406,13 @@ class ASTDeclContextNameLookupTrait NamedDecl *DeclForLocalLookup = getDeclForLocalLookup(Writer.getLangOpts(), D); + // Namespace may have many redeclarations in many TU. + // Also, these namespaces are symmetric. So that we try to use + // the local redecl if any. + if (isa(DeclForLocalLookup) && + DeclForLocalLookup->isFromASTFile()) + DeclForLocalLookup = getLocalRedecl(DeclForLocalLookup); + if (Writer.getDoneWritingDeclsAndTypes() && !Writer.wasDeclEmitted(DeclForLocalLookup)) return; @@ -4524,7 +4534,6 @@ class LazySpecializationInfoLookupTrait { "have reference to loaded module file but no chain?"); using namespace llvm::support; - Writer.addTouchedModuleFile(F); endian::write(Out, Writer.getChain()->getModuleFileID(F), llvm::endianness::little); } @@ -4623,7 +4632,7 @@ void ASTWriter::GenerateSpecializationInfoLookupTable( Generator.insert(HashValue, Trait.getData(Specs, ExisitingSpecs), Trait); } - Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr); + Generator.emit(LookupTable, Trait, nullptr); } uint64_t ASTWriter::WriteSpecializationInfoLookupTable( @@ -4817,10 +4826,8 @@ void ASTWriter::GenerateNameLookupTable( 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); + // Create the on-disk hash table. + Generator.emit(LookupTable, Trait, nullptr); const auto &ModuleLocalDecls = Trait.getModuleLocalDecls(); if (!ModuleLocalDecls.empty()) { @@ -4836,11 +4843,8 @@ void ASTWriter::GenerateNameLookupTable( ModuleLocalTrait); } - auto *ModuleLocalLookups = - Chain ? Chain->getModuleLocalLookupTables(DC) : nullptr; - ModuleLocalLookupGenerator.emit( - ModuleLocalLookupTable, ModuleLocalTrait, - ModuleLocalLookups ? &ModuleLocalLookups->Table : nullptr); + ModuleLocalLookupGenerator.emit(ModuleLocalLookupTable, ModuleLocalTrait, + nullptr); } const auto &TULocalDecls = Trait.getTULocalDecls(); @@ -4856,9 +4860,7 @@ void ASTWriter::GenerateNameLookupTable( TULookupGenerator.insert(Key, TULocalTrait.getData(IDs), TULocalTrait); } - auto *TULocalLookups = Chain ? Chain->getTULocalLookupTables(DC) : nullptr; - TULookupGenerator.emit(TULookupTable, TULocalTrait, - TULocalLookups ? &TULocalLookups->Table : nullptr); + TULookupGenerator.emit(TULookupTable, TULocalTrait, nullptr); } } diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 7646d5d5efe00..22c754033a0d2 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -2234,8 +2234,15 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable *D) { // redecl chain. unsigned I = Record.size(); Record.push_back(0); - if (Writer.Chain) - AddFirstDeclFromEachModule(DAsT, /*IncludeLocal*/false); + if (Writer.Chain) { + // Namespace can have many redeclaration in many TU. + // We try to avoid touching every redeclaration to try to + // reduce the dependencies as much as possible. + if (!isa(DAsT)) + AddFirstDeclFromEachModule(DAsT, /*IncludeLocal*/ false); + else + Record.AddDeclRef(nullptr); + } // This is the number of imported first declarations + 1. Record[I] = Record.size() - I; @@ -2265,8 +2272,10 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable *D) { // // FIXME: This is not correct; when we reach an imported declaration we // won't emit its previous declaration. - (void)Writer.GetDeclRef(D->getPreviousDecl()); - (void)Writer.GetDeclRef(MostRecent); + if (D->getPreviousDecl() && !D->getPreviousDecl()->isFromASTFile()) + (void)Writer.GetDeclRef(D->getPreviousDecl()); + if (!MostRecent->isFromASTFile()) + (void)Writer.GetDeclRef(MostRecent); } else { // We use the sentinel value 0 to indicate an only declaration. Record.push_back(0); diff --git a/clang/test/Modules/no-transitive-change-namespace.cppm b/clang/test/Modules/no-transitive-change-namespace.cppm new file mode 100644 index 0000000000000..f67dd8533a6df --- /dev/null +++ b/clang/test/Modules/no-transitive-change-namespace.cppm @@ -0,0 +1,44 @@ +// Test that adding a new decl in a module which originally only contained a namespace +// won't break the dependency. +// +// RUN: rm -rf %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/Root.cppm -o %t/Root.pcm +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/N.cppm -o %t/N.pcm \ +// RUN: -fmodule-file=Root=%t/Root.pcm +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/N.v1.cppm -o %t/N.v1.pcm \ +// RUN: -fmodule-file=Root=%t/Root.pcm +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/M.cppm -o %t/M.pcm \ +// RUN: -fmodule-file=N=%t/N.pcm -fmodule-file=Root=%t/Root.pcm +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/M.cppm -o %t/M.v1.pcm \ +// RUN: -fmodule-file=N=%t/N.v1.pcm -fmodule-file=Root=%t/Root.pcm +// +// RUN: diff %t/M.pcm %t/M.v1.pcm &> /dev/null + +//--- Root.cppm +export module Root; +export namespace N { + +} + +//--- N.cppm +export module N; +import Root; +export namespace N { + +} + +//--- N.v1.cppm +export module N; +import Root; +export namespace N { +struct NN {}; +} + +//--- M.cppm +export module M; +import N; +export namespace N { +struct MM {}; +} diff --git a/clang/test/Modules/no-transitive-decl-change-4.cppm b/clang/test/Modules/no-transitive-decl-change-4.cppm index 944878be8df63..bb7e47f32669e 100644 --- a/clang/test/Modules/no-transitive-decl-change-4.cppm +++ b/clang/test/Modules/no-transitive-decl-change-4.cppm @@ -27,7 +27,7 @@ // RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/B.cppm -o %t/B.v1.pcm \ // RUN: -fprebuilt-module-path=%t -fmodule-file=AWrapper=%t/AWrapper.v1.pcm -fmodule-file=A=%t/A.v1.pcm // -// RUN: not diff %t/B.pcm %t/B.v1.pcm &> /dev/null +// RUN: diff %t/B.pcm %t/B.v1.pcm &> /dev/null //--- T.cppm export module T;