diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -102,6 +102,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgument &Arg1, const TemplateArgument &Arg2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateArgumentLoc &Arg1, + const TemplateArgumentLoc &Arg2); static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, NestedNameSpecifier *NNS1, NestedNameSpecifier *NNS2); @@ -340,6 +343,30 @@ return true; } + bool IsStmtEquivalent(const OverloadExpr *E1, const OverloadExpr *E2) { + if (!IsStructurallyEquivalent(Context, E1->getName(), E2->getName())) + return false; + + if (static_cast(E1->getQualifier()) != + static_cast(E2->getQualifier())) + return false; + if (E1->getQualifier() && + !IsStructurallyEquivalent(Context, E1->getQualifier(), + E2->getQualifier())) + return false; + + if (E1->getNumTemplateArgs() != E2->getNumTemplateArgs()) + return false; + const TemplateArgumentLoc *Args1 = E1->getTemplateArgs(); + const TemplateArgumentLoc *Args2 = E2->getTemplateArgs(); + for (unsigned int ArgI = 0, ArgN = E1->getNumTemplateArgs(); ArgI < ArgN; + ++ArgI) + if (!IsStructurallyEquivalent(Context, Args1[ArgI], Args2[ArgI])) + return false; + + return true; + } + /// End point of the traversal chain. bool TraverseStmt(const Stmt *S1, const Stmt *S2) { return true; } @@ -599,6 +626,14 @@ return true; } +/// Determine whether two template argument locations are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateArgumentLoc &Arg1, + const TemplateArgumentLoc &Arg2) { + return IsStructurallyEquivalent(Context, Arg1.getArgument(), + Arg2.getArgument()); +} + /// Determine structural equivalence for the common part of array /// types. static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp --- a/clang/unittests/AST/StructuralEquivalenceTest.cpp +++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp @@ -2125,5 +2125,128 @@ EXPECT_FALSE(testStructuralMatch(t)); } +TEST_F(StructuralEquivalenceStmtTest, UnresolvedLookupDifferentName) { + auto t = makeStmts( + R"( + void f1(int); + template + void f(T t) { + f1(t); + } + void g() { f(1); } + )", + R"( + void f2(int); + template + void f(T t) { + f2(t); + } + void g() { f(1); } + )", + Lang_CXX03, unresolvedLookupExpr()); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceStmtTest, UnresolvedLookupDifferentQualifier) { + auto t = makeStmts( + R"( + struct X { + static void g(int); + static void g(char); + }; + + template + void f(T t) { + X::g(t); + } + + void g() { f(1); } + )", + R"( + struct Y { + static void g(int); + static void g(char); + }; + + template + void f(T t) { + Y::g(t); + } + + void g() { f(1); } + )", + Lang_CXX03, unresolvedLookupExpr()); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceStmtTest, + UnresolvedLookupDifferentTemplateArgument) { + auto t = makeStmts( + R"( + struct A {}; + template + void g() {} + + template + void f() { + g(); + } + + void h() { f(); } + )", + R"( + struct B {}; + template + void g() {} + + template + void f() { + g(); + } + + void h() { f(); } + )", + Lang_CXX03, unresolvedLookupExpr()); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceStmtTest, UnresolvedLookup) { + auto t = makeStmts( + R"( + struct A {}; + struct B { + template + static void g(int) {}; + template + static void g(char) {}; + }; + + template + void f(T2 x) { + B::g(x); + } + + void g() { f(1); } + )", + R"( + struct A {}; + struct B { + template + static void g(int) {}; + template + static void g(char) {}; + }; + + template + void f(T2 x) { + B::g(x); + } + + void g() { f(1); } + )", + Lang_CXX03, unresolvedLookupExpr()); + EXPECT_TRUE(testStructuralMatch(t)); +} + } // end namespace ast_matchers } // end namespace clang