From e3f1f350ff39f9ff38b1a7afd38c52469cf8afa0 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 1 Jul 2009 00:28:38 +0000 Subject: [PATCH] Cope with explicitly-specified function template arguments when there are fewer template arguments than there are template parameters for that function. llvm-svn: 74578 --- clang/lib/Sema/Sema.h | 1 + clang/lib/Sema/SemaTemplate.cpp | 13 +++++++++---- clang/lib/Sema/SemaTemplateDeduction.cpp | 17 ++++++++++------- clang/lib/Sema/SemaTemplateInstantiate.cpp | 9 +++++++++ clang/lib/Sema/SemaTemplateInstantiateExpr.cpp | 11 ++++++++++- .../temp/temp.fct.spec/temp.arg.explicit/p3.cpp | 11 +++++++++++ 6 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 clang/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 9b906aadbd59..7576be8af147 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2162,6 +2162,7 @@ public: const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc, + bool PartialTemplateArgs, TemplateArgumentListBuilder &Converted); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index d72fcf8adcd6..568d68c9a7e8 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -852,7 +852,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, NumTemplateArgs); if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, TemplateArgs, NumTemplateArgs, RAngleLoc, - Converted)) + false, Converted)) return QualType(); assert((Converted.structuredSize() == @@ -1055,6 +1055,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc, + bool PartialTemplateArgs, TemplateArgumentListBuilder &Converted) { TemplateParameterList *Params = Template->getTemplateParameters(); unsigned NumParams = Params->size(); @@ -1065,7 +1066,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack(); if ((NumArgs > NumParams && !HasParameterPack) || - NumArgs < Params->getMinRequiredArguments()) { + (NumArgs < Params->getMinRequiredArguments() && + !PartialTemplateArgs)) { // FIXME: point at either the first arg beyond what we can handle, // or the '>', depending on whether we have too many or too few // arguments. @@ -1092,6 +1094,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, for (TemplateParameterList::iterator Param = Params->begin(), ParamEnd = Params->end(); Param != ParamEnd; ++Param, ++ArgIdx) { + if (ArgIdx > NumArgs && PartialTemplateArgs) + break; + // Decode the template argument TemplateArgument Arg; if (ArgIdx >= NumArgs) { @@ -2338,7 +2343,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, TemplateArgs.size()); if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, TemplateArgs.data(), TemplateArgs.size(), - RAngleLoc, Converted)) + RAngleLoc, false, Converted)) return true; assert((Converted.structuredSize() == @@ -2633,7 +2638,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, TemplateArgs.size()); if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, TemplateArgs.data(), TemplateArgs.size(), - RAngleLoc, Converted)) + RAngleLoc, false, Converted)) return true; assert((Converted.structuredSize() == diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 810de048c213..ae0e7040654a 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -934,21 +934,24 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // there are corresponding template-parameters. TemplateArgumentListBuilder Builder(TemplateParams, NumExplicitTemplateArgs); + + // Enter a new template instantiation context where we check the + // explicitly-specified template arguments against this function template, + // and then substitute them into the function parameter types. + InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), + FunctionTemplate, Deduced.data(), Deduced.size()); + if (Inst) + return TDK_InstantiationDepth; + if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), SourceLocation(), ExplicitTemplateArgs, NumExplicitTemplateArgs, SourceLocation(), + true, Builder) || Trap.hasErrorOccurred()) return TDK_InvalidExplicitArguments; - // Enter a new template instantiation context for the substitution of the - // explicitly-specified template arguments into the - InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), - FunctionTemplate, Deduced.data(), Deduced.size()); - if (Inst) - return TDK_InstantiationDepth; - // Form the template argument list from the explicitly-specified // template arguments. TemplateArgumentList *ExplicitArgumentList diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index ff01e41214ce..3bc1cf9504b8 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -584,6 +584,15 @@ InstantiateTemplateTypeParmType(const TemplateTypeParmType *T) const { if (T->getDepth() == 0) { // Replace the template type parameter with its corresponding // template argument. + + // If the corresponding template argument is NULL or doesn't exist, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template class, but there were some + // arguments left unspecified. + if (T->getIndex() >= TemplateArgs.size() || + TemplateArgs[T->getIndex()].isNull()) + return QualType(T, 0); // Would be nice to keep the original type here + assert(TemplateArgs[T->getIndex()].getKind() == TemplateArgument::Type && "Template argument kind mismatch"); return TemplateArgs[T->getIndex()].getAsType(); diff --git a/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp b/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp index 58896d48fa92..c82e1a7da3c9 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -139,8 +139,17 @@ TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) { NamedDecl *D = E->getDecl(); if (NonTypeTemplateParmDecl *NTTP = dyn_cast(D)) { assert(NTTP->getDepth() == 0 && "No nested templates yet"); - const TemplateArgument &Arg = TemplateArgs[NTTP->getPosition()]; + // If the corresponding template argument is NULL or non-existent, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template, but there were some + // arguments left unspecified. + if (NTTP->getPosition() >= TemplateArgs.size() || + TemplateArgs[NTTP->getPosition()].isNull()) + return SemaRef.Owned(E); // FIXME: Clone the expression! + + const TemplateArgument &Arg = TemplateArgs[NTTP->getPosition()]; + // The template argument itself might be an expression, in which // case we just return that expression. if (Arg.getKind() == TemplateArgument::Expression) diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp new file mode 100644 index 000000000000..f4970b89f693 --- /dev/null +++ b/clang/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template X f(Y,Z); + +void g() { + f("aa",3.0); + f("aa",3.0); // Z is deduced to be double + f("aa",3.0); // Y is deduced to be char*, and + // Z is deduced to be double + f("aa",3.0); // expected-error{{no matching}} +} \ No newline at end of file