OSDN Git Service

* decl.c (initialize_local_var): Handle static variables here.
[pf3gnuchains/gcc-fork.git] / gcc / cp / semantics.c
index 38eab3b..9505535 100644 (file)
@@ -31,6 +31,7 @@
 #include "except.h"
 #include "lex.h"
 #include "toplev.h"
+#include "flags.h"
 
 /* There routines provide a modular interface to perform many parsing
    operations.  They may therefore be used during actual parsing, or
@@ -41,9 +42,8 @@
    parsing into this file; that will make implementing the new parser
    much easier since it will be able to make use of these routines.  */
 
-static void expand_stmts PROTO((tree));
-static void do_pushlevel PROTO((void));
-static tree do_poplevel PROTO((void));
+static tree expand_cond PROTO((tree));
+static tree maybe_convert_cond PROTO((tree));
 
 /* When parsing a template, LAST_TREE contains the last statement
    parsed.  These are chained together through the TREE_CHAIN field,
@@ -51,18 +51,64 @@ static tree do_poplevel PROTO((void));
    bottom-up.  This macro makes LAST_TREE the indicated SUBSTMT of
    STMT.  */
 
-#define RECHAIN_STMTS(stmt, substmt, last)     \
-  do {                                         \
-    substmt = last;                            \
-    TREE_CHAIN (stmt) = NULL_TREE;             \
-    last_tree = stmt;                          \
+#define RECHAIN_STMTS(stmt, substmt)   \
+  do {                                 \
+    substmt = TREE_CHAIN (stmt);       \
+    TREE_CHAIN (stmt) = NULL_TREE;     \
+    last_tree = stmt;                  \
   } while (0)
 
-#define RECHAIN_STMTS_FROM_LAST(stmt, substmt) \
-  RECHAIN_STMTS (stmt, substmt, last_tree)
+/* Finish processing the COND, the SUBSTMT condition for STMT.  */
+
+#define FINISH_COND(cond, stmt, substmt)               \
+  do {                                                 \
+    if (last_tree != stmt)                             \
+      {                                                        \
+        RECHAIN_STMTS (stmt, substmt);                 \
+        if (!processing_template_decl)                  \
+          {                                             \
+           cond = build_tree_list (substmt, cond);     \
+           substmt = cond;                             \
+          }                                             \
+      }                                                        \
+    else                                               \
+      substmt = cond;                                  \
+  } while (0)
+  
+/* T is a statement.  Add it to the statement-tree.  */
+
+void
+add_tree (t)
+     tree t;
+{
+  /* Add T to the statement-tree.  */
+  last_tree = TREE_CHAIN (last_tree) = t;
+
+  /* When we expand a statement-tree, we must know whether or not the
+     statements are full-expresions.  We record that fact here.  */
+  if (building_stmt_tree ())
+    STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p;
+}
+
+/* COND is the condition-expression for an if, while, etc.,
+   statement.  Convert it to a boolean value, if appropriate.  */
+
+static tree
+maybe_convert_cond (cond)
+     tree cond;
+{
+  /* Empty conditions remain empty.  */
+  if (!cond)
+    return NULL_TREE;
 
-#define RECHAIN_STMTS_FROM_CHAIN(stmt, substmt)        \
-  RECHAIN_STMTS (stmt, substmt, TREE_CHAIN (stmt))
+  /* Wait until we instantiate templates before doing conversion.  */
+  if (processing_template_decl)
+    return cond;
+
+  /* Do the conversion.  */
+  cond = convert_from_reference (cond);
+  return condition_conversion (cond);
+}
 
 /* Finish an expression-statement, whose EXPRESSION is as indicated.  */
 
@@ -113,6 +159,8 @@ begin_if_stmt ()
 {
   tree r;
 
+  do_pushlevel ();
+
   if (building_stmt_tree ())
     {
       r = build_min_nt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
@@ -121,8 +169,6 @@ begin_if_stmt ()
   else
     r = NULL_TREE;
 
-  do_pushlevel ();
-
   return r;
 }
 
@@ -134,17 +180,14 @@ finish_if_stmt_cond (cond, if_stmt)
      tree cond;
      tree if_stmt;
 {
+  cond = maybe_convert_cond (cond);
+
   if (building_stmt_tree ())
-    {
-      if (last_tree != if_stmt)
-       RECHAIN_STMTS_FROM_LAST (if_stmt, IF_COND (if_stmt));
-      else
-       IF_COND (if_stmt) = cond;
-    }
+    FINISH_COND (cond, if_stmt, IF_COND (if_stmt));
   else
     {
       emit_line_note (input_filename, lineno);
-      expand_start_cond (condition_conversion (cond), 0);
+      expand_start_cond (cond, 0);
     }
 }
 
@@ -157,8 +200,7 @@ finish_then_clause (if_stmt)
 {
   if (building_stmt_tree ())
     {
-      RECHAIN_STMTS_FROM_CHAIN (if_stmt, 
-                               THEN_CLAUSE (if_stmt));
+      RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
       last_tree = if_stmt;
       return if_stmt;
     }
@@ -183,7 +225,7 @@ finish_else_clause (if_stmt)
      tree if_stmt;
 {
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_CHAIN (if_stmt, ELSE_CLAUSE (if_stmt));
+    RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
 }
 
 /* Finsh an if-statement.  */
@@ -232,17 +274,14 @@ finish_while_stmt_cond (cond, while_stmt)
      tree cond;
      tree while_stmt;
 {
+  cond = maybe_convert_cond (cond);
+
   if (building_stmt_tree ())
-    {
-      if (last_tree != while_stmt)
-       RECHAIN_STMTS_FROM_LAST (while_stmt, WHILE_COND (while_stmt)); 
-      else
-       TREE_OPERAND (while_stmt, 0) = cond;
-    }
+    FINISH_COND (cond, while_stmt, WHILE_COND (while_stmt));
   else
     {
       emit_line_note (input_filename, lineno);
-      expand_exit_loop_if_false (0, condition_conversion (cond));
+      expand_exit_loop_if_false (0, cond);
     }
 
   /* If COND wasn't a declaration, clear out the
@@ -264,7 +303,7 @@ finish_while_stmt (while_stmt)
   do_poplevel ();
 
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_CHAIN (while_stmt, WHILE_BODY (while_stmt));
+    RECHAIN_STMTS (while_stmt, WHILE_BODY (while_stmt));
   else
     expand_end_loop ();
   finish_stmt ();
@@ -298,7 +337,7 @@ finish_do_body (do_stmt)
      tree do_stmt;
 {
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_CHAIN (do_stmt, DO_BODY (do_stmt));
+    RECHAIN_STMTS (do_stmt, DO_BODY (do_stmt));
   else
     expand_loop_continue_here ();
 }
@@ -311,12 +350,14 @@ finish_do_stmt (cond, do_stmt)
      tree cond;
      tree do_stmt;
 {
+  cond = maybe_convert_cond (cond);
+
   if (building_stmt_tree ())
     DO_COND (do_stmt) = cond;
   else
     {
       emit_line_note (input_filename, lineno);
-      expand_exit_loop_if_false (0, condition_conversion (cond));
+      expand_exit_loop_if_false (0, cond);
       expand_end_loop ();
     }
 
@@ -331,6 +372,33 @@ void
 finish_return_stmt (expr)
      tree expr;
 {
+  if (doing_semantic_analysis_p () && !processing_template_decl)
+    expr = check_return_expr (expr);
+
+  if (doing_semantic_analysis_p () && !processing_template_decl)
+    {
+      if (DECL_CONSTRUCTOR_P (current_function_decl) && ctor_label)
+       {
+         /* Even returns without a value in a constructor must return
+            `this'.  We accomplish this by sending all returns in a
+            constructor to the CTOR_LABEL; finish_function emits code to
+            return a value there.  When we finally generate the real
+            return statement, CTOR_LABEL is no longer set, and we fall
+            through into the normal return-processing code below.  */
+         finish_goto_stmt (ctor_label);
+         return;
+       }
+      else if (DECL_DESTRUCTOR_P (current_function_decl))
+       {
+         /* Similarly, all destructors must run destructors for
+            base-classes before returning.  So, all returns in a
+            destructor get sent to the DTOR_LABEL; finsh_function emits
+            code to return a value there.  */
+         finish_goto_stmt (dtor_label);
+         return;
+       }
+    }
+
   if (building_stmt_tree ())
     add_tree (build_min_nt (RETURN_STMT, expr));
   else
@@ -377,7 +445,7 @@ finish_for_init_stmt (for_stmt)
   if (building_stmt_tree ())
     {
       if (last_tree != for_stmt)
-       RECHAIN_STMTS_FROM_CHAIN (for_stmt, FOR_INIT_STMT (for_stmt));
+       RECHAIN_STMTS (for_stmt, FOR_INIT_STMT (for_stmt));
     }
   else
     {
@@ -397,18 +465,15 @@ finish_for_cond (cond, for_stmt)
      tree cond;
      tree for_stmt;
 {
+  cond = maybe_convert_cond (cond);
+
   if (building_stmt_tree ())
-    {
-      if (last_tree != for_stmt)
-       RECHAIN_STMTS_FROM_LAST (for_stmt, FOR_COND (for_stmt));
-      else
-       FOR_COND (for_stmt) = cond;
-    }
+    FINISH_COND (cond, for_stmt, FOR_COND (for_stmt));
   else
     {
       emit_line_note (input_filename, lineno);
       if (cond)
-       expand_exit_loop_if_false (0, condition_conversion (cond));
+       expand_exit_loop_if_false (0, cond);
     }
   
   /* If the cond wasn't a declaration, clear out the
@@ -450,7 +515,7 @@ finish_for_stmt (expr, for_stmt)
   do_poplevel ();
 
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_CHAIN (for_stmt, FOR_BODY (for_stmt));
+    RECHAIN_STMTS (for_stmt, FOR_BODY (for_stmt));
   else
     {
       emit_line_note (input_filename, lineno);
@@ -492,49 +557,51 @@ finish_continue_stmt ()
     cp_error ("continue statement not within a loop");   
 }
 
-/* Begin a switch-statement.  */
+/* Begin a switch-statement.  Returns a new SWITCH_STMT if
+   appropriate.  */
 
-void
+tree
 begin_switch_stmt ()
 {
+  tree r;
+
+  if (building_stmt_tree ())
+    {
+      r = build_min_nt (SWITCH_STMT, NULL_TREE, NULL_TREE);
+      add_tree (r);
+    }
+  else
+    r = NULL_TREE;
+
   do_pushlevel ();
+
+  return r;
 }
 
-/* Finish the cond of a switch-statement.  Returns a new
-   SWITCH_STMT if appropriate.  */ 
+/* Finish the cond of a switch-statement.  */
 
-tree
-finish_switch_cond (cond)
+void
+finish_switch_cond (cond, switch_stmt)
      tree cond;
+     tree switch_stmt;
 {
-  tree r;
-
   if (building_stmt_tree ())
-    {
-      r = build_min_nt (SWITCH_STMT, cond, NULL_TREE);
-      add_tree (r);
-    }
+    FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
   else if (cond != error_mark_node)
     {
       emit_line_note (input_filename, lineno);
       c_expand_start_case (cond);
-      r = NULL_TREE;
     }
   else
-    {
-      /* The code is in error, but we don't want expand_end_case to
-         crash. */
-      c_expand_start_case (boolean_false_node);
-      r = NULL_TREE;
-    }
+    /* The code is in error, but we don't want expand_end_case to
+       crash. */
+    c_expand_start_case (boolean_false_node);
 
   push_switch ();
 
   /* Don't let the tree nodes for COND be discarded by
      clear_momentary during the parsing of the next stmt.  */
   push_momentary ();
-
-  return r;
 }
 
 /* Finish the body of a switch-statement, which may be given by
@@ -546,7 +613,7 @@ finish_switch_stmt (cond, switch_stmt)
      tree switch_stmt;
 {
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_CHAIN (switch_stmt, SWITCH_BODY (switch_stmt));
+    RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt));
   else
     expand_end_case (cond);
   pop_momentary ();
@@ -564,7 +631,12 @@ finish_case_label (low_value, high_value)
 {
   if (building_stmt_tree ())
     {
+      /* Add a representation for the case label to the statement
+        tree.  */
       add_tree (build_min_nt (CASE_LABEL, low_value, high_value));
+      /* And warn about crossing initializations, etc.  */
+      if (!processing_template_decl)
+       define_case_label ();
       return;
     }
 
@@ -580,6 +652,11 @@ finish_goto_stmt (destination)
   if (TREE_CODE (destination) == IDENTIFIER_NODE)
     destination = lookup_label (destination);
 
+  /* We warn about unused labels with -Wunused.  That means we have to
+     mark the used labels as used.  */
+  if (TREE_CODE (destination) == LABEL_DECL)
+    TREE_USED (destination) = 1;
+    
   if (building_stmt_tree ())
     add_tree (build_min_nt (GOTO_STMT, destination));
   else
@@ -588,7 +665,7 @@ finish_goto_stmt (destination)
 
       if (TREE_CODE (destination) == LABEL_DECL)
        {
-         TREE_USED (destination) = 1;
+         label_rtx (destination);
          expand_goto (destination); 
        }
       else
@@ -626,6 +703,7 @@ begin_function_try_block ()
     {
       tree r = build_min_nt (TRY_BLOCK, NULL_TREE,
                             NULL_TREE);
+      FN_TRY_BLOCK_P (r) = 1;
       add_tree (r);
       return r;
     }
@@ -645,11 +723,22 @@ finish_try_block (try_block)
      tree try_block;
 {
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_LAST (try_block, TRY_STMTS (try_block));
+    RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
   else
     expand_start_all_catch ();  
 }
 
+/* Finish the body of a cleanup try-block, which may be given by
+   TRY_BLOCK.  */
+
+void
+finish_cleanup_try_block (try_block)
+     tree try_block;
+{
+  if (building_stmt_tree ())
+    RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
+}
+
 /* Finish an implicitly generated try-block, with a cleanup is given
    by CLEANUP.  */
 
@@ -674,13 +763,25 @@ finish_function_try_block (try_block)
      tree try_block; 
 {
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_LAST (try_block, TRY_STMTS (try_block));
+    {
+      if (TREE_CHAIN (try_block) 
+         && TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER)
+       {
+         /* Chain the compound statement after the CTOR_INITIALIZER.  */
+         TREE_CHAIN (TREE_CHAIN (try_block)) = last_tree;
+         /* And make the CTOR_INITIALIZER the body of the try-block.  */
+         RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
+       }
+      else
+       RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
+    }
   else
     {
       end_protect_partials ();
       expand_start_all_catch ();
-      in_function_try_handler = 1;
     }
+
+  in_function_try_handler = 1;
 }
 
 /* Finish a handler-sequence for a try-block, which may be given by
@@ -691,7 +792,7 @@ finish_handler_sequence (try_block)
      tree try_block;
 {
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block));
+    RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
   else
     expand_end_all_catch ();
 }
@@ -702,13 +803,12 @@ void
 finish_function_handler_sequence (try_block)
      tree try_block;
 {
+  in_function_try_handler = 0;
+
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block));
+    RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
   else
-    {
-      in_function_try_handler = 0;
-      expand_end_all_catch ();
-    }
+    expand_end_all_catch ();
 }
 
 /* Begin a handler.  Returns a HANDLER if appropriate.  */
@@ -732,26 +832,71 @@ begin_handler ()
 }
 
 /* Finish the handler-parameters for a handler, which may be given by
-   HANDLER.  */
+   HANDLER.  DECL is the declaration for the catch parameter, or NULL
+   if this is a `catch (...)' clause.  */
 
-void
-finish_handler_parms (handler)
+tree
+finish_handler_parms (decl, handler)
+     tree decl;
      tree handler;
 {
+  tree blocks = NULL_TREE;
+
+  if (processing_template_decl)
+    {
+      if (decl)
+       {
+         decl = pushdecl (decl);
+         decl = push_template_decl (decl);
+         add_decl_stmt (decl);
+         RECHAIN_STMTS (handler, HANDLER_PARMS (handler));
+       }
+    }
+  else if (building_stmt_tree ())
+    blocks = expand_start_catch_block (decl);
+
+  return blocks;
+}
+
+/* Note the beginning of a handler for TYPE.  This function is called
+   at the point to which control should be transferred when an
+   appropriately-typed exception is thrown.  */
+
+void
+begin_catch_block (type)
+     tree type;
+{
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_PARMS (handler));
+    add_tree (build (START_CATCH_STMT, type));
+  else
+    start_catch_handler (type);
 }
 
-/* Finish a handler, which may be given by HANDLER.  */
+/* Finish a handler, which may be given by HANDLER.  The BLOCKs are
+   the return value from the matching call to finish_handler_parms.  */
 
 void
-finish_handler (handler)
+finish_handler (blocks, handler)
+     tree blocks;
      tree handler;
 {
+  if (!processing_template_decl)
+    {
+      if (building_stmt_tree ())
+       expand_end_catch_block (blocks);
+
+      if (!building_stmt_tree ())
+       {
+         /* Fall to outside the try statement when done executing
+            handler and we fall off end of handler.  This is jump
+            Lresume in the documentation.  */
+         expand_goto (top_label_entry (&caught_return_label_stack));
+         end_catch_handler ();
+       }
+    }
+
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_BODY (handler));
-  else
-    expand_end_catch_block ();
+    RECHAIN_STMTS (handler, HANDLER_BODY (handler));
 
   do_poplevel ();
 }
@@ -787,6 +932,16 @@ begin_compound_stmt (has_no_scope)
        to accidentally keep a block *inside* the scopeless block.  */ 
     keep_next_level (0);
 
+  /* If this is the outermost block of the function, declare the
+     variables __FUNCTION__, __PRETTY_FUNCTION__, and so forth.  */
+  if (!current_function_name_declared 
+      && !processing_template_decl
+      && !has_no_scope)
+    {
+      declare_function_name ();
+      current_function_name_declared = 1;
+    }
+
   return r;
 }
 
@@ -809,10 +964,9 @@ finish_compound_stmt (has_no_scope, compound_stmt)
     r = NULL_TREE;
 
   if (building_stmt_tree ())
-    RECHAIN_STMTS_FROM_CHAIN (compound_stmt, 
-                             COMPOUND_BODY (compound_stmt));
+    RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt));
 
-  /* When we call finish_stmt we will lost LAST_EXPR_TYPE.  But, since
+  /* When we call finish_stmt we will lose LAST_EXPR_TYPE.  But, since
      the precise purpose of that variable is store the type of the
      last expression statement within the last compound statement, we
      preserve the value.  */
@@ -946,6 +1100,20 @@ finish_subobject (cleanup)
     add_partial_entry (cleanup);
 }
 
+/* When DECL goes out of scope, make sure that CLEANUP is executed.  */
+
+void 
+finish_decl_cleanup (decl, cleanup)
+     tree decl;
+     tree cleanup;
+{
+  if (building_stmt_tree ())
+    add_tree (build_min_nt (CLEANUP_STMT, decl, cleanup));
+  else if (!decl 
+          || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node))
+    expand_decl_cleanup (decl, cleanup);
+}
+
 /* Bind a name and initialization to the return value of
    the current function.  */
 
@@ -987,7 +1155,8 @@ finish_named_return_value (return_id, init)
     {
       /* Let `cp_finish_decl' know that this initializer is ok.  */
       DECL_INITIAL (decl) = init;
-      pushdecl (decl);
+      if (doing_semantic_analysis_p ())
+       pushdecl (decl);
 
       if (building_stmt_tree ())
        add_tree (build_min_nt (RETURN_INIT, return_id, init));
@@ -1006,26 +1175,74 @@ finish_named_return_value (return_id, init)
 void
 setup_vtbl_ptr ()
 {
-  if (base_init_expr == 0
-      && DECL_CONSTRUCTOR_P (current_function_decl))
+  my_friendly_assert (doing_semantic_analysis_p (), 19990919);
+
+  /* If we've already done this, there's no need to do it again.  */
+  if (vtbls_set_up_p)
+    return;
+
+  if (DECL_CONSTRUCTOR_P (current_function_decl))
     {
-      if (building_stmt_tree ())
+      if (processing_template_decl)
        add_tree (build_min_nt
                  (CTOR_INITIALIZER,
                   current_member_init_list, current_base_init_list));
       else
-       emit_base_init (current_class_type);
+       finish_expr_stmt (emit_base_init (current_class_type));
+    }
+  else if (DECL_DESTRUCTOR_P (current_function_decl)
+          && !processing_template_decl)
+    {
+      tree binfo = TYPE_BINFO (current_class_type);
+      tree if_stmt;
+      tree compound_stmt;
+
+      /* If the dtor is empty, and we know there is not possible way we
+        could use any vtable entries, before they are possibly set by
+        a base class dtor, we don't have to setup the vtables, as we
+        know that any base class dtoring will set up any vtables it
+        needs.  We avoid MI, because one base class dtor can do a
+        virtual dispatch to an overridden function that would need to
+        have a non-related vtable set up, we cannot avoid setting up
+        vtables in that case.  We could change this to see if there is
+        just one vtable.  */
+      if_stmt = begin_if_stmt ();
+
+      /* If it is not safe to avoid setting up the vtables, then
+        someone will change the condition to be boolean_true_node.  
+         (Actually, for now, we do not have code to set the condition
+        appropriate, so we just assume that we always need to
+        initialize the vtables.)  */
+      finish_if_stmt_cond (boolean_true_node, if_stmt);
+      current_vcalls_possible_p = &IF_COND (if_stmt);
+      compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+
+      /* Make all virtual function table pointers in non-virtual base
+        classes point to CURRENT_CLASS_TYPE's virtual function
+        tables.  */
+      expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr);
+
+      if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+       expand_indirect_vtbls_init (binfo, current_class_ref, 
+                                   current_class_ptr);
+
+      finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+      finish_then_clause (if_stmt);
+      finish_if_stmt ();
     }
 
   /* Always keep the BLOCK node associated with the outermost pair of
-     curley braces of a function.  These are needed for correct
+     curly braces of a function.  These are needed for correct
      operation of dwarfout.c.  */
   keep_next_level (1);
+
+  /* The virtual function tables are set up now.  */
+  vtbls_set_up_p = 1;
 }
 
 /* Begin a new scope.  */
 
-static void
+void
 do_pushlevel ()
 {
   if (!building_stmt_tree ())
@@ -1035,24 +1252,53 @@ do_pushlevel ()
     }
   push_momentary ();
   if (stmts_are_full_exprs_p)
-    pushlevel (0);
-  if (!building_stmt_tree () && stmts_are_full_exprs_p)
-    expand_start_bindings (0);
+    {
+      pushlevel (0);
+      if (!building_stmt_tree ()
+         && !current_function->x_whole_function_mode_p)
+       expand_start_bindings (0);
+      else if (building_stmt_tree () && !processing_template_decl)
+       {
+         tree ss = build_min_nt (SCOPE_STMT);
+         SCOPE_BEGIN_P (ss) = 1;
+         add_tree (ss);
+         current_scope_stmt_stack 
+           = tree_cons (NULL_TREE, ss, current_scope_stmt_stack);
+       }
+    }
 }
 
 /* Finish a scope.  */
 
-static tree
+tree
 do_poplevel ()
 {
-  tree t;
+  tree t = NULL_TREE;
 
-  if (!building_stmt_tree () && stmts_are_full_exprs_p)
-    expand_end_bindings (getdecls (), kept_level_p (), 0);
   if (stmts_are_full_exprs_p)
-    t = poplevel (kept_level_p (), 1, 0);
-  else
-    t = NULL_TREE;
+    {
+      if (!building_stmt_tree ()
+         && !current_function->x_whole_function_mode_p)
+       expand_end_bindings (getdecls (), kept_level_p (), 0);
+      else if (building_stmt_tree () && !processing_template_decl)
+       {
+         tree ss = build_min_nt (SCOPE_STMT);
+         SCOPE_NULLIFIED_P (ss) = !kept_level_p ();
+         SCOPE_NULLIFIED_P (TREE_VALUE (current_scope_stmt_stack))
+           = SCOPE_NULLIFIED_P (ss);
+         add_tree (ss);
+         current_scope_stmt_stack = TREE_CHAIN (current_scope_stmt_stack);
+
+         /* When not in function-at-a-time mode, expand_end_bindings
+            will warn about unused variables.  But, in
+            function-at-a-time mode expand_end_bindings is not passed
+            the list of variables in the current scope, and therefore
+            no warning is emitted.  So, we explicitly warn here.  */
+         warn_about_unused_variables (getdecls ());
+       }
+
+      t = poplevel (kept_level_p (), 1, 0);
+    }
   pop_momentary ();
   return t;
 }
@@ -1090,16 +1336,15 @@ begin_stmt_expr ()
    statement-expression.  */
 
 tree 
-finish_stmt_expr (rtl_expr, expr)
+finish_stmt_expr (rtl_expr)
      tree rtl_expr;
-     tree expr;
 {
   tree result;
 
   if (!building_stmt_tree ())
     {
       rtl_expr = expand_end_stmt_expr (rtl_expr);
-      /* The statements have side effects, so the group does.  */
+      /* The statements have side effects, so the group does too.  */
       TREE_SIDE_EFFECTS (rtl_expr) = 1;
     }
 
@@ -1117,21 +1362,9 @@ finish_stmt_expr (rtl_expr, expr)
       last_tree = rtl_expr;
       TREE_CHAIN (last_tree) = NULL_TREE;
     }
-  else if (expr && TREE_CODE (expr) == BLOCK)
-    {
-      result = build (BIND_EXPR, TREE_TYPE (rtl_expr),
-                     NULL_TREE, rtl_expr, expr);
-      delete_block (expr);
-    }
-  else
+  else 
     result = rtl_expr;
 
-  if (expr && TREE_CODE (expr) == BLOCK)
-    /* Remove the block from the tree at this point.  It gets put back
-       at the proper place when the STMT_EXPR or BIND_EXPR is
-       expanded.  */
-    delete_block (expr);
-
   return result;
 }
 
@@ -1440,8 +1673,7 @@ finish_translation_unit ()
 {
   /* In case there were missing closebraces,
      get us back to the global binding level.  */
-  while (! toplevel_bindings_p ())
-    poplevel (0, 0, 0);
+  pop_everything ();
   while (current_namespace != global_namespace)
     pop_namespace ();
   finish_file ();
@@ -1960,220 +2192,283 @@ void
 finish_stmt_tree (fn)
      tree fn;
 {
-  DECL_SAVED_TREE (fn) = TREE_CHAIN (DECL_SAVED_TREE (fn));
+  tree stmt;
+  
+  /* Remove the fake extra statement added in begin_stmt_tree.  */
+  stmt = TREE_CHAIN (DECL_SAVED_TREE (fn));
+  DECL_SAVED_TREE (fn) = stmt;
+
+  /* The line-number recorded in the outermost statement in a function
+     is the line number of the end of the function.  */
+  STMT_LINENO (stmt) = lineno;
+  STMT_LINENO_FOR_FN_P (stmt) = 1;
 }
 
-/* Generate RTL for the chain of statements T.  */
+/* We're about to expand T, a statement.  Set up appropriate context
+   for the substitution.  */
 
-static void 
-expand_stmts (t)
+void
+prep_stmt (t)
      tree t;
 {
-  while (t)
+  if (!STMT_LINENO_FOR_FN_P (t))
+    lineno = STMT_LINENO (t);
+  stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
+}
+
+/* Some statements, like for-statements or if-statements, require a
+   condition.  This condition can be a declaration.  If T is such a
+   declaration it is processed, and an expression appropriate to use
+   as the condition is returned.  Otherwise, T itself is returned.  */
+
+static tree
+expand_cond (t)
+     tree t;
+{
+  if (t && TREE_CODE (t) == TREE_LIST)
     {
-      expand_stmt (t);
-      t = TREE_CHAIN (t);
+      expand_stmt (TREE_PURPOSE (t));
+      return TREE_VALUE (t);
     }
+  else 
+    return t;
 }
 
-/* Generate RTL for the statement T, and its substatements.  */
+/* Generate RTL for the statement T, and its substatements, and any
+   other statements at its nesting level.  */
 
 tree
 expand_stmt (t)
      tree t;
 {
-  if (t == NULL_TREE || t == error_mark_node)
-    return NULL_TREE;
+  tree rval = NULL_TREE;
 
-  switch (TREE_CODE (t))
+  while (t && t != error_mark_node)
     {
-    case RETURN_STMT:
-      lineno = STMT_LINENO (t);
-      finish_return_stmt (RETURN_EXPR (t));
-      break;
+      int saved_stmts_are_full_exprs_p;
 
-    case EXPR_STMT:
-      lineno = STMT_LINENO (t);
-      finish_expr_stmt (EXPR_STMT_EXPR (t));
-      break;
+      /* Assume we'll have nothing to return.  */
+      rval = NULL_TREE;
 
-    case DECL_STMT:
-      {
-       tree decl;
-       int i = suspend_momentary ();
-
-       lineno = STMT_LINENO (t);
-       emit_line_note (input_filename, lineno);
-       decl = DECL_STMT_DECL (t);
-       if (TREE_CODE (decl) == LABEL_DECL)
-         finish_label_decl (DECL_NAME (decl));
-       else
+      /* Set up context appropriately for handling this statement.  */
+      saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p;
+      prep_stmt (t);
+
+      switch (TREE_CODE (t))
+       {
+       case RETURN_STMT:
+         finish_return_stmt (RETURN_EXPR (t));
+         break;
+
+       case EXPR_STMT:
+         finish_expr_stmt (EXPR_STMT_EXPR (t));
+         break;
+
+       case DECL_STMT:
          {
-           /* We need to clear DECL_CONTEXT so that maybe_push_decl
-              will push it into the current scope.  */
-           if (DECL_CONTEXT (decl) == current_function_decl)
-             DECL_CONTEXT (decl) = NULL_TREE;
-           /* If we marked this variable as dead when we processed it
-              before, we must undo that now.  The variable has been
-              resuscitated.  */
-           if (TREE_CODE (decl) == VAR_DECL)
-             DECL_DEAD_FOR_LOCAL (decl) = 0;
-           maybe_push_decl (decl);
-           if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl))
+           tree decl;
+           int i = suspend_momentary ();
+
+           emit_line_note (input_filename, lineno);
+           decl = DECL_STMT_DECL (t);
+           /* If this is a declaration for an automatic local
+              variable, initialize it.  Note that we might also see a
+              declaration for a namespace-scope object (declared with
+              `extern').  We don't have to handle the initialization
+              of those objects here; they can only be declarations,
+              rather than definitions.  */
+           if (TREE_CODE (decl) == VAR_DECL 
+               && !TREE_STATIC (decl)
+               && !DECL_EXTERNAL (decl))
              {
-               maybe_inject_for_scope_var (decl);
-               initialize_local_var (decl, DECL_INITIAL (decl), 0);
+               /* Let the back-end know about this variable.  */
+               if (!ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
+                 emit_local_var (decl);
+               else
+                 expand_anon_union_decl (decl, NULL_TREE, 
+                                         DECL_ANON_UNION_ELEMS (decl));
              }
+           else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
+             rest_of_decl_compilation 
+               (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+                /*top_level=*/0, /*at_end=*/0);
+
+           resume_momentary (i);
          }
-       resume_momentary (i);
-      }
-      break;
+         break;
 
-    case FOR_STMT:
-      {
-       tree tmp;
-
-       lineno = STMT_LINENO (t);
-       begin_for_stmt ();
-       for (tmp = FOR_INIT_STMT (t); tmp; tmp = TREE_CHAIN (tmp))
-         expand_stmt (tmp);
-       finish_for_init_stmt (NULL_TREE);
-       finish_for_cond (FOR_COND (t), NULL_TREE);
-       tmp = FOR_EXPR (t);
-       finish_for_expr (tmp, NULL_TREE);
-       expand_stmt (FOR_BODY (t));
-       finish_for_stmt (tmp, NULL_TREE);
-      }
-      break;
+       case CLEANUP_STMT:
+         finish_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
+         break;
 
-    case WHILE_STMT:
-      {
-       lineno = STMT_LINENO (t);
-       begin_while_stmt ();
-       finish_while_stmt_cond (WHILE_COND (t), NULL_TREE);
-       expand_stmt (WHILE_BODY (t));
-       finish_while_stmt (NULL_TREE);
-      }
-      break;
+       case START_CATCH_STMT:
+         begin_catch_block (TREE_TYPE (t));
+         break;
 
-    case DO_STMT:
-      {
-       lineno = STMT_LINENO (t);
-       begin_do_stmt ();
-       expand_stmt (DO_BODY (t));
-       finish_do_body (NULL_TREE);
-       finish_do_stmt (DO_COND (t), NULL_TREE);
-      }
-      break;
+       case FOR_STMT:
+         {
+           tree tmp;
+
+           begin_for_stmt ();
+           expand_stmt (FOR_INIT_STMT (t));
+           finish_for_init_stmt (NULL_TREE);
+           finish_for_cond (expand_cond (FOR_COND (t)), NULL_TREE);
+           tmp = FOR_EXPR (t);
+           finish_for_expr (tmp, NULL_TREE);
+           expand_stmt (FOR_BODY (t));
+           finish_for_stmt (tmp, NULL_TREE);
+         }
+         break;
 
-    case IF_STMT:
-      lineno = STMT_LINENO (t);
-      begin_if_stmt ();
-      finish_if_stmt_cond (IF_COND (t), NULL_TREE);
-      if (THEN_CLAUSE (t))
-       {
-         expand_stmt (THEN_CLAUSE (t));
-         finish_then_clause (NULL_TREE);
-       }
-      if (ELSE_CLAUSE (t))
-       {
-         begin_else_clause ();
-         expand_stmt (ELSE_CLAUSE (t));
-         finish_else_clause (NULL_TREE);
-       }
-      finish_if_stmt ();
-      break;
-
-    case COMPOUND_STMT:
-      lineno = STMT_LINENO (t);
-      begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
-      expand_stmts (COMPOUND_BODY (t));
-      return finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t), 
-                                  NULL_TREE);
-
-    case BREAK_STMT:
-      lineno = STMT_LINENO (t);
-      finish_break_stmt ();
-      break;
-
-    case CONTINUE_STMT:
-      lineno = STMT_LINENO (t);
-      finish_continue_stmt ();
-      break;
-
-    case SWITCH_STMT:
-      lineno = STMT_LINENO (t);
-      begin_switch_stmt ();
-      finish_switch_cond (SWITCH_COND (t));
-      if (TREE_OPERAND (t, 1))
-       expand_stmt (SWITCH_BODY (t));
-      finish_switch_stmt (SWITCH_COND (t), NULL_TREE);
-      break;
-
-    case CASE_LABEL:
-      finish_case_label (CASE_LOW (t), CASE_HIGH (t));
-      break;
-
-    case LABEL_STMT:
-      lineno = STMT_LINENO (t);
-      finish_label_stmt (DECL_NAME (LABEL_STMT_LABEL (t)));
-      break;
-
-    case GOTO_STMT:
-      lineno = STMT_LINENO (t);
-      if (TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL)
-       finish_goto_stmt (DECL_NAME (GOTO_DESTINATION (t)));
-      else
-       finish_goto_stmt (GOTO_DESTINATION (t));
-      break;
-
-    case ASM_STMT:
-      lineno = STMT_LINENO (t);
-      finish_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), ASM_OUTPUTS
-                      (t), ASM_INPUTS (t), ASM_CLOBBERS (t));
-      break;
-
-    case TRY_BLOCK:
-      lineno = STMT_LINENO (t);
-      if (CLEANUP_P (t))
-       {
-         expand_eh_region_start ();
-         expand_stmt (TRY_STMTS (t));
-         finish_cleanup (TRY_HANDLERS (t), NULL_TREE);
-       }
-      else
-       {
-         begin_try_block ();
-         expand_stmt (TRY_STMTS (t));
-         finish_try_block (NULL_TREE);
-         expand_stmts (TRY_HANDLERS (t));
-         finish_handler_sequence (NULL_TREE);
-       }
-      break;
+       case WHILE_STMT:
+         {
+           begin_while_stmt ();
+           finish_while_stmt_cond (expand_cond (WHILE_COND (t)), NULL_TREE);
+           expand_stmt (WHILE_BODY (t));
+           finish_while_stmt (NULL_TREE);
+         }
+         break;
 
-    case HANDLER:
-      lineno = STMT_LINENO (t);
-      begin_handler ();
-      if (HANDLER_PARMS (t))
-       expand_start_catch_block (DECL_STMT_DECL (HANDLER_PARMS (t)));
-      else
-       expand_start_catch_block (NULL_TREE);
-      finish_handler_parms (NULL_TREE);
-      expand_stmt (HANDLER_BODY (t));
-      finish_handler (NULL_TREE);
-      break;
+       case DO_STMT:
+         {
+           begin_do_stmt ();
+           expand_stmt (DO_BODY (t));
+           finish_do_body (NULL_TREE);
+           finish_do_stmt (DO_COND (t), NULL_TREE);
+         }
+         break;
+
+       case IF_STMT:
+         begin_if_stmt ();
+         finish_if_stmt_cond (expand_cond (IF_COND (t)), NULL_TREE);
+         if (THEN_CLAUSE (t))
+           {
+             expand_stmt (THEN_CLAUSE (t));
+             finish_then_clause (NULL_TREE);
+           }
+         if (ELSE_CLAUSE (t))
+           {
+             begin_else_clause ();
+             expand_stmt (ELSE_CLAUSE (t));
+             finish_else_clause (NULL_TREE);
+           }
+         finish_if_stmt ();
+         break;
+
+       case COMPOUND_STMT:
+         begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
+         expand_stmt (COMPOUND_BODY (t));
+         rval = finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t), 
+                                      NULL_TREE);
+         break;
+
+       case BREAK_STMT:
+         finish_break_stmt ();
+         break;
+
+       case CONTINUE_STMT:
+         finish_continue_stmt ();
+         break;
+
+       case SWITCH_STMT:
+         {
+           tree cond;
+
+           begin_switch_stmt ();
+           cond = expand_cond (SWITCH_COND (t));
+           finish_switch_cond (cond, NULL_TREE);
+           expand_stmt (SWITCH_BODY (t));
+           finish_switch_stmt (cond, NULL_TREE);
+         }
+         break;
+
+       case CASE_LABEL:
+         finish_case_label (CASE_LOW (t), CASE_HIGH (t));
+         break;
+
+       case LABEL_STMT:
+         expand_label (LABEL_STMT_LABEL (t));
+         break;
+
+       case GOTO_STMT:
+         finish_goto_stmt (GOTO_DESTINATION (t));
+         break;
+
+       case ASM_STMT:
+         finish_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), ASM_OUTPUTS
+                          (t), ASM_INPUTS (t), ASM_CLOBBERS (t));
+         break;
 
-    case SUBOBJECT:
-      lineno = STMT_LINENO (t);
-      finish_subobject (SUBOBJECT_CLEANUP (t));
-      break;
+       case TRY_BLOCK:
+         if (CLEANUP_P (t))
+           {
+             expand_eh_region_start ();
+             expand_stmt (TRY_STMTS (t));
+             finish_cleanup_try_block (NULL_TREE);
+             finish_cleanup (TRY_HANDLERS (t), NULL_TREE);
+           }
+         else
+           {
+             if (FN_TRY_BLOCK_P (t))
+               begin_function_try_block ();
+             else
+               begin_try_block ();
+
+             expand_stmt (TRY_STMTS (t));
+
+             if (FN_TRY_BLOCK_P (t))
+               {
+                 finish_function_try_block (NULL_TREE);
+                 expand_stmt (TRY_HANDLERS (t));
+                 finish_function_handler_sequence (NULL_TREE);
+               }
+             else
+               {
+                 finish_try_block (NULL_TREE);
+                 expand_stmt (TRY_HANDLERS (t));
+                 finish_handler_sequence (NULL_TREE);
+               }
+           }
+         break;
+
+       case HANDLER:
+         begin_handler ();
+         expand_stmt (HANDLER_BODY (t));
+         finish_handler (NULL_TREE, NULL_TREE);
+         break;
+
+       case SUBOBJECT:
+         finish_subobject (SUBOBJECT_CLEANUP (t));
+         break;
+
+       case SCOPE_STMT:
+         if (SCOPE_BEGIN_P (t))
+           expand_start_bindings (2 * SCOPE_NULLIFIED_P (t));
+         else if (SCOPE_END_P (t))
+           expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0);
+         break;
+
+       case RETURN_INIT:
+         /* Clear this out so that finish_named_return_value can set it
+            again.  */
+         DECL_NAME (DECL_RESULT (current_function_decl)) = NULL_TREE;
+         finish_named_return_value (TREE_OPERAND (t, 0), 
+                                    TREE_OPERAND (t, 1));
+         break;
+
+       default:
+         my_friendly_abort (19990810);
+         break;
+       }
+
+      /* Restore saved state.  */
+      stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
 
-    default:
-      my_friendly_abort (19990810);
-      break;
+      /* Go on to the next statement in this scope.  */
+      t = TREE_CHAIN (t);
     }
 
-  return NULL_TREE;
+  return rval;
 }
 
 /* Generate RTL for FN.  */
@@ -2182,58 +2477,56 @@ void
 expand_body (fn)
      tree fn;
 {
-  tree t;
-  tree try_block;
-
-  start_function (NULL_TREE, fn, NULL_TREE, SF_PRE_PARSED | SF_EXPAND);
-  store_parm_decls ();
+  int saved_lineno;
+  char *saved_input_filename;
+
+  /* When the parser calls us after finishing the body of a template
+     function, we don't really want to expand the body.  When we're
+     processing an in-class definition of an inline function,
+     PROCESSING_TEMPLATE_DECL will no longer be set here, so we have
+     to look at the function itself.  */
+  if (processing_template_decl
+      || (DECL_LANG_SPECIFIC (fn) 
+         && DECL_TEMPLATE_INFO (fn)
+         && uses_template_parms (DECL_TI_ARGS (fn))))
+    return;
 
-  /* There are a few things that we do not handle recursively.  For
-     example, a function try-block is handled differently from an
-     ordinary try-block, so we must handle it here.  */
-  t = DECL_SAVED_TREE (fn);
-  try_block = NULL_TREE;
-  if (t && TREE_CODE (t) == TRY_BLOCK)
-    {
-      try_block = t;
-      begin_function_try_block ();
-      t = TRY_STMTS (try_block);
-    }
+  /* There's no reason to do any of the work here if we're only doing
+     semantic analysis; this code just generates RTL.  */
+  if (flag_syntax_only)
+    return;
 
-  if (t && TREE_CODE (t) == RETURN_INIT)
-    {
-      /* Clear this out so that finish_named_return_value can set it
-        again.  */
-      DECL_NAME (DECL_RESULT (fn)) = NULL_TREE;
-      finish_named_return_value (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1));
-      t = TREE_CHAIN (t);
-    }
+  /* Save the current file name and line number.  When we expand the
+     body of the function, we'll set LINENO and INPUT_FILENAME so that
+     error-mesages come out in the right places.  */
+  saved_lineno = lineno;
+  saved_input_filename = input_filename;
+  lineno = DECL_SOURCE_LINE (fn);
+  input_filename = DECL_SOURCE_FILE (fn);
 
-  if (t && TREE_CODE (t) == CTOR_INITIALIZER)
-    {
-      current_member_init_list = TREE_OPERAND (t, 0);
-      current_base_init_list = TREE_OPERAND (t, 1);
-      t = TREE_CHAIN (t);
-    }
+  start_function (NULL_TREE, fn, NULL_TREE, SF_PRE_PARSED | SF_EXPAND);
+  store_parm_decls ();
 
-  /* If this is a constructor, we need to initialize our members and
-     base-classes.  */
-  setup_vtbl_ptr ();
+  /* We don't need to redeclare __FUNCTION__, __PRETTY_FUNCTION__, or
+     any of the other magic variables we set up when starting a
+     function body.  */
+  current_function_name_declared = 1;
 
   /* Expand the body.  */
-  expand_stmt (t);
+  expand_stmt (DECL_SAVED_TREE (fn));
 
-  /* If there was a function try-block, expand the handlers.  */
-  if (try_block)
-    {
-      finish_function_try_block (NULL_TREE);
-      {
-       tree handler = TRY_HANDLERS (try_block);
-       for (; handler; handler = TREE_CHAIN (handler))
-         expand_stmt (handler);
-      }
-      finish_function_handler_sequence (NULL_TREE);
-    }
+  /* Statements should always be full-expressions at the outermost set
+     of curly braces for a function.  */
+  my_friendly_assert (stmts_are_full_exprs_p, 19990831);
+
+  /* The outermost statement for a function contains the line number
+     recorded when we finished processing the function.  */
+  lineno = STMT_LINENO (DECL_SAVED_TREE (fn));
 
+  /* Generate code for the function.  */
   finish_function (lineno, 0);
+
+  /* And restore the current source position.  */
+  lineno = saved_lineno;
+  input_filename = saved_input_filename;
 }