OSDN Git Service

* attribs.c (strip_attrs): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / cp / semantics.c
index 9142a2c..cadb5a7 100644 (file)
@@ -3,8 +3,8 @@
    building RTL.  These routines are used both during actual parsing
    and during the instantiation of template functions. 
 
    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
+   Free Software Foundation, Inc.
    Written by Mark Mitchell (mmitchell@usa.net) based on code found
    formerly in parse.y and pt.c.  
 
    Written by Mark Mitchell (mmitchell@usa.net) based on code found
    formerly in parse.y and pt.c.  
 
@@ -32,8 +32,8 @@
 #include "tree.h"
 #include "cp-tree.h"
 #include "tree-inline.h"
 #include "tree.h"
 #include "cp-tree.h"
 #include "tree-inline.h"
+#include "tree-mudflap.h"
 #include "except.h"
 #include "except.h"
-#include "lex.h"
 #include "toplev.h"
 #include "flags.h"
 #include "rtl.h"
 #include "toplev.h"
 #include "flags.h"
 #include "rtl.h"
 #include "output.h"
 #include "timevar.h"
 #include "debug.h"
 #include "output.h"
 #include "timevar.h"
 #include "debug.h"
+#include "diagnostic.h"
 #include "cgraph.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
 
 /* 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 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
    ---------------------------------
 
 /* Deferred Access Checking Overview
    ---------------------------------
@@ -129,9 +113,36 @@ static void cp_expand_stmt (tree);
       In case of parsing error, we simply call `pop_deferring_access_checks'
       without `perform_deferred_access_checks'.  */
 
       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_O (deferred_access);
+
 /* Data for deferred access checking.  */
 /* 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.  */
 
 /* Save the current deferred access states and start deferred
    access checking iff DEFER_P is true.  */
@@ -139,27 +150,18 @@ static GTY(()) deferred_access *deferred_access_free_list;
 void
 push_deferring_access_checks (deferring_kind deferring)
 {
 void
 push_deferring_access_checks (deferring_kind deferring)
 {
-  deferred_access *d;
-
   /* For context like template instantiation, access checking
      disabling applies to all nested context.  */
   /* 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
   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
 }
 
 /* Resume deferring access checks again after we stopped doing
@@ -168,8 +170,9 @@ push_deferring_access_checks (deferring_kind deferring)
 void
 resume_deferring_access_checks (void)
 {
 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.  */
 }
 
 /* Stop deferring access checks.  */
@@ -177,8 +180,9 @@ resume_deferring_access_checks (void)
 void
 stop_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
 }
 
 /* Discard the current deferred access checks and restore the
@@ -187,15 +191,10 @@ stop_deferring_access_checks (void)
 void
 pop_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.  
 }
 
 /* Returns a TREE_LIST representing the deferred checks.  
@@ -206,7 +205,11 @@ pop_deferring_access_checks (void)
 tree
 get_deferred_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
 }
 
 /* Take current deferred checks and combine with the
@@ -216,27 +219,48 @@ get_deferred_access_checks (void)
 void
 pop_to_parent_deferring_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.
 }
 
 /* Perform the deferred access checks.
@@ -259,7 +283,9 @@ void
 perform_deferred_access_checks (void)
 {
   tree deferred_check;
 perform_deferred_access_checks (void)
 {
   tree deferred_check;
-  for (deferred_check = deferred_access_stack->deferred_access_checks;
+
+  for (deferred_check = (VEC_last (deferred_access, deferred_access_stack)
+                        ->deferred_access_checks);
        deferred_check;
        deferred_check = TREE_CHAIN (deferred_check))
     /* Check access.  */
        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;
 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 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;
     }
     {
       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.  */
   /* 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.  */
        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,
 }
 
 /* Returns nonzero if the current statement is a full expression,
@@ -321,6 +351,27 @@ current_stmt_tree (void)
          : &scope_chain->x_stmt_tree);
 }
 
          : &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 (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (expr), 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))
+    r = maybe_cleanup_point_expr (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].  */
 /* 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 +384,102 @@ anon_aggr_type_p (tree node)
 
 /* Finish a scope.  */
 
 
 /* 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 ())
 
   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.  */ 
 
 }
 
 /* Begin a new scope.  */ 
 
-void
+static tree
 do_pushlevel (scope_kind sk)
 {
 do_pushlevel (scope_kind sk)
 {
+  tree ret = push_stmt_list ();
   if (stmts_are_full_exprs_p ())
   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.  */
 }
 
 /* Finish a goto-statement.  */
@@ -398,7 +508,7 @@ finish_goto_stmt (tree destination)
   
   check_goto (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.,
 }
 
 /* COND is the condition-expression for an if, while, etc.,
@@ -430,11 +540,24 @@ finish_expr_stmt (tree expr)
   if (expr != NULL_TREE)
     {
       if (!processing_template_decl)
   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");
       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 the 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 (expr);
+       }
+
+      r = add_stmt (expr);
     }
 
   finish_stmt ();
     }
 
   finish_stmt ();
@@ -449,10 +572,11 @@ finish_expr_stmt (tree expr)
 tree
 begin_if_stmt (void)
 {
 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);
   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;
 }
 
   return r;
 }
 
@@ -462,8 +586,9 @@ begin_if_stmt (void)
 void 
 finish_if_stmt_cond (tree cond, tree if_stmt)
 {
 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
 }
 
 /* Finish the then-clause of an if-statement, which may be given by
@@ -472,15 +597,16 @@ finish_if_stmt_cond (tree cond, tree if_stmt)
 tree
 finish_then_clause (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.  */
 
   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
 }
 
 /* Finish the else-clause of an if-statement, which may be given by
@@ -489,16 +615,18 @@ begin_else_clause (void)
 void
 finish_else_clause (tree if_stmt)
 {
 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 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 ();
   finish_stmt ();
-  do_poplevel ();
 }
 
 /* Begin a while-statement.  Returns a newly created WHILE_STMT if
 }
 
 /* Begin a while-statement.  Returns a newly created WHILE_STMT if
@@ -510,7 +638,8 @@ begin_while_stmt (void)
   tree r;
   r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
   add_stmt (r);
   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;
 }
 
   return r;
 }
 
@@ -520,30 +649,8 @@ begin_while_stmt (void)
 void 
 finish_while_stmt_cond (tree cond, tree while_stmt)
 {
 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.  */
 }
 
 /* Finish a while-statement, which may be given by WHILE_STMT.  */
@@ -551,8 +658,7 @@ finish_while_stmt_cond (tree cond, tree while_stmt)
 void 
 finish_while_stmt (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 ();
 }
 
   finish_stmt ();
 }
 
@@ -564,6 +670,7 @@ begin_do_stmt (void)
 {
   tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE);
   add_stmt (r);
 {
   tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE);
   add_stmt (r);
+  DO_BODY (r) = push_stmt_list ();
   return r;
 }
 
   return r;
 }
 
@@ -572,7 +679,7 @@ begin_do_stmt (void)
 void
 finish_do_body (tree do_stmt)
 {
 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
 }
 
 /* Finish a do-statement, which may be given by DO_STMT, and whose
@@ -597,16 +704,21 @@ finish_return_stmt (tree expr)
   expr = check_return_expr (expr);
   if (!processing_template_decl)
     {
   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.  */
        {
          /* 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 (r);
+  r = add_stmt (r);
   finish_stmt ();
 
   return r;
   finish_stmt ();
 
   return r;
@@ -621,10 +733,12 @@ begin_for_stmt (void)
 
   r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, 
                  NULL_TREE, NULL_TREE);
 
   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;
 }
 
   return r;
 }
@@ -635,9 +749,11 @@ begin_for_stmt (void)
 void
 finish_for_init_stmt (tree for_stmt)
 {
 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
 }
 
 /* Finish the COND of a for-statement, which may be given by
@@ -646,30 +762,8 @@ finish_for_init_stmt (tree for_stmt)
 void
 finish_for_cond (tree cond, 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
 }
 
 /* Finish the increment-EXPRESSION in a for-statement, which may be
@@ -678,13 +772,16 @@ finish_for_cond (tree cond, tree for_stmt)
 void
 finish_for_expr (tree expr, 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 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;
     }
     {
       cxx_incomplete_type_error (expr, TREE_TYPE (expr));
       expr = error_mark_node;
     }
+  expr = maybe_cleanup_point_expr (expr);
   FOR_EXPR (for_stmt) = expr;
 }
 
   FOR_EXPR (for_stmt) = expr;
 }
 
@@ -695,11 +792,16 @@ finish_for_expr (tree expr, tree for_stmt)
 void
 finish_for_stmt (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.  */
   /* 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 (); 
 }
 
   finish_stmt (); 
 }
 
@@ -725,10 +827,14 @@ finish_continue_stmt (void)
 tree
 begin_switch_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);
   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_COND (r));
+
   return r;
 }
 
   return r;
 }
 
@@ -756,7 +862,7 @@ finish_switch_cond (tree cond, tree switch_stmt)
 
             Integral promotions are performed.  */
          cond = perform_integral_promotions (cond);
 
             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)
        }
 
       if (cond != error_mark_node)
@@ -766,14 +872,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.  */
             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;
        }
     }
            cond = index;
        }
     }
-  FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
+  finish_cond (&SWITCH_COND (switch_stmt), cond);
   SWITCH_TYPE (switch_stmt) = orig_type;
   SWITCH_TYPE (switch_stmt) = orig_type;
+  add_stmt (switch_stmt);
   push_switch (switch_stmt);
   push_switch (switch_stmt);
+  SWITCH_BODY (switch_stmt) = push_stmt_list ();
 }
 
 /* Finish the body of a switch-statement, which may be given by
 }
 
 /* Finish the body of a switch-statement, which may be given by
@@ -782,60 +890,15 @@ finish_switch_cond (tree cond, tree switch_stmt)
 void
 finish_switch_stmt (tree switch_stmt)
 {
 void
 finish_switch_stmt (tree switch_stmt)
 {
-  RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt));
+  tree scope;
+
+  SWITCH_BODY (switch_stmt) = pop_stmt_list (SWITCH_BODY (switch_stmt));
   pop_switch (); 
   finish_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
 }
 
 /* Begin a try-block.  Returns a newly-created TRY_BLOCK if
@@ -846,6 +909,7 @@ begin_try_block (void)
 {
   tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
   add_stmt (r);
 {
   tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
   add_stmt (r);
+  TRY_STMTS (r) = push_stmt_list ();
   return r;
 }
 
   return r;
 }
 
@@ -854,9 +918,8 @@ begin_try_block (void)
 tree
 begin_function_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;
   FN_TRY_BLOCK_P (r) = 1;
-  add_stmt (r);
   return r;
 }
 
   return r;
 }
 
@@ -865,7 +928,8 @@ begin_function_try_block (void)
 void
 finish_try_block (tree try_block)
 {
 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
 }
 
 /* Finish the body of a cleanup try-block, which may be given by
@@ -874,7 +938,7 @@ finish_try_block (tree try_block)
 void
 finish_cleanup_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
 }
 
 /* Finish an implicitly generated try-block, with a cleanup is given
@@ -892,16 +956,9 @@ finish_cleanup (tree cleanup, tree try_block)
 void
 finish_function_try_block (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;
 }
 
   in_function_try_handler = 1;
 }
 
@@ -911,7 +968,7 @@ finish_function_try_block (tree try_block)
 void
 finish_handler_sequence (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));
 }
 
   check_handlers (TRY_HANDLERS (try_block));
 }
 
@@ -921,21 +978,7 @@ void
 finish_function_handler_sequence (tree try_block)
 {
   in_function_try_handler = 0;
 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.  */
 }
 
 /* Begin a handler.  Returns a HANDLER if appropriate.  */
@@ -944,11 +987,14 @@ tree
 begin_handler (void)
 {
   tree r;
 begin_handler (void)
 {
   tree r;
+
   r = build_stmt (HANDLER, NULL_TREE, NULL_TREE);
   add_stmt (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.  */
   /* 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;
 }
 
   return r;
 }
 
@@ -966,8 +1012,7 @@ finish_handler_parms (tree decl, tree handler)
        {
          decl = pushdecl (decl);
          decl = push_template_decl (decl);
        {
          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);
        }
     }
          type = TREE_TYPE (decl);
        }
     }
@@ -987,91 +1032,80 @@ finish_handler (tree handler)
 {
   if (!processing_template_decl)
     expand_end_catch_block ();
 {
   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
+   behaviour 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
 
 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
   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;
 }
 
 
   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
   else
-    r = do_poplevel ();
+    stmt = do_poplevel (stmt);
 
 
-  RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_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 ();
   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
 
 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;
 
 {
   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 i;
   if (!processing_template_decl)
     {
       int i;
@@ -1133,9 +1167,10 @@ finish_asm_stmt (tree cv_qualifier,
        }
     }
 
        }
     }
 
-  r = build_stmt (ASM_STMT, cv_qualifier, string,
+  r = build_stmt (ASM_EXPR, string,
                  output_operands, input_operands,
                  clobbers);
                  output_operands, input_operands,
                  clobbers);
+  ASM_VOLATILE_P (r) = volatile_p;
   return add_stmt (r);
 }
 
   return add_stmt (r);
 }
 
@@ -1145,7 +1180,7 @@ tree
 finish_label_stmt (tree name)
 {
   tree decl = define_label (input_location, name);
 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
 }
 
 /* Finish a series of declarations for local labels.  G++ allows users
@@ -1156,7 +1191,7 @@ void
 finish_label_decl (tree name)
 {
   tree decl = declare_local_label (name);
 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.  */
 }
 
 /* When DECL goes out of scope, make sure that CLEANUP is executed.  */
@@ -1164,7 +1199,7 @@ finish_label_decl (tree name)
 void 
 finish_decl_cleanup (tree decl, tree cleanup)
 {
 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.  */
 }
 
 /* If the current scope exits with an exception, run CLEANUP.  */
@@ -1172,9 +1207,7 @@ finish_decl_cleanup (tree decl, tree cleanup)
 void
 finish_eh_cleanup (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
 }
 
 /* The MEM_INITS is a list of mem-initializers, in reverse of the
@@ -1194,14 +1227,6 @@ finish_mem_initializers (tree mem_inits)
     emit_mem_initializers (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 a parenthesized expression EXPR.  */
 
 tree
@@ -1209,7 +1234,7 @@ finish_parenthesized_expr (tree expr)
 {
   if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expr))))
     /* This inhibits warnings in c_common_truthvalue_conversion.  */
 {
   if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (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
 
   if (TREE_CODE (expr) == OFFSET_REF)
     /* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be
@@ -1224,7 +1249,7 @@ finish_parenthesized_expr (tree expr)
 tree
 finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
 {
 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 (!object)
     {
@@ -1257,7 +1282,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
          type = cp_build_qualified_type (type, quals);
        }
       
          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
     {
     }
   else
     {
@@ -1315,6 +1340,10 @@ check_accessibility_of_qualified_id (tree decl,
 {
   tree scope;
   tree qualifying_type = NULL_TREE;
 {
   tree scope;
   tree qualifying_type = NULL_TREE;
+
+  /* If we're not checking, return imediately.  */
+  if (deferred_access_no_check)
+    return;
   
   /* Determine the SCOPE of DECL.  */
   scope = context_for_name_lookup (decl);
   
   /* Determine the SCOPE of DECL.  */
   scope = context_for_name_lookup (decl);
@@ -1355,7 +1384,9 @@ check_accessibility_of_qualified_id (tree decl,
        its bases.  */
     qualifying_type = currently_open_derived_class (scope);
 
        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);
 }
 
     perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl);
 }
 
@@ -1422,17 +1453,7 @@ finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
 tree 
 begin_stmt_expr (void)
 {
 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
 }
 
 /* Process the final expression of a statement expression. EXPR can be
@@ -1441,17 +1462,16 @@ begin_stmt_expr (void)
    expression.  */
 
 tree
    expression.  */
 
 tree
-finish_stmt_expr_expr (tree expr)
+finish_stmt_expr_expr (tree expr, tree stmt_expr)
 {
   tree result = NULL_TREE;
 {
   tree result = NULL_TREE;
-  tree type = void_type_node;
 
   if (expr)
     {
 
   if (expr)
     {
-      type = TREE_TYPE (expr);
-      
       if (!processing_template_decl && !VOID_TYPE_P (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);
          if (TREE_CODE (type) == ARRAY_TYPE
              || TREE_CODE (type) == FUNCTION_TYPE)
            expr = decay_conversion (expr);
@@ -1459,6 +1479,8 @@ finish_stmt_expr_expr (tree expr)
          expr = convert_from_reference (expr);
          expr = require_complete_type (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
          /* 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 +1495,25 @@ finish_stmt_expr_expr (tree expr)
              expr = build_special_member_call
                (NULL_TREE, complete_ctor_identifier,
                 build_tree_list (NULL_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);
              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);
            }
        }
 
       if (expr != error_mark_node)
        {
          result = build_stmt (EXPR_STMT, expr);
+         EXPR_STMT_STMT_EXPR_RESULT (result) = 1;
          add_stmt (result);
        }
     }
   
   finish_stmt ();
 
          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;
 }
   
   return result;
 }
@@ -1500,58 +1523,97 @@ finish_stmt_expr_expr (tree expr)
    representing the statement-expression.  */
 
 tree 
    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
     {
     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)
 
   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.  */
     {
       /* 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;
 }
 
   return result;
 }
 
@@ -1618,8 +1680,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.  */
     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;
 
   orig_fn = fn;
   orig_args = args;
@@ -1629,7 +1690,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))
        {
       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;
        }
          KOENIG_LOOKUP_P (result) = koenig_p;
          return result;
        }
@@ -1704,7 +1765,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
       if (processing_template_decl)
        {
          if (type_dependent_expression_p (object))
       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);
        }
 
          object = build_non_dependent_expr (object);
        }
 
@@ -1737,7 +1798,8 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
 
   if (processing_template_decl)
     {
 
   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;
       KOENIG_LOOKUP_P (result) = koenig_p;
     }
   return result;
@@ -1793,7 +1855,7 @@ finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
   if (destructor == error_mark_node)
     return error_mark_node;
 
   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)
     {
 
   if (!processing_template_decl)
     {
@@ -1803,14 +1865,28 @@ finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
          return error_mark_node;
        }
       
          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);
          return error_mark_node;
        }
     }
 
        {
          error ("`%E' is not of type `%T'", 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.  */
 }
 
 /* Finish an expression of the form CODE EXPR.  */
@@ -1824,7 +1900,7 @@ 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
      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;
   overflow_warning (result);
       && INT_CST_LT (result, integer_zero_node))
     TREE_NEGATED_INT (result) = 1;
   overflow_warning (result);
@@ -1876,23 +1952,6 @@ finish_fname (tree id)
   return decl;
 }
 
   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 
 /* Finish a translation unit.  */
 
 void 
@@ -1936,7 +1995,7 @@ finish_template_template_parm (tree aggr, tree identifier)
   DECL_ARTIFICIAL (decl) = 1;
   end_template_decl ();
 
   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);
 }
 
   return finish_template_type_parm (aggr, tmpl);
 }
@@ -1974,24 +2033,6 @@ check_template_template_default_arg (tree argument)
   return 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
 /* Begin a class definition, as indicated by T.  */
 
 tree
@@ -2084,7 +2125,7 @@ finish_member_declaration (tree decl)
     return;
 
   /* We should see only one DECL at a time.  */
     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) 
 
   /* Set up access control for DECL.  */
   TREE_PRIVATE (decl) 
@@ -2115,7 +2156,7 @@ finish_member_declaration (tree decl)
     {
       /* We also need to add this function to the
         CLASSTYPE_METHOD_VEC.  */
     {
       /* 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;
 
       TREE_CHAIN (decl) = TYPE_METHODS (current_class_type);
       TYPE_METHODS (current_class_type) = decl;
@@ -2158,36 +2199,6 @@ finish_member_declaration (tree decl)
     }
 }
 
     }
 }
 
-/* Finish processing the declaration of a member class template
-   TYPES whose template parameters are given by PARMS.  */
-
-tree
-finish_member_class_template (tree types)
-{
-  tree t;
-
-  /* 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;
-  
-  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;
-}
-
 /* Finish processing a complete template declaration.  The PARMS are
    the template parameters.  */
 
 /* Finish processing a complete template declaration.  The PARMS are
    the template parameters.  */
 
@@ -2223,7 +2234,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
    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)
 
 tree 
 finish_base_specifier (tree base, tree access, bool virtual_p)
@@ -2245,7 +2257,8 @@ finish_base_specifier (tree base, tree access, bool virtual_p)
           base = TYPE_MAIN_VARIANT (base);
         }
       result = build_tree_list (access, 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;
     }
 
   return result;
@@ -2276,15 +2289,21 @@ check_multiple_declarators (void)
     error ("multiple declarators in template declaration");
 }
 
     error ("multiple declarators in template declaration");
 }
 
-/* Issue a diagnostic that NAME cannot be found in SCOPE.  */
+/* Issue a diagnostic that NAME cannot be found in SCOPE.  DECL is
+   what we found when we tried to do the lookup.  */
 
 void
 
 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);
 {
   if (TYPE_P (scope))
     {
       if (!COMPLETE_TYPE_P (scope))
        error ("incomplete type `%T' 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);
     }
       else
        error ("`%D' is not a member of `%T'", name, scope);
     }
@@ -2350,12 +2369,17 @@ finish_id_expression (tree id_expression,
       if (decl == error_mark_node)
        {
          /* Name lookup failed.  */
       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)
              return error_mark_node;
            }
          else if (!scope)
@@ -2364,6 +2388,8 @@ finish_id_expression (tree id_expression,
              *idk = CP_ID_KIND_UNQUALIFIED;
              return 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
        }
       /* If DECL is a variable that would be out of scope under
         ANSI/ISO rules, but in scope in the ARM, name lookup
@@ -2519,8 +2545,8 @@ 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))
              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 build2 (SCOPE_REF, TREE_TYPE (decl), scope,
+                              id_expression);
              else
                return decl;
            }
              else
                return decl;
            }
@@ -2546,25 +2572,15 @@ finish_id_expression (tree id_expression,
       /* Only certain kinds of names are allowed in constant
        expression.  Enumerators and template parameters 
        have already been handled above.  */
       /* Only certain kinds of names are allowed in constant
        expression.  Enumerators and template parameters 
        have already been handled above.  */
-      if (integral_constant_expression_p)
+      if (integral_constant_expression_p
+         && !DECL_INTEGRAL_CONSTANT_VAR_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 ("`%D' cannot appear in a constant-expression", decl);
+             return error_mark_node;
            }
            }
+         *non_integral_constant_expression_p = true;
        }
       
       if (TREE_CODE (decl) == NAMESPACE_DECL)
        }
       
       if (TREE_CODE (decl) == NAMESPACE_DECL)
@@ -2606,7 +2622,7 @@ finish_id_expression (tree id_expression,
          else if (!processing_template_decl)
            decl = convert_from_reference (decl);
          else if (TYPE_P (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);
+           decl = build2 (SCOPE_REF, TREE_TYPE (decl), scope, decl);
        }
       else if (TREE_CODE (decl) == FIELD_DECL)
        decl = finish_non_static_data_member (decl, current_class_ref,
        }
       else if (TREE_CODE (decl) == FIELD_DECL)
        decl = finish_non_static_data_member (decl, current_class_ref,
@@ -2665,7 +2681,7 @@ finish_id_expression (tree id_expression,
       /* Resolve references to variables of anonymous unions
         into COMPONENT_REFs.  */
       if (TREE_CODE (decl) == ALIAS_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))
     }
 
   if (TREE_DEPRECATED (decl))
@@ -2685,7 +2701,7 @@ finish_typeof (tree expr)
   if (type_dependent_expression_p (expr))
     {
       type = make_aggr_type (TYPEOF_TYPE);
   if (type_dependent_expression_p (expr))
     {
       type = make_aggr_type (TYPEOF_TYPE);
-      TYPE_FIELDS (type) = expr;
+      TYPEOF_TYPE_EXPR (type) = expr;
 
       return type;
     }
 
       return type;
     }
@@ -2701,37 +2717,8 @@ finish_typeof (tree expr)
   return type;
 }
 
   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
 /* 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, 
 
 static tree
 simplify_aggr_init_exprs_r (tree* tp, 
@@ -2771,7 +2758,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 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;
 
   tree call_expr;
   enum style_t { ctor, arg, pcc } style;
@@ -2782,12 +2769,11 @@ simplify_aggr_init_expr (tree *tp)
   else if (1)
     style = pcc;
 #endif
   else if (1)
     style = pcc;
 #endif
-  else if (TREE_ADDRESSABLE (type))
-    style = arg;
   else
   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)
     {
 
   if (style == ctor || style == arg)
     {
@@ -2799,25 +2785,23 @@ simplify_aggr_init_expr (tree *tp)
        args = TREE_CHAIN (args);
 
       cxx_mark_addressable (slot);
        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));
       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);
     }
 
          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
 
   if (style == arg)
     /* Tell the backend that we've added our return slot to the argument
@@ -2834,13 +2818,6 @@ simplify_aggr_init_expr (tree *tp)
       pop_deferring_access_checks ();
     }
 
       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;
 }
 
   *tp = call_expr;
 }
 
@@ -2873,7 +2850,7 @@ emit_associated_thunks (tree fn)
                }
            }
          else
                }
            }
          else
-           my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
+           gcc_assert (!DECL_THUNKS (thunk));
        }
     }
 }
        }
     }
 }
@@ -2884,7 +2861,7 @@ void
 expand_body (tree fn)
 {
   tree saved_function;
 expand_body (tree fn)
 {
   tree saved_function;
-  
+
   /* Compute the appropriate object-file linkage for inline
      functions.  */
   if (DECL_DECLARED_INLINE_P (fn))
   /* Compute the appropriate object-file linkage for inline
      functions.  */
   if (DECL_DECLARED_INLINE_P (fn))
@@ -2904,28 +2881,12 @@ expand_body (tree fn)
   /* Emit any thunks that should be emitted at the same time as FN.  */
   emit_associated_thunks (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);
-
   tree_rest_of_compilation (fn, function_depth > 1);
 
   current_function_decl = saved_function;
 
   extract_interface_info ();
 
   tree_rest_of_compilation (fn, function_depth > 1);
 
   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
   if (DECL_CLONED_FUNCTION_P (fn))
     {
       /* If this is a clone, go through the other clones now and mark
@@ -2979,15 +2940,45 @@ expand_or_defer_fn (tree fn)
       return;
     }
 
       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;
 
   /* 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.  */
   function_depth++;
 
   /* Expand or defer, at the whim of the compilation unit manager.  */
@@ -2996,37 +2987,94 @@ expand_or_defer_fn (tree fn)
   function_depth--;
 }
 
   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;
+};
+
+/* Helper function for walk_tree, used by finalize_nrv below.  */
 
 
-tree
-nullify_returns_r (tree* tp, int* walk_subtrees, void* data)
+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;
 
   /* 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
   else if (TREE_CODE (*tp) == CLEANUP_STMT
-          && CLEANUP_DECL (*tp) == nrv)
+          && CLEANUP_DECL (*tp) == dp->var)
     CLEANUP_EH_ONLY (*tp) = 1;
     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;
 }
 
 
   /* 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
 
 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.  */
 }
 
 /* Perform initialization related to this module.  */
@@ -3034,7 +3082,6 @@ cxx_expand_function_start (void)
 void
 init_cp_semantics (void)
 {
 void
 init_cp_semantics (void)
 {
-  lang_expand_stmt = cp_expand_stmt;
 }
 
 #include "gt-cp-semantics.h"
 }
 
 #include "gt-cp-semantics.h"