diff options
author | Faisal Vali <faisalv@yahoo.com> | 2016-04-17 17:32:04 +0000 |
---|---|---|
committer | Faisal Vali <faisalv@yahoo.com> | 2016-04-17 17:32:04 +0000 |
commit | 5e9e8ac4326b28ff5cc582f14c955391793a7e19 (patch) | |
tree | c5da389eb8b1e1ac4db89f5e2ebc7e81715465fc /clang/lib/Sema/SemaTemplate.cpp | |
parent | 6ccbd2bdd2f7c247d79054f361a32b5f50539b3c (diff) | |
download | bcm5719-llvm-5e9e8ac4326b28ff5cc582f14c955391793a7e19.tar.gz bcm5719-llvm-5e9e8ac4326b28ff5cc582f14c955391793a7e19.zip |
Implement CWG 941 - explicit specializations of deleted function templates
template<class T> void f(T) = delete;
template<> void f(int); // OK.
f(3); // OK
Implementation strategy:
When an explicit specialization of a function template, a member function template or a member function of a class template is declared, clang first implicitly instantiates the declaration of a specialization from the templated-entity being explicitly specialized (since their signatures must be the same) and then links the explicit specialization being declared as a redeclaration of the aforementioned specialization.
The problem was that when clang 'implicitly instantiates' the initial specialization, it marks the corresponding FunctionDecl as deleted if the corresponding templated-entity was deleted, rather than waiting to see whether the explicit specialization being declared provides a non-deleted body. (The eager marking of delete has advantages during overload resolution I suppose, where we don't have to try and instantiate a definition of the function to see if it is deleted).
The present fix entails recognizing that when clang knows that an explicit specialization is being declared (for whichever templated-entity), the prior implicit instantiation should not inherit the 'deleted' status, and so we reset it to false.
I suppose an alternative fix (amongst others) could consider creating a new context (ExplicitSpecializationDeclarationSubstitution or some such) that is checked during template-argument-deduction and final substitution, and avoid inheriting the deleted status during declaration substitution. But while conceptually cleaner, that would be a slightly more involved change (as could be some of the other alternatives: such as avoid tagging implicit specializations as deleted, and check their primary templates for the deleted status where needed), and so I chose a different path. Hopefully it'll prove to not be a bad choice.
llvm-svn: 266561
Diffstat (limited to 'clang/lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index d840e426d7a..3833e2c3f07 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -6978,6 +6978,13 @@ bool Sema::CheckFunctionTemplateSpecialization( // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. if (!isFriend) { + // Explicit specializations do not inherit '=delete' from their primary
+ // function template.
+ if (Specialization->isDeleted()) {
+ assert(!SpecInfo->isExplicitSpecialization());
+ assert(Specialization->getCanonicalDecl() == Specialization);
+ Specialization->setDeletedAsWritten(false);
+ } SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); MarkUnusedFileScopedDecl(Specialization); } @@ -7137,6 +7144,13 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { InstantiationFunction->setTemplateSpecializationKind( TSK_ExplicitSpecialization); InstantiationFunction->setLocation(Member->getLocation()); + // Explicit specializations of member functions of class templates do not + // inherit '=delete' from the member function they are specializing. + if (InstantiationFunction->isDeleted()) { + assert(InstantiationFunction->getCanonicalDecl() == + InstantiationFunction); + InstantiationFunction->setDeletedAsWritten(false);
+ } } cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction( |