llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Balázs Kéri (balazske) <details> <summary>Changes</summary> In some cases variable templates (specially if static member of record) were not correctly imported and an assertion "Missing call to MapImported?" could happen. --- Full diff: https://github.com/llvm/llvm-project/pull/72841.diff 2 Files Affected: - (modified) clang/lib/AST/ASTImporter.cpp (+17-10) - (modified) clang/unittests/AST/ASTImporterTest.cpp (+105) ``````````diff diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index c4e931e220f69b5..7a5e3d665328532 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -6245,17 +6245,21 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { D->getTemplatedDecl())) continue; if (IsStructuralMatch(D, FoundTemplate)) { - // The Decl in the "From" context has a definition, but in the - // "To" context we already have a definition. + // FIXME Check for ODR error if the two definitions have + // different initializers? VarTemplateDecl *FoundDef = getTemplateDefinition(FoundTemplate); - if (D->isThisDeclarationADefinition() && FoundDef) - // FIXME Check for ODR error if the two definitions have - // different initializers? - return Importer.MapImported(D, FoundDef); - if (FoundTemplate->getDeclContext()->isRecord() && - D->getDeclContext()->isRecord()) - return Importer.MapImported(D, FoundTemplate); - + if (D->getDeclContext()->isRecord()) { + assert(FoundTemplate->getDeclContext()->isRecord() && + "Member variable template imported as non-member, " + "inconsistent imported AST?"); + if (FoundDef) + return Importer.MapImported(D, FoundDef); + if (!D->isThisDeclarationADefinition()) + return Importer.MapImported(D, FoundTemplate); + } else { + if (FoundDef && D->isThisDeclarationADefinition()) + return Importer.MapImported(D, FoundDef); + } FoundByLookup = FoundTemplate; break; } @@ -6374,7 +6378,10 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl( // variable. return Importer.MapImported(D, FoundDef); } + // FIXME HandleNameConflict + return make_error<ASTImportError>(ASTImportError::NameConflict); } + return Importer.MapImported(D, D2); } else { TemplateArgumentListInfo ToTAInfo; if (const ASTTemplateArgumentListInfo *Args = D->getTemplateArgsInfo()) { diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 5f4d8d040772cb1..d439a14b7b9985f 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -5050,6 +5050,111 @@ TEST_P(ImportFriendClasses, RecordVarTemplateDecl) { EXPECT_EQ(ToTUX, ToX); } +TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateDeclConflict) { + Decl *ToTU = getToTuDecl( + R"( + template <class U> + constexpr int X = 1; + )", + Lang_CXX14); + + Decl *FromTU = getTuDecl( + R"( + template <class U> + constexpr int X = 2; + )", + Lang_CXX14, "input1.cc"); + auto *FromX = FirstDeclMatcher<VarTemplateDecl>().match( + FromTU, varTemplateDecl(hasName("X"))); + auto *ToX = Import(FromX, Lang_CXX11); + // FIXME: This import should fail. + EXPECT_TRUE(ToX); +} + +TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateStaticDefinition) { + Decl *ToTU = getToTuDecl( + R"( + struct A { + template <class U, class V> + static int X; + }; + )", + Lang_CXX14); + auto *ToX = FirstDeclMatcher<VarTemplateDecl>().match( + ToTU, varTemplateDecl(hasName("X"))); + ASSERT_FALSE(ToX->isThisDeclarationADefinition()); + + Decl *FromTU = getTuDecl( + R"( + struct A { + template <class U> + static int X; + }; + template <class U> + int A::X = 2; + )", + Lang_CXX14, "input1.cc"); + auto *FromXDef = LastDeclMatcher<VarTemplateDecl>().match( + FromTU, varTemplateDecl(hasName("X"))); + ASSERT_TRUE(FromXDef->isThisDeclarationADefinition()); + auto *ToXDef = Import(FromXDef, Lang_CXX14); + EXPECT_TRUE(ToXDef); + EXPECT_TRUE(ToXDef->isThisDeclarationADefinition()); + EXPECT_EQ(ToXDef->getPreviousDecl(), ToX); +} + +TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateSpecializationDeclValue) { + Decl *ToTU = getToTuDecl( + R"( + template <class U> + constexpr int X = U::Value; + struct A { static constexpr int Value = 1; }; + constexpr int Y = X<A>; + )", + Lang_CXX14); + + auto *ToTUX = FirstDeclMatcher<VarTemplateSpecializationDecl>().match( + ToTU, varTemplateSpecializationDecl(hasName("X"))); + Decl *FromTU = getTuDecl( + R"( + template <class U> + constexpr int X = U::Value; + struct A { static constexpr int Value = 1; }; + constexpr int Y = X<A>; + )", + Lang_CXX14, "input1.cc"); + auto *FromX = FirstDeclMatcher<VarTemplateSpecializationDecl>().match( + FromTU, varTemplateSpecializationDecl(hasName("X"))); + auto *ToX = Import(FromX, Lang_CXX14); + EXPECT_TRUE(ToX); + EXPECT_EQ(ToTUX, ToX); +} + +TEST_P(ASTImporterOptionSpecificTestBase, + VarTemplateSpecializationDeclValueConflict) { + Decl *ToTU = getToTuDecl( + R"( + template <class U> + constexpr int X = U::Value; + struct A { static constexpr int Value = 1; }; + constexpr int Y = X<A>; + )", + Lang_CXX14); + + Decl *FromTU = getTuDecl( + R"( + template <class U> + constexpr int X = U::Value; + struct A { static constexpr int Value = 2; }; + constexpr int Y = X<A>; + )", + Lang_CXX14, "input1.cc"); + auto *FromX = FirstDeclMatcher<VarTemplateSpecializationDecl>().match( + FromTU, varTemplateSpecializationDecl(hasName("X"))); + auto *ToX = Import(FromX, Lang_CXX14); + EXPECT_FALSE(ToX); +} + TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateParameterDeclContext) { constexpr auto Code = R"( `````````` </details> https://github.com/llvm/llvm-project/pull/72841 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits