This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

PATCH to tighten up specialization handling



This patch improves checking of explicit/partial specializations.  In
particular, we now (as per the standard): 

  o Forbid explicit specializations in non-namespace scope.
  o Forbid default arguments in partial specializations
  o Forbid partial specializations whose non-type arguments involve the
    unspecialized parameters.
  o Forbid partial specializations for which the type of a non-type
    arguments depends on a parameter.
  o Forbid specializations of member templates when the enclosing
    classes are not fully specialized.

Some of the test-cases (which I wrote :-)) used some of these
features.  They've been changed; there's no reason to support them.

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com

1998-09-05  Mark Mitchell  <mark@markmitchell.com>

	* cp-tree.h (TI_PENDING_SPECIALIZATION_FLAG): Remove.
	* class.c (finish_struct): Remove hackery to deal with explicit
	specializations in class scope.
	* decl.c (grokfndecl): Improve error-recovery.
	* decl2.c (grokfield): Likewise.
	* pt.c (check_specialization_scope): New function.
	(begin_specialization): Call it.
	(process_partial_specialization): New function, split out from
	push_template_decl.  Check partial specializations more
	stringently.
	(push_template_decl): Call it.
	(check_explicit_specialization): Don't attempt to handle explicit
	specializations in class scope.
	(template_parm_data): Document.  Add current_arg and
	arg_uses_template_parms. 
	(mark_template_parm): Set it.
	(tsubst_arg_types): Remove unused variable.
	* semantics.c (begin_class_definition): Tweak.
	
Index: testsuite/g++.old-deja/g++.pt/spec20.C
===================================================================
RCS file: spec20.C
diff -N spec20.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- spec20.C	Sat Sep  5 19:18:03 1998
***************
*** 0 ****
--- 1,11 ----
+ // Build don't link:
+ 
+ template <class T> 
+ struct S {
+   template <class U> void f(U);
+   template <> void f<int>(int); // ERROR - specialization
+ 
+   template <class V> struct I {};
+   template <class V> struct I<V*> {};
+   template <> struct I<int>; // ERROR - specialization
+ };
Index: testsuite/g++.old-deja/g++.pt/spec21.C
===================================================================
RCS file: spec21.C
diff -N spec21.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- spec21.C	Sat Sep  5 19:18:03 1998
***************
*** 0 ****
--- 1,16 ----
+ // Build don't link:
+ 
+ template <class T> struct S {};
+ template <class T = int> struct S<T*> {}; // ERROR - default argument
+ 
+ template <int I, int J> struct A {};
+ template <int I> struct A<I+5, I*2> {}; // ERROR - argument involves parameter
+ 
+ template <class T, T t> struct C {};
+ template <class T> struct C<T, 1>;  // ERROR - type depends on parameter
+ int i;
+ template <class T> struct C<T*, &i>; // ERROR - type depends on parameter
+ 
+ template< int X, int (*array_ptr)[X] > class B {};
+ int array[5];
+ template< int X > class B<X,&array> { }; // ERROR - type depends on parameter
Index: testsuite/g++.old-deja/g++.pt/spec22.C
===================================================================
RCS file: spec22.C
diff -N spec22.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- spec22.C	Sat Sep  5 19:18:03 1998
***************
*** 0 ****
--- 1,15 ----
+ // Build don't link:
+ 
+ template <class T>
+ struct S
+ {
+   template <class U>
+   void f();
+ };
+ 
+ 
+ template <class T> 
+ template <> // ERROR - enclosing classes not specialized
+ void S<T>::f<int> () 
+ {
+ }
Index: testsuite/g++.old-deja/g++.pt/explicit12.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/explicit12.C,v
retrieving revision 1.1
diff -c -p -r1.1 explicit12.C
*** explicit12.C	1997/09/26 03:13:10	1.1
--- explicit12.C	1998/09/06 02:18:02
*************** struct S 
*** 5,14 ****
  {
    template <class T>
    void foo(T t);
- 
-   template <>
-   void foo<int>(int) {}
  };
  
  int main()
  {
--- 5,16 ----
  {
    template <class T>
    void foo(T t);
  };
+ 
+ 
+ template <>
+ template <>
+ void S<char*>::foo<int>(int) {}
  
  int main()
  {
Index: testsuite/g++.old-deja/g++.pt/explicit13.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/explicit13.C,v
retrieving revision 1.1
diff -c -p -r1.1 explicit13.C
*** explicit13.C	1997/09/26 03:13:11	1.1
--- explicit13.C	1998/09/06 02:18:02
*************** struct S 
*** 7,18 ****
    template <class T>
    void foo(T t);
  
-   template <>
-   void foo(int) { }
- 
    template <class T>
    void bar(T t) { this->template foo<U>(3.74); }
  };
  
  int main()
  {
--- 7,19 ----
    template <class T>
    void foo(T t);
  
    template <class T>
    void bar(T t) { this->template foo<U>(3.74); }
  };
+ 
+ template <>
+ template <>
+ void S<int>::foo(int) { }
  
  int main()
  {
Index: testsuite/g++.old-deja/g++.pt/explicit35.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/explicit35.C,v
retrieving revision 1.1
diff -c -p -r1.1 explicit35.C
*** explicit35.C	1997/09/26 03:13:26	1.1
--- explicit35.C	1998/09/06 02:18:02
*************** struct S 
*** 4,13 ****
  {
    template <class T>
    void foo(T t);
- 
-   template <>
-   void foo<int>(int i) { }
  };
  
  int main()
  {
--- 4,13 ----
  {
    template <class T>
    void foo(T t);
  };
+ 
+ template <>
+ void S::foo<int>(int i) { }
  
  int main()
  {
Index: testsuite/g++.old-deja/g++.pt/memclass7.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/memclass7.C,v
retrieving revision 1.1
diff -c -p -r1.1 memclass7.C
*** memclass7.C	1998/03/15 19:54:35	1.1
--- memclass7.C	1998/09/06 02:18:03
*************** struct S 
*** 4,14 ****
    struct Y {
      template <class T>
      void foo(T t);
- 
-     template <>
-     void foo<int>(int i) { }
    };
  };
  
  int main()
  {
--- 4,15 ----
    struct Y {
      template <class T>
      void foo(T t);
    };
  };
+ 
+ template <>
+ template <>
+ void S::Y<char>::foo<int>(int i) { }
  
  int main()
  {
Index: testsuite/g++.old-deja/g++.pt/memtemp61.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/memtemp61.C,v
retrieving revision 1.1
diff -c -p -r1.1 memtemp61.C
*** memtemp61.C	1997/09/26 03:13:31	1.1
--- memtemp61.C	1998/09/06 02:18:03
*************** struct S
*** 4,12 ****
  {
    template <class T>
    void foo(T t);
-   
-   template <>
-   void foo(int i);
  };
  
  
--- 4,9 ----
Index: testsuite/g++.old-deja/g++.pt/memtemp62.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/memtemp62.C,v
retrieving revision 1.1
diff -c -p -r1.1 memtemp62.C
*** memtemp62.C	1997/09/26 03:13:32	1.1
--- memtemp62.C	1998/09/06 02:18:03
*************** struct S
*** 4,12 ****
  {
    template <class T>
    void foo(T t);
-   
-   template <>
-   void foo(int i);
  };
  
  
--- 4,9 ----
Index: testsuite/g++.old-deja/g++.pt/memtemp77.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C,v
retrieving revision 1.1
diff -c -p -r1.1 memtemp77.C
*** memtemp77.C	1998/07/28 01:03:08	1.1
--- memtemp77.C	1998/09/06 02:18:03
*************** struct S3
*** 7,15 ****
    static char* h(U);
  };
  
- template <class T>
  template <>
! char* S3<T>::h(int) { return __PRETTY_FUNCTION__; }
  
  template <>
  template <>
--- 7,15 ----
    static char* h(U);
  };
  
  template <>
! template <>
! char* S3<double>::h(int) { return __PRETTY_FUNCTION__; }
  
  template <>
  template <>
Index: testsuite/g++.old-deja/g++.pt/spec10.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/spec10.C,v
retrieving revision 1.1
diff -c -p -r1.1 spec10.C
*** spec10.C	1998/01/20 00:57:39	1.1
--- spec10.C	1998/09/06 02:18:03
*************** struct S
*** 5,18 ****
  {
    template <int i>
    int f(int j) { abort(); return 0; }
- 
-   template <>
-   int f<7>(int j) { return j + 7; }
- 
-   template <>
-   int f<8>(int j) { return j + 8; }
  };
  
  
  int main()
  {
--- 5,19 ----
  {
    template <int i>
    int f(int j) { abort(); return 0; }
  };
  
+ template <>
+ template <>
+ int S<double>::f<7>(int j) { return j + 7; }
+ 
+ template <>
+ template <>
+ int S<double>::f<8>(int j) { return j + 8; }
  
  int main()
  {
Index: testsuite/g++.old-deja/g++.pt/spec11.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/spec11.C,v
retrieving revision 1.1
diff -c -p -r1.1 spec11.C
*** spec11.C	1998/01/20 00:57:39	1.1
--- spec11.C	1998/09/06 02:18:03
*************** struct S
*** 7,15 ****
    int f(U u);
  };
  
- template <class T>
  template <>
! int S<T>::f(int i) { return 1; }
  
  int main()
  {
--- 7,15 ----
    int f(U u);
  };
  
  template <>
! template <>
! int S<char>::f(int i) { return 1; }
  
  int main()
  {
Index: testsuite/g++.old-deja/g++.pt/spec12.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/spec12.C,v
retrieving revision 1.1
diff -c -p -r1.1 spec12.C
*** spec12.C	1998/01/28 10:58:52	1.1
--- spec12.C	1998/09/06 02:18:03
*************** struct S
*** 8,16 ****
  };
  
  
- template <class T>
  template <>
! int S<T>::f<int>(int i) { return 1; }
  
  int main()
  {
--- 8,16 ----
  };
  
  
  template <>
! template <>
! int S<char>::f<int>(int i) { return 1; }
  
  int main()
  {
Index: testsuite/g++.old-deja/g++.pt/spec13.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/spec13.C,v
retrieving revision 1.1
diff -c -p -r1.1 spec13.C
*** spec13.C	1998/01/28 10:58:52	1.1
--- spec13.C	1998/09/06 02:18:03
*************** struct S1
*** 14,24 ****
  
    template <class T>
    void f(T* t);
- 
-   template <>
-   void f(int* ip) {}
  };
  
  template <class U>
  struct S2
  {
--- 14,24 ----
  
    template <class T>
    void f(T* t);
  };
  
+ template <>
+ void S1::f(int* ip) {}
+ 
  template <class U>
  struct S2
  {
*************** struct S2
*** 27,36 ****
  
    template <class T>
    void f(T* t);
- 
-   template <>
-   void f(int* ip) {}
  };
  
  int main()
  {
--- 27,37 ----
  
    template <class T>
    void f(T* t);
  };
+ 
+ template <>
+ template <>
+ void S2<double>::f(int* ip) {}
  
  int main()
  {
Index: testsuite/g++.old-deja/g++.pt/spec15.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/spec15.C,v
retrieving revision 1.1
diff -c -p -r1.1 spec15.C
*** spec15.C	1998/02/03 01:33:18	1.1
--- spec15.C	1998/09/06 02:18:03
*************** struct S3
*** 28,36 ****
    static int h(U);
  };
  
- template <class T>
  template <>
! int S3<T>::h(int) { return 0; }
  
  template <>
  template <>
--- 28,36 ----
    static int h(U);
  };
  
  template <>
! template <>
! int S3<double>::h(int) { return 0; }
  
  template <>
  template <>
Index: testsuite/g++.old-deja/g++.pt/spec6.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/spec6.C,v
retrieving revision 1.1
diff -c -p -r1.1 spec6.C
*** spec6.C	1998/01/20 00:57:39	1.1
--- spec6.C	1998/09/06 02:18:03
*************** struct S1
*** 4,23 ****
  {
    template <class T>
    void f(T t1, T t2);
- 
-   template <>
-   void f(int i1, int i2);
  };
  
  template <class U>
  struct S2
  {
    template <class T>
    void f(T t1, T t2);
- 
-   template <>
-   void f(int i1, int i2);
  };
  
  void h()
  {
--- 4,25 ----
  {
    template <class T>
    void f(T t1, T t2);
  };
  
+ 
+ template <>
+ void S1::f(int i1, int i2);
+ 
  template <class U>
  struct S2
  {
    template <class T>
    void f(T t1, T t2);
  };
+ 
+ template <>
+ template <>
+ void S2<char>::f(int i1, int i2);
  
  void h()
  {
Index: cp/class.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/class.c,v
retrieving revision 1.79
diff -c -p -r1.79 class.c
*** class.c	1998/09/01 13:17:34	1.79
--- class.c	1998/09/06 02:18:23
*************** finish_struct (t, list_of_fieldlists, at
*** 4148,4155 ****
  {
    tree fields = NULL_TREE;
    tree *tail = &TYPE_METHODS (t);
-   tree specializations = NULL_TREE;
-   tree *specialization_tail = &specializations;
    tree name = TYPE_NAME (t);
    tree x, last_x = NULL_TREE;
    tree access;
--- 4148,4153 ----
*************** finish_struct (t, list_of_fieldlists, at
*** 4259,4277 ****
  	      if (last_x)
  		TREE_CHAIN (last_x) = next_x;
  
- 	      if (DECL_TEMPLATE_SPECIALIZATION (x))
- 		/* We don't enter the specialization into the class
- 		   method vector since specializations don't affect
- 		   overloading.  Instead we keep track of the
- 		   specializations, and process them after the method
- 		   vector is complete.  */
- 		{
- 		  *specialization_tail = x;
- 		  specialization_tail = &TREE_CHAIN (x);
- 		  TREE_CHAIN (x) = NULL_TREE;
- 		  continue;
- 		}
- 
  	      /* Link x onto end of TYPE_METHODS.  */
  	      *tail = x;
  	      tail = &TREE_CHAIN (x);
--- 4257,4262 ----
*************** finish_struct (t, list_of_fieldlists, at
*** 4359,4385 ****
      t = finish_struct_1 (t, warn_anon);
  
    TYPE_BEING_DEFINED (t) = 0;
- 
-   /* Now, figure out which member templates we're specializing.  */
-   for (x = specializations; x != NULL_TREE; x = TREE_CHAIN (x))
-     {
-       int pending_specialization;
- 
-       pending_specialization 
- 	= TI_PENDING_SPECIALIZATION_FLAG (DECL_TEMPLATE_INFO (x));
-       check_explicit_specialization 
- 	(lookup_template_function (DECL_NAME (x), DECL_TI_ARGS (x)),
- 	 x, 0, 1 | (8 * pending_specialization));
-       TI_PENDING_SPECIALIZATION_FLAG (DECL_TEMPLATE_INFO (x)) = 0;
- 
-       /* Now, the assembler name will be correct for fn, so we
- 	 make its RTL.  */
-       DECL_RTL (x) = 0;
-       make_decl_rtl (x, NULL_PTR, 1);
-       DECL_RTL (DECL_TI_TEMPLATE (x)) = 0;
-       make_decl_rtl (DECL_TI_TEMPLATE (x), NULL_PTR, 1);
-     }
- 
    if (current_class_type)
      popclass (0);
    else
--- 4344,4349 ----
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.133
diff -c -p -r1.133 cp-tree.h
*** cp-tree.h	1998/09/04 11:31:28	1.133
--- cp-tree.h	1998/09/06 02:18:36
*************** Boston, MA 02111-1307, USA.  */
*** 35,41 ****
        (TREE_MANGLED) (in IDENTIFIER_NODE) (commented-out).
     1:  IDENTIFIER_VIRTUAL_P.
        TI_PENDING_TEMPLATE_FLAG.
-       TI_PENDING_SPECIALIZATION_FLAG.
        TEMPLATE_PARMS_FOR_INLINE.
        DELETE_EXPR_USE_VEC (in DELETE_EXPR).
        (TREE_CALLS_NEW) (in _EXPR or _REF) (commented-out).
--- 35,40 ----
*************** struct lang_decl
*** 1266,1276 ****
  #define TI_ARGS(NODE) (TREE_VALUE (NODE))
  #define TI_SPEC_INFO(NODE) (TREE_CHAIN (NODE))
  #define TI_PENDING_TEMPLATE_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
- 
- /* TI_PENDING_SPECIALIZATION_FLAG on a template-info node indicates
-    that the template is a specialization of a member template, but
-    that we don't yet know which one.  */
- #define TI_PENDING_SPECIALIZATION_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
  
  /* The TEMPLATE_DECL instantiated or specialized by NODE.  This
     TEMPLATE_DECL will be the immediate parent, not the most general
--- 1265,1270 ----
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.203
diff -c -p -r1.203 decl.c
*** decl.c	1998/09/03 14:15:31	1.203
--- decl.c	1998/09/06 02:19:17
*************** grokfndecl (ctype, type, declarator, ori
*** 8016,8021 ****
--- 8016,8023 ----
  					    template_count, 
  					    2 * (funcdef_flag != 0) + 
  					    4 * (friendp != 0));
+       if (decl == error_mark_node)
+ 	return error_mark_node;
  
        if ((! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl))
  	  && check)
*************** grokfndecl (ctype, type, declarator, ori
*** 8063,8068 ****
--- 8065,8073 ----
  					    template_count, 
  					    2 * (funcdef_flag != 0) + 
  					    4 * (friendp != 0));
+       if (decl == error_mark_node)
+ 	return error_mark_node;
+ 
        if (ctype != NULL_TREE
  	  && (! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl))
  	  && check)
*************** grokdeclarator (declarator, declspecs, d
*** 10392,10401 ****
  		if (decl && DECL_NAME (decl))
  		  {
  		    if (template_class_depth (current_class_type) == 0)
! 		      decl 
! 			= check_explicit_specialization 
! 			(declarator, decl,
! 			 template_count, 2 * (funcdef_flag != 0) + 4);
  		    t = do_friend (ctype, declarator, decl,
  				   last_function_parms, flags, quals,
  				   funcdef_flag);
--- 10397,10411 ----
  		if (decl && DECL_NAME (decl))
  		  {
  		    if (template_class_depth (current_class_type) == 0)
! 		      {
! 			decl 
! 			  = check_explicit_specialization 
! 			  (declarator, decl,
! 			   template_count, 2 * (funcdef_flag != 0) + 4);
! 			if (decl == error_mark_node)
! 			  return error_mark_node;
! 		      }
! 
  		    t = do_friend (ctype, declarator, decl,
  				   last_function_parms, flags, quals,
  				   funcdef_flag);
Index: cp/decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.130
diff -c -p -r1.130 decl2.c
*** decl2.c	1998/09/04 01:43:57	1.130
--- decl2.c	1998/09/06 02:19:39
*************** grokfield (declarator, declspecs, init, 
*** 1606,1613 ****
      init = NULL_TREE;
  
    value = grokdeclarator (declarator, declspecs, FIELD, init != 0, NULL_TREE);
!   if (! value)
!     return value; /* friend or constructor went bad.  */
  
    /* Pass friendly classes back.  */
    if (TREE_CODE (value) == VOID_TYPE)
--- 1606,1613 ----
      init = NULL_TREE;
  
    value = grokdeclarator (declarator, declspecs, FIELD, init != 0, NULL_TREE);
!   if (! value || value == error_mark_node)
!     return NULL_TREE; /* friend or constructor went bad.  */
  
    /* Pass friendly classes back.  */
    if (TREE_CODE (value) == VOID_TYPE)
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.198
diff -c -p -r1.198 pt.c
*** pt.c	1998/09/04 11:31:30	1.198
--- pt.c	1998/09/06 02:19:54
*************** static int template_class_depth_real PRO
*** 127,132 ****
--- 127,134 ----
  static tree tsubst_aggr_type PROTO((tree, tree, tree, int));
  static tree tsubst_decl PROTO((tree, tree, tree, tree));
  static tree tsubst_arg_types PROTO((tree, tree, tree));
+ static void check_specialization_scope PROTO((void));
+ static tree process_partial_specialization PROTO((tree));
  
  /* We use TREE_VECs to hold template arguments.  If there is only one
     level of template arguments, then the TREE_VEC contains the
*************** begin_template_parm_list ()
*** 575,586 ****
--- 577,620 ----
    note_template_header (0);
  }
  
+ /* This routine is called when a specialization is declared.  If it is
+    illegal to declare a specialization here, an error is reported.  */
+ 
+ void
+ check_specialization_scope ()
+ {
+   tree scope = current_scope ();
+   /* [temp.expl.spec] 
+      
+      An explicit specialization shall be declared in the namespace of
+      which the template is a member, or, for member templates, in the
+      namespace of which the enclosing class or enclosing class
+      template is a member.  An explicit specialization of a member
+      function, member class or static data member of a class template
+      shall be declared in the names- pace of which the class template
+      is a member.  */
+   if (scope && TREE_CODE (scope) != NAMESPACE_DECL)
+     cp_error ("explicit specialization in non-namespace scope `%D'",
+ 	      scope);
+   /* [temp.expl.spec] 
+ 
+      In an explicit specialization declaration for a member of a class
+      template or a member template that appears in namespace scope,
+      the member template and some of its enclosing class templates may
+      remain unspecialized, except that the declaration shall not
+      explicitly specialize a class member template if its enclosing
+      class templates are not explicitly specialized as well.  */
+   if (current_template_parms) 
+     cp_error ("enclosing class templates are not explicit specialized");
+ }
+ 
  /* We've just seen template <>. */
  
  void
  begin_specialization ()
  {
    note_template_header (1);
+   check_specialization_scope ();
  }
  
  /* Called at then end of processing a declaration preceeded by
*************** check_explicit_specialization (declarato
*** 1209,1225 ****
        if (ctype != NULL_TREE && TYPE_BEING_DEFINED (ctype))
  	{
  	  if (!explicit_instantiation)
! 	    {
! 	      /* Since finish_struct_1 has not been called yet, we
! 		 can't call lookup_fnfields.  We note that this
! 		 template is a specialization, and proceed, letting
! 		 finish_struct fix this up later.  */
! 	      tree ti = perm_tree_cons (NULL_TREE, 
! 					TREE_OPERAND (declarator, 1),
! 					NULL_TREE);
! 	      TI_PENDING_SPECIALIZATION_FLAG (ti) = 1;
! 	      DECL_TEMPLATE_INFO (decl) = ti;
! 	    }
  	  else
  	    /* It's not legal to write an explicit instantiation in
  	       class scope, e.g.:
--- 1243,1252 ----
        if (ctype != NULL_TREE && TYPE_BEING_DEFINED (ctype))
  	{
  	  if (!explicit_instantiation)
! 	    /* A specialization in class scope.  This is illegal,
! 	       but the error will already have been flagged by
! 	       check_specialization_scope.  */
! 	    return error_mark_node;
  	  else
  	    /* It's not legal to write an explicit instantiation in
  	       class scope, e.g.:
*************** build_template_decl (decl, parms)
*** 1759,1766 ****
--- 1786,1808 ----
  
  struct template_parm_data
  {
+   /* The level of the template parameters we are currently
+      processing.  */
    int level;
+ 
+   /* The index of the specialization argument we are currently
+      processing.  */
+   int current_arg;
+ 
+   /* An array whose size is the number of template parameters.  The
+      elements are non-zero if the parameter has been used in any one
+      of the arguments processed so far.  */
    int* parms;
+ 
+   /* An array whose size is the number of template arguments.  The
+      elements are non-zero if the argument makes use of template
+      parameters of this level.  */
+   int* arg_uses_template_parms;
  };
  
  /* Subroutine of push_template_decl used to see if each template
*************** mark_template_parm (t, data)
*** 1790,1802 ****
      }
  
    if (level == tpd->level)
!     tpd->parms[idx] = 1;
  
    /* Return zero so that for_each_template_parm will continue the
       traversal of the tree; we want to mark *every* template parm.  */
    return 0;
  }
  
  /* Creates a TEMPLATE_DECL for the indicated DECL using the template
     parameters given by current_template_args, or reuses a
     previously existing one, if appropriate.  Returns the DECL, or an
--- 1832,2036 ----
      }
  
    if (level == tpd->level)
!     {
!       tpd->parms[idx] = 1;
!       tpd->arg_uses_template_parms[tpd->current_arg] = 1;
!     }
  
    /* Return zero so that for_each_template_parm will continue the
       traversal of the tree; we want to mark *every* template parm.  */
    return 0;
  }
  
+ /* Process the partial specialization DECL.  */
+ 
+ tree
+ process_partial_specialization (decl)
+      tree decl;
+ {
+   tree type = TREE_TYPE (decl);
+   tree maintmpl = CLASSTYPE_TI_TEMPLATE (type);
+   tree specargs = CLASSTYPE_TI_ARGS (type);
+   tree inner_args = innermost_args (specargs);
+   tree inner_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+   tree main_inner_parms = DECL_INNERMOST_TEMPLATE_PARMS (maintmpl);
+   int nargs = TREE_VEC_LENGTH (inner_args);
+   int ntparms = TREE_VEC_LENGTH (inner_parms);
+   int  i;
+   int did_error_intro = 0;
+   int issued_default_arg_message = 0;
+   struct template_parm_data tpd;
+   struct template_parm_data tpd2;
+ 
+   /* [temp.class.spec]
+      
+      The template parameter list of a specialization shall not
+      contain default template argument values.  */
+   for (i = 0; i < ntparms; ++i) 
+     {
+       if (TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)))
+ 	{
+ 	  if (!issued_default_arg_message)
+ 	    {
+ 	      cp_error ("default argument in partial specialization `%T'", 
+ 			type);
+ 	      issued_default_arg_message = 1;
+ 	    }
+ 	  TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)) = NULL_TREE;
+ 	}
+     }
+ 
+   /* We check that each of the template parameters given in the
+      partial specialization is used in the argument list to the
+      specialization.  For example:
+ 
+        template <class T> struct S;
+        template <class T> struct S<T*>;
+ 
+      The second declaration is OK because `T*' uses the template
+      parameter T, whereas
+ 
+        template <class T> struct S<int>;
+ 
+      is no good.  Even trickier is:
+ 
+        template <class T>
+        struct S1
+        {
+ 	  template <class U>
+ 	  struct S2;
+ 	  template <class U>
+ 	  struct S2<T>;
+        };
+ 
+      The S2<T> declaration is actually illegal; it is a
+      full-specialization.  Of course, 
+ 
+ 	  template <class U>
+ 	  struct S2<T (*)(U)>;
+ 
+      or some such would have been OK.  */
+   tpd.level = TMPL_PARMS_DEPTH (current_template_parms);
+   tpd.parms = alloca (sizeof (int) * ntparms);
+   bzero (tpd.parms, sizeof (int) * nargs);
+ 
+   tpd.arg_uses_template_parms = alloca (sizeof (int) * nargs);
+   bzero (tpd.arg_uses_template_parms, sizeof (int) * nargs);
+   for (i = 0; i < nargs; ++i)
+     {
+       tpd.current_arg = i;
+       for_each_template_parm (TREE_VEC_ELT (inner_args, i),
+ 			      &mark_template_parm,
+ 			      &tpd);
+     }
+   for (i = 0; i < ntparms; ++i)
+     if (tpd.parms[i] == 0)
+       {
+ 	/* One of the template parms was not used in the
+            specialization.  */
+ 	if (!did_error_intro)
+ 	  {
+ 	    cp_error ("template parameters not used in partial specialization:");
+ 	    did_error_intro = 1;
+ 	  }
+ 
+ 	cp_error ("        `%D'", 
+ 		  TREE_VALUE (TREE_VEC_ELT (inner_parms, i)));
+       }
+ 
+   /* [temp.class.spec]
+ 
+      The argument list of the specialization shall not be identical to
+      the implicit argument list of the primary template.  */
+   if (comp_template_args (inner_args, 
+ 			  innermost_args (CLASSTYPE_TI_ARGS (TREE_TYPE
+ 							     (maintmpl)))))
+     cp_error ("partial specialization `%T' does not specialize any template arguments", type);
+ 
+   /* [temp.class.spec]
+ 
+      A partially specialized non-type argument expression shall not
+      involve template parameters of the partial specialization except
+      when the argument expression is a simple identifier.
+ 
+      The type of a template parameter corresponding to a specialized
+      non-type argument shall not be dependent on a parameter of the
+      specialization.  */
+   my_friendly_assert (nargs == DECL_NTPARMS (maintmpl), 0);
+   tpd2.parms = 0;
+   for (i = 0; i < nargs; ++i)
+     {
+       tree arg = TREE_VEC_ELT (inner_args, i);
+       if (/* These first two lines are the `non-type' bit.  */
+ 	  TREE_CODE_CLASS (TREE_CODE (arg)) != 't'
+ 	  && TREE_CODE (arg) != TEMPLATE_DECL
+ 	  /* This next line is the `argument expression is not just a
+ 	     simple identifier' condition and also the `specialized
+ 	     non-type argument' bit.  */
+ 	  && TREE_CODE (arg) != TEMPLATE_PARM_INDEX)
+ 	{
+ 	  if (tpd.arg_uses_template_parms[i])
+ 	    cp_error ("template argument `%E' involves template parameter(s)", arg);
+ 	  else 
+ 	    {
+ 	      /* Look at the corresponding template parameter,
+ 		 marking which template parameters its type depends
+ 		 upon.  */
+ 	      tree type = 
+ 		TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (main_inner_parms, 
+ 						     i)));
+ 
+ 	      if (!tpd2.parms)
+ 		{
+ 		  /* We haven't yet initialized TPD2.  Do so now.  */
+ 		  tpd2.arg_uses_template_parms 
+ 		    =  (int*) alloca (sizeof (int) * nargs);
+ 		  tpd2.parms = (int*) alloca (sizeof (int) * nargs);
+ 		  tpd2.level = 
+ 		    TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl));
+ 		}
+ 
+ 	      /* Mark the template paramters.  But this time, we're
+ 		 looking for the template parameters of the main
+ 		 template, not in the specialization.  */
+ 	      tpd2.current_arg = i;
+ 	      tpd2.arg_uses_template_parms[i] = 0;
+ 	      bzero (tpd.parms, sizeof (int) * nargs);
+ 	      for_each_template_parm (type,
+ 				      &mark_template_parm,
+ 				      &tpd2);
+ 		  
+ 	      if (tpd2.arg_uses_template_parms [i])
+ 		{
+ 		  /* The type depended on some template parameters.
+ 		     If they are fully specialized in the
+ 		     specialization, that's OK.  */
+ 		  int j;
+ 		  for (j = 0; j < nargs; ++j)
+ 		    if (tpd2.parms[j] != 0
+ 			&& tpd.arg_uses_template_parms [j])
+ 		      {
+ 			cp_error ("type `%T' of template argument `%E' depends on template paramter(s)", 
+ 				  type,
+ 				  arg);
+ 			break;
+ 		      }
+ 		}
+ 	    }
+ 	}
+     }
+ 
+   if (retrieve_specialization (maintmpl, specargs))
+     /* We've already got this specialization.  */
+     return decl;
+ 
+   DECL_TEMPLATE_SPECIALIZATIONS (maintmpl) = CLASSTYPE_TI_SPEC_INFO (type)
+     = perm_tree_cons (inner_args, inner_parms,
+ 		      DECL_TEMPLATE_SPECIALIZATIONS (maintmpl));
+   TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type;
+   return decl;
+ }
+ 
  /* Creates a TEMPLATE_DECL for the indicated DECL using the template
     parameters given by current_template_args, or reuses a
     previously existing one, if appropriate.  Returns the DECL, or an
*************** push_template_decl_real (decl, is_friend
*** 1868,1960 ****
    if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)
        && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
        && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
!     {
!       tree type = TREE_TYPE (decl);
!       tree maintmpl = CLASSTYPE_TI_TEMPLATE (type);
!       tree specargs = CLASSTYPE_TI_ARGS (type);
! 
!       /* We check that each of the template parameters given in the
! 	 partial specialization is used in the argument list to the
! 	 specialization.  For example:
! 	 
! 	   template <class T> struct S;
! 	   template <class T> struct S<T*>;
! 
! 	 The second declaration is OK because `T*' uses the template
! 	 parameter T, whereas
!        
!            template <class T> struct S<int>;
! 
! 	 is no good.  Even trickier is:
  
- 	   template <class T>
- 	   struct S1
- 	   {
- 	      template <class U>
- 	      struct S2;
- 	      template <class U>
- 	      struct S2<T>;
- 	   };
- 	   
- 	 The S2<T> declaration is actually illegal; it is a
- 	 full-specialization.  Of course, 
- 
-               template <class U>
-               struct S2<T (*)(U)>;
- 
-          or some such would have been OK.  */
-       int  i;
-       struct template_parm_data tpd;
-       int ntparms 
- 	= TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS (current_template_parms));
-       int did_error_intro = 0;
- 
-       tpd.level = TMPL_PARMS_DEPTH (current_template_parms);
-       tpd.parms = alloca (sizeof (int) * ntparms);
-       for (i = 0; i < ntparms; ++i)
- 	tpd.parms[i] = 0;
-       for (i = 0; i < TREE_VEC_LENGTH (specargs); ++i)
- 	for_each_template_parm (TREE_VEC_ELT (specargs, i),
- 				&mark_template_parm,
- 				&tpd);
-       for (i = 0; i < ntparms; ++i)
- 	if (tpd.parms[i] == 0)
- 	  {
- 	    /* One of the template parms was not used in the
- 	       specialization.  */
- 	    if (!did_error_intro)
- 	      {
- 		cp_error ("template parameters not used in partial specialization:");
- 		did_error_intro = 1;
- 	      }
- 
- 	    cp_error ("        `%D'", 
- 		      TREE_VALUE (TREE_VEC_ELT 
- 				  (TREE_VALUE (current_template_parms),
- 				   i)));
- 	  }
- 
-       /* [temp.class.spec]
- 
- 	 The argument list of the specialization shall not be
- 	 identical to the implicit argument list of the primary
- 	 template.  */
-       if (comp_template_args (specargs, 
- 			      CLASSTYPE_TI_ARGS (TREE_TYPE (maintmpl))))
- 	cp_error ("partial specialization `%T' does not specialize any template arguments", type);
- 			   
-       if (retrieve_specialization (maintmpl, specargs))
- 	/* We've already got this specialization.  */
- 	return decl;
- 
-       DECL_TEMPLATE_SPECIALIZATIONS (maintmpl) = CLASSTYPE_TI_SPEC_INFO (type)
- 	= perm_tree_cons (innermost_args (specargs),
- 			  INNERMOST_TEMPLATE_PARMS (current_template_parms),
- 			  DECL_TEMPLATE_SPECIALIZATIONS (maintmpl));
-       TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type;
-       return decl;
-     }
- 
    args = current_template_args ();
  
    if (!ctx 
--- 2102,2109 ----
    if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)
        && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
        && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
!     return process_partial_specialization (decl);
  
    args = current_template_args ();
  
    if (!ctx 
*************** tsubst_decl (t, args, type, in_decl)
*** 5194,5200 ****
    return r;
  }
  
- 
  /* Substitue into the ARG_TYPES of a function type.  */
  
  tree
--- 5343,5348 ----
*************** tsubst_arg_types (arg_types, args, in_de
*** 5204,5210 ****
       tree in_decl;
  {
    tree remaining_arg_types;
-   tree result;
    tree type;
  
    if (!arg_types || arg_types == void_list_node)
--- 5352,5357 ----
Index: cp/semantics.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/semantics.c,v
retrieving revision 1.27
diff -c -p -r1.27 semantics.c
*** semantics.c	1998/09/03 19:42:06	1.27
--- semantics.c	1998/09/06 02:19:58
*************** begin_class_definition (t)
*** 1234,1242 ****
        && TREE_CODE (TYPE_CONTEXT (t)) != NAMESPACE_DECL
        && ! current_class_type)
      push_template_decl (TYPE_STUB_DECL (t));
    pushclass (t, 0);
    TYPE_BEING_DEFINED (t) = 1;
-   maybe_process_partial_specialization (t);
    /* Reset the interface data, at the earliest possible
       moment, as it might have been set via a class foo;
       before.  */
--- 1234,1242 ----
        && TREE_CODE (TYPE_CONTEXT (t)) != NAMESPACE_DECL
        && ! current_class_type)
      push_template_decl (TYPE_STUB_DECL (t));
+   maybe_process_partial_specialization (t);
    pushclass (t, 0);
    TYPE_BEING_DEFINED (t) = 1;
    /* Reset the interface data, at the earliest possible
       moment, as it might have been set via a class foo;
       before.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]