diff options
author | Gabor Marton <martongabesz@gmail.com> | 2018-08-22 11:52:14 +0000 |
---|---|---|
committer | Gabor Marton <martongabesz@gmail.com> | 2018-08-22 11:52:14 +0000 |
commit | 42e15deb6c7b4c4794f19fdf81a37338bfcd7cd9 (patch) | |
tree | 4e29abc8923bfe44064461bfb38865d55945ff47 /clang/unittests/AST/ASTImporterTest.cpp | |
parent | c5e44c1805716316e95eded8bf014649ac69d5bd (diff) | |
download | bcm5719-llvm-42e15deb6c7b4c4794f19fdf81a37338bfcd7cd9.tar.gz bcm5719-llvm-42e15deb6c7b4c4794f19fdf81a37338bfcd7cd9.zip |
Fix import of class templates partial specialization
Summary:
Currently there are several issues with the import of class template
specializations. (1) Different TUs may have class template specializations
with the same template arguments, but with different set of instantiated
MethodDecls and FieldDecls. In this patch we provide a fix to merge these
methods and fields. (2) Currently, we search the partial template
specializations in the set of simple specializations and we add partial
specializations as simple specializations. This is bad, this patch fixes it.
Reviewers: a_sidorin, xazax.hun, r.stahl
Subscribers: rnkovacs, dkrupp, cfe-commits
Differential Revision: https://reviews.llvm.org/D50451
llvm-svn: 340402
Diffstat (limited to 'clang/unittests/AST/ASTImporterTest.cpp')
-rw-r--r-- | clang/unittests/AST/ASTImporterTest.cpp | 261 |
1 files changed, 259 insertions, 2 deletions
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 73bcb5851c2..c36af16df55 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -2955,12 +2955,12 @@ TEST_P( auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match( FromTu, classTemplateDecl(hasName("declToImport"))); auto *ToD = Import(FromD, Lang_CXX); - + auto Pattern = classTemplateDecl( has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl())))))); ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromD, Pattern)); EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToD, Pattern)); - + auto *Class = FirstDeclMatcher<ClassTemplateDecl>().match(ToD, classTemplateDecl()); auto *Friend = FirstDeclMatcher<FriendDecl>().match(ToD, friendDecl()); @@ -2968,6 +2968,263 @@ TEST_P( EXPECT_EQ(Friend->getFriendDecl()->getPreviousDecl(), Class); } +TEST_P(ASTImporterTestBase, MergeFieldDeclsOfClassTemplateSpecialization) { + std::string ClassTemplate = + R"( + template <typename T> + struct X { + int a{0}; // FieldDecl with InitListExpr + X(char) : a(3) {} // (1) + X(int) {} // (2) + }; + )"; + Decl *ToTU = getToTuDecl(ClassTemplate + + R"( + void foo() { + // ClassTemplateSpec with ctor (1): FieldDecl without InitlistExpr + X<char> xc('c'); + } + )", Lang_CXX11); + auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + ToTU, classTemplateSpecializationDecl(hasName("X"))); + // FieldDecl without InitlistExpr: + auto *ToField = *ToSpec->field_begin(); + ASSERT_TRUE(ToField); + ASSERT_FALSE(ToField->getInClassInitializer()); + Decl *FromTU = getTuDecl(ClassTemplate + + R"( + void bar() { + // ClassTemplateSpec with ctor (2): FieldDecl WITH InitlistExpr + X<char> xc(1); + } + )", Lang_CXX11); + auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + FromTU, classTemplateSpecializationDecl(hasName("X"))); + // FieldDecl with InitlistExpr: + auto *FromField = *FromSpec->field_begin(); + ASSERT_TRUE(FromField); + ASSERT_TRUE(FromField->getInClassInitializer()); + + auto *ImportedSpec = Import(FromSpec, Lang_CXX11); + ASSERT_TRUE(ImportedSpec); + EXPECT_EQ(ImportedSpec, ToSpec); + // After the import, the FieldDecl has to be merged, thus it should have the + // InitListExpr. + EXPECT_TRUE(ToField->getInClassInitializer()); +} + +TEST_P(ASTImporterTestBase, MergeFunctionOfClassTemplateSpecialization) { + std::string ClassTemplate = + R"( + template <typename T> + struct X { + void f() {} + void g() {} + }; + )"; + Decl *ToTU = getToTuDecl(ClassTemplate + + R"( + void foo() { + X<char> x; + x.f(); + } + )", Lang_CXX11); + Decl *FromTU = getTuDecl(ClassTemplate + + R"( + void bar() { + X<char> x; + x.g(); + } + )", Lang_CXX11); + auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + FromTU, classTemplateSpecializationDecl(hasName("X"))); + auto FunPattern = functionDecl(hasName("g"), + hasParent(classTemplateSpecializationDecl())); + auto *FromFun = + FirstDeclMatcher<FunctionDecl>().match(FromTU, FunPattern); + auto *ToFun = + FirstDeclMatcher<FunctionDecl>().match(ToTU, FunPattern); + ASSERT_TRUE(FromFun->hasBody()); + ASSERT_FALSE(ToFun->hasBody()); + auto *ImportedSpec = Import(FromSpec, Lang_CXX11); + ASSERT_TRUE(ImportedSpec); + auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + ToTU, classTemplateSpecializationDecl(hasName("X"))); + EXPECT_EQ(ImportedSpec, ToSpec); + EXPECT_TRUE(ToFun->hasBody()); +} + +TEST_P(ASTImporterTestBase, + ODRViolationOfClassTemplateSpecializationsShouldBeReported) { + std::string ClassTemplate = + R"( + template <typename T> + struct X {}; + )"; + Decl *ToTU = getToTuDecl(ClassTemplate + + R"( + template <> + struct X<char> { + int a; + }; + void foo() { + X<char> x; + } + )", + Lang_CXX11); + Decl *FromTU = getTuDecl(ClassTemplate + + R"( + template <> + struct X<char> { + int b; + }; + void foo() { + X<char> x; + } + )", + Lang_CXX11); + auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + FromTU, classTemplateSpecializationDecl(hasName("X"))); + auto *ImportedSpec = Import(FromSpec, Lang_CXX11); + + // We expect one (ODR) warning during the import. + EXPECT_EQ(1u, ToTU->getASTContext().getDiagnostics().getNumWarnings()); + + // The second specialization is different from the first, thus it violates + // ODR, consequently we expect to keep the first specialization only, which is + // already in the "To" context. + EXPECT_TRUE(ImportedSpec); + auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + ToTU, classTemplateSpecializationDecl(hasName("X"))); + EXPECT_EQ(ImportedSpec, ToSpec); + EXPECT_EQ(1u, DeclCounter<ClassTemplateSpecializationDecl>().match( + ToTU, classTemplateSpecializationDecl())); +} + +TEST_P(ASTImporterTestBase, MergeCtorOfClassTemplateSpecialization) { + std::string ClassTemplate = + R"( + template <typename T> + struct X { + X(char) {} + X(int) {} + }; + )"; + Decl *ToTU = getToTuDecl(ClassTemplate + + R"( + void foo() { + X<char> x('c'); + } + )", Lang_CXX11); + Decl *FromTU = getTuDecl(ClassTemplate + + R"( + void bar() { + X<char> x(1); + } + )", Lang_CXX11); + auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + FromTU, classTemplateSpecializationDecl(hasName("X"))); + // Match the void(int) ctor. + auto CtorPattern = + cxxConstructorDecl(hasParameter(0, varDecl(hasType(asString("int")))), + hasParent(classTemplateSpecializationDecl())); + auto *FromCtor = + FirstDeclMatcher<CXXConstructorDecl>().match(FromTU, CtorPattern); + auto *ToCtor = + FirstDeclMatcher<CXXConstructorDecl>().match(ToTU, CtorPattern); + ASSERT_TRUE(FromCtor->hasBody()); + ASSERT_FALSE(ToCtor->hasBody()); + auto *ImportedSpec = Import(FromSpec, Lang_CXX11); + ASSERT_TRUE(ImportedSpec); + auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + ToTU, classTemplateSpecializationDecl(hasName("X"))); + EXPECT_EQ(ImportedSpec, ToSpec); + EXPECT_TRUE(ToCtor->hasBody()); +} + +TEST_P(ASTImporterTestBase, + ClassTemplatePartialSpecializationsShouldNotBeDuplicated) { + auto Code = + R"( + // primary template + template<class T1, class T2, int I> + class A {}; + + // partial specialization + template<class T, int I> + class A<T, T*, I> {}; + )"; + Decl *ToTU = getToTuDecl(Code, Lang_CXX11); + Decl *FromTU = getTuDecl(Code, Lang_CXX11); + auto *FromSpec = + FirstDeclMatcher<ClassTemplatePartialSpecializationDecl>().match( + FromTU, classTemplatePartialSpecializationDecl()); + auto *ToSpec = + FirstDeclMatcher<ClassTemplatePartialSpecializationDecl>().match( + ToTU, classTemplatePartialSpecializationDecl()); + + auto *ImportedSpec = Import(FromSpec, Lang_CXX11); + EXPECT_EQ(ImportedSpec, ToSpec); + EXPECT_EQ(1u, DeclCounter<ClassTemplatePartialSpecializationDecl>().match( + ToTU, classTemplatePartialSpecializationDecl())); +} + +TEST_P(ASTImporterTestBase, ClassTemplateSpecializationsShouldNotBeDuplicated) { + auto Code = + R"( + // primary template + template<class T1, class T2, int I> + class A {}; + + // full specialization + template<> + class A<int, int, 1> {}; + )"; + Decl *ToTU = getToTuDecl(Code, Lang_CXX11); + Decl *FromTU = getTuDecl(Code, Lang_CXX11); + auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + FromTU, classTemplateSpecializationDecl()); + auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + ToTU, classTemplateSpecializationDecl()); + + auto *ImportedSpec = Import(FromSpec, Lang_CXX11); + EXPECT_EQ(ImportedSpec, ToSpec); + EXPECT_EQ(1u, DeclCounter<ClassTemplateSpecializationDecl>().match( + ToTU, classTemplateSpecializationDecl())); +} + +TEST_P(ASTImporterTestBase, ClassTemplateFullAndPartialSpecsShouldNotBeMixed) { + std::string PrimaryTemplate = + R"( + template<class T1, class T2, int I> + class A {}; + )"; + auto PartialSpec = + R"( + template<class T, int I> + class A<T, T*, I> {}; + )"; + auto FullSpec = + R"( + template<> + class A<int, int, 1> {}; + )"; + Decl *ToTU = getToTuDecl(PrimaryTemplate + FullSpec, Lang_CXX11); + Decl *FromTU = getTuDecl(PrimaryTemplate + PartialSpec, Lang_CXX11); + auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + FromTU, classTemplateSpecializationDecl()); + + auto *ImportedSpec = Import(FromSpec, Lang_CXX11); + EXPECT_TRUE(ImportedSpec); + // Check the number of partial specializations. + EXPECT_EQ(1u, DeclCounter<ClassTemplatePartialSpecializationDecl>().match( + ToTU, classTemplatePartialSpecializationDecl())); + // Check the number of full specializations. + EXPECT_EQ(1u, DeclCounter<ClassTemplateSpecializationDecl>().match( + ToTU, classTemplateSpecializationDecl( + unless(classTemplatePartialSpecializationDecl())))); +} + struct DeclContextTest : ASTImporterTestBase {}; TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) { |