Skip to content

Commit

Permalink
[clang][ASTImporter] Fix import of variable template redeclarations. (#…
Browse files Browse the repository at this point in the history
…72841)

In some cases variable templates (specially if static member of record)
were not correctly imported and an assertion "Missing call to
MapImported?" could happen.
  • Loading branch information
balazske committed Jan 15, 2024
1 parent 4c7e4e1 commit 5e35594
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 10 deletions.
24 changes: 14 additions & 10 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6280,17 +6280,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;
}
Expand Down
53 changes: 53 additions & 0 deletions clang/unittests/AST/ASTImporterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5219,6 +5219,59 @@ TEST_P(ImportFriendClasses, RecordVarTemplateDecl) {
EXPECT_EQ(ToTUX, ToX);
}

TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateDeclConflict) {
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>
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, VarTemplateParameterDeclContext) {
constexpr auto Code =
R"(
Expand Down

0 comments on commit 5e35594

Please sign in to comment.