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