OSDN Git Service

* cp-tree.h (do_poplevel): Remove prototype.
[pf3gnuchains/gcc-fork.git] / gcc / cp / semantics.c
index 19c6d5d..47ff6ea 100644 (file)
@@ -1,12 +1,12 @@
 /* Perform the semantic phase of parsing, i.e., the process of
    building tree structure, checking semantic consistency, and
    building RTL.  These routines are used both during actual parsing
 /* Perform the semantic phase of parsing, i.e., the process of
    building tree structure, checking semantic consistency, and
    building RTL.  These routines are used both during actual parsing
-   and during the instantiation of template functions. 
+   and during the instantiation of template functions.
 
 
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   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
    Free Software Foundation, Inc.
    Written by Mark Mitchell (mmitchell@usa.net) based on code found
-   formerly in parse.y and pt.c.  
+   formerly in parse.y and pt.c.
 
    This file is part of GCC.
 
 
    This file is part of GCC.
 
    under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
    under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
-   
+
    GCC is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.
    GCC is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with GCC; see the file COPYING.  If not, write to the Free
    You should have received a copy of the GNU General Public License
    along with GCC; see the file COPYING.  If not, write to the Free
-   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
 
 #include "config.h"
 #include "system.h"
@@ -57,6 +57,7 @@
    parsing into this file; that will make implementing the new parser
    much easier since it will be able to make use of these routines.  */
 
    parsing into this file; that will make implementing the new parser
    much easier since it will be able to make use of these routines.  */
 
+static tree do_poplevel (tree);
 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);
@@ -75,9 +76,9 @@ static tree finalize_nrv_r (tree *, int *, void *);
    example:
 
      class A {
    example:
 
      class A {
-         typedef int X;
+        typedef int X;
        public:
        public:
-         X f();
+        X f();
      };
 
      A::X A::f();
      };
 
      A::X A::f();
@@ -91,7 +92,7 @@ static tree finalize_nrv_r (tree *, int *, void *);
    instantiations.
 
    Typical use of access checking functions is described here:
    instantiations.
 
    Typical use of access checking functions is described here:
-   
+
    1. When we enter a context that requires certain access checking
       mode, the function `push_deferring_access_checks' is called with
       DEFERRING argument specifying the desired mode.  Access checking
    1. When we enter a context that requires certain access checking
       mode, the function `push_deferring_access_checks' is called with
       DEFERRING argument specifying the desired mode.  Access checking
@@ -121,28 +122,29 @@ typedef struct deferred_access GTY(())
      names used in a decl-specifier-seq until we know what is being
      declared because code like:
 
      names used in a decl-specifier-seq until we know what is being
      declared because code like:
 
-       class A { 
-         class B {};
-         B* f();
+       class A {
+        class B {};
+        B* f();
        }
 
        A::B* A::f() { return 0; }
 
        }
 
        A::B* A::f() { return 0; }
 
-     is valid, even though `A::B' is not generally accessible.  
+     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 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;
   /* The current mode of access checks.  */
   enum deferring_kind deferring_access_checks_kind;
-  
+
 } deferred_access;
 } deferred_access;
-DEF_VEC_GC_O (deferred_access);
+DEF_VEC_O (deferred_access);
+DEF_VEC_ALLOC_O (deferred_access,gc);
 
 /* Data for deferred access checking.  */
 
 /* Data for deferred access checking.  */
-static GTY(()) VEC (deferred_access) *deferred_access_stack;
+static GTY(()) VEC(deferred_access,gc) *deferred_access_stack;
 static GTY(()) unsigned deferred_access_no_check;
 
 /* Save the current deferred access states and start deferred
 static GTY(()) unsigned deferred_access_no_check;
 
 /* Save the current deferred access states and start deferred
@@ -159,7 +161,7 @@ push_deferring_access_checks (deferring_kind deferring)
     {
       deferred_access *ptr;
 
     {
       deferred_access *ptr;
 
-      ptr = VEC_safe_push (deferred_access, deferred_access_stack, NULL);
+      ptr = VEC_safe_push (deferred_access, gc, deferred_access_stack, NULL);
       ptr->deferred_access_checks = NULL_TREE;
       ptr->deferring_access_checks_kind = deferring;
     }
       ptr->deferred_access_checks = NULL_TREE;
       ptr->deferring_access_checks_kind = deferring;
     }
@@ -198,8 +200,8 @@ pop_deferring_access_checks (void)
     VEC_pop (deferred_access, deferred_access_stack);
 }
 
     VEC_pop (deferred_access, deferred_access_stack);
 }
 
-/* Returns a TREE_LIST representing the deferred checks.  
-   The TREE_PURPOSE of each node is the type through which the 
+/* Returns a TREE_LIST representing the deferred checks.
+   The TREE_PURPOSE of each node is the type through which the
    access occurred; the TREE_VALUE is the declaration named.
    */
 
    access occurred; the TREE_VALUE is the declaration named.
    */
 
@@ -235,8 +237,8 @@ pop_to_parent_deferring_access_checks (void)
       if (ptr->deferring_access_checks_kind == dk_no_deferred)
        {
          /* Check access.  */
       if (ptr->deferring_access_checks_kind == dk_no_deferred)
        {
          /* Check access.  */
-         for (; checks; checks = TREE_CHAIN (checks)) 
-           enforce_access (TREE_PURPOSE (checks), 
+         for (; checks; checks = TREE_CHAIN (checks))
+           enforce_access (TREE_PURPOSE (checks),
                            TREE_VALUE (checks));
        }
       else
                            TREE_VALUE (checks));
        }
       else
@@ -244,11 +246,11 @@ pop_to_parent_deferring_access_checks (void)
          /* Merge with parent.  */
          tree next;
          tree original = ptr->deferred_access_checks;
          /* Merge with parent.  */
          tree next;
          tree original = ptr->deferred_access_checks;
-         
+
          for (; checks; checks = next)
            {
              tree probe;
          for (; checks; checks = next)
            {
              tree probe;
-             
+
              next = TREE_CHAIN (checks);
 
              for (probe = original; probe; probe = TREE_CHAIN (probe))
              next = TREE_CHAIN (checks);
 
              for (probe = original; probe; probe = TREE_CHAIN (probe))
@@ -285,12 +287,11 @@ perform_deferred_access_checks (void)
 {
   tree deferred_check;
 
 {
   tree deferred_check;
 
-  for (deferred_check = (VEC_last (deferred_access, deferred_access_stack)
-                        ->deferred_access_checks);
+  for (deferred_check = get_deferred_access_checks ();
        deferred_check;
        deferred_check = TREE_CHAIN (deferred_check))
     /* Check access.  */
        deferred_check;
        deferred_check = TREE_CHAIN (deferred_check))
     /* Check access.  */
-    enforce_access (TREE_PURPOSE (deferred_check), 
+    enforce_access (TREE_PURPOSE (deferred_check),
                    TREE_VALUE (deferred_check));
 }
 
                    TREE_VALUE (deferred_check));
 }
 
@@ -307,18 +308,18 @@ perform_or_defer_access_check (tree binfo, tree decl)
      */
   if (deferred_access_no_check)
     return;
      */
   if (deferred_access_no_check)
     return;
-  
+
   gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
 
   ptr = VEC_last (deferred_access, deferred_access_stack);
   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 (ptr->deferring_access_checks_kind == dk_no_deferred)
     {
       enforce_access (binfo, decl);
       return;
     }
   /* If we are not supposed to defer access checks, just check now.  */
   if (ptr->deferring_access_checks_kind == dk_no_deferred)
     {
       enforce_access (binfo, decl);
       return;
     }
-  
+
   /* See if we are already going to perform this check.  */
   for (check = ptr->deferred_access_checks;
        check;
   /* See if we are already going to perform this check.  */
   for (check = ptr->deferred_access_checks;
        check;
@@ -340,6 +341,32 @@ stmts_are_full_exprs_p (void)
   return current_stmt_tree ()->stmts_are_full_exprs_p;
 }
 
   return current_stmt_tree ()->stmts_are_full_exprs_p;
 }
 
+/* T is a statement.  Add it to the statement-tree.  This is the C++
+   version.  The C/ObjC frontends have a slightly different version of
+   this function.  */
+
+tree
+add_stmt (tree t)
+{
+  enum tree_code code = TREE_CODE (t);
+
+  if (EXPR_P (t) && code != LABEL_EXPR)
+    {
+      if (!EXPR_HAS_LOCATION (t))
+       SET_EXPR_LOCATION (t, input_location);
+
+      /* When we expand a statement-tree, we must know whether or not the
+        statements are full-expressions.  We record that fact here.  */
+      STMT_IS_FULL_EXPR_P (t) = stmts_are_full_exprs_p ();
+    }
+
+  /* Add T to the statement-tree.  Non-side-effect statements need to be
+     recorded during statement expressions.  */
+  append_to_statement_list_force (t, &cur_stmt_list);
+
+  return t;
+}
+
 /* Returns the stmt_tree (if any) to which statements are currently
    being added.  If there is no active statement-tree, NULL is
    returned.  */
 /* Returns the stmt_tree (if any) to which statements are currently
    being added.  If there is no active statement-tree, NULL is
    returned.  */
@@ -347,8 +374,8 @@ stmts_are_full_exprs_p (void)
 stmt_tree
 current_stmt_tree (void)
 {
 stmt_tree
 current_stmt_tree (void)
 {
-  return (cfun 
-         ? &cfun->language->base.x_stmt_tree 
+  return (cfun
+         ? &cfun->language->base.x_stmt_tree
          : &scope_chain->x_stmt_tree);
 }
 
          : &scope_chain->x_stmt_tree);
 }
 
@@ -410,7 +437,7 @@ do_poplevel (tree stmt_list)
     block = poplevel (kept_level_p (), 1, 0);
 
   stmt_list = pop_stmt_list (stmt_list);
     block = poplevel (kept_level_p (), 1, 0);
 
   stmt_list = pop_stmt_list (stmt_list);
-  
+
   if (!processing_template_decl)
     {
       stmt_list = c_build_bind_expr (block, stmt_list);
   if (!processing_template_decl)
     {
       stmt_list = c_build_bind_expr (block, stmt_list);
@@ -420,7 +447,7 @@ do_poplevel (tree stmt_list)
   return stmt_list;
 }
 
   return stmt_list;
 }
 
-/* Begin a new scope.  */ 
+/* Begin a new scope.  */
 
 static tree
 do_pushlevel (scope_kind sk)
 
 static tree
 do_pushlevel (scope_kind sk)
@@ -472,14 +499,14 @@ finish_cond (tree *cond_p, tree expr)
 
 /* If *COND_P specifies a conditional with a declaration, transform the
    loop such that
 
 /* If *COND_P specifies a conditional with a declaration, transform the
    loop such that
-            while (A x = 42) { }
-            for (; A x = 42;) { }
+           while (A x = 42) { }
+           for (; A x = 42;) { }
    becomes
    becomes
-            while (true) { A x = 42; if (!x) break; }
-            for (;;) { A x = 42; if (!x) break; }
+           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.  */
    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)
 {
 static void
 simplify_loop_decl_cond (tree *cond_p, tree body)
 {
@@ -490,7 +517,7 @@ simplify_loop_decl_cond (tree *cond_p, tree body)
 
   cond = *cond_p;
   *cond_p = boolean_true_node;
 
   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);
   if_stmt = begin_if_stmt ();
   cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
   finish_if_stmt_cond (cond, if_stmt);
@@ -522,7 +549,7 @@ finish_goto_stmt (tree destination)
         addresses, or some such.  */
       DECL_UNINLINABLE (current_function_decl) = 1;
     }
         addresses, or some such.  */
       DECL_UNINLINABLE (current_function_decl) = 1;
     }
-  
+
   check_goto (destination);
 
   return add_stmt (build_stmt (GOTO_EXPR, destination));
   check_goto (destination);
 
   return add_stmt (build_stmt (GOTO_EXPR, destination));
@@ -600,7 +627,7 @@ begin_if_stmt (void)
 /* Process the COND of an if-statement, which may be given by
    IF_STMT.  */
 
 /* Process the COND of an if-statement, which may be given by
    IF_STMT.  */
 
-void 
+void
 finish_if_stmt_cond (tree cond, tree if_stmt)
 {
   finish_cond (&IF_COND (if_stmt), maybe_convert_cond (cond));
 finish_if_stmt_cond (tree cond, tree if_stmt)
 {
   finish_cond (&IF_COND (if_stmt), maybe_convert_cond (cond));
@@ -637,13 +664,14 @@ finish_else_clause (tree if_stmt)
 
 /* Finish an if-statement.  */
 
 
 /* Finish an if-statement.  */
 
-void 
+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_if_stmt (tree if_stmt)
 {
   tree scope = TREE_CHAIN (if_stmt);
   TREE_CHAIN (if_stmt) = NULL;
   add_stmt (do_poplevel (scope));
   finish_stmt ();
+  empty_body_warning (THEN_CLAUSE (if_stmt), ELSE_CLAUSE (if_stmt));
 }
 
 /* Begin a while-statement.  Returns a newly created WHILE_STMT if
 }
 
 /* Begin a while-statement.  Returns a newly created WHILE_STMT if
@@ -663,7 +691,7 @@ begin_while_stmt (void)
 /* Process the COND of a while-statement, which may be given by
    WHILE_STMT.  */
 
 /* Process the COND of a while-statement, which may be given by
    WHILE_STMT.  */
 
-void 
+void
 finish_while_stmt_cond (tree cond, tree while_stmt)
 {
   finish_cond (&WHILE_COND (while_stmt), maybe_convert_cond (cond));
 finish_while_stmt_cond (tree cond, tree while_stmt)
 {
   finish_cond (&WHILE_COND (while_stmt), maybe_convert_cond (cond));
@@ -672,7 +700,7 @@ finish_while_stmt_cond (tree cond, tree while_stmt)
 
 /* Finish a while-statement, which may be given by WHILE_STMT.  */
 
 
 /* Finish a while-statement, which may be given by WHILE_STMT.  */
 
-void 
+void
 finish_while_stmt (tree while_stmt)
 {
   WHILE_BODY (while_stmt) = do_poplevel (WHILE_BODY (while_stmt));
 finish_while_stmt (tree while_stmt)
 {
   WHILE_BODY (while_stmt) = do_poplevel (WHILE_BODY (while_stmt));
@@ -717,12 +745,13 @@ tree
 finish_return_stmt (tree expr)
 {
   tree r;
 finish_return_stmt (tree expr)
 {
   tree r;
+  bool no_warning;
 
 
-  expr = check_return_expr (expr);
+  expr = check_return_expr (expr, &no_warning);
   if (!processing_template_decl)
     {
       if (DECL_DESTRUCTOR_P (current_function_decl)
   if (!processing_template_decl)
     {
       if (DECL_DESTRUCTOR_P (current_function_decl)
-         || (DECL_CONSTRUCTOR_P (current_function_decl) 
+         || (DECL_CONSTRUCTOR_P (current_function_decl)
              && targetm.cxx.cdtor_returns_this ()))
        {
          /* Similarly, all destructors must run destructors for
              && targetm.cxx.cdtor_returns_this ()))
        {
          /* Similarly, all destructors must run destructors for
@@ -734,6 +763,7 @@ finish_return_stmt (tree expr)
     }
 
   r = build_stmt (RETURN_EXPR, expr);
     }
 
   r = build_stmt (RETURN_EXPR, expr);
+  TREE_NO_WARNING (r) |= no_warning;
   r = maybe_cleanup_point_expr_void (r);
   r = add_stmt (r);
   finish_stmt ();
   r = maybe_cleanup_point_expr_void (r);
   r = add_stmt (r);
   finish_stmt ();
@@ -748,7 +778,7 @@ begin_for_stmt (void)
 {
   tree r;
 
 {
   tree r;
 
-  r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, 
+  r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
                  NULL_TREE, NULL_TREE);
 
   if (flag_new_for_scope > 0)
                  NULL_TREE, NULL_TREE);
 
   if (flag_new_for_scope > 0)
@@ -801,7 +831,7 @@ finish_for_expr (tree expr, tree for_stmt)
   if (!processing_template_decl)
     {
       if (warn_sequence_point)
   if (!processing_template_decl)
     {
       if (warn_sequence_point)
-        verify_sequence_points (expr);
+       verify_sequence_points (expr);
       expr = convert_to_void (expr, "3rd expression in for");
     }
   else if (!type_dependent_expression_p (expr))
       expr = convert_to_void (expr, "3rd expression in for");
     }
   else if (!type_dependent_expression_p (expr))
@@ -827,7 +857,7 @@ finish_for_stmt (tree for_stmt)
       add_stmt (do_poplevel (scope));
     }
 
       add_stmt (do_poplevel (scope));
     }
 
-  finish_stmt (); 
+  finish_stmt ();
 }
 
 /* Finish a break-statement.  */
 }
 
 /* Finish a break-statement.  */
@@ -835,7 +865,7 @@ finish_for_stmt (tree for_stmt)
 tree
 finish_break_stmt (void)
 {
 tree
 finish_break_stmt (void)
 {
-  return add_stmt (build_break_stmt ());
+  return add_stmt (build_stmt (BREAK_STMT));
 }
 
 /* Finish a continue-statement.  */
 }
 
 /* Finish a continue-statement.  */
@@ -843,7 +873,7 @@ finish_break_stmt (void)
 tree
 finish_continue_stmt (void)
 {
 tree
 finish_continue_stmt (void)
 {
-  return add_stmt (build_continue_stmt ());
+  return add_stmt (build_stmt (CONTINUE_STMT));
 }
 
 /* Begin a switch-statement.  Returns a new SWITCH_STMT if
 }
 
 /* Begin a switch-statement.  Returns a new SWITCH_STMT if
@@ -858,7 +888,7 @@ begin_switch_stmt (void)
 
   scope = do_pushlevel (sk_block);
   TREE_CHAIN (r) = scope;
 
   scope = do_pushlevel (sk_block);
   TREE_CHAIN (r) = scope;
-  begin_cond (&SWITCH_COND (r));
+  begin_cond (&SWITCH_STMT_COND (r));
 
   return r;
 }
 
   return r;
 }
@@ -902,11 +932,11 @@ finish_switch_cond (tree cond, tree switch_stmt)
            cond = index;
        }
     }
            cond = index;
        }
     }
-  finish_cond (&SWITCH_COND (switch_stmt), cond);
-  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);
   add_stmt (switch_stmt);
   push_switch (switch_stmt);
-  SWITCH_BODY (switch_stmt) = push_stmt_list ();
+  SWITCH_STMT_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
@@ -917,8 +947,9 @@ finish_switch_stmt (tree switch_stmt)
 {
   tree scope;
 
 {
   tree scope;
 
-  SWITCH_BODY (switch_stmt) = pop_stmt_list (SWITCH_BODY (switch_stmt));
-  pop_switch (); 
+  SWITCH_STMT_BODY (switch_stmt) =
+    pop_stmt_list (SWITCH_STMT_BODY (switch_stmt));
+  pop_switch ();
   finish_stmt ();
 
   scope = TREE_CHAIN (switch_stmt);
   finish_stmt ();
 
   scope = TREE_CHAIN (switch_stmt);
@@ -1063,7 +1094,7 @@ finish_handler (tree handler)
 /* 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
 /* 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 
+   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.  */
 
    created on behalf of a TRY statement.  Returns a token to be passed to
    finish_compound_stmt.  */
 
@@ -1080,7 +1111,7 @@ begin_compound_stmt (unsigned int flags)
       /* 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
       /* 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.  */ 
+        *inside* the scopeless block.  */
       keep_next_level (false);
     }
   else
       keep_next_level (false);
     }
   else
@@ -1136,72 +1167,108 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands,
 {
   tree r;
   tree t;
 {
   tree r;
   tree t;
+  int ninputs = list_length (input_operands);
+  int noutputs = list_length (output_operands);
 
   if (!processing_template_decl)
     {
 
   if (!processing_template_decl)
     {
+      const char *constraint;
+      const char **oconstraints;
+      bool allows_mem, allows_reg, is_inout;
+      tree operand;
       int i;
       int i;
-      int ninputs;
-      int noutputs;
 
 
-      for (t = input_operands; t; t = TREE_CHAIN (t))
+      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)
        {
        {
-         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)
+         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;
+
+          if (operand != error_mark_node
+             && (TREE_READONLY (operand)
+                 || CP_TYPE_CONST_P (TREE_TYPE (operand))
+                 /* Functions are not modifiable, even though they are
+                    lvalues.  */
+                 || TREE_CODE (TREE_TYPE (operand)) == FUNCTION_TYPE
+                 || TREE_CODE (TREE_TYPE (operand)) == METHOD_TYPE
+                 /* If it's an aggregate and any field is const, then it is
+                    effectively const.  */
+                 || (CLASS_TYPE_P (TREE_TYPE (operand))
+                     && C_TYPE_FIELDS_READONLY (TREE_TYPE (operand)))))
+           readonly_error (operand, "assignment (via 'asm' output)", 0);
+
+         constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+         oconstraints[i] = constraint;
+
+         if (parse_output_constraint (&constraint, i, ninputs, noutputs,
+                                      &allows_mem, &allows_reg, &is_inout))
            {
            {
-             error ("type of asm operand %qE could not be determined", 
-                     TREE_VALUE (t));
-             converted_operand = error_mark_node;
+             /* If the operand is going to end up in memory,
+                mark it addressable.  */
+             if (!allows_reg && !cxx_mark_addressable (operand))
+               operand = error_mark_node;
            }
            }
-         TREE_VALUE (t) = converted_operand;
-       }
+         else
+           operand = error_mark_node;
 
 
-      ninputs = list_length (input_operands);
-      noutputs = list_length (output_operands);
+         TREE_VALUE (t) = operand;
+       }
 
 
-      for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i)
+      for (i = 0, t = input_operands; t; ++i, t = TREE_CHAIN (t))
        {
        {
-         bool allows_mem;
-         bool allows_reg;
-         bool is_inout;
-         const char *constraint;
-         tree operand;
-
          constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
          constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
-         operand = TREE_VALUE (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_output_constraint (&constraint,
-                                       i, ninputs, noutputs,
-                                       &allows_mem,
-                                       &allows_reg,
-                                       &is_inout))
+         if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
+                                     oconstraints, &allows_mem, &allows_reg))
            {
            {
-             /* 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 && 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;
 
 
-         /* 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;
        }
     }
 
   r = build_stmt (ASM_EXPR, string,
                  output_operands, input_operands,
                  clobbers);
        }
     }
 
   r = build_stmt (ASM_EXPR, string,
                  output_operands, input_operands,
                  clobbers);
-  ASM_VOLATILE_P (r) = volatile_p;
+  ASM_VOLATILE_P (r) = volatile_p || noutputs == 0;
   r = maybe_cleanup_point_expr_void (r);
   return add_stmt (r);
 }
   r = maybe_cleanup_point_expr_void (r);
   return add_stmt (r);
 }
@@ -1228,7 +1295,7 @@ finish_label_decl (tree name)
 
 /* When DECL goes out of scope, make sure that CLEANUP is executed.  */
 
 
 /* When DECL goes out of scope, make sure that CLEANUP is executed.  */
 
-void 
+void
 finish_decl_cleanup (tree decl, tree cleanup)
 {
   push_cleanup (decl, cleanup, false);
 finish_decl_cleanup (tree decl, tree cleanup)
 {
   push_cleanup (decl, cleanup, false);
@@ -1272,6 +1339,10 @@ finish_parenthesized_expr (tree expr)
     /* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be
        enclosed in parentheses.  */
     PTRMEM_OK_P (expr) = 0;
     /* [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;
 }
 
   return expr;
 }
 
@@ -1285,12 +1356,11 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
 
   if (!object)
     {
 
   if (!object)
     {
-      if (current_function_decl 
+      if (current_function_decl
          && DECL_STATIC_FUNCTION_P (current_function_decl))
          && DECL_STATIC_FUNCTION_P (current_function_decl))
-       cp_error_at ("invalid use of member %qD in static member function",
-                    decl);
+       error ("invalid use of member %q+D in static member function", decl);
       else
       else
-       cp_error_at ("invalid use of non-static data member %qD", decl);
+       error ("invalid use of non-static data member %q+D", decl);
       error ("from this location");
 
       return error_mark_node;
       error ("from this location");
 
       return error_mark_node;
@@ -1306,21 +1376,21 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
        {
          /* Set the cv qualifiers.  */
          int quals = cp_type_quals (TREE_TYPE (current_class_ref));
        {
          /* Set the cv qualifiers.  */
          int quals = cp_type_quals (TREE_TYPE (current_class_ref));
-         
+
          if (DECL_MUTABLE_P (decl))
            quals &= ~TYPE_QUAL_CONST;
 
          quals |= cp_type_quals (TREE_TYPE (decl));
          type = cp_build_qualified_type (type, quals);
        }
          if (DECL_MUTABLE_P (decl))
            quals &= ~TYPE_QUAL_CONST;
 
          quals |= cp_type_quals (TREE_TYPE (decl));
          type = cp_build_qualified_type (type, quals);
        }
-      
+
       return build_min (COMPONENT_REF, type, object, decl, NULL_TREE);
     }
   else
     {
       tree access_type = TREE_TYPE (object);
       tree lookup_context = context_for_name_lookup (decl);
       return build_min (COMPONENT_REF, type, object, decl, NULL_TREE);
     }
   else
     {
       tree access_type = TREE_TYPE (object);
       tree lookup_context = context_for_name_lookup (decl);
-      
+
       while (!DERIVED_FROM_P (lookup_context, access_type))
        {
          access_type = TYPE_CONTEXT (access_type);
       while (!DERIVED_FROM_P (lookup_context, access_type))
        {
          access_type = TYPE_CONTEXT (access_type);
@@ -1329,7 +1399,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
 
          if (!access_type)
            {
 
          if (!access_type)
            {
-             cp_error_at ("object missing in reference to %qD", decl);
+             error ("object missing in reference to %q+D", decl);
              error ("from this location");
              return error_mark_node;
            }
              error ("from this location");
              return error_mark_node;
            }
@@ -1339,8 +1409,10 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
         QUALIFYING_SCOPE is also non-null.  Wrap this in a SCOPE_REF
         for now.  */
       if (processing_template_decl)
         QUALIFYING_SCOPE is also non-null.  Wrap this in a SCOPE_REF
         for now.  */
       if (processing_template_decl)
-       return build_min (SCOPE_REF, TREE_TYPE (decl),
-                         qualifying_scope, DECL_NAME (decl));
+       return build_qualified_name (TREE_TYPE (decl),
+                                    qualifying_scope,
+                                    DECL_NAME (decl),
+                                    /*template_p=*/false);
 
       perform_or_defer_access_check (TYPE_BINFO (access_type), decl);
 
 
       perform_or_defer_access_check (TYPE_BINFO (access_type), decl);
 
@@ -1366,8 +1438,8 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
    `A::B' then NESTED_NAME_SPECIFIER is `A'.  */
 
 void
    `A::B' then NESTED_NAME_SPECIFIER is `A'.  */
 
 void
-check_accessibility_of_qualified_id (tree decl, 
-                                    tree object_type, 
+check_accessibility_of_qualified_id (tree decl,
+                                    tree object_type,
                                     tree nested_name_specifier)
 {
   tree scope;
                                     tree nested_name_specifier)
 {
   tree scope;
@@ -1376,21 +1448,21 @@ check_accessibility_of_qualified_id (tree decl,
   /* If we're not checking, return immediately.  */
   if (deferred_access_no_check)
     return;
   /* If we're not checking, return immediately.  */
   if (deferred_access_no_check)
     return;
-  
+
   /* Determine the SCOPE of DECL.  */
   scope = context_for_name_lookup (decl);
   /* If the SCOPE is not a type, then DECL is not a member.  */
   if (!TYPE_P (scope))
     return;
   /* Compute the scope through which DECL is being accessed.  */
   /* Determine the SCOPE of DECL.  */
   scope = context_for_name_lookup (decl);
   /* If the SCOPE is not a type, then DECL is not a member.  */
   if (!TYPE_P (scope))
     return;
   /* Compute the scope through which DECL is being accessed.  */
-  if (object_type 
+  if (object_type
       /* OBJECT_TYPE might not be a class type; consider:
 
           class A { typedef int I; };
           I *p;
           p->A::I::~I();
 
       /* OBJECT_TYPE might not be a class type; consider:
 
           class A { typedef int I; };
           I *p;
           p->A::I::~I();
 
-         In this case, we will have "A::I" as the DECL, but "I" as the
+        In this case, we will have "A::I" as the DECL, but "I" as the
         OBJECT_TYPE.  */
       && CLASS_TYPE_P (object_type)
       && DERIVED_FROM_P (scope, object_type))
         OBJECT_TYPE.  */
       && CLASS_TYPE_P (object_type)
       && DERIVED_FROM_P (scope, object_type))
@@ -1426,27 +1498,47 @@ check_accessibility_of_qualified_id (tree decl,
    class named to the left of the "::" operator.  DONE is true if this
    expression is a complete postfix-expression; it is false if this
    expression is followed by '->', '[', '(', etc.  ADDRESS_P is true
    class named to the left of the "::" operator.  DONE is true if this
    expression is a complete postfix-expression; it is false if this
    expression is followed by '->', '[', '(', etc.  ADDRESS_P is true
-   iff this expression is the operand of '&'.  */
+   iff this expression is the operand of '&'.  TEMPLATE_P is true iff
+   the qualified-id was of the form "A::template B".  TEMPLATE_ARG_P
+   is true iff this qualified name appears as a template argument.  */
 
 tree
 
 tree
-finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
-                         bool address_p)
+finish_qualified_id_expr (tree qualifying_class, 
+                         tree expr, 
+                         bool done,
+                         bool address_p, 
+                         bool template_p,
+                         bool template_arg_p)
 {
 {
+  gcc_assert (TYPE_P (qualifying_class));
+
   if (error_operand_p (expr))
     return error_mark_node;
 
   if (error_operand_p (expr))
     return error_mark_node;
 
+  if (DECL_P (expr) || BASELINK_P (expr))
+    mark_used (expr);
+
+  if (template_p)
+    check_template_keyword (expr);
+
   /* If EXPR occurs as the operand of '&', use special handling that
      permits a pointer-to-member.  */
   if (address_p && done)
     {
       if (TREE_CODE (expr) == SCOPE_REF)
        expr = TREE_OPERAND (expr, 1);
   /* If EXPR occurs as the operand of '&', use special handling that
      permits a pointer-to-member.  */
   if (address_p && done)
     {
       if (TREE_CODE (expr) == SCOPE_REF)
        expr = TREE_OPERAND (expr, 1);
-      expr = build_offset_ref (qualifying_class, expr, 
+      expr = build_offset_ref (qualifying_class, expr,
                               /*address_p=*/true);
       return expr;
     }
 
                               /*address_p=*/true);
       return expr;
     }
 
-  if (TREE_CODE (expr) == FIELD_DECL)
+  /* Within the scope of a class, turn references to non-static
+     members into expression of the form "this->...".  */
+  if (template_arg_p)
+    /* But, within a template argument, we do not want make the
+       transformation, as there is no "this" pointer.  */
+    ;
+  else if (TREE_CODE (expr) == FIELD_DECL)
     expr = finish_non_static_data_member (expr, current_class_ref,
                                          qualifying_class);
   else if (BASELINK_P (expr) && !processing_template_decl)
     expr = finish_non_static_data_member (expr, current_class_ref,
                                          qualifying_class);
   else if (BASELINK_P (expr) && !processing_template_decl)
@@ -1460,9 +1552,9 @@ finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
       /* If so, the expression may be relative to the current
         class.  */
       if (!shared_member_p (fns)
       /* If so, the expression may be relative to the current
         class.  */
       if (!shared_member_p (fns)
-         && current_class_type 
+         && current_class_type
          && DERIVED_FROM_P (qualifying_class, current_class_type))
          && DERIVED_FROM_P (qualifying_class, current_class_type))
-       expr = (build_class_member_access_expr 
+       expr = (build_class_member_access_expr
                (maybe_dummy_object (qualifying_class, NULL),
                 expr,
                 BASELINK_ACCESS_BINFO (expr),
                (maybe_dummy_object (qualifying_class, NULL),
                 expr,
                 BASELINK_ACCESS_BINFO (expr),
@@ -1479,123 +1571,111 @@ finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
 /* Begin a statement-expression.  The value returned must be passed to
    finish_stmt_expr.  */
 
 /* Begin a statement-expression.  The value returned must be passed to
    finish_stmt_expr.  */
 
-tree 
+tree
 begin_stmt_expr (void)
 {
   return push_stmt_list ();
 }
 
 /* Process the final expression of a statement expression. EXPR can be
 begin_stmt_expr (void)
 {
   return push_stmt_list ();
 }
 
 /* Process the final expression of a statement expression. EXPR can be
-   NULL, if the final expression is empty.  Build up a TARGET_EXPR so
-   that the result value can be safely returned to the enclosing
-   expression.  */
+   NULL, if the final expression is empty.  Return a STATEMENT_LIST
+   containing all the statements in the statement-expression, or
+   ERROR_MARK_NODE if there was an error.  */
 
 tree
 finish_stmt_expr_expr (tree expr, tree stmt_expr)
 {
 
 tree
 finish_stmt_expr_expr (tree expr, tree stmt_expr)
 {
-  tree result = NULL_TREE;
+  if (error_operand_p (expr))
+    return error_mark_node;
 
 
+  /* If the last statement does not have "void" type, then the value
+     of the last statement is the value of the entire expression.  */ 
   if (expr)
     {
   if (expr)
     {
-      if (!processing_template_decl && !VOID_TYPE_P (TREE_TYPE (expr)))
+      tree type;
+      type = TREE_TYPE (expr);
+      if (!dependent_type_p (type) && !VOID_TYPE_P (type))
        {
        {
-         tree type = TREE_TYPE (expr);
-
-         if (TREE_CODE (type) == ARRAY_TYPE
-             || TREE_CODE (type) == FUNCTION_TYPE)
-           expr = decay_conversion (expr);
-
-         expr = require_complete_type (expr);
-
+         expr = decay_conversion (expr);
+         if (error_operand_p (expr))
+           return error_mark_node;
          type = TREE_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
-            expression.  */
-         if (TREE_CODE (expr) == TARGET_EXPR)
-           ;
-         else if (!IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_INIT_REF (type))
-           expr = build_target_expr_with_type (expr, type);
+       }
+      /* The type of the statement-expression is the type of the last
+        expression.  */
+      TREE_TYPE (stmt_expr) = type;
+      /* We must take particular care if TYPE is a class type.  In
+        particular if EXPR creates a temporary of class type, then it
+        must be destroyed at the semicolon terminating the last
+        statement -- but we must make a copy before that happens.
+
+        This problem is solved by using a TARGET_EXPR to initialize a
+        new temporary variable.  The TARGET_EXPR itself is placed
+        outside the statement-expression.  However, the last
+        statement in the statement-expression is transformed from
+        EXPR to (approximately) T = EXPR, where T is the new
+        temporary variable.  Thus, the lifetime of the new temporary
+        extends to the full-expression surrounding the
+        statement-expression.  */
+      if (!processing_template_decl && !VOID_TYPE_P (type))
+       {
+         tree target_expr; 
+         if (CLASS_TYPE_P (type) 
+             && !TYPE_HAS_TRIVIAL_INIT_REF (type)) 
+           {
+             target_expr = build_target_expr_with_type (expr, type);
+             expr = TARGET_EXPR_INITIAL (target_expr);
+           }
          else
            {
          else
            {
-             /* Copy construct.  */
-             expr = build_special_member_call
-               (NULL_TREE, complete_ctor_identifier,
-                build_tree_list (NULL_TREE, expr),
-                type, LOOKUP_NORMAL);
-             expr = build_cplus_new (type, expr);
-             gcc_assert (TREE_CODE (expr) == TARGET_EXPR);
+             /* Normally, build_target_expr will not create a
+                TARGET_EXPR for scalars.  However, we need the
+                temporary here, in order to solve the scoping
+                problem described above.  */
+             target_expr = force_target_expr (type, expr);
+             expr = TARGET_EXPR_INITIAL (target_expr);
+             expr = build2 (INIT_EXPR, 
+                            type,
+                            TARGET_EXPR_SLOT (target_expr),
+                            expr);
            }
            }
-       }
-
-      if (expr != error_mark_node)
-       {
-         result = build_stmt (EXPR_STMT, expr);
-         EXPR_STMT_STMT_EXPR_RESULT (result) = 1;
-         add_stmt (result);
+         TARGET_EXPR_INITIAL (target_expr) = NULL_TREE;
+         /* Save away the TARGET_EXPR in the TREE_TYPE field of the
+            STATEMENT_EXPR.  We will retrieve it in
+            finish_stmt_expr.  */
+         TREE_TYPE (stmt_expr) = target_expr;
        }
     }
        }
     }
-  
-  finish_stmt ();
 
 
-  /* Remember the last expression so that finish_stmt_expr
-     can pull it apart.  */
-  TREE_TYPE (stmt_expr) = result;
-  
-  return result;
+  /* Having modified EXPR to reflect the extra initialization, we now
+     treat it just like an ordinary statement.  */
+  expr = finish_expr_stmt (expr);
+
+  /* Mark the last statement so that we can recognize it as such at
+     template-instantiation time.  */
+  if (expr && processing_template_decl)
+    EXPR_STMT_STMT_EXPR_RESULT (expr) = 1;
+
+  return stmt_expr;
 }
 
 /* Finish a statement-expression.  EXPR should be the value returned
    by the previous begin_stmt_expr.  Returns an expression
    representing the statement-expression.  */
 
 }
 
 /* Finish a statement-expression.  EXPR should be the value returned
    by the previous begin_stmt_expr.  Returns an expression
    representing the statement-expression.  */
 
-tree 
+tree
 finish_stmt_expr (tree stmt_expr, bool has_no_scope)
 {
 finish_stmt_expr (tree stmt_expr, bool has_no_scope)
 {
-  tree result, result_stmt, type;
-  tree *result_stmt_p = NULL;
+  tree type;
+  tree result;
 
 
-  result_stmt = TREE_TYPE (stmt_expr);
-  TREE_TYPE (stmt_expr) = void_type_node;
-  result = pop_stmt_list (stmt_expr);
+  if (error_operand_p (stmt_expr))
+    return error_mark_node;
 
 
-  if (!result_stmt || VOID_TYPE_P (result_stmt))
-    type = void_type_node;
-  else
-    {
-      /* 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)
-       {
-         t = *result_stmt_p;
-         if (t == result_stmt)
-           break;
+  gcc_assert (TREE_CODE (stmt_expr) == STATEMENT_LIST);
 
 
-         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 ();
-           }
-       }
-      type = TREE_TYPE (EXPR_STMT_EXPR (result_stmt));
-    }
+  type = TREE_TYPE (stmt_expr);
+  result = pop_stmt_list (stmt_expr);
 
   if (processing_template_decl)
     {
 
   if (processing_template_decl)
     {
@@ -1603,43 +1683,12 @@ finish_stmt_expr (tree stmt_expr, bool has_no_scope)
       TREE_SIDE_EFFECTS (result) = 1;
       STMT_EXPR_NO_SCOPE (result) = has_no_scope;
     }
       TREE_SIDE_EFFECTS (result) = 1;
       STMT_EXPR_NO_SCOPE (result) = has_no_scope;
     }
-  else if (!VOID_TYPE_P (type))
+  else if (!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 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;
+      gcc_assert (TREE_CODE (type) == TARGET_EXPR);
+      TARGET_EXPR_INITIAL (type) = result;
+      TREE_TYPE (result) = void_type_node;
+      result = type;
     }
 
   return result;
     }
 
   return result;
@@ -1681,8 +1730,6 @@ perform_koenig_lookup (tree fn, tree args)
        /* The unqualified name could not be resolved.  */
        fn = unqualified_fn_lookup_error (identifier);
     }
        /* The unqualified name could not be resolved.  */
        fn = unqualified_fn_lookup_error (identifier);
     }
-  else
-    fn = identifier;
 
   return fn;
 }
 
   return fn;
 }
@@ -1697,7 +1744,7 @@ perform_koenig_lookup (tree fn, tree args)
 
    Returns code for the call.  */
 
 
    Returns code for the call.  */
 
-tree 
+tree
 finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
 {
   tree result;
 finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
 {
   tree result;
@@ -1762,18 +1809,18 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
           function call is transformed into a qualified function call
           using (*this) as the postfix-expression to the left of the
           . operator.... [Otherwise] a contrived object of type T
           function call is transformed into a qualified function call
           using (*this) as the postfix-expression to the left of the
           . operator.... [Otherwise] a contrived object of type T
-          becomes the implied object argument.  
+          becomes the implied object argument.
 
 
-        This paragraph is unclear about this situation:
+       This paragraph is unclear about this situation:
 
          struct A { void f(); };
          struct B : public A {};
          struct C : public A { void g() { B::f(); }};
 
        In particular, for `B::f', this paragraph does not make clear
 
          struct A { void f(); };
          struct B : public A {};
          struct C : public A { void g() { B::f(); }};
 
        In particular, for `B::f', this paragraph does not make clear
-       whether "the class of that member function" refers to `A' or 
+       whether "the class of that member function" refers to `A' or
        to `B'.  We believe it refers to `B'.  */
        to `B'.  We believe it refers to `B'.  */
-      if (current_class_type 
+      if (current_class_type
          && DERIVED_FROM_P (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)),
                             current_class_type)
          && current_class_ref)
          && DERIVED_FROM_P (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)),
                             current_class_type)
          && current_class_ref)
@@ -1798,12 +1845,21 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
        }
 
       result = build_new_method_call (object, fn, args, NULL_TREE,
        }
 
       result = build_new_method_call (object, fn, args, NULL_TREE,
-                                     (disallow_virtual 
+                                     (disallow_virtual
                                       ? LOOKUP_NONVIRTUAL : 0));
     }
   else if (is_overloaded_fn (fn))
                                       ? LOOKUP_NONVIRTUAL : 0));
     }
   else if (is_overloaded_fn (fn))
-    /* A call to a namespace-scope function.  */
-    result = build_new_function_call (fn, args);
+    {
+      /* If the function is an overloaded builtin, resolve it.  */
+      if (TREE_CODE (fn) == FUNCTION_DECL
+         && (DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
+             || DECL_BUILT_IN_CLASS (fn) == BUILT_IN_MD))
+       result = resolve_overloaded_builtin (fn, args);
+
+      if (!result)
+       /* A call to a namespace-scope function.  */
+       result = build_new_function_call (fn, args, koenig_p);
+    }
   else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
     {
       if (args)
   else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
     {
       if (args)
@@ -1820,6 +1876,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
        have an overloaded `operator ()'.  */
     result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE,
                           /*overloaded_p=*/NULL);
        have an overloaded `operator ()'.  */
     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 (!result)
     /* A call where the function is unknown.  */
     result = build_function_call (fn, args);
@@ -1837,15 +1894,15 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
    is indicated by CODE, which should be POSTINCREMENT_EXPR or
    POSTDECREMENT_EXPR.)  */
 
    is indicated by CODE, which should be POSTINCREMENT_EXPR or
    POSTDECREMENT_EXPR.)  */
 
-tree 
+tree
 finish_increment_expr (tree expr, enum tree_code code)
 {
 finish_increment_expr (tree expr, enum tree_code code)
 {
-  return build_x_unary_op (code, expr);  
+  return build_x_unary_op (code, expr);
 }
 
 /* Finish a use of `this'.  Returns an expression for `this'.  */
 
 }
 
 /* Finish a use of `this'.  Returns an expression for `this'.  */
 
-tree 
+tree
 finish_this_expr (void)
 {
   tree result;
 finish_this_expr (void)
 {
   tree result;
@@ -1877,7 +1934,7 @@ finish_this_expr (void)
    the TYPE for the type given.  If SCOPE is non-NULL, the expression
    was of the form `OBJECT.SCOPE::~DESTRUCTOR'.  */
 
    the TYPE for the type given.  If SCOPE is non-NULL, the expression
    was of the form `OBJECT.SCOPE::~DESTRUCTOR'.  */
 
-tree 
+tree
 finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
 {
   if (destructor == error_mark_node)
 finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
 {
   if (destructor == error_mark_node)
@@ -1892,21 +1949,21 @@ finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
          error ("invalid qualifying scope in pseudo-destructor name");
          return error_mark_node;
        }
          error ("invalid qualifying scope in pseudo-destructor name");
          return error_mark_node;
        }
-      
+
       /* [expr.pseudo] says both:
 
       /* [expr.pseudo] says both:
 
-           The type designated by the pseudo-destructor-name shall be
+          The type designated by the pseudo-destructor-name shall be
           the same as the object type.
 
           the same as the object type.
 
-         and:
+        and:
 
 
-           The cv-unqualified versions of the object type and of the
+          The cv-unqualified versions of the object type and of the
           type designated by the pseudo-destructor-name shall be the
           same type.
 
           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), 
+        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 ("%qE is not of type %qT", object, destructor);
                                                      destructor))
        {
          error ("%qE is not of type %qT", object, destructor);
@@ -1930,7 +1987,12 @@ finish_unary_op_expr (enum tree_code code, tree expr)
       && TREE_CODE (result) == INTEGER_CST
       && !TYPE_UNSIGNED (TREE_TYPE (result))
       && INT_CST_LT (result, integer_zero_node))
       && TREE_CODE (result) == INTEGER_CST
       && !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;
 }
   overflow_warning (result);
   return result;
 }
@@ -1939,20 +2001,19 @@ finish_unary_op_expr (enum tree_code code, tree expr)
    the INITIALIZER_LIST is being cast.  */
 
 tree
    the INITIALIZER_LIST is being cast.  */
 
 tree
-finish_compound_literal (tree type, tree initializer_list)
+finish_compound_literal (tree type, VEC(constructor_elt,gc) *initializer_list)
 {
   tree compound_literal;
 
   /* Build a CONSTRUCTOR for the INITIALIZER_LIST.  */
   compound_literal = build_constructor (NULL_TREE, initializer_list);
 {
   tree compound_literal;
 
   /* Build a CONSTRUCTOR for the INITIALIZER_LIST.  */
   compound_literal = build_constructor (NULL_TREE, initializer_list);
-  /* Mark it as a compound-literal.  */
-  TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
   if (processing_template_decl)
     TREE_TYPE (compound_literal) = type;
   else
     {
       /* Check the initialization.  */
   if (processing_template_decl)
     TREE_TYPE (compound_literal) = type;
   else
     {
       /* Check the initialization.  */
-      compound_literal = digest_init (type, compound_literal, NULL);
+      compound_literal = reshape_init (type, compound_literal);
+      compound_literal = digest_init (type, compound_literal);
       /* If the TYPE was an array type with an unknown bound, then we can
         figure out the dimension now.  For example, something like:
 
       /* If the TYPE was an array type with an unknown bound, then we can
         figure out the dimension now.  For example, something like:
 
@@ -1960,9 +2021,13 @@ finish_compound_literal (tree type, tree initializer_list)
 
         implies that the array has two elements.  */
       if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
 
         implies that the array has two elements.  */
       if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
-       complete_array_type (type, compound_literal, 1);
+       cp_complete_array_type (&TREE_TYPE (compound_literal),
+                               compound_literal, 1);
     }
 
     }
 
+  /* Mark it as a compound-literal.  */
+  TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
+
   return compound_literal;
 }
 
   return compound_literal;
 }
 
@@ -1973,7 +2038,7 @@ tree
 finish_fname (tree id)
 {
   tree decl;
 finish_fname (tree id)
 {
   tree decl;
-  
+
   decl = fname_decl (C_RID_CODE (id), id);
   if (processing_template_decl)
     decl = DECL_NAME (decl);
   decl = fname_decl (C_RID_CODE (id), id);
   if (processing_template_decl)
     decl = DECL_NAME (decl);
@@ -1982,7 +2047,7 @@ finish_fname (tree id)
 
 /* Finish a translation unit.  */
 
 
 /* Finish a translation unit.  */
 
-void 
+void
 finish_translation_unit (void)
 {
   /* In case there were missing closebraces,
 finish_translation_unit (void)
 {
   /* In case there were missing closebraces,
@@ -1998,7 +2063,7 @@ finish_translation_unit (void)
 /* Finish a template type parameter, specified as AGGR IDENTIFIER.
    Returns the parameter.  */
 
 /* Finish a template type parameter, specified as AGGR IDENTIFIER.
    Returns the parameter.  */
 
-tree 
+tree
 finish_template_type_parm (tree aggr, tree identifier)
 {
   if (aggr != class_type_node)
 finish_template_type_parm (tree aggr, tree identifier)
 {
   if (aggr != class_type_node)
@@ -2013,7 +2078,7 @@ finish_template_type_parm (tree aggr, tree identifier)
 /* Finish a template template parameter, specified as AGGR IDENTIFIER.
    Returns the parameter.  */
 
 /* Finish a template template parameter, specified as AGGR IDENTIFIER.
    Returns the parameter.  */
 
-tree 
+tree
 finish_template_template_parm (tree aggr, tree identifier)
 {
   tree decl = build_decl (TYPE_DECL, identifier, NULL_TREE);
 finish_template_template_parm (tree aggr, tree identifier)
 {
   tree decl = build_decl (TYPE_DECL, identifier, NULL_TREE);
@@ -2045,13 +2110,13 @@ check_template_template_default_arg (tree argument)
 
          /* Try to emit a slightly smarter error message if we detect
             that the user is using a template instantiation.  */
 
          /* Try to emit a slightly smarter error message if we detect
             that the user is using a template instantiation.  */
-         if (CLASSTYPE_TEMPLATE_INFO (t) 
+         if (CLASSTYPE_TEMPLATE_INFO (t)
              && CLASSTYPE_TEMPLATE_INSTANTIATION (t))
            error ("invalid use of type %qT as a default value for a "
              && CLASSTYPE_TEMPLATE_INSTANTIATION (t))
            error ("invalid use of type %qT as a default value for a "
-                  "template template-parameter", t);
+                  "template template-parameter", t);
          else
            error ("invalid use of %qD as a default value for a template "
          else
            error ("invalid use of %qD as a default value for a template "
-                  "template-parameter", argument);
+                  "template-parameter", argument);
        }
       else
        error ("invalid default argument for a template template parameter");
        }
       else
        error ("invalid default argument for a template template parameter");
@@ -2077,7 +2142,7 @@ begin_class_definition (tree t)
   /* A non-implicit typename comes from code like:
 
        template <typename T> struct A {
   /* A non-implicit typename comes from code like:
 
        template <typename T> struct A {
-         template <typename U> struct A<T>::B ...
+        template <typename U> struct A<T>::B ...
 
      This is erroneous.  */
   else if (TREE_CODE (t) == TYPENAME_TYPE)
 
      This is erroneous.  */
   else if (TREE_CODE (t) == TYPENAME_TYPE)
@@ -2089,25 +2154,16 @@ begin_class_definition (tree t)
   if (t == error_mark_node || ! IS_AGGR_TYPE (t))
     {
       t = make_aggr_type (RECORD_TYPE);
   if (t == error_mark_node || ! IS_AGGR_TYPE (t))
     {
       t = make_aggr_type (RECORD_TYPE);
-      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 %q#T", t);
-      cp_error_at ("previous definition of %q#T", t);
-      return error_mark_node;
+      pushtag (make_anon_name (), t, /*tag_scope=*/ts_current);
     }
 
   /* Update the location of the decl.  */
   DECL_SOURCE_LOCATION (TYPE_NAME (t)) = input_location;
     }
 
   /* Update the location of the decl.  */
   DECL_SOURCE_LOCATION (TYPE_NAME (t)) = input_location;
-  
+
   if (TYPE_BEING_DEFINED (t))
     {
       t = make_aggr_type (TREE_CODE (t));
   if (TYPE_BEING_DEFINED (t))
     {
       t = make_aggr_type (TREE_CODE (t));
-      pushtag (TYPE_IDENTIFIER (t), t, 0);
+      pushtag (TYPE_IDENTIFIER (t), t, /*tag_scope=*/ts_current);
     }
   maybe_process_partial_specialization (t);
   pushclass (t);
     }
   maybe_process_partial_specialization (t);
   pushclass (t);
@@ -2133,7 +2189,7 @@ begin_class_definition (tree t)
        (t, finfo->interface_unknown);
     }
   reset_specialization();
        (t, finfo->interface_unknown);
     }
   reset_specialization();
-  
+
   /* Make a declaration for this class in its own scope.  */
   build_self_reference ();
 
   /* Make a declaration for this class in its own scope.  */
   build_self_reference ();
 
@@ -2157,9 +2213,9 @@ finish_member_declaration (tree decl)
   gcc_assert (TREE_CHAIN (decl) == NULL_TREE);
 
   /* Set up access control for DECL.  */
   gcc_assert (TREE_CHAIN (decl) == NULL_TREE);
 
   /* Set up access control for DECL.  */
-  TREE_PRIVATE (decl) 
+  TREE_PRIVATE (decl)
     = (current_access_specifier == access_private_node);
     = (current_access_specifier == access_private_node);
-  TREE_PROTECTED (decl) 
+  TREE_PROTECTED (decl)
     = (current_access_specifier == access_protected_node);
   if (TREE_CODE (decl) == TEMPLATE_DECL)
     {
     = (current_access_specifier == access_protected_node);
   if (TREE_CODE (decl) == TEMPLATE_DECL)
     {
@@ -2180,21 +2236,22 @@ finish_member_declaration (tree decl)
   /* Put functions on the TYPE_METHODS list and everything else on the
      TYPE_FIELDS list.  Note that these are built up in reverse order.
      We reverse them (to obtain declaration order) in finish_struct.  */
   /* Put functions on the TYPE_METHODS list and everything else on the
      TYPE_FIELDS list.  Note that these are built up in reverse order.
      We reverse them (to obtain declaration order) in finish_struct.  */
-  if (TREE_CODE (decl) == FUNCTION_DECL 
+  if (TREE_CODE (decl) == FUNCTION_DECL
       || DECL_FUNCTION_TEMPLATE_P (decl))
     {
       /* We also need to add this function to the
         CLASSTYPE_METHOD_VEC.  */
       || DECL_FUNCTION_TEMPLATE_P (decl))
     {
       /* We also need to add this function to the
         CLASSTYPE_METHOD_VEC.  */
-      add_method (current_class_type, decl);
-
-      TREE_CHAIN (decl) = TYPE_METHODS (current_class_type);
-      TYPE_METHODS (current_class_type) = decl;
+      if (add_method (current_class_type, decl, NULL_TREE))
+       {
+         TREE_CHAIN (decl) = TYPE_METHODS (current_class_type);
+         TYPE_METHODS (current_class_type) = decl;
 
 
-      maybe_add_class_template_decl_list (current_class_type, decl, 
-                                         /*friend_p=*/0);
+         maybe_add_class_template_decl_list (current_class_type, decl,
+                                             /*friend_p=*/0);
+       }
     }
   /* Enter the DECL into the scope of the class.  */
     }
   /* Enter the DECL into the scope of the class.  */
-  else if ((TREE_CODE (decl) == USING_DECL && TREE_TYPE (decl))
+  else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl))
           || pushdecl_class_level (decl))
     {
       /* All TYPE_DECLs go at the end of TYPE_FIELDS.  Ordinary fields
           || pushdecl_class_level (decl))
     {
       /* All TYPE_DECLs go at the end of TYPE_FIELDS.  Ordinary fields
@@ -2215,7 +2272,7 @@ finish_member_declaration (tree decl)
         list.)  */
 
       if (TREE_CODE (decl) == TYPE_DECL)
         list.)  */
 
       if (TREE_CODE (decl) == TYPE_DECL)
-       TYPE_FIELDS (current_class_type) 
+       TYPE_FIELDS (current_class_type)
          = chainon (TYPE_FIELDS (current_class_type), decl);
       else
        {
          = chainon (TYPE_FIELDS (current_class_type), decl);
       else
        {
@@ -2223,7 +2280,7 @@ finish_member_declaration (tree decl)
          TYPE_FIELDS (current_class_type) = decl;
        }
 
          TYPE_FIELDS (current_class_type) = decl;
        }
 
-      maybe_add_class_template_decl_list (current_class_type, decl, 
+      maybe_add_class_template_decl_list (current_class_type, decl,
                                          /*friend_p=*/0);
     }
 
                                          /*friend_p=*/0);
     }
 
@@ -2241,20 +2298,6 @@ note_decl_for_pch (tree decl)
 {
   gcc_assert (pch_file);
 
 {
   gcc_assert (pch_file);
 
-  /* 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;
-    }
-  
   /* 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
   /* 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
@@ -2300,7 +2343,7 @@ finish_template_type (tree name, tree args, int entering_scope)
    access_{default,public,protected_private}_node.  For a virtual base
    we set TREE_TYPE.  */
 
    access_{default,public,protected_private}_node.  For a virtual base
    we set TREE_TYPE.  */
 
-tree 
+tree
 finish_base_specifier (tree base, tree access, bool virtual_p)
 {
   tree result;
 finish_base_specifier (tree base, tree access, bool virtual_p)
 {
   tree result;
@@ -2315,10 +2358,10 @@ finish_base_specifier (tree base, tree access, bool virtual_p)
   else
     {
       if (cp_type_quals (base) != 0)
   else
     {
       if (cp_type_quals (base) != 0)
-        {
-          error ("base class %qT has cv qualifiers", base);
-          base = TYPE_MAIN_VARIANT (base);
-        }
+       {
+         error ("base class %qT has cv qualifiers", base);
+         base = TYPE_MAIN_VARIANT (base);
+       }
       result = build_tree_list (access, base);
       if (virtual_p)
        TREE_TYPE (result) = integer_type_node;
       result = build_tree_list (access, base);
       if (virtual_p)
        TREE_TYPE (result) = integer_type_node;
@@ -2333,7 +2376,9 @@ finish_base_specifier (tree base, tree access, bool virtual_p)
 void
 qualified_name_lookup_error (tree scope, tree name, tree decl)
 {
 void
 qualified_name_lookup_error (tree scope, tree name, tree decl)
 {
-  if (TYPE_P (scope))
+  if (scope == error_mark_node)
+    ; /* We already complained.  */
+  else if (TYPE_P (scope))
     {
       if (!COMPLETE_TYPE_P (scope))
        error ("incomplete type %qT used in nested name specifier", scope);
     {
       if (!COMPLETE_TYPE_P (scope))
        error ("incomplete type %qT used in nested name specifier", scope);
@@ -2350,12 +2395,12 @@ qualified_name_lookup_error (tree scope, tree name, tree decl)
   else
     error ("%<::%D%> has not been declared", name);
 }
   else
     error ("%<::%D%> has not been declared", name);
 }
-             
+
 /* ID_EXPRESSION is a representation of parsed, but unprocessed,
    id-expression.  (See cp_parser_id_expression for details.)  SCOPE,
    if non-NULL, is the type or namespace used to explicitly qualify
    ID_EXPRESSION.  DECL is the entity to which that name has been
 /* ID_EXPRESSION is a representation of parsed, but unprocessed,
    id-expression.  (See cp_parser_id_expression for details.)  SCOPE,
    if non-NULL, is the type or namespace used to explicitly qualify
    ID_EXPRESSION.  DECL is the entity to which that name has been
-   resolved.  
+   resolved.
 
    *CONSTANT_EXPRESSION_P is true if we are presently parsing a
    constant-expression.  In that case, *NON_CONSTANT_EXPRESSION_P will
 
    *CONSTANT_EXPRESSION_P is true if we are presently parsing a
    constant-expression.  In that case, *NON_CONSTANT_EXPRESSION_P will
@@ -2365,6 +2410,13 @@ qualified_name_lookup_error (tree scope, tree name, tree decl)
    constant-expression, but a non-constant expression is also
    permissible.
 
    constant-expression, but a non-constant expression is also
    permissible.
 
+   DONE is true if this expression is a complete postfix-expression;
+   it is false if this expression is followed by '->', '[', '(', etc.
+   ADDRESS_P is true iff this expression is the operand of '&'.
+   TEMPLATE_P is true iff the qualified-id was of the form
+   "A::template B".  TEMPLATE_ARG_P is true iff this qualified name
+   appears as a template argument.
+
    If an error occurs, and it is the kind of error that might cause
    the parser to abort a tentative parse, *ERROR_MSG is filled in.  It
    is the caller's responsibility to issue the message.  *ERROR_MSG
    If an error occurs, and it is the kind of error that might cause
    the parser to abort a tentative parse, *ERROR_MSG is filled in.  It
    is the caller's responsibility to issue the message.  *ERROR_MSG
@@ -2374,19 +2426,22 @@ qualified_name_lookup_error (tree scope, tree name, tree decl)
    Return an expression for the entity, after issuing appropriate
    diagnostics.  This function is also responsible for transforming a
    reference to a non-static member into a COMPONENT_REF that makes
    Return an expression for the entity, after issuing appropriate
    diagnostics.  This function is also responsible for transforming a
    reference to a non-static member into a COMPONENT_REF that makes
-   the use of "this" explicit.  
+   the use of "this" explicit.
 
    Upon return, *IDK will be filled in appropriately.  */
 
 tree
 
    Upon return, *IDK will be filled in appropriately.  */
 
 tree
-finish_id_expression (tree id_expression, 
+finish_id_expression (tree id_expression,
                      tree decl,
                      tree scope,
                      cp_id_kind *idk,
                      tree decl,
                      tree scope,
                      cp_id_kind *idk,
-                     tree *qualifying_class,
                      bool integral_constant_expression_p,
                      bool allow_non_integral_constant_expression_p,
                      bool *non_integral_constant_expression_p,
                      bool integral_constant_expression_p,
                      bool allow_non_integral_constant_expression_p,
                      bool *non_integral_constant_expression_p,
+                     bool template_p,
+                     bool done,
+                     bool address_p,
+                     bool template_arg_p,
                      const char **error_msg)
 {
   /* Initialize the output parameters.  */
                      const char **error_msg)
 {
   /* Initialize the output parameters.  */
@@ -2402,13 +2457,13 @@ finish_id_expression (tree id_expression,
           || TREE_CODE (decl) == TYPE_DECL)
     ;
   /* Look up the name.  */
           || TREE_CODE (decl) == TYPE_DECL)
     ;
   /* Look up the name.  */
-  else 
+  else
     {
       if (decl == error_mark_node)
        {
          /* Name lookup failed.  */
     {
       if (decl == error_mark_node)
        {
          /* Name lookup failed.  */
-         if (scope 
-             && (!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 (scope)
                      && !(TREE_CODE (id_expression) == IDENTIFIER_NODE
                           && IDENTIFIER_TYPENAME_P (id_expression)
@@ -2441,6 +2496,21 @@ finish_id_expression (tree id_expression,
         was entirely defined.  */
       if (!scope && decl != error_mark_node)
        maybe_note_name_used_in_class (id_expression, decl);
         was entirely defined.  */
       if (!scope && decl != error_mark_node)
        maybe_note_name_used_in_class (id_expression, decl);
+
+      /* Disallow uses of local variables from containing functions.  */
+      if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
+       {
+         tree context = decl_function_context (decl);
+         if (context != NULL_TREE && context != current_function_decl
+             && ! TREE_STATIC (decl))
+           {
+             error (TREE_CODE (decl) == VAR_DECL
+                    ? "use of %<auto%> variable from containing function"
+                    : "use of parameter from containing function");
+             error ("  %q+#D declared here", decl);
+             return error_mark_node;
+           }
+       }
     }
 
   /* If we didn't find anything, or what we found was a type,
     }
 
   /* If we didn't find anything, or what we found was a type,
@@ -2464,13 +2534,13 @@ finish_id_expression (tree id_expression,
       || TREE_CODE (decl) == TEMPLATE_PARM_INDEX)
     {
       tree r;
       || 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));
       *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 
+
+      if (integral_constant_expression_p
          && !dependent_type_p (TREE_TYPE (decl))
          && !(INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (r))))
        {
          && !dependent_type_p (TREE_TYPE (decl))
          && !(INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (r))))
        {
@@ -2482,7 +2552,7 @@ finish_id_expression (tree id_expression,
        }
       return r;
     }
        }
       return r;
     }
-  /* Similarly, we resolve enumeration constants to their 
+  /* Similarly, we resolve enumeration constants to their
      underlying values.  */
   else if (TREE_CODE (decl) == CONST_DECL)
     {
      underlying values.  */
   else if (TREE_CODE (decl) == CONST_DECL)
     {
@@ -2498,7 +2568,7 @@ finish_id_expression (tree id_expression,
       /* If the declaration was explicitly qualified indicate
         that.  The semantics of `A::f(3)' are different than
         `f(3)' if `f' is virtual.  */
       /* If the declaration was explicitly qualified indicate
         that.  The semantics of `A::f(3)' are different than
         `f(3)' if `f' is virtual.  */
-      *idk = (scope 
+      *idk = (scope
              ? CP_ID_KIND_QUALIFIED
              : (TREE_CODE (decl) == TEMPLATE_ID_EXPR
                 ? CP_ID_KIND_TEMPLATE_ID
              ? CP_ID_KIND_QUALIFIED
              : (TREE_CODE (decl) == TEMPLATE_ID_EXPR
                 ? CP_ID_KIND_TEMPLATE_ID
@@ -2522,13 +2592,13 @@ finish_id_expression (tree id_expression,
       /* A template-id where the name of the template was not resolved
         is definitely dependent.  */
       else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
       /* A template-id where the name of the template was not resolved
         is definitely dependent.  */
       else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
-              && (TREE_CODE (TREE_OPERAND (decl, 0)) 
+              && (TREE_CODE (TREE_OPERAND (decl, 0))
                   == IDENTIFIER_NODE))
        dependent_p = true;
       /* For anything except an overloaded function, just check its
         type.  */
       else if (!is_overloaded_fn (decl))
                   == IDENTIFIER_NODE))
        dependent_p = true;
       /* For anything except an overloaded function, just check its
         type.  */
       else if (!is_overloaded_fn (decl))
-       dependent_p 
+       dependent_p
          = dependent_type_p (TREE_TYPE (decl));
       /* For a set of overloaded functions, check each of the
         functions.  */
          = dependent_type_p (TREE_TYPE (decl));
       /* For a set of overloaded functions, check each of the
         functions.  */
@@ -2577,30 +2647,37 @@ finish_id_expression (tree id_expression,
             dependent.  */
          if (scope)
            {
             dependent.  */
          if (scope)
            {
-             if (TYPE_P (scope))
-               *qualifying_class = scope;
              /* 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;
              /* 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;
-             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 convert_from_reference
-                 (build2 (SCOPE_REF, TREE_TYPE (decl), scope, id_expression));
-             else
-               return convert_from_reference (decl);
+             if (TYPE_P (scope))
+               {
+                 if (address_p && done)
+                   decl = finish_qualified_id_expr (scope, decl,
+                                                    done, address_p,
+                                                    template_p,
+                                                    template_arg_p);
+                 else if (dependent_type_p (scope))
+                   decl = build_qualified_name (/*type=*/NULL_TREE,
+                                                scope,
+                                                id_expression,
+                                                template_p);
+                 else if (DECL_P (decl))
+                   decl = build_qualified_name (TREE_TYPE (decl),
+                                                scope,
+                                                id_expression,
+                                                template_p);
+               }
+             if (TREE_TYPE (decl))
+               decl = convert_from_reference (decl);
+             return decl;
            }
          /* A TEMPLATE_ID already contains all the information we
             need.  */
          if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR)
            return id_expression;
            }
          /* 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
          *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
@@ -2611,17 +2688,26 @@ finish_id_expression (tree id_expression,
          /* 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)
          /* 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)
-           return 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 ();
+             return decl;
+           }
          return id_expression;
        }
 
       /* Only certain kinds of names are allowed in constant
          return id_expression;
        }
 
       /* Only certain kinds of names are allowed in constant
-         expression.  Enumerators and template parameters have already
-         been handled above.  */
+        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))
+         && ! DECL_INTEGRAL_CONSTANT_VAR_P (decl)
+         && ! builtin_valid_in_constant_expr_p (decl))
        {
          if (!allow_non_integral_constant_expression_p)
            {
        {
          if (!allow_non_integral_constant_expression_p)
            {
@@ -2630,7 +2716,7 @@ finish_id_expression (tree id_expression,
            }
          *non_integral_constant_expression_p = true;
        }
            }
          *non_integral_constant_expression_p = true;
        }
-      
+
       if (TREE_CODE (decl) == NAMESPACE_DECL)
        {
          error ("use of namespace %qD as expression", decl);
       if (TREE_CODE (decl) == NAMESPACE_DECL)
        {
          error ("use of namespace %qD as expression", decl);
@@ -2659,27 +2745,40 @@ finish_id_expression (tree id_expression,
 
       if (scope)
        {
 
       if (scope)
        {
-         decl = (adjust_result_of_qualified_name_lookup 
+         decl = (adjust_result_of_qualified_name_lookup
                  (decl, scope, current_class_type));
 
          if (TREE_CODE (decl) == FUNCTION_DECL)
            mark_used (decl);
 
          if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl))
                  (decl, scope, current_class_type));
 
          if (TREE_CODE (decl) == FUNCTION_DECL)
            mark_used (decl);
 
          if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl))
-           *qualifying_class = scope;
+           decl = finish_qualified_id_expr (scope,
+                                            decl,
+                                            done,
+                                            address_p,
+                                            template_p,
+                                            template_arg_p);
          else
            {
              tree r = convert_from_reference (decl);
          else
            {
              tree r = convert_from_reference (decl);
-             
-             if (processing_template_decl
-                 && TYPE_P (scope))
-               r = build2 (SCOPE_REF, TREE_TYPE (r), scope, decl);
+
+             if (processing_template_decl && TYPE_P (scope))
+               r = build_qualified_name (TREE_TYPE (r),
+                                         scope, decl,
+                                         template_p);
              decl = r;
            }
        }
       else if (TREE_CODE (decl) == FIELD_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);
       else if (is_overloaded_fn (decl))
        {
          tree first_fn = OVL_CURRENT (decl);
@@ -2690,51 +2789,31 @@ finish_id_expression (tree id_expression,
          if (!really_overloaded_fn (decl))
            mark_used (first_fn);
 
          if (!really_overloaded_fn (decl))
            mark_used (first_fn);
 
-         if (TREE_CODE (first_fn) == FUNCTION_DECL
+         if (!template_arg_p
+             && TREE_CODE (first_fn) == FUNCTION_DECL
              && DECL_FUNCTION_MEMBER_P (first_fn)
              && !shared_member_p (decl))
            {
              /* A set of member functions.  */
              decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
              && DECL_FUNCTION_MEMBER_P (first_fn)
              && !shared_member_p (decl))
            {
              /* A set of member functions.  */
              decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
-             return finish_class_member_access_expr (decl, id_expression);
+             return finish_class_member_access_expr (decl, id_expression,
+                                                     /*template_p=*/false);
            }
        }
       else
        {
            }
        }
       else
        {
-         if (TREE_CODE (decl) == VAR_DECL
-             || TREE_CODE (decl) == PARM_DECL
-             || TREE_CODE (decl) == RESULT_DECL)
-           {
-             tree context = decl_function_context (decl);
-             
-             if (context != NULL_TREE && context != current_function_decl
-                 && ! TREE_STATIC (decl))
-               {
-                 error ("use of %s from containing function",
-                        (TREE_CODE (decl) == VAR_DECL
-                         ? "%<auto%> variable" : "parameter"));
-                 cp_error_at ("  %q#D declared here", decl);
-                 return error_mark_node;
-               }
-           }
-         
          if (DECL_P (decl) && DECL_NONLOCAL (decl)
              && DECL_CLASS_SCOPE_P (decl)
              && DECL_CONTEXT (decl) != current_class_type)
            {
              tree path;
          if (DECL_P (decl) && DECL_NONLOCAL (decl)
              && DECL_CLASS_SCOPE_P (decl)
              && DECL_CONTEXT (decl) != current_class_type)
            {
              tree path;
-             
+
              path = currently_open_derived_class (DECL_CONTEXT (decl));
              perform_or_defer_access_check (TYPE_BINFO (path), decl);
            }
              path = currently_open_derived_class (DECL_CONTEXT (decl));
              perform_or_defer_access_check (TYPE_BINFO (path), 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 = unshare_expr (DECL_INITIAL (decl));
     }
 
   if (TREE_DEPRECATED (decl))
     }
 
   if (TREE_DEPRECATED (decl))
@@ -2774,9 +2853,9 @@ finish_typeof (tree expr)
    with equivalent CALL_EXPRs.  */
 
 static tree
    with equivalent CALL_EXPRs.  */
 
 static tree
-simplify_aggr_init_exprs_r (tree* tp, 
-                            int* walk_subtrees,
-                            void* data ATTRIBUTE_UNUSED)
+simplify_aggr_init_exprs_r (tree* tp,
+                           int* walk_subtrees,
+                           void* data ATTRIBUTE_UNUSED)
 {
   /* We don't need to walk into types; there's nothing in a type that
      needs simplification.  (And, furthermore, there are places we
 {
   /* We don't need to walk into types; there's nothing in a type that
      needs simplification.  (And, furthermore, there are places we
@@ -2828,38 +2907,30 @@ simplify_aggr_init_expr (tree *tp)
       style = arg;
     }
 
       style = arg;
     }
 
-  if (style == ctor || style == arg)
+  if (style == ctor)
     {
     {
-      /* Pass the address of the slot.  If this is a constructor, we
-        replace the first argument; otherwise, we tack on a new one.  */
+      /* Replace the first argument to the ctor with the address of the
+        slot.  */
       tree addr;
 
       tree addr;
 
-      if (style == ctor)
-       args = TREE_CHAIN (args);
-
+      args = TREE_CHAIN (args);
       cxx_mark_addressable (slot);
       addr = build1 (ADDR_EXPR, build_pointer_type (type), slot);
       cxx_mark_addressable (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));
-         
-         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);
     }
 
       args = tree_cons (NULL_TREE, addr, args);
     }
 
-  call_expr = build3 (CALL_EXPR, 
+  call_expr = build3 (CALL_EXPR,
                      TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
                      fn, args, NULL_TREE);
 
   if (style == arg)
                      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
-       list.  */
-    CALL_EXPR_HAS_RETURN_SLOT_ADDR (call_expr) = 1;
+    {
+      /* Just mark it addressable here, and leave the rest to
+        expand_call{,_inline}.  */
+      cxx_mark_addressable (slot);
+      CALL_EXPR_RETURN_SLOT_OPT (call_expr) = true;
+      call_expr = build2 (MODIFY_EXPR, TREE_TYPE (call_expr), slot, call_expr);
+    }
   else if (style == pcc)
     {
       /* If we're using the non-reentrant PCC calling convention, then we
   else if (style == pcc)
     {
       /* If we're using the non-reentrant PCC calling convention, then we
@@ -2869,6 +2940,7 @@ simplify_aggr_init_expr (tree *tp)
       call_expr = build_aggr_init (slot, call_expr,
                                   DIRECT_BIND | LOOKUP_ONLYCONVERTING);
       pop_deferring_access_checks ();
       call_expr = build_aggr_init (slot, call_expr,
                                   DIRECT_BIND | LOOKUP_ONLYCONVERTING);
       pop_deferring_access_checks ();
+      call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (slot), call_expr, slot);
     }
 
   *tp = call_expr;
     }
 
   *tp = call_expr;
@@ -2887,7 +2959,7 @@ emit_associated_thunks (tree fn)
   if (DECL_VIRTUAL_P (fn))
     {
       tree thunk;
   if (DECL_VIRTUAL_P (fn))
     {
       tree thunk;
-      
+
       for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
        {
          if (!THUNK_ALIAS (thunk))
       for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
        {
          if (!THUNK_ALIAS (thunk))
@@ -2896,7 +2968,7 @@ emit_associated_thunks (tree fn)
              if (DECL_RESULT_THUNK_P (thunk))
                {
                  tree probe;
              if (DECL_RESULT_THUNK_P (thunk))
                {
                  tree probe;
-                 
+
                  for (probe = DECL_THUNKS (thunk);
                       probe; probe = TREE_CHAIN (probe))
                    use_thunk (probe, /*emit_p=*/1);
                  for (probe = DECL_THUNKS (thunk);
                       probe; probe = TREE_CHAIN (probe))
                    use_thunk (probe, /*emit_p=*/1);
@@ -2946,9 +3018,9 @@ expand_body (tree fn)
   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
-         their parameters used.  We have to do that here, as we don't
-         know whether any particular clone will be expanded, and
-         therefore cannot pick one arbitrarily.  */ 
+        their parameters used.  We have to do that here, as we don't
+        know whether any particular clone will be expanded, and
+        therefore cannot pick one arbitrarily.  */
       tree probe;
 
       for (probe = TREE_CHAIN (DECL_CLONED_FUNCTION (fn));
       tree probe;
 
       for (probe = TREE_CHAIN (DECL_CLONED_FUNCTION (fn));
@@ -2976,8 +3048,11 @@ expand_or_defer_fn (tree fn)
       /* Normally, collection only occurs in rest_of_compilation.  So,
         if we don't collect here, we never collect junk generated
         during the processing of templates until we hit a
       /* Normally, collection only occurs in rest_of_compilation.  So,
         if we don't collect here, we never collect junk generated
         during the processing of templates until we hit a
-        non-template function.  */
-      ggc_collect ();
+        non-template function.  It's not safe to do this inside a
+        nested class, though, as the parser may have local state that
+        is not a GC root.  */
+      if (!function_depth)
+       ggc_collect ();
       return;
     }
 
       return;
     }
 
@@ -3014,11 +3089,28 @@ expand_or_defer_fn (tree fn)
      these functions so that it can inline them as appropriate.  */
   if (DECL_DECLARED_INLINE_P (fn) || DECL_IMPLICIT_INSTANTIATION (fn))
     {
      these functions so that it can inline them as appropriate.  */
   if (DECL_DECLARED_INLINE_P (fn) || DECL_IMPLICIT_INSTANTIATION (fn))
     {
-      if (!at_eof)
+      if (DECL_INTERFACE_KNOWN (fn))
+       /* We've already made a decision as to how this function will
+          be handled.  */;
+      else if (!at_eof)
        {
          DECL_EXTERNAL (fn) = 1;
          DECL_NOT_REALLY_EXTERN (fn) = 1;
          note_vague_linkage_fn (fn);
        {
          DECL_EXTERNAL (fn) = 1;
          DECL_NOT_REALLY_EXTERN (fn) = 1;
          note_vague_linkage_fn (fn);
+         /* 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 (!DECL_IMPLICIT_INSTANTIATION (fn))
+           {
+             /* This function must have external linkage, as
+                otherwise DECL_INTERFACE_KNOWN would have been
+                set.  */
+             gcc_assert (TREE_PUBLIC (fn));
+             comdat_linkage (fn);
+             DECL_INTERFACE_KNOWN (fn) = 1;
+           }
        }
       else
        import_export_decl (fn);
        }
       else
        import_export_decl (fn);