Hi Vedant and Eric, Please retry after r322350. I suspect an interaction between templates and friend functions is causing this issue. This revision disables hashing for friend functions for now.
Richard On Thu, Jan 11, 2018 at 3:34 PM, Eric Fiselier <e...@efcs.ca> wrote: > I'm hitting the same issue as well. > > Please let me know if there is anything I can do to get this fixed quickly. > > /Eric > > On Wed, Jan 3, 2018 at 5:20 PM, Richard Trieu via cfe-commits < > cfe-commits@lists.llvm.org> wrote: > >> Vedant, >> >> I'm looking into it. >> >> >> On Wed, Jan 3, 2018 at 11:12 AM, Vedant Kumar <v...@apple.com> wrote: >> >>> Oops, the build log was too big to attach. Resending with just the bot >>> link, then: >>> http://lab.llvm.org:8080/green/view/Experimental/job/clang-s >>> tage2-coverage-R/2193/consoleText >>> >>> vedant >>> >>> On Jan 3, 2018, at 11:09 AM, Vedant Kumar <v...@apple.com> wrote: >>> >>> Hi Richard, >>> >>> This commit is causing an unexpected build failure in the stage2 >>> modules-enabled coverage bot. I've attached the build log. Here's the error: >>> >>> [3685/3899] >>> /Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/host-compiler/bin/clang++ >>> -DGTEST_HAS_RTTI=0 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS >>> -D__STDC_LIMIT_MACROS -Itools/lld/COFF >>> -I/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/COFF >>> >>> -I/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/include >>> -Itools/lld/include -I/usr/include/libxml2 -Iinclude >>> -I/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/include >>> -fPIC -fvisibility-inlines-hidden -Werror=date-time >>> -Werror=unguarded-availability-new -std=c++11 -fmodules >>> -fmodules-cache-path=/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/clang-build/module.cache >>> -fcxx-modules -Wall -W -Wno-unused-parameter -Wwrite-strings -Wcast-qual >>> -Wmissing-field-initializers -pedantic -Wno-long-long >>> -Wcovered-switch-default -Wnon-virtual-dtor -Wdelete-non-virtual-dtor >>> -Wstring-conversion -fcolor-diagnostics >>> -fprofile-instr-generate='/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/clang-build/profiles/%6m.profraw' >>> -fcoverage-mapping -O3 -DNDEBUG -fno-exceptions -fno-rtti -MMD -MT >>> tools/lld/COFF/CMakeFiles/lldCOFF.dir/PDB.cpp.o -MF >>> tools/lld/COFF/CMakeFiles/lldCOFF.dir/PDB.cpp.o.d -o >>> tools/lld/COFF/CMakeFiles/lldCOFF.dir/PDB.cpp.o -c >>> /Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/COFF/PDB.cpp >>> FAILED: tools/lld/COFF/CMakeFiles/lldCOFF.dir/PDB.cpp.o >>> /Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/host-compiler/bin/clang++ >>> -DGTEST_HAS_RTTI=0 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS >>> -D__STDC_LIMIT_MACROS -Itools/lld/COFF >>> -I/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/COFF >>> >>> -I/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/include >>> -Itools/lld/include -I/usr/include/libxml2 -Iinclude >>> -I/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/include >>> -fPIC -fvisibility-inlines-hidden -Werror=date-time >>> -Werror=unguarded-availability-new -std=c++11 -fmodules >>> -fmodules-cache-path=/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/clang-build/module.cache >>> -fcxx-modules -Wall -W -Wno-unused-parameter -Wwrite-strings -Wcast-qual >>> -Wmissing-field-initializers -pedantic -Wno-long-long >>> -Wcovered-switch-default -Wnon-virtual-dtor -Wdelete-non-virtual-dtor >>> -Wstring-conversion -fcolor-diagnostics >>> -fprofile-instr-generate='/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/clang-build/profiles/%6m.profraw' >>> -fcoverage-mapping -O3 -DNDEBUG -fno-exceptions -fno-rtti -MMD -MT >>> tools/lld/COFF/CMakeFiles/lldCOFF.dir/PDB.cpp.o -MF >>> tools/lld/COFF/CMakeFiles/lldCOFF.dir/PDB.cpp.o.d -o >>> tools/lld/COFF/CMakeFiles/lldCOFF.dir/PDB.cpp.o -c >>> /Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/COFF/PDB.cpp >>> In module 'std' imported from >>> /Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/COFF/Config.h:16: >>> /Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/host-compiler/include/c++/v1/list:389:10: >>> error: 'std::__1::operator==' has different definitions in different >>> modules; definition in module 'std.list' first difference is function body >>> bool operator==(const __list_iterator& __x, const __list_iterator& __y) >>> ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >>> /Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/host-compiler/include/c++/v1/list:389:10: >>> note: but in 'std.list' found a different body >>> bool operator==(const __list_iterator& __x, const __list_iterator& __y) >>> ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >>> /Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/host-compiler/include/c++/v1/list:394:11: >>> error: 'std::__1::operator!=' has different definitions in different >>> modules; definition in module 'std.list' first difference is function body >>> bool operator!=(const __list_iterator& __x, const __list_iterator& __y) >>> ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >>> /Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/host-compiler/include/c++/v1/list:394:11: >>> note: but in 'std.list' found a different body >>> bool operator!=(const __list_iterator& __x, const __list_iterator& __y) >>> ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >>> 2 errors generated. >>> >>> I'm not sure how to act on this, because it looks like the error is >>> saying that a definition in 'std.list' is incompatible with itself. >>> >>> I've temporarily disabled building with modules enabled on the bot. >>> Could you take a look? >>> >>> thanks, >>> vedant >>> >>> http://lab.llvm.org:8080/green/view/Experimental/job/clang-s >>> tage2-coverage-R/2193 >>> >>> <coverage-build-log.txt> >>> >>> >>> >>> On Dec 22, 2017, at 4:41 PM, Richard Trieu via cfe-commits < >>> cfe-commits@lists.llvm.org> wrote: >>> >>> Author: rtrieu >>> Date: Fri Dec 22 16:41:01 2017 >>> New Revision: 321395 >>> >>> URL: http://llvm.org/viewvc/llvm-project?rev=321395&view=rev >>> Log: >>> [ODRHash] Support ODR violation detection in functions. >>> >>> Extend the hashing to functions, which allows detection of function >>> definition >>> mismatches across modules. This is a re-commit of r320230. >>> >>> Modified: >>> cfe/trunk/include/clang/AST/Decl.h >>> cfe/trunk/include/clang/AST/ODRHash.h >>> cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td >>> cfe/trunk/include/clang/Serialization/ASTReader.h >>> cfe/trunk/lib/AST/Decl.cpp >>> cfe/trunk/lib/AST/ODRHash.cpp >>> cfe/trunk/lib/Serialization/ASTReader.cpp >>> cfe/trunk/lib/Serialization/ASTReaderDecl.cpp >>> cfe/trunk/lib/Serialization/ASTWriterDecl.cpp >>> cfe/trunk/test/Modules/odr_hash.cpp >>> >>> Modified: cfe/trunk/include/clang/AST/Decl.h >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ >>> AST/Decl.h?rev=321395&r1=321394&r2=321395&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/include/clang/AST/Decl.h (original) >>> +++ cfe/trunk/include/clang/AST/Decl.h Fri Dec 22 16:41:01 2017 >>> @@ -1759,6 +1759,11 @@ protected: >>> unsigned IsCopyDeductionCandidate : 1; >>> >>> private: >>> + >>> + /// Store the ODRHash after first calculation. >>> + unsigned HasODRHash : 1; >>> + unsigned ODRHash; >>> + >>> /// \brief End part of this FunctionDecl's source range. >>> /// >>> /// We could compute the full range in getSourceRange(). However, when >>> we're >>> @@ -1841,8 +1846,9 @@ protected: >>> IsExplicitlyDefaulted(false), HasImplicitReturnZero(false), >>> IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified), >>> InstantiationIsPending(false), UsesSEHTry(false), >>> HasSkippedBody(false), >>> - WillHaveBody(false), IsCopyDeductionCandidate(false), >>> - EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {} >>> + WillHaveBody(false), IsCopyDeductionCandidate(false), >>> HasODRHash(false), >>> + ODRHash(0), EndRangeLoc(NameInfo.getEndLoc()), >>> + DNLoc(NameInfo.getInfo()) {} >>> >>> using redeclarable_base = Redeclarable<FunctionDecl>; >>> >>> @@ -2439,6 +2445,10 @@ public: >>> /// returns 0. >>> unsigned getMemoryFunctionKind() const; >>> >>> + /// \brief Returns ODRHash of the function. This value is calculated >>> and >>> + /// stored on first call, then the stored value returned on the other >>> calls. >>> + unsigned getODRHash(); >>> + >>> // Implement isa/cast/dyncast/etc. >>> static bool classof(const Decl *D) { return classofKind(D->getKind()); >>> } >>> static bool classofKind(Kind K) { >>> >>> Modified: cfe/trunk/include/clang/AST/ODRHash.h >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ >>> AST/ODRHash.h?rev=321395&r1=321394&r2=321395&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/include/clang/AST/ODRHash.h (original) >>> +++ cfe/trunk/include/clang/AST/ODRHash.h Fri Dec 22 16:41:01 2017 >>> @@ -53,6 +53,10 @@ public: >>> // more information than the AddDecl class. >>> void AddCXXRecordDecl(const CXXRecordDecl *Record); >>> >>> + // Use this for ODR checking functions between modules. This method >>> compares >>> + // more information than the AddDecl class. >>> + void AddFunctionDecl(const FunctionDecl *Function); >>> + >>> // Process SubDecls of the main Decl. This method calls the >>> DeclVisitor >>> // while AddDecl does not. >>> void AddSubDecl(const Decl *D); >>> >>> Modified: cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ >>> Basic/DiagnosticSerializationKinds.td?rev=321395&r1=321394&r >>> 2=321395&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td >>> (original) >>> +++ cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td Fri >>> Dec 22 16:41:01 2017 >>> @@ -270,6 +270,29 @@ def note_module_odr_violation_mismatch_d >>> "friend function %2|" >>> "}1">; >>> >>> +def err_module_odr_violation_function : Error< >>> + "%q0 has different definitions in different modules; " >>> + "%select{definition in module '%2'|defined here}1 " >>> + "first difference is " >>> + "%select{" >>> + "return type is %4|" >>> + "%ordinal4 parameter with name %5|" >>> + "%ordinal4 parameter with type %5%select{| decayed from %7}6|" >>> + "%ordinal4 parameter with%select{out|}5 a default argument|" >>> + "%ordinal4 parameter with a default argument|" >>> + "function body" >>> + "}3">; >>> + >>> +def note_module_odr_violation_function : Note<"but in '%0' found " >>> + "%select{" >>> + "different return type %2|" >>> + "%ordinal2 parameter with name %3|" >>> + "%ordinal2 parameter with type %3%select{| decayed from %5}4|" >>> + "%ordinal2 parameter with%select{out|}3 a default argument|" >>> + "%ordinal2 parameter with a different default argument|" >>> + "a different body" >>> + "}1">; >>> + >>> def err_module_odr_violation_mismatch_decl_unknown : Error< >>> "%q0 %select{with definition in module '%2'|defined here}1 has >>> different " >>> "definitions in different modules; first difference is this " >>> >>> Modified: cfe/trunk/include/clang/Serialization/ASTReader.h >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ >>> Serialization/ASTReader.h?rev=321395&r1=321394&r2=321395&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/include/clang/Serialization/ASTReader.h (original) >>> +++ cfe/trunk/include/clang/Serialization/ASTReader.h Fri Dec 22 >>> 16:41:01 2017 >>> @@ -1092,6 +1092,10 @@ private: >>> llvm::SmallDenseMap<CXXRecordDecl *, llvm::SmallVector<DataPointers, >>> 2>, 2> >>> PendingOdrMergeFailures; >>> >>> + /// \brief Function definitions in which we found an ODR violation. >>> + llvm::SmallDenseMap<FunctionDecl *, llvm::SmallVector<FunctionDecl >>> *, 2>, 2> >>> + PendingFunctionOdrMergeFailures; >>> + >>> /// \brief DeclContexts in which we have diagnosed an ODR violation. >>> llvm::SmallPtrSet<DeclContext*, 2> DiagnosedOdrMergeFailures; >>> >>> >>> Modified: cfe/trunk/lib/AST/Decl.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.c >>> pp?rev=321395&r1=321394&r2=321395&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/AST/Decl.cpp (original) >>> +++ cfe/trunk/lib/AST/Decl.cpp Fri Dec 22 16:41:01 2017 >>> @@ -26,6 +26,7 @@ >>> #include "clang/AST/Expr.h" >>> #include "clang/AST/ExprCXX.h" >>> #include "clang/AST/ExternalASTSource.h" >>> +#include "clang/AST/ODRHash.h" >>> #include "clang/AST/PrettyPrinter.h" >>> #include "clang/AST/Redeclarable.h" >>> #include "clang/AST/Stmt.h" >>> @@ -3604,6 +3605,25 @@ unsigned FunctionDecl::getMemoryFunction >>> return 0; >>> } >>> >>> +unsigned FunctionDecl::getODRHash() { >>> + if (HasODRHash) >>> + return ODRHash; >>> + >>> + if (FunctionDecl *Definition = getDefinition()) { >>> + if (Definition != this) { >>> + HasODRHash = true; >>> + ODRHash = Definition->getODRHash(); >>> + return ODRHash; >>> + } >>> + } >>> + >>> + class ODRHash Hash; >>> + Hash.AddFunctionDecl(this); >>> + HasODRHash = true; >>> + ODRHash = Hash.CalculateHash(); >>> + return ODRHash; >>> +} >>> + >>> //===------------------------------------------------------- >>> ---------------===// >>> // FieldDecl Implementation >>> //===------------------------------------------------------- >>> ---------------===// >>> >>> Modified: cfe/trunk/lib/AST/ODRHash.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ODRHas >>> h.cpp?rev=321395&r1=321394&r2=321395&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/AST/ODRHash.cpp (original) >>> +++ cfe/trunk/lib/AST/ODRHash.cpp Fri Dec 22 16:41:01 2017 >>> @@ -466,6 +466,36 @@ void ODRHash::AddCXXRecordDecl(const CXX >>> } >>> } >>> >>> +void ODRHash::AddFunctionDecl(const FunctionDecl *Function) { >>> + assert(Function && "Expecting non-null pointer."); >>> + >>> + // Skip hashing these kinds of function. >>> + if (Function->isImplicit()) return; >>> + if (Function->isDefaulted()) return; >>> + if (Function->isDeleted()) return; >>> + if (!Function->hasBody()) return; >>> + if (!Function->getBody()) return; >>> + >>> + // Skip functions that are specializations or in specialization >>> context. >>> + const DeclContext *DC = Function; >>> + while (DC) { >>> + if (isa<ClassTemplateSpecializationDecl>(DC)) return; >>> + if (auto *F = dyn_cast<FunctionDecl>(DC)) >>> + if (F->isFunctionTemplateSpecialization()) return; >>> + DC = DC->getParent(); >>> + } >>> + >>> + AddDecl(Function); >>> + >>> + AddQualType(Function->getReturnType()); >>> + >>> + ID.AddInteger(Function->param_size()); >>> + for (auto Param : Function->parameters()) >>> + AddSubDecl(Param); >>> + >>> + AddStmt(Function->getBody()); >>> +} >>> + >>> void ODRHash::AddDecl(const Decl *D) { >>> assert(D && "Expecting non-null pointer."); >>> D = D->getCanonicalDecl(); >>> >>> Modified: cfe/trunk/lib/Serialization/ASTReader.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serializat >>> ion/ASTReader.cpp?rev=321395&r1=321394&r2=321395&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) >>> +++ cfe/trunk/lib/Serialization/ASTReader.cpp Fri Dec 22 16:41:01 2017 >>> @@ -9235,8 +9235,16 @@ void ASTReader::finishPendingActions() { >>> const FunctionDecl *Defn = nullptr; >>> if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) { >>> FD->setLazyBody(PB->second); >>> - } else >>> - mergeDefinitionVisibility(const_cast<FunctionDecl*>(Defn), FD); >>> + } else { >>> + auto *NonConstDefn = const_cast<FunctionDecl*>(Defn); >>> + mergeDefinitionVisibility(NonConstDefn, FD); >>> + >>> + if (!FD->isLateTemplateParsed() && >>> + !NonConstDefn->isLateTemplateParsed() && >>> + FD->getODRHash() != NonConstDefn->getODRHash()) { >>> + PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn); >>> + } >>> + } >>> continue; >>> } >>> >>> @@ -9253,7 +9261,8 @@ void ASTReader::finishPendingActions() { >>> } >>> >>> void ASTReader::diagnoseOdrViolations() { >>> - if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty()) >>> + if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty() >>> && >>> + PendingFunctionOdrMergeFailures.empty()) >>> return; >>> >>> // Trigger the import of the full definition of each class that had any >>> @@ -9275,6 +9284,20 @@ void ASTReader::diagnoseOdrViolations() >>> } >>> } >>> >>> + // Trigger the import of functions. >>> + auto FunctionOdrMergeFailures = std::move(PendingFunctionOdrMe >>> rgeFailures); >>> + PendingFunctionOdrMergeFailures.clear(); >>> + for (auto &Merge : FunctionOdrMergeFailures) { >>> + Merge.first->buildLookup(); >>> + Merge.first->decls_begin(); >>> + Merge.first->getBody(); >>> + for (auto &FD : Merge.second) { >>> + FD->buildLookup(); >>> + FD->decls_begin(); >>> + FD->getBody(); >>> + } >>> + } >>> + >>> // For each declaration from a merged context, check that the canonical >>> // definition of that context also contains a declaration of the same >>> // entity. >>> @@ -9357,13 +9380,35 @@ void ASTReader::diagnoseOdrViolations() >>> } >>> } >>> >>> - if (OdrMergeFailures.empty()) >>> + if (OdrMergeFailures.empty() && FunctionOdrMergeFailures.empty()) >>> return; >>> >>> // Ensure we don't accidentally recursively enter deserialization while >>> // we're producing our diagnostics. >>> Deserializing RecursionGuard(this); >>> >>> + // Common code for hashing helpers. >>> + ODRHash Hash; >>> + auto ComputeQualTypeODRHash = [&Hash](QualType Ty) { >>> + Hash.clear(); >>> + Hash.AddQualType(Ty); >>> + return Hash.CalculateHash(); >>> + }; >>> + >>> + auto ComputeODRHash = [&Hash](const Stmt *S) { >>> + assert(S); >>> + Hash.clear(); >>> + Hash.AddStmt(S); >>> + return Hash.CalculateHash(); >>> + }; >>> + >>> + auto ComputeSubDeclODRHash = [&Hash](const Decl *D) { >>> + assert(D); >>> + Hash.clear(); >>> + Hash.AddSubDecl(D); >>> + return Hash.CalculateHash(); >>> + }; >>> + >>> // Issue any pending ODR-failure diagnostics. >>> for (auto &Merge : OdrMergeFailures) { >>> // If we've already pointed out a specific problem with this class, >>> don't >>> @@ -9411,13 +9456,6 @@ void ASTReader::diagnoseOdrViolations() >>> << SecondModule << Range << DiffType; >>> }; >>> >>> - ODRHash Hash; >>> - auto ComputeQualTypeODRHash = [&Hash](QualType Ty) { >>> - Hash.clear(); >>> - Hash.AddQualType(Ty); >>> - return Hash.CalculateHash(); >>> - }; >>> - >>> unsigned FirstNumBases = FirstDD->NumBases; >>> unsigned FirstNumVBases = FirstDD->NumVBases; >>> unsigned SecondNumBases = SecondDD->NumBases; >>> @@ -9520,14 +9558,12 @@ void ASTReader::diagnoseOdrViolations() >>> if (FirstTemplate && SecondTemplate) { >>> DeclHashes FirstTemplateHashes; >>> DeclHashes SecondTemplateHashes; >>> - ODRHash Hash; >>> >>> auto PopulateTemplateParameterHashs = >>> - [&Hash](DeclHashes &Hashes, const ClassTemplateDecl *TD) { >>> + [&ComputeSubDeclODRHash](DeclHashes &Hashes, >>> + const ClassTemplateDecl *TD) { >>> for (auto *D : TD->getTemplateParameters()->asArray()) { >>> - Hash.clear(); >>> - Hash.AddSubDecl(D); >>> - Hashes.emplace_back(D, Hash.CalculateHash()); >>> + Hashes.emplace_back(D, ComputeSubDeclODRHash(D)); >>> } >>> }; >>> >>> @@ -9696,18 +9732,15 @@ void ASTReader::diagnoseOdrViolations() >>> >>> DeclHashes FirstHashes; >>> DeclHashes SecondHashes; >>> - ODRHash Hash; >>> >>> - auto PopulateHashes = [&Hash, FirstRecord](DeclHashes &Hashes, >>> - CXXRecordDecl >>> *Record) { >>> + auto PopulateHashes = [&ComputeSubDeclODRHash, FirstRecord]( >>> + DeclHashes &Hashes, CXXRecordDecl >>> *Record) { >>> for (auto *D : Record->decls()) { >>> // Due to decl merging, the first CXXRecordDecl is the parent >>> of >>> // Decls in both records. >>> if (!ODRHash::isWhitelistedDecl(D, FirstRecord)) >>> continue; >>> - Hash.clear(); >>> - Hash.AddSubDecl(D); >>> - Hashes.emplace_back(D, Hash.CalculateHash()); >>> + Hashes.emplace_back(D, ComputeSubDeclODRHash(D)); >>> } >>> }; >>> PopulateHashes(FirstHashes, FirstRecord); >>> @@ -9901,19 +9934,6 @@ void ASTReader::diagnoseOdrViolations() >>> << SecondModule << Range << DiffType; >>> }; >>> >>> - auto ComputeODRHash = [&Hash](const Stmt* S) { >>> - assert(S); >>> - Hash.clear(); >>> - Hash.AddStmt(S); >>> - return Hash.CalculateHash(); >>> - }; >>> - >>> - auto ComputeQualTypeODRHash = [&Hash](QualType Ty) { >>> - Hash.clear(); >>> - Hash.AddQualType(Ty); >>> - return Hash.CalculateHash(); >>> - }; >>> - >>> switch (FirstDiffType) { >>> case Other: >>> case EndOfClass: >>> @@ -10488,6 +10508,160 @@ void ASTReader::diagnoseOdrViolations() >>> << Merge.first; >>> } >>> } >>> + >>> + // Issue ODR failures diagnostics for functions. >>> + for (auto &Merge : FunctionOdrMergeFailures) { >>> + enum ODRFunctionDifference { >>> + ReturnType, >>> + ParameterName, >>> + ParameterType, >>> + ParameterSingleDefaultArgument, >>> + ParameterDifferentDefaultArgument, >>> + FunctionBody, >>> + }; >>> + >>> + FunctionDecl *FirstFunction = Merge.first; >>> + std::string FirstModule = getOwningModuleNameForDiagnost >>> ic(FirstFunction); >>> + >>> + bool Diagnosed = false; >>> + for (auto &SecondFunction : Merge.second) { >>> + >>> + if (FirstFunction == SecondFunction) >>> + continue; >>> + >>> + std::string SecondModule = >>> + getOwningModuleNameForDiagnostic(SecondFunction); >>> + >>> + auto ODRDiagError = [FirstFunction, &FirstModule, >>> + this](SourceLocation Loc, SourceRange Range, >>> + ODRFunctionDifference DiffType) { >>> + return Diag(Loc, diag::err_module_odr_violation_function) >>> + << FirstFunction << FirstModule.empty() << FirstModule >>> << Range >>> + << DiffType; >>> + }; >>> + auto ODRDiagNote = [&SecondModule, this](SourceLocation Loc, >>> + SourceRange Range, >>> + ODRFunctionDifference >>> DiffType) { >>> + return Diag(Loc, diag::note_module_odr_violation_function) >>> + << SecondModule << Range << DiffType; >>> + }; >>> + >>> + if (ComputeQualTypeODRHash(FirstFunction->getReturnType()) != >>> + ComputeQualTypeODRHash(SecondFunction->getReturnType())) { >>> + ODRDiagError(FirstFunction->getReturnTypeSourceRange( >>> ).getBegin(), >>> + FirstFunction->getReturnTypeSourceRange(), >>> ReturnType) >>> + << FirstFunction->getReturnType(); >>> + ODRDiagNote(SecondFunction->getReturnTypeSourceRange( >>> ).getBegin(), >>> + SecondFunction->getReturnTypeSourceRange(), >>> ReturnType) >>> + << SecondFunction->getReturnType(); >>> + Diagnosed = true; >>> + break; >>> + } >>> + >>> + assert(FirstFunction->param_size() == >>> SecondFunction->param_size() && >>> + "Merged functions with different number of parameters"); >>> + >>> + auto ParamSize = FirstFunction->param_size(); >>> + bool ParameterMismatch = false; >>> + for (unsigned I = 0; I < ParamSize; ++I) { >>> + auto *FirstParam = FirstFunction->getParamDecl(I); >>> + auto *SecondParam = SecondFunction->getParamDecl(I); >>> + >>> + assert(getContext().hasSameType(FirstParam->getType(), >>> + SecondParam->getType()) && >>> + "Merged function has different parameter types."); >>> + >>> + if (FirstParam->getDeclName() != SecondParam->getDeclName()) { >>> + ODRDiagError(FirstParam->getLocation(), >>> FirstParam->getSourceRange(), >>> + ParameterName) >>> + << I + 1 << FirstParam->getDeclName(); >>> + ODRDiagNote(SecondParam->getLocation(), >>> SecondParam->getSourceRange(), >>> + ParameterName) >>> + << I + 1 << SecondParam->getDeclName(); >>> + ParameterMismatch = true; >>> + break; >>> + }; >>> + >>> + QualType FirstParamType = FirstParam->getType(); >>> + QualType SecondParamType = SecondParam->getType(); >>> + if (FirstParamType != SecondParamType && >>> + ComputeQualTypeODRHash(FirstParamType) != >>> + ComputeQualTypeODRHash(SecondParamType)) { >>> + if (const DecayedType *ParamDecayedType = >>> + FirstParamType->getAs<DecayedType>()) { >>> + ODRDiagError(FirstParam->getLocation(), >>> + FirstParam->getSourceRange(), ParameterType) >>> + << (I + 1) << FirstParamType << true >>> + << ParamDecayedType->getOriginalType(); >>> + } else { >>> + ODRDiagError(FirstParam->getLocation(), >>> + FirstParam->getSourceRange(), ParameterType) >>> + << (I + 1) << FirstParamType << false; >>> + } >>> + >>> + if (const DecayedType *ParamDecayedType = >>> + SecondParamType->getAs<DecayedType>()) { >>> + ODRDiagNote(SecondParam->getLocation(), >>> + SecondParam->getSourceRange(), ParameterType) >>> + << (I + 1) << SecondParamType << true >>> + << ParamDecayedType->getOriginalType(); >>> + } else { >>> + ODRDiagNote(SecondParam->getLocation(), >>> + SecondParam->getSourceRange(), ParameterType) >>> + << (I + 1) << SecondParamType << false; >>> + } >>> + ParameterMismatch = true; >>> + break; >>> + } >>> + >>> + const Expr *FirstInit = FirstParam->getInit(); >>> + const Expr *SecondInit = SecondParam->getInit(); >>> + if ((FirstInit == nullptr) != (SecondInit == nullptr)) { >>> + ODRDiagError(FirstParam->getLocation(), >>> FirstParam->getSourceRange(), >>> + ParameterSingleDefaultArgument) >>> + << (I + 1) << (FirstInit == nullptr) >>> + << (FirstInit ? FirstInit->getSourceRange() : >>> SourceRange()); >>> + ODRDiagNote(SecondParam->getLocation(), >>> SecondParam->getSourceRange(), >>> + ParameterSingleDefaultArgument) >>> + << (I + 1) << (SecondInit == nullptr) >>> + << (SecondInit ? SecondInit->getSourceRange() : >>> SourceRange()); >>> + ParameterMismatch = true; >>> + break; >>> + } >>> + >>> + if (FirstInit && SecondInit && >>> + ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { >>> + ODRDiagError(FirstParam->getLocation(), >>> FirstParam->getSourceRange(), >>> + ParameterDifferentDefaultArgument) >>> + << (I + 1) << FirstInit->getSourceRange(); >>> + ODRDiagNote(SecondParam->getLocation(), >>> SecondParam->getSourceRange(), >>> + ParameterDifferentDefaultArgument) >>> + << (I + 1) << SecondInit->getSourceRange(); >>> + ParameterMismatch = true; >>> + break; >>> + } >>> + >>> + assert(ComputeSubDeclODRHash(FirstParam) == >>> + ComputeSubDeclODRHash(SecondParam) && >>> + "Undiagnosed parameter difference."); >>> + } >>> + >>> + if (ParameterMismatch) { >>> + Diagnosed = true; >>> + break; >>> + } >>> + >>> + // If no error has been generated before now, assume the problem >>> is in >>> + // the body and generate a message. >>> + ODRDiagError(FirstFunction->getLocation(), >>> + FirstFunction->getSourceRange(), FunctionBody); >>> + ODRDiagNote(SecondFunction->getLocation(), >>> + SecondFunction->getSourceRange(), FunctionBody); >>> + Diagnosed = true; >>> + break; >>> + } >>> + assert(Diagnosed && "Unable to emit ODR diagnostic."); >>> + } >>> } >>> >>> void ASTReader::StartedDeserializing() { >>> >>> Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serializat >>> ion/ASTReaderDecl.cpp?rev=321395&r1=321394&r2=321395&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) >>> +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Fri Dec 22 16:41:01 >>> 2017 >>> @@ -796,6 +796,9 @@ void ASTDeclReader::VisitFunctionDecl(Fu >>> FD->setCachedLinkage(Linkage(Record.readInt())); >>> FD->EndRangeLoc = ReadSourceLocation(); >>> >>> + FD->ODRHash = Record.readInt(); >>> + FD->HasODRHash = true; >>> + >>> switch ((FunctionDecl::TemplatedKind)Record.readInt()) { >>> case FunctionDecl::TK_NonTemplate: >>> mergeRedeclarable(FD, Redecl); >>> >>> Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serializat >>> ion/ASTWriterDecl.cpp?rev=321395&r1=321394&r2=321395&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original) >>> +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Fri Dec 22 16:41:01 >>> 2017 >>> @@ -538,6 +538,8 @@ void ASTDeclWriter::VisitFunctionDecl(Fu >>> Record.push_back(D->getLinkageInternal()); >>> Record.AddSourceLocation(D->getLocEnd()); >>> >>> + Record.push_back(D->getODRHash()); >>> + >>> Record.push_back(D->getTemplatedKind()); >>> switch (D->getTemplatedKind()) { >>> case FunctionDecl::TK_NonTemplate: >>> @@ -2072,6 +2074,7 @@ void ASTWriter::WriteDeclAbbrevs() { >>> Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // LateParsed >>> Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage >>> Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LocEnd >>> + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // ODRHash >>> Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // TemplateKind >>> // This Array slurps the rest of the record. Fortunately we want to >>> encode >>> // (nearly) all the remaining (variable number of) fields in the same >>> way. >>> >>> Modified: cfe/trunk/test/Modules/odr_hash.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/o >>> dr_hash.cpp?rev=321395&r1=321394&r2=321395&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/test/Modules/odr_hash.cpp (original) >>> +++ cfe/trunk/test/Modules/odr_hash.cpp Fri Dec 22 16:41:01 2017 >>> @@ -557,11 +557,11 @@ S10 s10; >>> >>> #if defined(FIRST) >>> struct S11 { >>> - void A(int x) {} >>> + void A(int x); >>> }; >>> #elif defined(SECOND) >>> struct S11 { >>> - void A(int y) {} >>> + void A(int y); >>> }; >>> #else >>> S11 s11; >>> @@ -571,11 +571,11 @@ S11 s11; >>> >>> #if defined(FIRST) >>> struct S12 { >>> - void A(int x) {} >>> + void A(int x); >>> }; >>> #elif defined(SECOND) >>> struct S12 { >>> - void A(int x = 1) {} >>> + void A(int x = 1); >>> }; >>> #else >>> S12 s12; >>> @@ -585,11 +585,11 @@ S12 s12; >>> >>> #if defined(FIRST) >>> struct S13 { >>> - void A(int x = 1 + 0) {} >>> + void A(int x = 1 + 0); >>> }; >>> #elif defined(SECOND) >>> struct S13 { >>> - void A(int x = 1) {} >>> + void A(int x = 1); >>> }; >>> #else >>> S13 s13; >>> @@ -599,11 +599,11 @@ S13 s13; >>> >>> #if defined(FIRST) >>> struct S14 { >>> - void A(int x[2]) {} >>> + void A(int x[2]); >>> }; >>> #elif defined(SECOND) >>> struct S14 { >>> - void A(int x[3]) {} >>> + void A(int x[3]); >>> }; >>> #else >>> S14 s14; >>> @@ -2751,14 +2751,14 @@ namespace DefaultArguments { >>> template <typename T> >>> struct S { >>> struct R { >>> - void foo(T x = 0) {} >>> + void foo(T x = 0); >>> }; >>> }; >>> #elif defined(SECOND) >>> template <typename T> >>> struct S { >>> struct R { >>> - void foo(T x = 1) {} >>> + void foo(T x = 1); >>> }; >>> }; >>> #else >>> @@ -2771,13 +2771,13 @@ void run() { >>> >>> #if defined(FIRST) >>> template <typename alpha> struct Bravo { >>> - void charlie(bool delta = false) {} >>> + void charlie(bool delta = false); >>> }; >>> typedef Bravo<char> echo; >>> echo foxtrot; >>> #elif defined(SECOND) >>> template <typename alpha> struct Bravo { >>> - void charlie(bool delta = (false)) {} >>> + void charlie(bool delta = (false)); >>> }; >>> typedef Bravo<char> echo; >>> echo foxtrot; >>> @@ -2788,6 +2788,142 @@ Bravo<char> golf; >>> #endif >>> } // namespace DefaultArguments >>> >>> +namespace FunctionDecl { >>> +#if defined(FIRST) >>> +struct S1 {}; >>> +S1 s1a; >>> +#elif defined(SECOND) >>> +struct S1 {}; >>> +#else >>> +S1 s1; >>> +#endif >>> + >>> +#if defined(FIRST) >>> +struct S2 { >>> + S2() = default; >>> +}; >>> +S2 s2a = S2(); >>> +#elif defined(SECOND) >>> +struct S2 { >>> + S2() = default; >>> +}; >>> +#else >>> +S2 s2; >>> +#endif >>> + >>> +#if defined(FIRST) >>> +struct S3 { >>> + S3() = delete; >>> +}; >>> +S3* s3c; >>> +#elif defined(SECOND) >>> +struct S3 { >>> + S3() = delete; >>> +}; >>> +#else >>> +S3* s3; >>> +#endif >>> + >>> +#if defined(FIRST) || defined(SECOND) >>> +int F1(int x, float y = 2.7) { return 1; } >>> +#else >>> +int I1 = F1(1); >>> +#endif >>> + >>> +#if defined(FIRST) >>> +int F2() { return 1; } >>> +#elif defined(SECOND) >>> +double F2() { return 1; } >>> +#else >>> +int I2 = F2(); >>> +// expected-error@-1 {{call to 'F2' is ambiguous}} >>> +// expected-note@first.h:* {{candidate function}} >>> +// expected-note@second.h:* {{candidate function}} >>> +#endif >>> + >>> +#if defined(FIRST) >>> +int F3(float) { return 1; } >>> +#elif defined(SECOND) >>> +int F3(double) { return 1; } >>> +#else >>> +int I3 = F3(1); >>> +// expected-error@-1 {{call to 'F3' is ambiguous}} >>> +// expected-note@first.h:* {{candidate function}} >>> +// expected-note@second.h:* {{candidate function}} >>> +#endif >>> + >>> +#if defined(FIRST) >>> +int F4(int x) { return 1; } >>> +#elif defined(SECOND) >>> +int F4(int y) { return 1; } >>> +#else >>> +int I4 = F4(1); >>> +// expected-error@second.h:* {{'FunctionDecl::F4' has different >>> definitions in different modules; definition in module 'SecondModule' first >>> difference is 1st parameter with name 'y'}} >>> +// expected-note@first.h:* {{but in 'FirstModule' found 1st parameter >>> with name 'x'}} >>> +#endif >>> + >>> +#if defined(FIRST) >>> +int F5(int x) { return 1; } >>> +#elif defined(SECOND) >>> +int F5(int x = 1) { return 1; } >>> +#else >>> +int I5 = F6(1); >>> +// expected-error@second.h:* {{'FunctionDecl::F5' has different >>> definitions in different modules; definition in module 'SecondModule' first >>> difference is 1st parameter without a default argument}} >>> +// expected-note@first.h:* {{but in 'FirstModule' found 1st parameter >>> with a default argument}} >>> +#endif >>> + >>> +#if defined(FIRST) >>> +int F6(int x = 2) { return 1; } >>> +#elif defined(SECOND) >>> +int F6(int x = 1) { return 1; } >>> +#else >>> +int I6 = F6(1); >>> +// expected-error@second.h:* {{'FunctionDecl::F6' has different >>> definitions in different modules; definition in module 'SecondModule' first >>> difference is 1st parameter with a default argument}} >>> +// expected-note@first.h:* {{but in 'FirstModule' found 1st parameter >>> with a different default argument}} >>> +#endif >>> + >>> +using I = int; >>> +#if defined(FIRST) >>> +I F7() { return 0; } >>> +#elif defined(SECOND) >>> +int F7() { return 0; } >>> +#else >>> +int I7 = F7(); >>> +// expected-error@second.h:* {{'FunctionDecl::F7' has different >>> definitions in different modules; definition in module 'SecondModule' first >>> difference is return type is 'int'}} >>> +// expected-note@first.h:* {{but in 'FirstModule' found different >>> return type 'FunctionDecl::I' (aka 'int')}} >>> +#endif >>> + >>> +#if defined(FIRST) >>> +int F8(int) { return 0; } >>> +#elif defined(SECOND) >>> +int F8(I) { return 0; } >>> +#else >>> +int I8 = F8(1); >>> +// expected-error@second.h:* {{'FunctionDecl::F8' has different >>> definitions in different modules; definition in module 'SecondModule' first >>> difference is 1st parameter with type 'FunctionDecl::I' (aka 'int')}} >>> +// expected-note@first.h:* {{but in 'FirstModule' found 1st parameter >>> with type 'int'}} >>> +#endif >>> + >>> +#if defined(FIRST) >>> +int F9(int[1]) { return 0; } >>> +#elif defined(SECOND) >>> +int F9(int[2]) { return 0; } >>> +#else >>> +int I9 = F9(nullptr); >>> +// expected-error@second.h:* {{'FunctionDecl::F9' has different >>> definitions in different modules; definition in module 'SecondModule' first >>> difference is 1st parameter with type 'int *' decayed from 'int [2]'}} >>> +// expected-note@first.h:* {{but in 'FirstModule' found 1st parameter >>> with type 'int *' decayed from 'int [1]'}} >>> +#endif >>> + >>> +#if defined(FIRST) >>> +int F10() { return 1; } >>> +#elif defined(SECOND) >>> +int F10() { return 2; } >>> +#else >>> +int I10 = F10(); >>> +#endif >>> +// expected-error@second.h:* {{'FunctionDecl::F10' has different >>> definitions in different modules; definition in module 'SecondModule' first >>> difference is function body}} >>> +// expected-note@first.h:* {{but in 'FirstModule' found a different >>> body}} >>> +} // namespace FunctionDecl >>> + >>> // Keep macros contained to one file. >>> #ifdef FIRST >>> #undef FIRST >>> >>> >>> _______________________________________________ >>> cfe-commits mailing list >>> cfe-commits@lists.llvm.org >>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >>> >>> >>> >>> >> >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits@lists.llvm.org >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> >> >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits