Skip to content

Commit 518d863

Browse files
authored
[clang][ASTImporter] Fix import of template parameter default values. (#100100)
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 16e9bb9 commit 518d863

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

clang/lib/AST/ASTImporter.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,54 @@ 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+
// Update the parameter list `NewParams` of a template declaration
375+
// by "inheriting" default argument values from `RecentParams`,
376+
// which is the parameter list of an earlier declaration of the
377+
// same template. (Note that "inheriting" default argument values
378+
// is not related to object-oriented inheritance.)
379+
//
380+
// In the clang AST template parameters (NonTypeTemplateParmDec,
381+
// TemplateTypeParmDecl, TemplateTemplateParmDecl) have a reference to the
382+
// default value, if one is specified at the first declaration. The default
383+
// value can be specified only once. The template parameters of the
384+
// following declarations have a reference to the original default value
385+
// through the "inherited" value. This value should be set for all imported
386+
// template parameters that have a previous declaration (also a previous
387+
// template declaration).
388+
//
389+
// In the `Visit*ParmDecl` functions the default value of these template
390+
// arguments is always imported. At that location the previous declaration
391+
// is not easily accessible, it is not possible to call
392+
// `setInheritedDefaultArgument` at that place.
393+
// `updateTemplateParametersInheritedFrom` is called later when the already
394+
// imported default value is erased and changed to "inherited".
395+
// It is important to change the mode to "inherited" otherwise false
396+
// structural in-equivalences could be detected.
397+
void updateTemplateParametersInheritedFrom(
398+
const TemplateParameterList &RecentParams,
399+
TemplateParameterList &NewParams) {
400+
for (auto [Idx, Param] : enumerate(RecentParams)) {
401+
tryUpdateTemplateParmDeclInheritedFrom<NonTypeTemplateParmDecl>(
402+
Param, NewParams.getParam(Idx));
403+
tryUpdateTemplateParmDeclInheritedFrom<TemplateTypeParmDecl>(
404+
Param, NewParams.getParam(Idx));
405+
tryUpdateTemplateParmDeclInheritedFrom<TemplateTemplateParmDecl>(
406+
Param, NewParams.getParam(Idx));
407+
}
408+
}
409+
362410
public:
363411
explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {}
364412

@@ -6132,6 +6180,9 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
61326180
}
61336181

61346182
D2->setPreviousDecl(Recent);
6183+
6184+
updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()),
6185+
**TemplateParamsOrErr);
61356186
}
61366187

61376188
return D2;
@@ -6446,6 +6497,9 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
64466497
ToTemplated->setPreviousDecl(PrevTemplated);
64476498
}
64486499
ToVarTD->setPreviousDecl(Recent);
6500+
6501+
updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()),
6502+
**TemplateParamsOrErr);
64496503
}
64506504

64516505
return ToVarTD;
@@ -6718,6 +6772,9 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
67186772
TemplatedFD->setPreviousDecl(PrevTemplated);
67196773
}
67206774
ToFunc->setPreviousDecl(Recent);
6775+
6776+
updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()),
6777+
*Params);
67216778
}
67226779

67236780
return ToFunc;

clang/unittests/AST/ASTImporterTest.cpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9797,6 +9797,128 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportMultipleAnonymousEnumDecls) {
97979797
ASSERT_NE(ToEnumDeclA, ToEnumDeclB);
97989798
}
97999799

9800+
struct ImportTemplateParmDeclDefaultValue
9801+
: public ASTImporterOptionSpecificTestBase {
9802+
protected:
9803+
void checkTemplateParams(RedeclarableTemplateDecl *D) {
9804+
auto *CanD = cast<RedeclarableTemplateDecl>(D->getCanonicalDecl());
9805+
auto *CanNonTypeP = cast<NonTypeTemplateParmDecl>(
9806+
CanD->getTemplateParameters()->getParam(0));
9807+
auto *CanTypeP =
9808+
cast<TemplateTypeParmDecl>(CanD->getTemplateParameters()->getParam(1));
9809+
auto *CanTemplateP = cast<TemplateTemplateParmDecl>(
9810+
CanD->getTemplateParameters()->getParam(2));
9811+
EXPECT_FALSE(CanNonTypeP->getDefaultArgStorage().isInherited());
9812+
EXPECT_FALSE(CanTypeP->getDefaultArgStorage().isInherited());
9813+
EXPECT_FALSE(CanTemplateP->getDefaultArgStorage().isInherited());
9814+
for (Decl *Redecl : D->redecls()) {
9815+
auto *ReD = cast<RedeclarableTemplateDecl>(Redecl);
9816+
if (ReD != CanD) {
9817+
auto *NonTypeP = cast<NonTypeTemplateParmDecl>(
9818+
ReD->getTemplateParameters()->getParam(0));
9819+
auto *TypeP = cast<TemplateTypeParmDecl>(
9820+
ReD->getTemplateParameters()->getParam(1));
9821+
auto *TemplateP = cast<TemplateTemplateParmDecl>(
9822+
ReD->getTemplateParameters()->getParam(2));
9823+
EXPECT_TRUE(NonTypeP->getDefaultArgStorage().isInherited());
9824+
EXPECT_TRUE(TypeP->getDefaultArgStorage().isInherited());
9825+
EXPECT_TRUE(TemplateP->getDefaultArgStorage().isInherited());
9826+
EXPECT_EQ(NonTypeP->getDefaultArgStorage().getInheritedFrom(),
9827+
CanNonTypeP);
9828+
EXPECT_EQ(TypeP->getDefaultArgStorage().getInheritedFrom(), CanTypeP);
9829+
EXPECT_EQ(TemplateP->getDefaultArgStorage().getInheritedFrom(),
9830+
CanTemplateP);
9831+
}
9832+
}
9833+
}
9834+
9835+
void testImport(RedeclarableTemplateDecl *FromD) {
9836+
RedeclarableTemplateDecl *ToD = Import(FromD, Lang_CXX14);
9837+
checkTemplateParams(ToD);
9838+
}
9839+
9840+
const char *CodeFunction =
9841+
R"(
9842+
template <class> struct X;
9843+
9844+
template <int A = 2, typename B = int, template<class> class C = X>
9845+
void f();
9846+
template <int A, typename B, template<class> class C>
9847+
void f();
9848+
template <int A, typename B, template<class> class C>
9849+
void f() {}
9850+
)";
9851+
9852+
const char *CodeClass =
9853+
R"(
9854+
template <class> struct X;
9855+
9856+
template <int A = 2, typename B = int, template<class> class C = X>
9857+
struct S;
9858+
template <int A, typename B, template<class> class C>
9859+
struct S;
9860+
template <int A, typename B, template<class> class C>
9861+
struct S {};
9862+
)";
9863+
9864+
const char *CodeVar =
9865+
R"(
9866+
template <class> struct X;
9867+
9868+
template <int A = 2, typename B = int, template<class> class C = X>
9869+
extern int V;
9870+
template <int A, typename B, template<class> class C>
9871+
extern int V;
9872+
template <int A, typename B, template<class> class C>
9873+
int V = A;
9874+
)";
9875+
};
9876+
9877+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportFunctionTemplate) {
9878+
Decl *FromTU = getTuDecl(CodeFunction, Lang_CXX14);
9879+
auto *FromLastD = LastDeclMatcher<FunctionTemplateDecl>().match(
9880+
FromTU, functionTemplateDecl(hasName("f")));
9881+
testImport(FromLastD);
9882+
}
9883+
9884+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportExistingFunctionTemplate) {
9885+
getToTuDecl(CodeFunction, Lang_CXX14);
9886+
Decl *FromTU = getTuDecl(CodeFunction, Lang_CXX14);
9887+
auto *FromLastD = LastDeclMatcher<FunctionTemplateDecl>().match(
9888+
FromTU, functionTemplateDecl(hasName("f")));
9889+
testImport(FromLastD);
9890+
}
9891+
9892+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportClassTemplate) {
9893+
Decl *FromTU = getTuDecl(CodeClass, Lang_CXX14);
9894+
auto *FromLastD = LastDeclMatcher<ClassTemplateDecl>().match(
9895+
FromTU, classTemplateDecl(hasName("S")));
9896+
testImport(FromLastD);
9897+
}
9898+
9899+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportExistingClassTemplate) {
9900+
getToTuDecl(CodeClass, Lang_CXX14);
9901+
Decl *FromTU = getTuDecl(CodeClass, Lang_CXX14);
9902+
auto *FromLastD = LastDeclMatcher<ClassTemplateDecl>().match(
9903+
FromTU, classTemplateDecl(hasName("S")));
9904+
testImport(FromLastD);
9905+
}
9906+
9907+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportVarTemplate) {
9908+
Decl *FromTU = getTuDecl(CodeVar, Lang_CXX14);
9909+
auto *FromLastD = LastDeclMatcher<VarTemplateDecl>().match(
9910+
FromTU, varTemplateDecl(hasName("V")));
9911+
testImport(FromLastD);
9912+
}
9913+
9914+
TEST_P(ImportTemplateParmDeclDefaultValue, ImportExistingVarTemplate) {
9915+
getToTuDecl(CodeVar, Lang_CXX14);
9916+
Decl *FromTU = getTuDecl(CodeVar, Lang_CXX14);
9917+
auto *FromLastD = LastDeclMatcher<VarTemplateDecl>().match(
9918+
FromTU, varTemplateDecl(hasName("V")));
9919+
testImport(FromLastD);
9920+
}
9921+
98009922
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest,
98019923
DefaultTestValuesForRunOptions);
98029924

@@ -9880,6 +10002,9 @@ INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportInjectedClassNameType,
988010002
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportMatrixType,
988110003
DefaultTestValuesForRunOptions);
988210004

10005+
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportTemplateParmDeclDefaultValue,
10006+
DefaultTestValuesForRunOptions);
10007+
988310008
// FIXME: Make ImportOpenCLPipe test work.
988410009
// INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportOpenCLPipe,
988510010
// DefaultTestValuesForRunOptions);

0 commit comments

Comments
 (0)