@@ -9900,15 +9900,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
99009900 // Match up the template parameter lists with the scope specifier, then
99019901 // determine whether we have a template or a template specialization.
99029902 bool Invalid = false;
9903+ TemplateIdAnnotation *TemplateId =
9904+ D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
9905+ ? D.getName().TemplateId
9906+ : nullptr;
99039907 TemplateParameterList *TemplateParams =
99049908 MatchTemplateParametersToScopeSpecifier(
99059909 D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
9906- D.getCXXScopeSpec(),
9907- D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
9908- ? D.getName().TemplateId
9909- : nullptr,
9910- TemplateParamLists, isFriend, isMemberSpecialization,
9911- Invalid);
9910+ D.getCXXScopeSpec(), TemplateId, TemplateParamLists, isFriend,
9911+ isMemberSpecialization, Invalid);
99129912 if (TemplateParams) {
99139913 // Check that we can declare a template here.
99149914 if (CheckTemplateDeclScope(S, TemplateParams))
@@ -9921,6 +9921,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
99219921 if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
99229922 Diag(NewFD->getLocation(), diag::err_destructor_template);
99239923 NewFD->setInvalidDecl();
9924+ // Function template with explicit template arguments.
9925+ } else if (TemplateId) {
9926+ Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec)
9927+ << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc);
9928+ NewFD->setInvalidDecl();
99249929 }
99259930
99269931 // If we're adding a template to a dependent context, we may need to
@@ -9973,6 +9978,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
99739978 << FixItHint::CreateRemoval(RemoveRange)
99749979 << FixItHint::CreateInsertion(InsertLoc, "<>");
99759980 Invalid = true;
9981+
9982+ // Recover by faking up an empty template argument list.
9983+ HasExplicitTemplateArgs = true;
9984+ TemplateArgs.setLAngleLoc(InsertLoc);
9985+ TemplateArgs.setRAngleLoc(InsertLoc);
99769986 }
99779987 }
99789988 } else {
@@ -9986,6 +9996,33 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
99869996 if (TemplateParamLists.size() > 0)
99879997 // For source fidelity, store all the template param lists.
99889998 NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists);
9999+
10000+ // "friend void foo<>(int);" is an implicit specialization decl.
10001+ if (isFriend && TemplateId)
10002+ isFunctionTemplateSpecialization = true;
10003+ }
10004+
10005+ // If this is a function template specialization and the unqualified-id of
10006+ // the declarator-id is a template-id, convert the template argument list
10007+ // into our AST format and check for unexpanded packs.
10008+ if (isFunctionTemplateSpecialization && TemplateId) {
10009+ HasExplicitTemplateArgs = true;
10010+
10011+ TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
10012+ TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
10013+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
10014+ TemplateId->NumArgs);
10015+ translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
10016+
10017+ // FIXME: Should we check for unexpanded packs if this was an (invalid)
10018+ // declaration of a function template partial specialization? Should we
10019+ // consider the unexpanded pack context to be a partial specialization?
10020+ for (const TemplateArgumentLoc &ArgLoc : TemplateArgs.arguments()) {
10021+ if (DiagnoseUnexpandedParameterPack(
10022+ ArgLoc, isFriend ? UPPC_FriendDeclaration
10023+ : UPPC_ExplicitSpecialization))
10024+ NewFD->setInvalidDecl();
10025+ }
998910026 }
999010027
999110028 if (Invalid) {
@@ -10438,46 +10475,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
1043810475 diag::ext_operator_new_delete_declared_inline)
1043910476 << NewFD->getDeclName();
1044010477
10441- // If the declarator is a template-id, translate the parser's template
10442- // argument list into our AST format.
10443- if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) {
10444- TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
10445- TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
10446- TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
10447- ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
10448- TemplateId->NumArgs);
10449- translateTemplateArguments(TemplateArgsPtr,
10450- TemplateArgs);
10451-
10452- HasExplicitTemplateArgs = true;
10453-
10454- if (NewFD->isInvalidDecl()) {
10455- HasExplicitTemplateArgs = false;
10456- } else if (FunctionTemplate) {
10457- // Function template with explicit template arguments.
10458- Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec)
10459- << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc);
10460-
10461- HasExplicitTemplateArgs = false;
10462- } else if (isFriend) {
10463- // "friend void foo<>(int);" is an implicit specialization decl.
10464- isFunctionTemplateSpecialization = true;
10465- } else {
10466- assert(isFunctionTemplateSpecialization &&
10467- "should have a 'template<>' for this decl");
10468- }
10469- } else if (isFriend && isFunctionTemplateSpecialization) {
10470- // This combination is only possible in a recovery case; the user
10471- // wrote something like:
10472- // template <> friend void foo(int);
10473- // which we're recovering from as if the user had written:
10474- // friend void foo<>(int);
10475- // Go ahead and fake up a template id.
10476- HasExplicitTemplateArgs = true;
10477- TemplateArgs.setLAngleLoc(D.getIdentifierLoc());
10478- TemplateArgs.setRAngleLoc(D.getIdentifierLoc());
10479- }
10480-
1048110478 // We do not add HD attributes to specializations here because
1048210479 // they may have different constexpr-ness compared to their
1048310480 // templates and, after maybeAddCUDAHostDeviceAttrs() is applied,
0 commit comments