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