r301989 - [ODRHash] Add support for array and decayed types, and parameter names and types.

Richard Trieu via cfe-commits cfe-commits at lists.llvm.org
Tue May 2 16:58:52 PDT 2017


Author: rtrieu
Date: Tue May  2 18:58:52 2017
New Revision: 301989

URL: http://llvm.org/viewvc/llvm-project?rev=301989&view=rev
Log:
[ODRHash] Add support for array and decayed types, and parameter names and types.

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=301989&r1=301988&r2=301989&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td Tue May  2 18:58:52 2017
@@ -146,7 +146,10 @@ def err_module_odr_violation_mismatch_de
   "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">;
+  "method %4 is %select{not inline|inline}5|"
+  "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}3">;
 
 def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
   "%select{"
@@ -166,7 +169,10 @@ def note_module_odr_violation_mismatch_d
   "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">;
+  "method %2 is %select{not inline|inline}3|"
+  "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}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=301989&r1=301988&r2=301989&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ODRHash.cpp (original)
+++ cfe/trunk/lib/AST/ODRHash.cpp Tue May  2 18:58:52 2017
@@ -169,6 +169,11 @@ public:
     Inherited::VisitValueDecl(D);
   }
 
+  void VisitParmVarDecl(const ParmVarDecl *D) {
+    // TODO: Handle default arguments.
+    Inherited::VisitParmVarDecl(D);
+  }
+
   void VisitAccessSpecDecl(const AccessSpecDecl *D) {
     ID.AddInteger(D->getAccess());
     Inherited::VisitAccessSpecDecl(D);
@@ -202,6 +207,12 @@ public:
     Hash.AddBoolean(D->isPure());
     Hash.AddBoolean(D->isDeletedAsWritten());
 
+    ID.AddInteger(D->param_size());
+
+    for (auto *Param : D->parameters()) {
+      Hash.AddSubDecl(Param);
+    }
+
     Inherited::VisitFunctionDecl(D);
   }
 
@@ -256,6 +267,11 @@ void ODRHash::AddSubDecl(const Decl *D)
 void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
   assert(Record && Record->hasDefinition() &&
          "Expected non-null record to be a definition.");
+
+  if (isa<ClassTemplateSpecializationDecl>(Record)) {
+    return;
+  }
+
   AddDecl(Record);
 
   // Filter out sub-Decls which will not be processed in order to get an
@@ -315,6 +331,14 @@ public:
     }
   }
 
+  void AddQualType(QualType T) {
+    Hash.AddQualType(T);
+  }
+
+  void VisitQualifiers(Qualifiers Quals) {
+    ID.AddInteger(Quals.getAsOpaqueValue());
+  }
+
   void Visit(const Type *T) {
     ID.AddInteger(T->getTypeClass());
     Inherited::Visit(T);
@@ -322,11 +346,69 @@ public:
 
   void VisitType(const Type *T) {}
 
+  void VisitAdjustedType(const AdjustedType *T) {
+    AddQualType(T->getOriginalType());
+    AddQualType(T->getAdjustedType());
+    VisitType(T);
+  }
+
+  void VisitDecayedType(const DecayedType *T) {
+    AddQualType(T->getDecayedType());
+    AddQualType(T->getPointeeType());
+    VisitAdjustedType(T);
+  }
+
+  void VisitArrayType(const ArrayType *T) {
+    AddQualType(T->getElementType());
+    ID.AddInteger(T->getSizeModifier());
+    VisitQualifiers(T->getIndexTypeQualifiers());
+    VisitType(T);
+  }
+  void VisitConstantArrayType(const ConstantArrayType *T) {
+    T->getSize().Profile(ID);
+    VisitArrayType(T);
+  }
+
+  void VisitDependentSizedArrayType(const DependentSizedArrayType *T) {
+    AddStmt(T->getSizeExpr());
+    VisitArrayType(T);
+  }
+
+  void VisitIncompleteArrayType(const IncompleteArrayType *T) {
+    VisitArrayType(T);
+  }
+
+  void VisitVariableArrayType(const VariableArrayType *T) {
+    AddStmt(T->getSizeExpr());
+    VisitArrayType(T);
+  }
+
   void VisitBuiltinType(const BuiltinType *T) {
     ID.AddInteger(T->getKind());
     VisitType(T);
   }
 
+  void VisitFunctionType(const FunctionType *T) {
+    AddQualType(T->getReturnType());
+    T->getExtInfo().Profile(ID);
+    Hash.AddBoolean(T->isConst());
+    Hash.AddBoolean(T->isVolatile());
+    Hash.AddBoolean(T->isRestrict());
+    VisitType(T);
+  }
+
+  void VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
+    VisitFunctionType(T);
+  }
+
+  void VisitFunctionProtoType(const FunctionProtoType *T) {
+    ID.AddInteger(T->getNumParams());
+    for (auto ParamType : T->getParamTypes())
+      AddQualType(ParamType);
+
+    VisitFunctionType(T);
+  }
+
   void VisitTypedefType(const TypedefType *T) {
     AddDecl(T->getDecl());
     Hash.AddQualType(T->getDecl()->getUnderlyingType());

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=301989&r1=301988&r2=301989&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Tue May  2 18:58:52 2017
@@ -9316,6 +9316,9 @@ void ASTReader::diagnoseOdrViolations()
         MethodVolatile,
         MethodConst,
         MethodInline,
+        MethodNumberParameters,
+        MethodParameterType,
+        MethodParameterName,
       };
 
       // These lambdas have the common portions of the ODR diagnostics.  This
@@ -9346,6 +9349,12 @@ void ASTReader::diagnoseOdrViolations()
         return Hash.CalculateHash();
       };
 
+      auto ComputeQualTypeODRHash = [&Hash](QualType Ty) {
+        Hash.clear();
+        Hash.AddQualType(Ty);
+        return Hash.CalculateHash();
+      };
+
       switch (FirstDiffType) {
       case Other:
       case EndOfClass:
@@ -9639,6 +9648,76 @@ void ASTReader::diagnoseOdrViolations()
           Diagnosed = true;
           break;
         }
+
+        const unsigned FirstNumParameters = FirstMethod->param_size();
+        const unsigned SecondNumParameters = SecondMethod->param_size();
+        if (FirstNumParameters != SecondNumParameters) {
+          ODRDiagError(FirstMethod->getLocation(),
+                       FirstMethod->getSourceRange(), MethodNumberParameters)
+              << FirstName << FirstNumParameters;
+          ODRDiagNote(SecondMethod->getLocation(),
+                      SecondMethod->getSourceRange(), MethodNumberParameters)
+              << SecondName << SecondNumParameters;
+          Diagnosed = true;
+          break;
+        }
+
+        // Need this status boolean to know when break out of the switch.
+        bool ParameterMismatch = false;
+        for (unsigned I = 0; I < FirstNumParameters; ++I) {
+          const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
+          const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
+
+          QualType FirstParamType = FirstParam->getType();
+          QualType SecondParamType = SecondParam->getType();
+          if (FirstParamType != SecondParamType &&
+              ComputeQualTypeODRHash(FirstParamType) !=
+                  ComputeQualTypeODRHash(SecondParamType)) {
+            if (const DecayedType *ParamDecayedType =
+                    FirstParamType->getAs<DecayedType>()) {
+              ODRDiagError(FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodParameterType)
+                  << FirstName << (I + 1) << FirstParamType << true
+                  << ParamDecayedType->getOriginalType();
+            } else {
+              ODRDiagError(FirstMethod->getLocation(),
+                           FirstMethod->getSourceRange(), MethodParameterType)
+                  << FirstName << (I + 1) << FirstParamType << false;
+            }
+
+            if (const DecayedType *ParamDecayedType =
+                    SecondParamType->getAs<DecayedType>()) {
+              ODRDiagNote(SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodParameterType)
+                  << SecondName << (I + 1) << SecondParamType << true
+                  << ParamDecayedType->getOriginalType();
+            } else {
+              ODRDiagNote(SecondMethod->getLocation(),
+                          SecondMethod->getSourceRange(), MethodParameterType)
+                  << SecondName << (I + 1) << SecondParamType << false;
+            }
+            ParameterMismatch = true;
+            break;
+          }
+
+          DeclarationName FirstParamName = FirstParam->getDeclName();
+          DeclarationName SecondParamName = SecondParam->getDeclName();
+          if (FirstParamName != SecondParamName) {
+            ODRDiagError(FirstMethod->getLocation(),
+                         FirstMethod->getSourceRange(), MethodParameterName)
+                << FirstName << (I + 1) << FirstParamName;
+            ODRDiagNote(SecondMethod->getLocation(),
+                        SecondMethod->getSourceRange(), MethodParameterName)
+                << SecondName << (I + 1) << SecondParamName;
+            ParameterMismatch = true;
+            break;
+          }
+        }
+
+        if (ParameterMismatch) {
+          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=301989&r1=301988&r2=301989&view=diff
==============================================================================
--- cfe/trunk/test/Modules/odr_hash.cpp (original)
+++ cfe/trunk/test/Modules/odr_hash.cpp Tue May  2 18:58:52 2017
@@ -275,6 +275,33 @@ S11 s11;
 // expected-note at first.h:* {{but in 'FirstModule' found field 'x' with a different initializer}}
 #endif
 
+#if defined(FIRST)
+struct S12 {
+  unsigned x[5];
+};
+#elif defined(SECOND)
+struct S12 {
+  unsigned x[7];
+};
+#else
+S12 s12;
+// expected-error at first.h:* {{'Field::S12::x' from module 'FirstModule' is not present in definition of 'Field::S12' in module 'SecondModule'}}
+// expected-note at second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+struct S13 {
+  unsigned x[7];
+};
+#elif defined(SECOND)
+struct S13 {
+  double x[7];
+};
+#else
+S13 s13;
+// expected-error at first.h:* {{'Field::S13::x' from module 'FirstModule' is not present in definition of 'Field::S13' in module 'SecondModule'}}
+// expected-note at second.h:* {{declaration of 'x' does not match}}
+#endif
 }  // namespace Field
 
 namespace Method {
@@ -403,6 +430,91 @@ S8 s8;
 // expected-note at first.h:* {{but in 'FirstModule' found method 'A' is const}}
 #endif
 
+#if defined(FIRST)
+struct S9 {
+  void A(int x) {}
+  void A(int x, int y) {}
+};
+#elif defined(SECOND)
+struct S9 {
+  void A(int x, int y) {}
+  void A(int x) {}
+};
+#else
+S9 s9;
+// expected-error at second.h:* {{'Method::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' that has 2 parameters}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'A' that has 1 parameter}}
+#endif
+
+#if defined(FIRST)
+struct S10 {
+  void A(int x) {}
+  void A(float x) {}
+};
+#elif defined(SECOND)
+struct S10 {
+  void A(float x) {}
+  void A(int x) {}
+};
+#else
+S10 s10;
+// expected-error at second.h:* {{'Method::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter of type 'float'}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter of type 'int'}}
+#endif
+
+#if defined(FIRST)
+struct S11 {
+  void A(int x) {}
+};
+#elif defined(SECOND)
+struct S11 {
+  void A(int y) {}
+};
+#else
+S11 s11;
+// expected-error at second.h:* {{'Method::S11' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter named 'y'}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter named 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S12 {
+  void A(int x) {}
+};
+#elif defined(SECOND)
+struct S12 {
+  void A(int x = 1) {}
+};
+#else
+S12 s12;
+// TODO: This should produce an error.
+#endif
+
+#if defined(FIRST)
+struct S13 {
+  void A(int x = 1 + 0) {}
+};
+#elif defined(SECOND)
+struct S13 {
+  void A(int x = 1) {}
+};
+#else
+S13 s13;
+// TODO: This should produce an error.
+#endif
+
+#if defined(FIRST)
+struct S14 {
+  void A(int x[2]) {}
+};
+#elif defined(SECOND)
+struct S14 {
+  void A(int x[3]) {}
+};
+#else
+S14 s14;
+// expected-error at second.h:* {{'Method::S14' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' with 1st parameter of type 'int *' decayed from 'int [3]'}}
+// expected-note at first.h:* {{but in 'FirstModule' found method 'A' with 1st parameter of type 'int *' decayed from 'int [2]'}}
+#endif
 }  // namespace Method
 
 // Naive parsing of AST can lead to cycles in processing.  Ensure
@@ -526,37 +638,43 @@ S3 s3;
 // 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 {
-#define CREATE_ALL_DECL_STRUCT(NAME, ACCESS) \
-  typedef int INT;                           \
-  struct NAME {                              \
-  public:                                    \
-  private:                                   \
-  protected:                                 \
-    static_assert(1 == 1, "Message");        \
-    static_assert(2 == 2);                   \
-                                             \
-    int x;                                   \
-    double y;                                \
-                                             \
-    INT z;                                   \
-                                             \
-    unsigned a : 1;                          \
-    unsigned b : 2 * 2 + 5 / 2;              \
-                                             \
-    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 {}             \
-                                             \
-    typedef int typedef_int;                 \
-    using using_int = int;                   \
-                                             \
-    ACCESS:                                  \
+#define CREATE_ALL_DECL_STRUCT(NAME, ACCESS)               \
+  typedef int INT;                                         \
+  struct NAME {                                            \
+  public:                                                  \
+  private:                                                 \
+  protected:                                               \
+    static_assert(1 == 1, "Message");                      \
+    static_assert(2 == 2);                                 \
+                                                           \
+    int x;                                                 \
+    double y;                                              \
+                                                           \
+    INT z;                                                 \
+                                                           \
+    unsigned a : 1;                                        \
+    unsigned b : 2 * 2 + 5 / 2;                            \
+                                                           \
+    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 {}                           \
+                                                           \
+    typedef int typedef_int;                               \
+    using using_int = int;                                 \
+                                                           \
+    void method_one_arg(int x) {}                          \
+    void method_one_arg_default_argument(int x = 5 + 5) {} \
+    void method_decayed_type(int x[5]) {}                  \
+                                                           \
+    int constant_arr[5];                                   \
+                                                           \
+    ACCESS:                                                \
   };
 
 #if defined(FIRST)
@@ -933,6 +1051,34 @@ Alpha::Alpha() {}
 #endif
 }
 
+namespace ParameterTest {
+#if defined(FIRST)
+class X {};
+template <typename G>
+class S {
+  public:
+   typedef G Type;
+   static inline G *Foo(const G *a, int * = nullptr);
+};
+
+template<typename G>
+G* S<G>::Foo(const G* aaaa, int*) {}
+#elif defined(SECOND)
+template <typename G>
+class S {
+  public:
+   typedef G Type;
+   static inline G *Foo(const G *a, int * = nullptr);
+};
+
+template<typename G>
+G* S<G>::Foo(const G* asdf, int*) {}
+#else
+S<X> s;
+#endif
+}
+
+
 // Keep macros contained to one file.
 #ifdef FIRST
 #undef FIRST




More information about the cfe-commits mailing list