diff options
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 146 |
1 files changed, 101 insertions, 45 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 322e473215..7cd604d585 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1887,7 +1887,6 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { } } - QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { @@ -1923,9 +1922,6 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, false, Converted)) return QualType(); - assert((Converted.size() == Template->getTemplateParameters()->size()) && - "Converted template argument list is too short!"); - QualType CanonType; bool InstantiationDependent = false; @@ -2866,6 +2862,29 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return false; } +/// \brief Diagnose an arity mismatch in the +static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template, + SourceLocation TemplateLoc, + TemplateArgumentListInfo &TemplateArgs) { + TemplateParameterList *Params = Template->getTemplateParameters(); + unsigned NumParams = Params->size(); + unsigned NumArgs = TemplateArgs.size(); + + SourceRange Range; + if (NumArgs > NumParams) + Range = SourceRange(TemplateArgs[NumParams].getLocation(), + TemplateArgs.getRAngleLoc()); + S.Diag(TemplateLoc, diag::err_template_arg_list_different_arity) + << (NumArgs > NumParams) + << (isa<ClassTemplateDecl>(Template)? 0 : + isa<FunctionTemplateDecl>(Template)? 1 : + isa<TemplateTemplateParmDecl>(Template)? 2 : 3) + << Template << Range; + S.Diag(Template->getLocation(), diag::note_template_decl_here) + << Params->getSourceRange(); + return true; +} + /// \brief Check that the given template argument list is well-formed /// for specializing the given template. bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, @@ -2883,26 +2902,6 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, bool HasParameterPack = NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack(); - if ((NumArgs > NumParams && !HasParameterPack) || - (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. - SourceRange Range; - if (NumArgs > NumParams) - Range = SourceRange(TemplateArgs[NumParams].getLocation(), RAngleLoc); - Diag(TemplateLoc, diag::err_template_arg_list_different_arity) - << (NumArgs > NumParams) - << (isa<ClassTemplateDecl>(Template)? 0 : - isa<FunctionTemplateDecl>(Template)? 1 : - isa<TemplateTemplateParmDecl>(Template)? 2 : 3) - << Template << Range; - Diag(Template->getLocation(), diag::note_template_decl_here) - << Params->getSourceRange(); - Invalid = true; - } - // C++ [temp.arg]p1: // [...] The type and form of each template-argument specified in // a template-id shall match the type and form specified for the @@ -2914,10 +2913,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, ParamEnd = Params->end(); unsigned ArgIdx = 0; LocalInstantiationScope InstScope(*this, true); + bool SawPackExpansion = false; while (Param != ParamEnd) { if (ArgIdx < NumArgs) { // If we have an expanded parameter pack, make sure we don't have too // many arguments. + // FIXME: This really should fall out from the normal arity checking. if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { if (NTTP->isExpandedParameterPack() && @@ -2951,6 +2952,15 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // Move to the next template parameter. ++Param; } + + // If this template argument is a pack expansion, record that fact + // and break out; we can't actually check any more. + if (TemplateArgs[ArgIdx].getArgument().isPackExpansion()) { + SawPackExpansion = true; + ++ArgIdx; + break; + } + ++ArgIdx; continue; } @@ -2970,7 +2980,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if ((*Param)->isTemplateParameterPack()) break; - // We have a default template argument that we will use. + // Check whether we have a default argument. TemplateArgumentLoc Arg; // Retrieve the default template argument from the template @@ -2979,10 +2989,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // (when the template parameter was part of a nested template) into // the default argument. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { - if (!TTP->hasDefaultArgument()) { - assert(Invalid && "Missing default argument"); - break; - } + if (!TTP->hasDefaultArgument()) + return diagnoseArityMismatch(*this, Template, TemplateLoc, + TemplateArgs); TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this, Template, @@ -2997,10 +3006,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - if (!NTTP->hasDefaultArgument()) { - assert(Invalid && "Missing default argument"); - break; - } + if (!NTTP->hasDefaultArgument()) + return diagnoseArityMismatch(*this, Template, TemplateLoc, + TemplateArgs); ExprResult E = SubstDefaultTemplateArgument(*this, Template, TemplateLoc, @@ -3016,10 +3024,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); - if (!TempParm->hasDefaultArgument()) { - assert(Invalid && "Missing default argument"); - break; - } + if (!TempParm->hasDefaultArgument()) + return diagnoseArityMismatch(*this, Template, TemplateLoc, + TemplateArgs); NestedNameSpecifierLoc QualifierLoc; TemplateName Name = SubstDefaultTemplateArgument(*this, Template, @@ -3057,11 +3064,65 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, ++ArgIdx; } + // If we saw a pack expansion, then directly convert the remaining arguments, + // because we don't know what parameters they'll match up with. + if (SawPackExpansion) { + bool AddToArgumentPack + = Param != ParamEnd && (*Param)->isTemplateParameterPack(); + while (ArgIdx < NumArgs) { + if (AddToArgumentPack) + ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument()); + else + Converted.push_back(TemplateArgs[ArgIdx].getArgument()); + ++ArgIdx; + } + + // Push the argument pack onto the list of converted arguments. + if (AddToArgumentPack) { + if (ArgumentPack.empty()) + Converted.push_back(TemplateArgument(0, 0)); + else { + Converted.push_back( + TemplateArgument::CreatePackCopy(Context, + ArgumentPack.data(), + ArgumentPack.size())); + ArgumentPack.clear(); + } + } + + return Invalid; + } + + // If we have any leftover arguments, then there were too many arguments. + // Complain and fail. + if (ArgIdx < NumArgs) + return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs); + + // If we have an expanded parameter pack, make sure we don't have too + // many arguments. + // FIXME: This really should fall out from the normal arity checking. + if (Param != ParamEnd) { + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { + if (NTTP->isExpandedParameterPack() && + ArgumentPack.size() < NTTP->getNumExpansionTypes()) { + Diag(TemplateLoc, diag::err_template_arg_list_different_arity) + << false + << (isa<ClassTemplateDecl>(Template)? 0 : + isa<FunctionTemplateDecl>(Template)? 1 : + isa<TemplateTemplateParmDecl>(Template)? 2 : 3) + << Template; + Diag(Template->getLocation(), diag::note_template_decl_here) + << Params->getSourceRange(); + return true; + } + } + } + // Form argument packs for each of the parameter packs remaining. while (Param != ParamEnd) { // If we're checking a partial list of template arguments, don't fill // in arguments for non-template parameter packs. - if ((*Param)->isTemplateParameterPack()) { if (!HasParameterPack) return true; @@ -3073,7 +3134,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, ArgumentPack.size())); ArgumentPack.clear(); } - } + } else if (!PartialTemplateArgs) + return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs); ++Param; } @@ -4961,9 +5023,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateArgs, false, Converted)) return true; - assert((Converted.size() == ClassTemplate->getTemplateParameters()->size()) && - "Converted template argument list is too short!"); - // Find the class template (partial) specialization declaration that // corresponds to these arguments. if (isPartialSpecialization) { @@ -5955,9 +6014,6 @@ Sema::ActOnExplicitInstantiation(Scope *S, TemplateArgs, false, Converted)) return true; - assert((Converted.size() == ClassTemplate->getTemplateParameters()->size()) && - "Converted template argument list is too short!"); - // Find the class template specialization declaration that // corresponds to these arguments. void *InsertPos = 0; |