FreeBSD/contrib/gcc/cp/call.c
/* Convert EXPR to the indicated reference TYPE, in a way suitable for
   initializing a variable of that TYPE.  If DECL is non-NULL, it is
   the VAR_DECL being initialized with the EXPR.  (In that case, the
   type of DECL will be TYPE.)  If DECL is non-NULL, then CLEANUP must
   also be non-NULL, and with *CLEANUP initialized to NULL.  Upon
   return, if *CLEANUP is no longer NULL, it will be an expression
   that should be pushed as a cleanup after the returned expression
   is used to initialize DECL.

   Return the converted expression.  */
Convert EXPR to the indicated reference TYPE, in a way suitable for
initializing a variable of that TYPE.  If DECL is non-NULL, it is
the VAR_DECL being initialized with the EXPR.  (In that case, the
type of DECL will be TYPE.)  If DECL is non-NULL, then CLEANUP must
also be non-NULL, and with *CLEANUP initialized to NULL.  Upon
return, if *CLEANUP is no longer NULL, it will be an expression
that should be pushed as a cleanup after the returned expression
is used to initialize DECL.

Return the converted expression.
Convert EXPR to the indicated reference TYPE in a way suitable for initializing a variable of that TYPE . If DECL is non - NULL it is the VAR_DECL being initialized with the EXPR . ( In that case the type of DECL will be TYPE . ) If DECL is non - NULL then CLEANUP must also be non - NULL and with * CLEANUP initialized to NULL . Upon return if * CLEANUP is no longer NULL it will be an expression that should be pushed as a cleanup after the returned expression is used to initialize DECL . Return the converted expression .
tree
initialize_reference (tree type, tree expr, tree decl, tree *cleanup)
{
  conversion *conv;
  void *p;
  if (type == error_mark_node || error_operand_p (expr))
    return error_mark_node;
  p = conversion_obstack_alloc (0);
  conv = reference_binding (type, TREE_TYPE (expr), expr, false,
			    LOOKUP_NORMAL);
  if (!conv || conv->bad_p)
    {
      if (!(TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST)
	  && !real_lvalue_p (expr))
	error ("invalid initialization of non-const reference of "
	       "type %qT from a temporary of type %qT",
	       type, TREE_TYPE (expr));
      else
	error ("invalid initialization of reference of type "
	       "%qT from expression of type %qT", type,
	       TREE_TYPE (expr));
      return error_mark_node;
    }
  gcc_assert (conv->kind == ck_ref_bind);
  if (decl)
    {
      tree var;
      tree base_conv_type;
      conv = conv->u.next;
      if (conv->kind == ck_base)
	{
	  if (conv->check_copy_constructor_p)
	    check_constructor_callable (TREE_TYPE (expr), expr);
	  base_conv_type = conv->type;
	  conv = conv->u.next;
	}
      else
	base_conv_type = NULL_TREE;
      expr = convert_like_real (conv, expr,
				NULL_TREE, 0,
				-1,
				true,
				false);
      if (error_operand_p (expr))
	expr = error_mark_node;
      else
	{
	  if (!real_lvalue_p (expr))
	    {
	      tree init;
	      tree type;
	      type = TREE_TYPE (expr);
	      var = make_temporary_var_for_ref_to_temp (decl, type);
	      layout_decl (var, 0);
	      if (TREE_CODE (expr) != TARGET_EXPR)
		expr = get_target_expr (expr);
	      init = build2 (INIT_EXPR, type, var, expr);
	      if (at_function_scope_p ())
		{
		  add_decl_expr (var);
		  *cleanup = cxx_maybe_build_cleanup (var);
		}
	      else
		{
		  rest_of_decl_compilation (var, 1, at_eof);
		  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
		    static_aggregates = tree_cons (NULL_TREE, var,
						   static_aggregates);
		}
	      expr = build_address (var);
	      if (base_conv_type)
		expr = convert_to_base (expr,
					build_pointer_type (base_conv_type),
					true,
					true);
	      expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
	    }
	  else
	    expr = build_unary_op (ADDR_EXPR, expr, 0);
	  if (base_conv_type)
	    expr = (perform_implicit_conversion
		    (build_pointer_type (base_conv_type), expr));
	  expr = build_nop (type, expr);
	}
    }
  else
    expr = convert_like (conv, expr);
  obstack_free (&conversion_obstack, p);
  return expr;
}
tree initialize_reference ( tree type , tree expr , tree decl , tree * cleanup ) { conversion * conv ; void * p ; if ( type == error_mark_node || error_operand_p ( expr ) ) return error_mark_node ; p = conversion_obstack_alloc ( 0 ) ; conv = reference_binding ( type , TREE_TYPE ( expr ) , expr , false , LOOKUP_NORMAL ) ; if ( ! conv || conv -> bad_p ) { if ( ! ( TYPE_QUALS ( TREE_TYPE ( type ) ) & TYPE_QUAL_CONST ) && ! real_lvalue_p ( expr ) ) error ( " " " " , type , TREE_TYPE ( expr ) ) ; else error ( " " " " , type , TREE_TYPE ( expr ) ) ; return error_mark_node ; } gcc_assert ( conv -> kind == ck_ref_bind ) ; if ( decl ) { tree var ; tree base_conv_type ; conv = conv -> u . next ; if ( conv -> kind == ck_base ) { if ( conv -> check_copy_constructor_p ) check_constructor_callable ( TREE_TYPE ( expr ) , expr ) ; base_conv_type = conv -> type ; conv = conv -> u . next ; } else base_conv_type = NULL_TREE ; expr = convert_like_real ( conv , expr , NULL_TREE , 0 , -1 , true , false ) ; if ( error_operand_p ( expr ) ) expr = error_mark_node ; else { if ( ! real_lvalue_p ( expr ) ) { tree init ; tree type ; type = TREE_TYPE ( expr ) ; var = make_temporary_var_for_ref_to_temp ( decl , type ) ; layout_decl ( var , 0 ) ; if ( TREE_CODE ( expr ) != TARGET_EXPR ) expr = get_target_expr ( expr ) ; init = build2 ( INIT_EXPR , type , var , expr ) ; if ( at_function_scope_p ( ) ) { add_decl_expr ( var ) ; * cleanup = cxx_maybe_build_cleanup ( var ) ; } else { rest_of_decl_compilation ( var , 1 , at_eof ) ; if ( TYPE_HAS_NONTRIVIAL_DESTRUCTOR ( type ) ) static_aggregates = tree_cons ( NULL_TREE , var , static_aggregates ) ; } expr = build_address ( var ) ; if ( base_conv_type ) expr = convert_to_base ( expr , build_pointer_type ( base_conv_type ) , true , true ) ; expr = build2 ( COMPOUND_EXPR , TREE_TYPE ( expr ) , init , expr ) ; } else expr = build_unary_op ( ADDR_EXPR , expr , 0 ) ; if ( base_conv_type ) expr = ( perform_implicit_conversion ( build_pointer_type ( base_conv_type ) , expr ) ) ; expr = build_nop ( type , expr ) ; } } else expr = convert_like ( conv , expr ) ; obstack_free ( & conversion_obstack , p ) ; return expr ; }
Convert EXPR to the indicated reference TYPE, in a way suitable for
initializing a variable of that TYPE.
Convert EXPR to the indicated reference TYPE in a way suitable for initializing a variable of that TYPE .
/* Get the high-water mark for the CONVERSION_OBSTACK.  */ /*c_cast_p=*/ /* If DECL is non-NULL, then this special rule applies:

       [class.temporary]

       The temporary to which the reference is bound or the temporary
       that is the complete object to which the reference is bound
       persists for the lifetime of the reference.

       The temporaries created during the evaluation of the expression
       initializing the reference, except the temporary to which the
       reference is bound, are destroyed at the end of the
       full-expression in which they are created.

     In that case, we store the converted expression into a new
     VAR_DECL in a new scope.

     However, we want to be careful not to create temporaries when
     they are not required.  For example, given:

       struct B {};
       struct D : public B {};
       D f();
       const B& b = f();

     there is no need to copy the return value from "f"; we can just
     extend its lifetime.  Similarly, given:

       struct S {};
       struct T { operator S(); };
       T t;
       const S& s = t;

    we can extend the lifetime of the return value of the conversion
    operator.  */ /* Skip over the REF_BIND.  */ /* If the next conversion is a BASE_CONV, skip that too -- but
	 remember that the conversion was required.  */ /* Perform the remainder of the conversion.  */ /*fn=*/ /*argnum=*/ /*inner=*/ /*issue_conversion_warnings=*/ /*c_cast_p=*/ /* Create the temporary variable.  */ /* If the rvalue is the result of a function call it will be
		 a TARGET_EXPR.  If it is some other construct (such as a
		 member access expression where the underlying object is
		 itself the result of a function call), turn it into a
		 TARGET_EXPR here.  It is important that EXPR be a
		 TARGET_EXPR below since otherwise the INIT_EXPR will
		 attempt to make a bitwise copy of EXPR to initialize
		 VAR.  */ /* Create the INIT_EXPR that will initialize the temporary
		 variable.  */ /* We must be careful to destroy the temporary only
		     after its initialization has taken place.  If the
		     initialization throws an exception, then the
		     destructor should not be run.  We cannot simply
		     transform INIT into something like:

			 (INIT, ({ CLEANUP_STMT; }))

		     because emit_local_var always treats the
		     initializer as a full-expression.  Thus, the
		     destructor would run too early; it would run at the
		     end of initializing the reference variable, rather
		     than at the end of the block enclosing the
		     reference variable.

		     The solution is to pass back a cleanup expression
		     which the caller is responsible for attaching to
		     the statement tree.  */ /*toplev=*/ /* Use its address to initialize the reference variable.  */ /*check_access=*/ /*nonnull=*/ /* Take the address of EXPR.  */ /* If a BASE_CONV was required, perform it now.  */ /* Perform the conversion.  */ /* Free all the conversions we allocated.  */