Skip to content

Commit 8a5280d

Browse files
committed
[clang][ASTImporter] Fix import of template parameter default values.
Default values of template parameters (non-type, type, template) were not correctly handled in the "inherited" case. This occurs if the first declaration contains the default value but a next one not. The default value is "inherited" from the first. In ASTImporter it was only possible to set the inherited status after the template object was created with the template parameters that were imported without handling the inherited case. The import function of the template parameter contains not enough information (previous declaration) to set the inherited-from status. After the template was created, default value of the parameters that should be inherited is reset to inherited mode.
1 parent 96d4121 commit 8a5280d

File tree

2 files changed

+179
-70
lines changed

2 files changed

+179
-70
lines changed

clang/lib/AST/ASTImporter.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,31 @@ namespace clang {
359359
Params, Importer.getToContext().getTranslationUnitDecl());
360360
}
361361

362+
template <typename TemplateParmDeclT>
363+
void tryUpdateTemplateParmDeclInheritedFrom(NamedDecl *RecentParm,
364+
NamedDecl *NewParm) {
365+
if (auto *ParmT = dyn_cast<TemplateParmDeclT>(RecentParm)) {
366+
if (ParmT->hasDefaultArgument()) {
367+
auto *P = cast<TemplateParmDeclT>(NewParm);
368+
P->removeDefaultArgument();
369+
P->setInheritedDefaultArgument(Importer.ToContext, ParmT);
370+
}
371+
}
372+
}
373+
374+
void updateTemplateParametersInheritedFrom(
375+
const TemplateParameterList &RecentParams,
376+
TemplateParameterList &NewParams) {
377+
for (auto [Idx, Param] : enumerate(RecentParams)) {
378+
tryUpdateTemplateParmDeclInheritedFrom<NonTypeTemplateParmDecl>(
379+
Param, NewParams.getParam(Idx));
380+
tryUpdateTemplateParmDeclInheritedFrom<TemplateTypeParmDecl>(
381+
Param, NewParams.getParam(Idx));
382+
tryUpdateTemplateParmDeclInheritedFrom<TemplateTemplateParmDecl>(
383+
Param, NewParams.getParam(Idx));
384+
}
385+
}
386+
362387
public:
363388
explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {}
364389

@@ -6138,6 +6163,9 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
61386163
}
61396164

61406165
D2->setPreviousDecl(Recent);
6166+
6167+
updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()),
6168+
**TemplateParamsOrErr);
61416169
}
61426170

61436171
return D2;
@@ -6452,6 +6480,9 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
64526480
ToTemplated->setPreviousDecl(PrevTemplated);
64536481
}
64546482
ToVarTD->setPreviousDecl(Recent);
6483+
6484+
updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()),
6485+
**TemplateParamsOrErr);
64556486
}
64566487

64576488
return ToVarTD;
@@ -6724,6 +6755,9 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
67246755
TemplatedFD->setPreviousDecl(PrevTemplated);
67256756
}
67266757
ToFunc->setPreviousDecl(Recent);
6758+
6759+
updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()),
6760+
*Params);
67276761
}
67286762

67296763
return ToFunc;

clang/unittests/AST/ASTImporterTest.cpp

Lines changed: 145 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -9681,59 +9681,40 @@ AST_MATCHER_P(EnumDecl, hasEnumConstName, StringRef, ConstName) {
96819681
return false;
96829682
}
96839683

9684-
TEST_P(ASTImporterOptionSpecificTestBase, ImportAnonymousEnums) {
9685-
const char *Code =
9684+
TEST_P(ASTImporterOptionSpecificTestBase, ImportExistingAnonymousEnum) {
9685+
const char *ToCode =
96869686
R"(
96879687
struct A {
9688-
enum { E1, E2 } x;
9689-
enum { E3, E4 } y;
9688+
enum { E1, E2} x;
9689+
enum { E3, E4} y;
96909690
};
96919691
)";
9692-
Decl *FromTU = getTuDecl(Code, Lang_CXX11);
9693-
auto *FromEnumE1 = FirstDeclMatcher<EnumDecl>().match(
9694-
FromTU, enumDecl(hasEnumConstName("E1")));
9695-
auto *ImportedEnumE1 = Import(FromEnumE1, Lang_CXX11);
9696-
EXPECT_TRUE(ImportedEnumE1);
9697-
auto *FromEnumE3 = FirstDeclMatcher<EnumDecl>().match(
9698-
FromTU, enumDecl(hasEnumConstName("E3")));
9699-
auto *ImportedEnumE3 = Import(FromEnumE3, Lang_CXX11);
9700-
EXPECT_TRUE(ImportedEnumE3);
9701-
EXPECT_NE(ImportedEnumE1, ImportedEnumE3);
9702-
}
9703-
9704-
TEST_P(ASTImporterOptionSpecificTestBase, ImportFreeStandingAnonymousEnums) {
9692+
Decl *ToTU = getToTuDecl(ToCode, Lang_CXX11);
9693+
auto *ToE1 = FirstDeclMatcher<EnumDecl>().match(
9694+
ToTU, enumDecl(hasEnumConstName("E1")));
9695+
auto *ToE3 = FirstDeclMatcher<EnumDecl>().match(
9696+
ToTU, enumDecl(hasEnumConstName("E3")));
97059697
const char *Code =
97069698
R"(
97079699
struct A {
9708-
enum { E1, E2 };
9709-
enum { E3, E4 };
9700+
enum { E1, E2} x;
9701+
enum { E3, E4} y;
97109702
};
97119703
)";
97129704
Decl *FromTU = getTuDecl(Code, Lang_CXX11);
9713-
auto *FromEnumE1 = FirstDeclMatcher<EnumDecl>().match(
9705+
auto *FromE1 = FirstDeclMatcher<EnumDecl>().match(
97149706
FromTU, enumDecl(hasEnumConstName("E1")));
9715-
auto *ImportedEnumE1 = Import(FromEnumE1, Lang_CXX11);
9716-
EXPECT_TRUE(ImportedEnumE1);
9717-
auto *FromEnumE3 = FirstDeclMatcher<EnumDecl>().match(
9707+
auto *ImportedE1 = Import(FromE1, Lang_CXX11);
9708+
ASSERT_TRUE(ImportedE1);
9709+
EXPECT_EQ(ImportedE1, ToE1);
9710+
auto *FromE3 = FirstDeclMatcher<EnumDecl>().match(
97189711
FromTU, enumDecl(hasEnumConstName("E3")));
9719-
auto *ImportedEnumE3 = Import(FromEnumE3, Lang_CXX11);
9720-
EXPECT_TRUE(ImportedEnumE3);
9721-
EXPECT_NE(ImportedEnumE1, ImportedEnumE3);
9712+
auto *ImportedE3 = Import(FromE3, Lang_CXX11);
9713+
ASSERT_TRUE(ImportedE3);
9714+
EXPECT_EQ(ImportedE3, ToE3);
97229715
}
97239716

9724-
TEST_P(ASTImporterOptionSpecificTestBase, ImportExistingAnonymousEnums) {
9725-
const char *ToCode =
9726-
R"(
9727-
struct A {
9728-
enum { E1, E2 } x;
9729-
enum { E3, E4 } y;
9730-
};
9731-
)";
9732-
Decl *ToTU = getToTuDecl(ToCode, Lang_CXX11);
9733-
auto *ToEnumE1 = FirstDeclMatcher<EnumDecl>().match(
9734-
ToTU, enumDecl(hasEnumConstName("E1")));
9735-
auto *ToEnumE3 = FirstDeclMatcher<EnumDecl>().match(
9736-
ToTU, enumDecl(hasEnumConstName("E3")));
9717+
TEST_P(ASTImporterOptionSpecificTestBase, ImportAnonymousEnum) {
97379718
const char *Code =
97389719
R"(
97399720
struct A {
@@ -9742,45 +9723,136 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportExistingAnonymousEnums) {
97429723
};
97439724
)";
97449725
Decl *FromTU = getTuDecl(Code, Lang_CXX11);
9745-
auto *FromEnumE1 = FirstDeclMatcher<EnumDecl>().match(
9726+
auto *FromE1 = FirstDeclMatcher<EnumDecl>().match(
97469727
FromTU, enumDecl(hasEnumConstName("E1")));
9747-
auto *ImportedEnumE1 = Import(FromEnumE1, Lang_CXX11);
9748-
ASSERT_TRUE(ImportedEnumE1);
9749-
EXPECT_EQ(ImportedEnumE1, ToEnumE1);
9750-
auto *FromEnumE3 = FirstDeclMatcher<EnumDecl>().match(
9728+
auto *ImportedE1 = Import(FromE1, Lang_CXX11);
9729+
ASSERT_TRUE(ImportedE1);
9730+
auto *FromE3 = FirstDeclMatcher<EnumDecl>().match(
97519731
FromTU, enumDecl(hasEnumConstName("E3")));
9752-
auto *ImportedEnumE3 = Import(FromEnumE3, Lang_CXX11);
9753-
ASSERT_TRUE(ImportedEnumE3);
9754-
EXPECT_EQ(ImportedEnumE3, ToEnumE3);
9732+
auto *ImportedE3 = Import(FromE3, Lang_CXX11);
9733+
ASSERT_TRUE(ImportedE3);
97559734
}
97569735

9757-
TEST_P(ASTImporterOptionSpecificTestBase, ImportExistingEmptyAnonymousEnums) {
9758-
const char *ToCode =
9736+
struct ImportTemplateParmDeclDefaultValue
9737+
: public ASTImporterOptionSpecificTestBase {
9738+
protected:
9739+
void checkTemplateParams(RedeclarableTemplateDecl *D) {
9740+
auto *CanD = cast<RedeclarableTemplateDecl>(D->getCanonicalDecl());
9741+
auto *CanNonTypeP = cast<NonTypeTemplateParmDecl>(
9742+
CanD->getTemplateParameters()->getParam(0));
9743+
auto *CanTypeP =
9744+
cast<TemplateTypeParmDecl>(CanD->getTemplateParameters()->getParam(1));
9745+
auto *CanTemplateP = cast<TemplateTemplateParmDecl>(
9746+
CanD->getTemplateParameters()->getParam(2));
9747+
EXPECT_FALSE(CanNonTypeP->getDefaultArgStorage().isInherited());
9748+
EXPECT_FALSE(CanTypeP->getDefaultArgStorage().isInherited());
9749+
EXPECT_FALSE(CanTemplateP->getDefaultArgStorage().isInherited());
9750+
for (Decl *Redecl : D->redecls()) {
9751+
auto *ReD = cast<RedeclarableTemplateDecl>(Redecl);
9752+
if (ReD != CanD) {
9753+
auto *NonTypeP = cast<NonTypeTemplateParmDecl>(
9754+
ReD->getTemplateParameters()->getParam(0));
9755+
auto *TypeP = cast<TemplateTypeParmDecl>(
9756+
ReD->getTemplateParameters()->getParam(1));
9757+
auto *TemplateP = cast<TemplateTemplateParmDecl>(
9758+
ReD->getTemplateParameters()->getParam(2));
9759+
EXPECT_TRUE(NonTypeP->getDefaultArgStorage().isInherited());
9760+
EXPECT_TRUE(TypeP->getDefaultArgStorage().isInherited());
9761+
EXPECT_TRUE(TemplateP->getDefaultArgStorage().isInherited());
9762+
EXPECT_EQ(NonTypeP->getDefaultArgStorage().getInheritedFrom(),
9763+
CanNonTypeP);
9764+
EXPECT_EQ(TypeP->getDefaultArgStorage().getInheritedFrom(), CanTypeP);
9765+
EXPECT_EQ(TemplateP->getDefaultArgStorage().getInheritedFrom(),
9766+
CanTemplateP);
9767+
}
9768+
}
9769+
}
9770+
9771+
void testImport(RedeclarableTemplateDecl *FromD) {
9772+
RedeclarableTemplateDecl *ToD = Import(FromD, Lang_CXX14);
9773+
checkTemplateParams(ToD);
9774+
}
9775+
9776+
const char *CodeFunction =
97599777
R"(
9760-
struct A {
9761-
enum {};
9762-
};
9778+
template <class> struct X;
9779+
9780+
template <int A = 2, typename B = int, template<class> class C = X>
9781+
void f();
9782+
template <int A, typename B, template<class> class C>
9783+
void f();
9784+
template <int A, typename B, template<class> class C>
9785+
void f() {}
97639786
)";
9764-
Decl *ToTU = getToTuDecl(ToCode, Lang_CXX11);
9765-
auto *ToE1 = FirstDeclMatcher<EnumDecl>().match(ToTU, enumDecl());
9766-
const char *Code =
9787+
9788+
const char *CodeClass =
97679789
R"(
9768-
struct A {
9769-
enum {};
9770-
enum {};
9771-
};
9790+
template <class> struct X;
9791+
9792+
template <int A = 2, typename B = int, template<class> class C = X>
9793+
struct S;
9794+
template <int A, typename B, template<class> class C>
9795+
struct S;
9796+
template <int A, typename B, template<class> class C>
9797+
struct S {};
97729798
)";
9773-
Decl *FromTU = getTuDecl(Code, Lang_CXX11);
9774-
auto *FromE1 = FirstDeclMatcher<EnumDecl>().match(FromTU, enumDecl());
9775-
auto *ImportedE1 = Import(FromE1, Lang_CXX11);
9776-
ASSERT_TRUE(ImportedE1);
9777-
EXPECT_EQ(ImportedE1, ToE1);
9778-
auto *FromE2 = LastDeclMatcher<EnumDecl>().match(FromTU, enumDecl());
9779-
ASSERT_NE(FromE1, FromE2);
9780-
auto *ImportedE2 = Import(FromE2, Lang_CXX11);
9781-
ASSERT_TRUE(ImportedE2);
9782-
// FIXME: These should not be equal, or the import should fail.
9783-
EXPECT_EQ(ImportedE2, ToE1);
9799+
9800+
const char *CodeVar =
9801+
R"(
9802+
template <class> struct X;
9803+
9804+
template <int A = 2, typename B = int, template<class> class C = X>
9805+
extern int V;
9806+
template <int A, typename B, template<class> class C>
9807+
extern int V;
9808+
template <int A, typename B, template<class> class C>
9809+
int V = A;
9810+
)";
9811+
};
9812+
9813+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportFunctionTemplate) {
9814+
Decl *FromTU = getTuDecl(CodeFunction, Lang_CXX14);
9815+
auto *FromLastD = LastDeclMatcher<FunctionTemplateDecl>().match(
9816+
FromTU, functionTemplateDecl(hasName("f")));
9817+
testImport(FromLastD);
9818+
}
9819+
9820+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportExistingFunctionTemplate) {
9821+
getToTuDecl(CodeFunction, Lang_CXX14);
9822+
Decl *FromTU = getTuDecl(CodeFunction, Lang_CXX14);
9823+
auto *FromLastD = LastDeclMatcher<FunctionTemplateDecl>().match(
9824+
FromTU, functionTemplateDecl(hasName("f")));
9825+
testImport(FromLastD);
9826+
}
9827+
9828+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportClassTemplate) {
9829+
Decl *FromTU = getTuDecl(CodeClass, Lang_CXX14);
9830+
auto *FromLastD = LastDeclMatcher<ClassTemplateDecl>().match(
9831+
FromTU, classTemplateDecl(hasName("S")));
9832+
testImport(FromLastD);
9833+
}
9834+
9835+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportExistingClassTemplate) {
9836+
getToTuDecl(CodeClass, Lang_CXX14);
9837+
Decl *FromTU = getTuDecl(CodeClass, Lang_CXX14);
9838+
auto *FromLastD = LastDeclMatcher<ClassTemplateDecl>().match(
9839+
FromTU, classTemplateDecl(hasName("S")));
9840+
testImport(FromLastD);
9841+
}
9842+
9843+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportVarTemplate) {
9844+
Decl *FromTU = getTuDecl(CodeVar, Lang_CXX14);
9845+
auto *FromLastD = LastDeclMatcher<VarTemplateDecl>().match(
9846+
FromTU, varTemplateDecl(hasName("V")));
9847+
testImport(FromLastD);
9848+
}
9849+
9850+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportExistingVarTemplate) {
9851+
getToTuDecl(CodeVar, Lang_CXX14);
9852+
Decl *FromTU = getTuDecl(CodeVar, Lang_CXX14);
9853+
auto *FromLastD = LastDeclMatcher<VarTemplateDecl>().match(
9854+
FromTU, varTemplateDecl(hasName("V")));
9855+
testImport(FromLastD);
97849856
}
97859857

97869858
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest,
@@ -9866,6 +9938,9 @@ INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportInjectedClassNameType,
98669938
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportMatrixType,
98679939
DefaultTestValuesForRunOptions);
98689940

9941+
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportTemplateParmDeclDefaultValue,
9942+
DefaultTestValuesForRunOptions);
9943+
98699944
// FIXME: Make ImportOpenCLPipe test work.
98709945
// INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportOpenCLPipe,
98719946
// DefaultTestValuesForRunOptions);

0 commit comments

Comments
 (0)