diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -394,6 +394,9 @@ /// Record code for the signature that identifiers this AST file. SIGNATURE = 1, + /// Record code for the signature of the AST block. + AST_SIGNATURE, + /// Record code for the diagnostic options table. DIAGNOSTIC_OPTIONS, diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -471,8 +471,9 @@ StringRef isysroot, const std::string &OutputFile); /// Write out the signature and diagnostic options, and return the signature. - ASTFileSignature writeUnhashedControlBlock(Preprocessor &PP, - ASTContext &Context); + ASTFileSignature + writeUnhashedControlBlock(Preprocessor &PP, ASTContext &Context, + const std::pair ASTBlockRange); /// Calculate hash of the pcm content. static ASTFileSignature createSignature(StringRef Bytes); diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h --- a/clang/include/clang/Serialization/ModuleFile.h +++ b/clang/include/clang/Serialization/ModuleFile.h @@ -168,6 +168,10 @@ /// and modification time to identify this particular file. ASTFileSignature Signature; + /// The signature of the AST block of the module file, this can be used to + /// unique module files based on AST contents. + ASTFileSignature ASTSignature; + /// Whether this module has been directly imported by the /// user. bool DirectlyImported = false; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3832,17 +3832,18 @@ while (Data < DataEnd) { // FIXME: Looking up dependency modules by filename is horrible. Let's - // start fixing this with prebuilt and explicit modules and see how it - // goes... + // 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 - ? ModuleMgr.lookupByModuleName(Name) - : ModuleMgr.lookupByFileName(Name)); + ModuleFile *OM = (Kind == MK_PrebuiltModule || Kind == MK_ExplicitModule || + Kind == MK_ImplicitModule + ? ModuleMgr.lookupByModuleName(Name) + : ModuleMgr.lookupByFileName(Name)); if (!OM) { std::string Msg = "SourceLocation remap refers to unknown module, cannot find "; @@ -4734,6 +4735,10 @@ if (F) std::copy(Record.begin(), Record.end(), F->Signature.data()); break; + case AST_SIGNATURE: + if (F) + std::copy(Record.begin(), Record.end(), F->ASTSignature.data()); + break; case DIAGNOSTIC_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; if (Listener && ValidateDiagnosticOptions && diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -64,6 +64,7 @@ #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Sema.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" @@ -961,6 +962,7 @@ BLOCK(UNHASHED_CONTROL_BLOCK); RECORD(SIGNATURE); + RECORD(AST_SIGNATURE); RECORD(DIAGNOSTIC_OPTIONS); RECORD(DIAG_PRAGMA_MAPPINGS); @@ -1044,8 +1046,9 @@ return Signature; } -ASTFileSignature ASTWriter::writeUnhashedControlBlock(Preprocessor &PP, - ASTContext &Context) { +ASTFileSignature ASTWriter::writeUnhashedControlBlock( + Preprocessor &PP, ASTContext &Context, + const std::pair ASTBlockRange) { // Flush first to prepare the PCM hash (signature). Stream.FlushToWord(); auto StartOfUnhashedControl = Stream.GetCurrentBitNo() >> 3; @@ -1062,6 +1065,11 @@ Record.append(Signature.begin(), Signature.end()); Stream.EmitRecord(SIGNATURE, Record); Record.clear(); + auto ASTSignature = createSignature( + StringRef(Buffer.begin() + ASTBlockRange.first, ASTBlockRange.second)); + Record.append(ASTSignature.begin(), ASTSignature.end()); + Stream.EmitRecord(AST_SIGNATURE, Record); + Record.clear(); } // Diagnostic options. @@ -4548,6 +4556,8 @@ populateInputFileIDs(Context.SourceMgr); // Write the remaining AST contents. + Stream.FlushToWord(); + auto StartOfASTBlock = Stream.GetCurrentBitNo() >> 3; Stream.EnterSubblock(AST_BLOCK_ID, 5); // This is so that older clang versions, before the introduction @@ -4679,9 +4689,9 @@ // c++-base-specifiers-id:i32 // type-id:i32) // - // module-kind is the ModuleKind enum value. If it is MK_PrebuiltModule or - // MK_ExplicitModule, then the module-name is the module name. Otherwise, - // it is the module file name. + // 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)); @@ -4694,10 +4704,11 @@ endian::Writer LE(Out, little); LE.write(static_cast(M.Kind)); - StringRef Name = - M.Kind == MK_PrebuiltModule || M.Kind == MK_ExplicitModule - ? M.ModuleName - : M.FileName; + StringRef Name = M.Kind == MK_PrebuiltModule || + M.Kind == MK_ExplicitModule || + M.Kind == MK_ImplicitModule + ? M.ModuleName + : M.FileName; LE.write(Name.size()); Out.write(Name.data(), Name.size()); @@ -4909,6 +4920,7 @@ NumStatements, NumMacros, NumLexicalDeclContexts, NumVisibleDeclContexts}; Stream.EmitRecord(STATISTICS, Record); Stream.ExitBlock(); + auto EndOfASTBlock = Stream.GetCurrentBitNo() >> 3; // Write the control block WriteControlBlock(PP, Context, isysroot, OutputFile); @@ -4917,7 +4929,9 @@ for (const auto &ExtWriter : ModuleFileExtensionWriters) WriteModuleFileExtension(SemaRef, *ExtWriter); - return writeUnhashedControlBlock(PP, Context); + return writeUnhashedControlBlock( + PP, Context, + std::make_pair(StartOfASTBlock, EndOfASTBlock - StartOfASTBlock)); } void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { diff --git a/clang/test/Modules/ASTSignature.c b/clang/test/Modules/ASTSignature.c new file mode 100644 --- /dev/null +++ b/clang/test/Modules/ASTSignature.c @@ -0,0 +1,18 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -iquote %S/Inputs/ASTHash/ -fsyntax-only -fmodules \ +// RUN: -fimplicit-module-maps -fmodules-strict-context-hash \ +// RUN: -fmodules-cache-path=%t %s -Rmodule-build 2> %t1 +// RUN: %clang_cc1 -iquote "/dev/null" -iquote %S/Inputs/ASTHash/ -fsyntax-only \ +// RUN: -fmodules -fimplicit-module-maps -fmodules-strict-context-hash \ +// RUN: -fmodules-cache-path=%t %s -Rmodule-build 2> %t2 +// RUN: cat %t1 | grep "remark: building module 'MyHeader2'" | cut -d "'" -f 4 \ +// RUN: | while read -r MODULE; do llvm-bcanalyzer --dump --disable-histogram \ +// RUN: $MODULE | grep "AST_SIGNATURE" > %t1.sig; done +// RUN: cat %t2 | grep "remark: building module 'MyHeader2'" | cut -d "'" -f 4 \ +// RUN: | while read -r MODULE; do llvm-bcanalyzer --dump --disable-histogram \ +// RUN: $MODULE | grep "AST_SIGNATURE" > %t1.sig; done +// RUN: diff %t1.sig %t2.sig + +#include "my_header_2.h" + +my_int var = 42; diff --git a/clang/test/Modules/Inputs/ASTHash/module.modulemap b/clang/test/Modules/Inputs/ASTHash/module.modulemap new file mode 100644 --- /dev/null +++ b/clang/test/Modules/Inputs/ASTHash/module.modulemap @@ -0,0 +1,8 @@ +module MyHeader1 { + header "my_header_1.h" +} + +module MyHeader2 { + header "my_header_2.h" + export * +} diff --git a/clang/test/Modules/Inputs/ASTHash/my_header_1.h b/clang/test/Modules/Inputs/ASTHash/my_header_1.h new file mode 100644 --- /dev/null +++ b/clang/test/Modules/Inputs/ASTHash/my_header_1.h @@ -0,0 +1 @@ +typedef int my_int; diff --git a/clang/test/Modules/Inputs/ASTHash/my_header_2.h b/clang/test/Modules/Inputs/ASTHash/my_header_2.h new file mode 100644 --- /dev/null +++ b/clang/test/Modules/Inputs/ASTHash/my_header_2.h @@ -0,0 +1,3 @@ +#include "my_header_1.h" + +extern my_int var;