r321395 - [ODRHash] Support ODR violation detection in functions.

Richard Trieu via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 11 20:46:11 PST 2018


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 <eric at 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 at lists.llvm.org> wrote:
>
>> Vedant,
>>
>> I'm looking into it.
>>
>>
>> On Wed, Jan 3, 2018 at 11:12 AM, Vedant Kumar <vsk at 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 <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-s
>>> tage2-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> 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 at -1 {{call to 'F2' is ambiguous}}
>>> +// expected-note at first.h:* {{candidate function}}
>>> +// 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:* {{candidate function}}
>>> +// 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:* {{'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:* {{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:* {{'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:* {{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:* {{'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:* {{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:* {{'FunctionDecl::F7' has different
>>> definitions in different modules; definition in module 'SecondModule' first
>>> difference is return type is 'int'}}
>>> +// 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:* {{'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:* {{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:* {{'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:* {{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:* {{'FunctionDecl::F10' has different
>>> definitions in different modules; definition in module 'SecondModule' first
>>> difference is function body}}
>>> +// 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
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>
>>>
>>>
>>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> 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/20180111/fd114e12/attachment-0001.html>


More information about the cfe-commits mailing list