OSDN Git Service

PR c++/19991
[pf3gnuchains/gcc-fork.git] / gcc / cp / semantics.c
index 511c7bc..2daff6f 100644 (file)
@@ -3,8 +3,8 @@
    building RTL.  These routines are used both during actual parsing
    and during the instantiation of template functions. 
 
-   Copyright (C) 1998, 1999, 2000, 2001, 2002,
-   2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
    Written by Mark Mitchell (mmitchell@usa.net) based on code found
    formerly in parse.y and pt.c.  
 
 #include "tm.h"
 #include "tree.h"
 #include "cp-tree.h"
+#include "c-common.h"
 #include "tree-inline.h"
+#include "tree-mudflap.h"
 #include "except.h"
-#include "lex.h"
 #include "toplev.h"
 #include "flags.h"
 #include "rtl.h"
 #include "output.h"
 #include "timevar.h"
 #include "debug.h"
+#include "diagnostic.h"
 #include "cgraph.h"
+#include "tree-iterator.h"
+#include "vec.h"
+#include "target.h"
 
 /* There routines provide a modular interface to perform many parsing
    operations.  They may therefore be used during actual parsing, or
 static tree maybe_convert_cond (tree);
 static tree simplify_aggr_init_exprs_r (tree *, int *, void *);
 static void emit_associated_thunks (tree);
-static void genrtl_try_block (tree);
-static void genrtl_eh_spec_block (tree);
-static void genrtl_handler (tree);
-static void cp_expand_stmt (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)
+static tree finalize_nrv_r (tree *, int *, void *);
+
 
 /* Deferred Access Checking Overview
    ---------------------------------
@@ -129,9 +114,36 @@ static void cp_expand_stmt (tree);
       In case of parsing error, we simply call `pop_deferring_access_checks'
       without `perform_deferred_access_checks'.  */
 
+typedef struct deferred_access GTY(())
+{
+  /* A TREE_LIST representing name-lookups for which we have deferred
+     checking access controls.  We cannot check the accessibility of
+     names used in a decl-specifier-seq until we know what is being
+     declared because code like:
+
+       class A { 
+         class B {};
+         B* f();
+       }
+
+       A::B* A::f() { return 0; }
+
+     is valid, even though `A::B' is not generally accessible.  
+
+     The TREE_PURPOSE of each node is the scope used to qualify the
+     name being looked up; the TREE_VALUE is the DECL to which the
+     name was resolved.  */
+  tree deferred_access_checks;
+  
+  /* The current mode of access checks.  */
+  enum deferring_kind deferring_access_checks_kind;
+  
+} deferred_access;
+DEF_VEC_GC_O (deferred_access);
+
 /* Data for deferred access checking.  */
-static GTY(()) deferred_access *deferred_access_stack;
-static GTY(()) deferred_access *deferred_access_free_list;
+static GTY(()) VEC (deferred_access) *deferred_access_stack;
+static GTY(()) unsigned deferred_access_no_check;
 
 /* Save the current deferred access states and start deferred
    access checking iff DEFER_P is true.  */
@@ -139,27 +151,18 @@ static GTY(()) deferred_access *deferred_access_free_list;
 void
 push_deferring_access_checks (deferring_kind deferring)
 {
-  deferred_access *d;
-
   /* For context like template instantiation, access checking
      disabling applies to all nested context.  */
-  if (deferred_access_stack
-      && deferred_access_stack->deferring_access_checks_kind == dk_no_check)
-    deferring = dk_no_check;
-
-  /* Recycle previously used free store if available.  */
-  if (deferred_access_free_list)
-    {
-      d = deferred_access_free_list;
-      deferred_access_free_list = d->next;
-    }
+  if (deferred_access_no_check || deferring == dk_no_check)
+    deferred_access_no_check++;
   else
-    d = ggc_alloc (sizeof (deferred_access));
+    {
+      deferred_access *ptr;
 
-  d->next = deferred_access_stack;
-  d->deferred_access_checks = NULL_TREE;
-  d->deferring_access_checks_kind = deferring;
-  deferred_access_stack = d;
+      ptr = VEC_safe_push (deferred_access, deferred_access_stack, NULL);
+      ptr->deferred_access_checks = NULL_TREE;
+      ptr->deferring_access_checks_kind = deferring;
+    }
 }
 
 /* Resume deferring access checks again after we stopped doing
@@ -168,8 +171,9 @@ push_deferring_access_checks (deferring_kind deferring)
 void
 resume_deferring_access_checks (void)
 {
-  if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
-    deferred_access_stack->deferring_access_checks_kind = dk_deferred;
+  if (!deferred_access_no_check)
+    VEC_last (deferred_access, deferred_access_stack)
+      ->deferring_access_checks_kind = dk_deferred;
 }
 
 /* Stop deferring access checks.  */
@@ -177,8 +181,9 @@ resume_deferring_access_checks (void)
 void
 stop_deferring_access_checks (void)
 {
-  if (deferred_access_stack->deferring_access_checks_kind == dk_deferred)
-    deferred_access_stack->deferring_access_checks_kind = dk_no_deferred;
+  if (!deferred_access_no_check)
+    VEC_last (deferred_access, deferred_access_stack)
+      ->deferring_access_checks_kind = dk_no_deferred;
 }
 
 /* Discard the current deferred access checks and restore the
@@ -187,15 +192,10 @@ stop_deferring_access_checks (void)
 void
 pop_deferring_access_checks (void)
 {
-  deferred_access *d = deferred_access_stack;
-  deferred_access_stack = d->next;
-
-  /* Remove references to access checks TREE_LIST.  */
-  d->deferred_access_checks = NULL_TREE;
-
-  /* Store in free list for later use.  */
-  d->next = deferred_access_free_list;
-  deferred_access_free_list = d;
+  if (deferred_access_no_check)
+    deferred_access_no_check--;
+  else
+    VEC_pop (deferred_access, deferred_access_stack);
 }
 
 /* Returns a TREE_LIST representing the deferred checks.  
@@ -206,7 +206,11 @@ pop_deferring_access_checks (void)
 tree
 get_deferred_access_checks (void)
 {
-  return deferred_access_stack->deferred_access_checks;
+  if (deferred_access_no_check)
+    return NULL;
+  else
+    return (VEC_last (deferred_access, deferred_access_stack)
+           ->deferred_access_checks);
 }
 
 /* Take current deferred checks and combine with the
@@ -216,27 +220,48 @@ get_deferred_access_checks (void)
 void
 pop_to_parent_deferring_access_checks (void)
 {
-  tree deferred_check = get_deferred_access_checks ();
-  deferred_access *d1 = deferred_access_stack;
-  deferred_access *d2 = deferred_access_stack->next;
-  deferred_access *d3 = deferred_access_stack->next->next;
-
-  /* Temporary swap the order of the top two states, just to make
-     sure the garbage collector will not reclaim the memory during 
-     processing below.  */
-  deferred_access_stack = d2;
-  d2->next = d1;
-  d1->next = d3;
+  if (deferred_access_no_check)
+    deferred_access_no_check--;
+  else
+    {
+      tree checks;
+      deferred_access *ptr;
 
-  for ( ; deferred_check; deferred_check = TREE_CHAIN (deferred_check))
-    /* Perform deferred check if required.  */
-    perform_or_defer_access_check (TREE_PURPOSE (deferred_check), 
-                                  TREE_VALUE (deferred_check));
+      checks = (VEC_last (deferred_access, deferred_access_stack)
+               ->deferred_access_checks);
 
-  deferred_access_stack = d1;
-  d1->next = d2;
-  d2->next = d3;
-  pop_deferring_access_checks ();
+      VEC_pop (deferred_access, deferred_access_stack);
+      ptr = VEC_last (deferred_access, deferred_access_stack);
+      if (ptr->deferring_access_checks_kind == dk_no_deferred)
+       {
+         /* Check access.  */
+         for (; checks; checks = TREE_CHAIN (checks)) 
+           enforce_access (TREE_PURPOSE (checks), 
+                           TREE_VALUE (checks));
+       }
+      else
+       {
+         /* Merge with parent.  */
+         tree next;
+         tree original = ptr->deferred_access_checks;
+         
+         for (; checks; checks = next)
+           {
+             tree probe;
+             
+             next = TREE_CHAIN (checks);
+
+             for (probe = original; probe; probe = TREE_CHAIN (probe))
+               if (TREE_VALUE (probe) == TREE_VALUE (checks)
+                   && TREE_PURPOSE (probe) == TREE_PURPOSE (checks))
+                 goto found;
+             /* Insert into parent's checks.  */
+             TREE_CHAIN (checks) = ptr->deferred_access_checks;
+             ptr->deferred_access_checks = checks;
+           found:;
+           }
+       }
+    }
 }
 
 /* Perform the deferred access checks.
@@ -259,7 +284,8 @@ void
 perform_deferred_access_checks (void)
 {
   tree deferred_check;
-  for (deferred_check = deferred_access_stack->deferred_access_checks;
+
+  for (deferred_check = get_deferred_access_checks ();
        deferred_check;
        deferred_check = TREE_CHAIN (deferred_check))
     /* Check access.  */
@@ -274,29 +300,33 @@ void
 perform_or_defer_access_check (tree binfo, tree decl)
 {
   tree check;
+  deferred_access *ptr;
 
-  my_friendly_assert (TREE_CODE (binfo) == TREE_VEC, 20030623);
+  /* Exit if we are in a context that no access checking is performed.
+     */
+  if (deferred_access_no_check)
+    return;
+  
+  gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
+
+  ptr = VEC_last (deferred_access, deferred_access_stack);
   
   /* If we are not supposed to defer access checks, just check now.  */
-  if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
+  if (ptr->deferring_access_checks_kind == dk_no_deferred)
     {
       enforce_access (binfo, decl);
       return;
     }
-  /* Exit if we are in a context that no access checking is performed.  */
-  else if (deferred_access_stack->deferring_access_checks_kind == dk_no_check)
-    return;
-
+  
   /* See if we are already going to perform this check.  */
-  for (check = deferred_access_stack->deferred_access_checks;
+  for (check = ptr->deferred_access_checks;
        check;
        check = TREE_CHAIN (check))
     if (TREE_VALUE (check) == decl && TREE_PURPOSE (check) == binfo)
       return;
   /* If not, record the check.  */
-  deferred_access_stack->deferred_access_checks
-    = tree_cons (binfo, decl,
-                deferred_access_stack->deferred_access_checks);
+  ptr->deferred_access_checks
+    = tree_cons (binfo, decl, ptr->deferred_access_checks);
 }
 
 /* Returns nonzero if the current statement is a full expression,
@@ -321,6 +351,43 @@ current_stmt_tree (void)
          : &scope_chain->x_stmt_tree);
 }
 
+/* If statements are full expressions, wrap STMT in a CLEANUP_POINT_EXPR.  */
+
+static tree
+maybe_cleanup_point_expr (tree expr)
+{
+  if (!processing_template_decl && stmts_are_full_exprs_p ())
+    expr = fold_build_cleanup_point_expr (TREE_TYPE (expr), expr);
+  return expr;
+}
+
+/* Like maybe_cleanup_point_expr except have the type of the new expression be
+   void so we don't need to create a temporary variable to hold the inner
+   expression.  The reason why we do this is because the original type might be
+   an aggregate and we cannot create a temporary variable for that type.  */
+
+static tree
+maybe_cleanup_point_expr_void (tree expr)
+{
+  if (!processing_template_decl && stmts_are_full_exprs_p ())
+    expr = fold_build_cleanup_point_expr (void_type_node, expr);
+  return expr;
+}
+
+
+
+/* Create a declaration statement for the declaration given by the DECL.  */
+
+void
+add_decl_expr (tree decl)
+{
+  tree r = build_stmt (DECL_EXPR, decl);
+  if (DECL_INITIAL (decl)
+      || (DECL_SIZE (decl) && TREE_SIDE_EFFECTS (DECL_SIZE (decl))))
+    r = maybe_cleanup_point_expr_void (r);
+  add_stmt (r);
+}
+
 /* Nonzero if TYPE is an anonymous union or struct type.  We have to use a
    flag for this because "A union for which objects or pointers are
    declared is not an anonymous union" [class.union].  */
@@ -333,43 +400,102 @@ anon_aggr_type_p (tree node)
 
 /* Finish a scope.  */
 
-tree
-do_poplevel (void)
+static tree
+do_poplevel (tree stmt_list)
 {
-  tree block = NULL_TREE;
+  tree block = NULL;
 
   if (stmts_are_full_exprs_p ())
-    {
-      tree scope_stmts = NULL_TREE;
+    block = poplevel (kept_level_p (), 1, 0);
 
-      block = poplevel (kept_level_p (), 1, 0);
-      if (!processing_template_decl)
-       {
-         /* This needs to come after the poplevel so that partial scopes
-            are properly nested.  */
-         scope_stmts = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
-         if (block)
-           {
-             SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
-             SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
-           }
-       }
+  stmt_list = pop_stmt_list (stmt_list);
+  
+  if (!processing_template_decl)
+    {
+      stmt_list = c_build_bind_expr (block, stmt_list);
+      /* ??? See c_end_compound_stmt re statement expressions.  */
     }
 
-  return block;
+  return stmt_list;
 }
 
 /* Begin a new scope.  */ 
 
-void
+static tree
 do_pushlevel (scope_kind sk)
 {
+  tree ret = push_stmt_list ();
   if (stmts_are_full_exprs_p ())
+    begin_scope (sk, NULL);
+  return ret;
+}
+
+/* Queue a cleanup.  CLEANUP is an expression/statement to be executed
+   when the current scope is exited.  EH_ONLY is true when this is not
+   meant to apply to normal control flow transfer.  */
+
+void
+push_cleanup (tree decl, tree cleanup, bool eh_only)
+{
+  tree stmt = build_stmt (CLEANUP_STMT, NULL, cleanup, decl);
+  CLEANUP_EH_ONLY (stmt) = eh_only;
+  add_stmt (stmt);
+  CLEANUP_BODY (stmt) = push_stmt_list ();
+}
+
+/* Begin a conditional that might contain a declaration.  When generating
+   normal code, we want the declaration to appear before the statement
+   containing the conditional.  When generating template code, we want the
+   conditional to be rendered as the raw DECL_EXPR.  */
+
+static void
+begin_cond (tree *cond_p)
+{
+  if (processing_template_decl)
+    *cond_p = push_stmt_list ();
+}
+
+/* Finish such a conditional.  */
+
+static void
+finish_cond (tree *cond_p, tree expr)
+{
+  if (processing_template_decl)
     {
-      if (!processing_template_decl)
-       add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
-      begin_scope (sk, NULL);
+      tree cond = pop_stmt_list (*cond_p);
+      if (TREE_CODE (cond) == DECL_EXPR)
+       expr = cond;
     }
+  *cond_p = expr;
+}
+
+/* If *COND_P specifies a conditional with a declaration, transform the
+   loop such that
+            while (A x = 42) { }
+            for (; A x = 42;) { }
+   becomes
+            while (true) { A x = 42; if (!x) break; }
+            for (;;) { A x = 42; if (!x) break; }
+   The statement list for BODY will be empty if the conditional did
+   not declare anything.  */
+                                                                                
+static void
+simplify_loop_decl_cond (tree *cond_p, tree body)
+{
+  tree cond, if_stmt;
+
+  if (!TREE_SIDE_EFFECTS (body))
+    return;
+
+  cond = *cond_p;
+  *cond_p = boolean_true_node;
+   
+  if_stmt = begin_if_stmt ();
+  cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
+  finish_if_stmt_cond (cond, if_stmt);
+  finish_break_stmt ();
+  finish_then_clause (if_stmt);
+  finish_if_stmt (if_stmt);
 }
 
 /* Finish a goto-statement.  */
@@ -398,7 +524,7 @@ finish_goto_stmt (tree destination)
   
   check_goto (destination);
 
-  return add_stmt (build_stmt (GOTO_STMT, destination));
+  return add_stmt (build_stmt (GOTO_EXPR, destination));
 }
 
 /* COND is the condition-expression for an if, while, etc.,
@@ -430,11 +556,24 @@ finish_expr_stmt (tree expr)
   if (expr != NULL_TREE)
     {
       if (!processing_template_decl)
-       expr = convert_to_void (expr, "statement");
+       {
+         if (warn_sequence_point)
+           verify_sequence_points (expr);
+         expr = convert_to_void (expr, "statement");
+       }
       else if (!type_dependent_expression_p (expr))
        convert_to_void (build_non_dependent_expr (expr), "statement");
-      
-      r = add_stmt (build_stmt (EXPR_STMT, expr));
+
+      /* Simplification of inner statement expressions, compound exprs,
+        etc can result in us already having an EXPR_STMT.  */
+      if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
+       {
+         if (TREE_CODE (expr) != EXPR_STMT)
+           expr = build_stmt (EXPR_STMT, expr);
+         expr = maybe_cleanup_point_expr_void (expr);
+       }
+
+      r = add_stmt (expr);
     }
 
   finish_stmt ();
@@ -449,10 +588,11 @@ finish_expr_stmt (tree expr)
 tree
 begin_if_stmt (void)
 {
-  tree r;
-  do_pushlevel (sk_block);
+  tree r, scope;
+  scope = do_pushlevel (sk_block);
   r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
-  add_stmt (r);
+  TREE_CHAIN (r) = scope;
+  begin_cond (&IF_COND (r));
   return r;
 }
 
@@ -462,8 +602,9 @@ begin_if_stmt (void)
 void 
 finish_if_stmt_cond (tree cond, tree if_stmt)
 {
-  cond = maybe_convert_cond (cond);
-  FINISH_COND (cond, if_stmt, IF_COND (if_stmt));
+  finish_cond (&IF_COND (if_stmt), maybe_convert_cond (cond));
+  add_stmt (if_stmt);
+  THEN_CLAUSE (if_stmt) = push_stmt_list ();
 }
 
 /* Finish the then-clause of an if-statement, which may be given by
@@ -472,15 +613,16 @@ finish_if_stmt_cond (tree cond, tree if_stmt)
 tree
 finish_then_clause (tree if_stmt)
 {
-  RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
+  THEN_CLAUSE (if_stmt) = pop_stmt_list (THEN_CLAUSE (if_stmt));
   return if_stmt;
 }
 
 /* Begin the else-clause of an if-statement.  */
 
-void 
-begin_else_clause (void)
+void
+begin_else_clause (tree if_stmt)
 {
+  ELSE_CLAUSE (if_stmt) = push_stmt_list ();
 }
 
 /* Finish the else-clause of an if-statement, which may be given by
@@ -489,16 +631,18 @@ begin_else_clause (void)
 void
 finish_else_clause (tree if_stmt)
 {
-  RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
+  ELSE_CLAUSE (if_stmt) = pop_stmt_list (ELSE_CLAUSE (if_stmt));
 }
 
 /* Finish an if-statement.  */
 
 void 
-finish_if_stmt (void)
+finish_if_stmt (tree if_stmt)
 {
+  tree scope = TREE_CHAIN (if_stmt);
+  TREE_CHAIN (if_stmt) = NULL;
+  add_stmt (do_poplevel (scope));
   finish_stmt ();
-  do_poplevel ();
 }
 
 /* Begin a while-statement.  Returns a newly created WHILE_STMT if
@@ -510,7 +654,8 @@ begin_while_stmt (void)
   tree r;
   r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
   add_stmt (r);
-  do_pushlevel (sk_block);
+  WHILE_BODY (r) = do_pushlevel (sk_block);
+  begin_cond (&WHILE_COND (r));
   return r;
 }
 
@@ -520,30 +665,8 @@ begin_while_stmt (void)
 void 
 finish_while_stmt_cond (tree cond, tree while_stmt)
 {
-  cond = maybe_convert_cond (cond);
-  if (processing_template_decl)
-    /* Don't mess with condition decls in a template.  */
-    FINISH_COND (cond, while_stmt, WHILE_COND (while_stmt));
-  else if (getdecls () == NULL_TREE)
-    /* It was a simple condition; install it.  */
-    WHILE_COND (while_stmt) = cond;
-  else
-    {
-      /* If there was a declaration in the condition, we can't leave it
-        there; transform
-           while (A x = 42) { }
-        to
-           while (true) { A x = 42; if (!x) break; }  */
-      tree if_stmt;
-      WHILE_COND (while_stmt) = boolean_true_node;
-
-      if_stmt = begin_if_stmt ();
-      cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
-      finish_if_stmt_cond (cond, if_stmt);
-      finish_break_stmt ();
-      finish_then_clause (if_stmt);
-      finish_if_stmt ();
-    }
+  finish_cond (&WHILE_COND (while_stmt), maybe_convert_cond (cond));
+  simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt));
 }
 
 /* Finish a while-statement, which may be given by WHILE_STMT.  */
@@ -551,8 +674,7 @@ finish_while_stmt_cond (tree cond, tree while_stmt)
 void 
 finish_while_stmt (tree while_stmt)
 {
-  do_poplevel ();
-  RECHAIN_STMTS (while_stmt, WHILE_BODY (while_stmt));
+  WHILE_BODY (while_stmt) = do_poplevel (WHILE_BODY (while_stmt));
   finish_stmt ();
 }
 
@@ -564,6 +686,7 @@ begin_do_stmt (void)
 {
   tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE);
   add_stmt (r);
+  DO_BODY (r) = push_stmt_list ();
   return r;
 }
 
@@ -572,7 +695,7 @@ begin_do_stmt (void)
 void
 finish_do_body (tree do_stmt)
 {
-  RECHAIN_STMTS (do_stmt, DO_BODY (do_stmt));
+  DO_BODY (do_stmt) = pop_stmt_list (DO_BODY (do_stmt));
 }
 
 /* Finish a do-statement, which may be given by DO_STMT, and whose
@@ -597,16 +720,21 @@ finish_return_stmt (tree expr)
   expr = check_return_expr (expr);
   if (!processing_template_decl)
     {
-      if (DECL_DESTRUCTOR_P (current_function_decl))
+      if (DECL_DESTRUCTOR_P (current_function_decl)
+         || (DECL_CONSTRUCTOR_P (current_function_decl) 
+             && targetm.cxx.cdtor_returns_this ()))
        {
          /* Similarly, all destructors must run destructors for
             base-classes before returning.  So, all returns in a
             destructor get sent to the DTOR_LABEL; finish_function emits
             code to return a value there.  */
-         return finish_goto_stmt (dtor_label);
+         return finish_goto_stmt (cdtor_label);
        }
     }
-  r = add_stmt (build_stmt (RETURN_STMT, expr));
+
+  r = build_stmt (RETURN_EXPR, expr);
+  r = maybe_cleanup_point_expr_void (r);
+  r = add_stmt (r);
   finish_stmt ();
 
   return r;
@@ -621,10 +749,12 @@ begin_for_stmt (void)
 
   r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, 
                  NULL_TREE, NULL_TREE);
-  NEW_FOR_SCOPE_P (r) = flag_new_for_scope > 0;
-  if (NEW_FOR_SCOPE_P (r))
-    do_pushlevel (sk_for);
-  add_stmt (r);
+
+  if (flag_new_for_scope > 0)
+    TREE_CHAIN (r) = do_pushlevel (sk_for);
+
+  if (processing_template_decl)
+    FOR_INIT_STMT (r) = push_stmt_list ();
 
   return r;
 }
@@ -635,9 +765,11 @@ begin_for_stmt (void)
 void
 finish_for_init_stmt (tree for_stmt)
 {
-  if (last_tree != for_stmt)
-    RECHAIN_STMTS (for_stmt, FOR_INIT_STMT (for_stmt));
-  do_pushlevel (sk_block);
+  if (processing_template_decl)
+    FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
+  add_stmt (for_stmt);
+  FOR_BODY (for_stmt) = do_pushlevel (sk_block);
+  begin_cond (&FOR_COND (for_stmt));
 }
 
 /* Finish the COND of a for-statement, which may be given by
@@ -646,30 +778,8 @@ finish_for_init_stmt (tree for_stmt)
 void
 finish_for_cond (tree cond, tree for_stmt)
 {
-  cond = maybe_convert_cond (cond);
-  if (processing_template_decl)
-    /* Don't mess with condition decls in a template.  */
-    FINISH_COND (cond, for_stmt, FOR_COND (for_stmt));
-  else if (getdecls () == NULL_TREE)
-    /* It was a simple condition; install it.  */
-    FOR_COND (for_stmt) = cond;
-  else
-    {
-      /* If there was a declaration in the condition, we can't leave it
-        there; transform
-           for (; A x = 42;) { }
-        to
-           for (;;) { A x = 42; if (!x) break; }  */
-      tree if_stmt;
-      FOR_COND (for_stmt) = NULL_TREE;
-
-      if_stmt = begin_if_stmt ();
-      cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
-      finish_if_stmt_cond (cond, if_stmt);
-      finish_break_stmt ();
-      finish_then_clause (if_stmt);
-      finish_if_stmt ();
-    }
+  finish_cond (&FOR_COND (for_stmt), maybe_convert_cond (cond));
+  simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt));
 }
 
 /* Finish the increment-EXPRESSION in a for-statement, which may be
@@ -678,13 +788,24 @@ finish_for_cond (tree cond, tree for_stmt)
 void
 finish_for_expr (tree expr, tree for_stmt)
 {
+  if (!expr)
+    return;
   /* If EXPR is an overloaded function, issue an error; there is no
      context available to use to perform overload resolution.  */
-  if (expr && type_unknown_p (expr))
+  if (type_unknown_p (expr))
     {
       cxx_incomplete_type_error (expr, TREE_TYPE (expr));
       expr = error_mark_node;
     }
+  if (!processing_template_decl)
+    {
+      if (warn_sequence_point)
+        verify_sequence_points (expr);
+      expr = convert_to_void (expr, "3rd expression in for");
+    }
+  else if (!type_dependent_expression_p (expr))
+    convert_to_void (build_non_dependent_expr (expr), "3rd expression in for");
+  expr = maybe_cleanup_point_expr_void (expr);
   FOR_EXPR (for_stmt) = expr;
 }
 
@@ -695,11 +816,16 @@ finish_for_expr (tree expr, tree for_stmt)
 void
 finish_for_stmt (tree for_stmt)
 {
+  FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt));
+
   /* Pop the scope for the body of the loop.  */
-  do_poplevel ();
-  RECHAIN_STMTS (for_stmt, FOR_BODY (for_stmt));
-  if (NEW_FOR_SCOPE_P (for_stmt))
-    do_poplevel ();
+  if (flag_new_for_scope > 0)
+    {
+      tree scope = TREE_CHAIN (for_stmt);
+      TREE_CHAIN (for_stmt) = NULL;
+      add_stmt (do_poplevel (scope));
+    }
+
   finish_stmt (); 
 }
 
@@ -725,10 +851,14 @@ finish_continue_stmt (void)
 tree
 begin_switch_stmt (void)
 {
-  tree r;
-  do_pushlevel (sk_block);
+  tree r, scope;
+
   r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
-  add_stmt (r);
+
+  scope = do_pushlevel (sk_block);
+  TREE_CHAIN (r) = scope;
+  begin_cond (&SWITCH_STMT_COND (r));
+
   return r;
 }
 
@@ -756,7 +886,7 @@ finish_switch_cond (tree cond, tree switch_stmt)
 
             Integral promotions are performed.  */
          cond = perform_integral_promotions (cond);
-         cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond));
+         cond = maybe_cleanup_point_expr (cond);
        }
 
       if (cond != error_mark_node)
@@ -766,14 +896,16 @@ finish_switch_cond (tree cond, tree switch_stmt)
             because if we did, int_fits_type_p would do the wrong thing
             when checking case values for being in range,
             and it's too hard to do the right thing.  */
-         if (TREE_UNSIGNED (TREE_TYPE (cond))
-             == TREE_UNSIGNED (TREE_TYPE (index)))
+         if (TYPE_UNSIGNED (TREE_TYPE (cond))
+             == TYPE_UNSIGNED (TREE_TYPE (index)))
            cond = index;
        }
     }
-  FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
-  SWITCH_TYPE (switch_stmt) = orig_type;
+  finish_cond (&SWITCH_STMT_COND (switch_stmt), cond);
+  SWITCH_STMT_TYPE (switch_stmt) = orig_type;
+  add_stmt (switch_stmt);
   push_switch (switch_stmt);
+  SWITCH_STMT_BODY (switch_stmt) = push_stmt_list ();
 }
 
 /* Finish the body of a switch-statement, which may be given by
@@ -782,60 +914,16 @@ finish_switch_cond (tree cond, tree switch_stmt)
 void
 finish_switch_stmt (tree switch_stmt)
 {
-  RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt));
+  tree scope;
+
+  SWITCH_STMT_BODY (switch_stmt) =
+    pop_stmt_list (SWITCH_STMT_BODY (switch_stmt));
   pop_switch (); 
   finish_stmt ();
-  do_poplevel ();
-}
-
-/* Generate the RTL for T, which is a TRY_BLOCK.  */
-
-static void 
-genrtl_try_block (tree t)
-{
-  if (CLEANUP_P (t))
-    {
-      expand_eh_region_start ();
-      expand_stmt (TRY_STMTS (t));
-      expand_eh_region_end_cleanup (TRY_HANDLERS (t));
-    }
-  else
-    {
-      if (!FN_TRY_BLOCK_P (t)) 
-       emit_line_note (input_location);
 
-      expand_eh_region_start ();
-      expand_stmt (TRY_STMTS (t));
-
-      if (FN_TRY_BLOCK_P (t))
-       {
-         expand_start_all_catch ();
-         in_function_try_handler = 1;
-         expand_stmt (TRY_HANDLERS (t));
-         in_function_try_handler = 0;
-         expand_end_all_catch ();
-       }
-      else 
-       {
-         expand_start_all_catch ();  
-         expand_stmt (TRY_HANDLERS (t));
-         expand_end_all_catch ();
-       }
-    }
-}
-
-/* Generate the RTL for T, which is an EH_SPEC_BLOCK.  */
-
-static void 
-genrtl_eh_spec_block (tree t)
-{
-  expand_eh_region_start ();
-  expand_stmt (EH_SPEC_STMTS (t));
-  expand_eh_region_end_allowed (EH_SPEC_RAISES (t),
-                               build_call (call_unexpected_node,
-                                           tree_cons (NULL_TREE,
-                                                      build_exc_ptr (),
-                                                      NULL_TREE)));
+  scope = TREE_CHAIN (switch_stmt);
+  TREE_CHAIN (switch_stmt) = NULL;
+  add_stmt (do_poplevel (scope));
 }
 
 /* Begin a try-block.  Returns a newly-created TRY_BLOCK if
@@ -846,6 +934,7 @@ begin_try_block (void)
 {
   tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
   add_stmt (r);
+  TRY_STMTS (r) = push_stmt_list ();
   return r;
 }
 
@@ -854,9 +943,8 @@ begin_try_block (void)
 tree
 begin_function_try_block (void)
 {
-  tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
+  tree r = begin_try_block ();
   FN_TRY_BLOCK_P (r) = 1;
-  add_stmt (r);
   return r;
 }
 
@@ -865,7 +953,8 @@ begin_function_try_block (void)
 void
 finish_try_block (tree try_block)
 {
-  RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
+  TRY_STMTS (try_block) = pop_stmt_list (TRY_STMTS (try_block));
+  TRY_HANDLERS (try_block) = push_stmt_list ();
 }
 
 /* Finish the body of a cleanup try-block, which may be given by
@@ -874,7 +963,7 @@ finish_try_block (tree try_block)
 void
 finish_cleanup_try_block (tree try_block)
 {
-  RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
+  TRY_STMTS (try_block) = pop_stmt_list (TRY_STMTS (try_block));
 }
 
 /* Finish an implicitly generated try-block, with a cleanup is given
@@ -892,16 +981,9 @@ finish_cleanup (tree cleanup, tree try_block)
 void
 finish_function_try_block (tree 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));
+  finish_try_block (try_block);
+  /* FIXME : something queer about CTOR_INITIALIZER somehow following
+     the try block, but moving it inside.  */
   in_function_try_handler = 1;
 }
 
@@ -911,7 +993,7 @@ finish_function_try_block (tree try_block)
 void
 finish_handler_sequence (tree try_block)
 {
-  RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
+  TRY_HANDLERS (try_block) = pop_stmt_list (TRY_HANDLERS (try_block));
   check_handlers (TRY_HANDLERS (try_block));
 }
 
@@ -921,21 +1003,7 @@ void
 finish_function_handler_sequence (tree try_block)
 {
   in_function_try_handler = 0;
-  RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
-  check_handlers (TRY_HANDLERS (try_block));
-}
-
-/* Generate the RTL for T, which is a HANDLER.  */
-
-static void
-genrtl_handler (tree t)
-{
-  genrtl_do_pushlevel ();
-  if (!processing_template_decl)
-    expand_start_catch (HANDLER_TYPE (t));
-  expand_stmt (HANDLER_BODY (t));
-  if (!processing_template_decl)
-    expand_end_catch ();
+  finish_handler_sequence (try_block);
 }
 
 /* Begin a handler.  Returns a HANDLER if appropriate.  */
@@ -944,11 +1012,14 @@ tree
 begin_handler (void)
 {
   tree r;
+
   r = build_stmt (HANDLER, NULL_TREE, NULL_TREE);
   add_stmt (r);
+
   /* Create a binding level for the eh_info and the exception object
      cleanup.  */
-  do_pushlevel (sk_catch);
+  HANDLER_BODY (r) = do_pushlevel (sk_catch);
+
   return r;
 }
 
@@ -966,8 +1037,7 @@ finish_handler_parms (tree decl, tree handler)
        {
          decl = pushdecl (decl);
          decl = push_template_decl (decl);
-         add_decl_stmt (decl);
-         RECHAIN_STMTS (handler, HANDLER_PARMS (handler));
+         HANDLER_PARMS (handler) = decl;
          type = TREE_TYPE (decl);
        }
     }
@@ -987,155 +1057,176 @@ finish_handler (tree handler)
 {
   if (!processing_template_decl)
     expand_end_catch_block ();
-  do_poplevel ();
-  RECHAIN_STMTS (handler, HANDLER_BODY (handler));
+  HANDLER_BODY (handler) = do_poplevel (HANDLER_BODY (handler));
 }
 
-/* Begin a compound-statement.  If HAS_NO_SCOPE is true, the
-   compound-statement does not define a scope.  Returns a new
-   COMPOUND_STMT.  */
+/* Begin a compound statement.  FLAGS contains some bits that control the
+   behavior and context.  If BCS_NO_SCOPE is set, the compound statement
+   does not define a scope.  If BCS_FN_BODY is set, this is the outermost
+   block of a function.  If BCS_TRY_BLOCK is set, this is the block 
+   created on behalf of a TRY statement.  Returns a token to be passed to
+   finish_compound_stmt.  */
 
 tree
-begin_compound_stmt (bool has_no_scope)
+begin_compound_stmt (unsigned int flags)
 {
-  tree r; 
-  int is_try = 0;
-
-  r = build_stmt (COMPOUND_STMT, NULL_TREE);
-
-  if (last_tree && TREE_CODE (last_tree) == TRY_BLOCK)
-    is_try = 1;
-
-  add_stmt (r);
-  if (has_no_scope)
-    COMPOUND_STMT_NO_SCOPE (r) = 1;
+  tree r;
 
-  last_expr_type = NULL_TREE;
+  if (flags & BCS_NO_SCOPE)
+    {
+      r = push_stmt_list ();
+      STATEMENT_LIST_NO_SCOPE (r) = 1;
 
-  if (!has_no_scope)
-    do_pushlevel (is_try ? sk_try : sk_block);
+      /* Normally, we try hard to keep the BLOCK for a statement-expression.
+        But, if it's a statement-expression with a scopeless block, there's
+        nothing to keep, and we don't want to accidentally keep a block
+        *inside* the scopeless block.  */ 
+      keep_next_level (false);
+    }
   else
-    /* Normally, we try hard to keep the BLOCK for a
-       statement-expression.  But, if it's a statement-expression with
-       a scopeless block, there's nothing to keep, and we don't want
-       to accidentally keep a block *inside* the scopeless block.  */ 
-    keep_next_level (false);
+    r = do_pushlevel (flags & BCS_TRY_BLOCK ? sk_try : sk_block);
+
+  /* When processing a template, we need to remember where the braces were,
+     so that we can set up identical scopes when instantiating the template
+     later.  BIND_EXPR is a handy candidate for this.
+     Note that do_poplevel won't create a BIND_EXPR itself here (and thus
+     result in nested BIND_EXPRs), since we don't build BLOCK nodes when
+     processing templates.  */
+  if (processing_template_decl)
+    {
+      r = build3 (BIND_EXPR, NULL, NULL, r, NULL);
+      BIND_EXPR_TRY_BLOCK (r) = (flags & BCS_TRY_BLOCK) != 0;
+      BIND_EXPR_BODY_BLOCK (r) = (flags & BCS_FN_BODY) != 0;
+      TREE_SIDE_EFFECTS (r) = 1;
+    }
 
   return r;
 }
 
-/* Finish a compound-statement, which is given by COMPOUND_STMT.  */
+/* Finish a compound-statement, which is given by STMT.  */
 
-tree
-finish_compound_stmt (tree compound_stmt)
+void
+finish_compound_stmt (tree stmt)
 {
-  tree r;
-  tree t;
-
-  if (COMPOUND_STMT_NO_SCOPE (compound_stmt))
-    r = NULL_TREE;
+  if (TREE_CODE (stmt) == BIND_EXPR)
+    BIND_EXPR_BODY (stmt) = do_poplevel (BIND_EXPR_BODY (stmt));
+  else if (STATEMENT_LIST_NO_SCOPE (stmt))
+    stmt = pop_stmt_list (stmt);
   else
-    r = do_poplevel ();
+    {
+      /* Destroy any ObjC "super" receivers that may have been
+        created.  */
+      objc_clear_super_receiver ();
 
-  RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt));
+      stmt = do_poplevel (stmt);
+    }
 
-  /* 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.  */
-  t = last_expr_type;
+  /* ??? See c_end_compound_stmt wrt statement expressions.  */
+  add_stmt (stmt);
   finish_stmt ();
-  last_expr_type = t;
-
-  return r;
 }
 
-/* Finish an asm-statement, whose components are a CV_QUALIFIER, a
-   STRING, some OUTPUT_OPERANDS, some INPUT_OPERANDS, and some
-   CLOBBERS.  */
+/* Finish an asm-statement, whose components are a STRING, some
+   OUTPUT_OPERANDS, some INPUT_OPERANDS, and some CLOBBERS.  Also note
+   whether the asm-statement should be considered volatile.  */
 
 tree
-finish_asm_stmt (tree cv_qualifier, 
-                 tree string, 
-                 tree output_operands,
-                tree input_operands, 
-                 tree clobbers)
+finish_asm_stmt (int volatile_p, tree string, tree output_operands,
+                tree input_operands, tree clobbers)
 {
   tree r;
   tree t;
 
-  if (cv_qualifier != NULL_TREE
-      && cv_qualifier != ridpointers[(int) RID_VOLATILE])
-    {
-      warning ("%s qualifier ignored on asm",
-                 IDENTIFIER_POINTER (cv_qualifier));
-      cv_qualifier = NULL_TREE;
-    }
-
   if (!processing_template_decl)
     {
+      int ninputs, noutputs;
+      const char *constraint;
+      const char **oconstraints;
+      bool allows_mem, allows_reg, is_inout;
+      tree operand;
       int i;
-      int ninputs;
-      int noutputs;
-
-      for (t = input_operands; t; t = TREE_CHAIN (t))
-       {
-         tree converted_operand 
-           = decay_conversion (TREE_VALUE (t)); 
-         
-         /* If the type of the operand hasn't been determined (e.g.,
-            because it involves an overloaded function), then issue
-            an error message.  There's no context available to
-            resolve the overloading.  */
-         if (TREE_TYPE (converted_operand) == unknown_type_node)
-           {
-             error ("type of asm operand `%E' could not be determined", 
-                       TREE_VALUE (t));
-             converted_operand = error_mark_node;
-           }
-         TREE_VALUE (t) = converted_operand;
-       }
 
       ninputs = list_length (input_operands);
       noutputs = list_length (output_operands);
+      oconstraints = (const char **) alloca (noutputs * sizeof (char *));
+
+      string = resolve_asm_operand_names (string, output_operands,
+                                         input_operands);
 
       for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i)
        {
-         bool allows_mem;
-         bool allows_reg;
-         bool is_inout;
-         const char *constraint;
-         tree operand;
+         operand = TREE_VALUE (t);
+
+         /* ??? Really, this should not be here.  Users should be using a
+            proper lvalue, dammit.  But there's a long history of using
+            casts in the output operands.  In cases like longlong.h, this
+            becomes a primitive form of typechecking -- if the cast can be
+            removed, then the output operand had a type of the proper width;
+            otherwise we'll get an error.  Gross, but ...  */
+         STRIP_NOPS (operand);
+
+         if (!lvalue_or_else (operand, lv_asm))
+           operand = error_mark_node;
 
          constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
-         operand = TREE_VALUE (t);
+         oconstraints[i] = constraint;
 
-         if (!parse_output_constraint (&constraint,
-                                       i, ninputs, noutputs,
-                                       &allows_mem,
-                                       &allows_reg,
-                                       &is_inout))
+         if (parse_output_constraint (&constraint, i, ninputs, noutputs,
+                                      &allows_mem, &allows_reg, &is_inout))
            {
-             /* By marking this operand as erroneous, we will not try
-                to process this operand again in expand_asm_operands.  */
-             TREE_VALUE (t) = error_mark_node;
-             continue;
+             /* If the operand is going to end up in memory,
+                mark it addressable.  */
+             if (!allows_reg && !cxx_mark_addressable (operand))
+               operand = error_mark_node;
            }
+         else
+           operand = error_mark_node;
 
-         /* If the operand is a DECL that is going to end up in
-            memory, assume it is addressable.  This is a bit more
-            conservative than it would ideally be; the exact test is
-            buried deep in expand_asm_operands and depends on the
-            DECL_RTL for the OPERAND -- which we don't have at this
-            point.  */
-         if (!allows_reg && DECL_P (operand))
-           cxx_mark_addressable (operand);
+         TREE_VALUE (t) = operand;
+       }
+
+      for (i = 0, t = input_operands; t; ++i, t = TREE_CHAIN (t))
+       {
+         constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+         operand = decay_conversion (TREE_VALUE (t)); 
+
+         /* If the type of the operand hasn't been determined (e.g.,
+            because it involves an overloaded function), then issue
+            an error message.  There's no context available to
+            resolve the overloading.  */
+         if (TREE_TYPE (operand) == unknown_type_node)
+           {
+             error ("type of asm operand %qE could not be determined", 
+                     TREE_VALUE (t));
+             operand = error_mark_node;
+           }
+
+         if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
+                                     oconstraints, &allows_mem, &allows_reg))
+           {
+             /* If the operand is going to end up in memory,
+                mark it addressable.  */
+             if (!allows_reg && allows_mem)
+               {
+                 /* Strip the nops as we allow this case.  FIXME, this really
+                    should be rejected or made deprecated.  */
+                 STRIP_NOPS (operand);
+                 if (!cxx_mark_addressable (operand))
+                   operand = error_mark_node;
+               }
+           }
+         else
+           operand = error_mark_node;
+
+         TREE_VALUE (t) = operand;
        }
     }
 
-  r = build_stmt (ASM_STMT, cv_qualifier, string,
+  r = build_stmt (ASM_EXPR, string,
                  output_operands, input_operands,
                  clobbers);
+  ASM_VOLATILE_P (r) = volatile_p;
+  r = maybe_cleanup_point_expr_void (r);
   return add_stmt (r);
 }
 
@@ -1145,7 +1236,7 @@ tree
 finish_label_stmt (tree name)
 {
   tree decl = define_label (input_location, name);
-  return add_stmt (build_stmt (LABEL_STMT, decl));
+  return add_stmt (build_stmt (LABEL_EXPR, decl));
 }
 
 /* Finish a series of declarations for local labels.  G++ allows users
@@ -1156,7 +1247,7 @@ void
 finish_label_decl (tree name)
 {
   tree decl = declare_local_label (name);
-  add_decl_stmt (decl);
+  add_decl_expr (decl);
 }
 
 /* When DECL goes out of scope, make sure that CLEANUP is executed.  */
@@ -1164,7 +1255,7 @@ finish_label_decl (tree name)
 void 
 finish_decl_cleanup (tree decl, tree cleanup)
 {
-  add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
+  push_cleanup (decl, cleanup, false);
 }
 
 /* If the current scope exits with an exception, run CLEANUP.  */
@@ -1172,9 +1263,7 @@ finish_decl_cleanup (tree decl, tree cleanup)
 void
 finish_eh_cleanup (tree cleanup)
 {
-  tree r = build_stmt (CLEANUP_STMT, NULL_TREE, cleanup);
-  CLEANUP_EH_ONLY (r) = 1;
-  add_stmt (r);
+  push_cleanup (NULL, cleanup, true);
 }
 
 /* The MEM_INITS is a list of mem-initializers, in reverse of the
@@ -1194,27 +1283,23 @@ finish_mem_initializers (tree mem_inits)
     emit_mem_initializers (mem_inits);
 }
 
-/* Returns the stack of SCOPE_STMTs for the current function.  */
-
-tree *
-current_scope_stmt_stack (void)
-{
-  return &cfun->language->base.x_scope_stmt_stack;
-}
-
 /* Finish a parenthesized expression EXPR.  */
 
 tree
 finish_parenthesized_expr (tree expr)
 {
-  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expr))))
+  if (EXPR_P (expr))
     /* This inhibits warnings in c_common_truthvalue_conversion.  */
-    C_SET_EXP_ORIGINAL_CODE (expr, ERROR_MARK); 
+    TREE_NO_WARNING (expr) = 1;
 
   if (TREE_CODE (expr) == OFFSET_REF)
     /* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be
        enclosed in parentheses.  */
     PTRMEM_OK_P (expr) = 0;
+  
+  if (TREE_CODE (expr) == STRING_CST)
+    PAREN_STRING_LITERAL_P (expr) = 1;
+  
   return expr;
 }
 
@@ -1224,16 +1309,16 @@ finish_parenthesized_expr (tree expr)
 tree
 finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
 {
-  my_friendly_assert (TREE_CODE (decl) == FIELD_DECL, 20020909);
+  gcc_assert (TREE_CODE (decl) == FIELD_DECL);
 
   if (!object)
     {
       if (current_function_decl 
          && DECL_STATIC_FUNCTION_P (current_function_decl))
-       cp_error_at ("invalid use of member `%D' in static member function",
+       cp_error_at ("invalid use of member %qD in static member function",
                     decl);
       else
-       cp_error_at ("invalid use of non-static data member `%D'", decl);
+       cp_error_at ("invalid use of non-static data member %qD", decl);
       error ("from this location");
 
       return error_mark_node;
@@ -1257,7 +1342,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
          type = cp_build_qualified_type (type, quals);
        }
       
-      return build_min (COMPONENT_REF, type, object, decl);
+      return build_min (COMPONENT_REF, type, object, decl, NULL_TREE);
     }
   else
     {
@@ -1272,7 +1357,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
 
          if (!access_type)
            {
-             cp_error_at ("object missing in reference to `%D'", decl);
+             cp_error_at ("object missing in reference to %qD", decl);
              error ("from this location");
              return error_mark_node;
            }
@@ -1315,6 +1400,10 @@ check_accessibility_of_qualified_id (tree decl,
 {
   tree scope;
   tree qualifying_type = NULL_TREE;
+
+  /* If we're not checking, return immediately.  */
+  if (deferred_access_no_check)
+    return;
   
   /* Determine the SCOPE of DECL.  */
   scope = context_for_name_lookup (decl);
@@ -1355,7 +1444,9 @@ check_accessibility_of_qualified_id (tree decl,
        its bases.  */
     qualifying_type = currently_open_derived_class (scope);
 
-  if (qualifying_type)
+  if (qualifying_type && IS_AGGR_TYPE_CODE (TREE_CODE (qualifying_type)))
+    /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM
+       or similar in a default argument value.  */
     perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl);
 }
 
@@ -1388,19 +1479,16 @@ finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
                                          qualifying_class);
   else if (BASELINK_P (expr) && !processing_template_decl)
     {
-      tree fn;
       tree fns;
 
       /* See if any of the functions are non-static members.  */
       fns = BASELINK_FUNCTIONS (expr);
       if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
        fns = TREE_OPERAND (fns, 0);
-      for (fn = fns; fn; fn = OVL_NEXT (fn))
-       if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
-         break;
       /* If so, the expression may be relative to the current
         class.  */
-      if (fn && current_class_type 
+      if (!shared_member_p (fns)
+         && current_class_type 
          && DERIVED_FROM_P (qualifying_class, current_class_type))
        expr = (build_class_member_access_expr 
                (maybe_dummy_object (qualifying_class, NULL),
@@ -1422,17 +1510,7 @@ finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
 tree 
 begin_stmt_expr (void)
 {
-  /* If we're outside a function, we won't have a statement-tree to
-     work with.  But, if we see a statement-expression we need to
-     create one.  */
-  if (! cfun && !last_tree)
-    begin_stmt_tree (&scope_chain->x_saved_tree);
-
-  last_expr_type = NULL_TREE;
-  
-  keep_next_level (true);
-
-  return last_tree; 
+  return push_stmt_list ();
 }
 
 /* Process the final expression of a statement expression. EXPR can be
@@ -1441,24 +1519,24 @@ begin_stmt_expr (void)
    expression.  */
 
 tree
-finish_stmt_expr_expr (tree expr)
+finish_stmt_expr_expr (tree expr, tree stmt_expr)
 {
   tree result = NULL_TREE;
-  tree type = void_type_node;
 
   if (expr)
     {
-      type = TREE_TYPE (expr);
-      
       if (!processing_template_decl && !VOID_TYPE_P (TREE_TYPE (expr)))
        {
+         tree type = TREE_TYPE (expr);
+
          if (TREE_CODE (type) == ARRAY_TYPE
              || TREE_CODE (type) == FUNCTION_TYPE)
            expr = decay_conversion (expr);
 
-         expr = convert_from_reference (expr);
          expr = require_complete_type (expr);
 
+         type = TREE_TYPE (expr);
+
          /* Build a TARGET_EXPR for this aggregate.  finish_stmt_expr
             will then pull it apart so the lifetime of the target is
             within the scope of the expression containing this statement
@@ -1473,24 +1551,25 @@ finish_stmt_expr_expr (tree expr)
              expr = build_special_member_call
                (NULL_TREE, complete_ctor_identifier,
                 build_tree_list (NULL_TREE, expr),
-                TYPE_BINFO (type), LOOKUP_NORMAL);
+                type, LOOKUP_NORMAL);
              expr = build_cplus_new (type, expr);
-             my_friendly_assert (TREE_CODE (expr) == TARGET_EXPR, 20030729);
+             gcc_assert (TREE_CODE (expr) == TARGET_EXPR);
            }
        }
 
       if (expr != error_mark_node)
        {
          result = build_stmt (EXPR_STMT, expr);
+         EXPR_STMT_STMT_EXPR_RESULT (result) = 1;
          add_stmt (result);
        }
     }
   
   finish_stmt ();
 
-  /* Remember the last expression so that finish_stmt_expr can pull it
-     apart.  */
-  last_expr_type = result ? result : void_type_node;
+  /* Remember the last expression so that finish_stmt_expr
+     can pull it apart.  */
+  TREE_TYPE (stmt_expr) = result;
   
   return result;
 }
@@ -1500,58 +1579,97 @@ finish_stmt_expr_expr (tree expr)
    representing the statement-expression.  */
 
 tree 
-finish_stmt_expr (tree rtl_expr, bool has_no_scope)
+finish_stmt_expr (tree stmt_expr, bool has_no_scope)
 {
-  tree result;
-  tree result_stmt = last_expr_type;
-  tree type;
-  
-  if (!last_expr_type)
+  tree result, result_stmt, type;
+  tree *result_stmt_p = NULL;
+
+  result_stmt = TREE_TYPE (stmt_expr);
+  TREE_TYPE (stmt_expr) = void_type_node;
+  result = pop_stmt_list (stmt_expr);
+
+  if (!result_stmt || VOID_TYPE_P (result_stmt))
     type = void_type_node;
   else
     {
-      if (result_stmt == void_type_node)
+      /* We need to search the statement expression for the result_stmt,
+        since we'll need to replace it entirely.  */
+      tree t;
+      result_stmt_p = &result;
+      while (1)
        {
-         type = void_type_node;
-         result_stmt = NULL_TREE;
+         t = *result_stmt_p;
+         if (t == result_stmt)
+           break;
+
+         switch (TREE_CODE (t))
+           {
+           case STATEMENT_LIST:
+             {
+               tree_stmt_iterator i = tsi_last (t);
+               result_stmt_p = tsi_stmt_ptr (i);
+               break;
+             }
+           case BIND_EXPR:
+             result_stmt_p = &BIND_EXPR_BODY (t);
+             break;
+           case TRY_FINALLY_EXPR:
+           case TRY_CATCH_EXPR:
+           case CLEANUP_STMT:
+             result_stmt_p = &TREE_OPERAND (t, 0);
+             break;
+           default:
+             gcc_unreachable ();
+           }
        }
-      else
-       type = TREE_TYPE (EXPR_STMT_EXPR (result_stmt));
+      type = TREE_TYPE (EXPR_STMT_EXPR (result_stmt));
     }
-  
-  result = build_min (STMT_EXPR, type, last_tree);
-  TREE_SIDE_EFFECTS (result) = 1;
-  STMT_EXPR_NO_SCOPE (result) = has_no_scope;
-  
-  last_expr_type = NULL_TREE;
-  
-  /* Remove the compound statement from the tree structure; it is
-     now saved in the STMT_EXPR.  */
-  last_tree = rtl_expr;
-  TREE_CHAIN (last_tree) = NULL_TREE;
-
-  /* If we created a statement-tree for this statement-expression,
-     remove it now.  */ 
-  if (! cfun
-      && TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE)
-    finish_stmt_tree (&scope_chain->x_saved_tree);
 
   if (processing_template_decl)
-    return result;
-
-  if (!VOID_TYPE_P (type))
+    {
+      result = build_min (STMT_EXPR, type, result);
+      TREE_SIDE_EFFECTS (result) = 1;
+      STMT_EXPR_NO_SCOPE (result) = has_no_scope;
+    }
+  else if (!VOID_TYPE_P (type))
     {
       /* Pull out the TARGET_EXPR that is the final expression. Put
         the target's init_expr as the final expression and then put
         the statement expression itself as the target's init
         expr. Finally, return the target expression.  */
-      tree last_expr = EXPR_STMT_EXPR (result_stmt);
-      
-      my_friendly_assert (TREE_CODE (last_expr) == TARGET_EXPR, 20030729);
-      EXPR_STMT_EXPR (result_stmt) = TREE_OPERAND (last_expr, 1);
-      TREE_OPERAND (last_expr, 1) = result;
-      result = last_expr;
+      tree init, target_expr = EXPR_STMT_EXPR (result_stmt);
+      gcc_assert (TREE_CODE (target_expr) == TARGET_EXPR);
+
+      /* The initializer will be void if the initialization is done by
+        AGGR_INIT_EXPR; propagate that out to the statement-expression as
+        a whole.  */
+      init = TREE_OPERAND (target_expr, 1);
+      type = TREE_TYPE (init);
+
+      init = maybe_cleanup_point_expr (init);
+      *result_stmt_p = init;
+
+      if (VOID_TYPE_P (type))
+       /* No frobbing needed.  */;
+      else if (TREE_CODE (result) == BIND_EXPR)
+       {
+         /* The BIND_EXPR created in finish_compound_stmt is void; if we're
+            returning a value directly, give it the appropriate type.  */
+         if (VOID_TYPE_P (TREE_TYPE (result)))
+           TREE_TYPE (result) = type;
+         else
+           gcc_assert (same_type_p (TREE_TYPE (result), type));
+       }
+      else if (TREE_CODE (result) == STATEMENT_LIST)
+       /* We need to wrap a STATEMENT_LIST in a BIND_EXPR so it can have a
+          type other than void.  FIXME why can't we just return a value
+          from STATEMENT_LIST?  */
+       result = build3 (BIND_EXPR, type, NULL, result, NULL);
+
+      TREE_OPERAND (target_expr, 1) = result;
+      result = target_expr;
     }
+
   return result;
 }
 
@@ -1618,8 +1736,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
     return error_mark_node;
 
   /* ARGS should be a list of arguments.  */
-  my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST,
-                     20020712);
+  gcc_assert (!args || TREE_CODE (args) == TREE_LIST);
 
   orig_fn = fn;
   orig_args = args;
@@ -1629,7 +1746,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
       if (type_dependent_expression_p (fn)
          || any_type_dependent_arguments_p (args))
        {
-         result = build_nt (CALL_EXPR, fn, args);
+         result = build_nt (CALL_EXPR, fn, args, NULL_TREE);
          KOENIG_LOOKUP_P (result) = koenig_p;
          return result;
        }
@@ -1704,7 +1821,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
       if (processing_template_decl)
        {
          if (type_dependent_expression_p (object))
-           return build_nt (CALL_EXPR, orig_fn, orig_args);
+           return build_nt (CALL_EXPR, orig_fn, orig_args, NULL_TREE);
          object = build_non_dependent_expr (object);
        }
 
@@ -1729,14 +1846,16 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
   else if (CLASS_TYPE_P (TREE_TYPE (fn)))
     /* If the "function" is really an object of class type, it might
        have an overloaded `operator ()'.  */
-    result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
+    result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE,
+                          /*overloaded_p=*/NULL);
   if (!result)
     /* A call where the function is unknown.  */
     result = build_function_call (fn, args);
 
   if (processing_template_decl)
     {
-      result = build (CALL_EXPR, TREE_TYPE (result), orig_fn, orig_args);
+      result = build3 (CALL_EXPR, TREE_TYPE (result), orig_fn,
+                      orig_args, NULL_TREE);
       KOENIG_LOOKUP_P (result) = koenig_p;
     }
   return result;
@@ -1766,15 +1885,15 @@ finish_this_expr (void)
   else if (current_function_decl
           && DECL_STATIC_FUNCTION_P (current_function_decl))
     {
-      error ("`this' is unavailable for static member functions");
+      error ("%<this%> is unavailable for static member functions");
       result = error_mark_node;
     }
   else
     {
       if (current_function_decl)
-       error ("invalid use of `this' in non-member function");
+       error ("invalid use of %<this%> in non-member function");
       else
-       error ("invalid use of `this' at top level");
+       error ("invalid use of %<this%> at top level");
       result = error_mark_node;
     }
 
@@ -1792,7 +1911,7 @@ finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
   if (destructor == error_mark_node)
     return error_mark_node;
 
-  my_friendly_assert (TYPE_P (destructor), 20010905);
+  gcc_assert (TYPE_P (destructor));
 
   if (!processing_template_decl)
     {
@@ -1802,14 +1921,28 @@ finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
          return error_mark_node;
        }
       
-      if (!same_type_p (TREE_TYPE (object), destructor))
+      /* [expr.pseudo] says both:
+
+           The type designated by the pseudo-destructor-name shall be
+          the same as the object type.
+
+         and:
+
+           The cv-unqualified versions of the object type and of the
+          type designated by the pseudo-destructor-name shall be the
+          same type.
+
+         We implement the more generous second sentence, since that is
+         what most other compilers do.  */
+      if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (object), 
+                                                     destructor))
        {
-         error ("`%E' is not of type `%T'", object, destructor);
+         error ("%qE is not of type %qT", object, destructor);
          return error_mark_node;
        }
     }
 
-  return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope, destructor);
+  return build3 (PSEUDO_DTOR_EXPR, void_type_node, object, scope, destructor);
 }
 
 /* Finish an expression of the form CODE EXPR.  */
@@ -1823,9 +1956,14 @@ finish_unary_op_expr (enum tree_code code, tree expr)
      setting TREE_NEGATED_INT.  */
   if (code == NEGATE_EXPR && TREE_CODE (expr) == INTEGER_CST
       && TREE_CODE (result) == INTEGER_CST
-      && !TREE_UNSIGNED (TREE_TYPE (result))
+      && !TYPE_UNSIGNED (TREE_TYPE (result))
       && INT_CST_LT (result, integer_zero_node))
-    TREE_NEGATED_INT (result) = 1;
+    {
+      /* RESULT may be a cached INTEGER_CST, so we must copy it before
+        setting TREE_NEGATED_INT.  */
+      result = copy_node (result);
+      TREE_NEGATED_INT (result) = 1;
+    }
   overflow_warning (result);
   return result;
 }
@@ -1875,23 +2013,6 @@ finish_fname (tree id)
   return decl;
 }
 
-/* Begin a function definition declared with DECL_SPECS, ATTRIBUTES,
-   and DECLARATOR.  Returns nonzero if the function-declaration is
-   valid.  */
-
-int
-begin_function_definition (tree decl_specs, tree attributes, tree declarator)
-{
-  if (!start_function (decl_specs, declarator, attributes, SF_DEFAULT))
-    return 0;
-
-  /* The things we're about to see are not directly qualified by any
-     template headers we've seen thus far.  */
-  reset_specialization ();
-
-  return 1;
-}
-
 /* Finish a translation unit.  */
 
 void 
@@ -1915,7 +2036,7 @@ finish_template_type_parm (tree aggr, tree identifier)
 {
   if (aggr != class_type_node)
     {
-      pedwarn ("template type parameters must use the keyword `class' or `typename'");
+      pedwarn ("template type parameters must use the keyword %<class%> or %<typename%>");
       aggr = class_type_node;
     }
 
@@ -1935,7 +2056,7 @@ finish_template_template_parm (tree aggr, tree identifier)
   DECL_ARTIFICIAL (decl) = 1;
   end_template_decl ();
 
-  my_friendly_assert (DECL_TEMPLATE_PARMS (tmpl), 20010110);
+  gcc_assert (DECL_TEMPLATE_PARMS (tmpl));
 
   return finish_template_type_parm (aggr, tmpl);
 }
@@ -1959,10 +2080,10 @@ check_template_template_default_arg (tree argument)
             that the user is using a template instantiation.  */
          if (CLASSTYPE_TEMPLATE_INFO (t) 
              && CLASSTYPE_TEMPLATE_INSTANTIATION (t))
-           error ("invalid use of type `%T' as a default value for a "
+           error ("invalid use of type %qT as a default value for a "
                   "template template-parameter", t);
          else
-           error ("invalid use of `%D' as a default value for a template "
+           error ("invalid use of %qD as a default value for a template "
                   "template-parameter", argument);
        }
       else
@@ -1973,24 +2094,6 @@ check_template_template_default_arg (tree argument)
   return argument;
 }
 
-/* Finish a parameter list, indicated by PARMS.  If ELLIPSIS is
-   nonzero, the parameter list was terminated by a `...'.  */
-
-tree
-finish_parmlist (tree parms, int ellipsis)
-{
-  if (parms)
-    {
-      /* We mark the PARMS as a parmlist so that declarator processing can
-         disambiguate certain constructs.  */
-      TREE_PARMLIST (parms) = 1;
-      /* We do not append void_list_node here, but leave it to grokparms
-         to do that.  */
-      PARMLIST_ELLIPSIS_P (parms) = ellipsis;
-    }
-  return parms;
-}
-
 /* Begin a class definition, as indicated by T.  */
 
 tree
@@ -2001,7 +2104,7 @@ begin_class_definition (tree t)
 
   if (processing_template_parmlist)
     {
-      error ("definition of `%#T' inside template parameter list", t);
+      error ("definition of %q#T inside template parameter list", t);
       return error_mark_node;
     }
   /* A non-implicit typename comes from code like:
@@ -2012,7 +2115,7 @@ begin_class_definition (tree t)
      This is erroneous.  */
   else if (TREE_CODE (t) == TYPENAME_TYPE)
     {
-      error ("invalid definition of qualified type `%T'", t);
+      error ("invalid definition of qualified type %qT", t);
       t = error_mark_node;
     }
 
@@ -2022,15 +2125,6 @@ begin_class_definition (tree t)
       pushtag (make_anon_name (), t, 0);
     }
 
-  /* If this type was already complete, and we see another definition,
-     that's an error.  */
-  if (COMPLETE_TYPE_P (t))
-    {
-      error ("redefinition of `%#T'", t);
-      cp_error_at ("previous definition of `%#T'", t);
-      return error_mark_node;
-    }
-
   /* Update the location of the decl.  */
   DECL_SOURCE_LOCATION (TYPE_NAME (t)) = input_location;
   
@@ -2042,15 +2136,25 @@ begin_class_definition (tree t)
   maybe_process_partial_specialization (t);
   pushclass (t);
   TYPE_BEING_DEFINED (t) = 1;
-  TYPE_PACKED (t) = flag_pack_struct;
+  if (flag_pack_struct)
+    {
+      tree v;
+      TYPE_PACKED (t) = 1;
+      /* Even though the type is being defined for the first time
+        here, there might have been a forward declaration, so there
+        might be cv-qualified variants of T.  */
+      for (v = TYPE_NEXT_VARIANT (t); v; v = TYPE_NEXT_VARIANT (v))
+       TYPE_PACKED (v) = 1;
+    }
   /* Reset the interface data, at the earliest possible
      moment, as it might have been set via a class foo;
      before.  */
   if (! TYPE_ANONYMOUS_P (t))
     {
-      CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
+      struct c_fileinfo *finfo = get_fileinfo (lbasename (input_filename));
+      CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only;
       SET_CLASSTYPE_INTERFACE_UNKNOWN_X
-       (t, interface_unknown);
+       (t, finfo->interface_unknown);
     }
   reset_specialization();
   
@@ -2074,7 +2178,7 @@ finish_member_declaration (tree decl)
     return;
 
   /* We should see only one DECL at a time.  */
-  my_friendly_assert (TREE_CHAIN (decl) == NULL_TREE, 0);
+  gcc_assert (TREE_CHAIN (decl) == NULL_TREE);
 
   /* Set up access control for DECL.  */
   TREE_PRIVATE (decl) 
@@ -2105,7 +2209,7 @@ finish_member_declaration (tree decl)
     {
       /* We also need to add this function to the
         CLASSTYPE_METHOD_VEC.  */
-      add_method (current_class_type, decl, /*error_p=*/0);
+      add_method (current_class_type, decl);
 
       TREE_CHAIN (decl) = TYPE_METHODS (current_class_type);
       TYPE_METHODS (current_class_type) = decl;
@@ -2146,36 +2250,40 @@ finish_member_declaration (tree decl)
       maybe_add_class_template_decl_list (current_class_type, decl, 
                                          /*friend_p=*/0);
     }
+
+  if (pch_file)
+    note_decl_for_pch (decl);
 }
 
-/* Finish processing the declaration of a member class template
-   TYPES whose template parameters are given by PARMS.  */
+/* DECL has been declared while we are building a PCH file.  Perform
+   actions that we might normally undertake lazily, but which can be
+   performed now so that they do not have to be performed in
+   translation units which include the PCH file.  */
 
-tree
-finish_member_class_template (tree types)
+void
+note_decl_for_pch (tree decl)
 {
-  tree t;
+  gcc_assert (pch_file);
 
-  /* If there are declared, but undefined, partial specializations
-     mixed in with the typespecs they will not yet have passed through
-     maybe_process_partial_specialization, so we do that here.  */
-  for (t = types; t != NULL_TREE; t = TREE_CHAIN (t))
-    if (IS_AGGR_TYPE_CODE (TREE_CODE (TREE_VALUE (t))))
-      maybe_process_partial_specialization (TREE_VALUE (t));
-
-  grok_x_components (types);
-  if (TYPE_CONTEXT (TREE_VALUE (types)) != current_class_type)
-    /* The component was in fact a friend declaration.  We avoid
-       finish_member_template_decl performing certain checks by
-       unsetting TYPES.  */
-    types = NULL_TREE;
+  /* A non-template inline function with external linkage will always
+     be COMDAT.  As we must eventually determine the linkage of all
+     functions, and as that causes writes to the data mapped in from
+     the PCH file, it's advantageous to mark the functions at this
+     point.  */
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && TREE_PUBLIC (decl)
+      && DECL_DECLARED_INLINE_P (decl)
+      && !DECL_IMPLICIT_INSTANTIATION (decl))
+    {
+      comdat_linkage (decl);
+      DECL_INTERFACE_KNOWN (decl) = 1;
+    }
   
-  finish_member_template_decl (types);
-
-  /* As with other component type declarations, we do
-     not store the new DECL on the list of
-     component_decls.  */
-  return NULL_TREE;
+  /* There's a good chance that we'll have to mangle names at some
+     point, even if only for emission in debugging information.  */
+  if (TREE_CODE (decl) == VAR_DECL
+      || TREE_CODE (decl) == FUNCTION_DECL)
+    mangle_decl (decl);
 }
 
 /* Finish processing a complete template declaration.  The PARMS are
@@ -2213,7 +2321,8 @@ finish_template_type (tree name, tree args, int entering_scope)
    Return a TREE_LIST containing the ACCESS_SPECIFIER and the
    BASE_CLASS, or NULL_TREE if an error occurred.  The
    ACCESS_SPECIFIER is one of
-   access_{default,public,protected_private}[_virtual]_node.*/
+   access_{default,public,protected_private}_node.  For a virtual base
+   we set TREE_TYPE.  */
 
 tree 
 finish_base_specifier (tree base, tree access, bool virtual_p)
@@ -2231,57 +2340,39 @@ finish_base_specifier (tree base, tree access, bool virtual_p)
     {
       if (cp_type_quals (base) != 0)
         {
-          error ("base class `%T' has cv qualifiers", base);
+          error ("base class %qT has cv qualifiers", base);
           base = TYPE_MAIN_VARIANT (base);
         }
       result = build_tree_list (access, base);
-      TREE_VIA_VIRTUAL (result) = virtual_p;
+      if (virtual_p)
+       TREE_TYPE (result) = integer_type_node;
     }
 
   return result;
 }
 
-/* Called when multiple declarators are processed.  If that is not
-   permitted in this context, an error is issued.  */
+/* Issue a diagnostic that NAME cannot be found in SCOPE.  DECL is
+   what we found when we tried to do the lookup.  */
 
 void
-check_multiple_declarators (void)
-{
-  /* [temp]
-     
-     In a template-declaration, explicit specialization, or explicit
-     instantiation the init-declarator-list in the declaration shall
-     contain at most one declarator.  
-
-     We don't just use PROCESSING_TEMPLATE_DECL for the first
-     condition since that would disallow the perfectly valid code, 
-     like `template <class T> struct S { int i, j; };'.  */
-  if (at_function_scope_p ())
-    /* It's OK to write `template <class T> void f() { int i, j;}'.  */
-    return;
-     
-  if (PROCESSING_REAL_TEMPLATE_DECL_P () 
-      || processing_explicit_instantiation
-      || processing_specialization)
-    error ("multiple declarators in template declaration");
-}
-
-/* Issue a diagnostic that NAME cannot be found in SCOPE.  */
-
-void
-qualified_name_lookup_error (tree scope, tree name)
+qualified_name_lookup_error (tree scope, tree name, tree decl)
 {
   if (TYPE_P (scope))
     {
       if (!COMPLETE_TYPE_P (scope))
-       error ("incomplete type `%T' used in nested name specifier", scope);
+       error ("incomplete type %qT used in nested name specifier", scope);
+      else if (TREE_CODE (decl) == TREE_LIST)
+       {
+         error ("reference to %<%T::%D%> is ambiguous", scope, name);
+         print_candidates (decl);
+       }
       else
-       error ("`%D' is not a member of `%T'", name, scope);
+       error ("%qD is not a member of %qT", name, scope);
     }
   else if (scope != global_namespace)
-    error ("`%D' is not a member of `%D'", name, scope);
+    error ("%qD is not a member of %qD", name, scope);
   else
-    error ("`::%D' has not been declared", name);
+    error ("%<::%D%> has not been declared", name);
 }
              
 /* ID_EXPRESSION is a representation of parsed, but unprocessed,
@@ -2340,12 +2431,17 @@ finish_id_expression (tree id_expression,
       if (decl == error_mark_node)
        {
          /* Name lookup failed.  */
-         if (scope && (!TYPE_P (scope) || !dependent_type_p (scope)))
+         if (scope 
+             && (!TYPE_P (scope) 
+                 || (!dependent_type_p (scope)
+                     && !(TREE_CODE (id_expression) == IDENTIFIER_NODE
+                          && IDENTIFIER_TYPENAME_P (id_expression)
+                          && dependent_type_p (TREE_TYPE (id_expression))))))
            {
-             /* Qualified name lookup failed, and the qualifying name
-                was not a dependent type.  That is always an
-                error.  */
-             qualified_name_lookup_error (scope, id_expression);
+             /* If the qualifying type is non-dependent (and the name
+                does not name a conversion operator to a dependent
+                type), issue an error.  */
+             qualified_name_lookup_error (scope, id_expression, decl);
              return error_mark_node;
            }
          else if (!scope)
@@ -2354,6 +2450,8 @@ finish_id_expression (tree id_expression,
              *idk = CP_ID_KIND_UNQUALIFIED;
              return id_expression;
            }
+         else
+           decl = id_expression;
        }
       /* If DECL is a variable that would be out of scope under
         ANSI/ISO rules, but in scope in the ARM, name lookup
@@ -2389,20 +2487,24 @@ finish_id_expression (tree id_expression,
   if ((TREE_CODE (decl) == CONST_DECL && DECL_TEMPLATE_PARM_P (decl))
       || TREE_CODE (decl) == TEMPLATE_PARM_INDEX)
     {
+      tree r;
+      
       *idk = CP_ID_KIND_NONE;
       if (TREE_CODE (decl) == TEMPLATE_PARM_INDEX)
        decl = TEMPLATE_PARM_DECL (decl);
+      r = convert_from_reference (DECL_INITIAL (decl));
+      
       if (integral_constant_expression_p 
          && !dependent_type_p (TREE_TYPE (decl))
-         && !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))) 
+         && !(INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (r))))
        {
          if (!allow_non_integral_constant_expression_p)
-           error ("template parameter `%D' of type `%T' is not allowed in "
+           error ("template parameter %qD of type %qT is not allowed in "
                   "an integral constant expression because it is not of "
                   "integral or enumeration type", decl, TREE_TYPE (decl));
          *non_integral_constant_expression_p = true;
        }
-      return DECL_INITIAL (decl);
+      return r;
     }
   /* Similarly, we resolve enumeration constants to their 
      underlying values.  */
@@ -2509,68 +2611,68 @@ finish_id_expression (tree id_expression,
              if (TYPE_P (scope) && dependent_type_p (scope))
                return build_nt (SCOPE_REF, scope, id_expression);
              else if (TYPE_P (scope) && DECL_P (decl))
-               return build (SCOPE_REF, TREE_TYPE (decl), scope,
-                             id_expression);
+               return convert_from_reference
+                 (build2 (SCOPE_REF, TREE_TYPE (decl), scope, id_expression));
              else
-               return decl;
+               return convert_from_reference (decl);
            }
          /* A TEMPLATE_ID already contains all the information we
             need.  */
          if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR)
            return id_expression;
-         /* Since this name was dependent, the expression isn't
-            constant -- yet.  No error is issued because it might be
-            constant when things are instantiated.  */
-         if (integral_constant_expression_p)
-           *non_integral_constant_expression_p = true;
          *idk = CP_ID_KIND_UNQUALIFIED_DEPENDENT;
          /* If we found a variable, then name lookup during the
             instantiation will always resolve to the same VAR_DECL
             (or an instantiation thereof).  */
          if (TREE_CODE (decl) == VAR_DECL
              || TREE_CODE (decl) == PARM_DECL)
-           return decl;
+           return convert_from_reference (decl);
+         /* The same is true for FIELD_DECL, but we also need to
+            make sure that the syntax is correct.  */
+         else if (TREE_CODE (decl) == FIELD_DECL)
+           {
+             /* Since SCOPE is NULL here, this is an unqualified name.
+                Access checking has been performed during name lookup
+                already.  Turn off checking to avoid duplicate errors.  */
+             push_deferring_access_checks (dk_no_check);
+             decl = finish_non_static_data_member
+                      (decl, current_class_ref,
+                       /*qualifying_scope=*/NULL_TREE);
+             pop_deferring_access_checks ();
+             return decl;
+           }
          return id_expression;
        }
 
       /* Only certain kinds of names are allowed in constant
-       expression.  Enumerators and template parameters 
-       have already been handled above.  */
-      if (integral_constant_expression_p)
+         expression.  Enumerators and template parameters have already
+         been handled above.  */
+      if (integral_constant_expression_p
+         && ! DECL_INTEGRAL_CONSTANT_VAR_P (decl)
+         && ! builtin_valid_in_constant_expr_p (decl))
        {
-           /* Const variables or static data members of integral or
-             enumeration types initialized with constant expressions
-             are OK.  */
-         if (TREE_CODE (decl) == VAR_DECL
-             && CP_TYPE_CONST_P (TREE_TYPE (decl))
-             && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))
-             && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
-           ;
-         else
+         if (!allow_non_integral_constant_expression_p)
            {
-             if (!allow_non_integral_constant_expression_p)
-               {
-                 error ("`%D' cannot appear in a constant-expression", decl);
-                 return error_mark_node;
-               }
-             *non_integral_constant_expression_p = true;
+             error ("%qD cannot appear in a constant-expression", decl);
+             return error_mark_node;
            }
+         *non_integral_constant_expression_p = true;
        }
       
       if (TREE_CODE (decl) == NAMESPACE_DECL)
        {
-         error ("use of namespace `%D' as expression", decl);
+         error ("use of namespace %qD as expression", decl);
          return error_mark_node;
        }
       else if (DECL_CLASS_TEMPLATE_P (decl))
        {
-         error ("use of class template `%T' as expression", decl);
+         error ("use of class template %qT as expression", decl);
          return error_mark_node;
        }
       else if (TREE_CODE (decl) == TREE_LIST)
        {
          /* Ambiguous reference to base members.  */
-         error ("request for member `%D' is ambiguous in "
+         error ("request for member %qD is ambiguous in "
                 "multiple inheritance lattice", id_expression);
          print_candidates (decl);
          return error_mark_node;
@@ -2593,14 +2695,26 @@ finish_id_expression (tree id_expression,
 
          if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl))
            *qualifying_class = scope;
-         else if (!processing_template_decl)
-           decl = convert_from_reference (decl);
-         else if (TYPE_P (scope))
-           decl = build (SCOPE_REF, TREE_TYPE (decl), scope, decl);
+         else
+           {
+             tree r = convert_from_reference (decl);
+             
+             if (processing_template_decl
+                 && TYPE_P (scope))
+               r = build2 (SCOPE_REF, TREE_TYPE (r), scope, decl);
+             decl = r;
+           }
        }
       else if (TREE_CODE (decl) == FIELD_DECL)
-       decl = finish_non_static_data_member (decl, current_class_ref,
-                                             /*qualifying_scope=*/NULL_TREE);
+       {
+         /* Since SCOPE is NULL here, this is an unqualified name.
+            Access checking has been performed during name lookup
+            already.  Turn off checking to avoid duplicate errors.  */
+         push_deferring_access_checks (dk_no_check);
+         decl = finish_non_static_data_member (decl, current_class_ref,
+                                               /*qualifying_scope=*/NULL_TREE);
+         pop_deferring_access_checks ();
+       }
       else if (is_overloaded_fn (decl))
        {
          tree first_fn = OVL_CURRENT (decl);
@@ -2612,7 +2726,8 @@ finish_id_expression (tree id_expression,
            mark_used (first_fn);
 
          if (TREE_CODE (first_fn) == FUNCTION_DECL
-             && DECL_FUNCTION_MEMBER_P (first_fn))
+             && DECL_FUNCTION_MEMBER_P (first_fn)
+             && !shared_member_p (decl))
            {
              /* A set of member functions.  */
              decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
@@ -2632,8 +2747,8 @@ finish_id_expression (tree id_expression,
                {
                  error ("use of %s from containing function",
                         (TREE_CODE (decl) == VAR_DECL
-                         ? "`auto' variable" : "parameter"));
-                 cp_error_at ("  `%#D' declared here", decl);
+                         ? "%<auto%> variable" : "parameter"));
+                 cp_error_at ("  %q#D declared here", decl);
                  return error_mark_node;
                }
            }
@@ -2648,14 +2763,13 @@ finish_id_expression (tree id_expression,
              perform_or_defer_access_check (TYPE_BINFO (path), decl);
            }
          
-         if (! processing_template_decl)
-           decl = convert_from_reference (decl);
+         decl = convert_from_reference (decl);
        }
       
       /* Resolve references to variables of anonymous unions
         into COMPONENT_REFs.  */
       if (TREE_CODE (decl) == ALIAS_DECL)
-       decl = DECL_INITIAL (decl);
+       decl = unshare_expr (DECL_INITIAL (decl));
     }
 
   if (TREE_DEPRECATED (decl))
@@ -2675,7 +2789,7 @@ finish_typeof (tree expr)
   if (type_dependent_expression_p (expr))
     {
       type = make_aggr_type (TYPEOF_TYPE);
-      TYPE_FIELDS (type) = expr;
+      TYPEOF_TYPE_EXPR (type) = expr;
 
       return type;
     }
@@ -2684,44 +2798,15 @@ finish_typeof (tree expr)
 
   if (!type || type == unknown_type_node)
     {
-      error ("type of `%E' is unknown", expr);
+      error ("type of %qE is unknown", expr);
       return error_mark_node;
     }
 
   return type;
 }
 
-/* Generate RTL for the statement T, and its substatements, and any
-   other statements at its nesting level.  */
-
-static void
-cp_expand_stmt (tree t)
-{
-  switch (TREE_CODE (t))
-    {
-    case TRY_BLOCK:
-      genrtl_try_block (t);
-      break;
-
-    case EH_SPEC_BLOCK:
-      genrtl_eh_spec_block (t);
-      break;
-
-    case HANDLER:
-      genrtl_handler (t);
-      break;
-
-    case USING_STMT:
-      break;
-    
-    default:
-      abort ();
-      break;
-    }
-}
-
 /* Called from expand_body via walk_tree.  Replace all AGGR_INIT_EXPRs
-   will equivalent CALL_EXPRs.  */
+   with equivalent CALL_EXPRs.  */
 
 static tree
 simplify_aggr_init_exprs_r (tree* tp, 
@@ -2761,7 +2846,7 @@ simplify_aggr_init_expr (tree *tp)
   tree fn = TREE_OPERAND (aggr_init_expr, 0);
   tree args = TREE_OPERAND (aggr_init_expr, 1);
   tree slot = TREE_OPERAND (aggr_init_expr, 2);
-  tree type = TREE_TYPE (aggr_init_expr);
+  tree type = TREE_TYPE (slot);
 
   tree call_expr;
   enum style_t { ctor, arg, pcc } style;
@@ -2772,12 +2857,11 @@ simplify_aggr_init_expr (tree *tp)
   else if (1)
     style = pcc;
 #endif
-  else if (TREE_ADDRESSABLE (type))
-    style = arg;
   else
-    /* We shouldn't build an AGGR_INIT_EXPR if we don't need any special
-       handling.  See build_cplus_new.  */
-    abort ();
+    {
+      gcc_assert (TREE_ADDRESSABLE (type));
+      style = arg;
+    }
 
   if (style == ctor || style == arg)
     {
@@ -2789,25 +2873,23 @@ simplify_aggr_init_expr (tree *tp)
        args = TREE_CHAIN (args);
 
       cxx_mark_addressable (slot);
-      addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (slot)), slot);
+      addr = build1 (ADDR_EXPR, build_pointer_type (type), slot);
       if (style == arg)
        {
          /* The return type might have different cv-quals from the slot.  */
          tree fntype = TREE_TYPE (TREE_TYPE (fn));
-#ifdef ENABLE_CHECKING
-         if (TREE_CODE (fntype) != FUNCTION_TYPE
-             && TREE_CODE (fntype) != METHOD_TYPE)
-           abort ();
-#endif
+         
+         gcc_assert (TREE_CODE (fntype) == FUNCTION_TYPE
+                     || TREE_CODE (fntype) == METHOD_TYPE);
          addr = convert (build_pointer_type (TREE_TYPE (fntype)), addr);
        }
 
       args = tree_cons (NULL_TREE, addr, args);
     }
 
-  call_expr = build (CALL_EXPR, 
-                    TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
-                    fn, args, NULL_TREE);
+  call_expr = build3 (CALL_EXPR, 
+                     TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
+                     fn, args, NULL_TREE);
 
   if (style == arg)
     /* Tell the backend that we've added our return slot to the argument
@@ -2824,13 +2906,6 @@ simplify_aggr_init_expr (tree *tp)
       pop_deferring_access_checks ();
     }
 
-  /* We want to use the value of the initialized location as the
-     result.  */
-  call_expr = build (COMPOUND_EXPR, type,
-                    call_expr, slot);
-
-  /* Replace the AGGR_INIT_EXPR with the CALL_EXPR.  */
-  TREE_CHAIN (call_expr) = TREE_CHAIN (aggr_init_expr);
   *tp = call_expr;
 }
 
@@ -2863,7 +2938,7 @@ emit_associated_thunks (tree fn)
                }
            }
          else
-           my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
+           gcc_assert (!DECL_THUNKS (thunk));
        }
     }
 }
@@ -2874,7 +2949,7 @@ void
 expand_body (tree fn)
 {
   tree saved_function;
-  
+
   /* Compute the appropriate object-file linkage for inline
      functions.  */
   if (DECL_DECLARED_INLINE_P (fn))
@@ -2894,28 +2969,15 @@ expand_body (tree fn)
   /* Emit any thunks that should be emitted at the same time as FN.  */
   emit_associated_thunks (fn);
 
-  timevar_push (TV_INTEGRATION);
-  optimize_function (fn);
-  timevar_pop (TV_INTEGRATION);
+  /* This function is only called from cgraph, or recursively from
+     emit_associated_thunks.  In neither case should we be currently
+     generating trees for a function.  */
+  gcc_assert (function_depth == 0);
 
-  tree_rest_of_compilation (fn, function_depth > 1);
+  tree_rest_of_compilation (fn);
 
   current_function_decl = saved_function;
 
-  extract_interface_info ();
-
-  /* If this function is marked with the constructor attribute, add it
-     to the list of functions to be called along with constructors
-     from static duration objects.  */
-  if (DECL_STATIC_CONSTRUCTOR (fn))
-    static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
-
-  /* If this function is marked with the destructor attribute, add it
-     to the list of functions to be called along with destructors from
-     static duration objects.  */
-  if (DECL_STATIC_DESTRUCTOR (fn))
-    static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
-
   if (DECL_CLONED_FUNCTION_P (fn))
     {
       /* If this is a clone, go through the other clones now and mark
@@ -2969,15 +3031,45 @@ expand_or_defer_fn (tree fn)
       return;
     }
 
+  /* If this function is marked with the constructor attribute, add it
+     to the list of functions to be called along with constructors
+     from static duration objects.  */
+  if (DECL_STATIC_CONSTRUCTOR (fn))
+    static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
+
+  /* If this function is marked with the destructor attribute, add it
+     to the list of functions to be called along with destructors from
+     static duration objects.  */
+  if (DECL_STATIC_DESTRUCTOR (fn))
+    static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
+
+  /* We make a decision about linkage for these functions at the end
+     of the compilation.  Until that point, we do not want the back
+     end to output them -- but we do want it to see the bodies of
+     these functions so that it can inline them as appropriate.  */
+  if (DECL_DECLARED_INLINE_P (fn) || DECL_IMPLICIT_INSTANTIATION (fn))
+    {
+      if (!at_eof)
+       {
+         DECL_EXTERNAL (fn) = 1;
+         DECL_NOT_REALLY_EXTERN (fn) = 1;
+         note_vague_linkage_fn (fn);
+       }
+      else
+       import_export_decl (fn);
+
+      /* If the user wants us to keep all inline functions, then mark
+        this function as needed so that finish_file will make sure to
+        output it later.  */
+      if (flag_keep_inline_functions && DECL_DECLARED_INLINE_P (fn))
+       mark_needed (fn);
+    }
+
   /* 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;
 
-  /* Compute the appropriate object-file linkage for inline functions.  */
-  if (DECL_DECLARED_INLINE_P (fn))
-    import_export_decl (fn);
-
   function_depth++;
 
   /* Expand or defer, at the whim of the compilation unit manager.  */
@@ -2986,37 +3078,94 @@ expand_or_defer_fn (tree fn)
   function_depth--;
 }
 
-/* Helper function for walk_tree, used by finish_function to override all
-   the RETURN_STMTs and pertinent CLEANUP_STMTs for the named return
-   value optimization.  */
+struct nrv_data
+{
+  tree var;
+  tree result;
+  htab_t visited;
+};
 
-tree
-nullify_returns_r (tree* tp, int* walk_subtrees, void* data)
+/* Helper function for walk_tree, used by finalize_nrv below.  */
+
+static tree
+finalize_nrv_r (tree* tp, int* walk_subtrees, void* data)
 {
-  tree nrv = (tree) data;
+  struct nrv_data *dp = (struct nrv_data *)data;
+  void **slot;
 
   /* No need to walk into types.  There wouldn't be any need to walk into
      non-statements, except that we have to consider STMT_EXPRs.  */
   if (TYPE_P (*tp))
     *walk_subtrees = 0;
-  else if (TREE_CODE (*tp) == RETURN_STMT)
-    RETURN_STMT_EXPR (*tp) = NULL_TREE;
+  /* Change all returns to just refer to the RESULT_DECL; this is a nop,
+     but differs from using NULL_TREE in that it indicates that we care
+     about the value of the RESULT_DECL.  */
+  else if (TREE_CODE (*tp) == RETURN_EXPR)
+    TREE_OPERAND (*tp, 0) = dp->result;
+  /* Change all cleanups for the NRV to only run when an exception is
+     thrown.  */
   else if (TREE_CODE (*tp) == CLEANUP_STMT
-          && CLEANUP_DECL (*tp) == nrv)
+          && CLEANUP_DECL (*tp) == dp->var)
     CLEANUP_EH_ONLY (*tp) = 1;
+  /* Replace the DECL_EXPR for the NRV with an initialization of the
+     RESULT_DECL, if needed.  */
+  else if (TREE_CODE (*tp) == DECL_EXPR
+          && DECL_EXPR_DECL (*tp) == dp->var)
+    {
+      tree init;
+      if (DECL_INITIAL (dp->var)
+         && DECL_INITIAL (dp->var) != error_mark_node)
+       {
+         init = build2 (INIT_EXPR, void_type_node, dp->result,
+                        DECL_INITIAL (dp->var));
+         DECL_INITIAL (dp->var) = error_mark_node;
+       }
+      else
+       init = build_empty_stmt ();
+      SET_EXPR_LOCUS (init, EXPR_LOCUS (*tp));
+      *tp = init;
+    }
+  /* And replace all uses of the NRV with the RESULT_DECL.  */
+  else if (*tp == dp->var)
+    *tp = dp->result;
+
+  /* Avoid walking into the same tree more than once.  Unfortunately, we
+     can't just use walk_tree_without duplicates because it would only call
+     us for the first occurrence of dp->var in the function body.  */
+  slot = htab_find_slot (dp->visited, *tp, INSERT);
+  if (*slot)
+    *walk_subtrees = 0;
+  else
+    *slot = *tp;
 
   /* Keep iterating.  */
   return NULL_TREE;
 }
 
-/* Start generating the RTL for FN.  */
+/* Called from finish_function to implement the named return value
+   optimization by overriding all the RETURN_EXPRs and pertinent
+   CLEANUP_STMTs and replacing all occurrences of VAR with RESULT, the
+   RESULT_DECL for the function.  */
 
 void
-cxx_expand_function_start (void)
+finalize_nrv (tree *tp, tree var, tree result)
 {
-  /* Give our named return value the same RTL as our RESULT_DECL.  */
-  if (current_function_return_value)
-    COPY_DECL_RTL (DECL_RESULT (cfun->decl), current_function_return_value);
+  struct nrv_data data;
+
+  /* Copy debugging information from VAR to RESULT.  */
+  DECL_NAME (result) = DECL_NAME (var);
+  DECL_ARTIFICIAL (result) = DECL_ARTIFICIAL (var);
+  DECL_IGNORED_P (result) = DECL_IGNORED_P (var);
+  DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (var);
+  DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (var);
+  /* Don't forget that we take its address.  */
+  TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (var);
+
+  data.var = var;
+  data.result = result;
+  data.visited = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
+  walk_tree (tp, finalize_nrv_r, &data, 0);
+  htab_delete (data.visited);
 }
 
 /* Perform initialization related to this module.  */
@@ -3024,7 +3173,6 @@ cxx_expand_function_start (void)
 void
 init_cp_semantics (void)
 {
-  lang_expand_stmt = cp_expand_stmt;
 }
 
 #include "gt-cp-semantics.h"