OSDN Git Service

PR rtl-optimization/14782
[pf3gnuchains/gcc-fork.git] / gcc / c-typeck.c
index c1a262b..e619fa1 100644 (file)
@@ -23,11 +23,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 /* This file is part of the C front end.
    It contains routines to build C expressions given their operands,
    including computing the types of the result, C-specific error checks,
-   and some optimization.
-
-   There are also routines to build RETURN_STMT nodes and CASE_STMT nodes,
-   and to process initializations in declarations (since they work
-   like a strange sort of assignment).  */
+   and some optimization.  */
 
 #include "config.h"
 #include "system.h"
@@ -45,6 +41,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "intl.h"
 #include "ggc.h"
 #include "target.h"
+#include "tree-iterator.h"
+#include "tree-gimple.h"
+
 
 /* Nonzero if we've already printed a "missing braces around initializer"
    message within this initializer.  */
@@ -862,7 +861,7 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
            tagged_tu_seen_base = &tts;
 
            if (DECL_NAME (s1) != NULL)
-             for (s2 = TYPE_VALUES (t2); s2; s2 = TREE_CHAIN (s2))
+             for (s2 = TYPE_FIELDS (t2); s2; s2 = TREE_CHAIN (s2))
                if (DECL_NAME (s1) == DECL_NAME (s2))
                  {
                    int result;
@@ -2199,26 +2198,6 @@ parser_build_binary_op (enum tree_code code, tree arg1, tree arg2)
   return result;
 }
 \f
-
-/* Return true if `t' is known to be non-negative.  */
-
-int
-c_tree_expr_nonnegative_p (tree t)
-{
-  if (TREE_CODE (t) == STMT_EXPR)
-    {
-      t = COMPOUND_BODY (STMT_EXPR_STMT (t));
-
-      /* Find the last statement in the chain, ignoring the final
-            * scope statement */
-      while (TREE_CHAIN (t) != NULL_TREE
-             && TREE_CODE (TREE_CHAIN (t)) != SCOPE_STMT)
-        t = TREE_CHAIN (t);
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
-    }
-  return tree_expr_nonnegative_p (t);
-}
-
 /* Return a tree for the difference of pointers OP0 and OP1.
    The resulting tree has type int.  */
 
@@ -2817,8 +2796,8 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
              /* Do not warn if the signed quantity is an unsuffixed
                 integer literal (or some static constant expression
                 involving such literals) and it is non-negative.  */
-             else if ((unsigned_op2 && c_tree_expr_nonnegative_p (op1))
-                      || (unsigned_op1 && c_tree_expr_nonnegative_p (op2)))
+             else if ((unsigned_op2 && tree_expr_nonnegative_p (op1))
+                      || (unsigned_op1 && tree_expr_nonnegative_p (op2)))
                /* OK */;
              else
                warning ("signed and unsigned type in conditional expression");
@@ -2956,7 +2935,7 @@ internal_build_compound_expr (tree list, int first_p)
      `foo() + bar(), baz()' the result of the `+' operator is not used,
      so we should issue a warning.  */
   else if (warn_unused_value)
-    warn_if_unused_value (TREE_VALUE (list));
+    warn_if_unused_value (TREE_VALUE (list), input_location);
 
   return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
 }
@@ -6131,7 +6110,7 @@ process_init_element (tree value)
 \f
 /* Build a complete asm-statement, whose components are a CV_QUALIFIER
    (guaranteed to be 'volatile' or null) and ARGS (represented using
-   an ASM_STMT node).  */
+   an ASM_EXPR node).  */
 tree
 build_asm_stmt (tree cv_qualifier, tree args)
 {
@@ -6144,7 +6123,7 @@ build_asm_stmt (tree cv_qualifier, tree args)
    some INPUTS, and some CLOBBERS.  The latter three may be NULL.
    SIMPLE indicates whether there was anything at all after the
    string in the asm expression -- asm("blah") and asm("blah" : )
-   are subtly different.  We use a ASM_STMT node to represent this.  */
+   are subtly different.  We use a ASM_EXPR node to represent this.  */
 tree
 build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
                bool simple)
@@ -6195,7 +6174,7 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
   for (tail = inputs; tail; tail = TREE_CHAIN (tail))
     TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
 
-  args = build_stmt (ASM_STMT, string, outputs, inputs, clobbers);
+  args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
 
   /* Simple asm statements are treated as volatile.  */
   if (simple)
@@ -6265,12 +6244,11 @@ c_expand_asm_operands (tree string, tree outputs, tree inputs,
   emit_queue ();
 }
 \f
-/* Expand a C `return' statement.
-   RETVAL is the expression for what to return,
-   or a null pointer for `return;' with no value.  */
+/* Generate a C `return' statement.  RETVAL is the expression for what
+   to return, or a null pointer for `return;' with no value.  */
 
-tree
-c_expand_return (tree retval)
+void
+c_finish_return (tree retval)
 {
   tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
 
@@ -6299,7 +6277,7 @@ c_expand_return (tree retval)
 
       current_function_returns_value = 1;
       if (t == error_mark_node)
-       return NULL_TREE;
+       return;
 
       inner = t = convert (TREE_TYPE (res), t);
 
@@ -6357,7 +6335,7 @@ c_expand_return (tree retval)
       retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
     }
 
return add_stmt (build_return_stmt (retval));
 add_stmt (build_stmt (RETURN_EXPR, retval));
 }
 \f
 struct c_switch {
@@ -6435,19 +6413,11 @@ do_case (tree low_value, tree high_value)
 
   if (switch_stack)
     {
-      bool switch_was_empty_p = (SWITCH_BODY (switch_stack->switch_stmt) == NULL_TREE);
-
       label = c_add_case_label (switch_stack->cases,
                                SWITCH_COND (switch_stack->switch_stmt),
                                low_value, high_value);
       if (label == error_mark_node)
        label = NULL_TREE;
-      else if (switch_was_empty_p)
-       {
-         /* Attach the first case label to the SWITCH_BODY.  */
-         SWITCH_BODY (switch_stack->switch_stmt) = TREE_CHAIN (switch_stack->switch_stmt);
-         TREE_CHAIN (switch_stack->switch_stmt) = NULL_TREE;
-       }
     }
   else if (low_value)
     error ("case label not within a switch statement");
@@ -6460,22 +6430,433 @@ do_case (tree low_value, tree high_value)
 /* Finish the switch statement.  */
 
 void
-c_finish_case (void)
+c_finish_case (tree body)
 {
   struct c_switch *cs = switch_stack;
 
+  SWITCH_BODY (cs->switch_stmt) = body;
+
   /* Emit warnings as needed.  */
   c_do_switch_warnings (cs->cases, cs->switch_stmt);
 
-  /* Rechain the next statements to the SWITCH_STMT.  */
-  last_tree = cs->switch_stmt;
-
   /* Pop the stack.  */
   switch_stack = switch_stack->next;
   splay_tree_delete (cs->cases);
   free (cs);
 }
+\f
+/* Keep a stack of if statements.  We record the number of compound
+   statements seen up to the if keyword, as well as the line number
+   and file of the if.  If a potentially ambiguous else is seen, that
+   fact is recorded; the warning is issued when we can be sure that
+   the enclosing if statement does not have an else branch.  */
+typedef struct
+{
+  tree if_stmt;
+  location_t empty_locus;
+  int compstmt_count;
+  int stmt_count;
+  unsigned int needs_warning : 1;
+  unsigned int saw_else : 1;
+} if_elt;
+
+static if_elt *if_stack;
+
+/* Amount of space in the if statement stack.  */
+static int if_stack_space = 0;
+
+/* Stack pointer.  */
+static int if_stack_pointer = 0;
+
+/* Begin an if-statement.  */
+
+void
+c_begin_if_stmt (void)
+{
+  tree r;
+  if_elt *elt;
+
+  /* Make sure there is enough space on the stack.  */
+  if (if_stack_space == 0)
+    {
+      if_stack_space = 10;
+      if_stack = xmalloc (10 * sizeof (if_elt));
+    }
+  else if (if_stack_space == if_stack_pointer)
+    {
+      if_stack_space += 10;
+      if_stack = xrealloc (if_stack, if_stack_space * sizeof (if_elt));
+    }
+
+  r = add_stmt (build_stmt (COND_EXPR, NULL_TREE, NULL_TREE, NULL_TREE));
+
+  /* Record this if statement.  */
+  elt = &if_stack[if_stack_pointer++];
+  memset (elt, 0, sizeof (*elt));
+  elt->if_stmt = r;
+}
+
+/* Record the start of an if-then, and record the start of it
+   for ambiguous else detection.
+
+   COND is the condition for the if-then statement.
+
+   IF_STMT is the statement node that has already been created for
+   this if-then statement.  It is created before parsing the
+   condition to keep line number information accurate.  */
+
+void
+c_finish_if_cond (tree cond, int compstmt_count, int stmt_count)
+{
+  if_elt *elt = &if_stack[if_stack_pointer - 1];
+  elt->compstmt_count = compstmt_count;
+  elt->stmt_count = stmt_count;
+  COND_EXPR_COND (elt->if_stmt) = lang_hooks.truthvalue_conversion (cond);
+}
+
+/* Called after the then-clause for an if-statement is processed.  */
+
+void
+c_finish_then (tree then_stmt)
+{
+  if_elt *elt = &if_stack[if_stack_pointer - 1];
+  COND_EXPR_THEN (elt->if_stmt) = then_stmt;
+  elt->empty_locus = input_location;
+}
+
+/* Called between the then-clause and the else-clause
+   of an if-then-else.  */
+
+void
+c_begin_else (int stmt_count)
+{
+  if_elt *elt = &if_stack[if_stack_pointer - 1];
+
+  /* An ambiguous else warning must be generated for the enclosing if
+     statement, unless we see an else branch for that one, too.  */
+  if (warn_parentheses
+      && if_stack_pointer > 1
+      && (elt[0].compstmt_count == elt[-1].compstmt_count))
+    elt[-1].needs_warning = 1;
+
+  /* Even if a nested if statement had an else branch, it can't be
+     ambiguous if this one also has an else.  So don't warn in that
+     case.  Also don't warn for any if statements nested in this else.  */
+  elt->needs_warning = 0;
+  elt->compstmt_count--;
+  elt->saw_else = 1;
+  elt->stmt_count = stmt_count;
+}
+
+/* Called after the else-clause for an if-statement is processed.  */
+
+void
+c_finish_else (tree else_stmt)
+{
+  if_elt *elt = &if_stack[if_stack_pointer - 1];
+  COND_EXPR_ELSE (elt->if_stmt) = else_stmt;
+  elt->empty_locus = input_location;
+}
+
+/* Record the end of an if-then.  Optionally warn if a nested
+   if statement had an ambiguous else clause.  */
+
+void
+c_finish_if_stmt (int stmt_count)
+{
+  if_elt *elt = &if_stack[--if_stack_pointer];
+
+  if (COND_EXPR_ELSE (elt->if_stmt) == NULL)
+    COND_EXPR_ELSE (elt->if_stmt) = build_empty_stmt ();
+
+  if (elt->needs_warning)
+    warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
+            EXPR_LOCUS (elt->if_stmt));
+
+  if (extra_warnings && stmt_count == elt->stmt_count)
+    {
+      if (elt->saw_else)
+       warning ("%Hempty body in an else-statement", &elt->empty_locus);
+      else
+       warning ("%Hempty body in an if-statement", &elt->empty_locus);
+    }
+}
+\f
+/* Begin a while statement.  Returns a newly created WHILE_STMT if
+   appropriate.  */
+
+tree
+c_begin_while_stmt (void)
+{
+  tree r;
+  r = add_stmt (build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE));
+  return r;
+}
+
+void
+c_finish_while_stmt_cond (tree cond, tree while_stmt)
+{
+  WHILE_COND (while_stmt) = (*lang_hooks.truthvalue_conversion) (cond);
+}
+
+void
+c_finish_while_stmt (tree body, tree while_stmt)
+{
+  WHILE_BODY (while_stmt) = body;
+}
+\f
+/* Create a for statement.  */
+
+tree
+c_begin_for_stmt (void)
+{
+  tree r;
+  r = add_stmt (build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
+                           NULL_TREE, NULL_TREE));
+  FOR_INIT_STMT (r) = push_stmt_list ();
+  return r;
+}
+
+void
+c_finish_for_stmt_init (tree for_stmt)
+{
+  FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
+}
+
+void
+c_finish_for_stmt_cond (tree cond, tree for_stmt)
+{
+  if (cond)
+    FOR_COND (for_stmt) = lang_hooks.truthvalue_conversion (cond);
+}
+
+void
+c_finish_for_stmt_incr (tree expr, tree for_stmt)
+{
+  FOR_EXPR (for_stmt) = expr;
+}
+
+void
+c_finish_for_stmt (tree body, tree for_stmt)
+{
+  FOR_BODY (for_stmt) = body;
+}
+\f
+/* A helper routine for c_finish_expr_stmt and c_finish_stmt_expr.  */
+
+static void
+emit_side_effect_warnings (tree expr)
+{
+  if (!TREE_SIDE_EFFECTS (expr))
+    {
+      if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
+       warning ("%Hstatement with no effect",
+                EXPR_LOCUS (expr) ? EXPR_LOCUS (expr) : &input_location);
+    }
+  else if (warn_unused_value)
+    warn_if_unused_value (expr, input_location);
+}
 
+/* Emit an expression as a statement.  */
+
+void
+c_finish_expr_stmt (tree expr)
+{
+  if (!expr)
+    return;
+
+  /* Do default conversion if safe and possibly important,
+     in case within ({...}).  */
+  if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+       && (flag_isoc99 || lvalue_p (expr)))
+      || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
+    expr = default_conversion (expr);
+
+  if (warn_sequence_point)
+    verify_sequence_points (expr);
+
+  if (TREE_TYPE (expr) != error_mark_node
+      && !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr))
+      && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
+    error ("expression statement has incomplete type");
+
+  /* If we're not processing a statement expression, warn about unused values.
+     Warnings for statement expressions will be emitted later, once we figure
+     out which is the result.  */
+  if (!STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
+      && (extra_warnings || warn_unused_value))
+    emit_side_effect_warnings (expr);
+
+  /* If the expression is not of a type to which we cannot assign a line
+     number, wrap the thing in a no-op NOP_EXPR.  */
+  if (DECL_P (expr) || TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
+    expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
+
+  add_stmt (expr);
+}
+
+/* Do the opposite and emit a statement as an expression.  To begin,
+   create a new binding level and return it.  */
+
+tree
+c_begin_stmt_expr (void)
+{
+  tree ret;
+
+  /* We must force a BLOCK for this level so that, if it is not expanded
+     later, there is a way to turn off the entire subtree of blocks that
+     are contained in it.  */
+  keep_next_level ();
+  ret = c_begin_compound_stmt (true);
+
+  /* Mark the current statement list as belonging to a statement list.  */
+  STATEMENT_LIST_STMT_EXPR (ret) = 1;
+
+  return ret;
+}
+
+tree
+c_finish_stmt_expr (tree body)
+{
+  tree last, type, tmp, val;
+  tree *last_p;
+
+  body = c_end_compound_stmt (body, true);
+
+  /* Locate the last statement in BODY.  See c_end_compound_stmt
+     about always returning a BIND_EXPR.  */
+  last_p = &BIND_EXPR_BODY (body);
+  last = BIND_EXPR_BODY (body);
+
+ continue_searching:
+  if (TREE_CODE (last) == STATEMENT_LIST)
+    {
+      tree_stmt_iterator i;
+
+      /* This can happen with degenerate cases like ({ }).  No value.  */
+      if (!TREE_SIDE_EFFECTS (last))
+       return body;
+
+      /* If we're supposed to generate side effects warnings, process
+        all of the statements except the last.  */
+      if (extra_warnings || warn_unused_value)
+       {
+         for (i = tsi_start (last); !tsi_one_before_end_p (i); tsi_next (&i))
+           emit_side_effect_warnings (tsi_stmt (i));
+       }
+      else
+       i = tsi_last (last);
+      last_p = tsi_stmt_ptr (i);
+      last = *last_p;
+    }
+
+  /* If the end of the list is exception related, then the list was split
+     by a call to push_cleanup.  Continue searching.  */
+  if (TREE_CODE (last) == TRY_FINALLY_EXPR
+      || TREE_CODE (last) == TRY_CATCH_EXPR)
+    {
+      last_p = &TREE_OPERAND (last, 0);
+      last = *last_p;
+      goto continue_searching;
+    }
+
+  /* In the case that the BIND_EXPR is not necessary, return the
+     expression out from inside it.  */
+  if (last == BIND_EXPR_BODY (body) && BIND_EXPR_VARS (body) == NULL)
+    return last;
+
+  /* Extract the type of said expression.  */
+  type = TREE_TYPE (last);
+
+  /* If we're not returning a value at all, then the BIND_EXPR that
+     we already have is a fine expression to return.  */
+  if (!type || VOID_TYPE_P (type))
+    return body;
+
+  /* Now that we've located the expression containing the value, it seems
+     silly to make voidify_wrapper_expr repeat the process.  Create a
+     temporary of the appropriate type and stick it in a TARGET_EXPR.  */
+  tmp = create_tmp_var_raw (type, NULL);
+
+  /* Unwrap a no-op NOP_EXPR as added by c_finish_expr_stmt.  This avoids
+     tree_expr_nonnegative_p giving up immediately.  */
+  val = last;
+  if (TREE_CODE (val) == NOP_EXPR
+      && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0)))
+    val = TREE_OPERAND (val, 0);
+
+  *last_p = build (MODIFY_EXPR, void_type_node, tmp, val);
+  SET_EXPR_LOCUS (*last_p, EXPR_LOCUS (last));
+
+  return build (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
+}
+\f
+/* Begin and end compound statements.  This is as simple as pushing
+   and popping new statement lists from the tree.  */
+
+tree
+c_begin_compound_stmt (bool do_scope)
+{
+  tree stmt = push_stmt_list ();
+  if (do_scope)
+    {
+      push_scope ();
+      clear_last_expr ();
+    }
+  return stmt;
+}
+
+tree
+c_end_compound_stmt (tree stmt, bool do_scope)
+{
+  tree block = NULL;
+
+  if (do_scope)
+    {
+      if (c_dialect_objc ())
+       objc_clear_super_receiver ();
+      block = pop_scope ();
+    }
+
+  stmt = pop_stmt_list (stmt);
+  stmt = c_build_bind_expr (block, stmt);
+
+  /* If this compound statement is nested immediately inside a statement
+     expression, then force a BIND_EXPR to be created.  Otherwise we'll
+     do the wrong thing for ({ { 1; } }) or ({ 1; { } }).  In particular,
+     STATEMENT_LISTs merge, and thus we can lose track of what statement
+     was really last.  */
+  if (cur_stmt_list
+      && STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
+      && TREE_CODE (stmt) != BIND_EXPR)
+    {
+      stmt = build (BIND_EXPR, void_type_node, NULL, stmt, NULL);
+      TREE_SIDE_EFFECTS (stmt) = 1;
+    }
+
+  return stmt;
+}
+
+/* Queue a cleanup.  CLEANUP is an expression/statement to be executed
+   when the current scope is exited.  EH_ONLY is true when this is not
+   meant to apply to normal control flow transfer.  */
+
+void
+push_cleanup (tree decl ATTRIBUTE_UNUSED, tree cleanup, bool eh_only)
+{
+  enum tree_code code;
+  tree stmt, list;
+  bool stmt_expr;
+
+  code = eh_only ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR;
+  stmt = build_stmt (code, NULL, cleanup);
+  add_stmt (stmt);
+  stmt_expr = STATEMENT_LIST_STMT_EXPR (cur_stmt_list);
+  list = push_stmt_list ();
+  TREE_OPERAND (stmt, 0) = list;
+  STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
+}
+\f
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
    This function differs from `build' in several ways:
@@ -7091,7 +7472,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                     constant expression involving such literals or a
                     conditional expression involving such literals)
                     and it is non-negative.  */
-                 if (c_tree_expr_nonnegative_p (sop))
+                 if (tree_expr_nonnegative_p (sop))
                    /* OK */;
                  /* Do not warn if the comparison is an equality operation,
                     the unsigned quantity is an integral constant, and it