@@ -134,8 +134,8 @@ struct StructuralEquivalenceTest : ::testing::Test {
134134
135135 bool testStructuralMatch (Decl *D0, Decl *D1,
136136 bool IgnoreTemplateParmDepth = false ) {
137- llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls01;
138- llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls10;
137+ StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls01;
138+ StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls10;
139139 StructuralEquivalenceContext Ctx01 (
140140 D0->getASTContext (), D1->getASTContext (), NonEquivalentDecls01,
141141 StructuralEquivalenceKind::Default, /* StrictTypeSpelling=*/ false ,
@@ -153,8 +153,8 @@ struct StructuralEquivalenceTest : ::testing::Test {
153153 }
154154
155155 bool testStructuralMatch (StmtWithASTContext S0, StmtWithASTContext S1) {
156- llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls01;
157- llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls10;
156+ StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls01;
157+ StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls10;
158158 StructuralEquivalenceContext Ctx01 (
159159 *S0.Context , *S1.Context , NonEquivalentDecls01,
160160 StructuralEquivalenceKind::Default, false , false );
@@ -1792,7 +1792,7 @@ TEST_F(
17921792 EXPECT_FALSE (testStructuralMatch (t));
17931793}
17941794struct StructuralEquivalenceCacheTest : public StructuralEquivalenceTest {
1795- llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;
1795+ StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls;
17961796
17971797 template <typename NodeType, typename MatcherType>
17981798 std::pair<NodeType *, NodeType *>
@@ -1804,8 +1804,10 @@ struct StructuralEquivalenceCacheTest : public StructuralEquivalenceTest {
18041804 }
18051805
18061806 template <typename NodeType>
1807- bool isInNonEqCache (std::pair<NodeType *, NodeType *> D) {
1808- return NonEquivalentDecls.count (D) > 0 ;
1807+ bool isInNonEqCache (std::pair<NodeType *, NodeType *> D,
1808+ bool IgnoreTemplateParmDepth = false ) {
1809+ return NonEquivalentDecls.count (
1810+ std::make_tuple (D.first , D.second , IgnoreTemplateParmDepth)) > 0 ;
18091811 }
18101812};
18111813
@@ -2015,6 +2017,78 @@ TEST_F(StructuralEquivalenceCacheTest, Cycle) {
20152017 findDeclPair<FunctionDecl>(TU, functionDecl (hasName (" x" )))));
20162018}
20172019
2020+ TEST_F (StructuralEquivalenceCacheTest, TemplateParmDepth) {
2021+ // In 'friend struct Y' ClassTemplateDecl has the TU as parent context.
2022+ // This declaration has template depth 1 (it is already inside a template).
2023+ // It has not a previous declaration and is an "undeclared" friend.
2024+ //
2025+ // Second TU has a specialization of 'struct X'.
2026+ // In this case 'friend struct Y' has the ClassTemplateSpecializationDecl as
2027+ // parent. It has template depth 0 (it is in the specialization). It has the
2028+ // first 'struct Y' declaration as previous declaration and canonical
2029+ // declaration.
2030+ //
2031+ // When these two 'friend struct Y' are compared, only the template depth is
2032+ // different.
2033+ // FIXME: Structural equivalence checks the depth only in types, not in
2034+ // TemplateParmDecl. For this reason the second 'A1' argument is needed (as a
2035+ // type) in the template to make the check fail.
2036+ auto TU = makeTuDecls (
2037+ R"(
2038+ template <class A1, A1>
2039+ struct Y;
2040+
2041+ template <class A>
2042+ struct X {
2043+ template <class A1, A1>
2044+ friend struct Y;
2045+ };
2046+ )" ,
2047+ R"(
2048+ template <class A1, A1>
2049+ struct Y;
2050+
2051+ template <class A>
2052+ struct X {
2053+ template <class A1, A1>
2054+ friend struct Y;
2055+ };
2056+
2057+ X<int> x;
2058+ )" ,
2059+ Lang_CXX03);
2060+
2061+ auto *D0 = LastDeclMatcher<ClassTemplateDecl>().match (
2062+ get<0 >(TU), classTemplateDecl (hasName (" Y" ), unless (isImplicit ())));
2063+ auto *D1 = LastDeclMatcher<ClassTemplateDecl>().match (
2064+ get<1 >(TU), classTemplateDecl (hasName (" Y" ), unless (isImplicit ())));
2065+ ASSERT_EQ (D0->getTemplateDepth (), 1u );
2066+ ASSERT_EQ (D1->getTemplateDepth (), 0u );
2067+
2068+ StructuralEquivalenceContext Ctx_NoIgnoreTemplateParmDepth (
2069+ get<0 >(TU)->getASTContext (), get<1 >(TU)->getASTContext (),
2070+ NonEquivalentDecls, StructuralEquivalenceKind::Default, false , false ,
2071+ false , false );
2072+
2073+ EXPECT_FALSE (Ctx_NoIgnoreTemplateParmDepth.IsEquivalent (D0, D1));
2074+
2075+ Decl *NonEqDecl0 =
2076+ D0->getCanonicalDecl ()->getTemplateParameters ()->getParam (1 );
2077+ Decl *NonEqDecl1 =
2078+ D1->getCanonicalDecl ()->getTemplateParameters ()->getParam (1 );
2079+ EXPECT_TRUE (isInNonEqCache (std::make_pair (NonEqDecl0, NonEqDecl1), false ));
2080+ EXPECT_FALSE (isInNonEqCache (std::make_pair (NonEqDecl0, NonEqDecl1), true ));
2081+
2082+ StructuralEquivalenceContext Ctx_IgnoreTemplateParmDepth (
2083+ get<0 >(TU)->getASTContext (), get<1 >(TU)->getASTContext (),
2084+ NonEquivalentDecls, StructuralEquivalenceKind::Default, false , false ,
2085+ false , true );
2086+
2087+ EXPECT_TRUE (Ctx_IgnoreTemplateParmDepth.IsEquivalent (D0, D1));
2088+
2089+ EXPECT_FALSE (isInNonEqCache (std::make_pair (NonEqDecl0, NonEqDecl1), true ));
2090+ }
2091+
20182092struct StructuralEquivalenceStmtTest : StructuralEquivalenceTest {};
20192093
20202094// / Fallback matcher to be used only when there is no specific matcher for a
0 commit comments