cp-tree.h (FN_TRY_BLOCK_P): New macro.
authorMark Mitchell <mark@codesourcery.com>
Fri, 10 Sep 1999 09:21:37 +0000 (09:21 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 10 Sep 1999 09:21:37 +0000 (09:21 +0000)
* cp-tree.h (FN_TRY_BLOCK_P): New macro.
* init.c (perform_member_init): Remove obstack machinations.
(expand_cleanup_for_base): Likewise.
(finish_init_stmts): Mark the statement-expression as used.
* method.c (emit_thunk): Use tree-generating functions, not
RTL.
(do_build_copy_constructor): Likewise.
(do_build_assign_ref): Likewise.
(synthesize_method): Likewise.  Keep track of line numbers.
* pt.c (tsubst_expr): Handle various kinds of try blocks.
* semantics.c (expand_stmts): Remove.
(begin_function_try_block): Set FN_TRY_BLOCK_P.
(finish_function_try_block): Be careful rechaining
function try blocks.
(expand_stmt): Loop through all the statements at a given level.
(exapnd_body): Be careful with line-numbers here too.  Prepare for
being called directly from the parser.

From-SVN: r29263

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/init.c
gcc/cp/method.c
gcc/cp/pt.c
gcc/cp/semantics.c

index b9737eca0b48d40ecd10ab4a52ddc29c6dbb646b..8996c44b51235ca0574aebe830f05ea9a9f5fd13 100644 (file)
@@ -1,5 +1,23 @@
 1999-09-10  Mark Mitchell  <mark@codesourcery.com>
 
+       * cp-tree.h (FN_TRY_BLOCK_P): New macro.
+       * init.c (perform_member_init): Remove obstack machinations.
+       (expand_cleanup_for_base): Likewise.
+       (finish_init_stmts): Mark the statement-expression as used.
+       * method.c (emit_thunk): Use tree-generating functions, not
+       RTL.
+       (do_build_copy_constructor): Likewise.
+       (do_build_assign_ref): Likewise.
+       (synthesize_method): Likewise.  Keep track of line numbers.
+       * pt.c (tsubst_expr): Handle various kinds of try blocks.
+       * semantics.c (expand_stmts): Remove.
+       (begin_function_try_block): Set FN_TRY_BLOCK_P.
+       (finish_function_try_block): Be careful rechaining 
+       function try blocks.
+       (expand_stmt): Loop through all the statements at a given level.
+       (exapnd_body): Be careful with line-numbers here too.  Prepare for
+       being called directly from the parser.
+
        * cp-tree.h (finish_function): Adjust prototype.
        * decl.c (finish_function): Return the function compiled.
        * pt.c (instantiate_decl): Don't play games with obstacks.
index dd88d1a727ed36235c0825fa970c49fee7a29fe3..9be527edb5a45d48c1e03813df90821f66fb71ad 100644 (file)
@@ -63,6 +63,7 @@ Boston, MA 02111-1307, USA.  */
       BINFO_PUSHDECLS_MARKED.
       (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
       ICS_BAD_FLAG (in _CONV)
+      FN_TRY_BLOCK_P (in TRY_BLOCK)
    4: BINFO_NEW_VTABLE_MARKED.
       TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
           or FIELD_DECL).
@@ -2429,6 +2430,8 @@ extern int flag_new_for_scope;
 #define TRY_STMTS(NODE)         TREE_OPERAND (NODE, 0)
 #define TRY_HANDLERS(NODE)      TREE_OPERAND (NODE, 1)
 #define CLEANUP_P(NODE)         TREE_LANG_FLAG_0 (NODE)
+/* Nonzero if this try block is a function try block.  */
+#define FN_TRY_BLOCK_P(NODE)    TREE_LANG_FLAG_3 (NODE)
 #define HANDLER_PARMS(NODE)     TREE_OPERAND (NODE, 0)
 #define HANDLER_BODY(NODE)      TREE_OPERAND (NODE, 1)
 #define COMPOUND_BODY(NODE)     TREE_OPERAND (NODE, 0)
index fd48f198cab385aa6ad451d1644529527c028d0e..0d9af2c6bd5ab3f86939d68cda37de783d70d371 100644 (file)
@@ -225,10 +225,6 @@ perform_member_init (member, name, init, explicit)
     {
       tree expr;
 
-      /* All cleanups must be on the function_obstack.  */
-      push_obstacks_nochange ();
-      resume_temporary_allocation ();
-
       expr = build_component_ref (current_class_ref, name, NULL_TREE,
                                  explicit);
       expr = build_delete (type, expr, integer_zero_node,
@@ -236,8 +232,6 @@ perform_member_init (member, name, init, explicit)
 
       if (expr != error_mark_node)
        finish_subobject (expr);
-
-      pop_obstacks ();
     }
 }
 
@@ -699,10 +693,6 @@ expand_cleanup_for_base (binfo, flag)
   if (!TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo)))
     return;
 
-  /* All cleanups must be on the function_obstack.  */
-  push_obstacks_nochange ();
-  resume_temporary_allocation ();
-
   /* Call the destructor.  */
   expr = (build_scoped_method_call
          (current_class_ref, binfo, dtor_identifier,
@@ -712,7 +702,6 @@ expand_cleanup_for_base (binfo, flag)
                        truthvalue_conversion (flag),
                        expr, integer_zero_node));
 
-  pop_obstacks ();
   finish_subobject (expr);
 }
 
@@ -1009,9 +998,17 @@ finish_init_stmts (stmt_expr, compound_stmt)
      tree compound_stmt;
 {
   pop_momentary ();
-  return finish_stmt_expr (stmt_expr,
-                          finish_compound_stmt (/*has_no_scope=*/1, 
-                                                compound_stmt));
+  stmt_expr 
+    = finish_stmt_expr (stmt_expr,
+                       finish_compound_stmt (/*has_no_scope=*/1, 
+                                             compound_stmt));
+
+  /* To avoid spurious warnings about unused values, we set 
+     TREE_USED.  */
+  if (stmt_expr)
+    TREE_USED (stmt_expr) = 1;
+
+  return stmt_expr;
 }
 
 /* This is like `expand_member_init', only it stores one aggregate
index e91eefabba2df3ed5dd3e5fdcf763b5746c1e2f4..5e9c578bf8dfb5846dc339ca5a150693206e582c 100644 (file)
@@ -2147,7 +2147,7 @@ emit_thunk (thunk_fndecl)
       t = tree_cons (NULL_TREE, a, t);
     t = nreverse (t);
     t = build_call (function, TREE_TYPE (TREE_TYPE (function)), t);
-    c_expand_return (t);
+    finish_return_stmt (t);
 
     finish_function (lineno, 0);
 
@@ -2172,7 +2172,6 @@ do_build_copy_constructor (fndecl)
      tree fndecl;
 {
   tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
-  tree compound_stmt;
   tree t;
 
   if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
@@ -2249,9 +2248,6 @@ do_build_copy_constructor (fndecl)
       current_base_init_list = nreverse (current_base_init_list);
       setup_vtbl_ptr ();
     }
-
-  compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
-  finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
 }
 
 static void
@@ -2290,7 +2286,7 @@ do_build_assign_ref (fndecl)
          p = convert_from_reference (p);
          p = build_member_call (basetype, ansi_opname [MODIFY_EXPR],
                                 build_expr_list (NULL_TREE, p));
-         expand_expr_stmt (p);
+         finish_expr_stmt (p);
        }
       for (; fields; fields = TREE_CHAIN (fields))
        {
@@ -2342,10 +2338,10 @@ do_build_assign_ref (fndecl)
          comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field);
          init = build (COMPONENT_REF, TREE_TYPE (field), init, field);
 
-         expand_expr_stmt (build_modify_expr (comp, NOP_EXPR, init));
+         finish_expr_stmt (build_modify_expr (comp, NOP_EXPR, init));
        }
     }
-  c_expand_return (current_class_ref);
+  finish_return_stmt (current_class_ref);
   finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
 }
 
@@ -2355,6 +2351,7 @@ synthesize_method (fndecl)
 {
   int nested = (current_function_decl != NULL_TREE);
   tree context = hack_decl_function_context (fndecl);
+  int need_body = 1;
 
   if (at_eof)
     import_export_decl (fndecl);
@@ -2364,13 +2361,25 @@ synthesize_method (fndecl)
   else if (nested)
     push_function_context_to (context);
 
+  /* Put the function definition at the position where it is needed,
+     rather than within the body of the class.  That way, an error
+     during the generation of the implicit body points at the place
+     where the attempt to generate the function occurs, giving the
+     user a hint as to why we are attempting to generate the
+     function. */
+  DECL_SOURCE_LINE (fndecl) = lineno;
+  DECL_SOURCE_FILE (fndecl) = input_filename;
+
   interface_unknown = 1;
   start_function (NULL_TREE, fndecl, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED);
   store_parm_decls ();
   clear_last_expr ();
 
   if (DECL_NAME (fndecl) == ansi_opname[MODIFY_EXPR])
-    do_build_assign_ref (fndecl);
+    {
+      do_build_assign_ref (fndecl);
+      need_body = 0;
+    }
   else if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
     ;
   else
@@ -2381,13 +2390,16 @@ synthesize_method (fndecl)
       if (arg_chain != void_list_node)
        do_build_copy_constructor (fndecl);
       else if (TYPE_NEEDS_CONSTRUCTING (current_class_type))
-       {
-         tree compound_stmt;
+       setup_vtbl_ptr ();
+    }
 
-         setup_vtbl_ptr ();
-         compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
-         finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
-       }
+  /* If we haven't yet generated the body of the function, just
+     generate an empty compound statement.  */
+  if (need_body)
+    {
+      tree compound_stmt;
+      compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+      finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
     }
 
   finish_function (lineno, 0);
index 8af26e5befddbc4168b4f6475fec4f3e2f710668..a21431796837bc5447c3c4eb45d4f65f6f7db2aa 100644 (file)
@@ -7443,16 +7443,32 @@ tsubst_expr (t, args, complain, in_decl)
 
     case TRY_BLOCK:
       prep_stmt (t);
-      stmt = begin_try_block ();
-      tsubst_expr (TRY_STMTS (t), args, complain, in_decl);
-      finish_try_block (stmt);
       if (CLEANUP_P (t))
-       finish_cleanup (tsubst_expr (TRY_HANDLERS (t), args,
-                                    complain, in_decl),
-                       stmt);
+       {
+         begin_try_block ();
+         tsubst_expr (TRY_STMTS (t), args, complain, in_decl);
+         finish_cleanup_try_block (stmt);
+         finish_cleanup (tsubst_expr (TRY_HANDLERS (t), args,
+                                      complain, in_decl),
+                         stmt);
+       }
       else
        {
-         tree handler = TRY_HANDLERS (t);
+         tree handler;
+
+         if (FN_TRY_BLOCK_P (t))
+           stmt = begin_function_try_block ();
+         else
+           stmt = begin_try_block ();
+
+         tsubst_expr (TRY_STMTS (t), args, complain, in_decl);
+
+         if (FN_TRY_BLOCK_P (t))
+           finish_function_try_block (stmt);
+         else
+           finish_try_block (stmt);
+
+         handler = TRY_HANDLERS (t);
          for (; handler; handler = TREE_CHAIN (handler))
            tsubst_expr (handler, args, complain, in_decl);
          finish_handler_sequence (stmt);
index 771f7c8a830fb160d3286010c6aef026568c5395..d2f6969bc7b701ae03c2eb5fbcde68380f152b22 100644 (file)
@@ -41,7 +41,6 @@
    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 void finish_expr_stmt_real PROTO((tree, int));
@@ -650,6 +649,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;
     }
@@ -674,6 +674,14 @@ finish_try_block (try_block)
     expand_start_all_catch ();  
 }
 
+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.  */
 
@@ -698,7 +706,18 @@ finish_function_try_block (try_block)
      tree try_block; 
 {
   if (building_stmt_tree ())
-    RECHAIN_STMTS (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 ();
@@ -2025,219 +2044,225 @@ expand_cond (t)
     return t;
 }
 
-/* Generate RTL for the chain of statements T.  */
-
-static void 
-expand_stmts (t)
-     tree t;
-{
-  while (t)
-    {
-      expand_stmt (t);
-      t = TREE_CHAIN (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;
 {
-  int saved_stmts_are_full_exprs_p;
   tree rval;
 
-  if (t == NULL_TREE || t == error_mark_node)
-    return NULL_TREE;
+  while (t && t != error_mark_node)
+    {
+      int saved_stmts_are_full_exprs_p;
 
-  /* Assume we'll have nothing to return.  */
-  rval = NULL_TREE;
+      /* Assume we'll have nothing to return.  */
+      rval = NULL_TREE;
 
-  /* Set up context appropriately for handling this statement.  */
-  saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p;
-  prep_stmt (t);
+      /* 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;
+      switch (TREE_CODE (t))
+       {
+       case RETURN_STMT:
+         finish_return_stmt (RETURN_EXPR (t));
+         break;
 
-    case EXPR_STMT:
-      finish_expr_stmt_real (EXPR_STMT_EXPR (t),
-                            EXPR_STMT_ASSIGNS_THIS (t));
-      break;
+       case EXPR_STMT:
+         finish_expr_stmt_real (EXPR_STMT_EXPR (t),
+                                EXPR_STMT_ASSIGNS_THIS (t));
+         break;
 
-    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
+       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 (TREE_CODE (decl) == LABEL_DECL)
+             finish_label_decl (DECL_NAME (decl));
+           else
              {
-               maybe_inject_for_scope_var (decl);
-               initialize_local_var (decl, DECL_INITIAL (decl), 0);
+               /* 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;
+               /* 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;
+                   maybe_push_decl (decl);
+                 }
+               /* 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') or an object with static storage duration
+                  (declared with `static').  We don't have to handle the
+                  initialization of those objects here; the former can
+                  never be a definition (only a declaration), and the
+                  latter is handled in finish_file.  */
+               if (TREE_CODE (decl) == VAR_DECL 
+                   && !TREE_STATIC (decl)
+                   && !DECL_EXTERNAL (decl))
+                 {
+                   /* Support the old for-scope rules for backwards
+                      compatibility.  */
+                   maybe_inject_for_scope_var (decl);
+                   /* Let the back-end know about this variable.  */
+                   initialize_local_var (decl, DECL_INITIAL (decl), 0);
+                 }
              }
+           resume_momentary (i);
          }
-       resume_momentary (i);
-      }
-      break;
-
-    case FOR_STMT:
-      {
-       tree tmp;
-
-       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 (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 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;
+         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_stmts (COMPOUND_BODY (t));
-      rval = finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t), 
-                                  NULL_TREE);
-      break;
-
-    case BREAK_STMT:
-      finish_break_stmt ();
-      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 CONTINUE_STMT:
-      finish_continue_stmt ();
-      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 SWITCH_STMT:
-      {
-       tree cond;
+       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;
 
-       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 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 CASE_LABEL:
-      finish_case_label (CASE_LOW (t), CASE_HIGH (t));
-      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 LABEL_STMT:
-      finish_label_stmt (DECL_NAME (LABEL_STMT_LABEL (t)));
-      break;
+       case BREAK_STMT:
+         finish_break_stmt ();
+         break;
 
-    case GOTO_STMT:
-      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 CONTINUE_STMT:
+         finish_continue_stmt ();
+         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 SWITCH_STMT:
+         {
+           tree cond;
 
-    case TRY_BLOCK:
-      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);
+           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:
+         finish_label_stmt (DECL_NAME (LABEL_STMT_LABEL (t)));
+         break;
+
+       case GOTO_STMT:
+         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:
+         finish_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), ASM_OUTPUTS
+                          (t), ASM_INPUTS (t), ASM_CLOBBERS (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
+           {
+             begin_try_block ();
+             expand_stmt (TRY_STMTS (t));
+             finish_try_block (NULL_TREE);
+             expand_stmt (TRY_HANDLERS (t));
+             finish_handler_sequence (NULL_TREE);
+           }
+         break;
+
+       case HANDLER:
+         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 SUBOBJECT:
+         finish_subobject (SUBOBJECT_CLEANUP (t));
+         break;
+
+       default:
+         my_friendly_abort (19990810);
+         break;
        }
-      break;
 
-    case HANDLER:
-      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;
+      /* Restore saved state.  */
+      stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
 
-    case SUBOBJECT:
-      finish_subobject (SUBOBJECT_CLEANUP (t));
-      break;
-
-    default:
-      my_friendly_abort (19990810);
-      break;
+      /* Go on to the next statement in this scope.  */
+      t = TREE_CHAIN (t);
     }
 
-  /* Restore saved state.  */
-  stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
-
   return rval;
 }
 
@@ -2247,9 +2272,30 @@ void
 expand_body (fn)
      tree fn;
 {
+  int saved_lineno;
+  char *saved_input_filename;
   tree t;
   tree try_block;
 
+  /* 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;
+
+  /* Save the current file name and line number.  When we expand the
+     body of the funciton, 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);
+
   start_function (NULL_TREE, fn, NULL_TREE, SF_PRE_PARSED | SF_EXPAND);
   store_parm_decls ();
 
@@ -2292,13 +2338,22 @@ expand_body (fn)
   if (try_block)
     {
       finish_function_try_block (NULL_TREE);
-      {
-       tree handler = TRY_HANDLERS (try_block);
-       for (; handler; handler = TREE_CHAIN (handler))
-         expand_stmt (handler);
-      }
+      expand_stmt (TRY_HANDLERS (try_block));
       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;
 }