================ @@ -10442,32 +10441,54 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (getLangOpts().CUDA && !isFunctionTemplateSpecialization) maybeAddCUDAHostDeviceAttrs(NewFD, Previous); - // If it's a friend (and only if it's a friend), it's possible - // that either the specialized function type or the specialized - // template is dependent, and therefore matching will fail. In - // this case, don't check the specialization yet. - if (isFunctionTemplateSpecialization && isFriend && - (NewFD->getType()->isDependentType() || DC->isDependentContext() || - TemplateSpecializationType::anyInstantiationDependentTemplateArguments( - TemplateArgs.arguments()))) { - assert(HasExplicitTemplateArgs && - "friend function specialization without template args"); - if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, - Previous)) - NewFD->setInvalidDecl(); - } else if (isFunctionTemplateSpecialization) { - if (CurContext->isDependentContext() && CurContext->isRecord() - && !isFriend) { - isDependentClassScopeExplicitSpecialization = true; - } else if (!NewFD->isInvalidDecl() && - CheckFunctionTemplateSpecialization( - NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), - Previous)) - NewFD->setInvalidDecl(); + // Handle explict specializations of function templates + // and friend function declarations with an explicit + // template argument list. + if (isFunctionTemplateSpecialization) { + bool isDependentSpecialization = false; + if (isFriend) { + // For friend function specializations, this is a dependent + // specialization if its semantic context is dependent, its + // type is dependent, or if its template-id is dependent. + isDependentSpecialization = + DC->isDependentContext() || NewFD->getType()->isDependentType() || + (HasExplicitTemplateArgs && + TemplateSpecializationType:: + anyInstantiationDependentTemplateArguments( + TemplateArgs.arguments())); + assert(!isDependentSpecialization || + (HasExplicitTemplateArgs == isDependentSpecialization) && + "dependent friend function specialization without template " + "args"); + } else { + // For class-scope explicit specializations of function templates, + // if the lexical context is dependent, then the specialization + // is dependent. + isDependentSpecialization = + CurContext->isRecord() && CurContext->isDependentContext(); + } + + TemplateArgumentListInfo *ExplicitTemplateArgs = + HasExplicitTemplateArgs ? &TemplateArgs : nullptr; + if (isDependentSpecialization) { + // If it's a dependent specialization, it may not be possible + // to determine the primary template (for explicit specializations) + // or befriended declaration (for friends) until the enclosing + // template is instantiated. In such cases, we store the declarations + // found by name lookup and defer resolution until instantiation. + if (CheckDependentFunctionTemplateSpecialization( + NewFD, ExplicitTemplateArgs, Previous)) + NewFD->setInvalidDecl(); + } else if (!NewFD->isInvalidDecl()) { + if (CheckFunctionTemplateSpecialization(NewFD, ExplicitTemplateArgs, + Previous)) + NewFD->setInvalidDecl(); + } // C++ [dcl.stc]p1: // A storage-class-specifier shall not be specified in an explicit // specialization (14.7.3) + // FIXME: We should be checking this for dependent specializations. ---------------- sdkrystian wrote:
I opted to not fix it in this commit to minimize unrelated changes. We _should_ be doing this check if `!isFriend` (since we already diagnose storage class specifiers on friend declarations elsewhere). Furthermore, the check for inconsistent storage class should happen in `CheckFunctionTemplateSpecialization` (so we check during the instantiation of dependent specializations, once the primary template is known). https://github.com/llvm/llvm-project/pull/66636 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits