[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