Skip to content

Commit 5857fec

Browse files
authored
[clang][ASTImporter] Fix of possible crash "Did not find base!". (#67680)
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 <[email protected]>
1 parent c67b862 commit 5857fec

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

clang/lib/AST/ASTImporter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,8 @@ ASTNodeImporter::import(const TemplateArgument &From) {
811811
ExpectedType ToTypeOrErr = import(From.getParamTypeForDecl());
812812
if (!ToTypeOrErr)
813813
return ToTypeOrErr.takeError();
814-
return TemplateArgument(*ToOrErr, *ToTypeOrErr, From.getIsDefaulted());
814+
return TemplateArgument(dyn_cast<ValueDecl>((*ToOrErr)->getCanonicalDecl()),
815+
*ToTypeOrErr, From.getIsDefaulted());
815816
}
816817

817818
case TemplateArgument::NullPtr: {

clang/unittests/AST/ASTImporterTest.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9175,6 +9175,64 @@ TEST_P(ASTImporterOptionSpecificTestBase,
91759175
EXPECT_TRUE(ToXType->typeMatchesDecl());
91769176
}
91779177

9178+
TEST_P(ASTImporterOptionSpecificTestBase,
9179+
ImportTemplateArgumentWithPointerToDifferentInstantiation) {
9180+
const char *CodeTo =
9181+
R"(
9182+
template<class A>
9183+
A f1() {
9184+
return A();
9185+
}
9186+
template<class A, A (B)()>
9187+
class X {};
9188+
9189+
X<int, f1<int>> x;
9190+
)";
9191+
const char *CodeFrom =
9192+
R"(
9193+
template<class A>
9194+
A f1();
9195+
template<class A, A (B)()>
9196+
class X {};
9197+
9198+
X<int, f1<int>> x;
9199+
)";
9200+
Decl *ToTU = getToTuDecl(CodeTo, Lang_CXX11);
9201+
Decl *FromTU = getTuDecl(CodeFrom, Lang_CXX11);
9202+
9203+
auto *ToF1 = FirstDeclMatcher<FunctionDecl>().match(
9204+
ToTU, functionDecl(hasName("f1"), isInstantiated()));
9205+
auto *FromF1 = FirstDeclMatcher<FunctionDecl>().match(
9206+
FromTU, functionDecl(hasName("f1"), isInstantiated()));
9207+
EXPECT_TRUE(ToF1->isThisDeclarationADefinition());
9208+
EXPECT_FALSE(FromF1->isThisDeclarationADefinition());
9209+
9210+
auto *ToX = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
9211+
ToTU, classTemplateSpecializationDecl(hasName("X")));
9212+
auto *FromX = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
9213+
FromTU, classTemplateSpecializationDecl(hasName("X")));
9214+
9215+
Decl *ToTArgF = ToX->getTemplateArgs().get(1).getAsDecl();
9216+
Decl *FromTArgF = FromX->getTemplateArgs().get(1).getAsDecl();
9217+
EXPECT_EQ(ToTArgF, ToF1);
9218+
EXPECT_EQ(FromTArgF, FromF1);
9219+
9220+
auto *ToXImported = Import(FromX, Lang_CXX11);
9221+
// The template argument 1 of 'X' in the "From" code points to a function
9222+
// that has no definition. The import must ensure that this template argument
9223+
// is imported in a way that it will point to the existing 'f1' function, not
9224+
// to the 'f1' that is imported. In this way when specialization of 'X' is
9225+
// imported it will have the same template arguments as the existing one.
9226+
EXPECT_EQ(ToXImported, ToX);
9227+
// FIXME: This matcher causes a crash "Tried to match orphan node".
9228+
// The code is removed until the problem is fixed.
9229+
// auto *ToF1Imported =
9230+
// LastDeclMatcher<FunctionDecl>().match(ToTU,
9231+
// functionDecl(hasName("f1"),isInstantiated()));
9232+
// EXPECT_NE(ToF1Imported, ToF1);
9233+
// EXPECT_EQ(ToF1Imported->getPreviousDecl(), ToF1);
9234+
}
9235+
91789236
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest,
91799237
DefaultTestValuesForRunOptions);
91809238

0 commit comments

Comments
 (0)