This is the mail archive of the gcc@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]

[RFC] Covariant return patch for GCC 3.1


Hi y'all,

    While working on a project of my own, I ran into some severe
problems moving my work from Windows 2000 to Linux, namely the lack of
support for covariant returns. I created a patch for the GCC 3.1 release
( not the branch ) to allow me to use my old code without an extensive
rewrite. The patch is semi-stable; it works for my purposes, but
introduces quite a few problems. However, it might be useful to base a
real solution on and works fine if you have a pressing need to support
covariance. Thus, I am giving it here.

   I would appreciate any suggestions as to where certain components of
the patch should be placed and the right way to do things. I need this
patch and am going to use it in my own development, so I'd like for it
to be as close to correct as possible. :)

   Also, I have no idea whether or not this will work on anything other
than the 2.4 Kernel of Linux. I hope so. ;)

   Everyone loves bullets, right? How about the MASSIVE PROBLEMS
introduced by this patch first?

* This patch constitutes an ABI change. A new hidden parameter,
__classtype_parm, is used to indicate which return value is desired. So,
applying this patch will prevent you from linking with any libraries
which include (possible) covariant return functions, but were compiled
with the actual ABI.

* Weak symbols HAVE to be supported. The patch uses the vtable pointer
for the desired class ( i.e. vptr for 'BASE'; never 'BASE in DERIVED' )
to indicate the return type. Thus, this value must be the same across
libraries and so forth.

* gcc must be configured with '--enable-languages=c,c++'. The java
support library will not compile with this patch. ( I have not yet
determined why, but I think it has to do with __classtype_parm not being
introduced into certain declarations... )

   Next, the smaller problems :

- Covariant return values must be polymorphic classes. This is due to
the fact that the vptr is used as identification.

- Derived classes which overload covariant return functions need to use
'virtual' in the declaration. Most likely, this is because my code to
identify possible covariant return functions occurs too "early".

   Finally, the good points :

+ It works, though it's only been lightly tested. I've tried some of the
test cases I've seen which demonstrate the problem, the standard library
( which has one or two that get the new parameter, but that's it ), and
the libraries for my project. I plan to try Qt soon and see if that
comes out allright...

+ The solution is a simple one and fairly easy to understand. The use of

+ the vptr as the hidden parameter should be fairly easy to change if 
+ something better can be found.

   Please be patient with my explanation and forgive the horrible
placement of some of the patch code. My knowledge of where to place
certain code was primarily derived from using "gcc -dy" then checking
how the calls where made in "cp/parse.y". So, I ask your forgiveness.

   All file references refer to the "gcc/cp" subdirectory.

   Possible covariant return functions are identified as being "any
virtual function returning a pointer or reference to a structure". Once
identified, the new artificial parameter, __classtype_parm, is added to
the parameter list immediately following the this pointer. This is
accomplished in "finish_member_declaraion" in "semantics.c" by utilizing
the new functions "decl_needs_classtype_parm_p()" and
"decl_has_classtype_parm_p()" in "typeck.c" and "add_classtype_parm()"
in "tree.c". This is also done in "grokfndecl()" in "decl.c".

   In the body of the function, the return statement is mangled.
Ordinarily, a return statement of the form "return expr;" generates code
akin to :


  __result_slot = expr;
  return;


In a function with covariant returns, this becomes an (admittedly ugly)
passel of if statements :


  __result_slot = expr;

  if ( __classtype_parm = <vptr of BASE> )
    {
       __result_slot = static_cast<BASE *> ( __result_slot );
      return;
    }

  if ( __classtype_parm = <vptr of BASE2> )
                 .
                 .
                 .

  return;

This change does not occur in thunk functions as the covariance is
handled in the called function. This is accomplished in
"finish_return_stmt()" in "semantics.c" by utilizing the new functions
"decl_has_classtype_parm_p()" in "typeck.c" and "get_raw_vtbl_address()"
in "init.c".

   When a covariant function is called, we need to set the
__classtype_parm to the vptr for the desired return type. This is
accomplished in "call.c" by two changes. First, we need to change the
way functions are compared to account for the new artificial parameter.
I changed "add_function_candidate()" in "call.c" and "check_classfn()"
in "decl2.c" to temporarily remove __classtype_parm while it checks the
new candidate. Second, we need to introduce some code to set the new
parameter. A change at the very beginning "build_over_call()" in
"call.c" to set the argument during argument evaluation was used. The
new function "set_classtype_arg()" in "tree.c" performs the actual work
of setting the parameter.

   Also, I removed the sorry() for covariant returns in "search.c",
added declarations to "cp-tree.h" and inserted "__classtype_parm" as a
new reserved identifier in "decl.c".

--- David Craig Hunt 
--- hunt.d@attbi.com

Index: gcc/gcc/cp/call.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.307.2.6
diff -c -3 -p -r1.307.2.6 call.c
*** gcc/gcc/cp/call.c	13 Apr 2002 01:31:06 -0000	1.307.2.6
--- gcc/gcc/cp/call.c	10 Jun 2002 19:39:34 -0000
*************** static tree convert_class_to_reference P
*** 102,107 ****
--- 102,108 ----
  static tree direct_reference_binding PARAMS ((tree, tree));
  static int promoted_arithmetic_type_p PARAMS ((tree));
  static tree conditional_conversion PARAMS ((tree, tree));
+ static void debug_candidates PARAMS ((struct z_candidate *)); /* DCH 
+ 2002.05.22 */
  
  tree
  build_vfield_ref (datum, type)
*************** struct z_candidate {
*** 592,597 ****
--- 593,627 ----
    ((struct z_candidate *)WRAPPER_PTR (TREE_OPERAND (NODE, 1)))
  #define USER_CONV_FN(NODE) (USER_CONV_CAND (NODE)->fn)
  
+ /* DCH 2002.05.22 -- CHANGES_BEGIN */
+ static void
+ debug_candidates ( struct z_candidate *candidates )
+ {
+   int i;
+ 
+   i = 0;
+   while ( candidates )
+     {
+        fprintf ( stderr, "<<< Candidate #%d follows : >>>", i );
+        fprintf ( stderr, "--- fn\n" );
+        debug_tree ( candidates->fn );
+        fprintf ( stderr, "--- convs\n" );
+        debug_tree ( candidates->convs );
+        fprintf ( stderr, "--- second_conv\n" );
+        debug_tree ( candidates->second_conv );
+        fprintf ( stderr, "--- viable : %d\n", candidates->viable );
+        fprintf ( stderr, "--- basetype_path\n" );
+        debug_tree ( candidates->basetype_path );
+        fprintf ( stderr, "--- template\n" );
+        debug_tree ( candidates->template );
+        fprintf ( stderr, "--- warnings\n" );
+        debug_tree ( candidates->warnings );
+        candidates = candidates->next;
+     }
+   fprintf ( stderr, "<<< End of candidate dump >>>\n" );
+ }
+ /* DCH 2002.05.22 -- CHANGES_END */
+ 
  int
  null_ptr_cst_p (t)
       tree t;
*************** add_function_candidate (candidates, fn, 
*** 1333,1338 ****
--- 1363,1371 ----
    tree convs;
    tree parmnode, argnode;
    int viable = 1;
+   tree classtype_parm; /* DCH */ /* The saved classtype parameter */
+ 
+   classtype_parm = NULL_TREE; /*DCH*/ /* Used to flag */
  
    /* The `this', `in_chrg' and VTT arguments to constructors are not
       considered in overload resolution.  */
*************** add_function_candidate (candidates, fn, 
*** 1342,1347 ****
--- 1375,1389 ----
        arglist = skip_artificial_parms_for (fn, arglist);
      }
  
+   /* DCH 2002.05.22 -- CHANGES_BEGIN */
+   if ( decl_has_classtype_parm_p (fn) )
+     {
+       classtype_parm = TREE_CHAIN (parmlist);
+ 
+       TREE_CHAIN (parmlist) = TREE_CHAIN (classtype_parm);
+     }
+   /* DCH 2002.05.22 -- CHANGES_END */
+ 
    len = list_length (arglist);
    convs = make_tree_vec (len);
  
*************** add_function_candidate (candidates, fn, 
*** 1438,1443 ****
--- 1480,1491 ----
      }
  
   out:
+ 
+   /* DCH 2002.05.22 -- CHANGES_BEGIN */
+   if ( classtype_parm != NULL_TREE )
+     TREE_CHAIN (parmlist) = classtype_parm;
+   /* DCH 2002.05.22 -- CHANGES_END */
+ 
    return add_candidate (candidates, fn, convs, viable);
  }
  
*************** build_over_call (cand, args, flags)
*** 4150,4157 ****
--- 4198,4229 ----
    tree converted_args = NULL_TREE;
    tree parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
    tree conv, arg, val;
+   tree new_convs; /*DCH*/
    int i = 0;
    int is_method = 0;
+ 
+   /* DCH 2002.05.23 --- CHANGES_BEGIN */
+   if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
+       && decl_has_classtype_parm_p ( fn ) )
+       {
+         args = set_classtype_arg ( fn, args, 1 );
+ 
+         new_convs = make_tree_vec ( TREE_VEC_LENGTH ( convs ) + 1 );
+ 
+         TREE_VEC_ELT ( new_convs, 0 ) = TREE_VEC_ELT ( convs, 0 );
+         TREE_VEC_ELT ( new_convs, 1 ) = build1 ( IDENTITY_CONV, 
+ TREE_TYPE ( TREE_CHAIN ( args ) ), TREE_CHAIN ( args ) );
+ 
+         for ( i = 2; i < TREE_VEC_LENGTH ( new_convs ); i++ )
+           {
+             TREE_VEC_ELT ( new_convs, i ) = TREE_VEC_ELT ( convs, i -
1 );
+           }
+ 
+ 
+           i = 0;
+  
+           cand->convs = convs = new_convs;
+       }
+   /* DCH 2002.05.23 -- CHANGES_END */
  
    /* Give any warnings we noticed during overload resolution.  */
    if (cand->warnings)
Index: gcc/gcc/cp/cp-tree.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.681.2.10
diff -c -3 -p -r1.681.2.10 cp-tree.h
*** gcc/gcc/cp/cp-tree.h	23 Apr 2002 21:51:13 -0000
1.681.2.10
--- gcc/gcc/cp/cp-tree.h	10 Jun 2002 19:39:51 -0000
*************** enum cp_tree_index
*** 568,573 ****
--- 568,574 ----
      CPTI_PFN_IDENTIFIER,
      CPTI_VPTR_IDENTIFIER,
      CPTI_STD_IDENTIFIER,
+     CPTI_CLASSTYPE_PARM_IDENTIFIER, /* DCH 2002.05.22 */
  
      CPTI_LANG_NAME_C,
      CPTI_LANG_NAME_CPLUSPLUS,
*************** extern tree cp_global_trees[CPTI_MAX];
*** 677,682 ****
--- 678,684 ----
  #define vptr_identifier
cp_global_trees[CPTI_VPTR_IDENTIFIER]
  /* The name of the std namespace.  */
  #define std_identifier
cp_global_trees[CPTI_STD_IDENTIFIER]
+ #define classtype_parm_identifier
cp_global_trees[CPTI_CLASSTYPE_PARM_IDENTIFIER] /* DCH 2002.05.22 */
  #define lang_name_c
cp_global_trees[CPTI_LANG_NAME_C]
  #define lang_name_cplusplus
cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS]
  #define lang_name_java
cp_global_trees[CPTI_LANG_NAME_JAVA]
*************** extern void begin_init_stmts            
*** 3915,3920 ****
--- 3917,3923 ----
  extern tree finish_init_stmts                   PARAMS ((tree, tree));
  extern void initialize_vtbl_ptrs                PARAMS ((tree));
  extern tree build_java_class_ref                PARAMS ((tree));
+ extern tree get_raw_vtbl_address		PARAMS ((tree)); /* DCH
2002.06.02 */
  
  /* in input.c */
  
*************** extern tree cp_copy_res_decl_for_inlinin
*** 4282,4287 ****
--- 4285,4292 ----
  						   int*, void*));
  extern int cp_start_inlining			PARAMS ((tree));
  extern void cp_end_inlining			PARAMS ((tree));
+ extern void add_classtype_parm			PARAMS ((tree));
/* DCH 2002.05.22 */
+ extern tree set_classtype_arg			PARAMS
((tree,tree,int)); /* DCH 2002.05.22 */
  
  /* in typeck.c */
  extern int string_conv_p			PARAMS ((tree, tree,
int));
*************** extern tree composite_pointer_type      
*** 4345,4350 ****
--- 4350,4357 ----
  						       const char*));
  extern tree merge_types				PARAMS ((tree,
tree));
  extern tree check_return_expr                   PARAMS ((tree));
+ extern int decl_needs_classtype_parm_p		PARAMS ((tree));
/* DCH 2002.05.07 -- CHANGE_BEGIN CHANGE_END */
+ extern int decl_has_classtype_parm_p		PARAMS ((tree)); /* DCH
2002.05.22 */
  #define cp_build_binary_op(code, arg1, arg2) \
    build_binary_op(code, arg1, arg2, 1)
  
Index: gcc/gcc/cp/decl.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.866.2.32
diff -c -3 -p -r1.866.2.32 decl.c
*** gcc/gcc/cp/decl.c	3 May 2002 18:55:23 -0000	1.866.2.32
--- gcc/gcc/cp/decl.c	10 Jun 2002 19:40:08 -0000
*************** initialize_predefined_identifiers ()
*** 6453,6458 ****
--- 6453,6459 ----
      { "_vptr", &vptr_identifier, 0 },
      { "__vtt_parm", &vtt_parm_identifier, 0 },
      { "std", &std_identifier, 0 },
+     { "__classtype_parm", &classtype_parm_identifier, 0 }, /* DCH 
+ 2002.05.22 */
      { NULL, NULL, 0 }
    };
  
*************** grokfndecl (ctype, type, declarator, ori
*** 9166,9171 ****
--- 9167,9183 ----
  
  	  /* Attempt to merge the declarations.  This can fail, in
  	     the case of some illegal specialization declarations.  */
+ 
+ 	  /* DCH 2002.05.21 -- CHANGES_BEGIN */
+ 
+ 	  /* We use "old_decl" because "decl" doesn't have the virtual
flag
+ 	     set. */
+ 	  if ( decl_needs_classtype_parm_p ( old_decl ) )
+ 	    {
+               add_classtype_parm ( decl );
+ 	    }
+ 	  /* DCH 2002.05.21 -- CHANGES_END */
+ 
  	  if (!duplicate_decls (decl, old_decl))
  	    error ("no `%#D' member function declared in class `%T'",
  		      decl, ctype);
Index: gcc/gcc/cp/decl2.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.520.2.5
diff -c -3 -p -r1.520.2.5 decl2.c
*** gcc/gcc/cp/decl2.c	17 Apr 2002 17:13:39 -0000	1.520.2.5
--- gcc/gcc/cp/decl2.c	10 Jun 2002 19:40:14 -0000
*************** check_classfn (ctype, function)
*** 1331,1346 ****
  		      if (DECL_STATIC_FUNCTION_P (fndecl)
  			  && TREE_CODE (TREE_TYPE (function)) ==
METHOD_TYPE)
  			p1 = TREE_CHAIN (p1);
  
! 		      if (same_type_p (TREE_TYPE (TREE_TYPE (function)),
! 				       TREE_TYPE (TREE_TYPE (fndecl)))
! 			  && compparms (p1, p2)
! 			  && (DECL_TEMPLATE_SPECIALIZATION (function)
! 			      == DECL_TEMPLATE_SPECIALIZATION (fndecl))
! 			  && (!DECL_TEMPLATE_SPECIALIZATION (function)
! 			      || (DECL_TI_TEMPLATE (function) 
! 				  == DECL_TI_TEMPLATE (fndecl))))
! 			return fndecl;
  		    }
  		}
  	      break;		/* loser */
--- 1331,1378 ----
  		      if (DECL_STATIC_FUNCTION_P (fndecl)
  			  && TREE_CODE (TREE_TYPE (function)) ==
METHOD_TYPE)
  			p1 = TREE_CHAIN (p1);
+                       /* DCH 2002.05.13 - CHANGES_BEGIN */
  
!                       /* If the function has a covariant return, we
need to 
!                          skip over the type parameter. */
!                       if ( decl_has_classtype_parm_p ( fndecl ) )
!                         {
!                           tree void_param;
! 
!                           /* We need to remove the faked parameter. */
!                           void_param = TREE_CHAIN (p2);
!                           TREE_CHAIN (p2) = TREE_CHAIN ( TREE_CHAIN (
p2 ) );
! 
!                           if (same_type_p (TREE_TYPE (TREE_TYPE
(function)),
!                                            TREE_TYPE (TREE_TYPE
(fndecl)))
!                               && compparms (p1, p2)
!                               && (DECL_TEMPLATE_SPECIALIZATION
(function)
!                                   == DECL_TEMPLATE_SPECIALIZATION
(fndecl))
!                               && (!DECL_TEMPLATE_SPECIALIZATION
(function)
!                                   || (DECL_TI_TEMPLATE (function)
!                                       == DECL_TI_TEMPLATE (fndecl))))
!                             {
!                               /* Restore the dropped parameter */
!                               TREE_CHAIN (p2) = void_param;
! 
!                               return fndecl;
!                             } /* end of if functions match */
! 
!                             /* Restore the dropped parameter */
!                             TREE_CHAIN (p2) = void_param;
!                         }
!                       else
! 
! 		        if (same_type_p (TREE_TYPE (TREE_TYPE
(function)),
! 		  		         TREE_TYPE (TREE_TYPE (fndecl)))
! 			    && compparms (p1, p2)
! 			    && (DECL_TEMPLATE_SPECIALIZATION (function)
! 			        == DECL_TEMPLATE_SPECIALIZATION
(fndecl))
! 			    && (!DECL_TEMPLATE_SPECIALIZATION (function)
! 			        || (DECL_TI_TEMPLATE (function) 
! 				    == DECL_TI_TEMPLATE (fndecl))))
! 			  return fndecl;
! 	              /* DCH 2002.05.13 -- CHANGES_END */
  		    }
  		}
  	      break;		/* loser */
Index: gcc/gcc/cp/init.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.264.2.10
diff -c -3 -p -r1.264.2.10 init.c
*** gcc/gcc/cp/init.c	2 May 2002 20:02:41 -0000	1.264.2.10
--- gcc/gcc/cp/init.c	10 Jun 2002 19:40:21 -0000
*************** build_vec_delete (base, maxindex, auto_d
*** 3419,3421 ****
--- 3419,3461 ----
    return build_vec_delete_1 (base, maxindex, type, auto_delete_vec,
  			     use_global_delete);
  }
+ 
+ /* DCH 2002.06.02 -- CHANGES_BEGIN */
+ tree
+ get_raw_vtbl_address (binfo)
+   tree binfo;  /* BINFO */
+ {
+   tree retval; /* Return value; an ADDR_EXPR */
+   tree vtbl;   /* Temporary; a VAR_DECL */
+ 
+   /* From build_vtbl_address, make sure that the table gets emitted */
+   vtbl = get_vtbl_decl_for_binfo (binfo);
+   assemble_external (vtbl);
+   TREE_USED (vtbl) = 1;
+ 
+   /* Retrieve the binfo's vtable */
+   retval = BINFO_VTABLE (binfo);
+ 
+   switch (TREE_CODE (retval))
+     {
+       case PLUS_EXPR :
+         retval = TREE_OPERAND (retval, 0);
+         break;
+ 
+       case VAR_DECL :
+         retval = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE
(retval)), retval);
+         break;
+     }
+ 
+   if ( TREE_CODE (retval) != ADDR_EXPR )
+     {
+       retval = error_mark_node;
+       error ( "internal compiler error; unable to take address of
vtable" );
+     }
+ 
+   /* ??? This is necessary, but I have no idea why... */
+   retval = build (PLUS_EXPR, TREE_TYPE (retval), retval,
integer_zero_node);
+   return retval;
+ }
+ 
+ /* DCH 2002.06.02 -- CHANGES_END */
Index: gcc/gcc/cp/search.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/search.c,v
retrieving revision 1.223.2.3
diff -c -3 -p -r1.223.2.3 search.c
*** gcc/gcc/cp/search.c	18 Apr 2002 13:59:00 -0000	1.223.2.3
--- gcc/gcc/cp/search.c	10 Jun 2002 19:40:47 -0000
*************** lookup_base (t, base, access, kind_ptr)
*** 327,333 ****
    /* Ensure that the types are instantiated.  */
    t = complete_type (TYPE_MAIN_VARIANT (t));
    base = complete_type (TYPE_MAIN_VARIANT (base));
!   
    bk = lookup_base_r (TYPE_BINFO (t), base, access & ~ba_quiet,
  		      0, 0, 0, &binfo);
  
--- 327,333 ----
    /* Ensure that the types are instantiated.  */
    t = complete_type (TYPE_MAIN_VARIANT (t));
    base = complete_type (TYPE_MAIN_VARIANT (base));
! 
    bk = lookup_base_r (TYPE_BINFO (t), base, access & ~ba_quiet,
  		      0, 0, 0, &binfo);
  
*************** check_final_overrider (overrider, basefn
*** 1816,1823 ****
      /* OK */;
    else if ((i = covariant_return_p (base_return, over_return)))
      {
!       if (i == 2)
! 	sorry ("adjusting pointers for covariant returns");
  
        if (pedantic && i == -1)
  	{
--- 1816,1825 ----
      /* OK */;
    else if ((i = covariant_return_p (base_return, over_return)))
      {
!       /* DCH 2002.05.29 -- CHANGES_BEGIN */
!       /*if (i == 2)
! 	sorry ("adjusting pointers for covariant returns");*/
!       /* DCH 20002.05.29 -- CHANGES_END */
  
        if (pedantic && i == -1)
  	{
Index: gcc/gcc/cp/semantics.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.252.2.6
diff -c -3 -p -r1.252.2.6 semantics.c
*** gcc/gcc/cp/semantics.c	17 Apr 2002 01:44:01 -0000
1.252.2.6
--- gcc/gcc/cp/semantics.c	10 Jun 2002 19:40:50 -0000
*************** finish_return_stmt (expr)
*** 389,394 ****
--- 389,396 ----
       tree expr;
  {
    tree r;
+   int n_baseclasses; /*DCH*/
+   int i; /*DCH*/
  
    if (!processing_template_decl)
      expr = check_return_expr (expr);
*************** finish_return_stmt (expr)
*** 403,411 ****
  	  return finish_goto_stmt (dtor_label);
  	}
      }
-   r = add_stmt (build_stmt (RETURN_STMT, expr));
-   finish_stmt ();
  
    return r;
  }
  
--- 405,470 ----
  	  return finish_goto_stmt (dtor_label);
  	}
      }
  
+   /* DCH 2002.05.27 -- CHANGES_BEGIN */
+ 
+   /* This statement bears some explanation. First, we only need to
process
+      covariant return functions if the function has __classtype_parm.
Second,
+      we only need to do something if the return value has extant base
classes.
+      The gross triple TREE_TYPE is to get the RECORD_TYPE for the
function
+      return value. */
+ 
+   n_baseclasses = decl_has_classtype_parm_p (current_function_decl) &&
!DECL_THUNK_P (current_function_decl)
+                   ? CLASSTYPE_N_BASECLASSES (TREE_TYPE (TREE_TYPE
(TREE_TYPE (current_function_decl))))
+                   : 0;
+ 
+   if (n_baseclasses)
+     {
+       tree binfos = TYPE_BINFO_BASETYPES (TREE_TYPE (TREE_TYPE
(TREE_TYPE (current_function_decl))));
+       tree parameter = TREE_CHAIN (DECL_ARGUMENTS
(current_function_decl));
+       tree cast_expr;
+ 
+       /* Evaluate the expression and store it into RESULT_DECL */
+       finish_expr_stmt (expr);
+ 
+       for ( i = 0; i < n_baseclasses; i++ )
+         {
+           tree classtype = get_raw_vtbl_address (TYPE_BINFO (TREE_TYPE
(TREE_VEC_ELT (binfos, i))));
+           tree condition = build_x_binary_op (EQ_EXPR, classtype,
parameter);
+           tree new_return_type;
+           tree if_stmt;
+ 
+           /* First, initialize the new_return_type. We want it to be
basically
+             the same, just a different record. */
+           new_return_type = build_qualified_type (TREE_TYPE
(TREE_VEC_ELT (binfos,i)), TYPE_QUALS (TREE_TYPE (TREE_TYPE (expr))));
+           new_return_type = build_pointer_type (new_return_type);
+           new_return_type = build_qualified_type (new_return_type, 
+ TYPE_QUALS (TREE_TYPE (expr)));
+ 
+           /* Create the if statement */
+           if_stmt = begin_if_stmt();
+           finish_if_stmt_cond (condition, if_stmt);
+ 
+           /* Create an expression of the form "RESULT_DECL =
static_cast<classtype *> ( RESULT_DECL )" */
+           cast_expr = build_static_cast (new_return_type, TREE_OPERAND
(expr,0));
+           cast_expr = build (INIT_EXPR, TREE_TYPE (expr), TREE_OPERAND

+ (expr,0), cast_expr);
+ 
+           /* Add the return statmenet and end the if */
+           r = add_stmt (build_stmt (RETURN_STMT, cast_expr));
+           finish_stmt();
+           finish_then_clause (if_stmt);
+           finish_if_stmt();
+         }
+ 
+       /* The final return statement is one without a cast */
+       r = add_stmt (build_stmt (RETURN_STMT, NULL_TREE));
+       finish_stmt();
+     }
+   else
+     {
+       r = add_stmt (build_stmt (RETURN_STMT, expr));
+       finish_stmt();
+     }
+   /* DCH 2002.05.27 -- CHANGES_END */
    return r;
  }
  
*************** finish_member_declaration (decl)
*** 1818,1823 ****
--- 1877,1899 ----
    if (TREE_CODE (decl) == FUNCTION_DECL 
        || DECL_FUNCTION_TEMPLATE_P (decl))
      {
+       /* DCH 2002.05.07 -- CHANGE_BEGIN
+          If the member could be covariant, we need to give it another
hidden
+          parameter. This parameter will contain the address of the
(ordinary)
+          destructor for the class whose type is desired. */
+ 
+ 
+       /* ??? This code does not currently handle covariance of 
+          the form "A **", but I'm not even sure that such a construct
+          is legal. */
+ 
+       if ( decl_needs_classtype_parm_p (decl) 
+            && !decl_has_classtype_parm_p (decl) )
+         {
+           add_classtype_parm ( decl );
+         }
+       /* DCH 2002.05.07 -- Changes end. */
+ 
        /* We also need to add this function to the
  	 CLASSTYPE_METHOD_VEC.  */
        add_method (current_class_type, decl, /*error_p=*/0);
Index: gcc/gcc/cp/tree.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.268.2.3
diff -c -3 -p -r1.268.2.3 tree.c
*** gcc/gcc/cp/tree.c	25 Apr 2002 00:14:25 -0000	1.268.2.3
--- gcc/gcc/cp/tree.c	10 Jun 2002 19:40:53 -0000
*************** decl_linkage (decl)
*** 2501,2503 ****
--- 2501,2576 ----
    /* Everything else has internal linkage.  */
    return lk_internal;
  }
+ 
+ /* DCH 2002.05.22 -- CHANGES_BEGIN */
+ 
+ /* Inserts the artificial classtype parameter into the argument list
following
+    the this pointer. */
+ 
+ void
+ add_classtype_parm (fndecl)
+    tree fndecl; /* FUNCTION_DECL or OVERLOAD */
+ {
+   tree type_parm; /* Holds the new link for the void * parameter */
+   tree arg_list;  /* List of arguments for the function */
+ 
+   /* Get rid of those single function overloads which are all over the
place. */
+   fndecl = OVL_CURRENT ( fndecl );
+ 
+   /* First, we set up the actual parameter declaration. */
+   type_parm = build_pointer_type (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE
(get_identifier ("void"))));
+   arg_list = DECL_ARGUMENTS (fndecl);
+ 
+   type_parm = build_artificial_parm (classtype_parm_identifier, 
+ type_parm);
+ 
+   /* Insert after the 'this' pointer */
+   TREE_CHAIN (type_parm) = TREE_CHAIN (arg_list);
+   TREE_CHAIN (arg_list)  = type_parm;
+ 
+   /* Now, we insert the argument type in the type list */
+   type_parm = build_pointer_type (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE
(get_identifier ("void"))));
+   arg_list = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+ 
+   type_parm = build_tree_list (NULL_TREE, type_parm);
+ 
+   /* Insert after the 'this' pointer */
+   TREE_CHAIN (type_parm) = TREE_CHAIN (arg_list);
+   TREE_CHAIN (arg_list)  = type_parm;
+ }
+ 
+ /* Sets the argument value for the artificial classtype parameter.
Note that
+    the function assumes the this pointer is NOT on the list; this
seems to be
+    correct. */
+ tree
+ set_classtype_arg (fndecl, args, has_this )
+   tree fndecl;   /* FUNCTION_DECL or OVERLOAD */
+   tree args;     /* TREE_LIST */
+   int  has_this; /* boolean */
+ {
+   tree type_vptr;
+   tree return_type;
+ 
+   fndecl = OVL_CURRENT ( fndecl );
+ 
+   /* YOW! I know. We need to descend through the "function_decl", 
+      "method_type", and "pointer_type" levels to get the actual 
+      "record_type". */
+   return_type = TREE_TYPE (TREE_TYPE (TREE_TYPE (fndecl)));
+   type_vptr   = get_raw_vtbl_address (TYPE_BINFO (return_type));
+ 
+   if ( has_this )
+     {
+       TREE_CHAIN (type_vptr) = TREE_CHAIN (args);
+       TREE_CHAIN (args)      = type_vptr;
+ 
+       return args;
+     }
+   else
+     {
+       TREE_CHAIN (type_vptr) = args;
+ 
+       return type_vptr;
+     }
+ }
+ 
+ /* DCH 2002.05.22 -- CHANGES_END */
Index: gcc/gcc/cp/typeck.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.388.2.9
diff -c -3 -p -r1.388.2.9 typeck.c
*** gcc/gcc/cp/typeck.c	25 Apr 2002 00:14:24 -0000	1.388.2.9
--- gcc/gcc/cp/typeck.c	10 Jun 2002 19:41:01 -0000
*************** strip_all_pointer_quals (type)
*** 6920,6922 ****
--- 6920,6990 ----
    else
      return TYPE_MAIN_VARIANT (type);
  }
+ 
+ /* DCH 2002.05.07 -- CHANGE_BEGIN */
+ 
+ /* Returns TRUE if "fndecl" is a virtual member function with a
covariant
+    return type. FALSE for all other cases. */
+ 
+ int
+ decl_needs_classtype_parm_p (fndecl)
+      tree fndecl; /* FUNCTION_DECL or OVERLOAD */
+ {
+   /* ??? This code does not currently handle covariance of the form "A
**",
+      but I'm not even sure that such a construct is legal. */
+ 
+   tree rettype; /* xxx_TYPE */
+ 
+   if (fndecl != NULL_TREE )
+     {
+      /* Get the actual function in case of an overload */
+       fndecl = OVL_CURRENT ( fndecl );
+ 
+       if (TREE_CODE (fndecl) == FUNCTION_DECL 
+           && DECL_VIRTUAL_P (fndecl))
+         {
+          /* What's going on here? Since member functions can be either
static
+             or methods, the parser indicates that the function is a
method by
+             making the type of decl "METHOD_TYPE". In that case, the
TREE_TYPE
+             of the METHOD_TYPE is the actual return type. We do not
check to
+             make sure that the first TREE_TYPE gives us a METHOD_TYPE;
it must
+             be since DECL_VIRTUAL_P is true! */
+           rettype = TREE_TYPE (TREE_TYPE (fndecl));
+  
+           if (rettype != NULL_TREE 
+               && (TREE_CODE (rettype) == POINTER_TYPE
+               || TREE_CODE (rettype) == REFERENCE_TYPE))
+            {
+              return (TREE_CODE (TREE_TYPE (rettype)) == RECORD_TYPE);
+            }
+        }
+     }
+ 
+   return 0;
+ }
+ 
+ int
+ decl_has_classtype_parm_p (fndecl)
+   tree fndecl; /* FUNCTION_DECL or OVERLOAD */
+ {
+   tree classtype_parm;
+   
+   if ( fndecl != NULL_TREE )
+     {
+       /* Get the actual function in case of an overload */
+       fndecl = OVL_CURRENT ( fndecl );
+ 
+       if (TREE_CODE (fndecl) == FUNCTION_DECL
+           && DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl))
+         {
+           /* The classtype parameter is the second parameter... */
+           classtype_parm = TREE_CHAIN ( DECL_ARGUMENTS ( fndecl ) );
+ 
+           return ( classtype_parm != NULL_TREE
+                    && classtype_parm_identifier == DECL_NAME (
classtype_parm ) );
+         }
+     }
+   return 0;
+ }
+ /* DCH 2002.05.07 -- CHANGE_END */
+ 

Attachment: covariant.patch
Description: Binary data


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