public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] Class template instantiation according to core issue 287.
@ 2002-10-26  7:10 Kriang Lerdsuwanakij
  2002-10-27 22:29 ` Mark Mitchell
  0 siblings, 1 reply; 4+ messages in thread
From: Kriang Lerdsuwanakij @ 2002-10-26  7:10 UTC (permalink / raw)
  To: gcc-patches

Hi

After some thought, I decide to implement the proposed resolution
for Core issue 287 (class template instantiation dependencies).  
Although the core issue is still under review, it is better than 
our current ad hoc solution.  With the patch below, members and 
friends are processed according to the order of declaration during 
class template instantiation.

A new field CLASSTYPE_DECL_LIST is added to the type lang_specific 
node to hold all class declaration in the correct order.  A new
function maybe_add_class_template_decl_list is also introduced to
update this field.  Finally, instantiate_class_template walks
through CLASSTYPE_DECL_LIST and process declarations in the right
order.  I have verified that CLASSTYPE_DECL_LIST contains 
every tree nodes in TYPE_FIELDS, TYPE_METHODS, etc.  (The test 
code is removed from the final code below.)

Bootstrapped and tested on i686-pc-linux-gnu with no regression.
OK to commit to main trunk?

--Kriang


2002-10-26  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	Core issue 287, PR c++/7639
	* cp-tree.h (lang_type_class): Add decl_list field.
	(CLASSTYPE_DECL_LIST): New macro.
	(maybe_add_class_template_decl_list): Add declaration.
	* class.c (duplicate_tag_error): Initialize CLASSTYPE_DECL_LIST.
	(unreverse_member_declarations): Reverse CLASSTYPE_DECL_LIST.
	(maybe_add_class_template_decl_list): New function.
	(add_implicitly_declared_members): Use it.
	* decl.c (maybe_process_template_type_declaration): Likewise.
	(pushtag): Likewise.
	* friend.c (add_friend): Likewise.
	(make_friend_class): Likewise.
	* semantics.c (finish_member_declaration): Likewise.
	(begin_class_definition): Initialize CLASSTYPE_DECL_LIST.
	* pt.c (instantiate_class_template): Use CLASSTYPE_DECL_LIST
	to process members and friends in the order of declaration.

2002-10-26  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	Core issue 287, PR c++/7639
	* g++.dg/template/instantiate1.C: Adjust error location.
	* g++.dg/template/instantiate3.C: New test.
	* g++.old-deja/g++.pt/crash10.C: Adjust error location.
	* g++.old-deja/g++.pt/derived3.C: Adjust error location.
	* g++.old-deja/g++.pt/spec28.C: Reorder declaration.


diff -cprN gcc-main-save/gcc/cp/class.c gcc-main-new/gcc/cp/class.c
*** gcc-main-save/gcc/cp/class.c	Fri Oct 18 22:29:10 2002
--- gcc-main-new/gcc/cp/class.c	Sat Oct 26 18:32:12 2002
*************** duplicate_tag_error (t)
*** 2122,2127 ****
--- 2122,2128 ----
        TYPE_REDEFINED (t) = 1;
        CLASSTYPE_TEMPLATE_INFO (t) = template_info;
        CLASSTYPE_USE_TEMPLATE (t) = use_template;
+       CLASSTYPE_DECL_LIST (t) = NULL_TREE;
      }
    TYPE_SIZE (t) = NULL_TREE;
    TYPE_MODE (t) = VOIDmode;
*************** finish_struct_anon (t)
*** 2780,2785 ****
--- 2781,2806 ----
      }
  }
  
+ /* Add T to CLASSTYPE_DECL_LIST of TYPE which will be used
+    later during class template instantiation.
+    When FRIEND_P is zero, T can be member data, member
+    function, nested type, or member class template.
+    When FRIEND_P is nonzero, T is either friend class or
+    friend function.  */
+ 
+ void
+ maybe_add_class_template_decl_list (type, t, friend_p)
+      tree type;
+      tree t;
+      int friend_p;
+ {
+   /* Save some memory by not creating TREE_LIST if TYPE is not template.  */
+   if (CLASSTYPE_TEMPLATE_INFO (type))
+     CLASSTYPE_DECL_LIST (type)
+       = tree_cons (friend_p ? NULL_TREE : type,
+ 		   t, CLASSTYPE_DECL_LIST (type));
+ }
+ 
  /* Create default constructors, assignment operators, and so forth for
     the type indicated by T, if they are needed.
     CANT_HAVE_DEFAULT_CTOR, CANT_HAVE_CONST_CTOR, and
*************** add_implicitly_declared_members (t, cant
*** 2860,2866 ****
    /* Now, hook all of the new functions on to TYPE_METHODS,
       and add them to the CLASSTYPE_METHOD_VEC.  */
    for (f = &implicit_fns; *f; f = &TREE_CHAIN (*f))
!     add_method (t, *f, /*error_p=*/0);
    *f = TYPE_METHODS (t);
    TYPE_METHODS (t) = implicit_fns;
  
--- 2881,2890 ----
    /* Now, hook all of the new functions on to TYPE_METHODS,
       and add them to the CLASSTYPE_METHOD_VEC.  */
    for (f = &implicit_fns; *f; f = &TREE_CHAIN (*f))
!     {
!       add_method (t, *f, /*error_p=*/0);
!       maybe_add_class_template_decl_list (current_class_type, *f, /*friend_p=*/0);
!     }
    *f = TYPE_METHODS (t);
    TYPE_METHODS (t) = implicit_fns;
  
*************** unreverse_member_declarations (t)
*** 5239,5248 ****
    tree prev;
    tree x;
  
!   /* The TYPE_FIELDS, TYPE_METHODS, and CLASSTYPE_TAGS are all in
!      reverse order.  Put them in declaration order now.  */
    TYPE_METHODS (t) = nreverse (TYPE_METHODS (t));
    CLASSTYPE_TAGS (t) = nreverse (CLASSTYPE_TAGS (t));
  
    /* Actually, for the TYPE_FIELDS, only the non TYPE_DECLs are in
       reverse order, so we can't just use nreverse.  */
--- 5263,5273 ----
    tree prev;
    tree x;
  
!   /* The TYPE_FIELDS, TYPE_METHODS, CLASSTYPE_TAGS, and CLASSTYPE_DECL_LIST
!      are all in reverse order.  Put them in declaration order now.  */
    TYPE_METHODS (t) = nreverse (TYPE_METHODS (t));
    CLASSTYPE_TAGS (t) = nreverse (CLASSTYPE_TAGS (t));
+   CLASSTYPE_DECL_LIST (t) = nreverse (CLASSTYPE_DECL_LIST (t));
  
    /* Actually, for the TYPE_FIELDS, only the non TYPE_DECLs are in
       reverse order, so we can't just use nreverse.  */
diff -cprN gcc-main-save/gcc/cp/cp-tree.h gcc-main-new/gcc/cp/cp-tree.h
*** gcc-main-save/gcc/cp/cp-tree.h	Fri Oct 18 22:29:10 2002
--- gcc-main-new/gcc/cp/cp-tree.h	Sat Oct 26 20:39:18 2002
*************** struct lang_type_class GTY(())
*** 1156,1161 ****
--- 1156,1162 ----
    tree friend_classes;
    tree rtti;
    tree methods;
+   tree decl_list;
    tree template_info;
    tree befriending_classes;
  };
*************** struct lang_type GTY(())
*** 1292,1297 ****
--- 1293,1305 ----
     functions are sorted, once the class is complete.  */
  #define CLASSTYPE_METHOD_VEC(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->methods)
  
+ /* For class templates, this is a TREE_LIST of all member data,
+    functions, types, and friends in the order of declaration.
+    TREE_PURPOSE of each TREE_LIST provides the context of declaration
+    and TREE_VALUE is the actual declaration.  For friends, TREE_PURPOSE
+    is NULL_TREE.  Otherwise it is the class templates itself.  */
+ #define CLASSTYPE_DECL_LIST(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->decl_list)
+ 
  /* The slot in the CLASSTYPE_METHOD_VEC where constructors go.  */
  #define CLASSTYPE_CONSTRUCTOR_SLOT 0
  
*************** extern void cxx_print_error_function	PAR
*** 3560,3565 ****
--- 3568,3574 ----
  extern void build_self_reference		PARAMS ((void));
  extern int same_signature_p			PARAMS ((tree, tree));
  extern void warn_hidden				PARAMS ((tree));
+ extern void maybe_add_class_template_decl_list	PARAMS ((tree, tree, int));
  extern tree get_enclosing_class			PARAMS ((tree));
  int is_base_of_enclosing_class			PARAMS ((tree, tree));
  extern void unreverse_member_declarations       PARAMS ((tree));
diff -cprN gcc-main-save/gcc/cp/decl.c gcc-main-new/gcc/cp/decl.c
*** gcc-main-save/gcc/cp/decl.c	Fri Oct 18 22:29:11 2002
--- gcc-main-new/gcc/cp/decl.c	Sat Oct 26 18:19:12 2002
*************** maybe_process_template_type_declaration 
*** 2617,2623 ****
  	      b->level_chain->tags =
  		tree_cons (name, type, b->level_chain->tags);
  	      if (!COMPLETE_TYPE_P (current_class_type))
! 		CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
  	    }
  	}
      }
--- 2617,2627 ----
  	      b->level_chain->tags =
  		tree_cons (name, type, b->level_chain->tags);
  	      if (!COMPLETE_TYPE_P (current_class_type))
! 		{
! 		  maybe_add_class_template_decl_list (current_class_type,
! 						      type, /*friend_p=*/0);
! 		  CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
! 		}
  	    }
  	}
      }
*************** pushtag (name, type, globalize)
*** 2781,2787 ****
        if (b->parm_flag == 2)
  	{
  	  if (!COMPLETE_TYPE_P (current_class_type))
! 	    CLASSTYPE_TAGS (current_class_type) = b->tags;
  	}
      }
  
--- 2785,2795 ----
        if (b->parm_flag == 2)
  	{
  	  if (!COMPLETE_TYPE_P (current_class_type))
! 	    {
! 	      maybe_add_class_template_decl_list (current_class_type,
! 						  type, /*friend_p=*/0);
! 	      CLASSTYPE_TAGS (current_class_type) = b->tags;
! 	    }
  	}
      }
  
diff -cprN gcc-main-save/gcc/cp/friend.c gcc-main-new/gcc/cp/friend.c
*** gcc-main-save/gcc/cp/friend.c	Thu Sep 26 20:48:06 2002
--- gcc-main-new/gcc/cp/friend.c	Sat Oct 26 18:12:46 2002
*************** add_friend (type, decl)
*** 159,164 ****
--- 159,167 ----
  		  return;
  		}
  	    }
+ 
+ 	  maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);
+ 
  	  TREE_VALUE (list) = tree_cons (error_mark_node, decl,
  					 TREE_VALUE (list));
  	  return;
*************** add_friend (type, decl)
*** 166,171 ****
--- 169,176 ----
        list = TREE_CHAIN (list);
      }
  
+   maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);
+ 
    DECL_FRIENDLIST (typedecl)
      = tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl),
  		 DECL_FRIENDLIST (typedecl));
*************** make_friend_class (type, friend_type)
*** 267,272 ****
--- 272,279 ----
  		TREE_VALUE (classes), type);
    else
      {
+       maybe_add_class_template_decl_list (type, friend_type, /*friend_p=*/1);
+ 
        CLASSTYPE_FRIEND_CLASSES (type)
  	= tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type));
        if (is_template_friend)
diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c	Fri Oct 18 22:29:12 2002
--- gcc-main-new/gcc/cp/pt.c	Sat Oct 26 18:13:29 2002
*************** tree
*** 4977,4983 ****
  instantiate_class_template (type)
       tree type;
  {
!   tree template, args, pattern, t;
    tree typedecl;
  
    if (type == error_mark_node)
--- 4977,4983 ----
  instantiate_class_template (type)
       tree type;
  {
!   tree template, args, pattern, t, member;
    tree typedecl;
  
    if (type == error_mark_node)
*************** instantiate_class_template (type)
*** 5072,5077 ****
--- 5072,5078 ----
        TYPE_BINFO_BASETYPES (type) = TYPE_BINFO_BASETYPES (pattern);
        TYPE_FIELDS (type) = TYPE_FIELDS (pattern);
        TYPE_METHODS (type) = TYPE_METHODS (pattern);
+       CLASSTYPE_DECL_LIST (type) = CLASSTYPE_DECL_LIST (pattern);
        CLASSTYPE_TAGS (type) = CLASSTYPE_TAGS (pattern);
        CLASSTYPE_VBASECLASSES (type) = CLASSTYPE_VBASECLASSES (pattern);
        
*************** instantiate_class_template (type)
*** 5225,5399 ****
       class.  */
    pushclass (type, 1);
  
!   for (t = CLASSTYPE_TAGS (pattern); t; t = TREE_CHAIN (t))
      {
!       tree tag = TREE_VALUE (t);
!       tree name = TYPE_IDENTIFIER (tag);
!       tree newtag;
! 
!       newtag = tsubst (tag, args, tf_error, NULL_TREE);
!       my_friendly_assert (newtag != error_mark_node, 20010206);
!       if (TREE_CODE (newtag) != ENUMERAL_TYPE)
! 	{
! 	  if (TYPE_LANG_SPECIFIC (tag) && CLASSTYPE_IS_TEMPLATE (tag))
! 	    /* Unfortunately, lookup_template_class sets
! 	       CLASSTYPE_IMPLICIT_INSTANTIATION for a partial
! 	       instantiation (i.e., for the type of a member template
! 	       class nested within a template class.)  This behavior is
! 	       required for maybe_process_partial_specialization to work
! 	       correctly, but is not accurate in this case; the TAG is not
! 	       an instantiation of anything.  (The corresponding
! 	       TEMPLATE_DECL is an instantiation, but the TYPE is not.) */
! 	    CLASSTYPE_USE_TEMPLATE (newtag) = 0;
! 
! 	  /* Now, we call pushtag to put this NEWTAG into the scope of
! 	     TYPE.  We first set up the IDENTIFIER_TYPE_VALUE to avoid
! 	     pushtag calling push_template_decl.  We don't have to do
! 	     this for enums because it will already have been done in
! 	     tsubst_enum.  */
! 	  if (name)
! 	    SET_IDENTIFIER_TYPE_VALUE (name, newtag);
! 	  pushtag (name, newtag, /*globalize=*/0);
! 	}
!     }
  
!   /* Don't replace enum constants here.  */
!   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, tf_error | tf_warning, NULL_TREE);
! 	if (TREE_CODE (r) == VAR_DECL)
! 	  {
! 	    tree init;
! 
! 	    if (DECL_INITIALIZED_IN_CLASS_P (r))
! 	      init = tsubst_expr (DECL_INITIAL (t), args,
! 				  tf_error | tf_warning, NULL_TREE);
! 	    else
! 	      init = NULL_TREE;
! 
! 	    finish_static_data_member_decl (r, init,
! 					    /*asmspec_tree=*/NULL_TREE, 
! 					    /*flags=*/0);
! 
! 	    if (DECL_INITIALIZED_IN_CLASS_P (r))
! 	      check_static_variable_definition (r, TREE_TYPE (r));
! 	  }
! 	else if (TREE_CODE (r) == FIELD_DECL)
! 	  {
! 	    /* Determine whether R has a valid type and can be
! 	       completed later.  If R is invalid, then it is replaced
! 	       by error_mark_node so that it will not be added to
! 	       TYPE_FIELDS.  */
! 	    tree rtype = TREE_TYPE (r);
! 	    if (!can_complete_type_without_circularity (rtype))
! 	      {
! 		cxx_incomplete_type_error (r, rtype);
! 		r = error_mark_node;
! 	      }
! 	  }
! 
! 	/* R will have a TREE_CHAIN if and only if it has already been
! 	   processed by finish_member_declaration.  This can happen
! 	   if, for example, it is a TYPE_DECL for a class-scoped
! 	   ENUMERAL_TYPE; such a thing will already have been added to
! 	   the field list by tsubst_enum above.  */
! 	if (!TREE_CHAIN (r))
! 	  {
! 	    set_current_access_from_decl (r);
! 	    finish_member_declaration (r);
! 	  }
!       }
! 
!   /* Set up the list (TYPE_METHODS) and vector (CLASSTYPE_METHOD_VEC)
!      for this instantiation.  */
!   for (t = TYPE_METHODS (pattern); t; t = TREE_CHAIN (t))
!     {
!       tree r = tsubst (t, args, tf_error, NULL_TREE);
!       set_current_access_from_decl (r);
!       grok_special_member_properties (r);
!       finish_member_declaration (r);
!     }
  
!   /* Construct the DECL_FRIENDLIST for the new class type.  */
!   typedecl = TYPE_MAIN_DECL (type);
!   for (t = DECL_FRIENDLIST (TYPE_MAIN_DECL (pattern));
!        t != NULL_TREE;
!        t = TREE_CHAIN (t))
!     {
!       tree friends;
  
!       for (friends = TREE_VALUE (t);
! 	   friends != NULL_TREE;
! 	   friends = TREE_CHAIN (friends))
! 	if (TREE_PURPOSE (friends) == error_mark_node)
! 	  add_friend (type, 
! 		      tsubst_friend_function (TREE_VALUE (friends),
! 					      args));
! 	else
! 	  abort ();
!     }
  
!   for (t = CLASSTYPE_FRIEND_CLASSES (pattern);
!        t != NULL_TREE;
!        t = TREE_CHAIN (t))
!     {
!       tree friend_type = TREE_VALUE (t);
!       tree new_friend_type;
  
!       if (TREE_CODE (friend_type) == TEMPLATE_DECL)
! 	new_friend_type = tsubst_friend_class (friend_type, args);
!       else if (uses_template_parms (friend_type))
! 	new_friend_type = tsubst (friend_type, args,
! 				  tf_error | tf_warning, NULL_TREE);
!       else 
  	{
! 	  tree ns = decl_namespace_context (TYPE_MAIN_DECL (friend_type));
  
! 	  /* The call to xref_tag_from_type does injection for friend
! 	     classes.  */
! 	  push_nested_namespace (ns);
! 	  new_friend_type = 
! 	    xref_tag_from_type (friend_type, NULL_TREE, 1);
! 	  pop_nested_namespace (ns);
! 	}
  
!       if (TREE_CODE (friend_type) == TEMPLATE_DECL)
! 	/* Trick make_friend_class into realizing that the friend
! 	   we're adding is a template, not an ordinary class.  It's
! 	   important that we use make_friend_class since it will
! 	   perform some error-checking and output cross-reference
! 	   information.  */
! 	++processing_template_decl;
  
!       if (new_friend_type != error_mark_node)
!         make_friend_class (type, new_friend_type);
  
!       if (TREE_CODE (friend_type) == TEMPLATE_DECL)
! 	--processing_template_decl;
!     }
  
!   /* Now that TYPE_FIELDS and TYPE_METHODS are set up.  We can
!      instantiate templates used by this class.  */
!   for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
!     if (TREE_CODE (t) == FIELD_DECL)
!       {
! 	TREE_TYPE (t) = complete_type (TREE_TYPE (t));
! 	require_complete_type (t);
!       }
  
    /* Set the file and line number information to whatever is given for
       the class itself.  This puts error messages involving generated
       implicit functions at a predictable point, and the same point
       that would be used for non-template classes.  */
    lineno = DECL_SOURCE_LINE (typedecl);
    input_filename = DECL_SOURCE_FILE (typedecl);
  
--- 5226,5399 ----
       class.  */
    pushclass (type, 1);
  
!   /* Now members are processed in the order of declaration.  */
!   for (member = CLASSTYPE_DECL_LIST (pattern); member; member = TREE_CHAIN (member))
      {
!       tree t = TREE_VALUE (member);
  
!       if (TREE_PURPOSE (member))
! 	{
! 	  if (TYPE_P (t))
! 	    {
! 	      /* Build new CLASSTYPE_TAGS.  */
  
! 	      tree tag = t;
! 	      tree name = TYPE_IDENTIFIER (tag);
! 	      tree newtag;
! 
! 	      newtag = tsubst (tag, args, tf_error, NULL_TREE);
! 	      my_friendly_assert (newtag != error_mark_node, 20010206);
! 	      if (TREE_CODE (newtag) != ENUMERAL_TYPE)
! 		{
! 		  if (TYPE_LANG_SPECIFIC (tag) && CLASSTYPE_IS_TEMPLATE (tag))
! 		    /* Unfortunately, lookup_template_class sets
! 		       CLASSTYPE_IMPLICIT_INSTANTIATION for a partial
! 		       instantiation (i.e., for the type of a member template
! 		       class nested within a template class.)  This behavior is
! 		       required for maybe_process_partial_specialization to work
! 		       correctly, but is not accurate in this case; the TAG is not
! 		       an instantiation of anything.  (The corresponding
! 		       TEMPLATE_DECL is an instantiation, but the TYPE is not.) */
! 		    CLASSTYPE_USE_TEMPLATE (newtag) = 0;
! 
! 		  /* Now, we call pushtag to put this NEWTAG into the scope of
! 		     TYPE.  We first set up the IDENTIFIER_TYPE_VALUE to avoid
! 		     pushtag calling push_template_decl.  We don't have to do
! 		     this for enums because it will already have been done in
! 		     tsubst_enum.  */
! 		  if (name)
! 		    SET_IDENTIFIER_TYPE_VALUE (name, newtag);
! 		  pushtag (name, newtag, /*globalize=*/0);
! 		}
! 	    }
! 	  else if (TREE_CODE (t) == FUNCTION_DECL 
! 		   || DECL_FUNCTION_TEMPLATE_P (t))
! 	    {
! 	      /* Build new TYPE_METHODS.  */
  
! 	      tree r = tsubst (t, args, tf_error, NULL_TREE);
! 	      set_current_access_from_decl (r);
! 	      grok_special_member_properties (r);
! 	      finish_member_declaration (r);
! 	    }
! 	  else
! 	    {
! 	      /* Build new TYPE_FIELDS.  */
  
! 	      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, tf_error | tf_warning, NULL_TREE);
! 		  if (TREE_CODE (r) == VAR_DECL)
! 		    {
! 		      tree init;
! 
! 		      if (DECL_INITIALIZED_IN_CLASS_P (r))
! 			init = tsubst_expr (DECL_INITIAL (t), args,
! 					    tf_error | tf_warning, NULL_TREE);
! 		      else
! 			init = NULL_TREE;
! 
! 		      finish_static_data_member_decl (r, init,
! 						      /*asmspec_tree=*/NULL_TREE, 
! 						      /*flags=*/0);
! 
! 		      if (DECL_INITIALIZED_IN_CLASS_P (r))
! 			check_static_variable_definition (r, TREE_TYPE (r));
! 		    }
! 		  else if (TREE_CODE (r) == FIELD_DECL)
! 		    {
! 		      /* Determine whether R has a valid type and can be
! 			 completed later.  If R is invalid, then it is
! 			 replaced by error_mark_node so that it will not be
! 			 added to TYPE_FIELDS.  */
! 		      tree rtype = TREE_TYPE (r);
! 		      if (can_complete_type_without_circularity (rtype))
! 			complete_type (rtype);
! 
! 		      if (!COMPLETE_TYPE_P (rtype))
! 			{
! 			  cxx_incomplete_type_error (r, rtype);
! 		  	  r = error_mark_node;
! 			}
! 		    }
! 
! 		  /* If it is a TYPE_DECL for a class-scoped ENUMERAL_TYPE,
! 		     such a thing will already have been added to the field
! 		     list by tsubst_enum in finish_member_declaration in the
! 		     CLASSTYPE_TAGS case above.  */
! 		  if (!(TREE_CODE (r) == TYPE_DECL
! 			&& TREE_CODE (TREE_TYPE (r)) == ENUMERAL_TYPE
! 			&& TYPE_CONTEXT (TREE_TYPE (r)) == type))
! 		    {
! 		      set_current_access_from_decl (r);
! 		      finish_member_declaration (r);
! 		    }
! 	        }
! 	    }
! 	}
!       else
  	{
! 	  if (TYPE_P (t) || DECL_CLASS_TEMPLATE_P (t))
! 	    {
! 	      /* Build new CLASSTYPE_FRIEND_CLASSES.  */
  
! 	      tree friend_type = t;
! 	      tree new_friend_type;
  
! 	      if (TREE_CODE (friend_type) == TEMPLATE_DECL)
! 		new_friend_type = tsubst_friend_class (friend_type, args);
! 	      else if (uses_template_parms (friend_type))
! 		new_friend_type = tsubst (friend_type, args,
! 					  tf_error | tf_warning, NULL_TREE);
! 	      else 
! 		{
! 		  tree ns = decl_namespace_context (TYPE_MAIN_DECL (friend_type));
  
! 		  /* The call to xref_tag_from_type does injection for friend
! 		     classes.  */
! 		  push_nested_namespace (ns);
! 		  new_friend_type = 
! 		    xref_tag_from_type (friend_type, NULL_TREE, 1);
! 		  pop_nested_namespace (ns);
! 		}
  
! 	      if (TREE_CODE (friend_type) == TEMPLATE_DECL)
! 		/* Trick make_friend_class into realizing that the friend
! 		   we're adding is a template, not an ordinary class.  It's
! 		   important that we use make_friend_class since it will
! 		   perform some error-checking and output cross-reference
! 		   information.  */
! 		++processing_template_decl;
  
! 	      if (new_friend_type != error_mark_node)
! 	        make_friend_class (type, new_friend_type);
! 
! 	      if (TREE_CODE (friend_type) == TEMPLATE_DECL)
! 		--processing_template_decl;
! 	    }
! 	  else
! 	    {
! 	      /* Build new DECL_FRIENDLIST.  */
! 
! 	      add_friend (type, 
! 			  tsubst_friend_function (t, args));
! 	    }
! 	}
!     }
  
    /* Set the file and line number information to whatever is given for
       the class itself.  This puts error messages involving generated
       implicit functions at a predictable point, and the same point
       that would be used for non-template classes.  */
+   typedecl = TYPE_MAIN_DECL (type);
    lineno = DECL_SOURCE_LINE (typedecl);
    input_filename = DECL_SOURCE_FILE (typedecl);
  
diff -cprN gcc-main-save/gcc/cp/semantics.c gcc-main-new/gcc/cp/semantics.c
*** gcc-main-save/gcc/cp/semantics.c	Fri Oct 18 22:29:13 2002
--- gcc-main-new/gcc/cp/semantics.c	Sat Oct 26 18:12:56 2002
*************** begin_class_definition (t)
*** 1754,1759 ****
--- 1754,1760 ----
  	  TYPE_BINFO_BASETYPES (t) = NULL_TREE;
  	  TYPE_FIELDS (t) = NULL_TREE;
  	  TYPE_METHODS (t) = NULL_TREE;
+ 	  CLASSTYPE_DECL_LIST (t) = NULL_TREE;
  	  CLASSTYPE_TAGS (t) = NULL_TREE;
  	  CLASSTYPE_VBASECLASSES (t) = NULL_TREE;
  	  TYPE_SIZE (t) = NULL_TREE;
*************** finish_member_declaration (decl)
*** 1835,1840 ****
--- 1836,1843 ----
    if (DECL_LANG_SPECIFIC (decl) && DECL_LANGUAGE (decl) == lang_c)
      SET_DECL_LANGUAGE (decl, lang_cplusplus);
  
+   maybe_add_class_template_decl_list (current_class_type, decl, /*friend_p=*/0);
+ 
    /* Put functions on the TYPE_METHODS list and everything else on the
       TYPE_FIELDS list.  Note that these are built up in reverse order.
       We reverse them (to obtain declaration order) in finish_struct.  */
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/instantiate1.C gcc-main-new/gcc/testsuite/g++.dg/template/instantiate1.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/instantiate1.C	Tue Jul  2 22:56:01 2002
--- gcc-main-new/gcc/testsuite/g++.dg/template/instantiate1.C	Sat Oct 26 15:21:41 2002
*************** template <class T> struct X {
*** 8,19 ****
    T t;				// { dg-error "incomplete" }
  };
  
! template <class T> struct Y {	// { dg-error "instantiated" }
!   X<T> x;
  };
  
! template <class T> struct Z {	// { dg-error "instantiated|declaration" }
!   Y<Z<T> > y;
  };
  
  struct ZZ : Z<int>
--- 8,19 ----
    T t;				// { dg-error "incomplete" }
  };
  
! template <class T> struct Y {
!   X<T> x;			// { dg-error "instantiated" }
  };
  
! template <class T> struct Z {	// { dg-error "declaration" }
!   Y<Z<T> > y;			// { dg-error "instantiated" }
  };
  
  struct ZZ : Z<int>
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/instantiate3.C gcc-main-new/gcc/testsuite/g++.dg/template/instantiate3.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/instantiate3.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/instantiate3.C	Sat Oct 26 15:22:03 2002
***************
*** 0 ****
--- 1,17 ----
+ // { dg-do compile }
+ // Origin: Scott Snyder <snyder@fnal.gov>
+ 
+ // PR c++/7639
+ // ICE when accessing member with incomplete type.
+ 
+ class ACE_Null_Mutex;	// { dg-error "forward declaration" }
+ 
+ template <class TYPE>
+ struct ACE_Cleanup_Adapter
+ {
+   TYPE &object ()
+   { return object_; }	// { dg-error "no member" }
+   TYPE object_;		// { dg-error "incomplete type" }
+ };
+ 
+ template class ACE_Cleanup_Adapter<ACE_Null_Mutex>; // { dg-error "instantiated from here" }
diff -cprN gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/crash10.C gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/crash10.C
*** gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/crash10.C	Thu Dec 17 04:54:07 1998
--- gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/crash10.C	Sat Oct 26 17:44:33 2002
***************
*** 3,11 ****
  template<int M, int N>
  class GCD {
  public:
!   enum { val = (N == 0) ? M : GCD<N, M % N>::val }; 
  };
  
  int main() {
!   GCD< 1, 0 >::val; // ERROR - division
  }
--- 3,11 ----
  template<int M, int N>
  class GCD {
  public:
!   enum { val = (N == 0) ? M : GCD<N, M % N>::val }; // ERROR - division
  };
  
  int main() {
!   GCD< 1, 0 >::val; // ERROR - instantiated
  }
diff -cprN gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/derived3.C gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/derived3.C
*** gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/derived3.C	Thu Feb 28 03:29:44 2002
--- gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/derived3.C	Sat Oct 26 16:45:10 2002
***************
*** 6,15 ****
  
  template<class T>
  class X {
! 	class Y : public T {}; // ERROR - invalid base type
! 	Y y;
  };
  int main() {
! 	X<int> x;
  }
  
--- 6,15 ----
  
  template<class T>
  class X {
! 	class Y : public T {};
! 	Y y;			// ERROR - invalid base type
  };
  int main() {
! 	X<int> x;		// ERROR - instantiated
  }
  
diff -cprN gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/spec28.C gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/spec28.C
*** gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/spec28.C	Sat Sep  4 22:09:08 1999
--- gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/spec28.C	Sat Oct 26 16:48:43 2002
***************
*** 2,9 ****
  
  template <class T> 
  struct S1 {
-   friend bool f<>(const S1&);
    typedef T X;
  };
  
  template <class T>
--- 2,9 ----
  
  template <class T> 
  struct S1 {
    typedef T X;
+   friend bool f<>(const S1&);
  };
  
  template <class T>


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [C++ PATCH] Class template instantiation according to core issue 287.
  2002-10-26  7:10 [C++ PATCH] Class template instantiation according to core issue 287 Kriang Lerdsuwanakij
@ 2002-10-27 22:29 ` Mark Mitchell
  2002-10-27 22:42   ` Gabriel Dos Reis
  2002-10-29  5:56   ` Kriang Lerdsuwanakij
  0 siblings, 2 replies; 4+ messages in thread
From: Mark Mitchell @ 2002-10-27 22:29 UTC (permalink / raw)
  To: Kriang Lerdsuwanakij, gcc-patches



--On Saturday, October 26, 2002 09:13:31 PM +0700 Kriang Lerdsuwanakij 
<lerdsuwa@users.sourceforge.net> wrote:

> Hi
>
> After some thought, I decide to implement the proposed resolution
> for Core issue 287 (class template instantiation dependencies).  Although
> the core issue is still under review, it is better than our current ad
> hoc solution.  With the patch below, members and friends are processed
> according to the order of declaration during class template instantiation.

This is the right approach.

> A new field CLASSTYPE_DECL_LIST is added to the type lang_specific node
> to hold all class declaration in the correct order.

Probably, we should just figure out a way to use TYPE_FIELDs; that's
already got stuff other than FIELD_DECLs on it.  And, in a template,
nothing in the middle end should see the TYPE_FIELDs list; those types
should not escape the front end.  We do not need to do that optimization
yet, though; correctness first.

> Bootstrapped and tested on i686-pc-linux-gnu with no regression.
> OK to commit to main trunk?

This is a regression, right?  If so, commit it to both the mainline
and the branch.

>   + /* Add T to CLASSTYPE_DECL_LIST of TYPE which will be used
> +    later during class template instantiation.
> +    When FRIEND_P is zero, T can be member data, member
> +    function, nested type, or member class template.
> +    When FRIEND_P is nonzero, T is either friend class or
> +    friend function.  */

Reword this to talk abut the kinds of tree nodes:

  T can be a non-static data member (FIELD_DECL), a member function
  (FUNCTION_DECL), a nested class (RECORD_TYPE), etc.

I want us to start thinking of the tree structure as strongly typed.

Also, what about non-static data members?

>   !   /* The TYPE_FIELDS, TYPE_METHODS, and CLASSTYPE_TAGS are all in
> !      reverse order.  Put them in declaration order now.  */

Just say:

  /* The following lists are all in reverse order...

Then we do not have list each one explicitly, and keep updating them.

> +    TREE_PURPOSE of each TREE_LIST provides the context of declaration
> +    and TREE_VALUE is the actual declaration.  For friends, TREE_PURPOSE
> +    is NULL_TREE.  Otherwise it is the class templates itself.  */

Just say:

  /* The TREE_PURPOSE of each TREE_LIST node is NULL_TREE for a friend,
     and the RECORD_TYPE/UNION_TYPE for the class template otherwise.  */

Thanks!

-- 
Mark Mitchell                mark@codesourcery.com
CodeSourcery, LLC            http://www.codesourcery.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [C++ PATCH] Class template instantiation according to core  issue 287.
  2002-10-27 22:29 ` Mark Mitchell
@ 2002-10-27 22:42   ` Gabriel Dos Reis
  2002-10-29  5:56   ` Kriang Lerdsuwanakij
  1 sibling, 0 replies; 4+ messages in thread
From: Gabriel Dos Reis @ 2002-10-27 22:42 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: Kriang Lerdsuwanakij, gcc-patches

Mark Mitchell <mark@codesourcery.com> writes:

| Reword this to talk abut the kinds of tree nodes:
| 
|   T can be a non-static data member (FIELD_DECL), a member function
|   (FUNCTION_DECL), a nested class (RECORD_TYPE), etc.
| 
| I want us to start thinking of the tree structure as strongly typed.

Definitely!  I would also like to see us go away from abusing the tree
structure.  That would save us much of troubles.

-- Gaby

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [C++ PATCH] Class template instantiation according to core issue 287.
  2002-10-27 22:29 ` Mark Mitchell
  2002-10-27 22:42   ` Gabriel Dos Reis
@ 2002-10-29  5:56   ` Kriang Lerdsuwanakij
  1 sibling, 0 replies; 4+ messages in thread
From: Kriang Lerdsuwanakij @ 2002-10-29  5:56 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: gcc-patches

Mark Mitchell wrote:

>
>> Bootstrapped and tested on i686-pc-linux-gnu with no regression.
>> OK to commit to main trunk?
>
>
> This is a regression, right? If so, commit it to both the mainline
> and the branch.

It's only a regression in mainline. Other regressions in the branch
appear to unrelate to this issue. So I am going to commit it only on
mainline.

>
>> + /* Add T to CLASSTYPE_DECL_LIST of TYPE which will be used
>> + later during class template instantiation.
>> + When FRIEND_P is zero, T can be member data, member
>> + function, nested type, or member class template.
>> + When FRIEND_P is nonzero, T is either friend class or
>> + friend function. */
>
>
> Reword this to talk abut the kinds of tree nodes:
>
> T can be a non-static data member (FIELD_DECL), a member function
> (FUNCTION_DECL), a nested class (RECORD_TYPE), etc.
>
> I want us to start thinking of the tree structure as strongly typed.
>
> Also, what about non-static data members?

Both static and non-static data members are handled in the case
TYPE_FIELDS. They are VAR_DECL and FIELD_DECL respectively.

--Kriang



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2002-10-29 13:56 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-10-26  7:10 [C++ PATCH] Class template instantiation according to core issue 287 Kriang Lerdsuwanakij
2002-10-27 22:29 ` Mark Mitchell
2002-10-27 22:42   ` Gabriel Dos Reis
2002-10-29  5:56   ` Kriang Lerdsuwanakij

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).