r339256 - [AST] Check described template at structural equivalence check.
Balazs Keri via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 8 08:04:28 PDT 2018
Author: balazske
Date: Wed Aug 8 08:04:27 2018
New Revision: 339256
URL: http://llvm.org/viewvc/llvm-project?rev=339256&view=rev
Log:
[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
Modified:
cfe/trunk/include/clang/AST/ASTStructuralEquivalence.h
cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp
cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp
Modified: cfe/trunk/include/clang/AST/ASTStructuralEquivalence.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTStructuralEquivalence.h?rev=339256&r1=339255&r2=339256&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTStructuralEquivalence.h (original)
+++ cfe/trunk/include/clang/AST/ASTStructuralEquivalence.h Wed Aug 8 08:04:27 2018
@@ -114,8 +114,19 @@ struct StructuralEquivalenceContext {
private:
/// Finish checking all of the structural equivalences.
///
- /// \returns true if an error occurred, false otherwise.
+ /// \returns true if the equivalence check failed (non-equivalence detected),
+ /// false if equivalence was detected.
bool Finish();
+
+ /// Check for common properties at Finish.
+ /// \returns true if D1 and D2 may be equivalent,
+ /// false if they are for sure not.
+ bool CheckCommonEquivalence(Decl *D1, Decl *D2);
+
+ /// Check for class dependent properties at Finish.
+ /// \returns true if D1 and D2 may be equivalent,
+ /// false if they are for sure not.
+ bool CheckKindSpecificEquivalence(Decl *D1, Decl *D2);
};
} // namespace clang
Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=339256&r1=339255&r2=339256&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp (original)
+++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp Wed Aug 8 08:04:27 2018
@@ -1023,7 +1023,7 @@ static bool IsStructurallyEquivalent(Str
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::IsEqu
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::Finis
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::Finis
std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl()));
return true;
}
- // FIXME: Check other declaration kinds!
}
return false;
Modified: cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp?rev=339256&r1=339255&r2=339256&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp (original)
+++ cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp Wed Aug 8 08:04:27 2018
@@ -78,11 +78,18 @@ struct StructuralEquivalenceTest : ::tes
}
bool testStructuralMatch(Decl *D0, Decl *D1) {
- llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;
- StructuralEquivalenceContext Ctx(
- D0->getASTContext(), D1->getASTContext(), NonEquivalentDecls,
- StructuralEquivalenceKind::Default, false, false);
- return Ctx.IsEquivalent(D0, D1);
+ llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls01;
+ llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls10;
+ StructuralEquivalenceContext Ctx01(
+ D0->getASTContext(), D1->getASTContext(),
+ NonEquivalentDecls01, StructuralEquivalenceKind::Default, false, false);
+ StructuralEquivalenceContext Ctx10(
+ D1->getASTContext(), D0->getASTContext(),
+ NonEquivalentDecls10, StructuralEquivalenceKind::Default, false, false);
+ bool Eq01 = Ctx01.IsEquivalent(D0, D1);
+ bool Eq10 = Ctx10.IsEquivalent(D1, D0);
+ EXPECT_EQ(Eq01, Eq10);
+ return Eq01;
}
bool testStructuralMatch(std::tuple<Decl *, Decl *> t) {
@@ -215,6 +222,14 @@ TEST_F(StructuralEquivalenceTest, WrongO
struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest {
};
+TEST_F(StructuralEquivalenceFunctionTest, TemplateVsNonTemplate) {
+ auto t = makeNamedDecls(
+ "void foo();",
+ "template<class T> void foo();",
+ Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {
auto t = makeNamedDecls("void foo(int&);",
"void foo(const int&);", Lang_CXX);
@@ -618,6 +633,14 @@ TEST_F(StructuralEquivalenceRecordTest,
EXPECT_FALSE(testStructuralMatch(R0, R1));
}
+TEST_F(StructuralEquivalenceRecordTest, TemplateVsNonTemplate) {
+ auto t = makeDecls<CXXRecordDecl>(
+ "struct A { };",
+ "template<class T> struct A { };",
+ Lang_CXX,
+ cxxRecordDecl(hasName("A")));
+ EXPECT_FALSE(testStructuralMatch(t));
+}
TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
auto t = makeNamedDecls(
More information about the cfe-commits
mailing list