From c0376bf8a43fa7b50defa143bf9b97c85508d40c Mon Sep 17 00:00:00 2001 From: Sam McCall Date: Tue, 31 Jan 2017 08:24:40 +0000 Subject: [PATCH] Revert r293585 "Add better ODR checking for modules." We're seeing what we believe are false positives. (It's hard to tell with the available diagnostics, and I'm not sure how to reduce them yet). I'll send Richard reproduction details offline. djasper/chandlerc suggested this should be a warning for now, to make rolling it out feasible. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@293611 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclCXX.h | 6 - include/clang/AST/ODRHash.h | 80 -- include/clang/AST/Stmt.h | 3 - .../Basic/DiagnosticSerializationKinds.td | 64 - lib/AST/CMakeLists.txt | 1 - lib/AST/DeclCXX.cpp | 15 +- lib/AST/ODRHash.cpp | 892 -------------- lib/AST/StmtProfile.cpp | 229 ++-- lib/Sema/SemaDecl.cpp | 5 +- lib/Serialization/ASTReader.cpp | 638 +--------- lib/Serialization/ASTReaderDecl.cpp | 2 - lib/Serialization/ASTWriter.cpp | 1 - test/Modules/merge-using-decls.cpp | 4 - test/Modules/odr_hash.cpp | 1077 ----------------- 14 files changed, 97 insertions(+), 2920 deletions(-) delete mode 100644 include/clang/AST/ODRHash.h delete mode 100644 lib/AST/ODRHash.cpp delete mode 100644 test/Modules/odr_hash.cpp diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 4e73613d34..0ca08db162 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -458,9 +458,6 @@ class CXXRecordDecl : public RecordDecl { /// \brief Whether we are currently parsing base specifiers. unsigned IsParsingBaseSpecifiers : 1; - /// \brief A hash of parts of the class to help in ODR checking. - unsigned ODRHash; - /// \brief The number of base class specifiers in Bases. unsigned NumBases; @@ -706,9 +703,6 @@ public: return data().IsParsingBaseSpecifiers; } - void computeODRHash(); - unsigned getODRHash() const { return data().ODRHash; } - /// \brief Sets the base classes of this struct or class. void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases); diff --git a/include/clang/AST/ODRHash.h b/include/clang/AST/ODRHash.h deleted file mode 100644 index 0bf4d83807..0000000000 --- a/include/clang/AST/ODRHash.h +++ /dev/null @@ -1,80 +0,0 @@ -//===-- ODRHash.h - Hashing to diagnose ODR failures ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file contains the declaration of the ODRHash class, which calculates -/// a hash based on AST nodes, which is stable across different runs. -/// -//===----------------------------------------------------------------------===// - -#include "clang/AST/DeclarationName.h" -#include "clang/AST/Type.h" -#include "clang/AST/TemplateBase.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/SmallVector.h" - -namespace clang { - -class Decl; -class IdentifierInfo; -class NestedNameSpecifer; -class Stmt; -class TemplateParameterList; - -// ODRHash is used to calculate a hash based on AST node contents that -// does not rely on pointer addresses. This allows the hash to not vary -// between runs and is usable to detect ODR problems in modules. To use, -// construct an ODRHash object, then call Add* methods over the nodes that -// need to be hashed. Then call CalculateHash to get the hash value. -// Typically, only one Add* call is needed. clear can be called to reuse the -// object. -class ODRHash { - // Use DenseMaps to convert between Decl and Type pointers and an index value. - llvm::DenseMap DeclMap; - llvm::DenseMap TypeMap; - - // Save space by processing bools at the end. - llvm::SmallVector Bools; - - llvm::FoldingSetNodeID ID; - -public: - ODRHash() {} - - // Use this for ODR checking classes between modules. This method compares - // more information than the AddDecl class. - void AddCXXRecordDecl(const CXXRecordDecl *Record); - - // Add AST nodes that need to be processes. Some nodes are processed - // immediately while others are queued and processed later. - void AddDecl(const Decl *D); - void AddType(const Type *T); - void AddQualType(QualType T); - void AddStmt(const Stmt *S); - void AddIdentifierInfo(const IdentifierInfo *II); - void AddNestedNameSpecifier(const NestedNameSpecifier *NNS); - void AddTemplateName(TemplateName Name); - void AddDeclarationName(DeclarationName Name); - void AddTemplateArgument(TemplateArgument TA); - void AddTemplateParameterList(const TemplateParameterList *TPL); - - // Reset the object for reuse. - void clear(); - - // Processes any unvisited nodes in Pointers and computes the final hash - // value. - unsigned CalculateHash(); - - // Save booleans until the end to lower the size of data to process. - void AddBoolean(bool value); -}; - -} // end namespace clang diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index defe6c2ac2..e28675d6a8 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -39,7 +39,6 @@ namespace clang { class Expr; class IdentifierInfo; class LabelDecl; - class ODRHash; class ParmVarDecl; class PrinterHelper; struct PrintingPolicy; @@ -437,8 +436,6 @@ public: /// written in the source. void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, bool Canonical) const; - - void ProcessODRHash(llvm::FoldingSetNodeID &ID, ODRHash& Hash) const; }; /// DeclStmt - Adaptor class for mixing declarations with statements and diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td index 9371b05c73..066a1f5fa6 100644 --- a/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/include/clang/Basic/DiagnosticSerializationKinds.td @@ -117,70 +117,6 @@ def note_module_odr_violation_different_definitions : Note< def err_module_odr_violation_different_instantiations : Error< "instantiation of %q0 is different in different modules">; -def err_module_odr_violation_mismatch_decl : Error< - "%q0 has different definitions in different modules; first difference is " - "%select{definition in module '%2'|defined here}1 found " - "%select{end of class|public access specifier|private access specifier|" - "protected access specifier|friend declaration|enum|" - "static assert|typedef|type alias|method|constructor|destructor|" - "conversion operator|field|other}3">; -def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found " - "%select{end of class|public access specifier|private access specifier|" - "protected access specifier|friend declaration|enum|" - "static assert|typedef|type alias|method|constructor|destructor|" - "conversion operator|field|other}1">; - -def err_module_odr_violation_mismatch_decl_diff : Error< - "%q0 has different definitions in different modules; first difference is " - "%select{definition in module '%2'|defined here}1 found " - "%select{friend %4|enum %4|element %4 in enum %5|" - "element %4 in enum %5 with initializer|" - "element %4 in enum %5 with no initializer|" - "element %4 in enum %5 with initializer|" - "enum %4 has %5 element%s5|" - "static assert with condition|" - "static assert with message|" - "static assert with %select{|no}4 message|" - "%select{typedef|type alias}4 name %5|" - "method named %4|" - "method %4 is %select{non-|}5static|" - "method %4 is %select{not |}5inline|" - "method %4 is %select{not |}5const|" - "method %4 has %5 parameter%s5|" - "method %4 has %ordinal5 parameter %select{named %7|with no name}6|" - "method %4 has %ordinal5 parameter with type %6|" - "method %4 has %ordinal5 parameter with default argument|" - "method %4 has %ordinal5 parameter with %select{no |}6 default argument|" - "method %4 has %select{|no }5body|" - "method %4 has different body|" - "field %4|" - "%select{field|bitfield}5 %4|" - "%select{non-mutable|mutable}5 %4}3">; -def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " - "%select{other friend %2|other enum %2|different element %2 in enum %3|" - "element %2 in enum %3 with initializer|" - "element %2 in enum %3 with no initializer|" - "element %2 in enum %3 with different initializer|" - "enum %2 has %3 element%s3|" - "static assert with different condition|" - "static assert with different message|" - "static assert with %select{|no}2 message|" - "different %select{typedef|type alias}2 name %3|" - "method named %2|" - "method %2 is %select{non-|}3static|" - "method %2 is %select{not |}3inline|" - "method %2 is %select{not |}3const|" - "method %2 has %3 parameter%s3|" - "method %2 has %ordinal3 parameter %select{named %5|with no name}4|" - "method %2 has %ordinal3 parameter with type %4|" - "method %2 has %ordinal3 parameter with different default argument|" - "method %2 has %ordinal3 parameter with %select{no |}4default argument|" - "method %2 has %select{|no }3body|" - "method %2 has different body|" - "field %2|" - "%select{field|bitfield}3 %2|" - "%select{non-mutable|mutable}3 %2}1">; - def warn_module_uses_date_time : Warning< "%select{precompiled header|module}0 uses __DATE__ or __TIME__">, InGroup>; diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 2e98f524da..e28bd2e16d 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -40,7 +40,6 @@ add_clang_library(clangAST MicrosoftMangle.cpp NestedNameSpecifier.cpp NSAPI.cpp - ODRHash.cpp OpenMPClause.cpp ParentMap.cpp RawCommentList.cpp diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 8fca00404c..a9db65a515 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -18,7 +18,6 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" -#include "clang/AST/ODRHash.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/STLExtras.h" @@ -72,8 +71,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) ImplicitCopyAssignmentHasConstParam(true), HasDeclaredCopyConstructorWithConstParam(false), HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false), - IsParsingBaseSpecifiers(false), ODRHash(0), NumBases(0), NumVBases(0), - Bases(), VBases(), Definition(D), FirstFriend() {} + IsParsingBaseSpecifiers(false), NumBases(0), NumVBases(0), Bases(), + VBases(), Definition(D), FirstFriend() {} CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const { return Bases.get(Definition->getASTContext().getExternalSource()); @@ -372,16 +371,6 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().IsParsingBaseSpecifiers = false; } -void CXXRecordDecl::computeODRHash() { - if (!DefinitionData) - return; - - ODRHash Hash; - Hash.AddCXXRecordDecl(this); - - DefinitionData->ODRHash = Hash.CalculateHash(); -} - void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) { // C++11 [class.copy]p11: // A defaulted copy/move constructor for a class X is defined as diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp deleted file mode 100644 index 207ac08386..0000000000 --- a/lib/AST/ODRHash.cpp +++ /dev/null @@ -1,892 +0,0 @@ -//===-- ODRHash.cpp - Hashing to diagnose ODR failures ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file implements the ODRHash class, which calculates a hash based -/// on AST nodes, which is stable across different runs. -/// -//===----------------------------------------------------------------------===// - -#include "clang/AST/ODRHash.h" - -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/NestedNameSpecifier.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/TypeVisitor.h" - -using namespace clang; - -// This method adds more information that AddDecl does. -void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) { - assert(Record && Record->hasDefinition() && - "Expected non-null record to be a definition."); - AddDecl(Record); - - // Additional information that is not needed in AddDecl. Do not move this - // to ODRTypeVisitor. - ID.AddInteger(Record->getNumBases()); - for (auto base : Record->bases()) { - AddBoolean(base.isVirtual()); - AddQualType(base.getType()); - } - - const ClassTemplateDecl *TD = Record->getDescribedClassTemplate(); - AddBoolean(TD); - if (TD) { - AddTemplateParameterList(TD->getTemplateParameters()); - } -} - -// Hashing for Stmt is with Stmt::Profile, since they derive from the same base -// class. -void ODRHash::AddStmt(const Stmt *S) { - assert(S && "Expecting non-null pointer."); - S->ProcessODRHash(ID, *this); -} - -void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) { - assert(II && "Expecting non-null pointer."); - ID.AddString(II->getName()); -} - -void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { - assert(NNS && "Expecting non-null pointer."); - const auto *Prefix = NNS->getPrefix(); - AddBoolean(Prefix); - if (Prefix) { - AddNestedNameSpecifier(Prefix); - } - - auto Kind = NNS->getKind(); - ID.AddInteger(Kind); - switch (Kind) { - case NestedNameSpecifier::Identifier: - AddIdentifierInfo(NNS->getAsIdentifier()); - break; - case NestedNameSpecifier::Namespace: - AddDecl(NNS->getAsNamespace()); - break; - case NestedNameSpecifier::NamespaceAlias: - AddDecl(NNS->getAsNamespaceAlias()); - break; - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: - AddType(NNS->getAsType()); - break; - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - break; - } -} - -void ODRHash::AddTemplateName(TemplateName Name) { - const auto Kind = Name.getKind(); - ID.AddInteger(Kind); - AddBoolean(Name.isDependent()); - AddBoolean(Name.isInstantiationDependent()); - switch (Kind) { - case TemplateName::Template: - AddDecl(Name.getAsTemplateDecl()); - break; - case TemplateName::OverloadedTemplate: { - const auto *Storage = Name.getAsOverloadedTemplate(); - ID.AddInteger(Storage->size()); - for (const auto *ND : *Storage) { - AddDecl(ND); - } - break; - } - case TemplateName::QualifiedTemplate: { - const auto *QTN = Name.getAsQualifiedTemplateName(); - AddNestedNameSpecifier(QTN->getQualifier()); - AddBoolean(QTN->hasTemplateKeyword()); - AddDecl(QTN->getDecl()); - break; - } - case TemplateName::DependentTemplate: { - const auto *DTN = Name.getAsDependentTemplateName(); - AddBoolean(DTN->isIdentifier()); - if (DTN->isIdentifier()) { - AddIdentifierInfo(DTN->getIdentifier()); - } else { - ID.AddInteger(DTN->getOperator()); - } - break; - } - case TemplateName::SubstTemplateTemplateParm: { - const auto *Storage = Name.getAsSubstTemplateTemplateParm(); - AddDecl(Storage->getParameter()); - AddTemplateName(Storage->getReplacement()); - break; - } - case TemplateName::SubstTemplateTemplateParmPack: { - const auto *Storage = Name.getAsSubstTemplateTemplateParmPack(); - AddDecl(Storage->getParameterPack()); - AddTemplateArgument(Storage->getArgumentPack()); - break; - } - } -} - -void ODRHash::AddDeclarationName(DeclarationName Name) { - AddBoolean(Name.isEmpty()); - if (Name.isEmpty()) { - return; - } - - auto Kind = Name.getNameKind(); - ID.AddInteger(Kind); - switch (Kind) { - case DeclarationName::Identifier: - AddIdentifierInfo(Name.getAsIdentifierInfo()); - break; - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: { - Selector S = Name.getObjCSelector(); - AddBoolean(S.isNull()); - AddBoolean(S.isKeywordSelector()); - AddBoolean(S.isUnarySelector()); - unsigned NumArgs = S.getNumArgs(); - for (unsigned i = 0; i < NumArgs; ++i) { - AddIdentifierInfo(S.getIdentifierInfoForSlot(i)); - } - break; - } - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - AddQualType(Name.getCXXNameType()); - break; - case DeclarationName::CXXOperatorName: - ID.AddInteger(Name.getCXXOverloadedOperator()); - break; - case DeclarationName::CXXLiteralOperatorName: - AddIdentifierInfo(Name.getCXXLiteralIdentifier()); - break; - case DeclarationName::CXXConversionFunctionName: - AddQualType(Name.getCXXNameType()); - break; - case DeclarationName::CXXUsingDirective: - break; - } -} - -void ODRHash::AddTemplateArgument(TemplateArgument TA) { - const auto Kind = TA.getKind(); - ID.AddInteger(Kind); - switch (Kind) { - case TemplateArgument::Null: - llvm_unreachable("Require valid TemplateArgument"); - case TemplateArgument::Type: - AddQualType(TA.getAsType()); - break; - case TemplateArgument::Declaration: - AddDecl(TA.getAsDecl()); - break; - case TemplateArgument::NullPtr: - AddQualType(TA.getNullPtrType()); - break; - case TemplateArgument::Integral: - TA.getAsIntegral().Profile(ID); - AddQualType(TA.getIntegralType()); - break; - case TemplateArgument::Template: - case TemplateArgument::TemplateExpansion: - AddTemplateName(TA.getAsTemplateOrTemplatePattern()); - break; - case TemplateArgument::Expression: - AddStmt(TA.getAsExpr()); - break; - case TemplateArgument::Pack: - ID.AddInteger(TA.pack_size()); - for (auto SubTA : TA.pack_elements()) { - AddTemplateArgument(SubTA); - } - break; - } -} - -void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) { - assert(TPL && "Expecting non-null pointer."); - ID.AddInteger(TPL->size()); - for (auto *ND : TPL->asArray()) { - AddDecl(ND); - } -} - -void ODRHash::clear() { - DeclMap.clear(); - TypeMap.clear(); - Bools.clear(); - ID.clear(); -} - -unsigned ODRHash::CalculateHash() { - // Append the bools to the end of the data segment backwards. This allows - // for the bools data to be compressed 32 times smaller compared to using - // ID.AddBoolean - const unsigned unsigned_bits = sizeof(unsigned) * CHAR_BIT; - const unsigned size = Bools.size(); - const unsigned remainder = size % unsigned_bits; - const unsigned loops = size / unsigned_bits; - auto I = Bools.rbegin(); - unsigned value = 0; - for (unsigned i = 0; i < remainder; ++i) { - value <<= 1; - value |= *I; - ++I; - } - ID.AddInteger(value); - - for (unsigned i = 0; i < loops; ++i) { - value = 0; - for (unsigned j = 0; j < unsigned_bits; ++j) { - value <<= 1; - value |= *I; - ++I; - } - ID.AddInteger(value); - } - - assert(I == Bools.rend()); - return ID.ComputeHash(); -} - -// Process a Decl pointer. Add* methods call back into ODRHash while Visit* -// methods process the relevant parts of the Decl. -class ODRDeclVisitor : public ConstDeclVisitor { - typedef ConstDeclVisitor Inherited; - llvm::FoldingSetNodeID &ID; - ODRHash &Hash; - -public: - ODRDeclVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash) - : ID(ID), Hash(Hash) {} - - void AddDecl(const Decl *D) { - Hash.AddBoolean(D); - if (D) { - Hash.AddDecl(D); - } - } - - void AddStmt(const Stmt *S) { - Hash.AddBoolean(S); - if (S) { - Hash.AddStmt(S); - } - } - - void AddQualType(QualType T) { - Hash.AddQualType(T); - } - - void AddIdentifierInfo(const IdentifierInfo *II) { - Hash.AddBoolean(II); - if (II) { - Hash.AddIdentifierInfo(II); - } - } - - void AddTemplateParameterList(TemplateParameterList *TPL) { - Hash.AddBoolean(TPL); - if (TPL) { - Hash.AddTemplateParameterList(TPL); - } - } - - void AddTemplateArgument(TemplateArgument TA) { - Hash.AddTemplateArgument(TA); - } - - void VisitDecl(const Decl *D) { - if (!D) { - return; - } - if (D->isImplicit()) { - return; - } - if (D->isInvalidDecl()) { - return; - } - ID.AddInteger(D->getKind()); - Hash.AddBoolean(D->hasAttrs()); - - if (auto *DC = dyn_cast(D)) { - llvm::SmallVector Decls; - for (const Decl* D : DC->decls()) { - if (!D->isImplicit()) { - Decls.push_back(D); - } - } - ID.AddInteger(Decls.size()); - for (auto SubDecl : Decls) { - AddDecl(SubDecl); - } - } - - Inherited::VisitDecl(D); - } - - void VisitLabelDecl(const LabelDecl *D) { - Inherited::VisitLabelDecl(D); - } - - void VisitEnumDecl(const EnumDecl *D) { - const bool isFixed = D->isFixed(); - Hash.AddBoolean(isFixed); - if (isFixed) { - AddQualType(D->getIntegerType()); - } - Hash.AddBoolean(D->isScoped()); - Hash.AddBoolean(D->isScopedUsingClassTag()); - - Inherited::VisitEnumDecl(D); - } - - void VisitEnumConstantDecl(const EnumConstantDecl *D) { - auto *E = D->getInitExpr(); - AddStmt(E); - - Inherited::VisitEnumConstantDecl(D); - } - - void VisitNamedDecl(const NamedDecl *D) { - AddIdentifierInfo(D->getIdentifier()); - Inherited::VisitNamedDecl(D); - } - - void VisitValueDecl(const ValueDecl *D) { - AddQualType(D->getType()); - Inherited::VisitValueDecl(D); - } - - void VisitParmVarDecl(const ParmVarDecl *D) { - AddStmt(D->getDefaultArg()); - Inherited::VisitParmVarDecl(D); - } - - void VisitAccessSpecDecl(const AccessSpecDecl *D) { - ID.AddInteger(D->getAccess()); - Inherited::VisitAccessSpecDecl(D); - } - - void VisitFriendDecl(const FriendDecl *D) { - TypeSourceInfo *TSI = D->getFriendType(); - Hash.AddBoolean(TSI); - if (TSI) { - AddQualType(TSI->getType()); - } else { - AddDecl(D->getFriendDecl()); - } - - unsigned NumLists = D->getFriendTypeNumTemplateParameterLists(); - ID.AddInteger(NumLists); - for (unsigned i = 0; i < NumLists; ++i) { - AddTemplateParameterList(D->getFriendTypeTemplateParameterList(i)); - } - - Inherited::VisitFriendDecl(D); - } - - void VisitStaticAssertDecl(const StaticAssertDecl *D) { - AddStmt(D->getAssertExpr()); - AddStmt(D->getMessage()); - - Inherited::VisitStaticAssertDecl(D); - } - - void VisitTypedefNameDecl(const TypedefNameDecl *D) { - AddQualType(D->getUnderlyingType()); - - Inherited::VisitTypedefNameDecl(D); - } - - void VisitFunctionDecl(const FunctionDecl *D) { - AddStmt(D->getBody()); - - ID.AddInteger(D->getStorageClass()); - Hash.AddBoolean(D->isInlineSpecified()); - Hash.AddBoolean(D->isVirtualAsWritten()); - Hash.AddBoolean(D->isPure()); - Hash.AddBoolean(D->isDeletedAsWritten()); - ID.AddInteger(D->getOverloadedOperator()); - Inherited::VisitFunctionDecl(D); - } - - void VisitCXXMethodDecl(const CXXMethodDecl *D) { - Hash.AddBoolean(D->isStatic()); - Hash.AddBoolean(D->isInstance()); - Hash.AddBoolean(D->isConst()); - Hash.AddBoolean(D->isVolatile()); - Inherited::VisitCXXMethodDecl(D); - } - - void VisitCXXConstructorDecl(const CXXConstructorDecl *D) { - Hash.AddBoolean(D->isExplicitSpecified()); - unsigned NumCtorInits = 0; - llvm::SmallVector Initializers; - ID.AddInteger(D->getNumCtorInitializers()); - for (auto Initializer : D->inits()) { - if (Initializer->isWritten()) { - ++NumCtorInits; - Initializers.push_back(Initializer); - } - } - for (auto Initializer : Initializers) { - AddStmt(Initializer->getInit()); - } - - Inherited::VisitCXXConstructorDecl(D); - } - - void VisitCXXConversionDecl(const CXXConversionDecl *D) { - AddQualType(D->getConversionType()); - Hash.AddBoolean(D->isExplicitSpecified()); - Inherited::VisitCXXConversionDecl(D); - } - - void VisitFieldDecl(const FieldDecl *D) { - Hash.AddBoolean(D->isMutable()); - - const bool isBitField = D->isBitField(); - Hash.AddBoolean(isBitField); - if (isBitField) { - AddStmt(D->getBitWidth()); - } - - AddStmt(D->getInClassInitializer()); - - Inherited::VisitFieldDecl(D); - } - - void VisitTemplateDecl(const TemplateDecl *D) { - AddDecl(D->getTemplatedDecl()); - - auto *Parameters = D->getTemplateParameters(); - ID.AddInteger(Parameters->size()); - for (auto *ND : *Parameters) { - AddDecl(ND); - } - - Inherited::VisitTemplateDecl(D); - } - - void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { - Inherited::VisitFunctionTemplateDecl(D); - } - - void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { - const bool hasDefaultArgument = D->hasDefaultArgument(); - Hash.AddBoolean(hasDefaultArgument); - if (hasDefaultArgument) { - AddTemplateArgument(D->getDefaultArgument()); - } - - Inherited::VisitTemplateTypeParmDecl(D); - } - - void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { - AddStmt(D->hasDefaultArgument() ? D->getDefaultArgument() : nullptr); - - Inherited::VisitNonTypeTemplateParmDecl(D); - } - - void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) { - const bool hasDefaultArgument = D->hasDefaultArgument(); - Hash.AddBoolean(hasDefaultArgument); - if (hasDefaultArgument) { - AddTemplateArgument(D->getDefaultArgument().getArgument()); - } - - Inherited::VisitTemplateTemplateParmDecl(D); - } -}; - -void ODRHash::AddDecl(const Decl *D) { - assert(D && "Expecting non-null pointer."); - auto Result = DeclMap.insert(std::make_pair(D, DeclMap.size())); - ID.AddInteger(Result.first->second); - // On first encounter of a Decl pointer, process it. Every time afterwards, - // only the index value is needed. - if (Result.second) { - ODRDeclVisitor(ID, *this).Visit(D); - } -} - -// Process a Type pointer. Add* methods call back into ODRHash while Visit* -// methods process the relevant parts of the Type. -class ODRTypeVisitor : public TypeVisitor { - typedef TypeVisitor Inherited; - llvm::FoldingSetNodeID &ID; - ODRHash &Hash; - -public: - ODRTypeVisitor(llvm::FoldingSetNodeID &ID, ODRHash &Hash) - : ID(ID), Hash(Hash) {} - - void AddQualType(QualType T) { - Hash.AddQualType(T); - } - - void AddDecl(Decl *D) { - Hash.AddBoolean(D); - if (D) { - Hash.AddDecl(D); - } - } - - void AddTemplateArgument(TemplateArgument TA) { - Hash.AddTemplateArgument(TA); - } - - void AddStmt(Stmt *S) { - Hash.AddBoolean(S); - if (S) { - Hash.AddStmt(S); - } - } - - void AddNestedNameSpecifier(NestedNameSpecifier *NNS) { - Hash.AddBoolean(NNS); - if (NNS) { - Hash.AddNestedNameSpecifier(NNS); - } - } - void AddIdentiferInfo(const IdentifierInfo *II) { - Hash.AddBoolean(II); - if (II) { - Hash.AddIdentifierInfo(II); - } - } - - void AddTemplateName(TemplateName TN) { - Hash.AddTemplateName(TN); - } - - void VisitQualifiers(Qualifiers Quals) { - ID.AddInteger(Quals.getAsOpaqueValue()); - } - - void VisitType(const Type *T) { ID.AddInteger(T->getTypeClass()); } - - void VisitAdjustedType(const AdjustedType *T) { - AddQualType(T->getOriginalType()); - AddQualType(T->getAdjustedType()); - VisitType(T); - } - - void VisitDecayedType(const DecayedType *T) { - AddQualType(T->getDecayedType()); - AddQualType(T->getPointeeType()); - VisitAdjustedType(T); - } - - void VisitArrayType(const ArrayType *T) { - AddQualType(T->getElementType()); - ID.AddInteger(T->getSizeModifier()); - VisitQualifiers(T->getIndexTypeQualifiers()); - VisitType(T); - } - void VisitConstantArrayType(const ConstantArrayType *T) { - T->getSize().Profile(ID); - VisitArrayType(T); - } - - void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { - AddStmt(T->getSizeExpr()); - VisitArrayType(T); - } - - void VisitIncompleteArrayType(const IncompleteArrayType *T) { - VisitArrayType(T); - } - - void VisitVariableArrayType(const VariableArrayType *T) { - AddStmt(T->getSizeExpr()); - VisitArrayType(T); - } - - void VisitAtomicType(const AtomicType *T) { - AddQualType(T->getValueType()); - VisitType(T); - } - - void VisitAttributedType(const AttributedType *T) { - ID.AddInteger(T->getAttrKind()); - AddQualType(T->getModifiedType()); - AddQualType(T->getEquivalentType()); - VisitType(T); - } - - void VisitBlockPointerType(const BlockPointerType *T) { - AddQualType(T->getPointeeType()); - VisitType(T); - } - - void VisitBuiltinType(const BuiltinType *T) { - ID.AddInteger(T->getKind()); - VisitType(T); - } - - void VisitComplexType(const ComplexType *T) { - AddQualType(T->getElementType()); - VisitType(T); - } - - void VisitDecltypeType(const DecltypeType *T) { - AddQualType(T->getUnderlyingType()); - AddStmt(T->getUnderlyingExpr()); - VisitType(T); - } - - void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *T) { - AddQualType(T->getElementType()); - AddStmt(T->getSizeExpr()); - VisitType(T); - } - - void VisitFunctionType(const FunctionType *T) { - AddQualType(T->getReturnType()); - T->getExtInfo().Profile(ID); - Hash.AddBoolean(T->isConst()); - Hash.AddBoolean(T->isVolatile()); - Hash.AddBoolean(T->isRestrict()); - VisitType(T); - } - - void VisitFunctionNoProtoType(const FunctionNoProtoType *T) { - VisitFunctionType(T); - } - - void VisitFunctionProtoType(const FunctionProtoType *T) { - ID.AddInteger(T->getNumParams()); - for (auto ParamType : T->getParamTypes()) { - AddQualType(ParamType); - } - - const auto &epi = T->getExtProtoInfo(); - ID.AddInteger(epi.Variadic); - ID.AddInteger(epi.TypeQuals); - ID.AddInteger(epi.RefQualifier); - ID.AddInteger(epi.ExceptionSpec.Type); - - if (epi.ExceptionSpec.Type == EST_Dynamic) { - for (QualType Ex : epi.ExceptionSpec.Exceptions) { - AddQualType(Ex); - } - } else if (epi.ExceptionSpec.Type == EST_ComputedNoexcept && - epi.ExceptionSpec.NoexceptExpr) { - AddStmt(epi.ExceptionSpec.NoexceptExpr); - } else if (epi.ExceptionSpec.Type == EST_Uninstantiated || - epi.ExceptionSpec.Type == EST_Unevaluated) { - AddDecl(epi.ExceptionSpec.SourceDecl->getCanonicalDecl()); - } - if (epi.ExtParameterInfos) { - for (unsigned i = 0; i != T->getNumParams(); ++i) { - ID.AddInteger(epi.ExtParameterInfos[i].getOpaqueValue()); - } - } - epi.ExtInfo.Profile(ID); - Hash.AddBoolean(epi.HasTrailingReturn); - - VisitFunctionType(T); - } - - void VisitInjectedClassNameType(const InjectedClassNameType *T) { - AddQualType(T->getInjectedSpecializationType()); - AddDecl(T->getDecl()); - VisitType(T); - } - - void VisitMemberPointerType(const MemberPointerType *T) { - AddQualType(T->getPointeeType()); - Visit(T->getClass()); - VisitType(T); - } - - void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { - AddQualType(T->getPointeeType()); - VisitType(T); - } - - void VisitObjCObjectType(const ObjCObjectType *T) { - QualType Base = T->getBaseType(); - const bool SameType = Base.getTypePtr() == T; - Hash.AddBoolean(SameType); - if (!SameType) { - AddQualType(Base); - } - auto TypeArgs = T->getTypeArgsAsWritten(); - ID.AddInteger(TypeArgs.size()); - for (auto TypeArg : TypeArgs) { - AddQualType(TypeArg); - } - ID.AddInteger(T->getNumProtocols()); - for (auto proto : T->quals()) { - AddDecl(proto); - } - ID.AddInteger(T->isKindOfTypeAsWritten()); - VisitType(T); - } - - void VisitObjCInterfaceType(const ObjCInterfaceType *T) { - VisitObjCObjectType(T); - } - - void VisitObjCObjectTypeImpl(const ObjCObjectTypeImpl *T) { - VisitObjCObjectType(T); - } - - void VisitPackExpansionType(const PackExpansionType *T) { - AddQualType(T->getPattern()); - auto NumExpansions = T->getNumExpansions(); - Hash.AddBoolean(NumExpansions.hasValue()); - if (NumExpansions) { - ID.AddInteger(*NumExpansions); - } - VisitType(T); - }; - - void VisitPointerType(const PointerType *T) { - AddQualType(T->getPointeeType()); - VisitType(T); - } - - void VisitReferenceType(const ReferenceType *T) { - AddQualType(T->getPointeeTypeAsWritten()); - VisitType(T); - } - - void VisitLValueReferenceType(const LValueReferenceType *T) { - VisitReferenceType(T); - } - - void VisitRValueReferenceType(const RValueReferenceType *T) { - VisitReferenceType(T); - } - - void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { - AddQualType(T->getReplacementType()); - AddQualType(QualType(T->getReplacedParameter(), 0)); - VisitType(T); - } - - void - VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) { - AddQualType(QualType(T->getReplacedParameter(), 0)); - AddTemplateArgument(T->getArgumentPack()); - VisitType(T); - } - - void VisitTagType(const TagType *T) { - AddDecl(T->getDecl()); - Hash.AddBoolean(T->isBeingDefined()); - VisitType(T); - } - - void VisitEnumType(const EnumType *T) { - AddDecl(T->getDecl()); - VisitTagType(T); - } - - void VisitRecordType(const RecordType *T) { - AddDecl(T->getDecl()); - VisitTagType(T); - } - - void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - AddTemplateName(T->getTemplateName()); - ID.AddInteger(T->getNumArgs()); - for (auto I = T->begin(), E = T->end(); I != E; ++I) { - AddTemplateArgument(*I); - } - VisitType(T); - } - - void VisitTemplateTypeParmType(const TemplateTypeParmType *T) { - ID.AddInteger(T->getDepth()); - ID.AddInteger(T->getIndex()); - Hash.AddBoolean(T->isParameterPack()); - AddDecl(T->getDecl()); - VisitType(T); - } - - void VisitTypedefType(const TypedefType *T) { - AddDecl(T->getDecl()); - VisitType(T); - } - - void VisitTypeOfExprType(const TypeOfExprType *T) { - AddStmt(T->getUnderlyingExpr()); - VisitType(T); - } - - void VisitDependentTypeOfExprType(const DependentTypeOfExprType *T) { - VisitTypeOfExprType(T); - } - - void VisitTypeWithKeyword(const TypeWithKeyword *T) { VisitType(T); } - - void VisitElaboratedType(const ElaboratedType *T) { - ID.AddInteger(T->getKeyword()); - AddNestedNameSpecifier(T->getQualifier()); - AddQualType(T->getNamedType()); - VisitTypeWithKeyword(T); - } - - void VisitUnaryTransformType(const UnaryTransformType *T) { - AddQualType(T->getBaseType()); - ID.AddInteger(T->getUTTKind()); - VisitType(T); - } - - void VisitDependentUnaryTransformType(const DependentUnaryTransformType *T) { - VisitUnaryTransformType(T); - } - - void VisitUnresolvedUsingType(const UnresolvedUsingType *T) { - AddDecl(T->getDecl()); - VisitType(T); - } - - void VisitVectorType(const VectorType *T) { - AddQualType(T->getElementType()); - ID.AddInteger(T->getNumElements()); - ID.AddInteger(T->getVectorKind()); - VisitType(T); - } - - void VisitExtVectorType(const ExtVectorType *T) { VisitVectorType(T); } -}; - -void ODRHash::AddType(const Type *T) { - assert(T && "Expecting non-null pointer."); - auto Result = TypeMap.insert(std::make_pair(T, TypeMap.size())); - ID.AddInteger(Result.first->second); - // On first encounter of a Type pointer, process it. Every time afterwards, - // only the index value is needed. - if (Result.second) { - ODRTypeVisitor(ID, *this).Visit(T); - } -} - -void ODRHash::AddQualType(QualType T) { - AddBoolean(T.isNull()); - if (T.isNull()) { - return; - } - SplitQualType split = T.split(); - ID.AddInteger(split.Quals.getAsOpaqueValue()); - AddType(split.Ty); -} - -void ODRHash::AddBoolean(bool Value) { - Bools.push_back(Value); -} diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index e228bc9a1b..49e43de638 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -19,22 +19,20 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" -#include "clang/AST/ODRHash.h" #include "clang/AST/StmtVisitor.h" #include "llvm/ADT/FoldingSet.h" using namespace clang; namespace { class StmtProfiler : public ConstStmtVisitor { - protected: llvm::FoldingSetNodeID &ID; + const ASTContext &Context; bool Canonical; public: - StmtProfiler(llvm::FoldingSetNodeID &ID, bool Canonical) - : ID(ID), Canonical(Canonical) {} - - virtual ~StmtProfiler() {} + StmtProfiler(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + bool Canonical) + : ID(ID), Context(Context), Canonical(Canonical) { } void VisitStmt(const Stmt *S); @@ -43,25 +41,22 @@ namespace { /// \brief Visit a declaration that is referenced within an expression /// or statement. - virtual void VisitDecl(const Decl *D) = 0; + void VisitDecl(const Decl *D); /// \brief Visit a type that is referenced within an expression or /// statement. - virtual void VisitType(QualType T) = 0; + void VisitType(QualType T); /// \brief Visit a name that occurs within an expression or statement. - virtual void VisitName(DeclarationName Name) = 0; - - /// \brief Visit identifiers that are not in Decl's or Type's. - virtual void VisitIdentifierInfo(IdentifierInfo *II) = 0; + void VisitName(DeclarationName Name); /// \brief Visit a nested-name-specifier that occurs within an expression /// or statement. - virtual void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) = 0; + void VisitNestedNameSpecifier(NestedNameSpecifier *NNS); /// \brief Visit a template name that occurs within an expression or /// statement. - virtual void VisitTemplateName(TemplateName Name) = 0; + void VisitTemplateName(TemplateName Name); /// \brief Visit template arguments that occur within an expression or /// statement. @@ -71,127 +66,6 @@ namespace { /// \brief Visit a single template argument. void VisitTemplateArgument(const TemplateArgument &Arg); }; - - class StmtProfilerWithPointers : public StmtProfiler { - const ASTContext &Context; - - public: - StmtProfilerWithPointers(llvm::FoldingSetNodeID &ID, - const ASTContext &Context, bool Canonical) - : StmtProfiler(ID, Canonical), Context(Context) {} - private: - void VisitDecl(const Decl *D) override { - ID.AddInteger(D ? D->getKind() : 0); - - if (Canonical && D) { - if (const NonTypeTemplateParmDecl *NTTP = - dyn_cast(D)) { - ID.AddInteger(NTTP->getDepth()); - ID.AddInteger(NTTP->getIndex()); - ID.AddBoolean(NTTP->isParameterPack()); - VisitType(NTTP->getType()); - return; - } - - if (const ParmVarDecl *Parm = dyn_cast(D)) { - // The Itanium C++ ABI uses the type, scope depth, and scope - // index of a parameter when mangling expressions that involve - // function parameters, so we will use the parameter's type for - // establishing function parameter identity. That way, our - // definition of "equivalent" (per C++ [temp.over.link]) is at - // least as strong as the definition of "equivalent" used for - // name mangling. - VisitType(Parm->getType()); - ID.AddInteger(Parm->getFunctionScopeDepth()); - ID.AddInteger(Parm->getFunctionScopeIndex()); - return; - } - - if (const TemplateTypeParmDecl *TTP = - dyn_cast(D)) { - ID.AddInteger(TTP->getDepth()); - ID.AddInteger(TTP->getIndex()); - ID.AddBoolean(TTP->isParameterPack()); - return; - } - - if (const TemplateTemplateParmDecl *TTP = - dyn_cast(D)) { - ID.AddInteger(TTP->getDepth()); - ID.AddInteger(TTP->getIndex()); - ID.AddBoolean(TTP->isParameterPack()); - return; - } - } - - ID.AddPointer(D ? D->getCanonicalDecl() : nullptr); - } - - void VisitType(QualType T) override { - if (Canonical) - T = Context.getCanonicalType(T); - - ID.AddPointer(T.getAsOpaquePtr()); - } - - void VisitName(DeclarationName Name) override { - ID.AddPointer(Name.getAsOpaquePtr()); - } - - void VisitIdentifierInfo(IdentifierInfo *II) override { - ID.AddPointer(II); - } - - void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override { - if (Canonical) - NNS = Context.getCanonicalNestedNameSpecifier(NNS); - ID.AddPointer(NNS); - } - - void VisitTemplateName(TemplateName Name) override { - if (Canonical) - Name = Context.getCanonicalTemplateName(Name); - - Name.Profile(ID); - } - }; - - class StmtProfilerWithoutPointers : public StmtProfiler { - ODRHash &Hash; - public: - StmtProfilerWithoutPointers(llvm::FoldingSetNodeID &ID, ODRHash &Hash) - : StmtProfiler(ID, false), Hash(Hash) {} - - private: - void VisitType(QualType T) override { - Hash.AddQualType(T); - } - - void VisitName(DeclarationName Name) override { - Hash.AddDeclarationName(Name); - } - void VisitIdentifierInfo(IdentifierInfo *II) override { - ID.AddBoolean(II); - if (II) { - Hash.AddIdentifierInfo(II); - } - } - void VisitDecl(const Decl *D) override { - ID.AddBoolean(D); - if (D) { - Hash.AddDecl(D); - } - } - void VisitTemplateName(TemplateName Name) override { - Hash.AddTemplateName(Name); - } - void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override { - ID.AddBoolean(NNS); - if (NNS) { - Hash.AddNestedNameSpecifier(NNS); - } - } - }; } void StmtProfiler::VisitStmt(const Stmt *S) { @@ -979,7 +853,7 @@ void StmtProfiler::VisitOffsetOfExpr(const OffsetOfExpr *S) { break; case OffsetOfNode::Identifier: - VisitIdentifierInfo(ON.getFieldName()); + ID.AddPointer(ON.getFieldName()); break; case OffsetOfNode::Base: @@ -987,7 +861,7 @@ void StmtProfiler::VisitOffsetOfExpr(const OffsetOfExpr *S) { break; } } - + VisitExpr(S); } @@ -1577,7 +1451,7 @@ StmtProfiler::VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) { if (S->getDestroyedTypeInfo()) VisitType(S->getDestroyedType()); else - VisitIdentifierInfo(S->getDestroyedTypeIdentifier()); + ID.AddPointer(S->getDestroyedTypeIdentifier()); } void StmtProfiler::VisitOverloadExpr(const OverloadExpr *S) { @@ -1827,6 +1701,77 @@ void StmtProfiler::VisitObjCAvailabilityCheckExpr( VisitExpr(S); } +void StmtProfiler::VisitDecl(const Decl *D) { + ID.AddInteger(D? D->getKind() : 0); + + if (Canonical && D) { + if (const NonTypeTemplateParmDecl *NTTP = + dyn_cast(D)) { + ID.AddInteger(NTTP->getDepth()); + ID.AddInteger(NTTP->getIndex()); + ID.AddBoolean(NTTP->isParameterPack()); + VisitType(NTTP->getType()); + return; + } + + if (const ParmVarDecl *Parm = dyn_cast(D)) { + // The Itanium C++ ABI uses the type, scope depth, and scope + // index of a parameter when mangling expressions that involve + // function parameters, so we will use the parameter's type for + // establishing function parameter identity. That way, our + // definition of "equivalent" (per C++ [temp.over.link]) is at + // least as strong as the definition of "equivalent" used for + // name mangling. + VisitType(Parm->getType()); + ID.AddInteger(Parm->getFunctionScopeDepth()); + ID.AddInteger(Parm->getFunctionScopeIndex()); + return; + } + + if (const TemplateTypeParmDecl *TTP = + dyn_cast(D)) { + ID.AddInteger(TTP->getDepth()); + ID.AddInteger(TTP->getIndex()); + ID.AddBoolean(TTP->isParameterPack()); + return; + } + + if (const TemplateTemplateParmDecl *TTP = + dyn_cast(D)) { + ID.AddInteger(TTP->getDepth()); + ID.AddInteger(TTP->getIndex()); + ID.AddBoolean(TTP->isParameterPack()); + return; + } + } + + ID.AddPointer(D? D->getCanonicalDecl() : nullptr); +} + +void StmtProfiler::VisitType(QualType T) { + if (Canonical) + T = Context.getCanonicalType(T); + + ID.AddPointer(T.getAsOpaquePtr()); +} + +void StmtProfiler::VisitName(DeclarationName Name) { + ID.AddPointer(Name.getAsOpaquePtr()); +} + +void StmtProfiler::VisitNestedNameSpecifier(NestedNameSpecifier *NNS) { + if (Canonical) + NNS = Context.getCanonicalNestedNameSpecifier(NNS); + ID.AddPointer(NNS); +} + +void StmtProfiler::VisitTemplateName(TemplateName Name) { + if (Canonical) + Name = Context.getCanonicalTemplateName(Name); + + Name.Profile(ID); +} + void StmtProfiler::VisitTemplateArguments(const TemplateArgumentLoc *Args, unsigned NumArgs) { ID.AddInteger(NumArgs); @@ -1876,12 +1821,6 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, bool Canonical) const { - StmtProfilerWithPointers Profiler(ID, Context, Canonical); - Profiler.Visit(this); -} - -void Stmt::ProcessODRHash(llvm::FoldingSetNodeID &ID, - class ODRHash &Hash) const { - StmtProfilerWithoutPointers Profiler(ID, Hash); + StmtProfiler Profiler(ID, Context, Canonical); Profiler.Visit(this); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f65a83f4b6..60daae056b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -13705,11 +13705,8 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD, RD->completeDefinition(); } - if (auto *RD = dyn_cast(Tag)) { + if (isa(Tag)) FieldCollector->FinishClass(); - if (Context.getLangOpts().Modules) - RD->computeODRHash(); - } // Exit this scope of this tag's definition. PopDeclContext(); diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 74da6be206..da8e5ff6b9 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -26,7 +26,6 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" -#include "clang/AST/ODRHash.h" #include "clang/AST/RawCommentList.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" @@ -8885,638 +8884,21 @@ void ASTReader::diagnoseOdrViolations() { for (auto *RD : Merge.second) { // Multiple different declarations got merged together; tell the user // where they came from. - if (Merge.first == RD) - continue; - - llvm::SmallVector, 4> FirstHashes; - llvm::SmallVector, 4> SecondHashes; - ODRHash Hash; - for (auto D : Merge.first->decls()) { - if (D->isImplicit()) - continue; - Hash.clear(); - Hash.AddDecl(D); - FirstHashes.emplace_back(D, Hash.CalculateHash()); - } - for (auto D : RD->decls()) { - if (D->isImplicit()) - continue; - Hash.clear(); - Hash.AddDecl(D); - SecondHashes.emplace_back(D, Hash.CalculateHash()); - } - - // Used with err_module_odr_violation_mismatch_decl and - // note_module_odr_violation_mismatch_decl - enum { - EndOfClass, - PublicSpecifer, - PrivateSpecifer, - ProtectedSpecifer, - Friend, - Enum, - StaticAssert, - Typedef, - TypeAlias, - CXXMethod, - CXXConstructor, - CXXDestructor, - CXXConversion, - Field, - Other - } FirstDiffType = Other, - SecondDiffType = Other; - - auto DifferenceSelector = [](Decl *D) { - assert(D && "valid Decl required"); - switch (D->getKind()) { - default: - return Other; - case Decl::AccessSpec: - switch (D->getAccess()) { - case AS_public: - return PublicSpecifer; - case AS_private: - return PrivateSpecifer; - case AS_protected: - return ProtectedSpecifer; - case AS_none: - llvm_unreachable("Invalid access specifier"); - } - case Decl::Friend: - return Friend; - case Decl::Enum: - return Enum; - case Decl::StaticAssert: - return StaticAssert; - case Decl::Typedef: - return Typedef; - case Decl::TypeAlias: - return TypeAlias; - case Decl::CXXMethod: - return CXXMethod; - case Decl::CXXConstructor: - return CXXConstructor; - case Decl::CXXDestructor: - return CXXDestructor; - case Decl::CXXConversion: - return CXXConversion; - case Decl::Field: - return Field; - } - }; - Decl *FirstDecl = nullptr; - Decl *SecondDecl = nullptr; - auto FirstIt = FirstHashes.begin(); - auto SecondIt = SecondHashes.begin(); - - // If there is a diagnoseable difference, FirstDiffType and - // SecondDiffType will not be Other and FirstDecl and SecondDecl will be - // filled in if not EndOfClass. - while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) { - if (FirstIt->second == SecondIt->second) { - ++FirstIt; - ++SecondIt; - continue; - } - - FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first; - SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first; - - FirstDiffType = FirstDecl ? DifferenceSelector(FirstDecl) : EndOfClass; - SecondDiffType = - SecondDecl ? DifferenceSelector(SecondDecl) : EndOfClass; - - break; - } - - if (FirstDiffType == Other || SecondDiffType == Other) { - // Reaching this point means an unexpected Decl was encountered - // or no difference was detected. This causes a generic error - // message to be emitted. - std::string Module = getOwningModuleNameForDiagnostic(Merge.first); - Diag(Merge.first->getLocation(), - diag::err_module_odr_violation_different_definitions) + if (Merge.first != RD) { + // FIXME: Walk the definition, figure out what's different, + // and diagnose that. + if (!Diagnosed) { + std::string Module = getOwningModuleNameForDiagnostic(Merge.first); + Diag(Merge.first->getLocation(), + diag::err_module_odr_violation_different_definitions) << Merge.first << Module.empty() << Module; - - - - Diag(RD->getLocation(), - diag::note_module_odr_violation_different_definitions) - << getOwningModuleNameForDiagnostic(RD); - Diagnosed = true; - break; - } - - std::string FirstModule = getOwningModuleNameForDiagnostic(Merge.first); - std::string SecondModule = getOwningModuleNameForDiagnostic(RD); - - if (FirstDiffType != SecondDiffType) { - SourceLocation FirstLoc; - SourceRange FirstRange; - if (FirstDiffType == EndOfClass) { - FirstLoc = Merge.first->getBraceRange().getEnd(); - } else { - FirstLoc = FirstIt->first->getLocation(); - FirstRange = FirstIt->first->getSourceRange(); - } - Diag(FirstLoc, diag::err_module_odr_violation_mismatch_decl) - << Merge.first << FirstModule.empty() << FirstModule << FirstRange - << FirstDiffType; - - SourceLocation SecondLoc; - SourceRange SecondRange; - if (SecondDiffType == EndOfClass) { - SecondLoc = RD->getBraceRange().getEnd(); - } else { - SecondLoc = SecondDecl->getLocation(); - SecondRange = SecondDecl->getSourceRange(); - } - Diag(SecondLoc, diag::note_module_odr_violation_mismatch_decl) - << SecondModule << SecondRange << SecondDiffType; - Diagnosed = true; - break; - } - - // Used with err_module_odr_violation_mismatch_decl_diff and - // note_module_odr_violation_mismatch_decl_diff - enum ODRDeclDifference{ - FriendName, - EnumName, - EnumConstantName, - EnumConstantInit, - EnumConstantNoInit, - EnumConstantDiffInit, - EnumNumberOfConstants, - StaticAssertCondition, - StaticAssertMessage, - StaticAssertOnlyMessage, - TypedefName, - MethodName, - MethodStatic, - MethodInline, - MethodConst, - MethodNumParams, - MethodParamName, - MethodParamType, - MethodDefaultArg, - MethodOnlyDefaultArg, - MethodOnlyBody, - MethodBody, - FieldName, - FieldSingleBitField, - FieldMutable, - }; - - // These lambdas have the common portions of the ODR diagnostics. This - // has the same return as Diag(), so addition parameters can be passed - // in with operator<< - auto ODRDiagError = [&Merge, &FirstModule, this]( - SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) { - return Diag(Loc, diag::err_module_odr_violation_mismatch_decl_diff) - << Merge.first << FirstModule.empty() << FirstModule << Range - << DiffType; - }; - auto ODRDiagNote = [&SecondModule, this]( - SourceLocation Loc, SourceRange Range, ODRDeclDifference DiffType) { - return Diag(Loc, diag::note_module_odr_violation_mismatch_decl_diff) - << SecondModule << Range << DiffType; - }; - - auto ComputeODRHash = [&Hash](const Stmt* S) { - assert(S); - Hash.clear(); - Hash.AddStmt(S); - return Hash.CalculateHash(); - }; - - // At this point, both decls are of the same type. Dive down deeper into - // the Decl to determine where the first difference is located. - switch (FirstDiffType) { - case Friend: { - FriendDecl *FirstFriend = cast(FirstDecl); - FriendDecl *SecondFriend = cast(SecondDecl); - { - auto D = ODRDiagError(FirstFriend->getFriendLoc(), - FirstFriend->getSourceRange(), FriendName); - if (TypeSourceInfo *FirstTSI = FirstFriend->getFriendType()) - D << FirstTSI->getType(); - else - D << FirstFriend->getFriendDecl(); - } - { - auto D = ODRDiagNote(SecondFriend->getFriendLoc(), - SecondFriend->getSourceRange(), FriendName); - if (TypeSourceInfo *SecondTSI = SecondFriend->getFriendType()) - D << SecondTSI->getType(); - else - D << SecondFriend->getFriendDecl(); - } - Diagnosed = true; - break; - } - case Enum: { - EnumDecl *FirstEnum = cast(FirstDecl); - EnumDecl *SecondEnum = cast(SecondDecl); - if (FirstEnum->getName() != SecondEnum->getName()) { - ODRDiagError(FirstEnum->getLocStart(), FirstEnum->getSourceRange(), - EnumName) - << FirstEnum; - ODRDiagNote(SecondEnum->getLocStart(), SecondEnum->getSourceRange(), - EnumName) - << SecondEnum; Diagnosed = true; - break; } - // Don't use EnumDecl::enumerator_{begin,end}. Decl merging can - // cause the iterators from them to be the same for both Decl's. - EnumDecl::enumerator_iterator FirstEnumIt(FirstEnum->decls_begin()); - EnumDecl::enumerator_iterator FirstEnumEnd(FirstEnum->decls_end()); - EnumDecl::enumerator_iterator SecondEnumIt(SecondEnum->decls_begin()); - EnumDecl::enumerator_iterator SecondEnumEnd(SecondEnum->decls_end()); - int NumElements = 0; - for (; FirstEnumIt != FirstEnumEnd && SecondEnumIt != SecondEnumEnd; - ++FirstEnumIt, ++SecondEnumIt, ++NumElements) { - if (FirstEnumIt->getName() != SecondEnumIt->getName()) { - ODRDiagError(FirstEnumIt->getLocStart(), - FirstEnumIt->getSourceRange(), EnumConstantName) - << *FirstEnumIt << FirstEnum; - ODRDiagNote(SecondEnumIt->getLocStart(), - SecondEnumIt->getSourceRange(), EnumConstantName) - << *SecondEnumIt << SecondEnum; - Diagnosed = true; - break; - } - Expr *FirstInit = FirstEnumIt->getInitExpr(); - Expr *SecondInit = SecondEnumIt->getInitExpr(); - - if (FirstInit && !SecondInit) { - ODRDiagError(FirstEnumIt->getLocStart(), - FirstEnumIt->getSourceRange(), EnumConstantInit) - << *FirstEnumIt << FirstEnum; - - ODRDiagNote(SecondEnumIt->getLocStart(), - SecondEnumIt->getSourceRange(), EnumConstantNoInit) - << *SecondEnumIt << SecondEnum; - Diagnosed = true; - break; - } - - if (!FirstInit && SecondInit) { - ODRDiagError(FirstEnumIt->getLocStart(), - FirstEnumIt->getSourceRange(), EnumConstantNoInit) - << *FirstEnumIt << FirstEnum; - ODRDiagNote(SecondEnumIt->getLocStart(), - SecondEnumIt->getSourceRange(), EnumConstantInit) - << *SecondEnumIt << SecondEnum; - Diagnosed = true; - break; - } - - if (FirstInit == SecondInit) - continue; - - unsigned FirstODRHash = ComputeODRHash(FirstInit); - unsigned SecondODRHash = ComputeODRHash(SecondInit); - - if (FirstODRHash != SecondODRHash) { - ODRDiagError(FirstEnumIt->getLocStart(), - FirstEnumIt->getSourceRange(), EnumConstantDiffInit) - << *FirstEnumIt << FirstEnum; - ODRDiagNote(SecondEnumIt->getLocStart(), - SecondEnumIt->getSourceRange(), EnumConstantDiffInit) - << *SecondEnumIt << SecondEnum; - Diagnosed = true; - break; - } - } - - if (FirstEnumIt == FirstEnumEnd && SecondEnumIt != SecondEnumEnd) { - unsigned FirstEnumSize = NumElements; - unsigned SecondEnumSize = NumElements; - for (; SecondEnumIt != SecondEnumEnd; ++SecondEnumIt) - ++SecondEnumSize; - ODRDiagError(FirstEnum->getLocStart(), FirstEnum->getSourceRange(), - EnumNumberOfConstants) - << FirstEnum << FirstEnumSize; - ODRDiagNote(SecondEnum->getLocStart(), SecondEnum->getSourceRange(), - EnumNumberOfConstants) - << SecondEnum << SecondEnumSize; - Diagnosed = true; - break; - } - - if (FirstEnumIt != FirstEnumEnd && SecondEnumIt == SecondEnumEnd) { - unsigned FirstEnumSize = NumElements; - unsigned SecondEnumSize = NumElements; - for (; FirstEnumIt != FirstEnumEnd; ++FirstEnumIt) - ++FirstEnumSize; - ODRDiagError(FirstEnum->getLocStart(), FirstEnum->getSourceRange(), - EnumNumberOfConstants) - << FirstEnum << FirstEnumSize; - ODRDiagNote(SecondEnum->getLocStart(), SecondEnum->getSourceRange(), - EnumNumberOfConstants) - << SecondEnum << SecondEnumSize; - Diagnosed = true; - break; - } - - break; - } - case StaticAssert: { - StaticAssertDecl *FirstSA = cast(FirstDecl); - StaticAssertDecl *SecondSA = cast(SecondDecl); - - Expr *FirstExpr = FirstSA->getAssertExpr(); - Expr *SecondExpr = SecondSA->getAssertExpr(); - unsigned FirstODRHash = ComputeODRHash(FirstExpr); - unsigned SecondODRHash = ComputeODRHash(SecondExpr); - if (FirstODRHash != SecondODRHash) { - ODRDiagError(FirstExpr->getLocStart(), FirstExpr->getSourceRange(), - StaticAssertCondition); - ODRDiagNote(SecondExpr->getLocStart(), - SecondExpr->getSourceRange(), StaticAssertCondition); - Diagnosed = true; - break; - } - - StringLiteral *FirstStr = FirstSA->getMessage(); - StringLiteral *SecondStr = SecondSA->getMessage(); - if ((FirstStr && !SecondStr) || (!FirstStr && SecondStr)) { - SourceLocation FirstLoc, SecondLoc; - SourceRange FirstRange, SecondRange; - if (FirstStr) { - FirstLoc = FirstStr->getLocStart(); - FirstRange = FirstStr->getSourceRange(); - } else { - FirstLoc = FirstSA->getLocStart(); - FirstRange = FirstSA->getSourceRange(); - } - if (SecondStr) { - SecondLoc = SecondStr->getLocStart(); - SecondRange = SecondStr->getSourceRange(); - } else { - SecondLoc = SecondSA->getLocStart(); - SecondRange = SecondSA->getSourceRange(); - } - ODRDiagError(FirstLoc, FirstRange, StaticAssertOnlyMessage) - << (FirstStr == nullptr); - ODRDiagNote(SecondLoc, SecondRange, StaticAssertOnlyMessage) - << (SecondStr == nullptr); - Diagnosed = true; - break; - } - - if (FirstStr && SecondStr && - FirstStr->getString() != SecondStr->getString()) { - ODRDiagError(FirstStr->getLocStart(), FirstStr->getSourceRange(), - StaticAssertMessage); - ODRDiagNote(SecondStr->getLocStart(), SecondStr->getSourceRange(), - StaticAssertMessage); - Diagnosed = true; - break; - } - break; - } - case Typedef: - case TypeAlias: { - TypedefNameDecl *FirstTD = cast(FirstDecl); - TypedefNameDecl *SecondTD = cast(SecondDecl); - IdentifierInfo *FirstII = FirstTD->getIdentifier(); - IdentifierInfo *SecondII = SecondTD->getIdentifier(); - if (FirstII && SecondII && FirstII->getName() != SecondII->getName()) { - ODRDiagError(FirstTD->getLocation(), FirstTD->getSourceRange(), - TypedefName) - << (FirstDiffType == TypeAlias) << FirstII; - ODRDiagNote(SecondTD->getLocation(), SecondTD->getSourceRange(), - TypedefName) - << (FirstDiffType == TypeAlias) << SecondII; - Diagnosed = true; - break; - } - break; - } - case CXXMethod: - case CXXConstructor: - case CXXConversion: - case CXXDestructor: { - // TODO: Merge with existing method diff logic. - CXXMethodDecl *FirstMD = cast(FirstDecl); - CXXMethodDecl *SecondMD = cast(SecondDecl); - IdentifierInfo *FirstII = FirstMD->getIdentifier(); - IdentifierInfo *SecondII = SecondMD->getIdentifier(); - if (FirstII && SecondII && FirstII->getName() != SecondII->getName()) { - ODRDiagError(FirstMD->getLocation(), FirstMD->getSourceRange(), - MethodName) - << FirstII; - ODRDiagNote(SecondMD->getLocation(), SecondMD->getSourceRange(), - MethodName) - << SecondII; - Diagnosed = true; - break; - } - - bool FirstStatic = FirstMD->getStorageClass() == SC_Static; - bool SecondStatic = SecondMD->getStorageClass() == SC_Static; - if (FirstStatic != SecondStatic) { - ODRDiagError(FirstMD->getLocation(), FirstMD->getSourceRange(), - MethodStatic) - << FirstMD << FirstStatic; - ODRDiagNote(SecondMD->getLocation(), SecondMD->getSourceRange(), - MethodStatic) - << SecondMD << SecondStatic; - Diagnosed = true; - break; - } - - bool FirstInline = FirstMD->isInlineSpecified(); - bool SecondInline = SecondMD->isInlineSpecified(); - if (FirstInline != SecondInline) { - ODRDiagError(FirstMD->getLocation(), FirstMD->getSourceRange(), - MethodInline) - << FirstMD << FirstInline; - ODRDiagNote(SecondMD->getLocation(), SecondMD->getSourceRange(), - MethodInline) - << SecondMD << SecondInline; - Diagnosed = true; - break; - } - - bool FirstConst = FirstMD->isConst(); - bool SecondConst = SecondMD->isConst(); - if (FirstConst != SecondConst) { - ODRDiagError(FirstMD->getLocation(), FirstMD->getSourceRange(), - MethodConst) - << FirstMD << FirstInline; - ODRDiagNote(SecondMD->getLocation(), SecondMD->getSourceRange(), - MethodConst) - << SecondMD << SecondInline; - Diagnosed = true; - break; - } - - if (FirstMD->getNumParams() != SecondMD->getNumParams()) { - ODRDiagError(FirstMD->getLocation(), FirstMD->getSourceRange(), - MethodNumParams) - << SecondMD << FirstMD->getNumParams(); - ODRDiagNote(SecondMD->getLocation(), SecondMD->getSourceRange(), - MethodNumParams) - << SecondMD << SecondMD->getNumParams(); - Diagnosed = true; - break; - } - - for (unsigned i = 0, e = FirstMD->getNumParams(); i < e; ++i) { - ParmVarDecl *FirstParam = FirstMD->getParamDecl(i); - ParmVarDecl *SecondParam = SecondMD->getParamDecl(i); - IdentifierInfo *FirstII = FirstParam->getIdentifier(); - IdentifierInfo *SecondII = SecondParam->getIdentifier(); - if ((!FirstII && SecondII) || (FirstII && !SecondII) || - (FirstII && SecondII && - FirstII->getName() != SecondII->getName())) { - ODRDiagError(FirstParam->getLocation(), - FirstParam->getSourceRange(), MethodParamName) - << SecondMD << i + 1 << (FirstII == nullptr) << FirstII; - ODRDiagNote(SecondParam->getLocation(), - SecondParam->getSourceRange(), MethodParamName) - << SecondMD << i + 1 << (SecondII == nullptr) << SecondII; - Diagnosed = true; - break; - } - - if (FirstParam->getType() != SecondParam->getType()) { - ODRDiagError(FirstParam->getLocation(), - FirstParam->getSourceRange(), MethodParamType) - << SecondMD << i + 1 << FirstParam->getType(); - ODRDiagNote(SecondParam->getLocation(), - SecondParam->getSourceRange(), MethodParamType) - << SecondMD << i + 1 << SecondParam->getType(); - Diagnosed = true; - break; - } - - Expr *FirstDefaultArg = FirstParam->getDefaultArg(); - Expr *SecondDefaultArg = SecondParam->getDefaultArg(); - if ((!FirstDefaultArg && SecondDefaultArg) || - (FirstDefaultArg && !SecondDefaultArg)) { - ODRDiagError(FirstParam->getLocation(), - FirstParam->getSourceRange(), MethodOnlyDefaultArg) - << SecondMD << i + 1 << (FirstDefaultArg != nullptr); - ODRDiagNote(SecondParam->getLocation(), - SecondParam->getSourceRange(), MethodOnlyDefaultArg) - << SecondMD << i + 1 << (SecondDefaultArg != nullptr); - Diagnosed = true; - break; - } - - if (FirstDefaultArg && SecondDefaultArg) { - unsigned FirstODRHash = ComputeODRHash(FirstDefaultArg); - unsigned SecondODRHash = ComputeODRHash(SecondDefaultArg); - if (FirstODRHash != SecondODRHash) { - ODRDiagError(FirstParam->getLocation(), - FirstParam->getSourceRange(), MethodDefaultArg) - << SecondMD << i + 1; - ODRDiagNote(SecondParam->getLocation(), - SecondParam->getSourceRange(), MethodDefaultArg) - << SecondMD << i + 1; - Diagnosed = true; - break; - } - } - } - - // TODO: Figure out how to diagnose different function bodies. - // Deserialization does not import the second function body. - - break; - } - case Field: { - // TODO: Merge with exising field diff logic. - FieldDecl *FirstField = cast(FirstDecl); - FieldDecl *SecondField = cast(SecondDecl); - IdentifierInfo *FirstII = FirstField->getIdentifier(); - IdentifierInfo *SecondII = SecondField->getIdentifier(); - if (FirstII->getName() != SecondII->getName()) { - ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), - FieldName) - << FirstII; - ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), - FieldName) - << SecondII; - Diagnosed = true; - break; - } - - // This case is handled elsewhere. - if (FirstField->getType() != SecondField->getType()) { - break; - } - - bool FirstBitField = FirstField->isBitField(); - bool SecondBitField = SecondField->isBitField(); - if (FirstBitField != SecondBitField) { - ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), - FieldSingleBitField) - << FirstII << FirstBitField; - ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), - FieldSingleBitField) - << SecondII << SecondBitField; - Diagnosed = true; - break; - } - - if (FirstBitField && SecondBitField) { - Expr* FirstWidth = FirstField->getBitWidth(); - Expr *SecondWidth = SecondField->getBitWidth(); - unsigned FirstODRHash = ComputeODRHash(FirstWidth); - unsigned SecondODRHash = ComputeODRHash(SecondWidth); - if (FirstODRHash != SecondODRHash) { - ODRDiagError(FirstField->getLocation(), - FirstField->getSourceRange(), FieldSingleBitField) - << FirstII << FirstBitField; - ODRDiagNote(SecondField->getLocation(), - SecondField->getSourceRange(), FieldSingleBitField) - << SecondII << SecondBitField; - Diagnosed = true; - break; - } - } - - bool FirstMutable = FirstField->isMutable(); - bool SecondMutable = SecondField->isMutable(); - if (FirstMutable != SecondMutable) { - ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), - FieldMutable) - << FirstII << FirstMutable; - ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), - FieldMutable) - << SecondII << SecondMutable; - Diagnosed = true; - break; - } - break; - } - case Other: - case EndOfClass: - case PublicSpecifer: - case PrivateSpecifer: - case ProtectedSpecifer: - llvm_unreachable("Invalid diff type"); + Diag(RD->getLocation(), + diag::note_module_odr_violation_different_definitions) + << getOwningModuleNameForDiagnostic(RD); } - - if (Diagnosed == true) - continue; - - // Unable to find difference in Decl's, print simple different - // definitions diagnostic. - Diag(Merge.first->getLocation(), - diag::err_module_odr_violation_different_definitions) - << Merge.first << FirstModule.empty() << FirstModule; - Diag(RD->getLocation(), - diag::note_module_odr_violation_different_definitions) - << SecondModule; - Diagnosed = true; } if (!Diagnosed) { diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index ba05e83c0a..afda1a83c2 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1521,7 +1521,6 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.ImplicitCopyAssignmentHasConstParam = Record.readInt(); Data.HasDeclaredCopyConstructorWithConstParam = Record.readInt(); Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt(); - Data.ODRHash = Record.readInt(); Data.NumBases = Record.readInt(); if (Data.NumBases) @@ -1652,7 +1651,6 @@ void ASTDeclReader::MergeDefinitionData( OR_FIELD(HasDeclaredCopyConstructorWithConstParam) OR_FIELD(HasDeclaredCopyAssignmentWithConstParam) MATCH_FIELD(IsLambda) - MATCH_FIELD(ODRHash) #undef OR_FIELD #undef MATCH_FIELD diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 7e3daf9595..cfd4c38888 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -5699,7 +5699,6 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { Record->push_back(Data.ImplicitCopyAssignmentHasConstParam); Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam); Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam); - Record->push_back(Data.ODRHash); // IsLambda bit is already saved. Record->push_back(Data.NumBases); diff --git a/test/Modules/merge-using-decls.cpp b/test/Modules/merge-using-decls.cpp index 4153d14207..98989d12f9 100644 --- a/test/Modules/merge-using-decls.cpp +++ b/test/Modules/merge-using-decls.cpp @@ -37,10 +37,6 @@ template int UseAll(); // Here, we're instantiating the definition from 'A' and merging the definition // from 'B' into it. -// expected-error@b.h:* {{'D::type' from module 'B' is not present in definition of 'D' in module 'A'}} -// expected-error@b.h:* {{'D::value' from module 'B' is not present in definition of 'D' in module 'A'}} - - // expected-error@b.h:* {{'E::value' from module 'B' is not present in definition of 'E' in module 'A'}} // expected-error@b.h:* {{'E::v' from module 'B' is not present in definition of 'E' in module 'A'}} diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp deleted file mode 100644 index 4ba220e404..0000000000 --- a/test/Modules/odr_hash.cpp +++ /dev/null @@ -1,1077 +0,0 @@ -// Clear and create directories -// RUN: rm -rf %t -// RUN: mkdir %t -// RUN: mkdir %t/cache -// RUN: mkdir %t/Inputs - -// Build first header file -// RUN: echo "#define FIRST" >> %t/Inputs/first.h -// RUN: cat %s >> %t/Inputs/first.h - -// Build second header file -// RUN: echo "#define SECOND" >> %t/Inputs/second.h -// RUN: cat %s >> %t/Inputs/second.h - -// Build module map file -// RUN: echo "module first {" >> %t/Inputs/module.map -// RUN: echo " header \"first.h\"" >> %t/Inputs/module.map -// RUN: echo "}" >> %t/Inputs/module.map -// RUN: echo "module second {" >> %t/Inputs/module.map -// RUN: echo " header \"second.h\"" >> %t/Inputs/module.map -// RUN: echo "}" >> %t/Inputs/module.map - -// Run test -// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x c++ -I%t/Inputs -verify %s -std=c++11 - -#if !defined(FIRST) && !defined(SECOND) -#include "first.h" -#include "second.h" -#endif - -#if defined(FIRST) -struct S1 { - public: -}; -#elif defined(SECOND) -struct S1 { - private: -}; -#else -S1 s1; -// expected-error@first.h:* {{'S1' has different definitions in different modules; first difference is definition in module 'first' found public access specifier}} -// expected-note@second.h:* {{but in 'second' found private access specifier}} -#endif - -#if defined(FIRST) -struct S2Friend2 {}; -struct S2 { - friend S2Friend2; -}; -#elif defined(SECOND) -struct S2Friend1 {}; -struct S2 { - friend S2Friend1; -}; -#else -S2 s2; -// expected-error@first.h:* {{'S2' has different definitions in different modules; first difference is definition in module 'first' found friend 'S2Friend2'}} -// expected-note@second.h:* {{but in 'second' found other friend 'S2Friend1'}} -#endif - -#if defined(FIRST) -template -struct S3Template {}; -struct S3 { - friend S3Template; -}; -#elif defined(SECOND) -template -struct S3Template {}; -struct S3 { - friend S3Template; -}; -#else -S3 s3; -// expected-error@first.h:* {{'S3' has different definitions in different modules; first difference is definition in module 'first' found friend 'S3Template'}} -// expected-note@second.h:* {{but in 'second' found other friend 'S3Template'}} -#endif - -#if defined(FIRST) -struct S4 { - static_assert(1 == 1, "First"); -}; -#elif defined(SECOND) -struct S4 { - static_assert(1 == 1, "Second"); -}; -#else -S4 s4; -// expected-error@first.h:* {{'S4' has different definitions in different modules; first difference is definition in module 'first' found static assert with message}} -// expected-note@second.h:* {{but in 'second' found static assert with different message}} -#endif - -#if defined(FIRST) -struct S5 { - static_assert(1 == 1, "Message"); -}; -#elif defined(SECOND) -struct S5 { - static_assert(2 == 2, "Message"); -}; -#else -S5 s5; -// expected-error@first.h:* {{'S5' has different definitions in different modules; first difference is definition in module 'first' found static assert with condition}} -// expected-note@second.h:* {{but in 'second' found static assert with different condition}} -#endif - -#if defined(FIRST) -struct S6 { - int First(); -}; -#elif defined(SECOND) -struct S6 { - int Second(); -}; -#else -S6 s6; -// expected-error@second.h:* {{'S6::Second' from module 'second' is not present in definition of 'S6' in module 'first'}} -// expected-note@first.h:* {{definition has no member 'Second'}} -#endif - -#if defined(FIRST) -struct S7 { - double foo(); -}; -#elif defined(SECOND) -struct S7 { - int foo(); -}; -#else -S7 s7; -// expected-error@second.h:* {{'S7::foo' from module 'second' is not present in definition of 'S7' in module 'first'}} -// expected-note@first.h:* {{declaration of 'foo' does not match}} -#endif - -#if defined(FIRST) -struct S8 { - void foo(); -}; -#elif defined(SECOND) -struct S8 { - void foo() {} -}; -#else -S8 s8; -// expected-error@first.h:* {{'S8' has different definitions in different modules; definition in module 'first' is here}} -// expected-note@second.h:* {{definition in module 'second' is here}} -#endif - -#if defined(FIRST) -struct S9 { - void foo() { int y = 5; } -}; -#elif defined(SECOND) -struct S9 { - void foo() { int x = 5; } -}; -#else -S9 s9; -// expected-error@first.h:* {{'S9' has different definitions in different modules; definition in module 'first' is here}} -// expected-note@second.h:* {{definition in module 'second' is here}} -#endif - -#if defined(FIRST) -struct S10 { - struct { - int x; - } a; -}; -#elif defined(SECOND) -struct S10 { - struct { - int x; - int y; - } a; -}; -#else -S10 s10; -// expected-error-re@second.h:* {{'S10::(anonymous struct)::y' from module 'second' is not present in definition of 'S10::(anonymous struct at {{.*}}first.h:{{[0-9]*}}:{{[0-9]*}})' in module 'first'}} -// expected-note@first.h:* {{definition has no member 'y'}} - -// expected-error@first.h:* {{'S10' has different definitions in different modules; definition in module 'first' is here}} -// expected-note@second.h:* {{definition in module 'second' is here}} -#endif - -#if defined(FIRST) -struct S11 { - void foo() { int y = sizeof(int); } -}; -#elif defined(SECOND) -struct S11 { - void foo() { int y = sizeof(double); } -}; -#else -S11 s11; -// expected-error@first.h:* {{'S11' has different definitions in different modules; definition in module 'first' is here}} -// expected-note@second.h:* {{definition in module 'second' is here}} -#endif - -#if defined(FIRST) -struct S12 { - int x = sizeof(x); - int y = sizeof(x); -}; -#elif defined(SECOND) -struct S12 { - int x = sizeof(x); - int y = sizeof(y); -}; -#else -S12 s12; -// expected-error@first.h:* {{'S12' has different definitions in different modules; definition in module 'first' is here}} -// expected-note@second.h:* {{definition in module 'second' is here}} -#endif - -#if defined(FIRST) -struct S13 { - template void foo(); -}; -#elif defined(SECOND) -struct S13 { - template void foo(); -}; -#else -S13 s13; -// expected-error@first.h:* {{'S13' has different definitions in different modules; definition in module 'first' is here}} -// expected-note@second.h:* {{definition in module 'second' is here}} -#endif - -#if defined(FIRST) -struct S14 { - template void foo(); -}; -#elif defined(SECOND) -struct S14 { - template void foo(); -}; -#else -S14 s14; -// expected-error@second.h:* {{'S14::foo' from module 'second' is not present in definition of 'S14' in module 'first'}} -// expected-note@first.h:* {{declaration of 'foo' does not match}} -#endif - -#if defined(FIRST) -template -struct S15 : T { - void foo() { - int x = __builtin_offsetof(T, first); - } -}; -#elif defined(SECOND) -template -struct S15 : T { - void foo() { - int x = __builtin_offsetof(T, second); - } -}; -#else -template -void Test15() { - S15 s15; -// expected-error@first.h:* {{'S15' has different definitions in different modules; definition in module 'first' is here}} -// expected-note@second.h:* {{definition in module 'second' is here}} -} -#endif - -#if defined(FIRST) -struct S16 { - template class Y> - void foo() { - Y<> y; - } -}; -#elif defined(SECOND) -struct S16 { - template class Y> - void foo() { - Y<> y; - } -}; -#else -void TestS16() { - S16 s16; -} -// expected-error@first.h:* {{'S16' has different definitions in different modules; definition in module 'first' is here}} -// expected-note@second.h:* {{definition in module 'second' is here}} -#endif - -#if defined(FIRST) -struct S17 { - template