r321395 - [ODRHash] Support ODR violation detection in functions.
Vedant Kumar via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 3 11:12:50 PST 2018
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-stage2-coverage-R/2193/consoleText <http://lab.llvm.org:8080/green/view/Experimental/job/clang-stage2-coverage-R/2193/consoleText>
vedant
> On Jan 3, 2018, at 11:09 AM, Vedant Kumar <vsk at 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-stage2-coverage-R/2193 <http://lab.llvm.org:8080/green/view/Experimental/job/clang-stage2-coverage-R/2193>
>
> <coverage-build-log.txt>
>
>
>
>> On Dec 22, 2017, at 4:41 PM, Richard Trieu via cfe-commits <cfe-commits at lists.llvm.org <mailto:cfe-commits at 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 <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 <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 <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&r2=321395&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td?rev=321395&r1=321394&r2=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 <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.cpp?rev=321395&r1=321394&r2=321395&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?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/ODRHash.cpp?rev=321395&r1=321394&r2=321395&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ODRHash.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/Serialization/ASTReader.cpp?rev=321395&r1=321394&r2=321395&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/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(PendingFunctionOdrMergeFailures);
>> + 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 = getOwningModuleNameForDiagnostic(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/Serialization/ASTReaderDecl.cpp?rev=321395&r1=321394&r2=321395&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/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/Serialization/ASTWriterDecl.cpp?rev=321395&r1=321394&r2=321395&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/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/odr_hash.cpp?rev=321395&r1=321394&r2=321395&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/odr_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 at -1 {{call to 'F2' is ambiguous}}
>> +// expected-note at first.h <mailto:expected-note at first.h>:* {{candidate function}}
>> +// expected-note at second.h <mailto:expected-note at 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 at -1 {{call to 'F3' is ambiguous}}
>> +// expected-note at first.h <mailto:expected-note at first.h>:* {{candidate function}}
>> +// expected-note at second.h <mailto:expected-note at 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 at second.h <mailto:expected-error at second.h>:* {{'FunctionDecl::F4' has different definitions in different modules; definition in module 'SecondModule' first difference is 1st parameter with name 'y'}}
>> +// expected-note at first.h <mailto:expected-note at 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 at second.h <mailto:expected-error at 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 at first.h <mailto:expected-note at 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 at second.h <mailto:expected-error at 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 at first.h <mailto:expected-note at 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 at second.h <mailto:expected-error at second.h>:* {{'FunctionDecl::F7' has different definitions in different modules; definition in module 'SecondModule' first difference is return type is 'int'}}
>> +// expected-note at first.h <mailto:expected-note at 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 at second.h <mailto:expected-error at 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 at first.h <mailto:expected-note at 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 at second.h <mailto:expected-error at 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 at first.h <mailto:expected-note at 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 at second.h <mailto:expected-error at second.h>:* {{'FunctionDecl::F10' has different definitions in different modules; definition in module 'SecondModule' first difference is function body}}
>> +// expected-note at first.h <mailto:expected-note at 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 at lists.llvm.org <mailto:cfe-commits at lists.llvm.org>
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180103/93ec58ed/attachment-0001.html>
More information about the cfe-commits
mailing list