[clang] 07ab514 - [clang][ASTImporter]Skip check depth of friend template parameter
via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 21 22:16:40 PDT 2023
Author: huqizhi
Date: 2023-08-22T13:16:11+08:00
New Revision: 07ab5140080eecdf9f0f6215f70377accb8696f1
URL: https://github.com/llvm/llvm-project/commit/07ab5140080eecdf9f0f6215f70377accb8696f1
DIFF: https://github.com/llvm/llvm-project/commit/07ab5140080eecdf9f0f6215f70377accb8696f1.diff
LOG: [clang][ASTImporter]Skip check depth of friend template parameter
Depth of the parameter of friend template class declaration in a
template class is 1, while in the specialization the depth is 0.
This will cause failure on 'IsStructurallyEquivalent' as a name
conflict in 'VisitClassTemplateDecl'(see testcase of
'SkipComparingFriendTemplateDepth'). The patch fix it by ignore
the depth only in this special case.
Reviewed By: balazske
Differential Revision: https://reviews.llvm.org/D156693
Added:
Modified:
clang/include/clang/AST/ASTStructuralEquivalence.h
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/ASTStructuralEquivalence.cpp
clang/unittests/AST/ASTImporterTest.cpp
clang/unittests/AST/StructuralEquivalenceTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/AST/ASTStructuralEquivalence.h b/clang/include/clang/AST/ASTStructuralEquivalence.h
index 4a79e64fe5d517..029439c8e9a3ac 100644
--- a/clang/include/clang/AST/ASTStructuralEquivalence.h
+++ b/clang/include/clang/AST/ASTStructuralEquivalence.h
@@ -69,15 +69,19 @@ struct StructuralEquivalenceContext {
/// \c true if the last diagnostic came from ToCtx.
bool LastDiagFromC2 = false;
+ /// 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)
+ 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) {}
+ ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain),
+ IgnoreTemplateParmDepth(IgnoreTemplateParmDepth) {}
DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID);
DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 736aac8a646b7a..5ef8b6a5c50ee9 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -508,7 +508,8 @@ namespace clang {
template <typename T>
bool hasSameVisibilityContextAndLinkage(T *Found, T *From);
- bool IsStructuralMatch(Decl *From, Decl *To, bool Complain = true);
+ bool IsStructuralMatch(Decl *From, Decl *To, bool Complain = true,
+ bool IgnoreTemplateParmDepth = false);
ExpectedDecl VisitDecl(Decl *D);
ExpectedDecl VisitImportDecl(ImportDecl *D);
ExpectedDecl VisitEmptyDecl(EmptyDecl *D);
@@ -2269,7 +2270,8 @@ getStructuralEquivalenceKind(const ASTImporter &Importer) {
: StructuralEquivalenceKind::Default;
}
-bool ASTNodeImporter::IsStructuralMatch(Decl *From, Decl *To, bool Complain) {
+bool ASTNodeImporter::IsStructuralMatch(Decl *From, Decl *To, bool Complain,
+ bool IgnoreTemplateParmDepth) {
// Eliminate a potential failure point where we attempt to re-import
// something we're trying to import while completing ToRecord.
Decl *ToOrigin = Importer.GetOriginalDecl(To);
@@ -2280,7 +2282,8 @@ bool ASTNodeImporter::IsStructuralMatch(Decl *From, Decl *To, bool Complain) {
StructuralEquivalenceContext Ctx(
Importer.getFromContext(), Importer.getToContext(),
Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer),
- false, Complain);
+ /*StrictTypeSpelling=*/false, Complain, /*ErrorOnTagTypeMismatch=*/false,
+ IgnoreTemplateParmDepth);
return Ctx.IsEquivalent(From, To);
}
@@ -5848,7 +5851,12 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (!hasSameVisibilityContextAndLinkage(FoundTemplate, D))
continue;
- if (IsStructuralMatch(D, FoundTemplate)) {
+ // FIXME: sufficient conditon for 'IgnoreTemplateParmDepth'?
+ bool IgnoreTemplateParmDepth =
+ FoundTemplate->getFriendObjectKind() != Decl::FOK_None &&
+ !D->specializations().empty();
+ if (IsStructuralMatch(D, FoundTemplate, /*Complain=*/true,
+ IgnoreTemplateParmDepth)) {
ClassTemplateDecl *TemplateWithDef =
getTemplateDefinition(FoundTemplate);
if (D->isThisDeclarationADefinition() && TemplateWithDef)
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index f867b6bf84beb7..b211e349a41299 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -1092,7 +1092,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
case Type::TemplateTypeParm: {
const auto *Parm1 = cast<TemplateTypeParmType>(T1);
const auto *Parm2 = cast<TemplateTypeParmType>(T2);
- if (Parm1->getDepth() != Parm2->getDepth())
+ if (!Context.IgnoreTemplateParmDepth &&
+ Parm1->getDepth() != Parm2->getDepth())
return false;
if (Parm1->getIndex() != Parm2->getIndex())
return false;
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 057701dea2c51d..ed3703d116a626 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -4246,6 +4246,58 @@ TEST_P(ImportFriendClasses, DeclsFromFriendsShouldBeInRedeclChains) {
EXPECT_TRUE(Imported->getPreviousDecl());
}
+TEST_P(ImportFriendClasses, SkipComparingFriendTemplateDepth) {
+ Decl *ToTU = getToTuDecl(
+ R"(
+ template <class T, T U>
+ class A;
+
+ template <class T, T U>
+ class A {
+ public:
+ template <class P, P Q>
+ friend class A;
+
+ A(T x) :x(x) {}
+
+ private:
+ T x;
+ };
+ )",
+ Lang_CXX11);
+
+ auto *Fwd = FirstDeclMatcher<ClassTemplateDecl>().match(
+ ToTU,
+ classTemplateDecl(has(cxxRecordDecl(hasDefinition(), hasName("A")))));
+ Decl *FromTU = getTuDecl(
+ R"(
+ template <class T, T U>
+ class A;
+
+ template <class T, T U>
+ class A {
+ public:
+ template <class P, P Q>
+ friend class A;
+
+ A(T x) : x(x) {}
+
+ private:
+ T x;
+ };
+
+ A<int,3> a1(0);
+ )",
+ Lang_CXX11, "input1.cc");
+ auto *FromA = FirstDeclMatcher<ClassTemplateDecl>().match(
+ FromTU,
+ classTemplateDecl(has(cxxRecordDecl(hasDefinition(), hasName("A")))));
+ auto *ToA = Import(FromA, Lang_CXX11);
+ EXPECT_TRUE(ToA);
+ EXPECT_EQ(Fwd->getTemplatedDecl()->getTypeForDecl(),
+ ToA->getTemplatedDecl()->getTypeForDecl());
+}
+
TEST_P(ImportFriendClasses,
ImportOfClassTemplateDefinitionShouldConnectToFwdFriend) {
Decl *ToTU = getToTuDecl(
diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp
index 092d9cc319a2e5..1001ce49b06739 100644
--- a/clang/unittests/AST/StructuralEquivalenceTest.cpp
+++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp
@@ -1,5 +1,6 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTStructuralEquivalence.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Testing/CommandLineArgs.h"
@@ -130,15 +131,20 @@ struct StructuralEquivalenceTest : ::testing::Test {
return makeStmts(Wrap(SrcCode0), Wrap(SrcCode1), Lang, AMatcher);
}
- bool testStructuralMatch(Decl *D0, Decl *D1) {
+ bool testStructuralMatch(Decl *D0, Decl *D1,
+ bool IgnoreTemplateParmDepth = false) {
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);
+ D0->getASTContext(), D1->getASTContext(), NonEquivalentDecls01,
+ StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false,
+ /*Complain=*/false, /*ErrorOnTagTypeMismatch=*/false,
+ IgnoreTemplateParmDepth);
StructuralEquivalenceContext Ctx10(
- D1->getASTContext(), D0->getASTContext(),
- NonEquivalentDecls10, StructuralEquivalenceKind::Default, false, false);
+ D1->getASTContext(), D0->getASTContext(), NonEquivalentDecls10,
+ StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false,
+ /*Complain=*/false, /*ErrorOnTagTypeMismatch=*/false,
+ IgnoreTemplateParmDepth);
bool Eq01 = Ctx01.IsEquivalent(D0, D1);
bool Eq10 = Ctx10.IsEquivalent(D1, D0);
EXPECT_EQ(Eq01, Eq10);
@@ -165,8 +171,9 @@ struct StructuralEquivalenceTest : ::testing::Test {
return testStructuralMatch(get<0>(t), get<1>(t));
}
- bool testStructuralMatch(std::tuple<Decl *, Decl *> t) {
- return testStructuralMatch(get<0>(t), get<1>(t));
+ bool testStructuralMatch(std::tuple<Decl *, Decl *> t,
+ bool IgnoreTemplateParmDepth = false) {
+ return testStructuralMatch(get<0>(t), get<1>(t), IgnoreTemplateParmDepth);
}
};
@@ -1689,6 +1696,40 @@ TEST_F(
EXPECT_FALSE(testStructuralMatch(t));
}
+TEST_F(StructuralEquivalenceTemplateTest,
+ IgnoreTemplateParmDepthAtTemplateTypeParmDecl) {
+ auto Decls = makeDecls<ClassTemplateDecl>(
+ R"(
+ template<class> struct A;
+ )",
+ R"(
+ template<class> struct S {
+ template<class> friend struct A;
+ };
+ )",
+ Lang_CXX03, classTemplateDecl(hasName("A")),
+ classTemplateDecl(hasName("A")));
+ EXPECT_TRUE(testStructuralMatch(Decls));
+ EXPECT_TRUE(testStructuralMatch(Decls, true));
+}
+
+TEST_F(StructuralEquivalenceTemplateTest,
+ IgnoreTemplateParmDepthAtNonTypeTemplateParmDecl) {
+ auto Decls = makeDecls<ClassTemplateDecl>(
+ R"(
+ template<class T, T U> struct A;
+ )",
+ R"(
+ template<class T> struct S {
+ template<class P, P Q> friend struct A;
+ };
+ )",
+ Lang_CXX03, classTemplateDecl(hasName("A")),
+ classTemplateDecl(hasName("A")));
+ EXPECT_FALSE(testStructuralMatch(Decls));
+ EXPECT_TRUE(testStructuralMatch(Decls, /*IgnoreTemplateParmDepth=*/true));
+}
+
TEST_F(
StructuralEquivalenceTemplateTest,
ClassTemplSpecWithInequivalentShadowedTemplArg) {
More information about the cfe-commits
mailing list