]> granicus.if.org Git - clang/commitdiff
[ODRHash] Skip some typedef types.
authorRichard Trieu <rtrieu@google.com>
Sat, 22 Jun 2019 00:32:19 +0000 (00:32 +0000)
committerRichard Trieu <rtrieu@google.com>
Sat, 22 Jun 2019 00:32:19 +0000 (00:32 +0000)
In some cases, a typedef only strips aways a keyword for a type, keeping the
same name as the root record type.  This causes some confusion when the type
is defined in one modules but only forward declared in another.  Skipping the
typedef and going straight to the record will avoid this issue.

typedef struct S {} S;
S* s;  // S is TypedefType here

struct S;
S* s;  // S is RecordType here

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@364119 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ODRHash.cpp
test/Modules/odr_hash.cpp

index ba3b2ee49c54905fa56c4e9e2266bb8ad9375997..e47154088d9f99e89e558be78c71e49863374c19 100644 (file)
@@ -696,7 +696,52 @@ public:
     ID.AddInteger(Quals.getAsOpaqueValue());
   }
 
+  // Return the RecordType if the typedef only strips away a keyword.
+  // Otherwise, return the original type.
+  static const Type *RemoveTypedef(const Type *T) {
+    const auto *TypedefT = dyn_cast<TypedefType>(T);
+    if (!TypedefT) {
+      return T;
+    }
+
+    const TypedefNameDecl *D = TypedefT->getDecl();
+    QualType UnderlyingType = D->getUnderlyingType();
+
+    if (UnderlyingType.hasLocalQualifiers()) {
+      return T;
+    }
+
+    const auto *ElaboratedT = dyn_cast<ElaboratedType>(UnderlyingType);
+    if (!ElaboratedT) {
+      return T;
+    }
+
+    if (ElaboratedT->getQualifier() != nullptr) {
+      return T;
+    }
+
+    QualType NamedType = ElaboratedT->getNamedType();
+    if (NamedType.hasLocalQualifiers()) {
+      return T;
+    }
+
+    const auto *RecordT = dyn_cast<RecordType>(NamedType);
+    if (!RecordT) {
+      return T;
+    }
+
+    const IdentifierInfo *TypedefII = TypedefT->getDecl()->getIdentifier();
+    const IdentifierInfo *RecordII = RecordT->getDecl()->getIdentifier();
+    if (!TypedefII || !RecordII ||
+        TypedefII->getName() != RecordII->getName()) {
+      return T;
+    }
+
+    return RecordT;
+  }
+
   void Visit(const Type *T) {
+    T = RemoveTypedef(T);
     ID.AddInteger(T->getTypeClass());
     Inherited::Visit(T);
   }
index f22a8b8f8a01951ebb4a56ec3db77b3cafc25c77..ff7cfb3ae7fdefa9946d3b997171e68fd2450d92 100644 (file)
@@ -4621,9 +4621,70 @@ struct S2 {
 #else
 S2 s2;
 #endif
-
 }
 
+namespace TypedefStruct {
+#if defined(FIRST)
+struct T1;
+class S1 {
+  T1* t;
+};
+#elif defined(SECOND)
+typedef struct T1 {} T1;
+class S1 {
+  T1* t;
+};
+#else
+S1 s1;
+#endif
+
+#if defined(FIRST)
+struct T2;
+class S2 {
+  const T2* t = nullptr;
+};
+#elif defined(SECOND)
+typedef struct T2 {} T2;
+class S2 {
+  const T2* t = nullptr;
+};
+#else
+S2 s2;
+#endif
+
+#if defined(FIRST)
+struct T3;
+class S3 {
+  T3* const t = nullptr;
+};
+#elif defined(SECOND)
+typedef struct T3 {} T3;
+class S3 {
+  T3* const t = nullptr;
+};
+#else
+S3 s3;
+#endif
+
+#if defined(FIRST)
+namespace NS4 {
+struct T4;
+} // namespace NS4
+class S4 {
+  NS4::T4* t = 0;
+};
+#elif defined(SECOND)
+namespace NS4 {
+typedef struct T4 {} T4;
+} // namespace NS4
+class S4 {
+  NS4::T4* t = 0;
+};
+#else
+S4 s4;
+#endif
+} // namespace TypedefStruct
+
 // Keep macros contained to one file.
 #ifdef FIRST
 #undef FIRST