diff options
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 94 |
1 files changed, 45 insertions, 49 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index ffbe317..8e46c49 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9900,15 +9900,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. bool Invalid = false; + TemplateIdAnnotation *TemplateId = + D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId + ? D.getName().TemplateId + : nullptr; TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), - D.getCXXScopeSpec(), - D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId - ? D.getName().TemplateId - : nullptr, - TemplateParamLists, isFriend, isMemberSpecialization, - Invalid); + D.getCXXScopeSpec(), TemplateId, TemplateParamLists, isFriend, + isMemberSpecialization, Invalid); if (TemplateParams) { // Check that we can declare a template here. if (CheckTemplateDeclScope(S, TemplateParams)) @@ -9921,6 +9921,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (Name.getNameKind() == DeclarationName::CXXDestructorName) { Diag(NewFD->getLocation(), diag::err_destructor_template); NewFD->setInvalidDecl(); + // Function template with explicit template arguments. + } else if (TemplateId) { + Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); + NewFD->setInvalidDecl(); } // 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, << FixItHint::CreateRemoval(RemoveRange) << FixItHint::CreateInsertion(InsertLoc, "<>"); Invalid = true; + + // Recover by faking up an empty template argument list. + HasExplicitTemplateArgs = true; + TemplateArgs.setLAngleLoc(InsertLoc); + TemplateArgs.setRAngleLoc(InsertLoc); } } } else { @@ -9986,6 +9996,33 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (TemplateParamLists.size() > 0) // For source fidelity, store all the template param lists. NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists); + + // "friend void foo<>(int);" is an implicit specialization decl. + if (isFriend && TemplateId) + isFunctionTemplateSpecialization = true; + } + + // If this is a function template specialization and the unqualified-id of + // the declarator-id is a template-id, convert the template argument list + // into our AST format and check for unexpanded packs. + if (isFunctionTemplateSpecialization && TemplateId) { + HasExplicitTemplateArgs = true; + + TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); + TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + + // FIXME: Should we check for unexpanded packs if this was an (invalid) + // declaration of a function template partial specialization? Should we + // consider the unexpanded pack context to be a partial specialization? + for (const TemplateArgumentLoc &ArgLoc : TemplateArgs.arguments()) { + if (DiagnoseUnexpandedParameterPack( + ArgLoc, isFriend ? UPPC_FriendDeclaration + : UPPC_ExplicitSpecialization)) + NewFD->setInvalidDecl(); + } } if (Invalid) { @@ -10438,46 +10475,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, diag::ext_operator_new_delete_declared_inline) << NewFD->getDeclName(); - // If the declarator is a template-id, translate the parser's template - // argument list into our AST format. - if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getName().TemplateId; - TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); - TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), - TemplateId->NumArgs); - translateTemplateArguments(TemplateArgsPtr, - TemplateArgs); - - HasExplicitTemplateArgs = true; - - if (NewFD->isInvalidDecl()) { - HasExplicitTemplateArgs = false; - } else if (FunctionTemplate) { - // Function template with explicit template arguments. - Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec) - << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); - - HasExplicitTemplateArgs = false; - } else if (isFriend) { - // "friend void foo<>(int);" is an implicit specialization decl. - isFunctionTemplateSpecialization = true; - } else { - assert(isFunctionTemplateSpecialization && - "should have a 'template<>' for this decl"); - } - } else if (isFriend && isFunctionTemplateSpecialization) { - // This combination is only possible in a recovery case; the user - // wrote something like: - // template <> friend void foo(int); - // which we're recovering from as if the user had written: - // friend void foo<>(int); - // Go ahead and fake up a template id. - HasExplicitTemplateArgs = true; - TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); - TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); - } - // We do not add HD attributes to specializations here because // they may have different constexpr-ness compared to their // templates and, after maybeAddCUDAHostDeviceAttrs() is applied, @@ -15845,8 +15842,6 @@ static void diagnoseImplicitlyRetainedSelf(Sema &S) { } void Sema::CheckCoroutineWrapper(FunctionDecl *FD) { - if (!FD) - return; RecordDecl *RD = FD->getReturnType()->getAsRecordDecl(); if (!RD || !RD->getUnderlyingDecl()->hasAttr<CoroReturnTypeAttr>()) return; @@ -15869,7 +15864,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - if (getLangOpts().Coroutines) { + // If we skip function body, we can't tell if a function is a coroutine. + if (getLangOpts().Coroutines && FD && !FD->hasSkippedBody()) { if (FSI->isCoroutine()) CheckCompletedCoroutineBody(FD, Body); else |