Author: rtrieu
Date: Fri Mar  3 18:08:58 2017
New Revision: 296932

URL: http://llvm.org/viewvc/llvm-project?rev=296932&view=rev
Log:
[ODRHash] Add support for detecting different method properties.

Now print diagnostics for static, virtual, inline, volatile, and const
differences in methods.  Also use DeclarationName instead of IdentifierInfo
for additional robustness in diagnostic printing.

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=296932&r1=296931&r2=296932&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td Fri Mar  3 
18:08:58 2017
@@ -140,7 +140,13 @@ def err_module_odr_violation_mismatch_de
   "%select{non-|}5mutable field %4|"
   "field %4 with %select{no|an}5 initalizer|"
   "field %4 with an initializer|"
-  "method %4}3">;
+  "method %4|"
+  "method %4 is %select{not deleted|deleted}5|"
+  "method %4 is %select{|pure }5%select{not virtual|virtual}6|"
+  "method %4 is %select{not static|static}5|"
+  "method %4 is %select{not volatile|volatile}5|"
+  "method %4 is %select{not const|const}5|"
+  "method %4 is %select{not inline|inline}5}3">;
 
 def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
   "%select{"
@@ -154,7 +160,13 @@ def note_module_odr_violation_mismatch_d
   "%select{non-|}3mutable field %2|"
   "field %2 with %select{no|an}3 initializer|"
   "field %2 with a different initializer|"
-  "method %2}1">;
+  "method %2|"
+  "method %2 is %select{not deleted|deleted}3|"
+  "method %2 is %select{|pure }3%select{not virtual|virtual}4|"
+  "method %2 is %select{not static|static}3|"
+  "method %2 is %select{not volatile|volatile}3|"
+  "method %2 is %select{not const|const}3|"
+  "method %2 is %select{not inline|inline}3}1">;
 
 def warn_module_uses_date_time : Warning<
   "%select{precompiled header|module}0 uses __DATE__ or __TIME__">,

Modified: cfe/trunk/lib/AST/ODRHash.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ODRHash.cpp?rev=296932&r1=296931&r2=296932&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ODRHash.cpp (original)
+++ cfe/trunk/lib/AST/ODRHash.cpp Fri Mar  3 18:08:58 2017
@@ -160,7 +160,7 @@ public:
   }
 
   void VisitNamedDecl(const NamedDecl *D) {
-    AddIdentifierInfo(D->getIdentifier());
+    Hash.AddDeclarationName(D->getDeclName());
     Inherited::VisitNamedDecl(D);
   }
 
@@ -196,10 +196,19 @@ public:
   }
 
   void VisitFunctionDecl(const FunctionDecl *D) {
+    ID.AddInteger(D->getStorageClass());
+    Hash.AddBoolean(D->isInlineSpecified());
+    Hash.AddBoolean(D->isVirtualAsWritten());
+    Hash.AddBoolean(D->isPure());
+    Hash.AddBoolean(D->isDeletedAsWritten());
+
     Inherited::VisitFunctionDecl(D);
   }
 
   void VisitCXXMethodDecl(const CXXMethodDecl *D) {
+    Hash.AddBoolean(D->isConst());
+    Hash.AddBoolean(D->isVolatile());
+
     Inherited::VisitCXXMethodDecl(D);
   }
 };

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=296932&r1=296931&r2=296932&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Fri Mar  3 18:08:58 2017
@@ -9067,6 +9067,12 @@ void ASTReader::diagnoseOdrViolations()
         FieldSingleInitializer,
         FieldDifferentInitializers,
         MethodName,
+        MethodDeleted,
+        MethodVirtual,
+        MethodStatic,
+        MethodVolatile,
+        MethodConst,
+        MethodInline,
       };
 
       // These lambdas have the common portions of the ODR diagnostics.  This
@@ -9290,16 +9296,103 @@ void ASTReader::diagnoseOdrViolations()
       case CXXMethod: {
         const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(FirstDecl);
         const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(SecondDecl);
-        IdentifierInfo *FirstII = FirstMethod->getIdentifier();
-        IdentifierInfo *SecondII = SecondMethod->getIdentifier();
-        if (FirstII->getName() != SecondII->getName()) {
+        auto FirstName = FirstMethod->getDeclName();
+        auto SecondName = SecondMethod->getDeclName();
+        if (FirstName != SecondName) {
           ODRDiagError(FirstMethod->getLocation(),
                        FirstMethod->getSourceRange(), MethodName)
-              << FirstII;
+              << FirstName;
           ODRDiagNote(SecondMethod->getLocation(),
                       SecondMethod->getSourceRange(), MethodName)
-              << SecondII;
+              << SecondName;
+
+          Diagnosed = true;
+          break;
+        }
+
+        const bool FirstDeleted = FirstMethod->isDeleted();
+        const bool SecondDeleted = SecondMethod->isDeleted();
+        if (FirstDeleted != SecondDeleted) {
+          ODRDiagError(FirstMethod->getLocation(),
+                       FirstMethod->getSourceRange(), MethodDeleted)
+              << FirstName << FirstDeleted;
+
+          ODRDiagNote(SecondMethod->getLocation(),
+                      SecondMethod->getSourceRange(), MethodDeleted)
+              << SecondName << SecondDeleted;
+          Diagnosed = true;
+          break;
+        }
+
+        const bool FirstVirtual = FirstMethod->isVirtualAsWritten();
+        const bool SecondVirtual = SecondMethod->isVirtualAsWritten();
+        const bool FirstPure = FirstMethod->isPure();
+        const bool SecondPure = SecondMethod->isPure();
+        if ((FirstVirtual || SecondVirtual) &&
+            (FirstVirtual != SecondVirtual || FirstPure != SecondPure)) {
+          ODRDiagError(FirstMethod->getLocation(),
+                       FirstMethod->getSourceRange(), MethodVirtual)
+              << FirstName << FirstPure << FirstVirtual;
+          ODRDiagNote(SecondMethod->getLocation(),
+                      SecondMethod->getSourceRange(), MethodVirtual)
+              << SecondName << SecondPure << SecondVirtual;
+          Diagnosed = true;
+          break;
+        }
 
+        // CXXMethodDecl::isStatic uses the canonical Decl.  With Decl merging,
+        // FirstDecl is the canonical Decl of SecondDecl, so the storage
+        // class needs to be checked instead.
+        const auto FirstStorage = FirstMethod->getStorageClass();
+        const auto SecondStorage = SecondMethod->getStorageClass();
+        const bool FirstStatic = FirstStorage == SC_Static;
+        const bool SecondStatic = SecondStorage == SC_Static;
+        if (FirstStatic != SecondStatic) {
+          ODRDiagError(FirstMethod->getLocation(),
+                       FirstMethod->getSourceRange(), MethodStatic)
+              << FirstName << FirstStatic;
+          ODRDiagNote(SecondMethod->getLocation(),
+                      SecondMethod->getSourceRange(), MethodStatic)
+              << SecondName << SecondStatic;
+          Diagnosed = true;
+          break;
+        }
+
+        const bool FirstVolatile = FirstMethod->isVolatile();
+        const bool SecondVolatile = SecondMethod->isVolatile();
+        if (FirstVolatile != SecondVolatile) {
+          ODRDiagError(FirstMethod->getLocation(),
+                       FirstMethod->getSourceRange(), MethodVolatile)
+              << FirstName << FirstVolatile;
+          ODRDiagNote(SecondMethod->getLocation(),
+                      SecondMethod->getSourceRange(), MethodVolatile)
+              << SecondName << SecondVolatile;
+          Diagnosed = true;
+          break;
+        }
+
+        const bool FirstConst = FirstMethod->isConst();
+        const bool SecondConst = SecondMethod->isConst();
+        if (FirstConst != SecondConst) {
+          ODRDiagError(FirstMethod->getLocation(),
+                       FirstMethod->getSourceRange(), MethodConst)
+              << FirstName << FirstConst;
+          ODRDiagNote(SecondMethod->getLocation(),
+                      SecondMethod->getSourceRange(), MethodConst)
+              << SecondName << SecondConst;
+          Diagnosed = true;
+          break;
+        }
+
+        const bool FirstInline = FirstMethod->isInlineSpecified();
+        const bool SecondInline = SecondMethod->isInlineSpecified();
+        if (FirstInline != SecondInline) {
+          ODRDiagError(FirstMethod->getLocation(),
+                       FirstMethod->getSourceRange(), MethodInline)
+              << FirstName << FirstInline;
+          ODRDiagNote(SecondMethod->getLocation(),
+                      SecondMethod->getSourceRange(), MethodInline)
+              << SecondName << SecondInline;
           Diagnosed = true;
           break;
         }

Modified: cfe/trunk/test/Modules/odr_hash.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/odr_hash.cpp?rev=296932&r1=296931&r2=296932&view=diff
==============================================================================
--- cfe/trunk/test/Modules/odr_hash.cpp (original)
+++ cfe/trunk/test/Modules/odr_hash.cpp Fri Mar  3 18:08:58 2017
@@ -308,6 +308,99 @@ S2 s2;
 // expected-error@second.h:* {{'Method::S2' has different definitions in 
different modules; first difference is definition in module 'SecondModule' 
found method 'B'}}
 // expected-note@first.h:* {{but in 'FirstModule' found method 'A'}}
 #endif
+
+#if defined(FIRST)
+struct S3 {
+  static void A() {}
+};
+#elif defined(SECOND)
+struct S3 {
+  void A() {}
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'Method::S3' has different definitions in 
different modules; first difference is definition in module 'SecondModule' 
found method 'A' is not static}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is static}}
+#endif
+
+#if defined(FIRST)
+struct S4 {
+  virtual void A() {}
+  void B() {}
+};
+#elif defined(SECOND)
+struct S4 {
+  void A() {}
+  virtual void B() {}
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'Method::S4' has different definitions in 
different modules; first difference is definition in module 'SecondModule' 
found method 'A' is not virtual}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is virtual}}
+#endif
+
+#if defined(FIRST)
+struct S5 {
+  virtual void A() = 0;
+  virtual void B() {};
+};
+#elif defined(SECOND)
+struct S5 {
+  virtual void A() {}
+  virtual void B() = 0;
+};
+#else
+S5 *s5;
+// expected-error@second.h:* {{'Method::S5' has different definitions in 
different modules; first difference is definition in module 'SecondModule' 
found method 'A' is virtual}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is pure 
virtual}}
+#endif
+
+#if defined(FIRST)
+struct S6 {
+  inline void A() {}
+};
+#elif defined(SECOND)
+struct S6 {
+  void A() {}
+};
+#else
+S6 s6;
+// expected-error@second.h:* {{'Method::S6' has different definitions in 
different modules; first difference is definition in module 'SecondModule' 
found method 'A' is not inline}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is inline}}
+#endif
+
+#if defined(FIRST)
+struct S7 {
+  void A() volatile {}
+  void A() {}
+};
+#elif defined(SECOND)
+struct S7 {
+  void A() {}
+  void A() volatile {}
+};
+#else
+S7 s7;
+// expected-error@second.h:* {{'Method::S7' has different definitions in 
different modules; first difference is definition in module 'SecondModule' 
found method 'A' is not volatile}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is 
volatile}}
+#endif
+
+#if defined(FIRST)
+struct S8 {
+  void A() const {}
+  void A() {}
+};
+#elif defined(SECOND)
+struct S8 {
+  void A() {}
+  void A() const {}
+};
+#else
+S8 s8;
+// expected-error@second.h:* {{'Method::S8' has different definitions in 
different modules; first difference is definition in module 'SecondModule' 
found method 'A' is not const}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is const}}
+#endif
+
 }  // namespace Method
 
 // Naive parsing of AST can lead to cycles in processing.  Ensure
@@ -359,6 +452,12 @@ struct S {
   mutable int c = sizeof(x + y);
 
   void method() {}
+  static void static_method() {}
+  virtual void virtual_method() {}
+  virtual void pure_virtual_method() = 0;
+  inline void inline_method() {}
+  void volatile_method() volatile {}
+  void const_method() const {}
 };
 #elif defined(SECOND)
 typedef int INT;
@@ -381,9 +480,15 @@ struct S {
   mutable int c = sizeof(x + y);
 
   void method() {}
+  static void static_method() {}
+  virtual void virtual_method() {}
+  virtual void pure_virtual_method() = 0;
+  inline void inline_method() {}
+  void volatile_method() volatile {}
+  void const_method() const {}
 };
 #else
-S s;
+S *s;
 #endif
 
 #if defined(FIRST)
@@ -407,6 +512,12 @@ struct T {
   mutable int c = sizeof(x + y);
 
   void method() {}
+  static void static_method() {}
+  virtual void virtual_method() {}
+  virtual void pure_virtual_method() = 0;
+  inline void inline_method() {}
+  void volatile_method() volatile {}
+  void const_method() const {}
 
   private:
 };
@@ -431,11 +542,17 @@ struct T {
   mutable int c = sizeof(x + y);
 
   void method() {}
+  static void static_method() {}
+  virtual void virtual_method() {}
+  virtual void pure_virtual_method() = 0;
+  inline void inline_method() {}
+  void volatile_method() volatile {}
+  void const_method() const {}
 
   public:
 };
 #else
-T t;
+T *t;
 // expected-error@second.h:* {{'AllDecls::T' has different definitions in 
different modules; first difference is definition in module 'SecondModule' 
found public access specifier}}
 // expected-note@first.h:* {{but in 'FirstModule' found private access 
specifier}}
 #endif


_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to