Patch for specializations of static members, and other problems

Mark Mitchell mmitchell@usa.net
Thu Jan 29 16:50:00 GMT 1998


Jason --

  Here's a patch that fixes problems reported by the folks above:
mostly compiler crashes or spurious errors, but one actual
code-generation problem with code like this:

  int i;
  int j = i++;

at file scope: i was not being incremented!

  It's in a slightly unusual format.  There are actually two patches
below: one for the cp directory, and one for the testsuite.  The
reason is that I wanted to make diffs against the current state of the
repository since I wasn't sure exactly what form the stuff I'd sent
you lately had ended up in.  Search for `CUT HERE' to find the
separation betwen the two patches.

-- 
Mark Mitchell		mmitchell@usa.net
Stanford University	http://www.stanford.edu

Thu Jan 29 16:19:39 1998  Mark Mitchell  <mmitchell@usa.net>

	* call.c (add_template_candidate_real): Pass extra parameter to
	fn_type_unification. 
	* cp-tree.h (DECL_NONSTATIC_FUNCTION_MEMBER_P): New macro.	
	(revert_static_member_fn): Declare.
	(fn_type_unification): Add parameter.
	* decl.c (revert_static_member_fn): Remove declaration.  Change
	linkage from internal to external.
	(lookup_name_real): Do not assume all contexts are type contexts 
	when considering making an implicit typename.
	(cp_finish_decl): Deal with virtual functions in classes local to
	template functions.
	* decl2.c (finish_file): Don't forget to emit increment/decrement
	expressions in initializers for file-scope variables.
	* parse.y (typename_sub2): If the typename doesn't names a
	template, rather than a type, issue an error message.
	* pt.c (check_explicit_specialization): Handle specializations of
	static member functions.
	(coerce_template_parms): Handle offset references to lists of
	member functions.
	(fn_type_unification): Add additional parameter to deal with
	static member functions.
	(get_bindings): Deal with static member functions.
	* search.c (note_debug_info_needed): Don't crash when handed a
	type which is being defined.
	* typeck.c (complete_type): Don't crash when handed NULL_TREE;
	that can happen with some illegal code.

diff -c -p ./call.c /home/mitchell/projects/egcs/gcc/cp/call.c
*** ./call.c	Tue Jan 27 22:53:38 1998
--- /home/mitchell/projects/egcs/gcc/cp/call.c	Thu Jan 29 14:46:50 1998
*************** add_template_candidate_real (candidates,
*** 4176,4182 ****
    tree fn;
  
    i = fn_type_unification (tmpl, explicit_targs, targs, arglist,
! 			   return_type, 0); 
  
    if (i != 0)
      return candidates;
--- 4176,4182 ----
    tree fn;
  
    i = fn_type_unification (tmpl, explicit_targs, targs, arglist,
! 			   return_type, 0, NULL_TREE); 
  
    if (i != 0)
      return candidates;
diff -c -p ./cp-tree.h /home/mitchell/projects/egcs/gcc/cp/cp-tree.h
*** ./cp-tree.h	Wed Jan 28 12:03:11 1998
--- /home/mitchell/projects/egcs/gcc/cp/cp-tree.h	Thu Jan 29 14:46:27 1998
*************** struct lang_decl
*** 1020,1029 ****
    (TREE_CODE (NODE) == VAR_DECL || TREE_CODE (NODE) == TYPE_DECL \
     || TREE_CODE (NODE) == CONST_DECL)
  				
  /* Nonzero for FUNCTION_DECL means that this decl is a member function
     (static or non-static).  */
  #define DECL_FUNCTION_MEMBER_P(NODE) \
!  (TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE || DECL_STATIC_FUNCTION_P (NODE))
  
  /* Nonzero for FUNCTION_DECL means that this member function
     has `this' as const X *const.  */
--- 1020,1034 ----
    (TREE_CODE (NODE) == VAR_DECL || TREE_CODE (NODE) == TYPE_DECL \
     || TREE_CODE (NODE) == CONST_DECL)
  				
+ /* Nonzero for FUNCTION_DECL means that this decl is a non-static
+    member function.  */
+ #define DECL_NONSTATIC_FUNCTION_MEMBER_P(NODE) \
+   (TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE)
+ 
  /* Nonzero for FUNCTION_DECL means that this decl is a member function
     (static or non-static).  */
  #define DECL_FUNCTION_MEMBER_P(NODE) \
!  (DECL_NONSTATIC_FUNCTION_MEMBER_P(NODE) || DECL_STATIC_FUNCTION_P (NODE))
  
  /* Nonzero for FUNCTION_DECL means that this member function
     has `this' as const X *const.  */
*************** extern int in_function_p			PROTO((void))
*** 2119,2124 ****
--- 2124,2130 ----
  extern void replace_defarg			PROTO((tree, tree));
  extern void print_other_binding_stack		PROTO((struct binding_level *));
  extern tree strip_attrs				PROTO((tree));
+ extern void revert_static_member_fn             PROTO((tree*, tree*, tree*));
  
  /* in decl2.c */
  extern int flag_assume_nonnull_objects;
*************** extern int uses_template_parms			PROTO((
*** 2347,2353 ****
  extern tree instantiate_class_template		PROTO((tree));
  extern tree instantiate_template		PROTO((tree, tree));
  extern void overload_template_name		PROTO((tree));
! extern int fn_type_unification                  PROTO((tree, tree, tree, tree, tree, int));
  extern int type_unification			PROTO((tree, tree *, tree, tree, tree, int *, int, int));
  struct tinst_level *tinst_for_decl		PROTO((void));
  extern void mark_decl_instantiated		PROTO((tree, int));
--- 2353,2359 ----
  extern tree instantiate_class_template		PROTO((tree));
  extern tree instantiate_template		PROTO((tree, tree));
  extern void overload_template_name		PROTO((tree));
! extern int fn_type_unification                  PROTO((tree, tree, tree, tree, tree, int, tree));
  extern int type_unification			PROTO((tree, tree *, tree, tree, tree, int *, int, int));
  struct tinst_level *tinst_for_decl		PROTO((void));
  extern void mark_decl_instantiated		PROTO((tree, int));
diff -c -p ./decl.c /home/mitchell/projects/egcs/gcc/cp/decl.c
*** ./decl.c	Wed Jan 28 12:03:11 1998
--- /home/mitchell/projects/egcs/gcc/cp/decl.c	Thu Jan 29 14:32:13 1998
*************** static struct stack_level *decl_stack;
*** 136,142 ****
  static tree grokparms				PROTO((tree, int));
  static tree lookup_nested_type			PROTO((tree, tree));
  static char *redeclaration_error_message	PROTO((tree, tree));
- static void revert_static_member_fn		PROTO((tree *, tree *, tree *));
  static tree push_overloaded_decl		PROTO((tree, int));
  static void push_overloaded_decl_top_level	PROTO((tree, int));
  
--- 136,141 ----
*************** lookup_name_real (name, prefer_type, non
*** 4622,4627 ****
--- 4621,4627 ----
        if (processing_template_decl
  	  && classval && TREE_CODE (classval) == TYPE_DECL
  	  && DECL_CONTEXT (classval) != current_class_type
+ 	  && hack_decl_function_context (classval) == NULL_TREE
  	  && uses_template_parms (DECL_CONTEXT (classval))
  	  && ! DECL_ARTIFICIAL (classval))
  	{
*************** cp_finish_decl (decl, init, asmspec_tree
*** 6495,6502 ****
  	{
  	  tree stmt = DECL_VINDEX (decl);
  	  /* If the decl is declaring a member of a local class (in a
! 	     template function), there will be no associated stmt.  */
! 	  if (stmt != NULL_TREE)
  	    {
  	      DECL_VINDEX (decl) = NULL_TREE;
  	      TREE_OPERAND (stmt, 2) = copy_to_permanent (init);
--- 6495,6504 ----
  	{
  	  tree stmt = DECL_VINDEX (decl);
  	  /* If the decl is declaring a member of a local class (in a
! 	     template function), the DECL_VINDEX will either be NULL,
! 	     or it will be an actual virtual function index, not a
! 	     DECL_STMT.  */
! 	  if (stmt != NULL_TREE && TREE_CODE (stmt) == DECL_STMT)
  	    {
  	      DECL_VINDEX (decl) = NULL_TREE;
  	      TREE_OPERAND (stmt, 2) = copy_to_permanent (init);
*************** finish_stmt ()
*** 13008,13014 ****
     (TREE_TYPE (decl)) to ARGTYPES, as doing so will corrupt the types of
     other decls.  Either pass the addresses of local variables or NULL.  */
  
! static void
  revert_static_member_fn (decl, fn, argtypes)
       tree *decl, *fn, *argtypes;
  {
--- 13010,13016 ----
     (TREE_TYPE (decl)) to ARGTYPES, as doing so will corrupt the types of
     other decls.  Either pass the addresses of local variables or NULL.  */
  
! void
  revert_static_member_fn (decl, fn, argtypes)
       tree *decl, *fn, *argtypes;
  {
diff -c -p ./decl2.c /home/mitchell/projects/egcs/gcc/cp/decl2.c
*** ./decl2.c	Thu Jan 29 00:22:48 1998
--- /home/mitchell/projects/egcs/gcc/cp/decl2.c	Thu Jan 29 10:57:19 1998
*************** finish_file ()
*** 3139,3144 ****
--- 3139,3148 ----
  		}
  	      else
  		expand_assignment (decl, init, 0, 0);
+ 	      
+ 	      /* The expression might have involved increments and
+ 		 decrements.  */
+ 	      emit_queue ();
  
  	      /* Cleanup any temporaries needed for the initial value.  */
  	      expand_end_target_temps ();
diff -c -p ./parse.y /home/mitchell/projects/egcs/gcc/cp/parse.y
*** ./parse.y	Thu Jan 29 00:23:02 1998
--- /home/mitchell/projects/egcs/gcc/cp/parse.y	Thu Jan 29 16:17:45 1998
*************** typename_sub2:
*** 3308,3315 ****
  	  TYPENAME SCOPE
  		{
  		  if (TREE_CODE ($1) != IDENTIFIER_NODE)
! 		    $$ = lastiddecl;
! 		  got_scope = $$ = complete_type (TREE_TYPE ($$));
  		}
  	| SELFNAME SCOPE
  		{
--- 3308,3319 ----
  	  TYPENAME SCOPE
  		{
  		  if (TREE_CODE ($1) != IDENTIFIER_NODE)
! 		    $1 = lastiddecl;
! 
! 		  got_scope = $$ = complete_type (TREE_TYPE ($1));
! 
! 		  if ($$ == error_mark_node)
! 		    cp_error ("`%T' is not a class or namespace", $1);
  		}
  	| SELFNAME SCOPE
  		{
diff -c -p ./pt.c /home/mitchell/projects/egcs/gcc/cp/pt.c
*** ./pt.c	Thu Jan 29 15:51:45 1998
--- /home/mitchell/projects/egcs/gcc/cp/pt.c	Thu Jan 29 15:47:19 1998
*************** check_explicit_specialization (declarato
*** 866,871 ****
--- 866,874 ----
  		SET_DECL_EXPLICIT_INSTANTIATION (decl);
  	      return decl;
  	    }
+ 	  else if (DECL_STATIC_FUNCTION_P (tmpl)
+ 		   && DECL_NONSTATIC_FUNCTION_MEMBER_P (decl))
+ 	    revert_static_member_fn (&decl, 0, 0);
  
  	  /* Mangle the function name appropriately.  Note that we do
  	     not mangle specializations of non-template member
*************** coerce_template_parms (parms, arglist, i
*** 1820,1830 ****
  	  continue;
  	}
  
!       /* In case we are checking arguments inside a template template
! 	 parameter, ARG that does not come from default argument is 
! 	 also a TREE_LIST node */
!       if (TREE_CODE (arg) == TREE_LIST && ! is_overloaded_fn (arg))
  	{
            is_tmpl_parm = 1;
  	  arg = TREE_VALUE (arg);
  	}
--- 1827,1849 ----
  	  continue;
  	}
  
!       if (TREE_CODE (arg) == TREE_LIST 
! 	  && TREE_TYPE (arg) != NULL_TREE
! 	  && TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
! 	{  
! 	  /* The template argument was the name of some
! 	     member function.  That's usually
! 	     illegal, but static members are OK.  In any
! 	     case, grab the underlying fields/functions
! 	     and issue an error later if required.  */
! 	  arg = TREE_VALUE (arg);
! 	  TREE_TYPE (arg) = unknown_type_node;
! 	}
!       else if (TREE_CODE (arg) == TREE_LIST && ! is_overloaded_fn (arg))
  	{
+ 	  /* In case we are checking arguments inside a template template
+ 	     parameter, ARG that does not come from default argument is 
+ 	     also a TREE_LIST node */
            is_tmpl_parm = 1;
  	  arg = TREE_VALUE (arg);
  	}
*************** overload_template_name (type)
*** 4584,4596 ****
    pushdecl_class_level (decl);
  }
  
  /* Like type_unification but designed specially to handle conversion
!    operators.  */
  
  int
! fn_type_unification (fn, explicit_targs, targs, args, return_type, strict)
       tree fn, explicit_targs, targs, args, return_type;
       int strict;
  {
    int i, dummy = 0;
    tree fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
--- 4606,4622 ----
    pushdecl_class_level (decl);
  }
  
+ 
  /* Like type_unification but designed specially to handle conversion
!    operators.  The EXTRA_FN_ARG, if any, is the type of an additional
!    parameter to be added to the beginning of FN's parameter list.  */
  
  int
! fn_type_unification (fn, explicit_targs, targs, args, return_type,
! 		     strict, extra_fn_arg)
       tree fn, explicit_targs, targs, args, return_type;
       int strict;
+      tree extra_fn_arg;
  {
    int i, dummy = 0;
    tree fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
*************** fn_type_unification (fn, explicit_targs,
*** 4603,4615 ****
        /* This is a template conversion operator.  Use the return types
           as well as the argument types.  */
        fn_arg_types = scratch_tree_cons (NULL_TREE, 
! 				TREE_TYPE (TREE_TYPE (fn)),
! 				fn_arg_types);
        decl_arg_types = scratch_tree_cons (NULL_TREE,
! 				  return_type,
! 				  decl_arg_types);
      }
  
    i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn), 
  			&TREE_VEC_ELT (targs, 0), 
  			fn_arg_types,
--- 4629,4645 ----
        /* This is a template conversion operator.  Use the return types
           as well as the argument types.  */
        fn_arg_types = scratch_tree_cons (NULL_TREE, 
! 					TREE_TYPE (TREE_TYPE (fn)),
! 					fn_arg_types);
        decl_arg_types = scratch_tree_cons (NULL_TREE,
! 					  return_type,
! 					  decl_arg_types);
      }
  
+   if (extra_fn_arg != NULL_TREE)
+     fn_arg_types = scratch_tree_cons (NULL_TREE, extra_fn_arg,
+ 				      fn_arg_types); 
+ 
    i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn), 
  			&TREE_VEC_ELT (targs, 0), 
  			fn_arg_types,
*************** get_bindings (fn, decl, explicit_args)
*** 5247,5258 ****
  {
    int ntparms = DECL_NTPARMS (fn);
    tree targs = make_scratch_vec (ntparms);
    int i;
  
    i = fn_type_unification (fn, explicit_args, targs, 
! 			   TYPE_ARG_TYPES (TREE_TYPE (decl)), 
  			   TREE_TYPE (TREE_TYPE (decl)),
! 			   1);
  
    if (i == 0)
      {
--- 5277,5311 ----
  {
    int ntparms = DECL_NTPARMS (fn);
    tree targs = make_scratch_vec (ntparms);
+   tree decl_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
+   tree extra_fn_arg = NULL_TREE;
    int i;
  
+   if (DECL_STATIC_FUNCTION_P (fn) 
+       && DECL_NONSTATIC_FUNCTION_MEMBER_P (decl))
+     {
+       /* Sometimes we are trying to figure out what's being
+ 	 specialized by a declaration that looks like a method, and it
+ 	 turns out to be a static member function.  */
+       if (CLASSTYPE_TEMPLATE_INFO (DECL_REAL_CONTEXT (fn))
+ 	  && !is_member_template (fn))
+ 	/* The natural thing to do here seems to be to remove the
+ 	   spurious `this' parameter from the DECL, but that prevents
+ 	   unification from making use of the class type.  So,
+ 	   instead, we have fn_type_unification add to the parameters
+ 	   for FN.  */
+ 	extra_fn_arg = build_pointer_type (DECL_REAL_CONTEXT (fn));
+       else
+ 	/* In this case, though, adding the extra_fn_arg can confuse
+ 	   things, so we remove from decl_arg_types instead.  */
+ 	decl_arg_types = TREE_CHAIN (decl_arg_types);
+     }
+ 
    i = fn_type_unification (fn, explicit_args, targs, 
! 			   decl_arg_types,
  			   TREE_TYPE (TREE_TYPE (decl)),
! 			   1,
! 			   extra_fn_arg);
  
    if (i == 0)
      {
diff -c -p ./search.c /home/mitchell/projects/egcs/gcc/cp/search.c
*** ./search.c	Thu Jan 22 21:35:30 1998
--- /home/mitchell/projects/egcs/gcc/cp/search.c	Thu Jan 29 10:14:39 1998
*************** note_debug_info_needed (type)
*** 3220,3225 ****
--- 3220,3229 ----
  
    if (current_template_parms)
      return;
+     
+   if (TYPE_BEING_DEFINED (type))
+     /* We can't go looking for the base types and fields just yet.  */
+     return;
  
    /* We can't do the TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
       does not support name references between translation units.  Well, we
diff -c -p ./typeck.c /home/mitchell/projects/egcs/gcc/cp/typeck.c
*** ./typeck.c	Thu Jan 29 00:23:02 1998
--- /home/mitchell/projects/egcs/gcc/cp/typeck.c	Thu Jan 29 10:11:50 1998
*************** tree
*** 134,139 ****
--- 134,144 ----
  complete_type (type)
       tree type;
  {
+   if (type == NULL_TREE)
+     /* Rather than crash, we return something sure to cause an error
+        at some point.  */
+     return error_mark_node;
+ 
    if (type == error_mark_node || TYPE_SIZE (type) != NULL_TREE)
      ;
    else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))

------------------------CUT HERE-----------------

Index: gcc/testsuite/g++.old-deja/g++.other/init1.C
===================================================================
RCS file: init1.C
diff -N init1.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- init1.C	Thu Jan 29 10:56:02 1998
***************
*** 0 ****
--- 1,10 ----
+ extern "C" void abort();
+ 
+ int i;
+ int j = i++;
+ 
+ int main()
+ {
+   if (i != 1)
+     abort();
+ }
Index: gcc/testsuite/g++.old-deja/g++.pt/crash1.C
===================================================================
RCS file: crash1.C
diff -N crash1.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- /tmp/cvs27039caa	Thu Jan 29 16:15:09 1998
***************
*** 0 ****
--- 1,11 ----
+ template<class T> class A {
+     public:
+         class subA {};
+ };
+ 
+ 
+ template<class T> class B : public A<T> {
+     public:
+   class subB : public A::subA {}; // ERROR - not a class or namespace
+ };
+  
Index: gcc/testsuite/g++.old-deja/g++.pt/crash2.C
===================================================================
RCS file: crash2.C
diff -N crash2.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- crash2.C	Thu Jan 29 15:43:14 1998
***************
*** 0 ****
--- 1,14 ----
+ // Build don't link:
+ 
+ template <class T> 
+ struct S1
+ {
+   T* t;
+   static int foo;
+ };
+ 
+ 
+ struct S2 : public S1<S2>
+ {
+   S2* s;
+ };
Index: gcc/testsuite/g++.old-deja/g++.pt/explicit66.C
===================================================================
RCS file: explicit66.C
diff -N explicit66.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- /tmp/cvs27039daa	Thu Jan 29 16:15:10 1998
***************
*** 0 ****
--- 1,11 ----
+ void f(int) {}
+ void f(double);
+ 
+ template <void (*fn)(int)>
+ void foo() {}
+ 
+ int main()
+ {
+   foo<f>();
+ }
+ 
Index: gcc/testsuite/g++.old-deja/g++.pt/explicit67.C
===================================================================
RCS file: explicit67.C
diff -N explicit67.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- /tmp/cvs27039eaa	Thu Jan 29 16:15:10 1998
***************
*** 0 ****
--- 1,20 ----
+ struct S
+ {
+   void f(int);
+   void f(double);
+ };
+ 
+ void g(int);
+ void g(double);
+ 
+ template <int* IP>
+ void foo();
+ template <long l>
+ void foo();
+ 
+ void bar()
+ {
+   foo<S::f>(); // ERROR - no matching function
+   foo<g>();    // ERROR - no matching function
+   
+ }
Index: gcc/testsuite/g++.old-deja/g++.pt/local6.C
===================================================================
RCS file: local6.C
diff -N local6.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- /tmp/cvs27039faa	Thu Jan 29 16:15:11 1998
***************
*** 0 ****
--- 1,24 ----
+ extern "C" void abort();
+ 
+ template <class T>
+ int f(T)
+ {
+   struct S1 {
+     virtual int foo() { return 1; }
+   };
+ 
+   struct S2 : public S1 {
+     int foo() { return 2; }
+   };
+ 
+   S1* s2 = new S2;
+ 
+   return s2->foo();
+ }
+ 
+ 
+ int main()
+ {
+   if (f(3) != 2)
+     abort();
+ }
Index: gcc/testsuite/g++.old-deja/g++.pt/spec14.C
===================================================================
RCS file: spec14.C
diff -N spec14.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- /tmp/cvs27039haa	Thu Jan 29 16:15:12 1998
***************
*** 0 ****
--- 1,9 ----
+ class X
+ {
+ public:
+   template <typename A, typename B, typename C>
+   X() {}
+   
+   template <typename A, typename B>
+   X::X<A, void, B>() {} // ERROR - non-template type used as a template
+ };
Index: gcc/testsuite/g++.old-deja/g++.pt/spec15.C
===================================================================
RCS file: spec15.C
diff -N spec15.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- spec15.C	Thu Jan 29 15:21:49 1998
***************
*** 0 ****
--- 1,49 ----
+ extern "C" void abort();
+ 
+ template <class T>
+ struct S1
+ {
+   static void f();
+ };
+ 
+ template <>
+ void S1<int>::f() {}
+ 
+ struct S2
+ {
+   template <class T>
+   static void g(T);
+ };
+ 
+ template <>
+ void S2::g(double) {}
+ 
+ template <>
+ void S2::g<int>(int) {}
+ 
+ template <class T>
+ struct S3
+ {
+   template <class U>
+   static int h(U);
+ };
+ 
+ template <class T>
+ template <>
+ int S3<T>::h(int) { return 0; }
+ 
+ template <>
+ template <>
+ int S3<char>::h(int) { return 1; }
+ 
+ int main()
+ {
+   S1<int>::f();
+   S2::g(3.0);
+   S2::g(7);
+ 
+   if (S3<double>::h(7) != 0) 
+     abort();
+   if (S3<char>::h(7) != 1)
+     abort();
+ }



More information about the Gcc-bugs mailing list