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.
/// Retrieve the function declaration from which this function could
/// be instantiated, if it is an instantiation (rather than a non-template
/// or a specialization, for example).
- FunctionDecl *getTemplateInstantiationPattern() const;
+ ///
+ /// If \p ForDefinition is \c false, explicit specializations will be treated
+ /// as if they were implicit instantiations. This will then find the pattern
+ /// corresponding to non-definition portions of the declaration, such as
+ /// default arguments and the exception specification.
+ FunctionDecl *
+ getTemplateInstantiationPattern(bool ForDefinition = true) const;
/// Retrieve the primary template that this function template
/// specialization either specializes or was instantiated from.
return clang::isTemplateInstantiation(getTemplateSpecializationKind());
}
-FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
+FunctionDecl *
+FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const {
// If this is a generic lambda call operator specialization, its
// instantiation pattern is always its primary template's pattern
// even if its primary template was instantiated from another
}
if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) {
- if (!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind()))
+ if (ForDefinition &&
+ !clang::isTemplateInstantiation(Info->getTemplateSpecializationKind()))
return nullptr;
return getDefinitionOrSelf(cast<FunctionDecl>(Info->getInstantiatedFrom()));
}
- if (!clang::isTemplateInstantiation(getTemplateSpecializationKind()))
+ if (ForDefinition &&
+ !clang::isTemplateInstantiation(getTemplateSpecializationKind()))
return nullptr;
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
// If we hit a point where the user provided a specialization of this
// template, we're done looking.
- while (!Primary->isMemberSpecialization()) {
+ while (!ForDefinition || !Primary->isMemberSpecialization()) {
auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
if (!NewPrimary)
break;
// default argument expression appears.
ContextRAII SavedContext(*this, FD);
LocalInstantiationScope Local(*this);
+
+ FunctionDecl *Pattern = FD->getTemplateInstantiationPattern(
+ /*ForDefinition*/ false);
+ if (addInstantiatedParametersToScope(*this, FD, Pattern, Local,
+ TemplateArgs))
+ return true;
+
runWithSufficientStackSpace(CallLoc, [&] {
Result = SubstInitializer(UninstExpr, TemplateArgs,
/*DirectInit*/false);
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
+ // FIXME: We can't use getTemplateInstantiationPattern(false) in general
+ // here, because for a non-defining friend declaration in a class template,
+ // we don't store enough information to map back to the friend declaration in
+ // the template.
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
if (addInstantiatedParametersToScope(*this, Decl, Template, Scope,
TemplateArgs)) {
};
}
+namespace use_of_earlier_param {
+ template<typename T> void f(T a, int = decltype(a)());
+ void g() { f(0); }
+}
+
#if __cplusplus >= 201402L
namespace lambda {
// Verify that a default argument in a lambda can refer to the type of a