diff --git a/clang/include/clang/Basic/ObjCRuntime.h b/clang/include/clang/Basic/ObjCRuntime.h --- a/clang/include/clang/Basic/ObjCRuntime.h +++ b/clang/include/clang/Basic/ObjCRuntime.h @@ -18,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/HashBuilder.h" #include "llvm/Support/VersionTuple.h" #include @@ -480,6 +481,12 @@ friend llvm::hash_code hash_value(const ObjCRuntime &OCR) { return llvm::hash_combine(OCR.getKind(), OCR.getVersion()); } + + template + friend void addHash(llvm::HashBuilderImpl &HBuilder, + const ObjCRuntime &OCR) { + HBuilder.add(OCR.getKind(), OCR.getVersion()); + } }; raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value); diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -16,6 +16,7 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/HashBuilder.h" #include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h" #include #include @@ -72,6 +73,12 @@ llvm::hash_code hash_value() const; + template + friend void addHash(llvm::HashBuilderImpl &HBuilder, + const SanitizerMask &SM) { + HBuilder.addRange(&SM.maskLoToHigh[0], &SM.maskLoToHigh[kNumElem]); + } + constexpr explicit operator bool() const { return maskLoToHigh[0] || maskLoToHigh[1]; } diff --git a/clang/include/clang/Lex/HeaderSearchOptions.h b/clang/include/clang/Lex/HeaderSearchOptions.h --- a/clang/include/clang/Lex/HeaderSearchOptions.h +++ b/clang/include/clang/Lex/HeaderSearchOptions.h @@ -14,10 +14,11 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/HashBuilder.h" #include +#include #include #include -#include namespace clang { @@ -256,11 +257,23 @@ return llvm::hash_combine(E.Path, E.Group, E.IsFramework, E.IgnoreSysRoot); } +template +inline void addHash(llvm::HashBuilderImpl &HBuilder, + const HeaderSearchOptions::Entry &E) { + HBuilder.add(E.Path, E.Group, E.IsFramework, E.IgnoreSysRoot); +} + inline llvm::hash_code hash_value(const HeaderSearchOptions::SystemHeaderPrefix &SHP) { return llvm::hash_combine(SHP.Prefix, SHP.IsSystemHeader); } +template +inline void addHash(llvm::HashBuilderImpl &HBuilder, + const HeaderSearchOptions::SystemHeaderPrefix &SHP) { + HBuilder.add(SHP.Prefix, SHP.IsSystemHeader); +} + } // namespace clang #endif // LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H diff --git a/clang/include/clang/Serialization/ModuleFileExtension.h b/clang/include/clang/Serialization/ModuleFileExtension.h --- a/clang/include/clang/Serialization/ModuleFileExtension.h +++ b/clang/include/clang/Serialization/ModuleFileExtension.h @@ -11,13 +11,14 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/ExtensibleRTTI.h" +#include "llvm/Support/HashBuilder.h" +#include "llvm/Support/MD5.h" #include #include namespace llvm { class BitstreamCursor; class BitstreamWriter; -class hash_code; class raw_ostream; } @@ -74,19 +75,20 @@ virtual ModuleFileExtensionMetadata getExtensionMetadata() const = 0; /// Hash information about the presence of this extension into the - /// module hash code. + /// module hash. /// - /// The module hash code is used to distinguish different variants - /// of a module that are incompatible. If the presence, absence, or - /// version of the module file extension should force the creation - /// of a separate set of module files, override this method to - /// combine that distinguishing information into the module hash - /// code. + /// The module hash is used to distinguish different variants of a module that + /// are incompatible. If the presence, absence, or version of the module file + /// extension should force the creation of a separate set of module files, + /// override this method to combine that distinguishing information into the + /// module hash. /// - /// The default implementation of this function simply returns the - /// hash code as given, so the presence/absence of this extension - /// does not distinguish module files. - virtual llvm::hash_code hashExtension(llvm::hash_code c) const; + /// The default implementation of this function simply does nothing, so the + /// presence/absence of this extension does not distinguish module files. + using ExtensionHashBuilder = + llvm::HashBuilderImpl; + virtual void hashExtension(ExtensionHashBuilder &HBuilder) const; /// Create a new module file extension writer, which will be /// responsible for writing the extension contents into a particular diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -78,6 +78,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/HashBuilder.h" #include "llvm/Support/Host.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" @@ -4469,116 +4470,101 @@ } std::string CompilerInvocation::getModuleHash() const { + // FIXME: We want to use something cryptographically sound. This was + // initially using CityHash (via `llvm::hash_code`). We moved to `llvm::MD5`. + // Is thie appropriate ? + llvm::HashBuilder HBuilder; + // Note: For QoI reasons, the things we use as a hash here should all be // dumped via the -module-info flag. - using llvm::hash_code; - using llvm::hash_value; - using llvm::hash_combine; - using llvm::hash_combine_range; // Start the signature with the compiler version. - // FIXME: We'd rather use something more cryptographically sound than - // CityHash, but this will do for now. - hash_code code = hash_value(getClangFullRepositoryVersion()); + HBuilder.add(getClangFullRepositoryVersion()); // Also include the serialization version, in case LLVM_APPEND_VC_REV is off // and getClangFullRepositoryVersion() doesn't include git revision. - code = hash_combine(code, serialization::VERSION_MAJOR, - serialization::VERSION_MINOR); + HBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR); // Extend the signature with the language options -#define LANGOPT(Name, Bits, Default, Description) \ - code = hash_combine(code, LangOpts->Name); -#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ - code = hash_combine(code, static_cast(LangOpts->get##Name())); +#define LANGOPT(Name, Bits, Default, Description) HBuilder.add(LangOpts->Name); +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + HBuilder.add(static_cast(LangOpts->get##Name())); #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" - for (StringRef Feature : LangOpts->ModuleFeatures) - code = hash_combine(code, Feature); + HBuilder.addRange(LangOpts->ModuleFeatures); - code = hash_combine(code, LangOpts->ObjCRuntime); - const auto &BCN = LangOpts->CommentOpts.BlockCommandNames; - code = hash_combine(code, hash_combine_range(BCN.begin(), BCN.end())); + HBuilder.add(LangOpts->ObjCRuntime); + HBuilder.addRange(LangOpts->CommentOpts.BlockCommandNames); // Extend the signature with the target options. - code = hash_combine(code, TargetOpts->Triple, TargetOpts->CPU, - TargetOpts->TuneCPU, TargetOpts->ABI); - for (const auto &FeatureAsWritten : TargetOpts->FeaturesAsWritten) - code = hash_combine(code, FeatureAsWritten); + HBuilder.add(TargetOpts->Triple, TargetOpts->CPU, TargetOpts->TuneCPU, + TargetOpts->ABI); + HBuilder.addRange(TargetOpts->FeaturesAsWritten); // Extend the signature with preprocessor options. const PreprocessorOptions &ppOpts = getPreprocessorOpts(); - const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); - code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord); + HBuilder.add(ppOpts.UsePredefines, ppOpts.DetailedRecord); - for (const auto &I : getPreprocessorOpts().Macros) { + const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); + for (const auto &Macro : getPreprocessorOpts().Macros) { // If we're supposed to ignore this macro for the purposes of modules, // don't put it into the hash. if (!hsOpts.ModulesIgnoreMacros.empty()) { // Check whether we're ignoring this macro. - StringRef MacroDef = I.first; + StringRef MacroDef = Macro.first; if (hsOpts.ModulesIgnoreMacros.count( llvm::CachedHashString(MacroDef.split('=').first))) continue; } - code = hash_combine(code, I.first, I.second); + HBuilder.add(Macro); } // Extend the signature with the sysroot and other header search options. - code = hash_combine(code, hsOpts.Sysroot, - hsOpts.ModuleFormat, - hsOpts.UseDebugInfo, - hsOpts.UseBuiltinIncludes, - hsOpts.UseStandardSystemIncludes, - hsOpts.UseStandardCXXIncludes, - hsOpts.UseLibcxx, - hsOpts.ModulesValidateDiagnosticOptions); - code = hash_combine(code, hsOpts.ResourceDir); + HBuilder.add(hsOpts.Sysroot, hsOpts.ModuleFormat, hsOpts.UseDebugInfo, + hsOpts.UseBuiltinIncludes, hsOpts.UseStandardSystemIncludes, + hsOpts.UseStandardCXXIncludes, hsOpts.UseLibcxx, + hsOpts.ModulesValidateDiagnosticOptions); + HBuilder.add(hsOpts.ResourceDir); if (hsOpts.ModulesStrictContextHash) { - hash_code SHPC = hash_combine_range(hsOpts.SystemHeaderPrefixes.begin(), - hsOpts.SystemHeaderPrefixes.end()); - hash_code UEC = hash_combine_range(hsOpts.UserEntries.begin(), - hsOpts.UserEntries.end()); - code = hash_combine(code, hsOpts.SystemHeaderPrefixes.size(), SHPC, - hsOpts.UserEntries.size(), UEC); + HBuilder.addRange(hsOpts.SystemHeaderPrefixes); + HBuilder.addRange(hsOpts.UserEntries); const DiagnosticOptions &diagOpts = getDiagnosticOpts(); - #define DIAGOPT(Name, Bits, Default) \ - code = hash_combine(code, diagOpts.Name); - #define ENUM_DIAGOPT(Name, Type, Bits, Default) \ - code = hash_combine(code, diagOpts.get##Name()); - #include "clang/Basic/DiagnosticOptions.def" - #undef DIAGOPT - #undef ENUM_DIAGOPT +#define DIAGOPT(Name, Bits, Default) HBuilder.add(diagOpts.Name); +#define ENUM_DIAGOPT(Name, Type, Bits, Default) \ + HBuilder.add(diagOpts.get##Name()); +#include "clang/Basic/DiagnosticOptions.def" +#undef DIAGOPT +#undef ENUM_DIAGOPT } // Extend the signature with the user build path. - code = hash_combine(code, hsOpts.ModuleUserBuildPath); + HBuilder.add(hsOpts.ModuleUserBuildPath); // Extend the signature with the module file extensions. - const FrontendOptions &frontendOpts = getFrontendOpts(); - for (const auto &ext : frontendOpts.ModuleFileExtensions) { - code = ext->hashExtension(code); - } + for (const auto &ext : getFrontendOpts().ModuleFileExtensions) + ext->hashExtension(HBuilder); // When compiling with -gmodules, also hash -fdebug-prefix-map as it // affects the debug info in the PCM. if (getCodeGenOpts().DebugTypeExtRefs) - for (const auto &KeyValue : getCodeGenOpts().DebugPrefixMap) - code = hash_combine(code, KeyValue.first, KeyValue.second); + HBuilder.addRange(getCodeGenOpts().DebugPrefixMap); // Extend the signature with the enabled sanitizers, if at least one is // enabled. Sanitizers which cannot affect AST generation aren't hashed. SanitizerSet SanHash = LangOpts->Sanitize; SanHash.clear(getPPTransparentSanitizers()); if (!SanHash.empty()) - code = hash_combine(code, SanHash.Mask); + HBuilder.add(SanHash.Mask); - return toString(llvm::APInt(64, code), 36, /*Signed=*/false); + llvm::MD5::MD5Result Result; + HBuilder.getHasher().final(Result); + uint64_t Hash = Result.high() ^ Result.low(); + return toString(llvm::APInt(64, Hash), 36, /*Signed=*/false); } void CompilerInvocation::generateCC1CommandLine( diff --git a/clang/lib/Frontend/TestModuleFileExtension.h b/clang/lib/Frontend/TestModuleFileExtension.h --- a/clang/lib/Frontend/TestModuleFileExtension.h +++ b/clang/lib/Frontend/TestModuleFileExtension.h @@ -55,7 +55,7 @@ ModuleFileExtensionMetadata getExtensionMetadata() const override; - llvm::hash_code hashExtension(llvm::hash_code Code) const override; + void hashExtension(ExtensionHashBuilder &HBuilder) const override; std::unique_ptr createExtensionWriter(ASTWriter &Writer) override; diff --git a/clang/lib/Frontend/TestModuleFileExtension.cpp b/clang/lib/Frontend/TestModuleFileExtension.cpp --- a/clang/lib/Frontend/TestModuleFileExtension.cpp +++ b/clang/lib/Frontend/TestModuleFileExtension.cpp @@ -93,16 +93,14 @@ return { BlockName, MajorVersion, MinorVersion, UserInfo }; } -llvm::hash_code TestModuleFileExtension::hashExtension( - llvm::hash_code Code) const { +void TestModuleFileExtension::hashExtension( + ExtensionHashBuilder &HBuilder) const { if (Hashed) { - Code = llvm::hash_combine(Code, BlockName); - Code = llvm::hash_combine(Code, MajorVersion); - Code = llvm::hash_combine(Code, MinorVersion); - Code = llvm::hash_combine(Code, UserInfo); + HBuilder.add(BlockName); + HBuilder.add(MajorVersion); + HBuilder.add(MinorVersion); + HBuilder.add(UserInfo); } - - return Code; } std::unique_ptr diff --git a/clang/lib/Serialization/ModuleFileExtension.cpp b/clang/lib/Serialization/ModuleFileExtension.cpp --- a/clang/lib/Serialization/ModuleFileExtension.cpp +++ b/clang/lib/Serialization/ModuleFileExtension.cpp @@ -11,12 +11,10 @@ char ModuleFileExtension::ID = 0; -ModuleFileExtension::~ModuleFileExtension() { } +ModuleFileExtension::~ModuleFileExtension() {} -llvm::hash_code ModuleFileExtension::hashExtension(llvm::hash_code Code) const { - return Code; -} +void ModuleFileExtension::hashExtension(ExtensionHashBuilder &HBuilder) const {} -ModuleFileExtensionWriter::~ModuleFileExtensionWriter() { } +ModuleFileExtensionWriter::~ModuleFileExtensionWriter() {} -ModuleFileExtensionReader::~ModuleFileExtensionReader() { } +ModuleFileExtensionReader::~ModuleFileExtensionReader() {} diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp --- a/clang/unittests/Frontend/CompilerInvocationTest.cpp +++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp @@ -860,9 +860,7 @@ return {}; }; - llvm::hash_code hashExtension(llvm::hash_code Code) const override { - return {}; - } + void hashExtension(ExtensionHashBuilder &HBuilder) const override {} std::unique_ptr createExtensionWriter(ASTWriter &Writer) override { diff --git a/llvm/include/llvm/Support/HashBuilder.h b/llvm/include/llvm/Support/HashBuilder.h --- a/llvm/include/llvm/Support/HashBuilder.h +++ b/llvm/include/llvm/Support/HashBuilder.h @@ -164,7 +164,7 @@ /// /// ``` /// template - /// void addHash(HashBuilder &HBuilder, + /// void addHash(HashBuilderImpl &HBuilder, /// const UserDefinedStruct &Value); /// ``` /// diff --git a/llvm/include/llvm/Support/VersionTuple.h b/llvm/include/llvm/Support/VersionTuple.h --- a/llvm/include/llvm/Support/VersionTuple.h +++ b/llvm/include/llvm/Support/VersionTuple.h @@ -17,6 +17,7 @@ #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/Optional.h" +#include "llvm/Support/HashBuilder.h" #include #include @@ -164,6 +165,12 @@ return llvm::hash_combine(VT.Major, VT.Minor, VT.Subminor, VT.Build); } + template + friend void addHash(HashBuilderImpl &HBuilder, + const VersionTuple &VT) { + HBuilder.add(VT.Major, VT.Minor, VT.Subminor, VT.Build); + } + /// Retrieve a string representation of the version number. std::string getAsString() const;