Skip to content

Commit a5569f0

Browse files
committed
Push parameters into the local instantiation scope before instantiating
a default argument. Default arguments can (after recent language changes) refer to parameters of the same function. Make sure they're added to the local instantiation scope before transforming a default argument so that we can remap such references to them properly.
1 parent 7462793 commit a5569f0

File tree

4 files changed

+30
-5
lines changed

4 files changed

+30
-5
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2618,7 +2618,13 @@ class FunctionDecl : public DeclaratorDecl,
26182618
/// Retrieve the function declaration from which this function could
26192619
/// be instantiated, if it is an instantiation (rather than a non-template
26202620
/// or a specialization, for example).
2621-
FunctionDecl *getTemplateInstantiationPattern() const;
2621+
///
2622+
/// If \p ForDefinition is \c false, explicit specializations will be treated
2623+
/// as if they were implicit instantiations. This will then find the pattern
2624+
/// corresponding to non-definition portions of the declaration, such as
2625+
/// default arguments and the exception specification.
2626+
FunctionDecl *
2627+
getTemplateInstantiationPattern(bool ForDefinition = true) const;
26222628

26232629
/// Retrieve the primary template that this function template
26242630
/// specialization either specializes or was instantiated from.

clang/lib/AST/Decl.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3623,7 +3623,8 @@ bool FunctionDecl::isTemplateInstantiation() const {
36233623
return clang::isTemplateInstantiation(getTemplateSpecializationKind());
36243624
}
36253625

3626-
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
3626+
FunctionDecl *
3627+
FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const {
36273628
// If this is a generic lambda call operator specialization, its
36283629
// instantiation pattern is always its primary template's pattern
36293630
// even if its primary template was instantiated from another
@@ -3640,18 +3641,20 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
36403641
}
36413642

36423643
if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) {
3643-
if (!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind()))
3644+
if (ForDefinition &&
3645+
!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind()))
36443646
return nullptr;
36453647
return getDefinitionOrSelf(cast<FunctionDecl>(Info->getInstantiatedFrom()));
36463648
}
36473649

3648-
if (!clang::isTemplateInstantiation(getTemplateSpecializationKind()))
3650+
if (ForDefinition &&
3651+
!clang::isTemplateInstantiation(getTemplateSpecializationKind()))
36493652
return nullptr;
36503653

36513654
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
36523655
// If we hit a point where the user provided a specialization of this
36533656
// template, we're done looking.
3654-
while (!Primary->isMemberSpecialization()) {
3657+
while (!ForDefinition || !Primary->isMemberSpecialization()) {
36553658
auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
36563659
if (!NewPrimary)
36573660
break;

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4273,6 +4273,13 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
42734273
// default argument expression appears.
42744274
ContextRAII SavedContext(*this, FD);
42754275
LocalInstantiationScope Local(*this);
4276+
4277+
FunctionDecl *Pattern = FD->getTemplateInstantiationPattern(
4278+
/*ForDefinition*/ false);
4279+
if (addInstantiatedParametersToScope(*this, FD, Pattern, Local,
4280+
TemplateArgs))
4281+
return true;
4282+
42764283
runWithSufficientStackSpace(CallLoc, [&] {
42774284
Result = SubstInitializer(UninstExpr, TemplateArgs,
42784285
/*DirectInit*/false);
@@ -4338,6 +4345,10 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
43384345
MultiLevelTemplateArgumentList TemplateArgs =
43394346
getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
43404347

4348+
// FIXME: We can't use getTemplateInstantiationPattern(false) in general
4349+
// here, because for a non-defining friend declaration in a class template,
4350+
// we don't store enough information to map back to the friend declaration in
4351+
// the template.
43414352
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
43424353
if (addInstantiatedParametersToScope(*this, Decl, Template, Scope,
43434354
TemplateArgs)) {

clang/test/SemaTemplate/default-arguments-cxx0x.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ namespace rdar34167492 {
116116
};
117117
}
118118

119+
namespace use_of_earlier_param {
120+
template<typename T> void f(T a, int = decltype(a)());
121+
void g() { f(0); }
122+
}
123+
119124
#if __cplusplus >= 201402L
120125
namespace lambda {
121126
// Verify that a default argument in a lambda can refer to the type of a

0 commit comments

Comments
 (0)