OSDN Git Service

* tree-def (WITH_SIZE_EXPR): New.
[pf3gnuchains/gcc-fork.git] / gcc / c-typeck.c
index e619fa1..2495550 100644 (file)
@@ -253,17 +253,29 @@ composite_type (tree t1, tree t2)
        tree pointed_to_2 = TREE_TYPE (t2);
        tree target = composite_type (pointed_to_1, pointed_to_2);
        t1 = build_pointer_type (target);
-       return build_type_attribute_variant (t1, attributes);
+       t1 = build_type_attribute_variant (t1, attributes);
+       return qualify_type (t1, t2);
       }
 
     case ARRAY_TYPE:
       {
        tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
+       
+       /* We should not have any type quals on arrays at all.  */
+       if (TYPE_QUALS (t1) || TYPE_QUALS (t2))
+         abort ();
+       
        /* Save space: see if the result is identical to one of the args.  */
        if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
          return build_type_attribute_variant (t1, attributes);
        if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
          return build_type_attribute_variant (t2, attributes);
+       
+       if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
+         return build_type_attribute_variant (t1, attributes);
+       if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
+         return build_type_attribute_variant (t2, attributes);
+       
        /* Merge the element types, and have a size if either arg has one.  */
        t1 = build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
        return build_type_attribute_variant (t1, attributes);
@@ -289,13 +301,15 @@ composite_type (tree t1, tree t2)
        /* Simple way if one arg fails to specify argument types.  */
        if (TYPE_ARG_TYPES (t1) == 0)
         {
-          t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2));
-          return build_type_attribute_variant (t1, attributes);
+           t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2));
+           t1 = build_type_attribute_variant (t1, attributes);
+           return qualify_type (t1, t2);
         }
        if (TYPE_ARG_TYPES (t2) == 0)
         {
           t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1));
-          return build_type_attribute_variant (t1, attributes);
+          t1 = build_type_attribute_variant (t1, attributes);
+          return qualify_type (t1, t2);
         }
 
        /* If both args specify argument types, we must merge the two
@@ -365,6 +379,7 @@ composite_type (tree t1, tree t2)
 
        c_override_global_bindings_to_false = false;
        t1 = build_function_type (valtype, newargs);
+       t1 = qualify_type (t1, t2);
        /* ... falls through ...  */
       }
 
@@ -1222,10 +1237,10 @@ default_function_array_conversion (tree exp)
 
       if (TREE_CODE (exp) == VAR_DECL)
        {
-         /* ??? This is not really quite correct
-            in that the type of the operand of ADDR_EXPR
-            is not the target type of the type of the ADDR_EXPR itself.
-            Question is, can this lossage be avoided?  */
+         /* We are making an ADDR_EXPR of ptrtype.  This is a valid
+            ADDR_EXPR because it's the best way of representing what
+            happens in C when we take the address of an array and place
+            it in a pointer to the element type.  */
          adr = build1 (ADDR_EXPR, ptrtype, exp);
          if (!c_mark_addressable (exp))
            return error_mark_node;
@@ -1483,7 +1498,8 @@ build_component_ref (tree datum, tree component)
          if (TREE_TYPE (subdatum) == error_mark_node)
            return error_mark_node;
 
-         ref = build (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum);
+         ref = build (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum,
+                      NULL_TREE);
          if (TREE_READONLY (datum) || TREE_READONLY (subdatum))
            TREE_READONLY (ref) = 1;
          if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (subdatum))
@@ -1636,7 +1652,7 @@ build_array_ref (tree array, tree index)
        }
 
       type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
-      rval = build (ARRAY_REF, type, array, index);
+      rval = build (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
       /* Array ref is const/volatile if the array elements are
          or if the array is.  */
       TREE_READONLY (rval)
@@ -1870,20 +1886,6 @@ build_function_call (tree function, tree params)
 
   check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params);
 
-  /* Recognize certain built-in functions so we can make tree-codes
-     other than CALL_EXPR.  We do this when it enables fold-const.c
-     to do something useful.  */
-
-  if (TREE_CODE (function) == ADDR_EXPR
-      && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
-      && DECL_BUILT_IN (TREE_OPERAND (function, 0)))
-    {
-      result = expand_tree_builtin (TREE_OPERAND (function, 0),
-                                   params, coerced_params);
-      if (result)
-       return result;
-    }
-
   result = build (CALL_EXPR, TREE_TYPE (fntype),
                  function, coerced_params, NULL_TREE);
   TREE_SIDE_EFFECTS (result) = 1;
@@ -2301,7 +2303,8 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
         is enough to prevent anybody from looking inside for
         associativity, but won't generate any code.  */
       if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
-           || typecode == COMPLEX_TYPE))
+           || typecode == COMPLEX_TYPE
+           || typecode == VECTOR_TYPE))
        {
          error ("wrong type argument to unary plus");
          return error_mark_node;
@@ -2562,6 +2565,9 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
        else
          addr = build1 (code, argtype, arg);
 
+       if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
+         TREE_INVARIANT (addr) = TREE_CONSTANT (addr) = 1;
+
        return addr;
       }
 
@@ -2605,7 +2611,6 @@ lvalue_p (tree ref)
              && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE);
 
     case BIND_EXPR:
-    case RTL_EXPR:
       return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE;
 
     default:
@@ -2710,7 +2715,6 @@ c_mark_addressable (tree exp)
            pedwarn ("address of register variable `%s' requested",
                     IDENTIFIER_POINTER (DECL_NAME (x)));
          }
-       put_var_into_stack (x, /*rescan=*/true);
 
        /* drops in */
       case FUNCTION_DECL:
@@ -6184,70 +6188,35 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
     }
   return args;
 }
+\f
+/* Generate a goto statement to LABEL.  */
 
-/* Expand an ASM statement with operands, handling output operands
-   that are not variables or INDIRECT_REFS by transforming such
-   cases into cases that expand_asm_operands can handle.
-
-   Arguments are same as for expand_asm_operands.  */
-
-void
-c_expand_asm_operands (tree string, tree outputs, tree inputs,
-                      tree clobbers, int vol, location_t locus)
+tree
+c_finish_goto_label (tree label)
 {
-  int noutputs = list_length (outputs);
-  int i;
-  /* o[I] is the place that output number I should be written.  */
-  tree *o = alloca (noutputs * sizeof (tree));
-  tree tail;
-
-  /* Record the contents of OUTPUTS before it is modified.  */
-  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
-    {
-      o[i] = TREE_VALUE (tail);
-      if (o[i] == error_mark_node)
-       return;
-    }
+  tree decl = lookup_label (label);
+  if (!decl)
+    return NULL_TREE;
 
-  /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of
-     OUTPUTS some trees for where the values were actually stored.  */
-  expand_asm_operands (string, outputs, inputs, clobbers, vol, locus);
+  TREE_USED (decl) = 1;
+  return add_stmt (build (GOTO_EXPR, void_type_node, decl));
+}
 
-  /* Copy all the intermediate outputs into the specified outputs.  */
-  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
-    {
-      if (o[i] != TREE_VALUE (tail))
-       {
-         expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)),
-                      NULL_RTX, VOIDmode, EXPAND_NORMAL);
-         free_temp_slots ();
+/* Generate a computed goto statement to EXPR.  */
 
-         /* Restore the original value so that it's correct the next
-            time we expand this function.  */
-         TREE_VALUE (tail) = o[i];
-       }
-      /* Detect modification of read-only values.
-        (Otherwise done by build_modify_expr.)  */
-      else
-       {
-         tree type = TREE_TYPE (o[i]);
-         if (TREE_READONLY (o[i])
-             || TYPE_READONLY (type)
-             || ((TREE_CODE (type) == RECORD_TYPE
-                  || TREE_CODE (type) == UNION_TYPE)
-                 && C_TYPE_FIELDS_READONLY (type)))
-           readonly_error (o[i], "modification by `asm'");
-       }
-    }
-
-  /* Those MODIFY_EXPRs could do autoincrements.  */
-  emit_queue ();
+tree
+c_finish_goto_ptr (tree expr)
+{
+  if (pedantic)
+    pedwarn ("ISO C forbids `goto *expr;'");
+  expr = convert (ptr_type_node, expr);
+  return add_stmt (build (GOTO_EXPR, void_type_node, expr));
 }
-\f
+
 /* Generate a C `return' statement.  RETVAL is the expression for what
    to return, or a null pointer for `return;' with no value.  */
 
-void
+tree
 c_finish_return (tree retval)
 {
   tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
@@ -6277,7 +6246,7 @@ c_finish_return (tree retval)
 
       current_function_returns_value = 1;
       if (t == error_mark_node)
-       return;
+       return NULL_TREE;
 
       inner = t = convert (TREE_TYPE (res), t);
 
@@ -6335,7 +6304,7 @@ c_finish_return (tree retval)
       retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
     }
 
-  add_stmt (build_stmt (RETURN_EXPR, retval));
+  return add_stmt (build_stmt (RETURN_EXPR, retval));
 }
 \f
 struct c_switch {
@@ -6357,7 +6326,7 @@ struct c_switch {
    during the processing of the body of a function, and we never
    collect at that point.  */
 
-static struct c_switch *switch_stack;
+struct c_switch *c_switch_stack;
 
 /* Start a C switch statement, testing expression EXP.  Return the new
    SWITCH_STMT.  */
@@ -6398,10 +6367,10 @@ c_start_case (tree exp)
   cs = xmalloc (sizeof (*cs));
   cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type);
   cs->cases = splay_tree_new (case_compare, NULL, NULL);
-  cs->next = switch_stack;
-  switch_stack = cs;
+  cs->next = c_switch_stack;
+  c_switch_stack = cs;
 
-  return add_stmt (switch_stack->switch_stmt);
+  return add_stmt (cs->switch_stmt);
 }
 
 /* Process a case label.  */
@@ -6411,10 +6380,10 @@ do_case (tree low_value, tree high_value)
 {
   tree label = NULL_TREE;
 
-  if (switch_stack)
+  if (c_switch_stack)
     {
-      label = c_add_case_label (switch_stack->cases,
-                               SWITCH_COND (switch_stack->switch_stmt),
+      label = c_add_case_label (c_switch_stack->cases,
+                               SWITCH_COND (c_switch_stack->switch_stmt),
                                low_value, high_value);
       if (label == error_mark_node)
        label = NULL_TREE;
@@ -6432,7 +6401,7 @@ do_case (tree low_value, tree high_value)
 void
 c_finish_case (tree body)
 {
-  struct c_switch *cs = switch_stack;
+  struct c_switch *cs = c_switch_stack;
 
   SWITCH_BODY (cs->switch_stmt) = body;
 
@@ -6440,230 +6409,193 @@ c_finish_case (tree body)
   c_do_switch_warnings (cs->cases, cs->switch_stmt);
 
   /* Pop the stack.  */
-  switch_stack = switch_stack->next;
+  c_switch_stack = cs->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.  */
+/* Emit an if statement.  IF_LOCUS is the location of the 'if'.  COND,
+   THEN_BLOCK and ELSE_BLOCK are expressions to be used; ELSE_BLOCK
+   may be null.  NESTED_IF is true if THEN_BLOCK contains another IF
+   statement, and was not surrounded with parenthesis.  */
 
 void
-c_begin_if_stmt (void)
+c_finish_if_stmt (location_t if_locus, tree cond, tree then_block,
+                 tree else_block, bool nested_if)
 {
-  tree r;
-  if_elt *elt;
+  tree stmt;
 
-  /* Make sure there is enough space on the stack.  */
-  if (if_stack_space == 0)
+  /* Diagnose an ambiguous else if if-then-else is nested inside if-then.  */
+  if (warn_parentheses && nested_if && else_block == NULL)
     {
-      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.  */
+      tree inner_if = then_block;
 
-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 ();
+      /* We know from the grammar productions that there is an IF nested
+        within THEN_BLOCK.  Due to labels and c99 conditional declarations,
+        it might not be exactly THEN_BLOCK, but should be the last
+        non-container statement within.  */
+      while (1)
+       switch (TREE_CODE (inner_if))
+         {
+         case COND_EXPR:
+           goto found;
+         case BIND_EXPR:
+           inner_if = BIND_EXPR_BODY (inner_if);
+           break;
+         case STATEMENT_LIST:
+           inner_if = expr_last (then_block);
+           break;
+         case TRY_FINALLY_EXPR:
+         case TRY_CATCH_EXPR:
+           inner_if = TREE_OPERAND (inner_if, 0);
+           break;
+         default:
+           abort ();
+         }
+    found:
 
-  if (elt->needs_warning)
-    warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
-            EXPR_LOCUS (elt->if_stmt));
+      if (COND_EXPR_ELSE (inner_if))
+        warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
+                 &if_locus);
+    }
 
-  if (extra_warnings && stmt_count == elt->stmt_count)
+  /* Diagnose ";" via the special empty statement node that we create.  */
+  if (extra_warnings)
     {
-      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);
+      if (TREE_CODE (then_block) == NOP_EXPR && !TREE_TYPE (then_block))
+       {
+         if (!else_block)
+           warning ("%Hempty body in an if-statement",
+                    EXPR_LOCUS (then_block));
+         then_block = alloc_stmt_list ();
+       }
+      if (else_block
+         && TREE_CODE (else_block) == NOP_EXPR
+         && !TREE_TYPE (else_block))
+       {
+         warning ("%Hempty body in an else-statement",
+                  EXPR_LOCUS (else_block));
+         else_block = alloc_stmt_list ();
+       }
     }
-}
-\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;
+  stmt = build3 (COND_EXPR, NULL_TREE, cond, then_block, else_block);
+  SET_EXPR_LOCATION (stmt, if_locus);
+  add_stmt (stmt);
 }
 
-void
-c_finish_while_stmt_cond (tree cond, tree while_stmt)
-{
-  WHILE_COND (while_stmt) = (*lang_hooks.truthvalue_conversion) (cond);
-}
+/* Emit a general-purpose loop construct.  START_LOCUS is the location of
+   the beginning of the loop.  COND is the loop condition.  COND_IS_FIRST
+   is false for DO loops.  INCR is the FOR increment expression.  BODY is
+   the statement controlled by the loop.  BLAB is the break label.  CLAB is
+   the continue label.  Everything is allowed to be NULL.  */
 
 void
-c_finish_while_stmt (tree body, tree while_stmt)
+c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
+              tree blab, tree clab, bool cond_is_first)
 {
-  WHILE_BODY (while_stmt) = body;
+  tree entry = NULL, exit = NULL, t;
+
+  /* Detect do { ... } while (0) and don't generate loop construct.  */
+  if (cond && !cond_is_first && integer_zerop (cond))
+    cond = NULL;
+  if (cond_is_first || cond)
+    {
+      tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+      /* If we have an exit condition, then we build an IF with gotos either
+         out of the loop, or to the top of it.  If there's no exit condition,
+         then we just build a jump back to the top.  */
+      exit = build_and_jump (&LABEL_EXPR_LABEL (top));
+      if (cond)
+        {
+          /* Canonicalize the loop condition to the end.  This means
+             generating a branch to the loop condition.  Reuse the
+             continue label, if possible.  */
+          if (cond_is_first)
+            {
+              if (incr || !clab)
+                {
+                  entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+                  t = build_and_jump (&LABEL_EXPR_LABEL (entry));
+                }
+              else
+                t = build1 (GOTO_EXPR, void_type_node, clab);
+             SET_EXPR_LOCATION (t, start_locus);
+              add_stmt (t);
+            }
+         t = build_and_jump (&blab);
+          exit = build (COND_EXPR, void_type_node, cond, exit, t);
+          exit = fold (exit);
+         if (cond_is_first)
+            SET_EXPR_LOCATION (exit, start_locus);
+         else
+            SET_EXPR_LOCATION (exit, input_location);
+        }
+      add_stmt (top);
+    }
+  if (body)
+    add_stmt (body);
+  if (clab)
+    add_stmt (build1 (LABEL_EXPR, void_type_node, clab));
+  if (incr)
+    add_stmt (incr);
+  if (entry)
+    add_stmt (entry);
+  if (exit)
+    add_stmt (exit);
+  if (blab)
+    add_stmt (build1 (LABEL_EXPR, void_type_node, blab));
 }
-\f
-/* Create a for statement.  */
 
 tree
-c_begin_for_stmt (void)
+c_finish_bc_stmt (tree *label_p, bool is_break)
 {
-  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;
-}
+  tree label = *label_p;
 
-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);
-}
+  if (!label)
+    *label_p = label = create_artificial_label ();
+  else if (TREE_CODE (label) != LABEL_DECL)
+    {
+      if (is_break)
+       error ("break statement not within loop or switch");
+      else
+        error ("continue statement not within a loop");
+      return NULL_TREE;
+    }
 
-void
-c_finish_for_stmt_incr (tree expr, tree for_stmt)
-{
-  FOR_EXPR (for_stmt) = expr;
+  return add_stmt (build (GOTO_EXPR, void_type_node, label));
 }
 
-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.  */
+/* A helper routine for c_process_expr_stmt and c_finish_stmt_expr.  */
 
 static void
 emit_side_effect_warnings (tree expr)
 {
-  if (!TREE_SIDE_EFFECTS (expr))
+  if (expr == error_mark_node)
+    ;
+  else 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);
+                EXPR_HAS_LOCATION (expr) ? EXPR_LOCUS (expr) : &input_location);
     }
   else if (warn_unused_value)
     warn_if_unused_value (expr, input_location);
 }
 
-/* Emit an expression as a statement.  */
+/* Process an expression as if it were a complete statement.  Emit
+   diagnostics, but do not call ADD_STMT.  */
 
-void
-c_finish_expr_stmt (tree expr)
+tree
+c_process_expr_stmt (tree expr)
 {
   if (!expr)
-    return;
+    return NULL_TREE;
 
   /* Do default conversion if safe and possibly important,
      in case within ({...}).  */
@@ -6692,7 +6624,21 @@ c_finish_expr_stmt (tree expr)
   if (DECL_P (expr) || TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
     expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
 
-  add_stmt (expr);
+  if (EXPR_P (expr))
+    SET_EXPR_LOCATION (expr, input_location);
+
+  return expr;
+}
+
+/* Emit an expression as a statement.  */
+
+tree
+c_finish_expr_stmt (tree expr)
+{
+  if (expr)
+    return add_stmt (c_process_expr_stmt (expr));
+  else
+    return NULL;
 }
 
 /* Do the opposite and emit a statement as an expression.  To begin,
@@ -6762,7 +6708,9 @@ c_finish_stmt_expr (tree body)
 
   /* 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)
+  if (last == error_mark_node
+      || (last == BIND_EXPR_BODY (body)
+         && BIND_EXPR_VARS (body) == NULL))
     return last;
 
   /* Extract the type of said expression.  */
@@ -6799,10 +6747,7 @@ c_begin_compound_stmt (bool do_scope)
 {
   tree stmt = push_stmt_list ();
   if (do_scope)
-    {
-      push_scope ();
-      clear_last_expr ();
-    }
+    push_scope ();
   return stmt;
 }