FreeBSD/contrib/gcc/cp/typeck.c
/* Check that returning RETVAL from the current function is valid.
   Return an expression explicitly showing all conversions required to
   change RETVAL into the function return type, and to assign it to
   the DECL_RESULT for the function.  Set *NO_WARNING to true if
   code reaches end of non-void function warning shouldn't be issued
   on this RETURN_EXPR.  */
Check that returning RETVAL from the current function is valid.
Return an expression explicitly showing all conversions required to
change RETVAL into the function return type, and to assign it to
the DECL_RESULT for the function.  Set *NO_WARNING to true if
code reaches end of non-void function warning shouldn't be issued
on this RETURN_EXPR.
Check that returning RETVAL from the current function is valid . Return an expression explicitly showing all conversions required to change RETVAL into the function return type and to assign it to the DECL_RESULT for the function . Set * NO_WARNING to true if code reaches end of non - void function warning shouldn ' t be issued on this RETURN_EXPR .
tree
check_return_expr (tree retval, bool *no_warning)
{
  tree result;
  tree valtype;
  int fn_returns_value_p;
  *no_warning = false;
  if (TREE_THIS_VOLATILE (current_function_decl))
    warning (0, "function declared %<noreturn%> has a %<return%> statement");
  if (DECL_DESTRUCTOR_P (current_function_decl))
    {
      if (retval)
	error ("returning a value from a destructor");
      return NULL_TREE;
    }
  else if (DECL_CONSTRUCTOR_P (current_function_decl))
    {
      if (in_function_try_handler)
	error ("cannot return from a handler of a function-try-block of a constructor");
      else if (retval)
	error ("returning a value from a constructor");
      return NULL_TREE;
    }
  if (cur_block && !cur_block->block_has_return_type)
    {
      if (cur_block->return_type == NULL_TREE)
  {
    if (retval)
      {
	 tree restype;
	 retval = decay_conversion (retval);
	 restype = TYPE_MAIN_VARIANT (TREE_TYPE (retval));
	 TREE_TYPE (current_function_decl)
      = build_function_type (restype,
		       TYPE_ARG_TYPES (TREE_TYPE (current_function_decl)));
	 TREE_TYPE (DECL_RESULT (current_function_decl)) = restype;
	 relayout_decl (DECL_RESULT (current_function_decl));
	 cur_block->return_type = restype;
      }
    else
      cur_block->return_type = void_type_node;
  }
      if (TREE_CODE (cur_block->return_type) == VOID_TYPE)
  {
    if (retval)
      {
	 error ("void block should not return a value");
	 return error_mark_node;
      }
  }
      else if (!retval)
  {
    error ("non-void block should return a value");
    return error_mark_node;
  }
      if (retval)
  {
    valtype = TREE_TYPE (retval);
    if (!types_are_block_compatible (cur_block->return_type, valtype))
      {
	 error ("incompatible type returning %qT, expected %qT",
	    valtype, cur_block->return_type);
	 return error_mark_node;
      }
  }
    }
  if (processing_template_decl)
    {
      current_function_returns_value = 1;
      return retval;
    }
  result = DECL_RESULT (current_function_decl);
  valtype = TREE_TYPE (result);
  gcc_assert (valtype != NULL_TREE);
  fn_returns_value_p = !VOID_TYPE_P (valtype);
  if (!retval && DECL_NAME (result) && fn_returns_value_p)
    retval = result;
  if (!retval && fn_returns_value_p)
    {
      pedwarn ("return-statement with no value, in function returning %qT",
	       valtype);
      current_function_returns_null = 0;
      *no_warning = true;
    }
  else if (retval && !fn_returns_value_p)
    {
      if (VOID_TYPE_P (TREE_TYPE (retval)))
	  finish_expr_stmt (retval);
      else
	pedwarn ("return-statement with a value, in function "
		 "returning 'void'");
      current_function_returns_null = 1;
      return NULL_TREE;
    }
  else if (!retval)
    current_function_returns_null = 1;
  else
    current_function_returns_value = 1;
  if (error_operand_p (retval))
    {
      current_function_return_value = error_mark_node;
      return error_mark_node;
    }
  if ((DECL_OVERLOADED_OPERATOR_P (current_function_decl) == NEW_EXPR
       || DECL_OVERLOADED_OPERATOR_P (current_function_decl) == VEC_NEW_EXPR)
      && !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl))
      && ! flag_check_new
      && null_ptr_cst_p (retval))
    warning (0, "%<operator new%> must not return NULL unless it is "
	     "declared %<throw()%> (or -fcheck-new is in effect)");
  if (warn_ecpp
      && DECL_NAME (current_function_decl) == ansi_assopname(NOP_EXPR))
    {
      bool warn = true;
      if (TREE_CODE (valtype) == REFERENCE_TYPE
	  && same_type_ignoring_top_level_qualifiers_p
	      (TREE_TYPE (valtype), TREE_TYPE (current_class_ref)))
	{
	  if (retval == current_class_ref)
	    warn = false;
	  else if (TREE_CODE (retval) == INDIRECT_REF
		   && TREE_CODE (TREE_OPERAND (retval, 0)) == CALL_EXPR)
	    warn = false;
	}
      if (warn)
	warning (OPT_Weffc__, "%<operator=%> should return a reference to %<*this%>");
    }
  if (fn_returns_value_p && flag_elide_constructors)
    {
      if (retval != NULL_TREE
	  && (current_function_return_value == NULL_TREE
	      || current_function_return_value == retval)
	  && TREE_CODE (retval) == VAR_DECL
	  && DECL_CONTEXT (retval) == current_function_decl
	  && ! TREE_STATIC (retval)
	  && ! DECL_ANON_UNION_VAR_P (retval)
	  && (DECL_ALIGN (retval)
	      >= DECL_ALIGN (DECL_RESULT (current_function_decl)))
	  && same_type_p ((TYPE_MAIN_VARIANT
			   (TREE_TYPE (retval))),
			  (TYPE_MAIN_VARIANT
			   (TREE_TYPE (TREE_TYPE (current_function_decl))))))
	current_function_return_value = retval;
      else
	current_function_return_value = error_mark_node;
    }
  if (!retval)
    return NULL_TREE;
  if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl))
    ;
  else
    {
      tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
      if (VOID_TYPE_P (functype))
	return error_mark_node;
      retval = convert_for_initialization
	(NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
	 "return", NULL_TREE, 0);
      retval = convert (valtype, retval);
      if (retval == error_mark_node)
	return retval;
      else if (! current_function_returns_struct
	       && TREE_CODE (retval) == TARGET_EXPR
	       && TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
	retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval,
			 TREE_OPERAND (retval, 0));
      else
	maybe_warn_about_returning_address_of_local (retval);
    }
  if (retval && retval != result)
    retval = build2 (INIT_EXPR, TREE_TYPE (result), result, retval);
  return retval;
}
tree check_return_expr ( tree retval , bool * no_warning ) { tree result ; tree valtype ; int fn_returns_value_p ; * no_warning = false ; if ( TREE_THIS_VOLATILE ( current_function_decl ) ) warning ( 0 , " " ) ; if ( DECL_DESTRUCTOR_P ( current_function_decl ) ) { if ( retval ) error ( " " ) ; return NULL_TREE ; } else if ( DECL_CONSTRUCTOR_P ( current_function_decl ) ) { if ( in_function_try_handler ) error ( " " ) ; else if ( retval ) error ( " " ) ; return NULL_TREE ; } if ( cur_block && ! cur_block -> block_has_return_type ) { if ( cur_block -> return_type == NULL_TREE ) { if ( retval ) { tree restype ; retval = decay_conversion ( retval ) ; restype = TYPE_MAIN_VARIANT ( TREE_TYPE ( retval ) ) ; TREE_TYPE ( current_function_decl ) = build_function_type ( restype , TYPE_ARG_TYPES ( TREE_TYPE ( current_function_decl ) ) ) ; TREE_TYPE ( DECL_RESULT ( current_function_decl ) ) = restype ; relayout_decl ( DECL_RESULT ( current_function_decl ) ) ; cur_block -> return_type = restype ; } else cur_block -> return_type = void_type_node ; } if ( TREE_CODE ( cur_block -> return_type ) == VOID_TYPE ) { if ( retval ) { error ( " " ) ; return error_mark_node ; } } else if ( ! retval ) { error ( " " ) ; return error_mark_node ; } if ( retval ) { valtype = TREE_TYPE ( retval ) ; if ( ! types_are_block_compatible ( cur_block -> return_type , valtype ) ) { error ( " " , valtype , cur_block -> return_type ) ; return error_mark_node ; } } } if ( processing_template_decl ) { current_function_returns_value = 1 ; return retval ; } result = DECL_RESULT ( current_function_decl ) ; valtype = TREE_TYPE ( result ) ; gcc_assert ( valtype != NULL_TREE ) ; fn_returns_value_p = ! VOID_TYPE_P ( valtype ) ; if ( ! retval && DECL_NAME ( result ) && fn_returns_value_p ) retval = result ; if ( ! retval && fn_returns_value_p ) { pedwarn ( " " , valtype ) ; current_function_returns_null = 0 ; * no_warning = true ; } else if ( retval && ! fn_returns_value_p ) { if ( VOID_TYPE_P ( TREE_TYPE ( retval ) ) ) finish_expr_stmt ( retval ) ; else pedwarn ( " " " " ) ; current_function_returns_null = 1 ; return NULL_TREE ; } else if ( ! retval ) current_function_returns_null = 1 ; else current_function_returns_value = 1 ; if ( error_operand_p ( retval ) ) { current_function_return_value = error_mark_node ; return error_mark_node ; } if ( ( DECL_OVERLOADED_OPERATOR_P ( current_function_decl ) == NEW_EXPR || DECL_OVERLOADED_OPERATOR_P ( current_function_decl ) == VEC_NEW_EXPR ) && ! TYPE_NOTHROW_P ( TREE_TYPE ( current_function_decl ) ) && ! flag_check_new && null_ptr_cst_p ( retval ) ) warning ( 0 , " " " " ) ; if ( warn_ecpp && DECL_NAME ( current_function_decl ) == ansi_assopname ( NOP_EXPR ) ) { bool warn = true ; if ( TREE_CODE ( valtype ) == REFERENCE_TYPE && same_type_ignoring_top_level_qualifiers_p ( TREE_TYPE ( valtype ) , TREE_TYPE ( current_class_ref ) ) ) { if ( retval == current_class_ref ) warn = false ; else if ( TREE_CODE ( retval ) == INDIRECT_REF && TREE_CODE ( TREE_OPERAND ( retval , 0 ) ) == CALL_EXPR ) warn = false ; } if ( warn ) warning ( OPT_Weffc__ , " " ) ; } if ( fn_returns_value_p && flag_elide_constructors ) { if ( retval != NULL_TREE && ( current_function_return_value == NULL_TREE || current_function_return_value == retval ) && TREE_CODE ( retval ) == VAR_DECL && DECL_CONTEXT ( retval ) == current_function_decl && ! TREE_STATIC ( retval ) && ! DECL_ANON_UNION_VAR_P ( retval ) && ( DECL_ALIGN ( retval ) >= DECL_ALIGN ( DECL_RESULT ( current_function_decl ) ) ) && same_type_p ( ( TYPE_MAIN_VARIANT ( TREE_TYPE ( retval ) ) ) , ( TYPE_MAIN_VARIANT ( TREE_TYPE ( TREE_TYPE ( current_function_decl ) ) ) ) ) ) current_function_return_value = retval ; else current_function_return_value = error_mark_node ; } if ( ! retval ) return NULL_TREE ; if ( retval == result || DECL_CONSTRUCTOR_P ( current_function_decl ) ) ; else { tree functype = TREE_TYPE ( TREE_TYPE ( current_function_decl ) ) ; if ( VOID_TYPE_P ( functype ) ) return error_mark_node ; retval = convert_for_initialization ( NULL_TREE , functype , retval , LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING , " " , NULL_TREE , 0 ) ; retval = convert ( valtype , retval ) ; if ( retval == error_mark_node ) return retval ; else if ( ! current_function_returns_struct && TREE_CODE ( retval ) == TARGET_EXPR && TREE_CODE ( TREE_OPERAND ( retval , 1 ) ) == AGGR_INIT_EXPR ) retval = build2 ( COMPOUND_EXPR , TREE_TYPE ( retval ) , retval , TREE_OPERAND ( retval , 0 ) ) ; else maybe_warn_about_returning_address_of_local ( retval ) ; } if ( retval && retval != result ) retval = build2 ( INIT_EXPR , TREE_TYPE ( result ) , result , retval ) ; return retval ; }
Check that returning RETVAL from the current function is valid.
Check that returning RETVAL from the current function is valid .
/* The type actually returned by the function, after any
     promotions.  */ /* A `volatile' function is one that isn't supposed to return, ever.
     (This is a G++ extension, used to get better code for functions
     that call the `volatile' function.)  */ /* Check for various simple errors.  */ /* If a return statement appears in a handler of the
	   function-try-block of a constructor, the program is ill-formed.  */ /* You can't return a value from a constructor.  */ /* APPLE LOCAL begin blocks 6040305 (cm) */ /* APPLE LOCAL radar 6185344 */ /* If this is the first return we've seen in the block, infer the type of
   the block from it. */ /* Verify that this result type matches the previous one.  We
   are pickier with blocks than for normal functions because
   this is a new feature and we set the rules. */ /* We have a non-void block with an expression, continue checking.  */ /* For now, restrict multiple return statements in a block to have 
	strict compatible types only. */ /* APPLE LOCAL end blocks 6040305 (cm) */ /* When no explicit return-value is given in a function with a named
     return value, the named return value is used.  */ /* Check for a return statement with no return value in a function
     that's supposed to return a value.  */ /* Clear this, so finish_function won't say that we reach the
	 end of a non-void function (which we don't, we gave a
	 return!).  */ /* And signal caller that TREE_NO_WARNING should be set on the
	 RETURN_EXPR to avoid control reaches end of non-void function
	 warnings in tree-cfg.c.  */ /* Check for a return statement with a value in a function that
     isn't supposed to return a value.  */ /* You can return a `void' value from a function of `void'
	   type.  In that case, we have to evaluate the expression for
	   its side-effects.  */ /* There's really no value to return, after all.  */ /* Remember that this function can sometimes return without a
       value.  */ /* Remember that this function did return a value.  */ /* Check for erroneous operands -- but after giving ourselves a
     chance to provide an error about returning a value from a void
     function.  */ /* Only operator new(...) throw(), can return NULL [expr.new/13].  */ /* Effective C++ rule 15.  See also start_function.  */ /* The function return type must be a reference to the current
	class.  */ /* Returning '*this' is obviously OK.  */ /* If we are calling a function whose return type is the same of
	     the current class reference, it is ok.  */ /* The fabled Named Return Value optimization, as per [class.copy]/15:

     [...]      For  a function with a class return type, if the expression
     in the return statement is the name of a local  object,  and  the  cv-
     unqualified  type  of  the  local  object  is the same as the function
     return type, an implementation is permitted to omit creating the  tem-
     porary  object  to  hold  the function return value [...]

     So, if this is a value-returning function that always returns the same
     local variable, remember it.

     It might be nice to be more flexible, and choose the first suitable
     variable even if the function sometimes returns something else, but
     then we run the risk of clobbering the variable we chose if the other
     returned expression uses the chosen variable somehow.  And people expect
     this restriction, anyway.  (jason 2000-11-19)

     See finish_function and finalize_nrv for the rest of this optimization.  */ /* We don't need to do any conversions when there's nothing being
     returned.  */ /* Do any required conversions.  */ /* No conversions are required.  */ /* The type the function is declared to return.  */ /* The functype's return type will have been set to void, if it
	 was an incomplete type.  Just treat this as 'return;' */ /* First convert the value to the function's return type, then
	 to the type of return value's location to handle the
	 case that functype is smaller than the valtype.  */ /* If the conversion failed, treat this just like `return;'.  */ /* We can't initialize a register from a AGGR_INIT_EXPR.  */ /* Actually copy the value returned into the appropriate location.  */