-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][AST] Add 'IgnoreTemplateParmDepth' to structural equivalence cache #115518
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -39,6 +39,10 @@ enum class StructuralEquivalenceKind { | |||||||
}; | ||||||||
|
||||||||
struct StructuralEquivalenceContext { | ||||||||
/// Store declaration pairs already found to be non-equivalent. | ||||||||
/// key: (from, to, IgnoreTemplateParmDepth) | ||||||||
using NonEquivalentDeclSet = llvm::DenseSet<std::tuple<Decl *, Decl *, int>>; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
As above. |
||||||||
|
||||||||
/// AST contexts for which we are checking structural equivalence. | ||||||||
ASTContext &FromCtx, &ToCtx; | ||||||||
|
||||||||
|
@@ -52,7 +56,7 @@ struct StructuralEquivalenceContext { | |||||||
|
||||||||
/// Declaration (from, to) pairs that are known not to be equivalent | ||||||||
/// (which we have already complained about). | ||||||||
llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls; | ||||||||
NonEquivalentDeclSet &NonEquivalentDecls; | ||||||||
|
||||||||
StructuralEquivalenceKind EqKind; | ||||||||
|
||||||||
|
@@ -72,12 +76,13 @@ struct StructuralEquivalenceContext { | |||||||
/// Whether to ignore comparing the depth of template param(TemplateTypeParm) | ||||||||
bool IgnoreTemplateParmDepth; | ||||||||
|
||||||||
StructuralEquivalenceContext( | ||||||||
ASTContext &FromCtx, ASTContext &ToCtx, | ||||||||
llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls, | ||||||||
StructuralEquivalenceKind EqKind, bool StrictTypeSpelling = false, | ||||||||
bool Complain = true, bool ErrorOnTagTypeMismatch = false, | ||||||||
bool IgnoreTemplateParmDepth = false) | ||||||||
StructuralEquivalenceContext(ASTContext &FromCtx, ASTContext &ToCtx, | ||||||||
NonEquivalentDeclSet &NonEquivalentDecls, | ||||||||
StructuralEquivalenceKind EqKind, | ||||||||
bool StrictTypeSpelling = false, | ||||||||
bool Complain = true, | ||||||||
bool ErrorOnTagTypeMismatch = false, | ||||||||
bool IgnoreTemplateParmDepth = false) | ||||||||
: FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls), | ||||||||
EqKind(EqKind), StrictTypeSpelling(StrictTypeSpelling), | ||||||||
ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain), | ||||||||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -2303,7 +2303,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, | |||||||
|
||||||||
// Check whether we already know that these two declarations are not | ||||||||
// structurally equivalent. | ||||||||
if (Context.NonEquivalentDecls.count(P)) | ||||||||
if (Context.NonEquivalentDecls.count( | ||||||||
std::make_tuple(D1, D2, Context.IgnoreTemplateParmDepth))) | ||||||||
Comment on lines
+2306
to
+2307
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
You can use a boolean value for indexing to select the right element in the array. |
||||||||
return false; | ||||||||
|
||||||||
// Check if a check for these declarations is already pending. | ||||||||
|
@@ -2511,7 +2512,8 @@ bool StructuralEquivalenceContext::Finish() { | |||||||
if (!Equivalent) { | ||||||||
// Note that these two declarations are not equivalent (and we already | ||||||||
// know about it). | ||||||||
NonEquivalentDecls.insert(P); | ||||||||
NonEquivalentDecls.insert( | ||||||||
std::make_tuple(D1, D2, IgnoreTemplateParmDepth)); | ||||||||
Comment on lines
+2515
to
+2516
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
return true; | ||||||||
} | ||||||||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -134,8 +134,8 @@ struct StructuralEquivalenceTest : ::testing::Test { | |||||||
|
||||||||
bool testStructuralMatch(Decl *D0, Decl *D1, | ||||||||
bool IgnoreTemplateParmDepth = false) { | ||||||||
llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls01; | ||||||||
llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls10; | ||||||||
StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls01; | ||||||||
StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls10; | ||||||||
StructuralEquivalenceContext Ctx01( | ||||||||
D0->getASTContext(), D1->getASTContext(), NonEquivalentDecls01, | ||||||||
StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, | ||||||||
|
@@ -153,8 +153,8 @@ struct StructuralEquivalenceTest : ::testing::Test { | |||||||
} | ||||||||
|
||||||||
bool testStructuralMatch(StmtWithASTContext S0, StmtWithASTContext S1) { | ||||||||
llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls01; | ||||||||
llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls10; | ||||||||
StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls01; | ||||||||
StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls10; | ||||||||
StructuralEquivalenceContext Ctx01( | ||||||||
*S0.Context, *S1.Context, NonEquivalentDecls01, | ||||||||
StructuralEquivalenceKind::Default, false, false); | ||||||||
|
@@ -1792,7 +1792,7 @@ TEST_F( | |||||||
EXPECT_FALSE(testStructuralMatch(t)); | ||||||||
} | ||||||||
struct StructuralEquivalenceCacheTest : public StructuralEquivalenceTest { | ||||||||
llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls; | ||||||||
StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls; | ||||||||
|
||||||||
template <typename NodeType, typename MatcherType> | ||||||||
std::pair<NodeType *, NodeType *> | ||||||||
|
@@ -1804,8 +1804,10 @@ struct StructuralEquivalenceCacheTest : public StructuralEquivalenceTest { | |||||||
} | ||||||||
|
||||||||
template <typename NodeType> | ||||||||
bool isInNonEqCache(std::pair<NodeType *, NodeType *> D) { | ||||||||
return NonEquivalentDecls.count(D) > 0; | ||||||||
bool isInNonEqCache(std::pair<NodeType *, NodeType *> D, | ||||||||
bool IgnoreTemplateParmDepth = false) { | ||||||||
return NonEquivalentDecls.count( | ||||||||
std::make_tuple(D.first, D.second, IgnoreTemplateParmDepth)) > 0; | ||||||||
Comment on lines
+1809
to
+1810
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
} | ||||||||
}; | ||||||||
|
||||||||
|
@@ -2015,6 +2017,78 @@ TEST_F(StructuralEquivalenceCacheTest, Cycle) { | |||||||
findDeclPair<FunctionDecl>(TU, functionDecl(hasName("x"))))); | ||||||||
} | ||||||||
|
||||||||
TEST_F(StructuralEquivalenceCacheTest, TemplateParmDepth) { | ||||||||
// In 'friend struct Y' ClassTemplateDecl has the TU as parent context. | ||||||||
// This declaration has template depth 1 (it is already inside a template). | ||||||||
// It has not a previous declaration and is an "undeclared" friend. | ||||||||
// | ||||||||
// Second TU has a specialization of 'struct X'. | ||||||||
// In this case 'friend struct Y' has the ClassTemplateSpecializationDecl as | ||||||||
// parent. It has template depth 0 (it is in the specialization). It has the | ||||||||
// first 'struct Y' declaration as previous declaration and canonical | ||||||||
// declaration. | ||||||||
// | ||||||||
// When these two 'friend struct Y' are compared, only the template depth is | ||||||||
// different. | ||||||||
// FIXME: Structural equivalence checks the depth only in types, not in | ||||||||
// TemplateParmDecl. For this reason the second 'A1' argument is needed (as a | ||||||||
// type) in the template to make the check fail. | ||||||||
auto TU = makeTuDecls( | ||||||||
R"( | ||||||||
template <class A1, A1> | ||||||||
struct Y; | ||||||||
|
||||||||
template <class A> | ||||||||
struct X { | ||||||||
template <class A1, A1> | ||||||||
friend struct Y; | ||||||||
}; | ||||||||
)", | ||||||||
R"( | ||||||||
template <class A1, A1> | ||||||||
struct Y; | ||||||||
|
||||||||
template <class A> | ||||||||
struct X { | ||||||||
template <class A1, A1> | ||||||||
friend struct Y; | ||||||||
}; | ||||||||
|
||||||||
X<int> x; | ||||||||
)", | ||||||||
Lang_CXX03); | ||||||||
|
||||||||
auto *D0 = LastDeclMatcher<ClassTemplateDecl>().match( | ||||||||
get<0>(TU), classTemplateDecl(hasName("Y"), unless(isImplicit()))); | ||||||||
auto *D1 = LastDeclMatcher<ClassTemplateDecl>().match( | ||||||||
get<1>(TU), classTemplateDecl(hasName("Y"), unless(isImplicit()))); | ||||||||
ASSERT_EQ(D0->getTemplateDepth(), 1u); | ||||||||
ASSERT_EQ(D1->getTemplateDepth(), 0u); | ||||||||
|
||||||||
StructuralEquivalenceContext Ctx_NoIgnoreTemplateParmDepth( | ||||||||
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), | ||||||||
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false, | ||||||||
false, false); | ||||||||
|
||||||||
EXPECT_FALSE(Ctx_NoIgnoreTemplateParmDepth.IsEquivalent(D0, D1)); | ||||||||
|
||||||||
Decl *NonEqDecl0 = | ||||||||
D0->getCanonicalDecl()->getTemplateParameters()->getParam(1); | ||||||||
Decl *NonEqDecl1 = | ||||||||
D1->getCanonicalDecl()->getTemplateParameters()->getParam(1); | ||||||||
EXPECT_TRUE(isInNonEqCache(std::make_pair(NonEqDecl0, NonEqDecl1), false)); | ||||||||
EXPECT_FALSE(isInNonEqCache(std::make_pair(NonEqDecl0, NonEqDecl1), true)); | ||||||||
|
||||||||
StructuralEquivalenceContext Ctx_IgnoreTemplateParmDepth( | ||||||||
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), | ||||||||
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false, | ||||||||
false, true); | ||||||||
|
||||||||
EXPECT_TRUE(Ctx_IgnoreTemplateParmDepth.IsEquivalent(D0, D1)); | ||||||||
|
||||||||
EXPECT_FALSE(isInNonEqCache(std::make_pair(NonEqDecl0, NonEqDecl1), true)); | ||||||||
} | ||||||||
|
||||||||
struct StructuralEquivalenceStmtTest : StructuralEquivalenceTest {}; | ||||||||
|
||||||||
/// Fallback matcher to be used only when there is no specific matcher for a | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you use two
DenseSet
s and put them into an array, you can use them without significant code changes.