diff options
author | Balazs Keri <1.int32@gmail.com> | 2018-08-08 15:04:27 +0000 |
---|---|---|
committer | Balazs Keri <1.int32@gmail.com> | 2018-08-08 15:04:27 +0000 |
commit | a0a81b17e0c3b8b472bcb80e04cfcc297c6684a1 (patch) | |
tree | 96b8209d1b99b43db6116d549cf5a17b48bbc91f /clang/lib/AST/ASTStructuralEquivalence.cpp | |
parent | 07224dfb475a95c6e8dd1e931cf8a33213d79f34 (diff) | |
download | bcm5719-llvm-a0a81b17e0c3b8b472bcb80e04cfcc297c6684a1.tar.gz bcm5719-llvm-a0a81b17e0c3b8b472bcb80e04cfcc297c6684a1.zip |
[AST] Check described template at structural equivalence check.
Summary:
When checking a class or function the described class or function template
is checked too.
Split StructuralEquivalenceContext::Finish into multiple functions.
Improved test with symmetric check, added new tests.
Reviewers: martong, a.sidorin, a_sidorin, bruno
Reviewed By: martong, a.sidorin
Subscribers: rnkovacs, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D49223
llvm-svn: 339256
Diffstat (limited to 'clang/lib/AST/ASTStructuralEquivalence.cpp')
-rw-r--r-- | clang/lib/AST/ASTStructuralEquivalence.cpp | 257 |
1 files changed, 138 insertions, 119 deletions
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index df3c2be9a2e..7fc3239b03d 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1023,7 +1023,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; // If any of the records has external storage and we do a minimal check (or - // AST import) we assmue they are equivalent. (If we didn't have this + // AST import) we assume they are equivalent. (If we didn't have this // assumption then `RecordDecl::LoadFieldsFromExternalStorage` could trigger // another AST import which in turn would call the structural equivalency // check again and finally we'd have an improper result.) @@ -1497,6 +1497,141 @@ bool StructuralEquivalenceContext::IsEquivalent(QualType T1, QualType T2) { return !Finish(); } +bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) { + // Check for equivalent described template. + TemplateDecl *Template1 = D1->getDescribedTemplate(); + TemplateDecl *Template2 = D2->getDescribedTemplate(); + if ((Template1 != nullptr) != (Template2 != nullptr)) + return false; + if (Template1 && !IsStructurallyEquivalent(*this, Template1, Template2)) + return false; + + // FIXME: Move check for identifier names into this function. + + return true; +} + +bool StructuralEquivalenceContext::CheckKindSpecificEquivalence( + Decl *D1, Decl *D2) { + // FIXME: Switch on all declaration kinds. For now, we're just going to + // check the obvious ones. + if (auto *Record1 = dyn_cast<RecordDecl>(D1)) { + if (auto *Record2 = dyn_cast<RecordDecl>(D2)) { + // Check for equivalent structure names. + IdentifierInfo *Name1 = Record1->getIdentifier(); + if (!Name1 && Record1->getTypedefNameForAnonDecl()) + Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Record2->getIdentifier(); + if (!Name2 && Record2->getTypedefNameForAnonDecl()) + Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Record1, Record2)) + return false; + } else { + // Record/non-record mismatch. + return false; + } + } else if (auto *Enum1 = dyn_cast<EnumDecl>(D1)) { + if (auto *Enum2 = dyn_cast<EnumDecl>(D2)) { + // Check for equivalent enum names. + IdentifierInfo *Name1 = Enum1->getIdentifier(); + if (!Name1 && Enum1->getTypedefNameForAnonDecl()) + Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Enum2->getIdentifier(); + if (!Name2 && Enum2->getTypedefNameForAnonDecl()) + Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Enum1, Enum2)) + return false; + } else { + // Enum/non-enum mismatch + return false; + } + } else if (const auto *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) { + if (const auto *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) { + if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(), + Typedef2->getIdentifier()) || + !::IsStructurallyEquivalent(*this, Typedef1->getUnderlyingType(), + Typedef2->getUnderlyingType())) + return false; + } else { + // Typedef/non-typedef mismatch. + return false; + } + } else if (auto *ClassTemplate1 = dyn_cast<ClassTemplateDecl>(D1)) { + if (auto *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, ClassTemplate1, + ClassTemplate2)) + return false; + } else { + // Class template/non-class-template mismatch. + return false; + } + } else if (auto *FunctionTemplate1 = dyn_cast<FunctionTemplateDecl>(D1)) { + if (auto *FunctionTemplate2 = dyn_cast<FunctionTemplateDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, FunctionTemplate1, + FunctionTemplate2)) + return false; + } else { + // Class template/non-class-template mismatch. + return false; + } + } else if (auto *TTP1 = dyn_cast<TemplateTypeParmDecl>(D1)) { + if (auto *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) + return false; + } else { + // Kind mismatch. + return false; + } + } else if (auto *NTTP1 = dyn_cast<NonTypeTemplateParmDecl>(D1)) { + if (auto *NTTP2 = dyn_cast<NonTypeTemplateParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2)) + return false; + } else { + // Kind mismatch. + return false; + } + } else if (auto *TTP1 = dyn_cast<TemplateTemplateParmDecl>(D1)) { + if (auto *TTP2 = dyn_cast<TemplateTemplateParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) + return false; + } else { + // Kind mismatch. + return false; + } + } else if (auto *MD1 = dyn_cast<CXXMethodDecl>(D1)) { + if (auto *MD2 = dyn_cast<CXXMethodDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, MD1, MD2)) + return false; + } else { + // Kind mismatch. + return false; + } + } else if (FunctionDecl *FD1 = dyn_cast<FunctionDecl>(D1)) { + if (FunctionDecl *FD2 = dyn_cast<FunctionDecl>(D2)) { + if (!::IsStructurallyEquivalent(FD1->getIdentifier(), + FD2->getIdentifier())) + return false; + if (!::IsStructurallyEquivalent(*this, FD1, FD2)) + return false; + } else { + // Kind mismatch. + return false; + } + } else if (FriendDecl *FrD1 = dyn_cast<FriendDecl>(D1)) { + if (FriendDecl *FrD2 = dyn_cast<FriendDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, FrD1, FrD2)) + return false; + } else { + // Kind mismatch. + return false; + } + } + + return true; +} + bool StructuralEquivalenceContext::Finish() { while (!DeclsToCheck.empty()) { // Check the next declaration. @@ -1506,123 +1641,8 @@ bool StructuralEquivalenceContext::Finish() { Decl *D2 = TentativeEquivalences[D1]; assert(D2 && "Unrecorded tentative equivalence?"); - bool Equivalent = true; - - // FIXME: Switch on all declaration kinds. For now, we're just going to - // check the obvious ones. - if (auto *Record1 = dyn_cast<RecordDecl>(D1)) { - if (auto *Record2 = dyn_cast<RecordDecl>(D2)) { - // Check for equivalent structure names. - IdentifierInfo *Name1 = Record1->getIdentifier(); - if (!Name1 && Record1->getTypedefNameForAnonDecl()) - Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier(); - IdentifierInfo *Name2 = Record2->getIdentifier(); - if (!Name2 && Record2->getTypedefNameForAnonDecl()) - Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier(); - if (!::IsStructurallyEquivalent(Name1, Name2) || - !::IsStructurallyEquivalent(*this, Record1, Record2)) - Equivalent = false; - } else { - // Record/non-record mismatch. - Equivalent = false; - } - } else if (auto *Enum1 = dyn_cast<EnumDecl>(D1)) { - if (auto *Enum2 = dyn_cast<EnumDecl>(D2)) { - // Check for equivalent enum names. - IdentifierInfo *Name1 = Enum1->getIdentifier(); - if (!Name1 && Enum1->getTypedefNameForAnonDecl()) - Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier(); - IdentifierInfo *Name2 = Enum2->getIdentifier(); - if (!Name2 && Enum2->getTypedefNameForAnonDecl()) - Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier(); - if (!::IsStructurallyEquivalent(Name1, Name2) || - !::IsStructurallyEquivalent(*this, Enum1, Enum2)) - Equivalent = false; - } else { - // Enum/non-enum mismatch - Equivalent = false; - } - } else if (const auto *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) { - if (const auto *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) { - if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(), - Typedef2->getIdentifier()) || - !::IsStructurallyEquivalent(*this, Typedef1->getUnderlyingType(), - Typedef2->getUnderlyingType())) - Equivalent = false; - } else { - // Typedef/non-typedef mismatch. - Equivalent = false; - } - } else if (auto *ClassTemplate1 = dyn_cast<ClassTemplateDecl>(D1)) { - if (auto *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) { - if (!::IsStructurallyEquivalent(*this, ClassTemplate1, - ClassTemplate2)) - Equivalent = false; - } else { - // Class template/non-class-template mismatch. - Equivalent = false; - } - } else if (auto *FunctionTemplate1 = dyn_cast<FunctionTemplateDecl>(D1)) { - if (auto *FunctionTemplate2 = dyn_cast<FunctionTemplateDecl>(D2)) { - if (!::IsStructurallyEquivalent(*this, FunctionTemplate1, - FunctionTemplate2)) - Equivalent = false; - } else { - // Class template/non-class-template mismatch. - Equivalent = false; - } - } else if (auto *TTP1 = dyn_cast<TemplateTypeParmDecl>(D1)) { - if (auto *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) { - if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } else if (auto *NTTP1 = dyn_cast<NonTypeTemplateParmDecl>(D1)) { - if (auto *NTTP2 = dyn_cast<NonTypeTemplateParmDecl>(D2)) { - if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } else if (auto *TTP1 = dyn_cast<TemplateTemplateParmDecl>(D1)) { - if (auto *TTP2 = dyn_cast<TemplateTemplateParmDecl>(D2)) { - if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } else if (auto *MD1 = dyn_cast<CXXMethodDecl>(D1)) { - if (auto *MD2 = dyn_cast<CXXMethodDecl>(D2)) { - if (!::IsStructurallyEquivalent(*this, MD1, MD2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } else if (FunctionDecl *FD1 = dyn_cast<FunctionDecl>(D1)) { - if (FunctionDecl *FD2 = dyn_cast<FunctionDecl>(D2)) { - if (!::IsStructurallyEquivalent(FD1->getIdentifier(), - FD2->getIdentifier())) - Equivalent = false; - if (!::IsStructurallyEquivalent(*this, FD1, FD2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } else if (FriendDecl *FrD1 = dyn_cast<FriendDecl>(D1)) { - if (FriendDecl *FrD2 = dyn_cast<FriendDecl>(D2)) { - if (!::IsStructurallyEquivalent(*this, FrD1, FrD2)) - Equivalent = false; - } else { - // Kind mismatch. - Equivalent = false; - } - } + bool Equivalent = + CheckCommonEquivalence(D1, D2) && CheckKindSpecificEquivalence(D1, D2); if (!Equivalent) { // Note that these two declarations are not equivalent (and we already @@ -1631,7 +1651,6 @@ bool StructuralEquivalenceContext::Finish() { std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl())); return true; } - // FIXME: Check other declaration kinds! } return false; |