@@ -9900,15 +9900,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
9900
9900
// Match up the template parameter lists with the scope specifier, then
9901
9901
// determine whether we have a template or a template specialization.
9902
9902
bool Invalid = false;
9903
+ TemplateIdAnnotation *TemplateId =
9904
+ D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
9905
+ ? D.getName().TemplateId
9906
+ : nullptr;
9903
9907
TemplateParameterList *TemplateParams =
9904
9908
MatchTemplateParametersToScopeSpecifier(
9905
9909
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);
9912
9912
if (TemplateParams) {
9913
9913
// Check that we can declare a template here.
9914
9914
if (CheckTemplateDeclScope(S, TemplateParams))
@@ -9921,6 +9921,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
9921
9921
if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
9922
9922
Diag(NewFD->getLocation(), diag::err_destructor_template);
9923
9923
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();
9924
9929
}
9925
9930
9926
9931
// 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,
9973
9978
<< FixItHint::CreateRemoval(RemoveRange)
9974
9979
<< FixItHint::CreateInsertion(InsertLoc, "<>");
9975
9980
Invalid = true;
9981
+
9982
+ // Recover by faking up an empty template argument list.
9983
+ HasExplicitTemplateArgs = true;
9984
+ TemplateArgs.setLAngleLoc(InsertLoc);
9985
+ TemplateArgs.setRAngleLoc(InsertLoc);
9976
9986
}
9977
9987
}
9978
9988
} else {
@@ -9986,6 +9996,33 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
9986
9996
if (TemplateParamLists.size() > 0)
9987
9997
// For source fidelity, store all the template param lists.
9988
9998
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
+ }
9989
10026
}
9990
10027
9991
10028
if (Invalid) {
@@ -10438,46 +10475,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
10438
10475
diag::ext_operator_new_delete_declared_inline)
10439
10476
<< NewFD->getDeclName();
10440
10477
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
-
10481
10478
// We do not add HD attributes to specializations here because
10482
10479
// they may have different constexpr-ness compared to their
10483
10480
// templates and, after maybeAddCUDAHostDeviceAttrs() is applied,
0 commit comments