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]
Other format: [Raw text]

C++ PATCH to anonymous union handling


This patch implements something I've been meaning to do for a while: we now
deal with anonymous unions by declaring the names to be COMPONENT_REFs
rather than by playing games with RTL.  This also changes the mangling of
static duration anonymous unions to be based on the name of the first named
field in a depthwise search; this has no binary compatibility impact,
however, since affected code was previously broken.  An example is
g++.brendan/union1.C, which is fixed by this patch.

2002-12-18  Jason Merrill  <jason@redhat.com>

	Handle anonymous unions at the tree level.
	C++ ABI change: Mangle anonymous unions using the name of their
	first named field (by depth-first search).  Should not cause
	binary compatibility problems, though, as the compiler previously
	didn't emit anything for affected unions.
	* cp-tree.def (ALIAS_DECL): New tree code.
	* decl2.c (build_anon_union_vars): Build ALIAS_DECLs.  Return the
	first field, not the largest.
	(finish_anon_union): Don't mess with RTL.  Do set DECL_ASSEMBLER_NAME,
	push the decl, and write it out at namespace scope.
	* decl.c (lookup_name_real): See through an ALIAS_DECL.
	(pushdecl): Add namespace bindings for ALIAS_DECLs.
	* rtti.c (unemitted_tinfo_decl_p): Don't try to look at the name
	of a decl which doesn't have one.
	* typeck.c (build_class_member_access_expr): Don't recurse if
	we already have the type we want.

*** cp-tree.def.~1~	2002-10-06 15:46:36.000000000 -0400
--- cp-tree.def	2002-12-18 17:07:15.000000000 -0500
*************** DEFTREECODE (THROW_EXPR, "throw_expr", '
*** 89,94 ****
--- 89,98 ----
     these to avoid actually creating instances of the empty classes.  */
  DEFTREECODE (EMPTY_CLASS_EXPR, "empty_class_expr", 'e', 0)
  
+ /* A DECL which is really just a placeholder for an expression.  Used to
+    implement non-class scope anonymous unions.  */
+ DEFTREECODE (ALIAS_DECL, "alias_decl", 'd', 0)
+ 
  /* A reference to a member function or member functions from a base
     class.  BASELINK_FUNCTIONS gives the FUNCTION_DECL,
     TEMPLATE_DECL, OVERLOAD, or TEMPLATE_ID_EXPR corresponding to the
*** decl2.c.~1~	2002-12-16 15:30:26.000000000 -0500
--- decl2.c	2002-12-18 19:07:22.000000000 -0500
*************** static int maybe_emit_vtables (tree);
*** 66,72 ****
  static int is_namespace_ancestor PARAMS ((tree, tree));
  static void add_using_namespace PARAMS ((tree, tree, int));
  static tree ambiguous_decl PARAMS ((tree, tree, tree,int));
! static tree build_anon_union_vars PARAMS ((tree, tree*, int, int));
  static int acceptable_java_type PARAMS ((tree));
  static void output_vtable_inherit PARAMS ((tree));
  static tree start_objects PARAMS ((int, int));
--- 66,72 ----
  static int is_namespace_ancestor PARAMS ((tree, tree));
  static void add_using_namespace PARAMS ((tree, tree, int));
  static tree ambiguous_decl PARAMS ((tree, tree, tree,int));
! static tree build_anon_union_vars PARAMS ((tree));
  static int acceptable_java_type PARAMS ((tree));
  static void output_vtable_inherit PARAMS ((tree));
  static tree start_objects PARAMS ((int, int));
*************** defer_fn (fn)
*** 1269,1290 ****
    VARRAY_PUSH_TREE (deferred_fns, fn);
  }
  
! /* Hunts through the global anonymous union ANON_DECL, building
!    appropriate VAR_DECLs.  Stores cleanups on the list of ELEMS, and
!    returns a VAR_DECL whose size is the same as the size of the
!    ANON_DECL, if one is available.
! 
!    FIXME: we should really handle anonymous unions by binding the names
!    of the members to COMPONENT_REFs rather than this kludge.  */
! 
! static tree 
! build_anon_union_vars (anon_decl, elems, static_p, external_p)
!      tree anon_decl;
!      tree* elems;
!      int static_p;
!      int external_p;
  {
!   tree type = TREE_TYPE (anon_decl);
    tree main_decl = NULL_TREE;
    tree field;
  
--- 1269,1283 ----
    VARRAY_PUSH_TREE (deferred_fns, fn);
  }
  
! /* Walks through the namespace- or function-scope anonymous union OBJECT,
!    building appropriate ALIAS_DECLs.  Returns one of the fields for use in
!    the mangled name.  */
! 
! static tree
! build_anon_union_vars (object)
!      tree object;
  {
!   tree type = TREE_TYPE (object);
    tree main_decl = NULL_TREE;
    tree field;
  
*************** build_anon_union_vars (anon_decl, elems,
*** 1298,1309 ****
         field = TREE_CHAIN (field))
      {
        tree decl;
  
        if (DECL_ARTIFICIAL (field))
  	continue;
        if (TREE_CODE (field) != FIELD_DECL)
  	{
! 	  cp_pedwarn_at ("`%#D' invalid; an anonymous union can only have non-static data members",
  			 field);
  	  continue;
  	}
--- 1291,1304 ----
         field = TREE_CHAIN (field))
      {
        tree decl;
+       tree ref;
  
        if (DECL_ARTIFICIAL (field))
  	continue;
        if (TREE_CODE (field) != FIELD_DECL)
  	{
! 	  cp_pedwarn_at ("\
! `%#D' invalid; an anonymous union can only have non-static data members",
  			 field);
  	  continue;
  	}
*************** build_anon_union_vars (anon_decl, elems,
*** 1313,1367 ****
        else if (TREE_PROTECTED (field))
  	cp_pedwarn_at ("protected member `%#D' in anonymous union", field);
  
!       if (DECL_NAME (field) == NULL_TREE
! 	  && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
! 	{
! 	  decl = build_anon_union_vars (field, elems, static_p, external_p);
! 	  if (!decl)
! 	    continue;
! 	}
!       else if (DECL_NAME (field) == NULL_TREE)
! 	continue;
!       else
  	{
! 	  decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field));
! 	  /* tell `pushdecl' that this is not tentative.  */
! 	  DECL_INITIAL (decl) = error_mark_node;
  	  TREE_PUBLIC (decl) = 0;
! 	  TREE_STATIC (decl) = static_p;
! 	  DECL_EXTERNAL (decl) = external_p;
  	  decl = pushdecl (decl);
- 	  DECL_INITIAL (decl) = NULL_TREE;
  	}
  
!       /* Only write out one anon union element--choose the largest
! 	 one.  We used to try to find one the same size as the union,
! 	 but that fails if the ABI forces us to align the union more
! 	 strictly.  */
!       if (main_decl == NULL_TREE
! 	  || tree_int_cst_lt (DECL_SIZE (main_decl), DECL_SIZE (decl)))
! 	{
! 	  if (main_decl)
! 	    TREE_ASM_WRITTEN (main_decl) = 1;
! 	  main_decl = decl;
! 	}
!       else 
! 	/* ??? This causes there to be no debug info written out
! 	   about this decl.  */
! 	TREE_ASM_WRITTEN (decl) = 1;
!       
!       if (DECL_NAME (field) == NULL_TREE
! 	  && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
! 	/* The remainder of the processing was already done in the
! 	   recursive call.  */
! 	continue;
! 
!       /* If there's a cleanup to do, it belongs in the
! 	 TREE_PURPOSE of the following TREE_LIST.  */
!       *elems = tree_cons (NULL_TREE, decl, *elems);
!       TREE_TYPE (*elems) = type;
      }
!   
    return main_decl;
  }
  
--- 1308,1332 ----
        else if (TREE_PROTECTED (field))
  	cp_pedwarn_at ("protected member `%#D' in anonymous union", field);
  
!       ref = build_class_member_access_expr (object, field, NULL_TREE,
! 					    false);
! 
!       if (DECL_NAME (field))
  	{
! 	  decl = build_decl (ALIAS_DECL, DECL_NAME (field), TREE_TYPE (field));
! 	  DECL_INITIAL (decl) = ref;	    
  	  TREE_PUBLIC (decl) = 0;
! 	  TREE_STATIC (decl) = 0;
! 	  DECL_EXTERNAL (decl) = 1;
  	  decl = pushdecl (decl);
  	}
+       else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+ 	decl = build_anon_union_vars (ref);
  
!       if (main_decl == NULL_TREE)
! 	main_decl = decl;
      }
! 
    return main_decl;
  }
  
*************** finish_anon_union (anon_union_decl)
*** 1376,1383 ****
    tree type = TREE_TYPE (anon_union_decl);
    tree main_decl;
    int public_p = TREE_PUBLIC (anon_union_decl);
-   int static_p = TREE_STATIC (anon_union_decl);
-   int external_p = DECL_EXTERNAL (anon_union_decl);
  
    /* The VAR_DECL's context is the same as the TYPE's context.  */
    DECL_CONTEXT (anon_union_decl) = DECL_CONTEXT (TYPE_NAME (type));
--- 1341,1346 ----
*************** finish_anon_union (anon_union_decl)
*** 1393,1421 ****
  
    if (!processing_template_decl)
      {
!       main_decl 
! 	= build_anon_union_vars (anon_union_decl,
! 				 &DECL_ANON_UNION_ELEMS (anon_union_decl),
! 				 static_p, external_p);
!       
        if (main_decl == NULL_TREE)
  	{
! 	  warning ("anonymous aggregate with no members");
  	  return;
  	}
  
!       if (static_p)
! 	{
! 	  make_decl_rtl (main_decl, 0);
! 	  COPY_DECL_RTL (main_decl, anon_union_decl);
! 	  expand_anon_union_decl (anon_union_decl, 
! 				  NULL_TREE,
! 				  DECL_ANON_UNION_ELEMS (anon_union_decl));
! 	  return;
! 	}
      }
  
!   add_decl_stmt (anon_union_decl);
  }
  
  /* Auxiliary functions to make type signatures for
--- 1356,1382 ----
  
    if (!processing_template_decl)
      {
!       main_decl = build_anon_union_vars (anon_union_decl);
! 
        if (main_decl == NULL_TREE)
  	{
! 	  warning ("anonymous union with no members");
  	  return;
  	}
  
!       /* Use main_decl to set the mangled name.  */
!       DECL_NAME (anon_union_decl) = DECL_NAME (main_decl);
!       mangle_decl (anon_union_decl);
!       DECL_NAME (anon_union_decl) = NULL_TREE;
      }
  
!   pushdecl (anon_union_decl);
!   if (building_stmt_tree ()
!       && at_function_scope_p ())
!     add_decl_stmt (anon_union_decl);
!   else if (!processing_template_decl)
!     rest_of_decl_compilation (anon_union_decl, NULL,
! 			      toplevel_bindings_p (), at_eof);
  }
  
  /* Auxiliary functions to make type signatures for
*** decl.c.~1~	2002-12-18 11:20:29.000000000 -0500
--- decl.c	2002-12-18 17:11:16.000000000 -0500
*************** pushdecl (x)
*** 4051,4056 ****
--- 4051,4057 ----
    		&& t != NULL_TREE)
   	      && (TREE_CODE (x) == TYPE_DECL
   		  || TREE_CODE (x) == VAR_DECL
+  		  || TREE_CODE (x) == ALIAS_DECL
   		  || TREE_CODE (x) == NAMESPACE_DECL
   		  || TREE_CODE (x) == CONST_DECL
   		  || TREE_CODE (x) == TEMPLATE_DECL))
*************** does not match lookup in the current sco
*** 6228,6233 ****
--- 6229,6237 ----
    else if (from_obj)
      val = from_obj;
  
+   if (val && TREE_CODE (val) == ALIAS_DECL)
+     val = DECL_INITIAL (val);
+ 
    return val;
  }
  
*** rtti.c.~1~	2002-12-16 15:30:30.000000000 -0500
--- rtti.c	2002-12-19 10:42:30.000000000 -0500
*************** unemitted_tinfo_decl_p (t, data)
*** 1444,1450 ****
  {
    if (/* It's a var decl */
        TREE_CODE (t) == VAR_DECL
!       /* whos name points back to itself */
        && IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == t
        /* whose name's type is non-null */
        && TREE_TYPE (DECL_NAME (t))
--- 1444,1452 ----
  {
    if (/* It's a var decl */
        TREE_CODE (t) == VAR_DECL
!       /* which has a name */
!       && DECL_NAME (t)
!       /* whose name points back to itself */
        && IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == t
        /* whose name's type is non-null */
        && TREE_TYPE (DECL_NAME (t))
*** typeck.c.~1~	2002-12-18 11:20:30.000000000 -0500
--- typeck.c	2002-12-19 10:53:31.000000000 -0500
*************** build_class_member_access_expr (tree obj
*** 1987,1993 ****
  	 OBJECT so that it refers to the class containing the
  	 anonymous union.  Generate a reference to the anonymous union
  	 itself, and recur to find MEMBER.  */
!       if (ANON_AGGR_TYPE_P (DECL_CONTEXT (member)))
  	{
  	  tree anonymous_union;
  
--- 1987,1994 ----
  	 OBJECT so that it refers to the class containing the
  	 anonymous union.  Generate a reference to the anonymous union
  	 itself, and recur to find MEMBER.  */
!       if (ANON_AGGR_TYPE_P (DECL_CONTEXT (member))
! 	  && !same_type_p (object_type, DECL_CONTEXT (member)))
  	{
  	  tree anonymous_union;
  

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