PATCH for miscellaneous improvements

Mark Mitchell mark@markmitchell.com
Fri Aug 7 16:34:00 GMT 1998


This patch fixes a few small problems:

  o We no longer allow the declaration of bitfields with function
    type.
  o The destruction of static data members whose destructors are
    private is permitted.
  o Crashes on certain programs making use of `typename' are avoided.

In addition, this patch improves the reporting of errors during
template instantiation.  Previously many errors were reported at the
instantiation site, like:

  template <class T>
  struct S {
     T* t;
  };

  template struct S<int&>; // ERROR: Cannnot form pointer to reference

Now, the error is associated with the declaration of `t'.  (Of course,
the `instantiated from here' message still appears at the point of
instantiation.)

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

1998-08-07  Mark Mitchell  <mark@markmitchell.com>

	* typeck.c (require_complete_type): Use complete_type_or_else.
	(complete_type_or_else): Always return NULL_TREE on failure, as
	documented.

	* pt.c (tsubst_aggr_type): Prototype.
	(tsubst_decl): New function, split out from tsubst.  Set
	input_filename and lineno as appropriate.
	(pop_tinst_level): Restore the file and line number saved in
	push_tinst_level.
	(instantiate_class_template): Set input_filename and lineno as
	appropriate.
	(tsubst): Move _DECL processing to tsubst_decl.  Make sure the
	context for a TYPENAME_TYPE is complete.

	* decl2.c (grokbitfield): Issue errors on bitfields declared with
	function type.
	(do_dtors): As in do_ctors, pretend to be a member of the same
	class as a static data member while generating a call to its
	destructor.

Index: testsuite/g++.old-deja/g++.other/dtor2.C
===================================================================
RCS file: dtor2.C
diff -N dtor2.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- dtor2.C	Fri Aug  7 16:26:22 1998
***************
*** 0 ****
--- 1,13 ----
+ // Build don't link:
+ 
+ class K {
+ public:
+   friend class C;
+ 
+ private:
+   static K qwe;
+   K();
+   ~K();
+ }; 
+ 
+ K K::qwe;
Index: testsuite/g++.old-deja/g++.bugs/900402_01.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.bugs/900402_01.C,v
retrieving revision 1.1.1.1
diff -c -p -r1.1.1.1 900402_01.C
*** 900402_01.C	1997/08/19 07:35:13	1.1.1.1
--- 900402_01.C	1998/08/07 22:24:57
***************
*** 9,15 ****
  typedef void (func_type) ();
  
  struct s {
!   func_type f:32;	// ERROR - XFAIL *-*-*
  };
  
  int main () { return 0; }
--- 9,15 ----
  typedef void (func_type) ();
  
  struct s {
!   func_type f:32;	// ERROR - bitified with function type
  };
  
  int main () { return 0; }
Index: testsuite/g++.old-deja/g++.law/visibility13.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.law/visibility13.C,v
retrieving revision 1.2
diff -c -p -r1.2 visibility13.C
*** visibility13.C	1997/11/13 09:36:10	1.2
--- visibility13.C	1998/08/07 22:25:01
***************
*** 14,20 ****
  const int ArraySize = 12;
  
  template <class Type>
! class Array {
  friend class Array_RC;
  public:
      Array(const Type *ar, int sz) { init(ar,sz); }
--- 14,20 ----
  const int ArraySize = 12;
  
  template <class Type>
! class Array { // ERROR - .struct Array_RC redecl.*
  friend class Array_RC;
  public:
      Array(const Type *ar, int sz) { init(ar,sz); }
*************** try_array( Array_RC<Type> &rc )
*** 97,103 ****
  main()
  {
      static int ia[10] = { 12, 7, 14, 9, 128, 17, 6, 3, 27, 5 };
!     Array_RC<int> iA(ia, 10);// ERROR - .struct Array_RC redecl.*
  
      cout << "template Array_RC class" << endl;
      try_array(iA);
--- 97,103 ----
  main()
  {
      static int ia[10] = { 12, 7, 14, 9, 128, 17, 6, 3, 27, 5 };
!     Array_RC<int> iA(ia, 10);// ERROR - instantiated from here
  
      cout << "template Array_RC class" << endl;
      try_array(iA);
Index: testsuite/g++.old-deja/g++.pt/friend23.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/friend23.C,v
retrieving revision 1.1
diff -c -p -r1.1 friend23.C
*** friend23.C	1998/07/28 01:03:08	1.1
--- friend23.C	1998/08/07 22:25:02
***************
*** 2,10 ****
  
  template <class T = int> // ERROR - original definition
  struct S
! {
    template <class U = int>
    friend class S;
  };
  
! template struct S<int>; // ERROR - redefinition of default arg
--- 2,10 ----
  
  template <class T = int> // ERROR - original definition
  struct S
! { // ERROR - redefinition of default arg
    template <class U = int>
    friend class S;
  };
  
! template struct S<int>; // ERROR - instantiated from here
Index: testsuite/g++.old-deja/g++.pt/t05.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/t05.C,v
retrieving revision 1.1.1.1
diff -c -p -r1.1.1.1 t05.C
*** t05.C	1997/08/19 07:35:47	1.1.1.1
--- t05.C	1998/08/07 22:25:02
***************
*** 1,9 ****
  // Build don't link: 
  
! template <class A> class B {
!   A a;
   public:
!   B(A&aa);			// ERROR - 
    ~B();
  };
! static B<int> b_int (3);	// ERROR - 
--- 1,9 ----
  // Build don't link: 
  
! template <class A> class B {    // ERROR - candidates
!   A a;                          
   public:
!   B(A&aa);			// ERROR - near match
    ~B();
  };
! static B<int> b_int (3);	// ERROR - no matching function
Index: testsuite/g++.old-deja/g++.pt/typename8.C
===================================================================
RCS file: typename8.C
diff -N typename8.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- typename8.C	Fri Aug  7 15:25:02 1998
***************
*** 0 ****
--- 1,27 ----
+ // Build don't link:
+ 
+ template < class T > class A
+ {
+ public:
+   typedef typename T::myT anotherT; // ERROR - undefined type
+ 
+   anotherT t; // ERROR - undefined type 
+ 
+   A(anotherT _t) { // ERROR - undefined type
+     t=_t;
+   }
+ 
+   anotherT getT() {
+     return t;
+   }
+ };
+ 
+ class B : public A< B >
+ {
+ public:
+   typedef int myT;
+ };
+ 
+ int main() {
+   B b;
+ }
Index: testsuite/g++.old-deja/g++.robertl/eb109.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.robertl/eb109.C,v
retrieving revision 1.2
diff -c -p -r1.2 eb109.C
*** eb109.C	1998/06/04 01:49:24	1.2
--- eb109.C	1998/08/07 22:25:02
*************** inline istream& operator>>(istream& is, 
*** 17,23 ****
  
  template<class VertexType, class EdgeType>
  class Graph
! {
    public:
      // public type interface
      typedef map<int, EdgeType > Successor;
--- 17,23 ----
  
  template<class VertexType, class EdgeType>
  class Graph
! { // ERROR - candidates
    public:
      // public type interface
      typedef map<int, EdgeType > Successor;
Index: testsuite/g++.old-deja/g++.robertl/eb128.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.robertl/eb128.C,v
retrieving revision 1.1
diff -c -p -r1.1 eb128.C
*** eb128.C	1998/06/02 19:45:48	1.1
--- eb128.C	1998/08/07 22:25:02
***************
*** 1,11 ****
  template<class T>
  struct A {
!   typedef T* iterator;
  public:
    A(){}
  };
  
  void f()
  {
!   A<int&> a;  // ERROR - pointer to reference
  }
--- 1,11 ----
  template<class T>
  struct A {
!   typedef T* iterator; // ERROR - pointer to reference
  public:
    A(){}
  };
  
  void f()
  {
!   A<int&> a; // ERROR - instantiated from here
  }
Index: cp/decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.110
diff -c -p -r1.110 decl2.c
*** decl2.c	1998/08/03 09:58:32	1.110
--- decl2.c	1998/08/07 22:26:03
*************** grokbitfield (declarator, declspecs, wid
*** 1845,1850 ****
--- 1845,1861 ----
        return NULL_TREE;
      }
  
+   /* Usually, finish_struct_1 catches bitifields with invalid types.
+      But, in the case of bitfields with function type, we confuse
+      ourselves into thinking they are member functions, so we must
+      check here.  */
+   if (TREE_CODE (value) == FUNCTION_DECL)
+     {
+       cp_error ("cannot declare bitfield `%D' with funcion type",
+ 		DECL_NAME (value));
+       return NULL_TREE;
+     }
+ 
    if (IS_SIGNATURE (current_class_type))
      {
        error ("field declaration not allowed in signature");
*************** do_dtors ()
*** 3001,3006 ****
--- 3012,3036 ----
  	  if (! current_function_decl)
  	    start_objects ('D');
  
+ 	  /* Because of:
+ 
+ 	       [class.access.spec]
+ 
+ 	       Access control for implicit calls to the constructors,
+ 	       the conversion functions, or the destructor called to
+ 	       create and destroy a static data member is per- formed as
+ 	       if these calls appeared in the scope of the member's
+ 	       class.  
+ 
+ 	     we must convince enforce_access to let us access the
+ 	     DECL.  */
+ 	  if (member_p (decl))
+ 	    {
+ 	      DECL_CLASS_CONTEXT (current_function_decl)
+ 		= DECL_CONTEXT (decl);
+ 	      DECL_STATIC_FUNCTION_P (current_function_decl) = 1;
+ 	    }
+ 
  	  temp = build_cleanup (decl);
  
  	  if (protect)
*************** do_dtors ()
*** 3015,3020 ****
--- 3045,3055 ----
  
  	  if (protect)
  	    expand_end_cond ();
+ 	  
+ 	  /* Now that we're done with DECL we don't need to pretend to
+ 	     be a member of its class any longer.  */
+ 	  DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE;
+ 	  DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
  	}
      }
  
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.174
diff -c -p -r1.174 pt.c
*** pt.c	1998/08/06 16:56:41	1.174
--- pt.c	1998/08/07 22:26:58
*************** static tree most_specialized_class PROTO
*** 122,127 ****
--- 122,129 ----
  static tree most_general_template PROTO((tree));
  static void set_mangled_name_for_template_decl PROTO((tree));
  static int template_class_depth_real PROTO((tree, int));
+ static tree tsubst_aggr_type PROTO((tree, tree, tree, int));
+ static tree tsubst_decl PROTO((tree, tree, tree, tree));
  
  /* We use TREE_VECs to hold template arguments.  If there is only one
     level of template arguments, then the TREE_VEC contains the
*************** pop_tinst_level ()
*** 3779,3784 ****
--- 3781,3791 ----
  {
    struct tinst_level *old = current_tinst_level;
  
+   /* Restore the filename and line number stashed away when we started
+      this instantiation.  */
+   lineno = old->line;
+   input_filename = old->file;
+   
    current_tinst_level = old->next;
    old->next = free_tinst_level;
    free_tinst_level = old;
*************** instantiate_class_template (type)
*** 4291,4297 ****
    for (t = TYPE_FIELDS (pattern); t; t = TREE_CHAIN (t))
      if (TREE_CODE (t) != CONST_DECL)
        {
! 	tree r = tsubst (t, args, NULL_TREE);
  	if (TREE_CODE (r) == VAR_DECL)
  	  {
  	    pending_statics = perm_tree_cons (NULL_TREE, r, pending_statics);
--- 4298,4312 ----
    for (t = TYPE_FIELDS (pattern); t; t = TREE_CHAIN (t))
      if (TREE_CODE (t) != CONST_DECL)
        {
! 	tree r;
! 
! 	/* The the file and line for this declaration, to assist in
! 	   error message reporting.  Since we called push_tinst_level
! 	   above, we don't need to restore these.  */
! 	lineno = DECL_SOURCE_LINE (t);
! 	input_filename = DECL_SOURCE_FILE (t);
! 
! 	r = tsubst (t, args, NULL_TREE);
  	if (TREE_CODE (r) == VAR_DECL)
  	  {
  	    pending_statics = perm_tree_cons (NULL_TREE, r, pending_statics);
*************** tsubst_aggr_type (t, args, in_decl, ente
*** 4618,4822 ****
        return tsubst (t, args, in_decl);
      }
  }
- 
- /* Take the tree structure T and replace template parameters used therein
-    with the argument vector ARGS.  IN_DECL is an associated decl for
-    diagnostics.
  
!    tsubst is used for dealing with types, decls and the like; for
!    expressions, use tsubst_expr or tsubst_copy.  */
  
  tree
! tsubst (t, args, in_decl)
!      tree t, args;
       tree in_decl;
  {
!   tree type;
! 
!   if (t == NULL_TREE || t == error_mark_node
!       || t == integer_type_node
!       || t == void_type_node
!       || t == char_type_node
!       || TREE_CODE (t) == NAMESPACE_DECL)
!     return t;
! 
!   if (TREE_CODE (t) == IDENTIFIER_NODE)
!     type = IDENTIFIER_TYPE_VALUE (t);
!   else
!     type = TREE_TYPE (t);
!   if (type == unknown_type_node)
!     my_friendly_abort (42);
  
!   if (type && TREE_CODE (t) != FUNCTION_DECL
!       && TREE_CODE (t) != TYPENAME_TYPE
!       && TREE_CODE (t) != TEMPLATE_DECL
!       && TREE_CODE (t) != IDENTIFIER_NODE)
!     type = tsubst (type, args, in_decl);
  
    switch (TREE_CODE (t))
      {
-     case RECORD_TYPE:
-     case UNION_TYPE:
-     case ENUMERAL_TYPE:
-       return tsubst_aggr_type (t, args, in_decl, /*entering_scope=*/0);
- 
-     case ERROR_MARK:
-     case IDENTIFIER_NODE:
-     case OP_IDENTIFIER:
-     case VOID_TYPE:
-     case REAL_TYPE:
-     case COMPLEX_TYPE:
-     case BOOLEAN_TYPE:
-     case INTEGER_CST:
-     case REAL_CST:
-     case STRING_CST:
-     case NAMESPACE_DECL:
-       return t;
- 
-     case INTEGER_TYPE:
-       if (t == integer_type_node)
- 	return t;
- 
-       if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST
- 	  && TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
- 	return t;
- 
-       {
- 	tree max = TREE_OPERAND (TYPE_MAX_VALUE (t), 0);
- 	max = tsubst_expr (max, args, in_decl);
- 	if (processing_template_decl)
- 	  {
- 	    tree itype = make_node (INTEGER_TYPE);
- 	    TYPE_MIN_VALUE (itype) = size_zero_node;
- 	    TYPE_MAX_VALUE (itype) = build_min (MINUS_EXPR, sizetype, max,
- 						integer_one_node);
- 	    return itype;
- 	  }
- 
- 	max = fold (build_binary_op (MINUS_EXPR, max, integer_one_node, 1));
- 	return build_index_2_type (size_zero_node, max);
-       }
- 
-     case TEMPLATE_TYPE_PARM:
-     case TEMPLATE_TEMPLATE_PARM:
-     case TEMPLATE_PARM_INDEX:
-       {
- 	int idx;
- 	int level;
- 	int levels;
- 	tree r = NULL_TREE;
- 
- 	if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
- 	    || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
- 	  {
- 	    idx = TEMPLATE_TYPE_IDX (t);
- 	    level = TEMPLATE_TYPE_LEVEL (t);
- 	  }
- 	else
- 	  {
- 	    idx = TEMPLATE_PARM_IDX (t);
- 	    level = TEMPLATE_PARM_LEVEL (t);
- 	  }
- 
- 	if (TREE_VEC_LENGTH (args) > 0)
- 	  {
- 	    tree arg = NULL_TREE;
- 
- 	    levels = TMPL_ARGS_DEPTH (args);
- 	    if (level <= levels)
- 	      arg = TMPL_ARG (args, level, idx);
- 
- 	    if (arg != NULL_TREE)
- 	      {
- 		if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
- 		  {
- 		    my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (arg))
- 					== 't', 0);
- 		    return cp_build_type_variant
- 		      (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
- 		       TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
- 		  }
- 		else if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
- 		  {
- 		    if (CLASSTYPE_TEMPLATE_INFO (t))
- 		      {
- 			/* We are processing a type constructed from
- 			   a template template parameter */
- 			tree argvec = tsubst (CLASSTYPE_TI_ARGS (t),
- 					      args, in_decl);
- 			tree r;
- 
- 			/* We can get a TEMPLATE_TEMPLATE_PARM here when 
- 			   we are resolving nested-types in the signature of 
- 			   a member function templates.
- 			   Otherwise ARG is a TEMPLATE_DECL and is the real 
- 			   template to be instantiated.  */
- 			if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
- 			  arg = TYPE_NAME (arg);
- 
- 			r = lookup_template_class (DECL_NAME (arg), 
- 						   argvec, in_decl, 
- 						   DECL_CONTEXT (arg),
- 						   /*entering_scope=*/0);
- 			return cp_build_type_variant (r, TYPE_READONLY (t),
- 						      TYPE_VOLATILE (t));
- 		      }
- 		    else
- 		      /* We are processing a template argument list.  */ 
- 		      return arg;
- 		  }
- 		else
- 		  return arg;
- 	      }
- 	  }
- 
- 	if (level == 1)
- 	  /* This can happen during the attempted tsubst'ing in
- 	     unify.  This means that we don't yet have any information
- 	     about the template parameter in question.  */
- 	  return t;
- 
- 	/* If we get here, we must have been looking at a parm for a
- 	   more deeply nested template.  Make a new version of this
- 	   template parameter, but with a lower level.  */
- 	switch (TREE_CODE (t))
- 	  {
- 	  case TEMPLATE_TYPE_PARM:
- 	  case TEMPLATE_TEMPLATE_PARM:
- 	    r = copy_node (t);
- 	    TEMPLATE_TYPE_PARM_INDEX (r)
- 	      = reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (t),
- 					    r, levels);
- 	    TYPE_STUB_DECL (r) = TYPE_NAME (r) = TEMPLATE_TYPE_DECL (r);
- 	    TYPE_MAIN_VARIANT (r) = r;
- 	    TYPE_POINTER_TO (r) = NULL_TREE;
- 	    TYPE_REFERENCE_TO (r) = NULL_TREE;
- 
- 	    if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
- 		&& CLASSTYPE_TEMPLATE_INFO (t))
- 	      {
- 		tree argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, in_decl);
- 		CLASSTYPE_TEMPLATE_INFO (r)
- 		  = perm_tree_cons (TYPE_NAME (t), argvec, NULL_TREE);
- 	      }
- 	    break;
- 
- 	  case TEMPLATE_PARM_INDEX:
- 	    r = reduce_template_parm_level (t, type, levels);
- 	    break;
- 	   
- 	  default:
- 	    my_friendly_abort (0);
- 	  }
- 
- 	return r;
-       }
- 
      case TEMPLATE_DECL:
        {
  	/* We can get here when processing a member template function
  	   of a template class.  */
- 	tree tmpl;
  	tree decl = DECL_TEMPLATE_RESULT (t);
  	tree parms;
  	tree* new_parms;
--- 4633,4667 ----
        return tsubst (t, args, in_decl);
      }
  }
  
! /* Substitute the ARGS into the T, which is a _DECL.  TYPE is the
!    (already computed) substitution of ARGS into TREE_TYPE (T), if
!    appropriate.  Return the result of the substitution.  IN_DECL is as
!    for tsubst.  */
  
  tree
! tsubst_decl (t, args, type, in_decl)
!      tree t;
!      tree args;
!      tree type;
       tree in_decl;
  {
!   int saved_lineno;
!   char* saved_filename;
!   tree r;
  
!   /* Set the filename and linenumber to improve error-reporting.  */
!   saved_lineno = lineno;
!   saved_filename = input_filename;
!   lineno = DECL_SOURCE_LINE (t);
!   input_filename = DECL_SOURCE_FILE (t);
  
    switch (TREE_CODE (t))
      {
      case TEMPLATE_DECL:
        {
  	/* We can get here when processing a member template function
  	   of a template class.  */
  	tree decl = DECL_TEMPLATE_RESULT (t);
  	tree parms;
  	tree* new_parms;
*************** tsubst (t, args, in_decl)
*** 4841,4847 ****
  
  	    spec = retrieve_specialization (t, full_args);
  	    if (spec != NULL_TREE)
! 	      return spec;
  	  }
  
  	/* Make a new template decl.  It will be similar to the
--- 4686,4695 ----
  
  	    spec = retrieve_specialization (t, full_args);
  	    if (spec != NULL_TREE)
! 	      {
! 		r = spec;
! 		break;
! 	      }
  	  }
  
  	/* Make a new template decl.  It will be similar to the
*************** tsubst (t, args, in_decl)
*** 4849,4908 ****
  	   We also create a new function declaration, which is just
  	   like the old one, but points to this new template, rather
  	   than the old one.  */
! 	tmpl = copy_node (t);
! 	copy_lang_decl (tmpl);
! 	my_friendly_assert (DECL_LANG_SPECIFIC (tmpl) != 0, 0);
! 	TREE_CHAIN (tmpl) = NULL_TREE;
  
  	if (is_template_template_parm)
  	  {
  	    tree new_decl = tsubst (decl, args, in_decl);
! 	    DECL_RESULT (tmpl) = new_decl;
! 	    TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
! 	    return tmpl;
  	  }
  
! 	DECL_CONTEXT (tmpl) 
  	  = tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl,
  			      /*entering_scope=*/1);
! 	DECL_CLASS_CONTEXT (tmpl) 
  	  = tsubst_aggr_type (DECL_CLASS_CONTEXT (t), args, in_decl,
  			      /*entering_scope=*/1);
! 	DECL_TEMPLATE_INFO (tmpl) = build_tree_list (t, args);
  
  	if (TREE_CODE (decl) == TYPE_DECL)
  	  {
  	    tree new_type = tsubst (TREE_TYPE (t), args, in_decl);
! 	    TREE_TYPE (tmpl) = new_type;
! 	    CLASSTYPE_TI_TEMPLATE (new_type) = tmpl;
! 	    DECL_RESULT (tmpl) = TYPE_MAIN_DECL (new_type);
! 	    DECL_TI_ARGS (tmpl) = CLASSTYPE_TI_ARGS (new_type);
  	  }
  	else
  	  {
  	    tree new_decl = tsubst (decl, args, in_decl);
! 	    DECL_RESULT (tmpl) = new_decl;
! 	    DECL_TI_TEMPLATE (new_decl) = tmpl;
! 	    TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
! 	    DECL_TI_ARGS (tmpl) = DECL_TI_ARGS (new_decl);
  	  }
  
! 	SET_DECL_IMPLICIT_INSTANTIATION (tmpl);
! 	DECL_TEMPLATE_INSTANTIATIONS (tmpl) = NULL_TREE;
! 	DECL_TEMPLATE_SPECIALIZATIONS (tmpl) = NULL_TREE;
  
  	/* The template parameters for this new template are all the
  	   template parameters for the old template, except the
  	   outermost level of parameters. */
! 	DECL_TEMPLATE_PARMS (tmpl) 
  	  = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args);
  
  	if (PRIMARY_TEMPLATE_P (t))
! 	  DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
  
  	/* We don't partially instantiate partial specializations.  */
  	if (TREE_CODE (decl) == TYPE_DECL)
! 	  return tmpl;
  
  	for (spec = DECL_TEMPLATE_SPECIALIZATIONS (t);
  	     spec != NULL_TREE;
--- 4697,4756 ----
  	   We also create a new function declaration, which is just
  	   like the old one, but points to this new template, rather
  	   than the old one.  */
! 	r = copy_node (t);
! 	copy_lang_decl (r);
! 	my_friendly_assert (DECL_LANG_SPECIFIC (r) != 0, 0);
! 	TREE_CHAIN (r) = NULL_TREE;
  
  	if (is_template_template_parm)
  	  {
  	    tree new_decl = tsubst (decl, args, in_decl);
! 	    DECL_RESULT (r) = new_decl;
! 	    TREE_TYPE (r) = TREE_TYPE (new_decl);
! 	    break;
  	  }
  
! 	DECL_CONTEXT (r) 
  	  = tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl,
  			      /*entering_scope=*/1);
! 	DECL_CLASS_CONTEXT (r) 
  	  = tsubst_aggr_type (DECL_CLASS_CONTEXT (t), args, in_decl,
  			      /*entering_scope=*/1);
! 	DECL_TEMPLATE_INFO (r) = build_tree_list (t, args);
  
  	if (TREE_CODE (decl) == TYPE_DECL)
  	  {
  	    tree new_type = tsubst (TREE_TYPE (t), args, in_decl);
! 	    TREE_TYPE (r) = new_type;
! 	    CLASSTYPE_TI_TEMPLATE (new_type) = r;
! 	    DECL_RESULT (r) = TYPE_MAIN_DECL (new_type);
! 	    DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
  	  }
  	else
  	  {
  	    tree new_decl = tsubst (decl, args, in_decl);
! 	    DECL_RESULT (r) = new_decl;
! 	    DECL_TI_TEMPLATE (new_decl) = r;
! 	    TREE_TYPE (r) = TREE_TYPE (new_decl);
! 	    DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
  	  }
  
! 	SET_DECL_IMPLICIT_INSTANTIATION (r);
! 	DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
! 	DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
  
  	/* The template parameters for this new template are all the
  	   template parameters for the old template, except the
  	   outermost level of parameters. */
! 	DECL_TEMPLATE_PARMS (r) 
  	  = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args);
  
  	if (PRIMARY_TEMPLATE_P (t))
! 	  DECL_PRIMARY_TEMPLATE (r) = r;
  
  	/* We don't partially instantiate partial specializations.  */
  	if (TREE_CODE (decl) == TYPE_DECL)
! 	  break;
  
  	for (spec = DECL_TEMPLATE_SPECIALIZATIONS (t);
  	     spec != NULL_TREE;
*************** tsubst (t, args, in_decl)
*** 4953,4972 ****
  	    new_fn = tsubst (DECL_RESULT (most_general_template (fn)), 
  			     spec_args, in_decl); 
  	    DECL_TI_TEMPLATE (new_fn) = fn;
! 	    register_specialization (new_fn, tmpl, 
  				     innermost_args (spec_args));
  	  }
  
  	/* Record this partial instantiation.  */
! 	register_specialization (tmpl, t, 
! 				 DECL_TI_ARGS (DECL_RESULT (tmpl)));
  
- 	return tmpl;
        }
  
      case FUNCTION_DECL:
        {
- 	tree r = NULL_TREE;
  	tree ctx;
  	tree argvec;
  	tree gen_tmpl;
--- 4801,4819 ----
  	    new_fn = tsubst (DECL_RESULT (most_general_template (fn)), 
  			     spec_args, in_decl); 
  	    DECL_TI_TEMPLATE (new_fn) = fn;
! 	    register_specialization (new_fn, r, 
  				     innermost_args (spec_args));
  	  }
  
  	/* Record this partial instantiation.  */
! 	register_specialization (r, t, 
! 				 DECL_TI_ARGS (DECL_RESULT (r)));
  
        }
+       break;
  
      case FUNCTION_DECL:
        {
  	tree ctx;
  	tree argvec;
  	tree gen_tmpl;
*************** tsubst (t, args, in_decl)
*** 4988,4994 ****
  	    /* Check to see if we already have this specialization.  */
  	    spec = retrieve_specialization (gen_tmpl, argvec);
  	    if (spec)
! 	      return spec;
  	  }
  	else
  	  {
--- 4835,4844 ----
  	    /* Check to see if we already have this specialization.  */
  	    spec = retrieve_specialization (gen_tmpl, argvec);
  	    if (spec)
! 	      {
! 		r = spec;
! 		break;
! 	      }
  	  }
  	else
  	  {
*************** tsubst (t, args, in_decl)
*** 5113,5125 ****
  		    == NULL_TREE))
  	      SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r), r);
  	  }
- 
- 	return r;
        }
  
      case PARM_DECL:
        {
! 	tree r = copy_node (t);
  	TREE_TYPE (r) = type;
  	if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
  	  DECL_INITIAL (r) = TREE_TYPE (r);
--- 4963,4974 ----
  		    == NULL_TREE))
  	      SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r), r);
  	  }
        }
+       break;
  
      case PARM_DECL:
        {
! 	r = copy_node (t);
  	TREE_TYPE (r) = type;
  	if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
  	  DECL_INITIAL (r) = TREE_TYPE (r);
*************** tsubst (t, args, in_decl)
*** 5135,5146 ****
  #endif
  	if (TREE_CHAIN (t))
  	  TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args, TREE_CHAIN (t));
- 	return r;
        }
  
      case FIELD_DECL:
        {
! 	tree r = copy_node (t);
  	TREE_TYPE (r) = type;
  	copy_lang_decl (r);
  #if 0
--- 4984,4995 ----
  #endif
  	if (TREE_CHAIN (t))
  	  TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args, TREE_CHAIN (t));
        }
+       break;
  
      case FIELD_DECL:
        {
! 	r = copy_node (t);
  	TREE_TYPE (r) = type;
  	copy_lang_decl (r);
  #if 0
*************** tsubst (t, args, in_decl)
*** 5150,5170 ****
  	TREE_CHAIN (r) = NULL_TREE;
  	if (TREE_CODE (type) == VOID_TYPE)
  	  cp_error_at ("instantiation of `%D' as type void", r);
- 	return r;
        }
  
      case USING_DECL:
        {
! 	tree r = copy_node (t);
  	DECL_INITIAL (r)
  	  = tsubst_copy (DECL_INITIAL (t), args, in_decl);
  	TREE_CHAIN (r) = NULL_TREE;
- 	return r;
        }
  
      case VAR_DECL:
        {
- 	tree r;
  	tree argvec;
  	tree gen_tmpl;
  	tree spec;
--- 4999,5018 ----
  	TREE_CHAIN (r) = NULL_TREE;
  	if (TREE_CODE (type) == VOID_TYPE)
  	  cp_error_at ("instantiation of `%D' as type void", r);
        }
+       break;
  
      case USING_DECL:
        {
! 	r = copy_node (t);
  	DECL_INITIAL (r)
  	  = tsubst_copy (DECL_INITIAL (t), args, in_decl);
  	TREE_CHAIN (r) = NULL_TREE;
        }
+       break;
  
      case VAR_DECL:
        {
  	tree argvec;
  	tree gen_tmpl;
  	tree spec;
*************** tsubst (t, args, in_decl)
*** 5183,5189 ****
  	spec = retrieve_specialization (gen_tmpl, argvec);
  	
  	if (spec)
! 	  return spec;
  
  	r = copy_node (t);
  	TREE_TYPE (r) = type;
--- 5031,5040 ----
  	spec = retrieve_specialization (gen_tmpl, argvec);
  	
  	if (spec)
! 	  {
! 	    r = spec;
! 	    break;
! 	  }
  
  	r = copy_node (t);
  	TREE_TYPE (r) = type;
*************** tsubst (t, args, in_decl)
*** 5207,5226 ****
  	TREE_CHAIN (r) = NULL_TREE;
  	if (TREE_CODE (type) == VOID_TYPE)
  	  cp_error_at ("instantiation of `%D' as type void", r);
- 	return r;
        }
  
      case TYPE_DECL:
        if (t == TYPE_NAME (TREE_TYPE (t)))
! 	return TYPE_NAME (type);
  
        {
! 	tree r = copy_node (t);
! 	TREE_TYPE (r) = type;
! 	DECL_CONTEXT (r) = current_class_type;
! 	TREE_CHAIN (r) = NULL_TREE;
  	return r;
!       }	  
  
      case TREE_LIST:
        {
--- 5058,5284 ----
  	TREE_CHAIN (r) = NULL_TREE;
  	if (TREE_CODE (type) == VOID_TYPE)
  	  cp_error_at ("instantiation of `%D' as type void", r);
        }
+       break;
  
      case TYPE_DECL:
        if (t == TYPE_NAME (TREE_TYPE (t)))
! 	r = TYPE_NAME (type);
!       else
! 	{
! 	  r = copy_node (t);
! 	  TREE_TYPE (r) = type;
! 	  DECL_CONTEXT (r) = current_class_type;
! 	  TREE_CHAIN (r) = NULL_TREE;
! 	}
!       break;
! 
!     default:
!       my_friendly_abort (0);
!     } 
! 
!   /* Restore the file and line information.  */
!   lineno = saved_lineno;
!   input_filename = saved_filename;
! 
!   return r;
! }
! 
! 
! /* Take the tree structure T and replace template parameters used therein
!    with the argument vector ARGS.  IN_DECL is an associated decl for
!    diagnostics.
! 
!    tsubst is used for dealing with types, decls and the like; for
!    expressions, use tsubst_expr or tsubst_copy.  */
! 
! tree
! tsubst (t, args, in_decl)
!      tree t, args;
!      tree in_decl;
! {
!   tree type;
! 
!   if (t == NULL_TREE || t == error_mark_node
!       || t == integer_type_node
!       || t == void_type_node
!       || t == char_type_node
!       || TREE_CODE (t) == NAMESPACE_DECL)
!     return t;
! 
!   if (TREE_CODE (t) == IDENTIFIER_NODE)
!     type = IDENTIFIER_TYPE_VALUE (t);
!   else
!     type = TREE_TYPE (t);
!   if (type == unknown_type_node)
!     my_friendly_abort (42);
! 
!   if (type && TREE_CODE (t) != FUNCTION_DECL
!       && TREE_CODE (t) != TYPENAME_TYPE
!       && TREE_CODE (t) != TEMPLATE_DECL
!       && TREE_CODE (t) != IDENTIFIER_NODE)
!     type = tsubst (type, args, in_decl);
! 
!   if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd')
!     return tsubst_decl (t, args, type, in_decl);
  
+   switch (TREE_CODE (t))
+     {
+     case RECORD_TYPE:
+     case UNION_TYPE:
+     case ENUMERAL_TYPE:
+       return tsubst_aggr_type (t, args, in_decl, /*entering_scope=*/0);
+ 
+     case ERROR_MARK:
+     case IDENTIFIER_NODE:
+     case OP_IDENTIFIER:
+     case VOID_TYPE:
+     case REAL_TYPE:
+     case COMPLEX_TYPE:
+     case BOOLEAN_TYPE:
+     case INTEGER_CST:
+     case REAL_CST:
+     case STRING_CST:
+       return t;
+ 
+     case INTEGER_TYPE:
+       if (t == integer_type_node)
+ 	return t;
+ 
+       if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST
+ 	  && TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
+ 	return t;
+ 
        {
! 	tree max = TREE_OPERAND (TYPE_MAX_VALUE (t), 0);
! 	max = tsubst_expr (max, args, in_decl);
! 	if (processing_template_decl)
! 	  {
! 	    tree itype = make_node (INTEGER_TYPE);
! 	    TYPE_MIN_VALUE (itype) = size_zero_node;
! 	    TYPE_MAX_VALUE (itype) = build_min (MINUS_EXPR, sizetype, max,
! 						integer_one_node);
! 	    return itype;
! 	  }
! 
! 	max = fold (build_binary_op (MINUS_EXPR, max, integer_one_node, 1));
! 	return build_index_2_type (size_zero_node, max);
!       }
! 
!     case TEMPLATE_TYPE_PARM:
!     case TEMPLATE_TEMPLATE_PARM:
!     case TEMPLATE_PARM_INDEX:
!       {
! 	int idx;
! 	int level;
! 	int levels;
! 	tree r = NULL_TREE;
! 
! 	if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
! 	    || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
! 	  {
! 	    idx = TEMPLATE_TYPE_IDX (t);
! 	    level = TEMPLATE_TYPE_LEVEL (t);
! 	  }
! 	else
! 	  {
! 	    idx = TEMPLATE_PARM_IDX (t);
! 	    level = TEMPLATE_PARM_LEVEL (t);
! 	  }
! 
! 	if (TREE_VEC_LENGTH (args) > 0)
! 	  {
! 	    tree arg = NULL_TREE;
! 
! 	    levels = TMPL_ARGS_DEPTH (args);
! 	    if (level <= levels)
! 	      arg = TMPL_ARG (args, level, idx);
! 
! 	    if (arg != NULL_TREE)
! 	      {
! 		if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
! 		  {
! 		    my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (arg))
! 					== 't', 0);
! 		    return cp_build_type_variant
! 		      (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
! 		       TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
! 		  }
! 		else if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
! 		  {
! 		    if (CLASSTYPE_TEMPLATE_INFO (t))
! 		      {
! 			/* We are processing a type constructed from
! 			   a template template parameter */
! 			tree argvec = tsubst (CLASSTYPE_TI_ARGS (t),
! 					      args, in_decl);
! 			tree r;
! 
! 			/* We can get a TEMPLATE_TEMPLATE_PARM here when 
! 			   we are resolving nested-types in the signature of 
! 			   a member function templates.
! 			   Otherwise ARG is a TEMPLATE_DECL and is the real 
! 			   template to be instantiated.  */
! 			if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
! 			  arg = TYPE_NAME (arg);
! 
! 			r = lookup_template_class (DECL_NAME (arg), 
! 						   argvec, in_decl, 
! 						   DECL_CONTEXT (arg),
! 						   /*entering_scope=*/0);
! 			return cp_build_type_variant (r, TYPE_READONLY (t),
! 						      TYPE_VOLATILE (t));
! 		      }
! 		    else
! 		      /* We are processing a template argument list.  */ 
! 		      return arg;
! 		  }
! 		else
! 		  return arg;
! 	      }
! 	  }
! 
! 	if (level == 1)
! 	  /* This can happen during the attempted tsubst'ing in
! 	     unify.  This means that we don't yet have any information
! 	     about the template parameter in question.  */
! 	  return t;
! 
! 	/* If we get here, we must have been looking at a parm for a
! 	   more deeply nested template.  Make a new version of this
! 	   template parameter, but with a lower level.  */
! 	switch (TREE_CODE (t))
! 	  {
! 	  case TEMPLATE_TYPE_PARM:
! 	  case TEMPLATE_TEMPLATE_PARM:
! 	    r = copy_node (t);
! 	    TEMPLATE_TYPE_PARM_INDEX (r)
! 	      = reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (t),
! 					    r, levels);
! 	    TYPE_STUB_DECL (r) = TYPE_NAME (r) = TEMPLATE_TYPE_DECL (r);
! 	    TYPE_MAIN_VARIANT (r) = r;
! 	    TYPE_POINTER_TO (r) = NULL_TREE;
! 	    TYPE_REFERENCE_TO (r) = NULL_TREE;
! 
! 	    if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
! 		&& CLASSTYPE_TEMPLATE_INFO (t))
! 	      {
! 		tree argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, in_decl);
! 		CLASSTYPE_TEMPLATE_INFO (r)
! 		  = perm_tree_cons (TYPE_NAME (t), argvec, NULL_TREE);
! 	      }
! 	    break;
! 
! 	  case TEMPLATE_PARM_INDEX:
! 	    r = reduce_template_parm_level (t, type, levels);
! 	    break;
! 	   
! 	  default:
! 	    my_friendly_abort (0);
! 	  }
! 
  	return r;
!       }
  
      case TREE_LIST:
        {
*************** tsubst (t, args, in_decl)
*** 5439,5444 ****
--- 5497,5515 ----
  	tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, in_decl,
  				     /*entering_scope=*/1);
  	tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args, in_decl);
+ 
+ 	/* Normally, make_typename_type does not require that the CTX
+ 	   have complete type in order to allow things like:
+ 	     
+              template <class T> struct S { typename S<T>::X Y; };
+ 
+ 	   But, such constructs have already been resolved by this
+ 	   point, so here CTX really should have complete type, unless
+ 	   it's a partial instantiation.  */
+ 	if (!uses_template_parms (ctx) 
+ 	    && !complete_type_or_else (ctx))
+ 	  return error_mark_node;
+ 
  	f = make_typename_type (ctx, f);
  	return cp_build_type_variant
  	  (f, TYPE_READONLY (f) || TYPE_READONLY (t),
Index: cp/typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.92
diff -c -p -r1.92 typeck.c
*** typeck.c	1998/08/03 22:11:25	1.92
--- typeck.c	1998/08/07 22:27:22
*************** target_type (type)
*** 80,86 ****
  }
  
  /* Do `exp = require_complete_type (exp);' to make sure exp
!    does not have an incomplete type.  (That includes void types.)  */
  
  tree
  require_complete_type (value)
--- 80,88 ----
  }
  
  /* Do `exp = require_complete_type (exp);' to make sure exp
!    does not have an incomplete type.  (That includes void types.)
!    Returns the error_mark_node if the VALUE does not have
!    complete type when this function returns.  */
  
  tree
  require_complete_type (value)
*************** require_complete_type (value)
*** 120,132 ****
        return require_complete_type (value);
      }
  
!   if (TYPE_SIZE (complete_type (type)))
      return value;
    else
!     {
!       incomplete_type_error (value, type);
!       return error_mark_node;
!     }
  }
  
  /* Try to complete TYPE, if it is incomplete.  For example, if TYPE is
--- 122,131 ----
        return require_complete_type (value);
      }
  
!   if (complete_type_or_else (type))
      return value;
    else
!     return error_mark_node;
  }
  
  /* Try to complete TYPE, if it is incomplete.  For example, if TYPE is
*************** complete_type_or_else (type)
*** 170,176 ****
       tree type;
  {
    type = complete_type (type);
!   if (type != error_mark_node && !TYPE_SIZE (type))
      {
        incomplete_type_error (NULL_TREE, type);
        return NULL_TREE;
--- 169,178 ----
       tree type;
  {
    type = complete_type (type);
!   if (type == error_mark_node)
!     /* We already issued an error.  */
!     return NULL_TREE;
!   else if (!TYPE_SIZE (type))
      {
        incomplete_type_error (NULL_TREE, type);
        return NULL_TREE;
cvs server: Diffing cp/inc



More information about the Gcc-patches mailing list