r330789 - [ODRHash] Hash template arguments of methods.
Richard Trieu via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 24 17:31:15 PDT 2018
Author: rtrieu
Date: Tue Apr 24 17:31:15 2018
New Revision: 330789
URL: http://llvm.org/viewvc/llvm-project?rev=330789&view=rev
Log:
[ODRHash] Hash template arguments of methods.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td
cfe/trunk/lib/AST/ODRHash.cpp
cfe/trunk/lib/Serialization/ASTReader.cpp
cfe/trunk/test/Modules/odr_hash.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td?rev=330789&r1=330788&r2=330789&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td Tue Apr 24 17:31:15 2018
@@ -211,6 +211,12 @@ def err_module_odr_violation_mismatch_de
"with %ordinal6 parameter with%select{out|}7 a default argument|"
"%select{method %5|constructor|destructor}4 "
"with %ordinal6 parameter with a default argument|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %select{no |}6template arguments|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %6 template argument%s6|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %6 for %ordinal7 template argument|"
"%select{typedef|type alias}4 name %5|"
"%select{typedef|type alias}4 %5 with underlying type %6|"
"data member with name %4|"
@@ -258,6 +264,12 @@ def note_module_odr_violation_mismatch_d
"with %ordinal4 parameter with%select{out|}5 a default argument|"
"%select{method %3|constructor|destructor}2 "
"with %ordinal4 parameter with a different default argument|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %select{no |}4template arguments|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %4 template argument%s4|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %4 for %ordinal5 template argument|"
"%select{typedef|type alias}2 name %3|"
"%select{typedef|type alias}2 %3 with different underlying type %4|"
"data member with name %2|"
Modified: cfe/trunk/lib/AST/ODRHash.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ODRHash.cpp?rev=330789&r1=330788&r2=330789&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ODRHash.cpp (original)
+++ cfe/trunk/lib/AST/ODRHash.cpp Tue Apr 24 17:31:15 2018
@@ -148,6 +148,8 @@ void ODRHash::AddTemplateArgument(Templa
AddQualType(TA.getAsType());
break;
case TemplateArgument::Declaration:
+ AddDecl(TA.getAsDecl());
+ break;
case TemplateArgument::NullPtr:
case TemplateArgument::Integral:
break;
@@ -330,6 +332,15 @@ public:
AddQualType(D->getReturnType());
+ const auto* SpecializationArgs = D->getTemplateSpecializationArgs();
+ Hash.AddBoolean(SpecializationArgs);
+ if (SpecializationArgs) {
+ ID.AddInteger(SpecializationArgs->size());
+ for (const TemplateArgument &TA : SpecializationArgs->asArray()) {
+ Hash.AddTemplateArgument(TA);
+ }
+ }
+
Inherited::VisitFunctionDecl(D);
}
Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=330789&r1=330788&r2=330789&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Tue Apr 24 17:31:15 2018
@@ -9450,6 +9450,12 @@ void ASTReader::diagnoseOdrViolations()
return Hash.CalculateHash();
};
+ auto ComputeTemplateArgumentODRHash = [&Hash](const TemplateArgument &TA) {
+ Hash.clear();
+ Hash.AddTemplateArgument(TA);
+ 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
@@ -9948,6 +9954,9 @@ void ASTReader::diagnoseOdrViolations()
MethodParameterName,
MethodParameterSingleDefaultArgument,
MethodParameterDifferentDefaultArgument,
+ MethodNoTemplateArguments,
+ MethodDifferentNumberTemplateArguments,
+ MethodDifferentTemplateArgument,
TypedefName,
TypedefType,
VarName,
@@ -10370,6 +10379,89 @@ void ASTReader::diagnoseOdrViolations()
break;
}
+ const auto *FirstTemplateArgs =
+ FirstMethod->getTemplateSpecializationArgs();
+ const auto *SecondTemplateArgs =
+ SecondMethod->getTemplateSpecializationArgs();
+
+ if ((FirstTemplateArgs && !SecondTemplateArgs) ||
+ (!FirstTemplateArgs && SecondTemplateArgs)) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), MethodNoTemplateArguments)
+ << FirstMethodType << FirstName << (FirstTemplateArgs != nullptr);
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), MethodNoTemplateArguments)
+ << SecondMethodType << SecondName
+ << (SecondTemplateArgs != nullptr);
+
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstTemplateArgs && SecondTemplateArgs) {
+ // Remove pack expansions from argument list.
+ auto ExpandTemplateArgumentList =
+ [](const TemplateArgumentList *TAL) {
+ llvm::SmallVector<const TemplateArgument *, 8> ExpandedList;
+ for (const TemplateArgument &TA : TAL->asArray()) {
+ if (TA.getKind() != TemplateArgument::Pack) {
+ ExpandedList.push_back(&TA);
+ continue;
+ }
+ for (const TemplateArgument &PackTA : TA.getPackAsArray()) {
+ ExpandedList.push_back(&PackTA);
+ }
+ }
+ return ExpandedList;
+ };
+ llvm::SmallVector<const TemplateArgument *, 8> FirstExpandedList =
+ ExpandTemplateArgumentList(FirstTemplateArgs);
+ llvm::SmallVector<const TemplateArgument *, 8> SecondExpandedList =
+ ExpandTemplateArgumentList(SecondTemplateArgs);
+
+ if (FirstExpandedList.size() != SecondExpandedList.size()) {
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(),
+ MethodDifferentNumberTemplateArguments)
+ << FirstMethodType << FirstName
+ << (unsigned)FirstExpandedList.size();
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(),
+ MethodDifferentNumberTemplateArguments)
+ << SecondMethodType << SecondName
+ << (unsigned)SecondExpandedList.size();
+
+ Diagnosed = true;
+ break;
+ }
+
+ bool TemplateArgumentMismatch = false;
+ for (unsigned i = 0, e = FirstExpandedList.size(); i != e; ++i) {
+ const TemplateArgument &FirstTA = *FirstExpandedList[i],
+ &SecondTA = *SecondExpandedList[i];
+ if (ComputeTemplateArgumentODRHash(FirstTA) ==
+ ComputeTemplateArgumentODRHash(SecondTA)) {
+ continue;
+ }
+
+ ODRDiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(),
+ MethodDifferentTemplateArgument)
+ << FirstMethodType << FirstName << FirstTA << i + 1;
+ ODRDiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(),
+ MethodDifferentTemplateArgument)
+ << SecondMethodType << SecondName << SecondTA << i + 1;
+
+ TemplateArgumentMismatch = true;
+ break;
+ }
+
+ if (TemplateArgumentMismatch) {
+ Diagnosed = true;
+ break;
+ }
+ }
break;
}
case TypeAlias:
Modified: cfe/trunk/test/Modules/odr_hash.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/odr_hash.cpp?rev=330789&r1=330788&r2=330789&view=diff
==============================================================================
--- cfe/trunk/test/Modules/odr_hash.cpp (original)
+++ cfe/trunk/test/Modules/odr_hash.cpp Tue Apr 24 17:31:15 2018
@@ -1635,6 +1635,96 @@ S6 s6;
// expected-note at first.h:* {{but in 'FirstModule' found field 'x'}}
#endif
+#if defined(FIRST)
+struct S7 {
+ template<int> void run() {}
+ template<> void run<1>() {}
+};
+#elif defined(SECOND)
+struct S7 {
+ template<int> void run() {}
+ void run() {}
+};
+#else
+S7 s7;
+// expected-error at second.h:* {{'TemplateArgument::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'run' with no template arguments}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'run' with template arguments}}
+#endif
+
+#if defined(FIRST)
+struct S8 {
+ static int a, b;
+ template<int&> void run() {}
+ template<int&, int&> void run() {}
+ template<> void run<a>() {}
+};
+#elif defined(SECOND)
+struct S8 {
+ static int a, b;
+ template<int&> void run() {}
+ template<int&, int&> void run() {}
+ template<> void run<a, b>() {}
+};
+#else
+S8 s8;
+// expected-error at second.h:* {{'TemplateArgument::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'run' with 2 template arguments}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'run' with 1 template argument}}
+#endif
+
+#if defined(FIRST)
+struct S9 {
+ static int a, b;
+ template<int&> void run() {}
+ template<> void run<a>() {}
+};
+#elif defined(SECOND)
+struct S9 {
+ static int a, b;
+ template<int&> void run() {}
+ template<> void run<b>() {}
+};
+#else
+S9 s9;
+// expected-error at second.h:* {{'TemplateArgument::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'run' with 'b' for 1st template argument}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'run' with 'a' for 1st template argument}}
+#endif
+
+#if defined(FIRST)
+struct S10 {
+ static int a, b;
+ template<int, int&...> void run() {}
+ template<> void run<1, a>() {}
+};
+#elif defined(SECOND)
+struct S10 {
+ static int a, b;
+ template<int, int&...> void run() {}
+ template<> void run<1, b>() {}
+};
+#else
+S10 s10;
+// expected-error at second.h:* {{'TemplateArgument::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'run' with 'b' for 2nd template argument}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'run' with 'a' for 2nd template argument}}
+#endif
+
+#if defined(FIRST)
+struct S11 {
+ static int a, b;
+ template<int, int&...> void run() {}
+ template<> void run<1, a>() {}
+};
+#elif defined(SECOND)
+struct S11 {
+ static int a, b;
+ template<int, int&...> void run() {}
+ template<> void run<1, a, a>() {}
+};
+#else
+S11 s11;
+// expected-error at second.h:* {{'TemplateArgument::S11' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'run' with 3 template arguments}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'run' with 2 template arguments}}
+#endif
+
#define DECLS \
OneClass<int> a; \
OneInt<1> b; \
@@ -1642,7 +1732,20 @@ S6 s6;
using d = OneInt<2>; \
using e = OneInt<2 + 2>; \
OneTemplateClass<OneClass> f; \
- OneTemplateInt<OneInt> g;
+ OneTemplateInt<OneInt> g; \
+ static int i1, i2; \
+ template <int &> \
+ void Function() {} \
+ template <int &, int &> \
+ void Function() {} \
+ template <> \
+ void Function<i1>() {} \
+ template <> \
+ void Function<i2>() {} \
+ template <> \
+ void Function<i1, i2>() {} \
+ template <> \
+ void Function<i2, i1>() {}
#if defined(FIRST) || defined(SECOND)
template <class> struct OneClass{};
More information about the cfe-commits
mailing list