[PATCH] Fix core-DR1755 & 727 & llvm-PR17294 & PR16906 - partial & explicit specializations of member templates (class/variable/function)
Faisal Vali
faisalv at gmail.com
Mon May 26 21:59:33 PDT 2014
This patch attempts to address issues related to member template
specializations.
As a quick review (incorporating direction from Issaquah):
1) Full specializations of function, class or variable member templates can be
declared at class or namespace scope.
2) Partial specializations of a class or variable member template can be
declared similarly.
3) A full or partial specialization, or a primary member template can be
explictly declared for an implicitly instantiated class specialization.
- if the primary template is so explicitly declared it does not
inherit partial specializations from the unspecialized prototype template.
- if a full or partial specialization is so explicitly declared it does
but wins out over other specializations that contains fewer empty template
parameter lists.
4) Explicitly declared specializations (full or partial) of member templates
are only substituted into:
- a class specialization needs to have its type completed
- a variable specialization is referenced (to determine type),
and then when its value (instantiate initializer) is needed.
- once a function template is selected, and its declaration is being
instantiated.
5) During substitution of any of the explicitly declared partial or full
specializations if an error occurs, that declaration is skipped and
is not considered either in the partial ordering, or explicit
specialization search.
Following are some examples:
template<class T, class> struct A {
template<class U> static A<U, T> var;
template<class U> static U var<U*>;
template<> static char var<char>;
template<class U> struct B {
template<class V1, class V2> V1* foo(V2);
template<> typename T::type* foo<typename T::type>(U) { return 0; }
};
template<class U> struct B<U*>;
};
template<class T, class T2> template<>
struct A<T, T2>::B<typename T::type> { };
template<class T, class T2> template<>
struct A<T, T2>::B<float> { };
template<class T, class T2> template<class U> template<>
char* A<T, T2>::B<U>::foo(T2) { return 0; }
template<> template<class U>
auto A<int>::var<U*> = [](U*) { };
template<> template<class U>
auto A<char>::var = [](U*, char) { };
Additionally, explicitly declared specializations (partial or full) of constexpr
member templates always require an initializer when in-class:
- if they are then declared out of class, it is treated as a definition and
can not have an initializer
- For variable templates (and their partial or full specializations) first
declared out of line as constexpr they must have an initializer - and
subsequently represent a definition.
For class templates, if a partial or full specialization is declared
after a potential use, it is an error.
For variables templates:
- if a partial or full specialization is declared after the 'type' of
a variable specialization (that would have used the expicitly declared
specialization) has been used, it is only valid if we can prove that
the type will be the same.
- When the variable specialization's initializer is needed (that is its
value is required), we once again search for the best specialization
declaration, and if all is consistent (type matches, value has not
been used etc.), we use its value.
Patch Implementation Notes:
I tried to comment the patch with code examples - but the comments do need
improvement. The patch is also short on good diagnostics.
I also introduced checking of class scope function specializations within
a dependent context by generating/inventing template arguments for each
enclosing template parameter list - so that we can compare function
templates, order them (requires their template depth to be zero)
and then link the full-specialization to its appropriate primary
template.
The alternatives were:
1) to postpone all analysis in the dependent context (status quo) and
only when the outer template arguments have been substituted, do
the analysis of the full specializations (the problem with this
is you can write some real non-sense in a dependent context that
could never specialize any of your member function templates) and
they would always potentially just get SFINAE'd out.
2) consider teaching TemplateDeclInstantiator & TemplateInstantiator to
do substitution of template parameters at specific template depths
or focus only on certain depths when doing deduction (currently when
we do partial ordering, the template delcaration's template parameters
must have a depth of 0).
Not sure if I made the right choice, but it seems to work reasonably
well.
I also merged some of the logic for handling partial specializations
of class and variable templates.
Looking forward to some feedback.
Thanks!
http://reviews.llvm.org/D3445
Files:
include/clang/AST/DeclTemplate.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
include/clang/Sema/SemaInternal.h
include/clang/Sema/Template.h
lib/AST/Decl.cpp
lib/AST/DeclTemplate.cpp
lib/AST/TemplateBase.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Sema/SemaType.cpp
test/CXX/drs/dr0xx.cpp
test/CXX/drs/dr5xx.cpp
test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp
test/SemaCXX/cxx1y-variable-templates_in_class.cpp
test/SemaCXX/cxx1y-variable-templates_top_level.cpp
test/SemaTemplate/explicit-specialization-member.cpp
test/SemaTemplate/member-templates.cpp
test/SemaTemplate/ms-class-specialization-class-scope.cpp
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D3445.9821.patch
Type: text/x-patch
Size: 252656 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140527/c8737f4f/attachment.bin>
More information about the cfe-commits
mailing list