[clang] [clang][ASTImporter] Fix import of variable template redeclarations. (PR #72841)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 20 01:31:39 PST 2023
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
More information about the cfe-commits
mailing list