summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/Decl.cpp11
-rw-r--r--clang/lib/AST/ODRHash.cpp36
-rw-r--r--clang/lib/Serialization/ASTReader.cpp204
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp5
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp3
5 files changed, 256 insertions, 3 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index a23499f3fe8..3b9b85a20af 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3973,6 +3973,17 @@ void EnumDecl::setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
SpecializationInfo = new (C) MemberSpecializationInfo(ED, TSK);
}
+unsigned EnumDecl::getODRHash() {
+ if (HasODRHash)
+ return ODRHash;
+
+ class ODRHash Hash;
+ Hash.AddEnumDecl(this);
+ HasODRHash = true;
+ ODRHash = Hash.CalculateHash();
+ return ODRHash;
+}
+
//===----------------------------------------------------------------------===//
// RecordDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 45b8ee61adb..e710d378033 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -407,12 +407,17 @@ public:
AddDecl(D->getTemplatedDecl());
Inherited::VisitFunctionTemplateDecl(D);
}
+
+ void VisitEnumConstantDecl(const EnumConstantDecl *D) {
+ AddStmt(D->getInitExpr());
+ Inherited::VisitEnumConstantDecl(D);
+ }
};
} // namespace
// Only allow a small portion of Decl's to be processed. Remove this once
// all Decl's can be handled.
-bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) {
+bool ODRHash::isWhitelistedDecl(const Decl *D, const DeclContext *Parent) {
if (D->isImplicit()) return false;
if (D->getDeclContext() != Parent) return false;
@@ -423,6 +428,7 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) {
case Decl::CXXConstructor:
case Decl::CXXDestructor:
case Decl::CXXMethod:
+ case Decl::EnumConstant: // Only found in EnumDecl's.
case Decl::Field:
case Decl::Friend:
case Decl::FunctionTemplate:
@@ -554,6 +560,34 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function,
}
}
+void ODRHash::AddEnumDecl(const EnumDecl *Enum) {
+ assert(Enum);
+ AddDeclarationName(Enum->getDeclName());
+
+ AddBoolean(Enum->isScoped());
+ if (Enum->isScoped())
+ AddBoolean(Enum->isScopedUsingClassTag());
+
+ if (Enum->getIntegerTypeSourceInfo())
+ AddQualType(Enum->getIntegerType());
+
+ // Filter out sub-Decls which will not be processed in order to get an
+ // accurate count of Decl's.
+ llvm::SmallVector<const Decl *, 16> Decls;
+ for (Decl *SubDecl : Enum->decls()) {
+ if (isWhitelistedDecl(SubDecl, Enum)) {
+ assert(isa<EnumConstantDecl>(SubDecl) && "Unexpected Decl");
+ Decls.push_back(SubDecl);
+ }
+ }
+
+ ID.AddInteger(Decls.size());
+ for (auto SubDecl : Decls) {
+ AddSubDecl(SubDecl);
+ }
+
+}
+
void ODRHash::AddDecl(const Decl *D) {
assert(D && "Expecting non-null pointer.");
D = D->getCanonicalDecl();
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 4167e868809..9a3b9e1da39 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -9443,7 +9443,8 @@ void ASTReader::finishPendingActions() {
void ASTReader::diagnoseOdrViolations() {
if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty() &&
- PendingFunctionOdrMergeFailures.empty())
+ PendingFunctionOdrMergeFailures.empty() &&
+ PendingEnumOdrMergeFailures.empty())
return;
// Trigger the import of the full definition of each class that had any
@@ -9479,6 +9480,16 @@ void ASTReader::diagnoseOdrViolations() {
}
}
+ // Trigger the import of enums.
+ auto EnumOdrMergeFailures = std::move(PendingEnumOdrMergeFailures);
+ PendingEnumOdrMergeFailures.clear();
+ for (auto &Merge : EnumOdrMergeFailures) {
+ Merge.first->decls_begin();
+ for (auto &Enum : Merge.second) {
+ Enum->decls_begin();
+ }
+ }
+
// For each declaration from a merged context, check that the canonical
// definition of that context also contains a declaration of the same
// entity.
@@ -9561,7 +9572,8 @@ void ASTReader::diagnoseOdrViolations() {
}
}
- if (OdrMergeFailures.empty() && FunctionOdrMergeFailures.empty())
+ if (OdrMergeFailures.empty() && FunctionOdrMergeFailures.empty() &&
+ EnumOdrMergeFailures.empty())
return;
// Ensure we don't accidentally recursively enter deserialization while
@@ -11308,6 +11320,194 @@ void ASTReader::diagnoseOdrViolations() {
(void)Diagnosed;
assert(Diagnosed && "Unable to emit ODR diagnostic.");
}
+
+ // Issue ODR failures diagnostics for enums.
+ for (auto &Merge : EnumOdrMergeFailures) {
+ enum ODREnumDifference {
+ SingleScopedEnum,
+ EnumTagKeywordMismatch,
+ SingleSpecifiedType,
+ DifferentSpecifiedTypes,
+ DifferentNumberEnumConstants,
+ EnumConstantName,
+ EnumConstantSingleInitilizer,
+ EnumConstantDifferentInitilizer,
+ };
+
+ // If we've already pointed out a specific problem with this enum, don't
+ // bother issuing a general "something's different" diagnostic.
+ if (!DiagnosedOdrMergeFailures.insert(Merge.first).second)
+ continue;
+
+ EnumDecl *FirstEnum = Merge.first;
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstEnum);
+
+ using DeclHashes =
+ llvm::SmallVector<std::pair<EnumConstantDecl *, unsigned>, 4>;
+ auto PopulateHashes = [&ComputeSubDeclODRHash, FirstEnum](
+ DeclHashes &Hashes, EnumDecl *Enum) {
+ for (auto *D : Enum->decls()) {
+ // Due to decl merging, the first EnumDecl is the parent of
+ // Decls in both records.
+ if (!ODRHash::isWhitelistedDecl(D, FirstEnum))
+ continue;
+ assert(isa<EnumConstantDecl>(D) && "Unexpected Decl kind");
+ Hashes.emplace_back(cast<EnumConstantDecl>(D),
+ ComputeSubDeclODRHash(D));
+ }
+ };
+ DeclHashes FirstHashes;
+ PopulateHashes(FirstHashes, FirstEnum);
+ bool Diagnosed = false;
+ for (auto &SecondEnum : Merge.second) {
+
+ if (FirstEnum == SecondEnum)
+ continue;
+
+ std::string SecondModule =
+ getOwningModuleNameForDiagnostic(SecondEnum);
+
+ auto ODRDiagError = [FirstEnum, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODREnumDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_enum)
+ << FirstEnum << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto ODRDiagNote = [&SecondModule, this](SourceLocation Loc,
+ SourceRange Range,
+ ODREnumDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_enum)
+ << SecondModule << Range << DiffType;
+ };
+
+ if (FirstEnum->isScoped() != SecondEnum->isScoped()) {
+ ODRDiagError(FirstEnum->getLocation(), FirstEnum->getSourceRange(),
+ SingleScopedEnum)
+ << FirstEnum->isScoped();
+ ODRDiagNote(SecondEnum->getLocation(), SecondEnum->getSourceRange(),
+ SingleScopedEnum)
+ << SecondEnum->isScoped();
+ Diagnosed = true;
+ continue;
+ }
+
+ if (FirstEnum->isScoped() && SecondEnum->isScoped()) {
+ if (FirstEnum->isScopedUsingClassTag() !=
+ SecondEnum->isScopedUsingClassTag()) {
+ ODRDiagError(FirstEnum->getLocation(), FirstEnum->getSourceRange(),
+ EnumTagKeywordMismatch)
+ << FirstEnum->isScopedUsingClassTag();
+ ODRDiagNote(SecondEnum->getLocation(), SecondEnum->getSourceRange(),
+ EnumTagKeywordMismatch)
+ << SecondEnum->isScopedUsingClassTag();
+ Diagnosed = true;
+ continue;
+ }
+ }
+
+ QualType FirstUnderlyingType =
+ FirstEnum->getIntegerTypeSourceInfo()
+ ? FirstEnum->getIntegerTypeSourceInfo()->getType()
+ : QualType();
+ QualType SecondUnderlyingType =
+ SecondEnum->getIntegerTypeSourceInfo()
+ ? SecondEnum->getIntegerTypeSourceInfo()->getType()
+ : QualType();
+ if (FirstUnderlyingType.isNull() != SecondUnderlyingType.isNull()) {
+ ODRDiagError(FirstEnum->getLocation(), FirstEnum->getSourceRange(),
+ SingleSpecifiedType)
+ << !FirstUnderlyingType.isNull();
+ ODRDiagNote(SecondEnum->getLocation(), SecondEnum->getSourceRange(),
+ SingleSpecifiedType)
+ << !SecondUnderlyingType.isNull();
+ Diagnosed = true;
+ continue;
+ }
+
+ if (!FirstUnderlyingType.isNull() && !SecondUnderlyingType.isNull()) {
+ if (ComputeQualTypeODRHash(FirstUnderlyingType) !=
+ ComputeQualTypeODRHash(SecondUnderlyingType)) {
+ ODRDiagError(FirstEnum->getLocation(), FirstEnum->getSourceRange(),
+ DifferentSpecifiedTypes)
+ << FirstUnderlyingType;
+ ODRDiagNote(SecondEnum->getLocation(), SecondEnum->getSourceRange(),
+ DifferentSpecifiedTypes)
+ << SecondUnderlyingType;
+ Diagnosed = true;
+ continue;
+ }
+ }
+
+ DeclHashes SecondHashes;
+ PopulateHashes(SecondHashes, SecondEnum);
+
+ if (FirstHashes.size() != SecondHashes.size()) {
+ ODRDiagError(FirstEnum->getLocation(), FirstEnum->getSourceRange(),
+ DifferentNumberEnumConstants)
+ << (int)FirstHashes.size();
+ ODRDiagNote(SecondEnum->getLocation(), SecondEnum->getSourceRange(),
+ DifferentNumberEnumConstants)
+ << (int)SecondHashes.size();
+ Diagnosed = true;
+ continue;
+ }
+
+ for (unsigned I = 0; I < FirstHashes.size(); ++I) {
+ if (FirstHashes[I].second == SecondHashes[I].second)
+ continue;
+ const EnumConstantDecl *FirstEnumConstant = FirstHashes[I].first;
+ const EnumConstantDecl *SecondEnumConstant = SecondHashes[I].first;
+
+ if (FirstEnumConstant->getDeclName() !=
+ SecondEnumConstant->getDeclName()) {
+
+ ODRDiagError(FirstEnumConstant->getLocation(),
+ FirstEnumConstant->getSourceRange(), EnumConstantName)
+ << I + 1 << FirstEnumConstant;
+ ODRDiagNote(SecondEnumConstant->getLocation(),
+ SecondEnumConstant->getSourceRange(), EnumConstantName)
+ << I + 1 << SecondEnumConstant;
+ Diagnosed = true;
+ break;
+ }
+
+ const Expr *FirstInit = FirstEnumConstant->getInitExpr();
+ const Expr *SecondInit = SecondEnumConstant->getInitExpr();
+ if (!FirstInit && !SecondInit)
+ continue;
+
+ if (!FirstInit || !SecondInit) {
+ ODRDiagError(FirstEnumConstant->getLocation(),
+ FirstEnumConstant->getSourceRange(),
+ EnumConstantSingleInitilizer)
+ << I + 1 << FirstEnumConstant << (FirstInit != nullptr);
+ ODRDiagNote(SecondEnumConstant->getLocation(),
+ SecondEnumConstant->getSourceRange(),
+ EnumConstantSingleInitilizer)
+ << I + 1 << SecondEnumConstant << (SecondInit != nullptr);
+ Diagnosed = true;
+ break;
+ }
+
+ if (ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
+ ODRDiagError(FirstEnumConstant->getLocation(),
+ FirstEnumConstant->getSourceRange(),
+ EnumConstantDifferentInitilizer)
+ << I + 1 << FirstEnumConstant;
+ ODRDiagNote(SecondEnumConstant->getLocation(),
+ SecondEnumConstant->getSourceRange(),
+ EnumConstantDifferentInitilizer)
+ << I + 1 << SecondEnumConstant;
+ Diagnosed = true;
+ break;
+ }
+ }
+ }
+
+ (void)Diagnosed;
+ assert(Diagnosed && "Unable to emit ODR diagnostic.");
+ }
}
void ASTReader::StartedDeserializing() {
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index b33b88c2715..7e2c4829b14 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -746,6 +746,9 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
ED->IsScopedUsingClassTag = Record.readInt();
ED->IsFixed = Record.readInt();
+ ED->HasODRHash = true;
+ ED->ODRHash = Record.readInt();
+
// If this is a definition subject to the ODR, and we already have a
// definition, merge this one into it.
if (ED->IsCompleteDefinition &&
@@ -766,6 +769,8 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
Reader.MergedDeclContexts.insert(std::make_pair(ED, OldDef));
ED->IsCompleteDefinition = false;
Reader.mergeDefinitionVisibility(OldDef, ED);
+ if (OldDef->getODRHash() != ED->getODRHash())
+ Reader.PendingEnumOdrMergeFailures[OldDef].push_back(ED);
} else {
OldDef = ED;
}
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 61d9fed4802..77e578f6bc5 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -431,6 +431,8 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
Record.push_back(D->isScoped());
Record.push_back(D->isScopedUsingClassTag());
Record.push_back(D->isFixed());
+ Record.push_back(D->getODRHash());
+
if (MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo()) {
Record.AddDeclRef(MemberInfo->getInstantiatedFrom());
Record.push_back(MemberInfo->getTemplateSpecializationKind());
@@ -1865,6 +1867,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScoped
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScopedUsingClassTag
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isFixed
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));// ODRHash
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InstantiatedMembEnum
// DC
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
OpenPOWER on IntegriCloud