From 0b60d9e0097e2d6a1a5e62396967e207c4a772f2 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 25 Sep 2009 23:53:26 +0000 Subject: [PATCH] Use explicitly-specified template argument lists to help naming explicit template specializations, when available. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82824 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Diagnostic.h | 6 +++ lib/Sema/Sema.h | 5 ++ lib/Sema/SemaDecl.cpp | 50 ++++++++++++++++--- lib/Sema/SemaTemplate.cpp | 11 ++-- test/SemaCXX/template-specialization.cpp | 6 --- .../function-template-specialization.cpp | 10 ++++ 6 files changed, 68 insertions(+), 20 deletions(-) delete mode 100644 test/SemaCXX/template-specialization.cpp diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 518c97b5c4..13596d7edf 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -254,6 +254,12 @@ public: } bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; } + /// \brief Pretend that the last diagnostic issued was ignored. This can + /// be used by clients who suppress diagnostics themselves. + void setLastDiagnosticIgnored() { + LastDiagLevel = Ignored; + } + /// setExtensionHandlingBehavior - This controls whether otherwise-unmapped /// extension diagnostics are mapped onto ignore/warning/error. This /// corresponds to the GCC -pedantic and -pedantic-errors option. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 56f4693cd2..a992fb16a2 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -403,6 +403,7 @@ public: // deduction, and that error is one of the SFINAE errors, // suppress the diagnostic. ++NumSFINAEErrors; + Diags.setLastDiagnosticIgnored(); return SemaDiagnosticBuilder(*this); } @@ -2444,6 +2445,10 @@ public: TemplateParameterList *TemplateParams, AccessSpecifier AS); + void translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, + SourceLocation *TemplateArgLocs, + llvm::SmallVector &TemplateArgs); + QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 074eb6e149..1f53cde64b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2693,15 +2693,49 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isOutOfScopePreviousDeclaration(PrevDecl, DC, Context))) PrevDecl = 0; - // FIXME: If the declarator has a template argument list but - // isFunctionTemplateSpecialization is false, this is a function template - // specialization but the user forgot the "template<>" header. Complain about - // the missing template<> header and set isFunctionTemplateSpecialization. - + // If the declarator is a template-id, translate the parser's template + // argument list into our AST format. + bool HasExplicitTemplateArgs = false; + llvm::SmallVector TemplateArgs; + SourceLocation LAngleLoc, RAngleLoc; + if (D.getKind() == Declarator::DK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getTemplateId(); + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->getTemplateArgIsType(), + TemplateId->NumArgs); + translateTemplateArguments(TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateArgs); + TemplateArgsPtr.release(); + + HasExplicitTemplateArgs = true; + LAngleLoc = TemplateId->LAngleLoc; + RAngleLoc = TemplateId->RAngleLoc; + + if (FunctionTemplate) { + // FIXME: Diagnostic function template with explicit template + // arguments. + HasExplicitTemplateArgs = false; + } else if (!isFunctionTemplateSpecialization && + !D.getDeclSpec().isFriendSpecified()) { + // We have encountered something that the user meant to be a + // specialization (because it has explicitly-specified template + // arguments) but that was not introduced with a "template<>" (or had + // too few of them). + Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) + << CodeModificationHint::CreateInsertion( + D.getDeclSpec().getSourceRange().getBegin(), + "template<> "); + isFunctionTemplateSpecialization = true; + } + } + if (isFunctionTemplateSpecialization && - CheckFunctionTemplateSpecialization(NewFD, - /*FIXME:*/false, SourceLocation(), - 0, 0, SourceLocation(), + CheckFunctionTemplateSpecialization(NewFD, HasExplicitTemplateArgs, + LAngleLoc, TemplateArgs.data(), + TemplateArgs.size(), RAngleLoc, PrevDecl)) NewFD->setInvalidDecl(); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 27e8edd962..e0c1afbf67 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1037,9 +1037,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, /// \brief Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. -static void -translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, - SourceLocation *TemplateArgLocs, +void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, + SourceLocation *TemplateArgLocs, llvm::SmallVector &TemplateArgs) { TemplateArgs.reserve(TemplateArgsIn.size()); @@ -3409,7 +3408,8 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return DeclPtrTy(); } - // Translate the parser's template argument list in our AST format. + // If the declarator is a template-id, translate the parser's template + // argument list into our AST format. bool HasExplicitTemplateArgs = false; llvm::SmallVector TemplateArgs; if (D.getKind() == Declarator::DK_TemplateId) { @@ -3423,8 +3423,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TemplateArgs); HasExplicitTemplateArgs = true; } - - + // C++ [temp.explicit]p1: // A [...] function [...] can be explicitly instantiated from its template. // A member function [...] of a class template can be explicitly diff --git a/test/SemaCXX/template-specialization.cpp b/test/SemaCXX/template-specialization.cpp deleted file mode 100644 index 963dccaccd..0000000000 --- a/test/SemaCXX/template-specialization.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// RN: clang-cc -fsyntax-only -verify %s -// RUN: false -// XFAIL -template void f(int (&array)[N]); - -template<> void f<1>(int (&array)[1]) { } diff --git a/test/SemaTemplate/function-template-specialization.cpp b/test/SemaTemplate/function-template-specialization.cpp index 5946d9b680..90e38cc882 100644 --- a/test/SemaTemplate/function-template-specialization.cpp +++ b/test/SemaTemplate/function-template-specialization.cpp @@ -12,6 +12,7 @@ void test_f0() { // Function template specialization where there are no matches template<> void f0(char (&array)[1]); // expected-error{{no function template matches}} +template<> void f0<2>(int (&array)[2]) { } // Function template specialization that requires partial ordering template void f1(T (&array)[N]); // expected-note{{matches}} @@ -23,3 +24,12 @@ template<> void f1(int (&array)[1]); // Function template specialization that results in an ambiguity template void f1(T (&array)[17]); // expected-note{{matches}} template<> void f1(int (&array)[17]); // expected-error{{ambiguous}} + +// Resolving that ambiguity with explicitly-specified template arguments. +template void f2(double (&array)[N]); +template void f2(T (&array)[42]); + +template<> void f2(double (&array)[42]); +template<> void f2<42>(double (&array)[42]); + +void f2<25>(double (&array)[25]); // expected-error{{specialization}}