diff options
-rw-r--r-- | clang/lib/AST/ODRHash.cpp | 45 | ||||
-rw-r--r-- | clang/test/Modules/odr_hash.cpp | 63 |
2 files changed, 107 insertions, 1 deletions
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index ba3b2ee49c5..e47154088d9 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -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); } diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp index f22a8b8f8a0..ff7cfb3ae7f 100644 --- a/clang/test/Modules/odr_hash.cpp +++ b/clang/test/Modules/odr_hash.cpp @@ -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 |