Makefile.in (parse.o, decl.o): Also depend on $(srcdir)/../except.h $(srcdir)/.....
[gcc.git] / gcc / cp / expr.c
index 27da793b1a7ed4060e0729742cb6dc8eb69ac140..a14695ddd51ff03fbc4c2e829d88f9b526fbc967 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert language-specific tree expression to rtl instructions,
    for GNU compiler.
-   Copyright (C) 1988, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -16,22 +16,26 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include "config.h"
+#include <stdio.h>
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
 #include "expr.h"
 #include "cp-tree.h"
 
-#undef NULL
-#define NULL 0
+static tree extract_aggr_init PROTO((tree, tree));
+static tree extract_scalar_init PROTO((tree, tree));
+static rtx cplus_expand_expr PROTO((tree, rtx, enum machine_mode,
+                                   enum expand_modifier));
 
 /* Hook used by expand_expr to expand language-specific tree codes.  */
 
-rtx
+static rtx
 cplus_expand_expr (exp, target, tmode, modifier)
      tree exp;
      rtx target;
@@ -41,11 +45,10 @@ cplus_expand_expr (exp, target, tmode, modifier)
   tree type = TREE_TYPE (exp);
   register enum machine_mode mode = TYPE_MODE (type);
   register enum tree_code code = TREE_CODE (exp);
-  rtx original_target = target;
   int ignore = target == const0_rtx;
 
   if (ignore)
-    target = 0, original_target = 0;
+    target = 0;
 
   /* No sense saving up arithmetic to be done
      if it's all in the wrong mode to form part of an address.
@@ -104,7 +107,7 @@ cplus_expand_expr (exp, target, tmode, modifier)
            && TREE_CODE (TREE_OPERAND (func, 0)) == FUNCTION_DECL
            && DECL_CONSTRUCTOR_P (TREE_OPERAND (func, 0)))
          {
-           type = TYPE_POINTER_TO (type);
+           type = build_pointer_type (type);
            /* Don't clobber a value that might be part of a default
               parameter value.  */
            mark_addressable (slot);
@@ -131,20 +134,28 @@ cplus_expand_expr (exp, target, tmode, modifier)
          }
        if (call_target)
          {
-           preserve_temp_slots (call_target);
-
            /* Make this a valid memory address now.  The code below assumes
               that it can compare rtx and make assumptions based on the
               result.  The assumptions are true only if the address was
               valid to begin with.  */
            call_target = validize_mem (call_target);
+
+           /* If this is a reference to a symbol, expand_inline_function
+              will do this transformation and return a different target
+              than the one we gave it, though functionally equivalent.  Do
+              the transformation here to avoid confusion.  */
+           if (! cse_not_expected && GET_CODE (call_target) == MEM
+               && GET_CODE (XEXP (call_target, 0)) == SYMBOL_REF)
+             {
+               call_target = gen_rtx
+                 (MEM, mode, memory_address (mode, XEXP (call_target, 0)));
+               MEM_IN_STRUCT_P (call_target) = 1;
+             }
          }
 
-       preserve_temp_slots (DECL_RTL (slot));
-       call_exp = build (CALL_EXPR, type, func, args, 0);
+       call_exp = build (CALL_EXPR, type, func, args, NULL_TREE);
        TREE_SIDE_EFFECTS (call_exp) = 1;
        return_target = expand_call (call_exp, call_target, ignore);
-       free_temp_slots ();
        if (call_target == 0)
          {
            if (pcc_struct_return)
@@ -168,7 +179,7 @@ cplus_expand_expr (exp, target, tmode, modifier)
 
                    init = maybe_build_cleanup (convert_from_reference (init));
                    if (init != NULL_TREE)
-                     expand_expr (init, 0, 0, 0);
+                     expand_expr (init, const0_rtx, VOIDmode, 0);
                  }
                call_target = return_target = DECL_RTL (slot);
              }
@@ -229,6 +240,14 @@ cplus_expand_expr (exp, target, tmode, modifier)
       expand_throw (TREE_OPERAND (exp, 0));
       return NULL;
 
+    case VEC_INIT_EXPR:
+      return expand_expr
+       (expand_vec_init
+        (NULL_TREE, TREE_OPERAND (exp, 0),
+         build_binary_op (MINUS_EXPR, TREE_OPERAND (exp, 2),
+                          integer_one_node, 1),
+         TREE_OPERAND (exp, 1), 0), target, tmode, modifier);
+
     default:
       break;
     }
@@ -273,19 +292,6 @@ fixup_result_decl (decl, result)
     }
 }
 
-/* Return nonzero iff DECL is memory-based.  The DECL_RTL of
-   certain const variables might be a CONST_INT, or a REG
-   in some cases.  We cannot use `memory_operand' as a test
-   here because on most RISC machines, a variable's address
-   is not, by itself, a legitimate address.  */
-
-int
-decl_in_memory_p (decl)
-     tree decl;
-{
-  return DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == MEM;
-}
-
 /* Expand this initialization inline and see if it's simple enough that
    it can be done at compile-time.  */
 
@@ -328,8 +334,8 @@ extract_scalar_init (decl, init)
 
       to = XEXP (r, 0);
 
-      if (! (to == value ||
-            (GET_CODE (to) == SUBREG && XEXP (to, 0) == value)))
+      if (! (to == value
+            || (GET_CODE (to) == SUBREG && XEXP (to, 0) == value)))
        return 0;
 
       r = XEXP (r, 1);
@@ -353,6 +359,7 @@ extract_init (decl, init)
 {
   return 0;
 
+#if 0
   if (IS_AGGR_TYPE (TREE_TYPE (decl))
       || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
     init = extract_aggr_init (decl, init);
@@ -364,4 +371,93 @@ extract_init (decl, init)
 
   DECL_INITIAL (decl) = init;
   return 1;
+#endif
+}
+
+void
+do_case (start, end)
+     tree start, end;
+{
+  tree value1 = NULL_TREE, value2 = NULL_TREE, label;
+
+  if (start != NULL_TREE && TREE_TYPE (start) != NULL_TREE 
+      && POINTER_TYPE_P (TREE_TYPE (start)))
+    error ("pointers are not permitted as case values");
+
+  if (end && pedantic)
+    pedwarn ("ANSI C++ forbids range expressions in switch statement");
+
+  if (processing_template_decl)
+    {
+      add_tree (build_min_nt (CASE_LABEL, start, end));
+      return;
+    }
+
+  if (start)
+    value1 = check_cp_case_value (start);
+  if (end)
+    value2 = check_cp_case_value (end);
+  
+  label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+  if (value1 != error_mark_node
+      && value2 != error_mark_node)
+    {
+      tree duplicate;
+      int success;
+
+      if (end)
+       success = pushcase_range (value1, value2, convert_and_check,
+                                 label, &duplicate);
+      else if (start)
+       success = pushcase (value1, convert_and_check, label, &duplicate);
+      else
+       success = pushcase (NULL_TREE, 0, label, &duplicate);
+
+      if (success == 1)
+       {
+         if (end)
+           error ("case label not within a switch statement");
+         else if (start)
+           cp_error ("case label `%E' not within a switch statement", start);
+         else
+           error ("default label not within a switch statement");
+       }
+      else if (success == 2)
+       {
+         if (end)
+           {
+             error ("duplicate (or overlapping) case value");
+             cp_error_at ("this is the first entry overlapping that value",
+                          duplicate);
+           }
+         else if (start)
+           {
+             cp_error ("duplicate case value `%E'", start);
+             cp_error_at ("previously used here", duplicate);
+           }
+         else
+           {
+             error ("multiple default labels in one switch");
+             cp_error_at ("this is the first default label", duplicate);
+           }
+       }
+      else if (success == 3)
+       warning ("case value out of range");
+      else if (success == 4)
+       warning ("empty range specified");
+      else if (success == 5)
+       {
+         if (end)
+           error ("case label within scope of cleanup or variable array");
+         else if (! start)
+           error ("`default' label within scope of cleanup or variable array");
+         else
+           cp_error ("case label `%E' within scope of cleanup or variable array", start);
+       }
+    }
+  if (start)
+    define_case_label (label);
+  else
+    define_case_label (NULL_TREE);
 }