Skip to content

Commit

Permalink
[clang][ASTImporter] Fix of possible crash "Did not find base!". (#67680
Browse files Browse the repository at this point in the history
)

A problem with AST import could lead to multiple instances of the same
template class specialization, with different template arguments. The
difference was caused by pointers to different declarations of the same
function.
Problem is fixed by using the canonical declaration at import.

Co-authored-by: Balázs Kéri <balazs.keri@ericsson.com>
  • Loading branch information
balazske and balazske committed Oct 16, 2023
1 parent c67b862 commit 5857fec
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
3 changes: 2 additions & 1 deletion clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,8 @@ ASTNodeImporter::import(const TemplateArgument &From) {
ExpectedType ToTypeOrErr = import(From.getParamTypeForDecl());
if (!ToTypeOrErr)
return ToTypeOrErr.takeError();
return TemplateArgument(*ToOrErr, *ToTypeOrErr, From.getIsDefaulted());
return TemplateArgument(dyn_cast<ValueDecl>((*ToOrErr)->getCanonicalDecl()),
*ToTypeOrErr, From.getIsDefaulted());
}

case TemplateArgument::NullPtr: {
Expand Down
58 changes: 58 additions & 0 deletions clang/unittests/AST/ASTImporterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9175,6 +9175,64 @@ TEST_P(ASTImporterOptionSpecificTestBase,
EXPECT_TRUE(ToXType->typeMatchesDecl());
}

TEST_P(ASTImporterOptionSpecificTestBase,
ImportTemplateArgumentWithPointerToDifferentInstantiation) {
const char *CodeTo =
R"(
template<class A>
A f1() {
return A();
}
template<class A, A (B)()>
class X {};
X<int, f1<int>> x;
)";
const char *CodeFrom =
R"(
template<class A>
A f1();
template<class A, A (B)()>
class X {};
X<int, f1<int>> x;
)";
Decl *ToTU = getToTuDecl(CodeTo, Lang_CXX11);
Decl *FromTU = getTuDecl(CodeFrom, Lang_CXX11);

auto *ToF1 = FirstDeclMatcher<FunctionDecl>().match(
ToTU, functionDecl(hasName("f1"), isInstantiated()));
auto *FromF1 = FirstDeclMatcher<FunctionDecl>().match(
FromTU, functionDecl(hasName("f1"), isInstantiated()));
EXPECT_TRUE(ToF1->isThisDeclarationADefinition());
EXPECT_FALSE(FromF1->isThisDeclarationADefinition());

auto *ToX = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
ToTU, classTemplateSpecializationDecl(hasName("X")));
auto *FromX = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
FromTU, classTemplateSpecializationDecl(hasName("X")));

Decl *ToTArgF = ToX->getTemplateArgs().get(1).getAsDecl();
Decl *FromTArgF = FromX->getTemplateArgs().get(1).getAsDecl();
EXPECT_EQ(ToTArgF, ToF1);
EXPECT_EQ(FromTArgF, FromF1);

auto *ToXImported = Import(FromX, Lang_CXX11);
// The template argument 1 of 'X' in the "From" code points to a function
// that has no definition. The import must ensure that this template argument
// is imported in a way that it will point to the existing 'f1' function, not
// to the 'f1' that is imported. In this way when specialization of 'X' is
// imported it will have the same template arguments as the existing one.
EXPECT_EQ(ToXImported, ToX);
// FIXME: This matcher causes a crash "Tried to match orphan node".
// The code is removed until the problem is fixed.
// auto *ToF1Imported =
// LastDeclMatcher<FunctionDecl>().match(ToTU,
// functionDecl(hasName("f1"),isInstantiated()));
// EXPECT_NE(ToF1Imported, ToF1);
// EXPECT_EQ(ToF1Imported->getPreviousDecl(), ToF1);
}

INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest,
DefaultTestValuesForRunOptions);

Expand Down

0 comments on commit 5857fec

Please sign in to comment.