r320230 - [ODRHash] Support ODR violation detection in functions.
Richard Trieu via cfe-commits
cfe-commits at lists.llvm.org
Fri Dec 8 17:29:40 PST 2017
Author: rtrieu
Date: Fri Dec 8 17:29:40 2017
New Revision: 320230
URL: http://llvm.org/viewvc/llvm-project?rev=320230&view=rev
Log:
[ODRHash] Support ODR violation detection in functions.
Extend the hashing to functions, which allows detection of function definition
mismatches across modules.
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=320230&r1=320229&r2=320230&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Fri Dec 8 17:29:40 2017
@@ -1760,6 +1760,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
@@ -1842,8 +1847,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>;
@@ -2443,6 +2449,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=320230&r1=320229&r2=320230&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ODRHash.h (original)
+++ cfe/trunk/include/clang/AST/ODRHash.h Fri Dec 8 17:29:40 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=320230&r1=320229&r2=320230&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td Fri Dec 8 17:29:40 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=320230&r1=320229&r2=320230&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Fri Dec 8 17:29:40 2017
@@ -1092,6 +1092,10 @@ private:
llvm::SmallDenseMap<CXXRecordDecl *, llvm::SmallVector<DataPointers, 2>, 2>
PendingOdrMergeFailures;
+ /// \brief Function definitions in which we found an ODR violation.
+ llvm::SmallDenseMap<FunctionDecl *, llvm::SmallVector<FunctionDecl *, 2>, 2>
+ PendingFunctionOdrMergeFailures;
+
/// \brief DeclContexts in which we have diagnosed an ODR violation.
llvm::SmallPtrSet<DeclContext*, 2> DiagnosedOdrMergeFailures;
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=320230&r1=320229&r2=320230&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Fri Dec 8 17:29:40 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"
@@ -3601,6 +3602,25 @@ unsigned FunctionDecl::getMemoryFunction
return 0;
}
+unsigned FunctionDecl::getODRHash() {
+ if (HasODRHash)
+ return ODRHash;
+
+ if (FunctionDecl *Definition = getDefinition()) {
+ if (Definition != this) {
+ HasODRHash = true;
+ ODRHash = Definition->getODRHash();
+ return ODRHash;
+ }
+ }
+
+ class ODRHash Hash;
+ Hash.AddFunctionDecl(this);
+ HasODRHash = true;
+ ODRHash = Hash.CalculateHash();
+ return ODRHash;
+}
+
//===----------------------------------------------------------------------===//
// FieldDecl Implementation
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/lib/AST/ODRHash.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ODRHash.cpp?rev=320230&r1=320229&r2=320230&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ODRHash.cpp (original)
+++ cfe/trunk/lib/AST/ODRHash.cpp Fri Dec 8 17:29:40 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.");
auto Result = DeclMap.insert(std::make_pair(D, DeclMap.size()));
Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=320230&r1=320229&r2=320230&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Fri Dec 8 17:29:40 2017
@@ -9235,8 +9235,16 @@ void ASTReader::finishPendingActions() {
const FunctionDecl *Defn = nullptr;
if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) {
FD->setLazyBody(PB->second);
- } else
- mergeDefinitionVisibility(const_cast<FunctionDecl*>(Defn), FD);
+ } else {
+ auto *NonConstDefn = const_cast<FunctionDecl*>(Defn);
+ mergeDefinitionVisibility(NonConstDefn, FD);
+
+ if (!FD->isLateTemplateParsed() &&
+ !NonConstDefn->isLateTemplateParsed() &&
+ FD->getODRHash() != NonConstDefn->getODRHash()) {
+ PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn);
+ }
+ }
continue;
}
@@ -9253,7 +9261,8 @@ void ASTReader::finishPendingActions() {
}
void ASTReader::diagnoseOdrViolations() {
- if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty())
+ if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty() &&
+ PendingFunctionOdrMergeFailures.empty())
return;
// Trigger the import of the full definition of each class that had any
@@ -9275,6 +9284,20 @@ void ASTReader::diagnoseOdrViolations()
}
}
+ // Trigger the import of functions.
+ auto FunctionOdrMergeFailures = std::move(PendingFunctionOdrMergeFailures);
+ PendingFunctionOdrMergeFailures.clear();
+ for (auto &Merge : FunctionOdrMergeFailures) {
+ Merge.first->buildLookup();
+ Merge.first->decls_begin();
+ Merge.first->getBody();
+ for (auto &FD : Merge.second) {
+ FD->buildLookup();
+ FD->decls_begin();
+ FD->getBody();
+ }
+ }
+
// For each declaration from a merged context, check that the canonical
// definition of that context also contains a declaration of the same
// entity.
@@ -9357,13 +9380,35 @@ void ASTReader::diagnoseOdrViolations()
}
}
- if (OdrMergeFailures.empty())
+ if (OdrMergeFailures.empty() && FunctionOdrMergeFailures.empty())
return;
// Ensure we don't accidentally recursively enter deserialization while
// we're producing our diagnostics.
Deserializing RecursionGuard(this);
+ // Common code for hashing helpers.
+ ODRHash Hash;
+ auto ComputeQualTypeODRHash = [&Hash](QualType Ty) {
+ Hash.clear();
+ Hash.AddQualType(Ty);
+ return Hash.CalculateHash();
+ };
+
+ auto ComputeODRHash = [&Hash](const Stmt *S) {
+ assert(S);
+ Hash.clear();
+ Hash.AddStmt(S);
+ return Hash.CalculateHash();
+ };
+
+ auto ComputeSubDeclODRHash = [&Hash](const Decl *D) {
+ assert(D);
+ Hash.clear();
+ Hash.AddSubDecl(D);
+ return Hash.CalculateHash();
+ };
+
// Issue any pending ODR-failure diagnostics.
for (auto &Merge : OdrMergeFailures) {
// If we've already pointed out a specific problem with this class, don't
@@ -9411,13 +9456,6 @@ void ASTReader::diagnoseOdrViolations()
<< SecondModule << Range << DiffType;
};
- ODRHash Hash;
- auto ComputeQualTypeODRHash = [&Hash](QualType Ty) {
- Hash.clear();
- Hash.AddQualType(Ty);
- return Hash.CalculateHash();
- };
-
unsigned FirstNumBases = FirstDD->NumBases;
unsigned FirstNumVBases = FirstDD->NumVBases;
unsigned SecondNumBases = SecondDD->NumBases;
@@ -9520,14 +9558,12 @@ void ASTReader::diagnoseOdrViolations()
if (FirstTemplate && SecondTemplate) {
DeclHashes FirstTemplateHashes;
DeclHashes SecondTemplateHashes;
- ODRHash Hash;
auto PopulateTemplateParameterHashs =
- [&Hash](DeclHashes &Hashes, const ClassTemplateDecl *TD) {
+ [&ComputeSubDeclODRHash](DeclHashes &Hashes,
+ const ClassTemplateDecl *TD) {
for (auto *D : TD->getTemplateParameters()->asArray()) {
- Hash.clear();
- Hash.AddSubDecl(D);
- Hashes.emplace_back(D, Hash.CalculateHash());
+ Hashes.emplace_back(D, ComputeSubDeclODRHash(D));
}
};
@@ -9696,18 +9732,15 @@ void ASTReader::diagnoseOdrViolations()
DeclHashes FirstHashes;
DeclHashes SecondHashes;
- ODRHash Hash;
- auto PopulateHashes = [&Hash, FirstRecord](DeclHashes &Hashes,
- CXXRecordDecl *Record) {
+ auto PopulateHashes = [&ComputeSubDeclODRHash, FirstRecord](
+ DeclHashes &Hashes, CXXRecordDecl *Record) {
for (auto *D : Record->decls()) {
// Due to decl merging, the first CXXRecordDecl is the parent of
// Decls in both records.
if (!ODRHash::isWhitelistedDecl(D, FirstRecord))
continue;
- Hash.clear();
- Hash.AddSubDecl(D);
- Hashes.emplace_back(D, Hash.CalculateHash());
+ Hashes.emplace_back(D, ComputeSubDeclODRHash(D));
}
};
PopulateHashes(FirstHashes, FirstRecord);
@@ -9901,19 +9934,6 @@ void ASTReader::diagnoseOdrViolations()
<< SecondModule << Range << DiffType;
};
- auto ComputeODRHash = [&Hash](const Stmt* S) {
- assert(S);
- Hash.clear();
- Hash.AddStmt(S);
- return Hash.CalculateHash();
- };
-
- auto ComputeQualTypeODRHash = [&Hash](QualType Ty) {
- Hash.clear();
- Hash.AddQualType(Ty);
- return Hash.CalculateHash();
- };
-
switch (FirstDiffType) {
case Other:
case EndOfClass:
@@ -10488,6 +10508,160 @@ void ASTReader::diagnoseOdrViolations()
<< Merge.first;
}
}
+
+ // Issue ODR failures diagnostics for functions.
+ for (auto &Merge : FunctionOdrMergeFailures) {
+ enum ODRFunctionDifference {
+ ReturnType,
+ ParameterName,
+ ParameterType,
+ ParameterSingleDefaultArgument,
+ ParameterDifferentDefaultArgument,
+ FunctionBody,
+ };
+
+ FunctionDecl *FirstFunction = Merge.first;
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstFunction);
+
+ bool Diagnosed = false;
+ for (auto &SecondFunction : Merge.second) {
+
+ if (FirstFunction == SecondFunction)
+ continue;
+
+ std::string SecondModule =
+ getOwningModuleNameForDiagnostic(SecondFunction);
+
+ auto ODRDiagError = [FirstFunction, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRFunctionDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_function)
+ << FirstFunction << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto ODRDiagNote = [&SecondModule, this](SourceLocation Loc,
+ SourceRange Range,
+ ODRFunctionDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_function)
+ << SecondModule << Range << DiffType;
+ };
+
+ if (ComputeQualTypeODRHash(FirstFunction->getReturnType()) !=
+ ComputeQualTypeODRHash(SecondFunction->getReturnType())) {
+ ODRDiagError(FirstFunction->getReturnTypeSourceRange().getBegin(),
+ FirstFunction->getReturnTypeSourceRange(), ReturnType)
+ << FirstFunction->getReturnType();
+ ODRDiagNote(SecondFunction->getReturnTypeSourceRange().getBegin(),
+ SecondFunction->getReturnTypeSourceRange(), ReturnType)
+ << SecondFunction->getReturnType();
+ Diagnosed = true;
+ break;
+ }
+
+ assert(FirstFunction->param_size() == SecondFunction->param_size() &&
+ "Merged functions with different number of parameters");
+
+ auto ParamSize = FirstFunction->param_size();
+ bool ParameterMismatch = false;
+ for (unsigned I = 0; I < ParamSize; ++I) {
+ auto *FirstParam = FirstFunction->getParamDecl(I);
+ auto *SecondParam = SecondFunction->getParamDecl(I);
+
+ assert(getContext().hasSameType(FirstParam->getType(),
+ SecondParam->getType()) &&
+ "Merged function has different parameter types.");
+
+ if (FirstParam->getDeclName() != SecondParam->getDeclName()) {
+ ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterName)
+ << I + 1 << FirstParam->getDeclName();
+ ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterName)
+ << I + 1 << SecondParam->getDeclName();
+ ParameterMismatch = true;
+ break;
+ };
+
+ QualType FirstParamType = FirstParam->getType();
+ QualType SecondParamType = SecondParam->getType();
+ if (FirstParamType != SecondParamType &&
+ ComputeQualTypeODRHash(FirstParamType) !=
+ ComputeQualTypeODRHash(SecondParamType)) {
+ if (const DecayedType *ParamDecayedType =
+ FirstParamType->getAs<DecayedType>()) {
+ ODRDiagError(FirstParam->getLocation(),
+ FirstParam->getSourceRange(), ParameterType)
+ << (I + 1) << FirstParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ ODRDiagError(FirstParam->getLocation(),
+ FirstParam->getSourceRange(), ParameterType)
+ << (I + 1) << FirstParamType << false;
+ }
+
+ if (const DecayedType *ParamDecayedType =
+ SecondParamType->getAs<DecayedType>()) {
+ ODRDiagNote(SecondParam->getLocation(),
+ SecondParam->getSourceRange(), ParameterType)
+ << (I + 1) << SecondParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ ODRDiagNote(SecondParam->getLocation(),
+ SecondParam->getSourceRange(), ParameterType)
+ << (I + 1) << SecondParamType << false;
+ }
+ ParameterMismatch = true;
+ break;
+ }
+
+ const Expr *FirstInit = FirstParam->getInit();
+ const Expr *SecondInit = SecondParam->getInit();
+ if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+ ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterSingleDefaultArgument)
+ << (I + 1) << (FirstInit == nullptr)
+ << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
+ ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterSingleDefaultArgument)
+ << (I + 1) << (SecondInit == nullptr)
+ << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+ ParameterMismatch = true;
+ break;
+ }
+
+ if (FirstInit && SecondInit &&
+ ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
+ ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterDifferentDefaultArgument)
+ << (I + 1) << FirstInit->getSourceRange();
+ ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterDifferentDefaultArgument)
+ << (I + 1) << SecondInit->getSourceRange();
+ ParameterMismatch = true;
+ break;
+ }
+
+ assert(ComputeSubDeclODRHash(FirstParam) ==
+ ComputeSubDeclODRHash(SecondParam) &&
+ "Undiagnosed parameter difference.");
+ }
+
+ if (ParameterMismatch) {
+ Diagnosed = true;
+ break;
+ }
+
+ // If no error has been generated before now, assume the problem is in
+ // the body and generate a message.
+ ODRDiagError(FirstFunction->getLocation(),
+ FirstFunction->getSourceRange(), FunctionBody);
+ ODRDiagNote(SecondFunction->getLocation(),
+ SecondFunction->getSourceRange(), FunctionBody);
+ Diagnosed = true;
+ break;
+ }
+ assert(Diagnosed && "Unable to emit ODR diagnostic.");
+ }
}
void ASTReader::StartedDeserializing() {
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=320230&r1=320229&r2=320230&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Fri Dec 8 17:29:40 2017
@@ -796,6 +796,9 @@ void ASTDeclReader::VisitFunctionDecl(Fu
FD->setCachedLinkage(Linkage(Record.readInt()));
FD->EndRangeLoc = ReadSourceLocation();
+ FD->ODRHash = Record.readInt();
+ FD->HasODRHash = true;
+
switch ((FunctionDecl::TemplatedKind)Record.readInt()) {
case FunctionDecl::TK_NonTemplate:
mergeRedeclarable(FD, Redecl);
Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=320230&r1=320229&r2=320230&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Fri Dec 8 17:29:40 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:
@@ -2074,6 +2076,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // LateParsed
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LocEnd
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // ODRHash
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // TemplateKind
// This Array slurps the rest of the record. Fortunately we want to encode
// (nearly) all the remaining (variable number of) fields in the same way.
Modified: cfe/trunk/test/Modules/odr_hash.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/odr_hash.cpp?rev=320230&r1=320229&r2=320230&view=diff
==============================================================================
--- cfe/trunk/test/Modules/odr_hash.cpp (original)
+++ cfe/trunk/test/Modules/odr_hash.cpp Fri Dec 8 17:29:40 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
More information about the cfe-commits
mailing list