FreeBSD/contrib/gcc/cp/method.c
/* Emit the definition of a C++ multiple inheritance or covariant
   return vtable thunk.  If EMIT_P is nonzero, the thunk is emitted
   immediately.  */
Emit the definition of a C++ multiple inheritance or covariant
return vtable thunk.  If EMIT_P is nonzero, the thunk is emitted
immediately.
Emit the definition of a C ++ multiple inheritance or covariant return vtable thunk . If EMIT_P is nonzero the thunk is emitted immediately .
void
use_thunk (tree thunk_fndecl, bool emit_p)
{
  tree a, t, function, alias;
  tree virtual_offset;
  HOST_WIDE_INT fixed_offset, virtual_value;
  bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl);
  gcc_assert (DECL_NAME (thunk_fndecl));
  gcc_assert (!THUNK_ALIAS (thunk_fndecl));
  if (TREE_ASM_WRITTEN (thunk_fndecl))
    return;
  function = THUNK_TARGET (thunk_fndecl);
  if (DECL_RESULT (thunk_fndecl))
    return;
  if (DECL_THUNK_P (function))
    use_thunk (function, emit_p);
  TREE_ADDRESSABLE (thunk_fndecl) = 1;
  TREE_ADDRESSABLE (function) = 1;
  mark_used (function);
  if (!emit_p)
    return;
  if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function))
   alias = make_alias_for_thunk (function);
  else
   alias = function;
  fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl);
  virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl);
  if (virtual_offset)
    {
      if (!this_adjusting)
	virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
      virtual_value = tree_low_cst (virtual_offset, 0);
      gcc_assert (virtual_value);
    }
  else
    virtual_value = 0;
  mark_used (thunk_fndecl);
  DECL_EXTERNAL (thunk_fndecl) = 0;
  TREE_PUBLIC (thunk_fndecl) = TREE_PUBLIC (function);
  DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function);
  DECL_VISIBILITY_SPECIFIED (thunk_fndecl)
    = DECL_VISIBILITY_SPECIFIED (function);
  if (DECL_ONE_ONLY (function))
    make_decl_one_only (thunk_fndecl);
  if (flag_syntax_only)
    {
      TREE_ASM_WRITTEN (thunk_fndecl) = 1;
      return;
    }
  push_to_top_level ();
  if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)
      && targetm.have_named_sections)
    {
      resolve_unique_section (function, 0, flag_function_sections);
      if (DECL_SECTION_NAME (function) != NULL && DECL_ONE_ONLY (function))
	{
	  resolve_unique_section (thunk_fndecl, 0, flag_function_sections);
	  DECL_SECTION_NAME (thunk_fndecl) = DECL_SECTION_NAME (function);
	}
    }
  t = NULL_TREE;
  for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
    {
      tree x = copy_node (a);
      TREE_CHAIN (x) = t;
      DECL_CONTEXT (x) = thunk_fndecl;
      SET_DECL_RTL (x, NULL_RTX);
      DECL_HAS_VALUE_EXPR_P (x) = 0;
      t = x;
    }
  a = nreverse (t);
  DECL_ARGUMENTS (thunk_fndecl) = a;
  if (this_adjusting
      && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
					      virtual_value, alias))
    {
      const char *fnname;
      tree fn_block;
      current_function_decl = thunk_fndecl;
      DECL_RESULT (thunk_fndecl)
	= build_decl (RESULT_DECL, 0, integer_type_node);
      fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
      fn_block = make_node (BLOCK);
      BLOCK_VARS (fn_block) = a;
      DECL_INITIAL (thunk_fndecl) = fn_block;
      init_function_start (thunk_fndecl);
      current_function_is_thunk = 1;
      assemble_start_function (thunk_fndecl, fnname);
      targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
				       fixed_offset, virtual_value, alias);
      assemble_end_function (thunk_fndecl, fnname);
      init_insn_lengths ();
      current_function_decl = 0;
      cfun = 0;
      TREE_ASM_WRITTEN (thunk_fndecl) = 1;
    }
  else
    {
      if (varargs_function_p (function))
	error ("generic thunk code fails for method %q#D which uses %<...%>",
	       function);
      DECL_RESULT (thunk_fndecl) = NULL_TREE;
      start_preparsed_function (thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
      push_deferring_access_checks (dk_no_check);
      t = a;
      if (this_adjusting)
	t = thunk_adjust (t, 1,
			  fixed_offset, virtual_offset);
      t = tree_cons (NULL_TREE, t, NULL_TREE);
      for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
	t = tree_cons (NULL_TREE, a, t);
      t = nreverse (t);
      t = build_call (alias, t);
      CALL_FROM_THUNK_P (t) = 1;
      if (VOID_TYPE_P (TREE_TYPE (t)))
	finish_expr_stmt (t);
      else
	{
	  if (!this_adjusting)
	    {
	      tree cond = NULL_TREE;
	      if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
		{
		  t = save_expr (t);
		  cond = cp_convert (boolean_type_node, t);
		}
	      t = thunk_adjust (t, 0,
				fixed_offset, virtual_offset);
	      if (cond)
		t = build3 (COND_EXPR, TREE_TYPE (t), cond, t,
			    cp_convert (TREE_TYPE (t), integer_zero_node));
	    }
	  if (IS_AGGR_TYPE (TREE_TYPE (t)))
	    t = build_cplus_new (TREE_TYPE (t), t);
	  finish_return_stmt (t);
	}
      mark_decl_referenced (thunk_fndecl);
      DECL_IGNORED_P (thunk_fndecl) = 1;
      pop_deferring_access_checks ();
      thunk_fndecl = finish_function (0);
      tree_lowering_passes (thunk_fndecl);
      expand_body (thunk_fndecl);
    }
  pop_from_top_level ();
}
void use_thunk ( tree thunk_fndecl , bool emit_p ) { tree a , t , function , alias ; tree virtual_offset ; HOST_WIDE_INT fixed_offset , virtual_value ; bool this_adjusting = DECL_THIS_THUNK_P ( thunk_fndecl ) ; gcc_assert ( DECL_NAME ( thunk_fndecl ) ) ; gcc_assert ( ! THUNK_ALIAS ( thunk_fndecl ) ) ; if ( TREE_ASM_WRITTEN ( thunk_fndecl ) ) return ; function = THUNK_TARGET ( thunk_fndecl ) ; if ( DECL_RESULT ( thunk_fndecl ) ) return ; if ( DECL_THUNK_P ( function ) ) use_thunk ( function , emit_p ) ; TREE_ADDRESSABLE ( thunk_fndecl ) = 1 ; TREE_ADDRESSABLE ( function ) = 1 ; mark_used ( function ) ; if ( ! emit_p ) return ; if ( TARGET_USE_LOCAL_THUNK_ALIAS_P ( function ) ) alias = make_alias_for_thunk ( function ) ; else alias = function ; fixed_offset = THUNK_FIXED_OFFSET ( thunk_fndecl ) ; virtual_offset = THUNK_VIRTUAL_OFFSET ( thunk_fndecl ) ; if ( virtual_offset ) { if ( ! this_adjusting ) virtual_offset = BINFO_VPTR_FIELD ( virtual_offset ) ; virtual_value = tree_low_cst ( virtual_offset , 0 ) ; gcc_assert ( virtual_value ) ; } else virtual_value = 0 ; mark_used ( thunk_fndecl ) ; DECL_EXTERNAL ( thunk_fndecl ) = 0 ; TREE_PUBLIC ( thunk_fndecl ) = TREE_PUBLIC ( function ) ; DECL_VISIBILITY ( thunk_fndecl ) = DECL_VISIBILITY ( function ) ; DECL_VISIBILITY_SPECIFIED ( thunk_fndecl ) = DECL_VISIBILITY_SPECIFIED ( function ) ; if ( DECL_ONE_ONLY ( function ) ) make_decl_one_only ( thunk_fndecl ) ; if ( flag_syntax_only ) { TREE_ASM_WRITTEN ( thunk_fndecl ) = 1 ; return ; } push_to_top_level ( ) ; if ( TARGET_USE_LOCAL_THUNK_ALIAS_P ( function ) && targetm . have_named_sections ) { resolve_unique_section ( function , 0 , flag_function_sections ) ; if ( DECL_SECTION_NAME ( function ) != NULL && DECL_ONE_ONLY ( function ) ) { resolve_unique_section ( thunk_fndecl , 0 , flag_function_sections ) ; DECL_SECTION_NAME ( thunk_fndecl ) = DECL_SECTION_NAME ( function ) ; } } t = NULL_TREE ; for ( a = DECL_ARGUMENTS ( function ) ; a ; a = TREE_CHAIN ( a ) ) { tree x = copy_node ( a ) ; TREE_CHAIN ( x ) = t ; DECL_CONTEXT ( x ) = thunk_fndecl ; SET_DECL_RTL ( x , NULL_RTX ) ; DECL_HAS_VALUE_EXPR_P ( x ) = 0 ; t = x ; } a = nreverse ( t ) ; DECL_ARGUMENTS ( thunk_fndecl ) = a ; if ( this_adjusting && targetm . asm_out . can_output_mi_thunk ( thunk_fndecl , fixed_offset , virtual_value , alias ) ) { const char * fnname ; tree fn_block ; current_function_decl = thunk_fndecl ; DECL_RESULT ( thunk_fndecl ) = build_decl ( RESULT_DECL , 0 , integer_type_node ) ; fnname = XSTR ( XEXP ( DECL_RTL ( thunk_fndecl ) , 0 ) , 0 ) ; fn_block = make_node ( BLOCK ) ; BLOCK_VARS ( fn_block ) = a ; DECL_INITIAL ( thunk_fndecl ) = fn_block ; init_function_start ( thunk_fndecl ) ; current_function_is_thunk = 1 ; assemble_start_function ( thunk_fndecl , fnname ) ; targetm . asm_out . output_mi_thunk ( asm_out_file , thunk_fndecl , fixed_offset , virtual_value , alias ) ; assemble_end_function ( thunk_fndecl , fnname ) ; init_insn_lengths ( ) ; current_function_decl = 0 ; cfun = 0 ; TREE_ASM_WRITTEN ( thunk_fndecl ) = 1 ; } else { if ( varargs_function_p ( function ) ) error ( " " , function ) ; DECL_RESULT ( thunk_fndecl ) = NULL_TREE ; start_preparsed_function ( thunk_fndecl , NULL_TREE , SF_PRE_PARSED ) ; push_deferring_access_checks ( dk_no_check ) ; t = a ; if ( this_adjusting ) t = thunk_adjust ( t , 1 , fixed_offset , virtual_offset ) ; t = tree_cons ( NULL_TREE , t , NULL_TREE ) ; for ( a = TREE_CHAIN ( a ) ; a ; a = TREE_CHAIN ( a ) ) t = tree_cons ( NULL_TREE , a , t ) ; t = nreverse ( t ) ; t = build_call ( alias , t ) ; CALL_FROM_THUNK_P ( t ) = 1 ; if ( VOID_TYPE_P ( TREE_TYPE ( t ) ) ) finish_expr_stmt ( t ) ; else { if ( ! this_adjusting ) { tree cond = NULL_TREE ; if ( TREE_CODE ( TREE_TYPE ( t ) ) == POINTER_TYPE ) { t = save_expr ( t ) ; cond = cp_convert ( boolean_type_node , t ) ; } t = thunk_adjust ( t , 0 , fixed_offset , virtual_offset ) ; if ( cond ) t = build3 ( COND_EXPR , TREE_TYPE ( t ) , cond , t , cp_convert ( TREE_TYPE ( t ) , integer_zero_node ) ) ; } if ( IS_AGGR_TYPE ( TREE_TYPE ( t ) ) ) t = build_cplus_new ( TREE_TYPE ( t ) , t ) ; finish_return_stmt ( t ) ; } mark_decl_referenced ( thunk_fndecl ) ; DECL_IGNORED_P ( thunk_fndecl ) = 1 ; pop_deferring_access_checks ( ) ; thunk_fndecl = finish_function ( 0 ) ; tree_lowering_passes ( thunk_fndecl ) ; expand_body ( thunk_fndecl ) ; } pop_from_top_level ( ) ; }
Emit the definition of a C++ multiple inheritance or covariant
return vtable thunk.
Emit the definition of a C ++ multiple inheritance or covariant return vtable thunk .
/* We should have called finish_thunk to give it a name.  */ /* We should never be using an alias, always refer to the
     aliased thunk.  */ /* We already turned this thunk into an ordinary function.
       There's no need to process this thunk again.  */ /* The target is itself a thunk, process it now.  */ /* Thunks are always addressable; they only appear in vtables.  */ /* Figure out what function is being thunked to.  It's referenced in
     this translation unit.  */ /*pos=*/ /* And, if we need to emit the thunk, it's used.  */ /* This thunk is actually defined.  */ /* The linkage of the function may have changed.  FIXME in linkage
     rewrite.  */ /* Output the thunk into the same section as function.  */ /* Set up cloned argument trees for the thunk.  */ /* The back-end expects DECL_INITIAL to contain a BLOCK, so we
	 create one.  */ /* If this is a covariant thunk, or we don't have the necessary
	 code for efficient thunks, generate a thunk function that
	 just makes a call to the real function.  Unfortunately, this
	 doesn't work for varargs.  */ /* We don't bother with a body block for thunks.  */ /* There's no need to check accessibility inside the thunk body.  */ /*this_adjusting=*/ /* Build up the call to the real function.  */ /* If the return type is a pointer, we need to
		     protect against NULL.  We know there will be an
		     adjustment, because that's why we're emitting a
		     thunk.  */ /*this_adjusting=*/ /* Since we want to emit the thunk, we explicitly mark its name as
	 referenced.  */ /* But we don't want debugging information about it.  */ /* Re-enable access control.  */