r305543 - [ODRHash] Hash VarDecl members.

Richard Trieu via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 15 19:44:29 PDT 2017


Author: rtrieu
Date: Thu Jun 15 21:44:29 2017
New Revision: 305543

URL: http://llvm.org/viewvc/llvm-project?rev=305543&view=rev
Log:
[ODRHash] Hash VarDecl members.

These VarDecl's are static data members of classes.  Since the initializers are
also hashed, this also provides checking for default arguments to 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=305543&r1=305542&r2=305543&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td Thu Jun 15 21:44:29 2017
@@ -121,10 +121,12 @@ def err_module_odr_violation_mismatch_de
   "%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|static assert|field|method|type alias|typedef}3">;
+  "protected access specifier|static assert|field|method|type alias|typedef|"
+  "data member}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|static assert|field|method|type alias|typedef}1">;
+  "protected access specifier|static assert|field|method|type alias|typedef|"
+  "data member}1">;
 
 def err_module_odr_violation_mismatch_decl_diff : Error<
   "%q0 has different definitions in different modules; first difference is "
@@ -150,8 +152,16 @@ def err_module_odr_violation_mismatch_de
   "method %4 that has %5 parameter%s5|"
   "method %4 with %ordinal5 parameter of type %6%select{| decayed from %8}7|"
   "method %4 with %ordinal5 parameter named %6|"
+  "method %4 with %ordinal5 parameter with%select{out|}6 a default argument|"
+  "method %4 with %ordinal5 parameter with a default argument|"
   "%select{typedef|type alias}4 name %5|"
-  "%select{typedef|type alias}4 %5 with underlying type %6}3">;
+  "%select{typedef|type alias}4 %5 with underlying type %6|"
+  "data member with name %4|"
+  "data member %4 with type %5|"
+  "data member %4 with%select{out|}5 an initializer|"
+  "data member %4 with an initializer|"
+  "data member %4 %select{is constexpr|is not constexpr}5|"
+  "}3">;
 
 def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
   "%select{"
@@ -175,18 +185,26 @@ def note_module_odr_violation_mismatch_d
   "method %2 that has %3 parameter%s3|"
   "method %2 with %ordinal3 parameter of type %4%select{| decayed from %6}5|"
   "method %2 with %ordinal3 parameter named %4|"
+  "method %2 with %ordinal3 parameter with%select{out|}4 a default argument|"
+  "method %2 with %ordinal3 parameter with a different default argument|"
   "%select{typedef|type alias}2 name %3|"
-  "%select{typedef|type alias}2 %3 with different underlying type %4}1">;
+  "%select{typedef|type alias}2 %3 with different underlying type %4|"
+  "data member with name %2|"
+  "data member %2 with different type %3|"
+  "data member %2 with%select{out|}3 an initializer|"
+  "data member %2 with a different initializer|"
+  "data member %2 %select{is constexpr|is not constexpr}3|"
+  "}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 "
-  "%select{||||static assert|field|method|type alias|typedef|"
+  "%select{||||static assert|field|method|type alias|typedef|data member|"
   "unexpected decl}3">;
 def note_module_odr_violation_mismatch_decl_unknown : Note<
   "but in '%0' found "
   "%select{||||different static assert|different field|different method|"
-  "different type alias|different typedef|"
+  "different type alias|different typedef|different data member|"
   "another unexpected decl}1">;
 
 def warn_duplicate_module_file_extension : Warning<

Modified: cfe/trunk/lib/AST/ODRHash.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ODRHash.cpp?rev=305543&r1=305542&r2=305543&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ODRHash.cpp (original)
+++ cfe/trunk/lib/AST/ODRHash.cpp Thu Jun 15 21:44:29 2017
@@ -252,6 +252,17 @@ public:
     Inherited::VisitValueDecl(D);
   }
 
+  void VisitVarDecl(const VarDecl *D) {
+    Hash.AddBoolean(D->isStaticLocal());
+    Hash.AddBoolean(D->isConstexpr());
+    const bool HasInit = D->hasInit();
+    Hash.AddBoolean(HasInit);
+    if (HasInit) {
+      AddStmt(D->getInit());
+    }
+    Inherited::VisitVarDecl(D);
+  }
+
   void VisitParmVarDecl(const ParmVarDecl *D) {
     // TODO: Handle default arguments.
     Inherited::VisitParmVarDecl(D);
@@ -336,6 +347,7 @@ bool ODRHash::isWhitelistedDecl(const De
     case Decl::StaticAssert:
     case Decl::TypeAlias:
     case Decl::Typedef:
+    case Decl::Var:
       return true;
   }
 }

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=305543&r1=305542&r2=305543&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Jun 15 21:44:29 2017
@@ -9253,6 +9253,7 @@ void ASTReader::diagnoseOdrViolations()
         CXXMethod,
         TypeAlias,
         TypeDef,
+        Var,
         Other
       } FirstDiffType = Other,
         SecondDiffType = Other;
@@ -9284,6 +9285,8 @@ void ASTReader::diagnoseOdrViolations()
           return TypeAlias;
         case Decl::Typedef:
           return TypeDef;
+        case Decl::Var:
+          return Var;
         }
       };
 
@@ -9380,8 +9383,15 @@ void ASTReader::diagnoseOdrViolations()
         MethodNumberParameters,
         MethodParameterType,
         MethodParameterName,
+        MethodParameterSingleDefaultArgument,
+        MethodParameterDifferentDefaultArgument,
         TypedefName,
         TypedefType,
+        VarName,
+        VarType,
+        VarSingleInitializer,
+        VarDifferentInitializer,
+        VarConstexpr,
       };
 
       // These lambdas have the common portions of the ODR diagnostics.  This
@@ -9748,6 +9758,38 @@ void ASTReader::diagnoseOdrViolations()
             ParameterMismatch = true;
             break;
           }
+
+          const Expr *FirstInit = FirstParam->getInit();
+          const Expr *SecondInit = SecondParam->getInit();
+          if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+            ODRDiagError(FirstMethod->getLocation(),
+                         FirstMethod->getSourceRange(),
+                         MethodParameterSingleDefaultArgument)
+                << FirstName << (I + 1) << (FirstInit == nullptr)
+                << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
+            ODRDiagNote(SecondMethod->getLocation(),
+                        SecondMethod->getSourceRange(),
+                        MethodParameterSingleDefaultArgument)
+                << SecondName << (I + 1) << (SecondInit == nullptr)
+                << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+            ParameterMismatch = true;
+            break;
+          }
+
+          if (FirstInit && SecondInit &&
+              ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
+            ODRDiagError(FirstMethod->getLocation(),
+                         FirstMethod->getSourceRange(),
+                         MethodParameterDifferentDefaultArgument)
+                << FirstName << (I + 1) << FirstInit->getSourceRange();
+            ODRDiagNote(SecondMethod->getLocation(),
+                        SecondMethod->getSourceRange(),
+                        MethodParameterDifferentDefaultArgument)
+                << SecondName << (I + 1) << SecondInit->getSourceRange();
+            ParameterMismatch = true;
+            break;
+
+          }
         }
 
         if (ParameterMismatch) {
@@ -9787,6 +9829,77 @@ void ASTReader::diagnoseOdrViolations()
           Diagnosed = true;
           break;
         }
+        break;
+      }
+      case Var: {
+        VarDecl *FirstVD = cast<VarDecl>(FirstDecl);
+        VarDecl *SecondVD = cast<VarDecl>(SecondDecl);
+        auto FirstName = FirstVD->getDeclName();
+        auto SecondName = SecondVD->getDeclName();
+        if (FirstName != SecondName) {
+          ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+                       VarName)
+              << FirstName;
+          ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+                      VarName)
+              << SecondName;
+          Diagnosed = true;
+          break;
+        }
+
+        QualType FirstType = FirstVD->getType();
+        QualType SecondType = SecondVD->getType();
+        if (ComputeQualTypeODRHash(FirstType) !=
+                        ComputeQualTypeODRHash(SecondType)) {
+          ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+                       VarType)
+              << FirstName << FirstType;
+          ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+                      VarType)
+              << SecondName << SecondType;
+          Diagnosed = true;
+          break;
+        }
+
+        const Expr *FirstInit = FirstVD->getInit();
+        const Expr *SecondInit = SecondVD->getInit();
+        if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+          ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+                       VarSingleInitializer)
+              << FirstName << (FirstInit == nullptr)
+              << (FirstInit ? FirstInit->getSourceRange(): SourceRange());
+          ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+                      VarSingleInitializer)
+              << SecondName << (SecondInit == nullptr)
+              << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+          Diagnosed = true;
+          break;
+        }
+
+        if (FirstInit && SecondInit &&
+            ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) {
+          ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+                       VarDifferentInitializer)
+              << FirstName << FirstInit->getSourceRange();
+          ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+                      VarDifferentInitializer)
+              << SecondName << SecondInit->getSourceRange();
+          Diagnosed = true;
+          break;
+        }
+
+        const bool FirstIsConstexpr = FirstVD->isConstexpr();
+        const bool SecondIsConstexpr = SecondVD->isConstexpr();
+        if (FirstIsConstexpr != SecondIsConstexpr) {
+          ODRDiagError(FirstVD->getLocation(), FirstVD->getSourceRange(),
+                       VarConstexpr)
+              << FirstName << FirstIsConstexpr;
+          ODRDiagNote(SecondVD->getLocation(), SecondVD->getSourceRange(),
+                      VarConstexpr)
+              << SecondName << SecondIsConstexpr;
+          Diagnosed = true;
+          break;
+        }
         break;
       }
       }

Modified: cfe/trunk/test/Modules/odr_hash.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/odr_hash.cpp?rev=305543&r1=305542&r2=305543&view=diff
==============================================================================
--- cfe/trunk/test/Modules/odr_hash.cpp (original)
+++ cfe/trunk/test/Modules/odr_hash.cpp Thu Jun 15 21:44:29 2017
@@ -486,7 +486,8 @@ struct S12 {
 };
 #else
 S12 s12;
-// TODO: This should produce an error.
+// expected-error at second.h:* {{'Method::S12' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter without a default argument}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter with a default argument}}
 #endif
 
 #if defined(FIRST)
@@ -499,7 +500,8 @@ struct S13 {
 };
 #else
 S13 s13;
-// TODO: This should produce an error.
+// expected-error at second.h:* {{'Method::S13' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter with a default argument}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter with a different default argument}}
 #endif
 
 #if defined(FIRST)
@@ -1112,6 +1114,179 @@ using TemplateTypeParmType::S2;
 #endif
 }
 
+namespace VarDecl {
+#if defined(FIRST)
+struct S1 {
+  static int x;
+  static int y;
+};
+#elif defined(SECOND)
+struct S1 {
+  static int y;
+  static int x;
+};
+#else
+S1 s1;
+// expected-error at second.h:* {{'VarDecl::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member with name 'y'}}
+// expected-note at first.h:* {{but in 'FirstModule' found data member with name 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+  static int x;
+};
+#elif defined(SECOND)
+using I = int;
+struct S2 {
+  static I x;
+};
+#else
+S2 s2;
+// expected-error at second.h:* {{'VarDecl::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with type 'VarDecl::I' (aka 'int')}}
+// expected-note at first.h:* {{but in 'FirstModule' found data member 'x' with different type 'int'}}
+#endif
+
+#if defined(FIRST)
+struct S3 {
+  static const int x = 1;
+};
+#elif defined(SECOND)
+struct S3 {
+  static const int x;
+};
+#else
+S3 s3;
+// expected-error at second.h:* {{'VarDecl::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with an initializer}}
+// expected-note at first.h:* {{but in 'FirstModule' found data member 'x' without an initializer}}
+#endif
+
+#if defined(FIRST)
+struct S4 {
+  static const int x = 1;
+};
+#elif defined(SECOND)
+struct S4 {
+  static const int x = 2;
+};
+#else
+S4 s4;
+// expected-error at second.h:* {{'VarDecl::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' with an initializer}}
+// expected-note at first.h:* {{but in 'FirstModule' found data member 'x' with a different initializer}}
+#endif
+
+#if defined(FIRST)
+struct S5 {
+  static const int x = 1;
+};
+#elif defined(SECOND)
+struct S5 {
+  static constexpr int x = 1;
+};
+#else
+S5 s5;
+// expected-error at second.h:* {{'VarDecl::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member 'x' is not constexpr}}
+// expected-note at first.h:* {{but in 'FirstModule' found data member 'x' is constexpr}}
+#endif
+
+#if defined(FIRST)
+struct S6 {
+  static const int x = 1;
+};
+#elif defined(SECOND)
+struct S6 {
+  static const int y = 1;
+};
+#else
+S6 s6;
+// expected-error at first.h:* {{'VarDecl::S6::x' from module 'FirstModule' is not present in definition of 'VarDecl::S6' in module 'SecondModule'}}
+// expected-note at second.h:* {{definition has no member 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S7 {
+  static const int x = 1;
+};
+#elif defined(SECOND)
+struct S7 {
+  static const unsigned x = 1;
+};
+#else
+S7 s7;
+// expected-error at first.h:* {{'VarDecl::S7::x' from module 'FirstModule' is not present in definition of 'VarDecl::S7' in module 'SecondModule'}}
+// expected-note at second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+struct S8 {
+public:
+  static const int x = 1;
+};
+#elif defined(SECOND)
+struct S8 {
+  static const int x = 1;
+public:
+};
+#else
+S8 s8;
+// expected-error at second.h:* {{'VarDecl::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found data member}}
+// expected-note at first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+
+#if defined(FIRST)
+struct S9 {
+  static const int x = 1;
+};
+#elif defined(SECOND)
+struct S9 {
+  static int x;
+};
+#else
+S9 s9;
+// expected-error at first.h:* {{'VarDecl::S9::x' from module 'FirstModule' is not present in definition of 'VarDecl::S9' in module 'SecondModule'}}
+// expected-note at second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+template <typename T>
+struct S {
+  struct R {
+    void foo(T x = 0) {}
+  };
+};
+#elif defined(SECOND)
+template <typename T>
+struct S {
+  struct R {
+    void foo(T x = 1) {}
+  };
+};
+#else
+void run() {
+  S<int>::R().foo();
+}
+// expected-error at second.h:* {{'VarDecl::S::R' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'foo' with 1st parameter with a default argument}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'foo' with 1st parameter with a different default argument}}
+#endif
+
+#if defined(FIRST)
+template <typename alpha> struct Bravo {
+  void charlie(bool delta = false) {}
+};
+typedef Bravo<char> echo;
+echo foxtrot;
+#elif defined(SECOND)
+template <typename alpha> struct Bravo {
+  void charlie(bool delta = (false)) {}
+};
+typedef Bravo<char> echo;
+echo foxtrot;
+#else
+Bravo<char> golf;
+// expected-error at second.h:* {{'VarDecl::Bravo' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'charlie' with 1st parameter with a default argument}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'charlie' with 1st parameter with a different default argument}}
+#endif
+}
+
 // Interesting cases that should not cause errors.  struct S should not error
 // while struct T should error at the access specifier mismatch at the end.
 namespace AllDecls {




More information about the cfe-commits mailing list