OSDN Git Service

(handle_braces): Rework last change.
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index 944acc6..60c8f00 100644 (file)
@@ -83,7 +83,7 @@ require_complete_type (value)
 {
   tree type;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return value;
 
   type = TREE_TYPE (value);
@@ -132,8 +132,7 @@ complete_type (type)
   else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
     {
       tree t = complete_type (TREE_TYPE (type));
-      if (TYPE_SIZE (t) != NULL_TREE
-         && current_template_parms == NULL_TREE)
+      if (TYPE_SIZE (t) != NULL_TREE && ! processing_template_decl)
        layout_type (type);
       TYPE_NEEDS_CONSTRUCTING (type)
        = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
@@ -1211,7 +1210,8 @@ unsigned_type (type)
     return unsigned_intHI_type_node;
   if (type1 == intQI_type_node)
     return unsigned_intQI_type_node;
-  return type;
+
+  return signed_or_unsigned_type (1, type);
 }
 
 /* Return a signed type the same as TYPE in other respects.  */
@@ -1239,7 +1239,8 @@ signed_type (type)
     return intHI_type_node;
   if (type1 == unsigned_intQI_type_node)
     return intQI_type_node;
-  return type;
+
+  return signed_or_unsigned_type (0, type);
 }
 
 /* Return a type the same as TYPE except unsigned or
@@ -1250,8 +1251,10 @@ signed_or_unsigned_type (unsignedp, type)
      int unsignedp;
      tree type;
 {
-  if (! INTEGRAL_TYPE_P (type))
+  if (! INTEGRAL_TYPE_P (type)
+      || TREE_UNSIGNED (type) == unsignedp)
     return type;
+
   if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
     return unsignedp ? unsigned_char_type_node : signed_char_type_node;
   if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) 
@@ -1275,7 +1278,7 @@ c_sizeof (type)
   enum tree_code code = TREE_CODE (type);
   tree t;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min (SIZEOF_EXPR, sizetype, type);
 
   if (code == FUNCTION_TYPE)
@@ -1341,7 +1344,7 @@ tree
 expr_sizeof (e)
      tree e;
 {
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min (SIZEOF_EXPR, sizetype, e);
 
   if (TREE_CODE (e) == COMPONENT_REF
@@ -1446,6 +1449,12 @@ decay_conversion (exp)
 
       type = TREE_TYPE (type);
       code = TREE_CODE (type);
+
+      if (type == unknown_type_node)
+       {
+         cp_pedwarn ("assuming & on overloaded member function");
+         return build_unary_op (ADDR_EXPR, exp, 0);
+       }
     }
 
   if (code == REFERENCE_TYPE)
@@ -1574,9 +1583,6 @@ default_conversion (exp)
       if (t != type)
        return convert (t, exp);
     }
-  if (flag_traditional
-      && TYPE_MAIN_VARIANT (type) == float_type_node)
-    return convert (double_type_node, exp);
 
   return exp;
 }
@@ -1623,8 +1629,8 @@ build_object_ref (datum, basetype, field)
     {
       tree binfo = binfo_or_else (basetype, dtype);
       if (binfo)
-       return build_component_ref (build_scoped_ref (datum, basetype),
-                                   field, binfo, 1);
+       return build_x_component_ref (build_scoped_ref (datum, basetype),
+                                     field, binfo, 1);
     }
   return error_mark_node;
 }
@@ -1709,7 +1715,7 @@ build_component_ref (datum, component, basetype_path, protect)
   register tree field = NULL;
   register tree ref;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (COMPONENT_REF, datum, component);
 
   /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference
@@ -1937,6 +1943,22 @@ build_component_ref (datum, component, basetype_path, protect)
 
   return ref;
 }
+
+/* Variant of build_component_ref for use in expressions, which should
+   never have REFERENCE_TYPE.  */
+
+tree
+build_x_component_ref (datum, component, basetype_path, protect)
+     tree datum, component, basetype_path;
+     int protect;
+{
+  tree t = build_component_ref (datum, component, basetype_path, protect);
+
+  if (! processing_template_decl)
+    t = convert_from_reference (t);
+
+  return t;
+}
 \f
 /* Given an expression PTR for a pointer, return an expression
    for the value pointed to.
@@ -1952,7 +1974,7 @@ build_x_indirect_ref (ptr, errorstring)
 {
   tree rval;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (INDIRECT_REF, ptr);
 
   rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, NULL_TREE);
@@ -2213,7 +2235,7 @@ build_x_function_call (function, params, decl)
   if (function == error_mark_node)
     return error_mark_node;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (CALL_EXPR, function, params, NULL_TREE);
 
   type = TREE_TYPE (function);
@@ -2451,8 +2473,8 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
       idx = save_expr (build_component_ref (function,
                                            index_identifier,
                                            NULL_TREE, 0));
-      e1 = build (GT_EXPR, boolean_type_node, idx,
-                 convert (delta_type_node, integer_zero_node));
+      e1 = fold (build (GT_EXPR, boolean_type_node, idx,
+                       convert (delta_type_node, integer_zero_node)));
       delta = convert (ptrdiff_type_node,
                       build_component_ref (function, delta_identifier, NULL_TREE, 0));
       delta2 = DELTA2_FROM_PTRMEMFUNC (function);
@@ -2461,7 +2483,7 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
       instance
        = convert_pointer_to_real (TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)),
                                   instance_ptr);
-      if (instance == error_mark_node)
+      if (instance == error_mark_node && instance_ptr != error_mark_node)
        return instance;
 
       vtbl = convert_pointer_to (ptr_type_node, instance);
@@ -2491,7 +2513,14 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
 
       e3 = PFN_FROM_PTRMEMFUNC (function);
       TREE_TYPE (e2) = TREE_TYPE (e3);
-      function = build_conditional_expr (e1, e2, e3);
+      e1 = build_conditional_expr (e1, e2, e3);
+
+      if (instance_ptr == error_mark_node
+         && TREE_CODE (e1) != ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (e1, 0)) != FUNCTION_DECL)
+       cp_error ("object missing in `%E'", function);
+
+      function = e1;
 
       /* Make sure this doesn't get evaluated first inside one of the
          branches of the COND_EXPR.  */
@@ -2793,9 +2822,9 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
            }
          else
            {
-             parmval = convert_for_initialization (return_loc, type, val,
-                                                   flags|INDIRECT_BIND,
-                                                   "argument passing", fndecl, i);
+             parmval = convert_for_initialization
+               (return_loc, type, val, flags,
+                "argument passing", fndecl, i);
 #ifdef PROMOTE_PROTOTYPES
              if ((TREE_CODE (type) == INTEGER_TYPE
                   || TREE_CODE (type) == ENUMERAL_TYPE)
@@ -2908,7 +2937,7 @@ build_x_binary_op (code, arg1, arg2)
 {
   tree rval;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (code, arg1, arg2);
 
   if (flag_ansi_overloading)
@@ -3459,18 +3488,12 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
        {
          result_type = type0;
-         if (pedantic)
-           pedwarn ("ANSI C++ forbids comparison between pointer and integer");
-         else if (! flag_traditional)
-           warning ("comparison between pointer and integer");
+         pedwarn ("ANSI C++ forbids comparison between pointer and integer");
        }
       else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
        {
          result_type = type1;
-         if (pedantic)
-           pedwarn ("ANSI C++ forbids comparison between pointer and integer");
-         else if (! flag_traditional)
-           warning ("comparison between pointer and integer");
+         pedwarn ("ANSI C++ forbids comparison between pointer and integer");
        }
       break;
     }
@@ -3958,7 +3981,7 @@ build_x_unary_op (code, xarg)
      enum tree_code code;
      tree xarg;
 {
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (code, xarg, NULL_TREE);
 
   /* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
@@ -4005,7 +4028,7 @@ condition_conversion (expr)
      tree expr;
 {
   tree t;
-  if (current_template_parms)
+  if (processing_template_decl)
     return expr;
   t = convert (boolean_type_node, expr);
   t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
@@ -4478,7 +4501,6 @@ unary_complex_lvalue (code, arg)
         is really the representation of a pointer to it.
         Here give the representation its true type.  */
       tree t;
-      tree offset;
 
       my_friendly_assert (TREE_CODE (arg) != SCOPE_REF, 313);
 
@@ -4493,6 +4515,9 @@ unary_complex_lvalue (code, arg)
        return build_unary_op (ADDR_EXPR, t, 0);
       else
        {
+         tree type;
+         tree offset = integer_zero_node;
+
          if (TREE_OPERAND (arg, 0)
              && (TREE_CODE (TREE_OPERAND (arg, 0)) != NOP_EXPR
                  || TREE_OPERAND (TREE_OPERAND (arg, 0), 0) != error_mark_node))
@@ -4504,10 +4529,23 @@ unary_complex_lvalue (code, arg)
                return error_mark_node;
              }
 
-         /* Add in the offset to the right subobject.  */
-         offset = get_delta_difference (DECL_FIELD_CONTEXT (t), 
-                                        TREE_TYPE (TREE_OPERAND (arg, 0)),
-                                        0);
+         type = TREE_TYPE (TREE_OPERAND (arg, 0));
+
+         if (TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
+           {
+             /* Add in the offset to the intermediate subobject, if any.  */
+             offset = get_delta_difference (TYPE_OFFSET_BASETYPE (TREE_TYPE (arg)),
+                                            type,
+                                            0);
+             type = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg));
+           }
+
+         /* Now in the offset to the final subobject.  */
+         offset = size_binop (PLUS_EXPR,
+                              offset,
+                              get_delta_difference (DECL_FIELD_CONTEXT (t), 
+                                                    type,
+                                                    0));
 
          /* Add in the offset to the field.  */
          offset = size_binop (PLUS_EXPR, offset,
@@ -4578,7 +4616,8 @@ mark_addressable (exp)
       case PARM_DECL:
        if (x == current_class_ptr)
          {
-           error ("address of `this' not available");
+           if (! flag_this_is_variable)
+             error ("address of `this' not available");
            TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
            put_var_into_stack (x);
            return 1;
@@ -4611,8 +4650,10 @@ mark_addressable (exp)
 
       case CONST_DECL:
       case RESULT_DECL:
-       /* For C++, we don't warn about taking the address of a register
-          variable for CONST_DECLs; ARM p97 explicitly says it's okay.  */
+       if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
+           && !DECL_ARTIFICIAL (x) && extra_warnings)
+         cp_warning ("address requested for `%D', which is declared `register'",
+                     x);
        put_var_into_stack (x);
        TREE_ADDRESSABLE (x) = 1;
        return 1;
@@ -4640,6 +4681,11 @@ mark_addressable (exp)
        TREE_ADDRESSABLE (x) = 1;
        return 1;
 
+      case TARGET_EXPR:
+       TREE_ADDRESSABLE (x) = 1;
+       mark_addressable (TREE_OPERAND (x, 0));
+       return 1;
+
       default:
        return 1;
     }
@@ -4653,7 +4699,7 @@ build_x_conditional_expr (ifexp, op1, op2)
 {
   tree rval = NULL_TREE;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (COND_EXPR, ifexp, op1, op2);
 
   if (flag_ansi_overloading)
@@ -4988,7 +5034,7 @@ build_x_compound_expr (list)
   tree rest = TREE_CHAIN (list);
   tree result;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (COMPOUND_EXPR, list, NULL_TREE);
 
   if (rest == NULL_TREE)
@@ -5068,7 +5114,7 @@ build_static_cast (type, expr)
   if (TREE_CODE (expr) == OFFSET_REF)
     expr = resolve_offset_ref (expr);
 
-  if (current_template_parms)
+  if (processing_template_decl)
     {
       tree t = build_min (STATIC_CAST_EXPR, type, expr);
       return t;
@@ -5160,7 +5206,7 @@ build_reinterpret_cast (type, expr)
   if (TREE_CODE (expr) == OFFSET_REF)
     expr = resolve_offset_ref (expr);
 
-  if (current_template_parms)
+  if (processing_template_decl)
     {
       tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
       return t;
@@ -5252,7 +5298,7 @@ build_const_cast (type, expr)
   if (TREE_CODE (expr) == OFFSET_REF)
     expr = resolve_offset_ref (expr);
 
-  if (current_template_parms)
+  if (processing_template_decl)
     {
       tree t = build_min (CONST_CAST_EXPR, type, expr);
       return t;
@@ -5361,7 +5407,7 @@ build_c_cast (type, expr, allow_nonconverting)
       return error_mark_node;
     }
 
-  if (current_template_parms)
+  if (processing_template_decl)
     {
       tree t = build_min (CAST_EXPR, type,
                          min_tree_cons (NULL_TREE, value, NULL_TREE));
@@ -5387,7 +5433,11 @@ build_c_cast (type, expr, allow_nonconverting)
         convert references to their expanded types,
         but don't convert any other types.  */
       if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
-         || TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
+         || (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
+             /* Don't do the default conversion if we want a
+                pointer to a function.  */
+             && TREE_CODE (type) != POINTER_TYPE
+             && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)
          || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
          || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
        value = default_conversion (value);
@@ -5993,7 +6043,7 @@ build_x_modify_expr (lhs, modifycode, rhs)
      enum tree_code modifycode;
      tree rhs;
 {
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (MODOP_EXPR, lhs,
                         build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
 
@@ -6040,7 +6090,7 @@ get_delta_difference (from, to, force)
   binfo = get_binfo (from, to, 1);
   if (binfo == error_mark_node)
     {
-      error ("   in pointer to member function conversion");
+      error ("   in pointer to member function conversiona");
       return delta;
     }
   if (binfo == 0)
@@ -6048,18 +6098,20 @@ get_delta_difference (from, to, force)
       if (!force)
        {
          error_not_base_type (from, to);
-         error ("   in pointer to member function conversion");
+         error ("   in pointer to member conversion");
          return delta;
        }
       binfo = get_binfo (to, from, 1);
       if (binfo == error_mark_node)
        {
-         error ("   in pointer to member function conversion");
+         if (!force)
+           error ("   in pointer to member conversion");
          return delta;
        }
       if (binfo == 0)
        {
-         cp_error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to);
+         if (!force)
+           cp_error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to);
          return delta;
        }
       if (TREE_VIA_VIRTUAL (binfo))
@@ -6531,31 +6583,6 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
                }
            }
        }
-      else if (TREE_CODE (ttr) == OFFSET_TYPE
-              && TREE_CODE (ttl) != OFFSET_TYPE)
-       {
-         /* Normally, pointers to different type codes (other
-            than void) are not compatible, but we perform
-            some type instantiation if that resolves the
-            ambiguity of (X Y::*) and (X *).  */
-
-         if (current_class_ptr)
-           {
-             if (TREE_CODE (rhs) == INTEGER_CST)
-               {
-                 rhs = build (PLUS_EXPR, build_pointer_type (TREE_TYPE (ttr)),
-                              current_class_ptr, rhs);
-                 return convert_for_assignment (type, rhs,
-                                                errtype, fndecl, parmnum);
-               }
-           }
-         if (TREE_CODE (ttl) == METHOD_TYPE)
-           error ("%s between pointer-to-method and pointer-to-member types",
-                  errtype);
-         else
-           error ("%s between pointer and pointer-to-member types", errtype);
-         return error_mark_node;
-       }
       else
        {
          int add_quals = 0, const_parity = 0, volatile_parity = 0;
@@ -6734,6 +6761,13 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
     }
   else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
     return convert (type, rhs);
+  /* Handle anachronistic conversions from (::*)() to void* or (*)().  */
+  else if (TREE_CODE (type) == POINTER_TYPE
+          && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+              || TREE_TYPE (type) == void_type_node)
+          && TREE_TYPE (rhs)
+          && TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
+    return convert (type, rhs);
 
   cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
   return error_mark_node;
@@ -7011,7 +7045,6 @@ c_expand_return (retval)
   extern tree dtor_label, ctor_label;
   tree result = DECL_RESULT (current_function_decl);
   tree valtype = TREE_TYPE (result);
-  int returns_value = 1;
 
   if (TREE_THIS_VOLATILE (current_function_decl))
     warning ("function declared `noreturn' has a `return' statement");
@@ -7022,7 +7055,7 @@ c_expand_return (retval)
       return;
     }
 
-  if (current_template_parms)
+  if (processing_template_decl)
     {
       add_tree (build_min_nt (RETURN_STMT, retval));
       return;
@@ -7067,20 +7100,20 @@ c_expand_return (retval)
   else if (DECL_CONSTRUCTOR_P (current_function_decl)
           && retval != current_class_ptr)
     {
-      error ("return from a constructor: use `this = ...' instead");
+      if (flag_this_is_variable)
+       error ("return from a constructor: use `this = ...' instead");
+      else
+       error ("return from a constructor");
       retval = current_class_ptr;
     }
 
   if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
     {
       current_function_returns_null = 1;
-      /* We do this here so we'll avoid a warning about how the function
-        "may or may not return a value" in finish_function.  */
-      returns_value = 0;
-
-      if (retval)
+      if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
        pedwarn ("`return' with a value, in function returning void");
       expand_return (retval);
+      return;
     }
   /* Add some useful error checking for C++.  */
   else if (TREE_CODE (valtype) == REFERENCE_TYPE)
@@ -7161,143 +7194,56 @@ c_expand_return (retval)
      (3) If an X(X&) constructor is defined, the return
      value must be returned via that.  */
 
-  /* If we're returning in a register, we can't initialize the
-     return value from a TARGET_EXPR.  */
-  if (TREE_CODE (retval) == TARGET_EXPR
-      && TYPE_MAIN_VARIANT (TREE_TYPE (retval)) == TYPE_MAIN_VARIANT (valtype)
-      && ! current_function_returns_struct)
-    retval = expand_target_expr (retval);
-
   if (retval == result
-      /* Watch out for constructors, which "return" aggregates
-        via initialization, but which otherwise "return" a pointer.  */
       || DECL_CONSTRUCTOR_P (current_function_decl))
+    /* It's already done for us.  */;
+  else if (TREE_TYPE (retval) == void_type_node)
     {
-      /* This is just an error--it's already been reported.  */
-      if (TYPE_SIZE (valtype) == NULL_TREE)
-       return;
-
-      if (TYPE_MODE (valtype) != BLKmode
-         && any_pending_cleanups (1))
-       retval = get_temp_regvar (valtype, retval);
-    }
-  else if (IS_AGGR_TYPE (valtype) && current_function_returns_struct)
-    {
-      expand_aggr_init (result, retval, 0, LOOKUP_ONLYCONVERTING);
-      expand_cleanups_to (NULL_TREE);
-      DECL_INITIAL (result) = NULL_TREE;
+      pedwarn ("return of void value in function returning non-void");
+      expand_expr_stmt (retval);
       retval = 0;
     }
   else
     {
-      if (TYPE_MODE (valtype) == VOIDmode)
-       {
-         if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode
-             && warn_return_type)
-           warning ("return of void value in function returning non-void");
-         expand_expr_stmt (retval);
-         retval = 0;
-         result = 0;
-       }
-      else if (TYPE_MODE (valtype) != BLKmode
-              && any_pending_cleanups (1))
-       {
-         retval = get_temp_regvar (valtype, retval);
-         expand_cleanups_to (NULL_TREE);
-         result = 0;
-       }
-      else
+      /* We already did this above for refs, don't do it again.  */
+      if (TREE_CODE (valtype) != REFERENCE_TYPE)
+       retval = convert_for_initialization (NULL_TREE, valtype, retval,
+                                            LOOKUP_NORMAL,
+                                            "return", NULL_TREE, 0);
+
+      /* We can't initialize a register from a NEW_EXPR.  */
+      if (! current_function_returns_struct
+         && TREE_CODE (retval) == TARGET_EXPR
+         && TREE_CODE (TREE_OPERAND (retval, 0)) == NEW_EXPR)
+       retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
+                       TREE_OPERAND (retval, 0));
+
+      if (retval == error_mark_node)
        {
-         /* We already did this above, don't do it again.  */
-         if (TREE_CODE (valtype) != REFERENCE_TYPE)
-           retval = convert_for_initialization (result, valtype, retval,
-                                                LOOKUP_NORMAL,
-                                                "return", NULL_TREE, 0);
-         DECL_INITIAL (result) = NULL_TREE;
+         /* Avoid warning about control reaching end of function.  */
+         expand_null_return ();
+         return;
        }
-      if (retval == error_mark_node)
-       return;
     }
 
-  emit_queue ();
-
   if (retval != NULL_TREE
       && TREE_CODE_CLASS (TREE_CODE (retval)) == 'd'
       && cond_stack == 0 && loop_stack == 0 && case_stack == 0)
     current_function_return_value = retval;
 
-  if (result)
+  if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
     {
-      /* Everything's great--RETVAL is in RESULT.  */
-      if (original_result_rtx)
-       {
-         store_expr (result, original_result_rtx, 0);
-         expand_cleanups_to (NULL_TREE);
-         use_variable (DECL_RTL (result));
-         if (ctor_label  && TREE_CODE (ctor_label) != ERROR_MARK)
-           expand_goto (ctor_label);
-         else
-           expand_null_return ();
-       }
-      else if (retval && retval != result)
-       {
-         /* Clear this out so the later call to decl_function_context
-            won't end up bombing on us.  */
-         if (DECL_CONTEXT (result) == error_mark_node)
-           DECL_CONTEXT (result) = NULL_TREE;
-         /* Here is where we finally get RETVAL into RESULT.
-            `expand_return' does the magic of protecting
-            RESULT from cleanups.  */
-         retval = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (result),
-                                retval));
-         /* This part _must_ come second, because expand_return looks for
-            the INIT_EXPR as the toplevel node only.  :-( */
-         retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
-         TREE_SIDE_EFFECTS (retval) = 1;
-         expand_return (retval);
-       }
-      else
-       expand_return (result);
+      /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do.  */
+      expand_goto (ctor_label);
     }
-  else
+
+  if (retval && retval != result)
     {
-      /* We may still need to put RETVAL into RESULT.  */
-      result = DECL_RESULT (current_function_decl);
-      if (original_result_rtx)
-       {
-         /* Here we have a named return value that went
-            into memory.  We can compute RETVAL into that.  */
-         if (retval)
-           expand_assignment (result, retval, 0, 0);
-         else
-           store_expr (result, original_result_rtx, 0);
-         result = make_tree (TREE_TYPE (result), original_result_rtx);
-       }
-      else if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
-       {
-         /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do.  */
-         expand_goto (ctor_label);
-       }
-      else if (retval)
-       {
-         /* Here is where we finally get RETVAL into RESULT.
-            `expand_return' does the magic of protecting
-            RESULT from cleanups.  */
-         result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
-         TREE_SIDE_EFFECTS (result) = 1;
-         expand_return (result);
-       }
-      else if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode)
-       expand_return (result);
+      result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
+      TREE_SIDE_EFFECTS (result) = 1;
     }
-
-  current_function_returns_value = returns_value;
-
-  /* One way to clear out cleanups that EXPR might
-     generate.  Note that this code will really be
-     dead code, but that is ok--cleanups that were
-     needed were handled by the magic of `return'.  */
-  expand_cleanups_to (NULL_TREE);
+  expand_return (result);
+  current_function_returns_value = 1;
 }
 \f
 /* Start a C switch statement, testing expression EXP.