Index: lib/AST/ASTStructuralEquivalence.cpp =================================================================== --- lib/AST/ASTStructuralEquivalence.cpp +++ lib/AST/ASTStructuralEquivalence.cpp @@ -955,6 +955,9 @@ if (!D1 || !D2) return true; + if (D1->isTemplated() != D2->isTemplated()) + return false; + if (auto *D1CXX = dyn_cast(D1)) { if (auto *D2CXX = dyn_cast(D2)) { if (D1CXX->hasExternalLexicalStorage() && @@ -962,6 +965,11 @@ D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX); } + if (auto *T1 = D1CXX->getDescribedClassTemplate()) + if (auto *T2 = D2CXX->getDescribedClassTemplate()) + if (!IsStructurallyEquivalent(Context, T1, T2)) + return false; + if (D1CXX->getNumBases() != D2CXX->getNumBases()) { if (Context.Complain) { Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) @@ -1309,6 +1317,14 @@ if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType())) return false; + if (D1->isTemplated() != D2->isTemplated()) + return false; + + if (auto T1 = D1->getDescribedFunctionTemplate()) + if (auto T2 = D2->getDescribedFunctionTemplate()) + if (!IsStructurallyEquivalent(Context, T1, T2)) + return false; + return true; } Index: unittests/AST/StructuralEquivalenceTest.cpp =================================================================== --- unittests/AST/StructuralEquivalenceTest.cpp +++ unittests/AST/StructuralEquivalenceTest.cpp @@ -63,10 +63,18 @@ } bool testStructuralMatch(NamedDecl *D0, NamedDecl *D1) { - llvm::DenseSet> NonEquivalentDecls; - StructuralEquivalenceContext Ctx(D0->getASTContext(), D1->getASTContext(), - NonEquivalentDecls, false, false); - return Ctx.IsStructurallyEquivalent(D0, D1); + llvm::DenseSet> NonEquivalentDecls01; + llvm::DenseSet> NonEquivalentDecls10; + StructuralEquivalenceContext Ctx01( + D0->getASTContext(), D1->getASTContext(), + NonEquivalentDecls01, false, false); + StructuralEquivalenceContext Ctx10( + D1->getASTContext(), D0->getASTContext(), + NonEquivalentDecls10, false, false); + bool Eq01 = Ctx01.IsStructurallyEquivalent(D0, D1); + bool Eq10 = Ctx10.IsStructurallyEquivalent(D1, D0); + EXPECT_EQ(Eq01, Eq10); + return Eq01; } bool testStructuralMatch(std::tuple t) { @@ -199,6 +207,14 @@ struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest { }; +TEST_F(StructuralEquivalenceFunctionTest, TemplateVsNonTemplate) { + auto t = makeNamedDecls( + "void foo();", + "template void foo();", + Lang_CXX); + EXPECT_FALSE(testStructuralMatch(t)); +} + TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) { auto t = makeNamedDecls("void foo(int&);", "void foo(const int&);", Lang_CXX); @@ -534,6 +550,15 @@ EXPECT_TRUE(testStructuralMatch(t)); } +TEST_F(StructuralEquivalenceRecordTest, TemplateVsNonTemplate) { + auto t = makeDecls( + "struct A { };", + "template struct A { };", + Lang_CXX, + cxxRecordDecl(hasName("A"))); + EXPECT_FALSE(testStructuralMatch(t)); +} + TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) { auto t = makeNamedDecls( "struct A{ }; struct B{ }; void foo(A a, A b);",