OSDN Git Service

PR c++/29048
[pf3gnuchains/gcc-fork.git] / gcc / cp / semantics.c
index a200bf4..49dd80e 100644 (file)
@@ -3,8 +3,8 @@
    building RTL.  These routines are used both during actual parsing
    and during the instantiation of template functions.
 
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-   Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+                2008 Free Software Foundation, Inc.
    Written by Mark Mitchell (mmitchell@usa.net) based on code found
    formerly in parse.y and pt.c.
 
@@ -12,7 +12,7 @@
 
    GCC is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GCC is distributed in the hope that it will be useful, but
    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
-   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.  */
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 /* There routines provide a modular interface to perform many parsing
    operations.  They may therefore be used during actual parsing, or
    during template instantiation, which may be regarded as a
-   degenerate form of parsing.  Since the current g++ parser is
-   lacking in several respects, and will be reimplemented, we are
-   attempting to move most code that is not directly related to
-   parsing into this file; that will make implementing the new parser
-   much easier since it will be able to make use of these routines.  */
+   degenerate form of parsing.  */
 
 static tree maybe_convert_cond (tree);
 static tree simplify_aggr_init_exprs_r (tree *, int *, void *);
-static void emit_associated_thunks (tree);
 static tree finalize_nrv_r (tree *, int *, void *);
 
 
@@ -100,7 +94,7 @@ static tree finalize_nrv_r (tree *, int *, void *);
 
    2. When a declaration such as a type, or a variable, is encountered,
       the function `perform_or_defer_access_check' is called.  It
-      maintains a TREE_LIST of all deferred checks.
+      maintains a VEC of all deferred checks.
 
    3. The global `current_class_type' or `current_function_decl' is then
       setup by the parser.  `enforce_access' relies on these information
@@ -108,7 +102,7 @@ static tree finalize_nrv_r (tree *, int *, void *);
 
    4. Upon exiting the context mentioned in step 1,
       `perform_deferred_access_checks' is called to check all declaration
-      stored in the TREE_LIST.   `pop_deferring_access_checks' is then
+      stored in the VEC. `pop_deferring_access_checks' is then
       called to restore the previous access checking mode.
 
       In case of parsing error, we simply call `pop_deferring_access_checks'
@@ -116,7 +110,7 @@ static tree finalize_nrv_r (tree *, int *, void *);
 
 typedef struct deferred_access GTY(())
 {
-  /* A TREE_LIST representing name-lookups for which we have deferred
+  /* A VEC representing name-lookups for which we have deferred
      checking access controls.  We cannot check the accessibility of
      names used in a decl-specifier-seq until we know what is being
      declared because code like:
@@ -128,12 +122,8 @@ typedef struct deferred_access GTY(())
 
        A::B* A::f() { return 0; }
 
-     is valid, even though `A::B' is not generally accessible.
-
-     The TREE_PURPOSE of each node is the scope used to qualify the
-     name being looked up; the TREE_VALUE is the DECL to which the
-     name was resolved.  */
-  tree deferred_access_checks;
+     is valid, even though `A::B' is not generally accessible.  */
+  VEC (deferred_access_check,gc)* GTY(()) deferred_access_checks;
 
   /* The current mode of access checks.  */
   enum deferring_kind deferring_access_checks_kind;
@@ -161,7 +151,7 @@ push_deferring_access_checks (deferring_kind deferring)
       deferred_access *ptr;
 
       ptr = VEC_safe_push (deferred_access, gc, deferred_access_stack, NULL);
-      ptr->deferred_access_checks = NULL_TREE;
+      ptr->deferred_access_checks = NULL;
       ptr->deferring_access_checks_kind = deferring;
     }
 }
@@ -204,7 +194,7 @@ pop_deferring_access_checks (void)
    access occurred; the TREE_VALUE is the declaration named.
    */
 
-tree
+VEC (deferred_access_check,gc)*
 get_deferred_access_checks (void)
 {
   if (deferred_access_no_check)
@@ -225,7 +215,7 @@ pop_to_parent_deferring_access_checks (void)
     deferred_access_no_check--;
   else
     {
-      tree checks;
+      VEC (deferred_access_check,gc) *checks;
       deferred_access *ptr;
 
       checks = (VEC_last (deferred_access, deferred_access_stack)
@@ -236,35 +226,54 @@ pop_to_parent_deferring_access_checks (void)
       if (ptr->deferring_access_checks_kind == dk_no_deferred)
        {
          /* Check access.  */
-         for (; checks; checks = TREE_CHAIN (checks))
-           enforce_access (TREE_PURPOSE (checks),
-                           TREE_VALUE (checks));
+         perform_access_checks (checks);
        }
       else
        {
          /* Merge with parent.  */
-         tree next;
-         tree original = ptr->deferred_access_checks;
+         int i, j;
+         deferred_access_check *chk, *probe;
 
-         for (; checks; checks = next)
+         for (i = 0 ;
+              VEC_iterate (deferred_access_check, checks, i, chk) ;
+              ++i)
            {
-             tree probe;
-
-             next = TREE_CHAIN (checks);
-
-             for (probe = original; probe; probe = TREE_CHAIN (probe))
-               if (TREE_VALUE (probe) == TREE_VALUE (checks)
-                   && TREE_PURPOSE (probe) == TREE_PURPOSE (checks))
-                 goto found;
+             for (j = 0 ;
+                  VEC_iterate (deferred_access_check,
+                               ptr->deferred_access_checks, j, probe) ;
+                  ++j)
+               {
+                 if (probe->binfo == chk->binfo &&
+                     probe->decl == chk->decl &&
+                     probe->diag_decl == chk->diag_decl)
+                   goto found;
+               }
              /* Insert into parent's checks.  */
-             TREE_CHAIN (checks) = ptr->deferred_access_checks;
-             ptr->deferred_access_checks = checks;
+             VEC_safe_push (deferred_access_check, gc,
+                            ptr->deferred_access_checks, chk);
            found:;
            }
        }
     }
 }
 
+/* Perform the access checks in CHECKS.  The TREE_PURPOSE of each node
+   is the BINFO indicating the qualifying scope used to access the
+   DECL node stored in the TREE_VALUE of the node.  */
+
+void
+perform_access_checks (VEC (deferred_access_check,gc)* checks)
+{
+  int i;
+  deferred_access_check *chk;
+
+  if (!checks)
+    return;
+
+  for (i = 0 ; VEC_iterate (deferred_access_check, checks, i, chk) ; ++i)
+    enforce_access (chk->binfo, chk->decl, chk->diag_decl);
+}
+
 /* Perform the deferred access checks.
 
    After performing the checks, we still have to keep the list
@@ -284,24 +293,20 @@ pop_to_parent_deferring_access_checks (void)
 void
 perform_deferred_access_checks (void)
 {
-  tree deferred_check;
-
-  for (deferred_check = get_deferred_access_checks ();
-       deferred_check;
-       deferred_check = TREE_CHAIN (deferred_check))
-    /* Check access.  */
-    enforce_access (TREE_PURPOSE (deferred_check),
-                   TREE_VALUE (deferred_check));
+  perform_access_checks (get_deferred_access_checks ());
 }
 
 /* Defer checking the accessibility of DECL, when looked up in
-   BINFO.  */
+   BINFO. DIAG_DECL is the declaration to use to print diagnostics.  */
 
 void
-perform_or_defer_access_check (tree binfo, tree decl)
+perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
 {
-  tree check;
+  int i;
   deferred_access *ptr;
+  deferred_access_check *chk;
+  deferred_access_check *new_access;
+
 
   /* Exit if we are in a context that no access checking is performed.
      */
@@ -315,19 +320,29 @@ perform_or_defer_access_check (tree binfo, tree decl)
   /* 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);
+      enforce_access (binfo, decl, diag_decl);
       return;
     }
 
   /* See if we are already going to perform this check.  */
-  for (check = ptr->deferred_access_checks;
-       check;
-       check = TREE_CHAIN (check))
-    if (TREE_VALUE (check) == decl && TREE_PURPOSE (check) == binfo)
-      return;
+  for (i = 0 ;
+       VEC_iterate (deferred_access_check,
+                   ptr->deferred_access_checks, i, chk) ;
+       ++i)
+    {
+      if (chk->decl == decl && chk->binfo == binfo &&
+         chk->diag_decl == diag_decl)
+       {
+         return;
+       }
+    }
   /* If not, record the check.  */
-  ptr->deferred_access_checks
-    = tree_cons (binfo, decl, ptr->deferred_access_checks);
+  new_access =
+    VEC_safe_push (deferred_access_check, gc,
+                  ptr->deferred_access_checks, 0);
+  new_access->binfo = binfo;
+  new_access->decl = decl;
+  new_access->diag_decl = diag_decl;
 }
 
 /* Returns nonzero if the current statement is a full expression,
@@ -420,7 +435,7 @@ add_decl_expr (tree decl)
    declared is not an anonymous union" [class.union].  */
 
 int
-anon_aggr_type_p (tree node)
+anon_aggr_type_p (const_tree node)
 {
   return ANON_AGGR_TYPE_P (node);
 }
@@ -492,6 +507,9 @@ finish_cond (tree *cond_p, tree expr)
       tree cond = pop_stmt_list (*cond_p);
       if (TREE_CODE (cond) == DECL_EXPR)
        expr = cond;
+
+      if (check_for_bare_parameter_packs (expr))
+        *cond_p = error_mark_node;
     }
   *cond_p = expr;
 }
@@ -570,6 +588,16 @@ maybe_convert_cond (tree cond)
 
   /* Do the conversion.  */
   cond = convert_from_reference (cond);
+
+  if (TREE_CODE (cond) == MODIFY_EXPR
+      && !TREE_NO_WARNING (cond)
+      && warn_parentheses)
+    {
+      warning (OPT_Wparentheses,
+              "suggest parentheses around assignment used as truth value");
+      TREE_NO_WARNING (cond) = 1;
+    }
+
   return condition_conversion (cond);
 }
 
@@ -591,6 +619,9 @@ finish_expr_stmt (tree expr)
       else if (!type_dependent_expression_p (expr))
        convert_to_void (build_non_dependent_expr (expr), "statement");
 
+      if (check_for_bare_parameter_packs (expr))
+        expr = error_mark_node;
+
       /* Simplification of inner statement expressions, compound exprs,
         etc can result in us already having an EXPR_STMT.  */
       if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
@@ -670,6 +701,7 @@ finish_if_stmt (tree if_stmt)
   TREE_CHAIN (if_stmt) = NULL;
   add_stmt (do_poplevel (scope));
   finish_stmt ();
+  empty_if_body_warning (THEN_CLAUSE (if_stmt), ELSE_CLAUSE (if_stmt));
 }
 
 /* Begin a while-statement.  Returns a newly created WHILE_STMT if
@@ -722,7 +754,14 @@ begin_do_stmt (void)
 void
 finish_do_body (tree do_stmt)
 {
-  DO_BODY (do_stmt) = pop_stmt_list (DO_BODY (do_stmt));
+  tree body = DO_BODY (do_stmt) = pop_stmt_list (DO_BODY (do_stmt));
+
+  if (TREE_CODE (body) == STATEMENT_LIST && STATEMENT_LIST_TAIL (body))
+    body = STATEMENT_LIST_TAIL (body)->stmt;
+
+  if (IS_EMPTY_STMT (body))
+    warning (OPT_Wempty_body,
+            "suggest explicit braces around empty body in %<do%> statement");
 }
 
 /* Finish a do-statement, which may be given by DO_STMT, and whose
@@ -746,6 +785,9 @@ finish_return_stmt (tree expr)
   bool no_warning;
 
   expr = check_return_expr (expr, &no_warning);
+
+  if (flag_openmp && !check_omp_return ())
+    return error_mark_node;
   if (!processing_template_decl)
     {
       if (DECL_DESTRUCTOR_P (current_function_decl)
@@ -835,6 +877,8 @@ finish_for_expr (tree expr, tree for_stmt)
   else if (!type_dependent_expression_p (expr))
     convert_to_void (build_non_dependent_expr (expr), "3rd expression in for");
   expr = maybe_cleanup_point_expr_void (expr);
+  if (check_for_bare_parameter_packs (expr))
+    expr = error_mark_node;
   FOR_EXPR (for_stmt) = expr;
 }
 
@@ -930,6 +974,8 @@ finish_switch_cond (tree cond, tree switch_stmt)
            cond = index;
        }
     }
+  if (check_for_bare_parameter_packs (cond))
+    cond = error_mark_node;
   finish_cond (&SWITCH_STMT_COND (switch_stmt), cond);
   SWITCH_STMT_TYPE (switch_stmt) = orig_type;
   add_stmt (switch_stmt);
@@ -967,12 +1013,18 @@ begin_try_block (void)
   return r;
 }
 
-/* Likewise, for a function-try-block.  */
+/* Likewise, for a function-try-block.  The block returned in
+   *COMPOUND_STMT is an artificial outer scope, containing the
+   function-try-block.  */
 
 tree
-begin_function_try_block (void)
+begin_function_try_block (tree *compound_stmt)
 {
-  tree r = begin_try_block ();
+  tree r;
+  /* This outer scope does not exist in the C++ standard, but we need
+     a place to put __FUNCTION__ and similar variables.  */
+  *compound_stmt = begin_compound_stmt (0);
+  r = begin_try_block ();
   FN_TRY_BLOCK_P (r) = 1;
   return r;
 }
@@ -1026,13 +1078,16 @@ finish_handler_sequence (tree try_block)
   check_handlers (TRY_HANDLERS (try_block));
 }
 
-/* Likewise, for a function-try-block.  */
+/* Finish the handler-seq for a function-try-block, given by
+   TRY_BLOCK.  COMPOUND_STMT is the outer block created by
+   begin_function_try_block.  */
 
 void
-finish_function_handler_sequence (tree try_block)
+finish_function_handler_sequence (tree try_block, tree compound_stmt)
 {
   in_function_try_handler = 0;
   finish_handler_sequence (try_block);
+  finish_compound_stmt (compound_stmt);
 }
 
 /* Begin a handler.  Returns a HANDLER if appropriate.  */
@@ -1072,7 +1127,6 @@ finish_handler_parms (tree decl, tree handler)
     }
   else
     type = expand_start_catch_block (decl);
-
   HANDLER_TYPE (handler) = type;
   if (!processing_template_decl && type)
     mark_used (eh_type_info (type));
@@ -1196,18 +1250,18 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands,
          if (!lvalue_or_else (operand, lv_asm))
            operand = error_mark_node;
 
-          if (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);
+                 /* 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)");
 
          constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
          oconstraints[i] = constraint;
@@ -1277,6 +1331,10 @@ tree
 finish_label_stmt (tree name)
 {
   tree decl = define_label (input_location, name);
+
+  if (decl  == error_mark_node)
+    return error_mark_node;
+
   return add_stmt (build_stmt (LABEL_EXPR, decl));
 }
 
@@ -1287,8 +1345,13 @@ finish_label_stmt (tree name)
 void
 finish_label_decl (tree name)
 {
-  tree decl = declare_local_label (name);
-  add_decl_expr (decl);
+  if (!at_function_scope_p ())
+    {
+      error ("__label__ declarations are only allowed in function scopes");
+      return;
+    }
+
+  add_decl_expr (declare_local_label (name));
 }
 
 /* When DECL goes out of scope, make sure that CLEANUP is executed.  */
@@ -1319,7 +1382,23 @@ finish_mem_initializers (tree mem_inits)
   mem_inits = nreverse (mem_inits);
 
   if (processing_template_decl)
-    add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
+    {
+      tree mem;
+
+      for (mem = mem_inits; mem; mem = TREE_CHAIN (mem))
+        {
+          /* If the TREE_PURPOSE is a TYPE_PACK_EXPANSION, skip the
+             check for bare parameter packs in the TREE_VALUE, because
+             any parameter packs in the TREE_VALUE have already been
+             bound as part of the TREE_PURPOSE.  See
+             make_pack_expansion for more information.  */
+          if (TREE_CODE (TREE_PURPOSE (mem)) != TYPE_PACK_EXPANSION
+              && check_for_bare_parameter_packs (TREE_VALUE (mem)))
+            TREE_VALUE (mem) = error_mark_node;
+        }
+
+      add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
+    }
   else
     emit_mem_initializers (mem_inits);
 }
@@ -1412,7 +1491,8 @@ finish_non_static_data_member (tree decl, tree object, tree 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,
+                                    decl);
 
       /* If the data member was named `C::M', convert `*this' to `C'
         first.  */
@@ -1486,10 +1566,13 @@ check_accessibility_of_qualified_id (tree decl,
        its bases.  */
     qualifying_type = currently_open_derived_class (scope);
 
-  if (qualifying_type && IS_AGGR_TYPE_CODE (TREE_CODE (qualifying_type)))
-    /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM
-       or similar in a default argument value.  */
-    perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl);
+  if (qualifying_type 
+      /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM
+        or similar in a default argument value.  */
+      && CLASS_TYPE_P (qualifying_type)
+      && !dependent_type_p (qualifying_type))
+    perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
+                                  decl);
 }
 
 /* EXPR is the result of a qualified-id.  The QUALIFYING_CLASS was the
@@ -1501,10 +1584,10 @@ check_accessibility_of_qualified_id (tree decl,
    is true iff this qualified name appears as a template argument.  */
 
 tree
-finish_qualified_id_expr (tree qualifying_class, 
-                         tree expr, 
+finish_qualified_id_expr (tree qualifying_class,
+                         tree expr,
                          bool done,
-                         bool address_p, 
+                         bool address_p,
                          bool template_p,
                          bool template_arg_p)
 {
@@ -1513,12 +1596,8 @@ finish_qualified_id_expr (tree qualifying_class,
   if (error_operand_p (expr))
     return error_mark_node;
 
-  if (DECL_P (expr))
+  if (DECL_P (expr) || BASELINK_P (expr))
     mark_used (expr);
-  else if (BASELINK_P (expr)
-          && TREE_CODE (BASELINK_FUNCTIONS (expr)) != TEMPLATE_ID_EXPR
-          && !really_overloaded_fn (BASELINK_FUNCTIONS (expr)))
-    mark_used (OVL_CURRENT (BASELINK_FUNCTIONS (expr)));
 
   if (template_p)
     check_template_keyword (expr);
@@ -1541,8 +1620,12 @@ finish_qualified_id_expr (tree qualifying_class,
        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);
+    {
+      push_deferring_access_checks (dk_no_check);
+      expr = finish_non_static_data_member (expr, current_class_ref,
+                                           qualifying_class);
+      pop_deferring_access_checks ();
+    }
   else if (BASELINK_P (expr) && !processing_template_decl)
     {
       tree fns;
@@ -1588,76 +1671,57 @@ tree
 finish_stmt_expr_expr (tree expr, tree stmt_expr)
 {
   if (error_operand_p (expr))
-    return error_mark_node;
+    {
+      /* The type of the statement-expression is the type of the last
+         expression.  */
+      TREE_TYPE (stmt_expr) = error_mark_node;
+      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.  */ 
+     of the last statement is the value of the entire expression.  */
   if (expr)
     {
-      tree type;
-      type = TREE_TYPE (expr);
-      if (!dependent_type_p (type) && !VOID_TYPE_P (type))
+      tree type = TREE_TYPE (expr);
+
+      if (processing_template_decl)
+       {
+         expr = build_stmt (EXPR_STMT, expr);
+         expr = add_stmt (expr);
+         /* Mark the last statement so that we can recognize it as such at
+            template-instantiation time.  */
+         EXPR_STMT_STMT_EXPR_RESULT (expr) = 1;
+       }
+      else if (VOID_TYPE_P (type))
+       {
+         /* Just treat this like an ordinary statement.  */
+         expr = finish_expr_stmt (expr);
+       }
+      else
        {
-         expr = decay_conversion (expr);
+         /* It actually has a value we need to deal with.  First, force it
+            to be an rvalue so that we won't need to build up a copy
+            constructor call later when we try to assign it to something.  */
+         expr = force_rvalue (expr);
          if (error_operand_p (expr))
            return error_mark_node;
+
+         /* Update for array-to-pointer decay.  */
          type = TREE_TYPE (expr);
+
+         /* Wrap it in a CLEANUP_POINT_EXPR and add it to the list like a
+            normal statement, but don't convert to void or actually add
+            the EXPR_STMT.  */
+         if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
+           expr = maybe_cleanup_point_expr (expr);
+         add_stmt (expr);
        }
+
       /* 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
-           {
-             /* 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);
-           }
-         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;
-       }
     }
 
-  /* 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;
 }
 
@@ -1678,6 +1742,7 @@ finish_stmt_expr (tree stmt_expr, bool has_no_scope)
 
   type = TREE_TYPE (stmt_expr);
   result = pop_stmt_list (stmt_expr);
+  TREE_TYPE (result) = type;
 
   if (processing_template_decl)
     {
@@ -1685,17 +1750,37 @@ finish_stmt_expr (tree stmt_expr, bool has_no_scope)
       TREE_SIDE_EFFECTS (result) = 1;
       STMT_EXPR_NO_SCOPE (result) = has_no_scope;
     }
-  else if (!TYPE_P (type))
+  else if (CLASS_TYPE_P (type))
     {
-      gcc_assert (TREE_CODE (type) == TARGET_EXPR);
-      TARGET_EXPR_INITIAL (type) = result;
-      TREE_TYPE (result) = void_type_node;
-      result = type;
+      /* Wrap the statement-expression in a TARGET_EXPR so that the
+        temporary object created by the final expression is destroyed at
+        the end of the full-expression containing the
+        statement-expression.  */
+      result = force_target_expr (type, result);
     }
 
   return result;
 }
 
+/* Returns the expression which provides the value of STMT_EXPR.  */
+
+tree
+stmt_expr_value_expr (tree stmt_expr)
+{
+  tree t = STMT_EXPR_STMT (stmt_expr);
+
+  if (TREE_CODE (t) == BIND_EXPR)
+    t = BIND_EXPR_BODY (t);
+
+  if (TREE_CODE (t) == STATEMENT_LIST)
+    t = STATEMENT_LIST_TAIL (t)->stmt;
+
+  if (TREE_CODE (t) == EXPR_STMT)
+    t = EXPR_STMT_EXPR (t);
+
+  return t;
+}
+
 /* Perform Koenig lookup.  FN is the postfix-expression representing
    the function (or functions) to call; ARGS are the arguments to the
    call.  Returns the functions to be considered by overload
@@ -1758,6 +1843,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
 
   /* ARGS should be a list of arguments.  */
   gcc_assert (!args || TREE_CODE (args) == TREE_LIST);
+  gcc_assert (!TYPE_P (fn));
 
   orig_fn = fn;
   orig_args = args;
@@ -1767,8 +1853,22 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
       if (type_dependent_expression_p (fn)
          || any_type_dependent_arguments_p (args))
        {
-         result = build_nt (CALL_EXPR, fn, args, NULL_TREE);
+         result = build_nt_call_list (fn, args);
          KOENIG_LOOKUP_P (result) = koenig_p;
+         if (cfun)
+           {
+             do
+               {
+                 tree fndecl = OVL_CURRENT (fn);
+                 if (TREE_CODE (fndecl) != FUNCTION_DECL
+                     || !TREE_THIS_VOLATILE (fndecl))
+                   break;
+                 fn = OVL_NEXT (fn);
+               }
+             while (fn);
+             if (!fn)
+               current_function_returns_abnormally = 1;
+           }
          return result;
        }
       if (!BASELINK_P (fn)
@@ -1778,26 +1878,8 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
       args = build_non_dependent_args (orig_args);
     }
 
-  /* A reference to a member function will appear as an overloaded
-     function (rather than a BASELINK) if an unqualified name was used
-     to refer to it.  */
-  if (!BASELINK_P (fn) && is_overloaded_fn (fn))
-    {
-      tree f = fn;
-
-      if (TREE_CODE (f) == TEMPLATE_ID_EXPR)
-       f = TREE_OPERAND (f, 0);
-      f = get_first_fn (f);
-      if (DECL_FUNCTION_MEMBER_P (f))
-       {
-         tree type = currently_open_derived_class (DECL_CONTEXT (f));
-         if (!type)
-           type = DECL_CONTEXT (f);
-         fn = build_baselink (TYPE_BINFO (type),
-                              TYPE_BINFO (type),
-                              fn, /*optype=*/NULL_TREE);
-       }
-    }
+  if (is_overloaded_fn (fn))
+    fn = baselink_for_fns (fn);
 
   result = NULL_TREE;
   if (BASELINK_P (fn))
@@ -1842,13 +1924,14 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
       if (processing_template_decl)
        {
          if (type_dependent_expression_p (object))
-           return build_nt (CALL_EXPR, orig_fn, orig_args, NULL_TREE);
+           return build_nt_call_list (orig_fn, orig_args);
          object = build_non_dependent_expr (object);
        }
 
       result = build_new_method_call (object, fn, args, NULL_TREE,
                                      (disallow_virtual
-                                      ? LOOKUP_NONVIRTUAL : 0));
+                                      ? LOOKUP_NONVIRTUAL : 0),
+                                     /*fn_p=*/NULL);
     }
   else if (is_overloaded_fn (fn))
     {
@@ -1885,8 +1968,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
 
   if (processing_template_decl)
     {
-      result = build3 (CALL_EXPR, TREE_TYPE (result), orig_fn,
-                      orig_args, NULL_TREE);
+      result = build_call_list (TREE_TYPE (result), orig_fn, orig_args);
       KOENIG_LOOKUP_P (result) = koenig_p;
     }
   return result;
@@ -1939,7 +2021,7 @@ finish_this_expr (void)
 tree
 finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
 {
-  if (destructor == error_mark_node)
+  if (object == error_mark_node || destructor == error_mark_node)
     return error_mark_node;
 
   gcc_assert (TYPE_P (destructor));
@@ -1951,6 +2033,13 @@ finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
          error ("invalid qualifying scope in pseudo-destructor name");
          return error_mark_node;
        }
+      if (scope && TYPE_P (scope) && !check_dtor_name (scope, destructor))
+       {
+         error ("qualified type %qT does not match destructor name ~%qT",
+                scope, destructor);
+         return error_mark_node;
+       }
+
 
       /* [expr.pseudo] says both:
 
@@ -1995,7 +2084,9 @@ finish_unary_op_expr (enum tree_code code, tree expr)
       result = copy_node (result);
       TREE_NEGATED_INT (result) = 1;
     }
-  overflow_warning (result);
+  if (TREE_OVERFLOW_P (result) && !TREE_OVERFLOW_P (expr))
+    overflow_warning (result);
+
   return result;
 }
 
@@ -2005,30 +2096,49 @@ finish_unary_op_expr (enum tree_code code, tree expr)
 tree
 finish_compound_literal (tree type, VEC(constructor_elt,gc) *initializer_list)
 {
+  tree var;
   tree compound_literal;
 
+  if (!TYPE_OBJ_P (type))
+    {
+      error ("compound literal of non-object type %qT", type);
+      return error_mark_node;
+    }
+
   /* Build a CONSTRUCTOR for the INITIALIZER_LIST.  */
   compound_literal = build_constructor (NULL_TREE, initializer_list);
-  /* Mark it as a compound-literal.  */
   if (processing_template_decl)
-    TREE_TYPE (compound_literal) = type;
-  else
     {
-      /* Check the initialization.  */
-      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:
-
-          `(int []) { 2, 3 }'
-
-        implies that the array has two elements.  */
-      if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
-       cp_complete_array_type (&TREE_TYPE (compound_literal),
-                               compound_literal, 1);
+      TREE_TYPE (compound_literal) = type;
+      /* Mark the expression as a compound literal.  */
+      TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
+      return compound_literal;
     }
 
-  TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
-  return compound_literal;
+  /* Create a temporary variable to represent the compound literal.  */
+  var = create_temporary_var (type);
+  if (!current_function_decl)
+    {
+      /* If this compound-literal appears outside of a function, then
+        the corresponding variable has static storage duration, just
+        like the variable in whose initializer it appears.  */
+      TREE_STATIC (var) = 1;
+      /* The variable has internal linkage, since there is no need to
+        reference it from another translation unit.  */
+      TREE_PUBLIC (var) = 0;
+      /* It must have a name, so that the name mangler can mangle it.  */
+      DECL_NAME (var) = make_anon_name ();
+    }
+  /* We must call pushdecl, since the gimplifier complains if the
+     variable has not been declared via a BIND_EXPR.  */
+  pushdecl (var);
+  /* Initialize the variable as we would any other variable with a
+     brace-enclosed initializer.  */
+  cp_finish_decl (var, compound_literal,
+                 /*init_const_expr_p=*/false,
+                 /*asmspec_tree=*/NULL_TREE,
+                 LOOKUP_ONLYCONVERTING);
+  return var;
 }
 
 /* Return the declaration for the function-name variable indicated by
@@ -2090,6 +2200,10 @@ finish_template_template_parm (tree aggr, tree identifier)
 
   gcc_assert (DECL_TEMPLATE_PARMS (tmpl));
 
+  check_default_tmpl_args (decl, DECL_TEMPLATE_PARMS (tmpl), 
+                          /*is_primary=*/true, /*is_partial=*/false,
+                          /*is_friend=*/0);
+
   return finish_template_type_parm (aggr, tmpl);
 }
 
@@ -2105,19 +2219,8 @@ check_template_template_default_arg (tree argument)
       && TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
     {
       if (TREE_CODE (argument) == TYPE_DECL)
-       {
-         tree t = TREE_TYPE (argument);
-
-         /* Try to emit a slightly smarter error message if we detect
-            that the user is using a template instantiation.  */
-         if (CLASSTYPE_TEMPLATE_INFO (t)
-             && CLASSTYPE_TEMPLATE_INSTANTIATION (t))
-           error ("invalid use of type %qT as a default value for a "
-                  "template template-parameter", t);
-         else
-           error ("invalid use of %qD as a default value for a template "
-                  "template-parameter", argument);
-       }
+       error ("invalid use of type %qT as a default value for a template "
+              "template-parameter", TREE_TYPE (argument));
       else
        error ("invalid default argument for a template template parameter");
       return error_mark_node;
@@ -2129,7 +2232,7 @@ check_template_template_default_arg (tree argument)
 /* Begin a class definition, as indicated by T.  */
 
 tree
-begin_class_definition (tree t)
+begin_class_definition (tree t, tree attributes)
 {
   if (t == error_mark_node)
     return error_mark_node;
@@ -2168,6 +2271,9 @@ begin_class_definition (tree t)
   maybe_process_partial_specialization (t);
   pushclass (t);
   TYPE_BEING_DEFINED (t) = 1;
+
+  cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
+
   if (flag_pack_struct)
     {
       tree v;
@@ -2183,7 +2289,7 @@ begin_class_definition (tree t)
      before.  */
   if (! TYPE_ANONYMOUS_P (t))
     {
-      struct c_fileinfo *finfo = get_fileinfo (lbasename (input_filename));
+      struct c_fileinfo *finfo = get_fileinfo (input_filename);
       CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only;
       SET_CLASSTYPE_INTERFACE_UNKNOWN_X
        (t, finfo->interface_unknown);
@@ -2226,6 +2332,15 @@ finish_member_declaration (tree decl)
   /* Mark the DECL as a member of the current class.  */
   DECL_CONTEXT (decl) = current_class_type;
 
+  /* Check for bare parameter packs in the member variable declaration.  */
+  if (TREE_CODE (decl) == FIELD_DECL)
+    {
+      if (check_for_bare_parameter_packs (TREE_TYPE (decl)))
+        TREE_TYPE (decl) = error_mark_node;
+      if (check_for_bare_parameter_packs (DECL_ATTRIBUTES (decl)))
+        DECL_ATTRIBUTES (decl) = NULL_TREE;
+    }
+
   /* [dcl.link]
 
      A C language linkage is ignored for the names of class members
@@ -2300,8 +2415,9 @@ note_decl_for_pch (tree 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
-      || TREE_CODE (decl) == FUNCTION_DECL)
+  if ((TREE_CODE (decl) == VAR_DECL
+       || TREE_CODE (decl) == FUNCTION_DECL)
+      && !processing_template_decl)
     mangle_decl (decl);
 }
 
@@ -2329,7 +2445,7 @@ finish_template_type (tree name, tree args, int entering_scope)
 
   decl = lookup_template_class (name, args,
                                NULL_TREE, NULL_TREE, entering_scope,
-                               tf_error | tf_warning | tf_user);
+                               tf_warning_or_error | tf_user);
   if (decl != error_mark_node)
     decl = TYPE_STUB_DECL (decl);
 
@@ -2396,6 +2512,35 @@ qualified_name_lookup_error (tree scope, tree name, tree decl)
     error ("%<::%D%> has not been declared", name);
 }
 
+/* If FNS is a member function, a set of member functions, or a
+   template-id referring to one or more member functions, return a
+   BASELINK for FNS, incorporating the current access context.
+   Otherwise, return FNS unchanged.  */
+
+tree
+baselink_for_fns (tree fns)
+{
+  tree fn;
+  tree cl;
+
+  if (BASELINK_P (fns) 
+      || error_operand_p (fns))
+    return fns;
+  
+  fn = fns;
+  if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
+    fn = TREE_OPERAND (fn, 0);
+  fn = get_first_fn (fn);
+  if (!DECL_FUNCTION_MEMBER_P (fn))
+    return fns;
+
+  cl = currently_open_derived_class (DECL_CONTEXT (fn));
+  if (!cl)
+    cl = DECL_CONTEXT (fn);
+  cl = TYPE_BINFO (cl);
+  return build_baselink (cl, cl, fns, /*optype=*/NULL_TREE);
+}
+
 /* 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
@@ -2558,7 +2703,10 @@ finish_id_expression (tree id_expression,
     {
       *idk = CP_ID_KIND_NONE;
       if (!processing_template_decl)
-       return DECL_INITIAL (decl);
+       {
+         used_types_insert (TREE_TYPE (decl));
+         return DECL_INITIAL (decl);
+       }
       return decl;
     }
   else
@@ -2781,8 +2929,12 @@ finish_id_expression (tree id_expression,
        }
       else if (is_overloaded_fn (decl))
        {
-         tree first_fn = OVL_CURRENT (decl);
+         tree first_fn;
 
+         first_fn = decl;
+         if (TREE_CODE (first_fn) == TEMPLATE_ID_EXPR)
+           first_fn = TREE_OPERAND (first_fn, 0);
+         first_fn = get_first_fn (first_fn);
          if (TREE_CODE (first_fn) == TEMPLATE_DECL)
            first_fn = DECL_TEMPLATE_RESULT (first_fn);
 
@@ -2799,17 +2951,21 @@ finish_id_expression (tree id_expression,
              return finish_class_member_access_expr (decl, id_expression,
                                                      /*template_p=*/false);
            }
+
+         decl = baselink_for_fns (decl);
        }
       else
        {
          if (DECL_P (decl) && DECL_NONLOCAL (decl)
-             && DECL_CLASS_SCOPE_P (decl)
-             && DECL_CONTEXT (decl) != current_class_type)
+             && DECL_CLASS_SCOPE_P (decl))
            {
-             tree path;
-
-             path = currently_open_derived_class (DECL_CONTEXT (decl));
-             perform_or_defer_access_check (TYPE_BINFO (path), decl);
+             tree context = context_for_name_lookup (decl); 
+             if (context != current_class_type)
+               {
+                 tree path = currently_open_derived_class (context);
+                 perform_or_defer_access_check (TYPE_BINFO (path),
+                                                decl, decl);
+               }
            }
 
          decl = convert_from_reference (decl);
@@ -2834,11 +2990,12 @@ finish_typeof (tree expr)
     {
       type = make_aggr_type (TYPEOF_TYPE);
       TYPEOF_TYPE_EXPR (type) = expr;
+      SET_TYPE_STRUCTURAL_EQUALITY (type);
 
       return type;
     }
 
-  type = TREE_TYPE (expr);
+  type = unlowered_expr_type (expr);
 
   if (!type || type == unknown_type_node)
     {
@@ -2849,6 +3006,31 @@ finish_typeof (tree expr)
   return type;
 }
 
+/* Perform C++-specific checks for __builtin_offsetof before calling
+   fold_offsetof.  */
+
+tree
+finish_offsetof (tree expr)
+{
+  if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR)
+    {
+      error ("cannot apply %<offsetof%> to destructor %<~%T%>",
+             TREE_OPERAND (expr, 2));
+      return error_mark_node;
+    }
+  if (TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE
+      || TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE
+      || TREE_CODE (TREE_TYPE (expr)) == UNKNOWN_TYPE)
+    {
+      if (TREE_CODE (expr) == COMPONENT_REF
+         || TREE_CODE (expr) == COMPOUND_EXPR)
+       expr = TREE_OPERAND (expr, 1);
+      error ("cannot apply %<offsetof%> to member function %qD", expr);
+      return error_mark_node;
+    }
+  return fold_offsetof (expr, NULL_TREE);
+}
+
 /* Called from expand_body via walk_tree.  Replace all AGGR_INIT_EXPRs
    with equivalent CALL_EXPRs.  */
 
@@ -2887,9 +3069,8 @@ simplify_aggr_init_expr (tree *tp)
   tree aggr_init_expr = *tp;
 
   /* Form an appropriate CALL_EXPR.  */
-  tree fn = TREE_OPERAND (aggr_init_expr, 0);
-  tree args = TREE_OPERAND (aggr_init_expr, 1);
-  tree slot = TREE_OPERAND (aggr_init_expr, 2);
+  tree fn = AGGR_INIT_EXPR_FN (aggr_init_expr);
+  tree slot = AGGR_INIT_EXPR_SLOT (aggr_init_expr);
   tree type = TREE_TYPE (slot);
 
   tree call_expr;
@@ -2907,23 +3088,20 @@ simplify_aggr_init_expr (tree *tp)
       style = arg;
     }
 
+  call_expr = build_call_array (TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
+                               fn,
+                               aggr_init_expr_nargs (aggr_init_expr),
+                               AGGR_INIT_EXPR_ARGP (aggr_init_expr));
+
   if (style == ctor)
     {
       /* Replace the first argument to the ctor with the address of the
         slot.  */
-      tree addr;
-
-      args = TREE_CHAIN (args);
       cxx_mark_addressable (slot);
-      addr = build1 (ADDR_EXPR, build_pointer_type (type), slot);
-      args = tree_cons (NULL_TREE, addr, args);
+      CALL_EXPR_ARG (call_expr, 0) =
+       build1 (ADDR_EXPR, build_pointer_type (type), slot);
     }
-
-  call_expr = build3 (CALL_EXPR,
-                     TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
-                     fn, args, NULL_TREE);
-
-  if (style == arg)
+  else if (style == arg)
     {
       /* Just mark it addressable here, and leave the rest to
         expand_call{,_inline}.  */
@@ -2948,7 +3126,7 @@ simplify_aggr_init_expr (tree *tp)
 
 /* Emit all thunks to FN that should be emitted when FN is emitted.  */
 
-static void
+void
 emit_associated_thunks (tree fn)
 {
   /* When we use vcall offsets, we emit thunks with the virtual
@@ -2983,62 +3161,6 @@ emit_associated_thunks (tree fn)
 /* Generate RTL for FN.  */
 
 void
-expand_body (tree fn)
-{
-  tree saved_function;
-
-  /* Compute the appropriate object-file linkage for inline
-     functions.  */
-  if (DECL_DECLARED_INLINE_P (fn))
-    import_export_decl (fn);
-
-  /* If FN is external, then there's no point in generating RTL for
-     it.  This situation can arise with an inline function under
-     `-fexternal-templates'; we instantiate the function, even though
-     we're not planning on emitting it, in case we get a chance to
-     inline it.  */
-  if (DECL_EXTERNAL (fn))
-    return;
-
-  /* ??? When is this needed?  */
-  saved_function = current_function_decl;
-
-  /* Emit any thunks that should be emitted at the same time as FN.  */
-  emit_associated_thunks (fn);
-
-  /* This function is only called from cgraph, or recursively from
-     emit_associated_thunks.  In neither case should we be currently
-     generating trees for a function.  */
-  gcc_assert (function_depth == 0);
-
-  tree_rest_of_compilation (fn);
-
-  current_function_decl = saved_function;
-
-  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.  */
-      tree probe;
-
-      for (probe = TREE_CHAIN (DECL_CLONED_FUNCTION (fn));
-          probe && DECL_CLONED_FUNCTION_P (probe);
-          probe = TREE_CHAIN (probe))
-       {
-         tree parms;
-
-         for (parms = DECL_ARGUMENTS (probe);
-              parms; parms = TREE_CHAIN (parms))
-           TREE_USED (parms) = 1;
-       }
-    }
-}
-
-/* Generate RTL for FN.  */
-
-void
 expand_or_defer_fn (tree fn)
 {
   /* When the parser calls us after finishing the body of a template
@@ -3057,9 +3179,9 @@ expand_or_defer_fn (tree fn)
     }
 
   /* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs.  */
-  walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
-                               simplify_aggr_init_exprs_r,
-                               NULL);
+  cp_walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
+                                  simplify_aggr_init_exprs_r,
+                                  NULL);
 
   /* If this is a constructor or destructor body, we have to clone
      it.  */
@@ -3071,18 +3193,6 @@ expand_or_defer_fn (tree fn)
       return;
     }
 
-  /* If this function is marked with the constructor attribute, add it
-     to the list of functions to be called along with constructors
-     from static duration objects.  */
-  if (DECL_STATIC_CONSTRUCTOR (fn))
-    static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
-
-  /* If this function is marked with the destructor attribute, add it
-     to the list of functions to be called along with destructors from
-     static duration objects.  */
-  if (DECL_STATIC_DESTRUCTOR (fn))
-    static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
-
   /* We make a decision about linkage for these functions at the end
      of the compilation.  Until that point, we do not want the back
      end to output them -- but we do want it to see the bodies of
@@ -3221,15 +3331,1122 @@ finalize_nrv (tree *tp, tree var, tree result)
   data.var = var;
   data.result = result;
   data.visited = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
-  walk_tree (tp, finalize_nrv_r, &data, 0);
+  cp_walk_tree (tp, finalize_nrv_r, &data, 0);
   htab_delete (data.visited);
 }
+\f
+/* For all elements of CLAUSES, validate them vs OpenMP constraints.
+   Remove any elements from the list that are invalid.  */
+
+tree
+finish_omp_clauses (tree clauses)
+{
+  bitmap_head generic_head, firstprivate_head, lastprivate_head;
+  tree c, t, *pc = &clauses;
+  const char *name;
+
+  bitmap_obstack_initialize (NULL);
+  bitmap_initialize (&generic_head, &bitmap_default_obstack);
+  bitmap_initialize (&firstprivate_head, &bitmap_default_obstack);
+  bitmap_initialize (&lastprivate_head, &bitmap_default_obstack);
+
+  for (pc = &clauses, c = clauses; c ; c = *pc)
+    {
+      bool remove = false;
+
+      switch (OMP_CLAUSE_CODE (c))
+       {
+       case OMP_CLAUSE_SHARED:
+         name = "shared";
+         goto check_dup_generic;
+       case OMP_CLAUSE_PRIVATE:
+         name = "private";
+         goto check_dup_generic;
+       case OMP_CLAUSE_REDUCTION:
+         name = "reduction";
+         goto check_dup_generic;
+       case OMP_CLAUSE_COPYPRIVATE:
+         name = "copyprivate";
+         goto check_dup_generic;
+       case OMP_CLAUSE_COPYIN:
+         name = "copyin";
+         goto check_dup_generic;
+       check_dup_generic:
+         t = OMP_CLAUSE_DECL (c);
+         if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+           {
+             if (processing_template_decl)
+               break;
+             if (DECL_P (t))
+               error ("%qD is not a variable in clause %qs", t, name);
+             else
+               error ("%qE is not a variable in clause %qs", t, name);
+             remove = true;
+           }
+         else if (bitmap_bit_p (&generic_head, DECL_UID (t))
+                  || bitmap_bit_p (&firstprivate_head, DECL_UID (t))
+                  || bitmap_bit_p (&lastprivate_head, DECL_UID (t)))
+           {
+             error ("%qD appears more than once in data clauses", t);
+             remove = true;
+           }
+         else
+           bitmap_set_bit (&generic_head, DECL_UID (t));
+         break;
+
+       case OMP_CLAUSE_FIRSTPRIVATE:
+         t = OMP_CLAUSE_DECL (c);
+         if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+           {
+             if (processing_template_decl)
+               break;
+             error ("%qE is not a variable in clause %<firstprivate%>", t);
+             remove = true;
+           }
+         else if (bitmap_bit_p (&generic_head, DECL_UID (t))
+                  || bitmap_bit_p (&firstprivate_head, DECL_UID (t)))
+           {
+             error ("%qE appears more than once in data clauses", t);
+             remove = true;
+           }
+         else
+           bitmap_set_bit (&firstprivate_head, DECL_UID (t));
+         break;
+
+       case OMP_CLAUSE_LASTPRIVATE:
+         t = OMP_CLAUSE_DECL (c);
+         if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+           {
+             if (processing_template_decl)
+               break;
+             error ("%qE is not a variable in clause %<lastprivate%>", t);
+             remove = true;
+           }
+         else if (bitmap_bit_p (&generic_head, DECL_UID (t))
+                  || bitmap_bit_p (&lastprivate_head, DECL_UID (t)))
+           {
+             error ("%qE appears more than once in data clauses", t);
+             remove = true;
+           }
+         else
+           bitmap_set_bit (&lastprivate_head, DECL_UID (t));
+         break;
+
+       case OMP_CLAUSE_IF:
+         t = OMP_CLAUSE_IF_EXPR (c);
+         t = maybe_convert_cond (t);
+         if (t == error_mark_node)
+           remove = true;
+         OMP_CLAUSE_IF_EXPR (c) = t;
+         break;
+
+       case OMP_CLAUSE_NUM_THREADS:
+         t = OMP_CLAUSE_NUM_THREADS_EXPR (c);
+         if (t == error_mark_node)
+           remove = true;
+         else if (!type_dependent_expression_p (t)
+                  && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+           {
+             error ("num_threads expression must be integral");
+             remove = true;
+           }
+         break;
+
+       case OMP_CLAUSE_SCHEDULE:
+         t = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c);
+         if (t == NULL)
+           ;
+         else if (t == error_mark_node)
+           remove = true;
+         else if (!type_dependent_expression_p (t)
+                  && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+           {
+             error ("schedule chunk size expression must be integral");
+             remove = true;
+           }
+         break;
+
+       case OMP_CLAUSE_NOWAIT:
+       case OMP_CLAUSE_ORDERED:
+       case OMP_CLAUSE_DEFAULT:
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+
+      if (remove)
+       *pc = OMP_CLAUSE_CHAIN (c);
+      else
+       pc = &OMP_CLAUSE_CHAIN (c);
+    }
+
+  for (pc = &clauses, c = clauses; c ; c = *pc)
+    {
+      enum tree_code c_kind = OMP_CLAUSE_CODE (c);
+      bool remove = false;
+      bool need_complete_non_reference = false;
+      bool need_default_ctor = false;
+      bool need_copy_ctor = false;
+      bool need_copy_assignment = false;
+      bool need_implicitly_determined = false;
+      tree type, inner_type;
+
+      switch (c_kind)
+       {
+       case OMP_CLAUSE_SHARED:
+         name = "shared";
+         need_implicitly_determined = true;
+         break;
+       case OMP_CLAUSE_PRIVATE:
+         name = "private";
+         need_complete_non_reference = true;
+         need_default_ctor = true;
+         need_implicitly_determined = true;
+         break;
+       case OMP_CLAUSE_FIRSTPRIVATE:
+         name = "firstprivate";
+         need_complete_non_reference = true;
+         need_copy_ctor = true;
+         need_implicitly_determined = true;
+         break;
+       case OMP_CLAUSE_LASTPRIVATE:
+         name = "lastprivate";
+         need_complete_non_reference = true;
+         need_copy_assignment = true;
+         need_implicitly_determined = true;
+         break;
+       case OMP_CLAUSE_REDUCTION:
+         name = "reduction";
+         need_implicitly_determined = true;
+         break;
+       case OMP_CLAUSE_COPYPRIVATE:
+         name = "copyprivate";
+         need_copy_assignment = true;
+         break;
+       case OMP_CLAUSE_COPYIN:
+         name = "copyin";
+         need_copy_assignment = true;
+         break;
+       default:
+         pc = &OMP_CLAUSE_CHAIN (c);
+         continue;
+       }
+
+      t = OMP_CLAUSE_DECL (c);
+      if (processing_template_decl
+         && TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+       {
+         pc = &OMP_CLAUSE_CHAIN (c);
+         continue;
+       }
+
+      switch (c_kind)
+       {
+       case OMP_CLAUSE_LASTPRIVATE:
+         if (!bitmap_bit_p (&firstprivate_head, DECL_UID (t)))
+           need_default_ctor = true;
+         break;
+
+       case OMP_CLAUSE_REDUCTION:
+         if (AGGREGATE_TYPE_P (TREE_TYPE (t))
+             || POINTER_TYPE_P (TREE_TYPE (t)))
+           {
+             error ("%qE has invalid type for %<reduction%>", t);
+             remove = true;
+           }
+         else if (FLOAT_TYPE_P (TREE_TYPE (t)))
+           {
+             enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c);
+             switch (r_code)
+               {
+               case PLUS_EXPR:
+               case MULT_EXPR:
+               case MINUS_EXPR:
+                 break;
+               default:
+                 error ("%qE has invalid type for %<reduction(%s)%>",
+                        t, operator_name_info[r_code].name);
+                 remove = true;
+               }
+           }
+         break;
+
+       case OMP_CLAUSE_COPYIN:
+         if (TREE_CODE (t) != VAR_DECL || !DECL_THREAD_LOCAL_P (t))
+           {
+             error ("%qE must be %<threadprivate%> for %<copyin%>", t);
+             remove = true;
+           }
+         break;
+
+       default:
+         break;
+       }
+
+      if (need_complete_non_reference)
+       {
+         t = require_complete_type (t);
+         if (t == error_mark_node)
+           remove = true;
+         else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+           {
+             error ("%qE has reference type for %qs", t, name);
+             remove = true;
+           }
+       }
+      if (need_implicitly_determined)
+       {
+         const char *share_name = NULL;
+
+         if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t))
+           share_name = "threadprivate";
+         else switch (cxx_omp_predetermined_sharing (t))
+           {
+           case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
+             break;
+           case OMP_CLAUSE_DEFAULT_SHARED:
+             share_name = "shared";
+             break;
+           case OMP_CLAUSE_DEFAULT_PRIVATE:
+             share_name = "private";
+             break;
+           default:
+             gcc_unreachable ();
+           }
+         if (share_name)
+           {
+             error ("%qE is predetermined %qs for %qs",
+                    t, share_name, name);
+             remove = true;
+           }
+       }
+
+      /* We're interested in the base element, not arrays.  */
+      inner_type = type = TREE_TYPE (t);
+      while (TREE_CODE (inner_type) == ARRAY_TYPE)
+       inner_type = TREE_TYPE (inner_type);
+
+      /* Check for special function availability by building a call to one.
+        Save the results, because later we won't be in the right context
+        for making these queries.  */
+      if (CLASS_TYPE_P (inner_type)
+         && (need_default_ctor || need_copy_ctor || need_copy_assignment)
+         && !type_dependent_expression_p (t))
+       {
+         int save_errorcount = errorcount;
+         tree info;
+
+         /* Always allocate 3 elements for simplicity.  These are the
+            function decls for the ctor, dtor, and assignment op.
+            This layout is known to the three lang hooks,
+            cxx_omp_clause_default_init, cxx_omp_clause_copy_init,
+            and cxx_omp_clause_assign_op.  */
+         info = make_tree_vec (3);
+         CP_OMP_CLAUSE_INFO (c) = info;
+
+         if (need_default_ctor
+             || (need_copy_ctor
+                 && !TYPE_HAS_TRIVIAL_INIT_REF (inner_type)))
+           {
+             if (need_default_ctor)
+               t = NULL;
+             else
+               {
+                 t = build_int_cst (build_pointer_type (inner_type), 0);
+                 t = build1 (INDIRECT_REF, inner_type, t);
+                 t = build_tree_list (NULL, t);
+               }
+             t = build_special_member_call (NULL_TREE,
+                                            complete_ctor_identifier,
+                                            t, inner_type, LOOKUP_NORMAL);
+
+             if (targetm.cxx.cdtor_returns_this ())
+               /* Because constructors and destructors return this,
+                  the call will have been cast to "void".  Remove the
+                  cast here.  We would like to use STRIP_NOPS, but it
+                  wouldn't work here because TYPE_MODE (t) and
+                  TYPE_MODE (TREE_OPERAND (t, 0)) are different.
+                  They are VOIDmode and Pmode, respectively.  */
+               if (TREE_CODE (t) == NOP_EXPR)
+                 t = TREE_OPERAND (t, 0);
+
+             t = get_callee_fndecl (t);
+             TREE_VEC_ELT (info, 0) = t;
+           }
+
+         if ((need_default_ctor || need_copy_ctor)
+             && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (inner_type))
+           {
+             t = build_int_cst (build_pointer_type (inner_type), 0);
+             t = build1 (INDIRECT_REF, inner_type, t);
+             t = build_special_member_call (t, complete_dtor_identifier,
+                                            NULL, inner_type, LOOKUP_NORMAL);
+
+             if (targetm.cxx.cdtor_returns_this ())
+               /* Because constructors and destructors return this,
+                  the call will have been cast to "void".  Remove the
+                  cast here.  We would like to use STRIP_NOPS, but it
+                  wouldn't work here because TYPE_MODE (t) and
+                  TYPE_MODE (TREE_OPERAND (t, 0)) are different.
+                  They are VOIDmode and Pmode, respectively.  */
+               if (TREE_CODE (t) == NOP_EXPR)
+                 t = TREE_OPERAND (t, 0);
+
+             t = get_callee_fndecl (t);
+             TREE_VEC_ELT (info, 1) = t;
+           }
+
+         if (need_copy_assignment
+             && !TYPE_HAS_TRIVIAL_ASSIGN_REF (inner_type))
+           {
+             t = build_int_cst (build_pointer_type (inner_type), 0);
+             t = build1 (INDIRECT_REF, inner_type, t);
+             t = build_special_member_call (t, ansi_assopname (NOP_EXPR),
+                                            build_tree_list (NULL, t),
+                                            inner_type, LOOKUP_NORMAL);
+
+             /* We'll have called convert_from_reference on the call, which
+                may well have added an indirect_ref.  It's unneeded here,
+                and in the way, so kill it.  */
+             if (TREE_CODE (t) == INDIRECT_REF)
+               t = TREE_OPERAND (t, 0);
+
+             t = get_callee_fndecl (t);
+             TREE_VEC_ELT (info, 2) = t;
+           }
+
+         if (errorcount != save_errorcount)
+           remove = true;
+       }
+
+      if (remove)
+       *pc = OMP_CLAUSE_CHAIN (c);
+      else
+       pc = &OMP_CLAUSE_CHAIN (c);
+    }
+
+  bitmap_obstack_release (NULL);
+  return clauses;
+}
+
+/* For all variables in the tree_list VARS, mark them as thread local.  */
+
+void
+finish_omp_threadprivate (tree vars)
+{
+  tree t;
+
+  /* Mark every variable in VARS to be assigned thread local storage.  */
+  for (t = vars; t; t = TREE_CHAIN (t))
+    {
+      tree v = TREE_PURPOSE (t);
+
+      /* If V had already been marked threadprivate, it doesn't matter
+        whether it had been used prior to this point.  */
+      if (TREE_USED (v)
+         && (DECL_LANG_SPECIFIC (v) == NULL
+             || !CP_DECL_THREADPRIVATE_P (v)))
+       error ("%qE declared %<threadprivate%> after first use", v);
+      else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v))
+       error ("automatic variable %qE cannot be %<threadprivate%>", v);
+      else if (! COMPLETE_TYPE_P (TREE_TYPE (v)))
+       error ("%<threadprivate%> %qE has incomplete type", v);
+      else if (TREE_STATIC (v) && TYPE_P (CP_DECL_CONTEXT (v)))
+       error ("%<threadprivate%> %qE is not file, namespace "
+              "or block scope variable", v);
+      else
+       {
+         /* Allocate a LANG_SPECIFIC structure for V, if needed.  */
+         if (DECL_LANG_SPECIFIC (v) == NULL)
+           {
+             retrofit_lang_decl (v);
+
+             /* Make sure that DECL_DISCRIMINATOR_P continues to be true
+                after the allocation of the lang_decl structure.  */
+             if (DECL_DISCRIMINATOR_P (v))
+               DECL_LANG_SPECIFIC (v)->decl_flags.u2sel = 1;
+           }
+
+         if (! DECL_THREAD_LOCAL_P (v))
+           {
+             DECL_TLS_MODEL (v) = decl_default_tls_model (v);
+             /* If rtl has been already set for this var, call
+                make_decl_rtl once again, so that encode_section_info
+                has a chance to look at the new decl flags.  */
+             if (DECL_RTL_SET_P (v))
+               make_decl_rtl (v);
+           }
+         CP_DECL_THREADPRIVATE_P (v) = 1;
+       }
+    }
+}
+
+/* Build an OpenMP structured block.  */
+
+tree
+begin_omp_structured_block (void)
+{
+  return do_pushlevel (sk_omp);
+}
+
+tree
+finish_omp_structured_block (tree block)
+{
+  return do_poplevel (block);
+}
+
+/* Similarly, except force the retention of the BLOCK.  */
+
+tree
+begin_omp_parallel (void)
+{
+  keep_next_level (true);
+  return begin_omp_structured_block ();
+}
+
+tree
+finish_omp_parallel (tree clauses, tree body)
+{
+  tree stmt;
+
+  body = finish_omp_structured_block (body);
+
+  stmt = make_node (OMP_PARALLEL);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_PARALLEL_CLAUSES (stmt) = clauses;
+  OMP_PARALLEL_BODY (stmt) = body;
+
+  return add_stmt (stmt);
+}
+
+/* Build and validate an OMP_FOR statement.  CLAUSES, BODY, COND, INCR
+   are directly for their associated operands in the statement.  DECL
+   and INIT are a combo; if DECL is NULL then INIT ought to be a
+   MODIFY_EXPR, and the DECL should be extracted.  PRE_BODY are
+   optional statements that need to go before the loop into its
+   sk_omp scope.  */
+
+tree
+finish_omp_for (location_t locus, tree decl, tree init, tree cond,
+               tree incr, tree body, tree pre_body)
+{
+  tree omp_for = NULL;
+
+  if (decl == NULL)
+    {
+      if (init != NULL)
+       switch (TREE_CODE (init))
+         {
+         case MODIFY_EXPR:
+           decl = TREE_OPERAND (init, 0);
+           init = TREE_OPERAND (init, 1);
+           break;
+         case MODOP_EXPR:
+           if (TREE_CODE (TREE_OPERAND (init, 1)) == NOP_EXPR)
+             {
+               decl = TREE_OPERAND (init, 0);
+               init = TREE_OPERAND (init, 2);
+             }
+           break;
+         default:
+           break;
+         }
+
+      if (decl == NULL)
+       {
+         error ("expected iteration declaration or initialization");
+         return NULL;
+       }
+    }
+
+  if (type_dependent_expression_p (decl)
+      || type_dependent_expression_p (init)
+      || (cond && type_dependent_expression_p (cond))
+      || (incr && type_dependent_expression_p (incr)))
+    {
+      tree stmt;
+
+      if (cond == NULL)
+       {
+         error ("%Hmissing controlling predicate", &locus);
+         return NULL;
+       }
+
+      if (incr == NULL)
+       {
+         error ("%Hmissing increment expression", &locus);
+         return NULL;
+       }
+
+      stmt = make_node (OMP_FOR);
+
+      /* This is really just a place-holder.  We'll be decomposing this
+        again and going through the build_modify_expr path below when
+        we instantiate the thing.  */
+      init = build2 (MODIFY_EXPR, void_type_node, decl, init);
+
+      TREE_TYPE (stmt) = void_type_node;
+      OMP_FOR_INIT (stmt) = init;
+      OMP_FOR_COND (stmt) = cond;
+      OMP_FOR_INCR (stmt) = incr;
+      OMP_FOR_BODY (stmt) = body;
+      OMP_FOR_PRE_BODY (stmt) = pre_body;
+
+      SET_EXPR_LOCATION (stmt, locus);
+      return add_stmt (stmt);
+    }
+
+  if (!DECL_P (decl))
+    {
+      error ("expected iteration declaration or initialization");
+      return NULL;
+    }
+
+  if (pre_body == NULL || IS_EMPTY_STMT (pre_body))
+    pre_body = NULL;
+  else if (! processing_template_decl)
+    {
+      add_stmt (pre_body);
+      pre_body = NULL;
+    }
+
+  if (!processing_template_decl)
+    init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
+  init = build_modify_expr (decl, NOP_EXPR, init);
+  if (cond && TREE_SIDE_EFFECTS (cond) && COMPARISON_CLASS_P (cond))
+    {
+      int n = TREE_SIDE_EFFECTS (TREE_OPERAND (cond, 1)) != 0;
+      tree t = TREE_OPERAND (cond, n);
+
+      if (!processing_template_decl)
+       TREE_OPERAND (cond, n)
+         = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+    }
+  if (decl != error_mark_node && init != error_mark_node)
+    omp_for = c_finish_omp_for (locus, decl, init, cond, incr, body, pre_body);
+  if (omp_for != NULL
+      && TREE_CODE (OMP_FOR_INCR (omp_for)) == MODIFY_EXPR
+      && TREE_SIDE_EFFECTS (TREE_OPERAND (OMP_FOR_INCR (omp_for), 1))
+      && BINARY_CLASS_P (TREE_OPERAND (OMP_FOR_INCR (omp_for), 1)))
+    {
+      tree t = TREE_OPERAND (OMP_FOR_INCR (omp_for), 1);
+      int n = TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)) != 0;
 
-/* Perform initialization related to this module.  */
+      if (!processing_template_decl)
+       TREE_OPERAND (t, n)
+         = fold_build_cleanup_point_expr (TREE_TYPE (TREE_OPERAND (t, n)),
+                                          TREE_OPERAND (t, n));
+    }
+  return omp_for;
+}
 
 void
+finish_omp_atomic (enum tree_code code, tree lhs, tree rhs)
+{
+  tree orig_lhs;
+  tree orig_rhs;
+  bool dependent_p;
+  tree stmt;
+
+  orig_lhs = lhs;
+  orig_rhs = rhs;
+  dependent_p = false;
+  stmt = NULL_TREE;
+
+  /* Even in a template, we can detect invalid uses of the atomic
+     pragma if neither LHS nor RHS is type-dependent.  */
+  if (processing_template_decl)
+    {
+      dependent_p = (type_dependent_expression_p (lhs)
+                    || type_dependent_expression_p (rhs));
+      if (!dependent_p)
+       {
+         lhs = build_non_dependent_expr (lhs);
+         rhs = build_non_dependent_expr (rhs);
+       }
+    }
+  if (!dependent_p)
+    {
+      stmt = c_finish_omp_atomic (code, lhs, rhs);
+      if (stmt == error_mark_node)
+       return;
+    }
+  if (processing_template_decl)
+    stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node,
+                  build2 (code, void_type_node, orig_lhs, orig_rhs));
+  add_stmt (stmt);
+}
+
+void
+finish_omp_barrier (void)
+{
+  tree fn = built_in_decls[BUILT_IN_GOMP_BARRIER];
+  tree stmt = finish_call_expr (fn, NULL, false, false);
+  finish_expr_stmt (stmt);
+}
+
+void
+finish_omp_flush (void)
+{
+  tree fn = built_in_decls[BUILT_IN_SYNCHRONIZE];
+  tree stmt = finish_call_expr (fn, NULL, false, false);
+  finish_expr_stmt (stmt);
+}
+
+/* True if OpenMP sharing attribute of DECL is predetermined.  */
+
+enum omp_clause_default_kind
+cxx_omp_predetermined_sharing (tree decl)
+{
+  enum omp_clause_default_kind kind;
+
+  kind = c_omp_predetermined_sharing (decl);
+  if (kind != OMP_CLAUSE_DEFAULT_UNSPECIFIED)
+    return kind;
+
+  /* Static data members are predetermined as shared.  */
+  if (TREE_STATIC (decl))
+    {
+      tree ctx = CP_DECL_CONTEXT (decl);
+      if (TYPE_P (ctx) && IS_AGGR_TYPE (ctx))
+       return OMP_CLAUSE_DEFAULT_SHARED;
+    }
+
+  return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
+}
+\f
+void
 init_cp_semantics (void)
 {
 }
+\f
+/* Build a STATIC_ASSERT for a static assertion with the condition
+   CONDITION and the message text MESSAGE.  LOCATION is the location
+   of the static assertion in the source code.  When MEMBER_P, this
+   static assertion is a member of a class.  */
+void 
+finish_static_assert (tree condition, tree message, location_t location, 
+                      bool member_p)
+{
+  if (check_for_bare_parameter_packs (condition))
+    condition = error_mark_node;
+
+  if (type_dependent_expression_p (condition) 
+      || value_dependent_expression_p (condition))
+    {
+      /* We're in a template; build a STATIC_ASSERT and put it in
+         the right place. */
+      tree assertion;
+
+      assertion = make_node (STATIC_ASSERT);
+      STATIC_ASSERT_CONDITION (assertion) = condition;
+      STATIC_ASSERT_MESSAGE (assertion) = message;
+      STATIC_ASSERT_SOURCE_LOCATION (assertion) = location;
+
+      if (member_p)
+        maybe_add_class_template_decl_list (current_class_type, 
+                                            assertion,
+                                            /*friend_p=*/0);
+      else
+        add_stmt (assertion);
+
+      return;
+    }
+
+  /* Fold the expression and convert it to a boolean value. */
+  condition = fold_non_dependent_expr (condition);
+  condition = cp_convert (boolean_type_node, condition);
+
+  if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
+    /* Do nothing; the condition is satisfied. */
+    ;
+  else 
+    {
+      location_t saved_loc = input_location;
+
+      input_location = location;
+      if (TREE_CODE (condition) == INTEGER_CST 
+          && integer_zerop (condition))
+        /* Report the error. */
+        error ("static assertion failed: %E", message);
+      else if (condition && condition != error_mark_node)
+        error ("non-constant condition for static assertion");
+      input_location = saved_loc;
+    }
+}
+\f
+/* Implements the C++0x decltype keyword. Returns the type of EXPR,
+   suitable for use as a type-specifier.
+
+   ID_EXPRESSION_OR_MEMBER_ACCESS_P is true when EXPR was parsed as an
+   id-expression or a class member access, FALSE when it was parsed as
+   a full expression.  */
+tree
+finish_decltype_type (tree expr, bool id_expression_or_member_access_p)
+{
+  tree orig_expr = expr;
+  tree type;
+
+  if (!expr || error_operand_p (expr))
+    return error_mark_node;
+
+  if (TYPE_P (expr)
+      || TREE_CODE (expr) == TYPE_DECL
+      || (TREE_CODE (expr) == BIT_NOT_EXPR
+         && TYPE_P (TREE_OPERAND (expr, 0))))
+    {
+      error ("argument to decltype must be an expression");
+      return error_mark_node;
+    }
+
+  if (type_dependent_expression_p (expr))
+    {
+      type = make_aggr_type (DECLTYPE_TYPE);
+      DECLTYPE_TYPE_EXPR (type) = expr;
+      DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type)
+        = id_expression_or_member_access_p;
+      SET_TYPE_STRUCTURAL_EQUALITY (type);
+
+      return type;
+    }
+
+  /* The type denoted by decltype(e) is defined as follows:  */
+
+  if (id_expression_or_member_access_p)
+    {
+      /* If e is an id-expression or a class member access (5.2.5
+         [expr.ref]), decltype(e) is defined as the type of the entity
+         named by e. If there is no such entity, or e names a set of
+         overloaded functions, the program is ill-formed.  */
+      if (TREE_CODE (expr) == IDENTIFIER_NODE)
+        expr = lookup_name (expr);
+
+      if (TREE_CODE (expr) == INDIRECT_REF)
+        /* This can happen when the expression is, e.g., "a.b". Just
+           look at the underlying operand.  */
+        expr = TREE_OPERAND (expr, 0);
+
+      if (TREE_CODE (expr) == OFFSET_REF
+          || TREE_CODE (expr) == MEMBER_REF)
+        /* We're only interested in the field itself. If it is a
+           BASELINK, we will need to see through it in the next
+           step.  */
+        expr = TREE_OPERAND (expr, 1);
+
+      if (TREE_CODE (expr) == BASELINK)
+        /* See through BASELINK nodes to the underlying functions.  */
+        expr = BASELINK_FUNCTIONS (expr);
+
+      if (TREE_CODE (expr) == OVERLOAD)
+        {
+          if (OVL_CHAIN (expr))
+            {
+              error ("%qE refers to a set of overloaded functions", orig_expr);
+              return error_mark_node;
+            }
+          else
+            /* An overload set containing only one function: just look
+               at that function.  */
+            expr = OVL_FUNCTION (expr);
+        }
+
+      switch (TREE_CODE (expr))
+        {
+        case FIELD_DECL:
+          if (DECL_C_BIT_FIELD (expr))
+            {
+              type = DECL_BIT_FIELD_TYPE (expr);
+              break;
+            }
+          /* Fall through for fields that aren't bitfields.  */
+
+        case FUNCTION_DECL:
+        case VAR_DECL:
+        case CONST_DECL:
+        case PARM_DECL:
+        case RESULT_DECL:
+          type = TREE_TYPE (expr);
+          break;
+
+        case ERROR_MARK:
+          type = error_mark_node;
+          break;
+
+        case COMPONENT_REF:
+          type = is_bitfield_expr_with_lowered_type (expr);
+          if (!type)
+            type = TREE_TYPE (TREE_OPERAND (expr, 1));
+          break;
+
+        case BIT_FIELD_REF:
+          gcc_unreachable ();
+
+        case INTEGER_CST:
+          /* We can get here when the id-expression refers to an
+             enumerator.  */
+          type = TREE_TYPE (expr);
+          break;
+
+        default:
+         gcc_assert (TYPE_P (expr) || DECL_P (expr)
+                     || TREE_CODE (expr) == SCOPE_REF);
+          error ("argument to decltype must be an expression");
+          return error_mark_node;
+        }
+    }
+  else
+    {
+      tree fndecl;
+
+      /* Expressions of reference type are sometimes wrapped in
+         INDIRECT_REFs.  INDIRECT_REFs are just internal compiler
+         representation, not part of the language, so we have to look
+         through them.  */
+      if (TREE_CODE (expr) == INDIRECT_REF
+          && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0)))
+         == REFERENCE_TYPE)
+        expr = TREE_OPERAND (expr, 0);
+
+      if (TREE_CODE (expr) == CALL_EXPR
+          && (fndecl = get_callee_fndecl (expr))
+          && (fndecl != error_mark_node))
+        /* If e is a function call (5.2.2 [expr.call]) or an
+           invocation of an overloaded operator (parentheses around e
+           are ignored), decltype(e) is defined as the return type of
+           that function.  */
+        type = TREE_TYPE (TREE_TYPE (fndecl));
+      else 
+        {
+          type = is_bitfield_expr_with_lowered_type (expr);
+          if (type)
+            {
+              /* Bitfields are special, because their type encodes the
+                 number of bits they store.  If the expression referenced a
+                 bitfield, TYPE now has the declared type of that
+                 bitfield.  */
+              type = cp_build_qualified_type (type, 
+                                              cp_type_quals (TREE_TYPE (expr)));
+              
+              if (real_lvalue_p (expr))
+                type = build_reference_type (type);
+            }
+          else
+            {
+              /* Otherwise, where T is the type of e, if e is an lvalue,
+                 decltype(e) is defined as T&, otherwise decltype(e) is
+                 defined as T.  */
+              type = TREE_TYPE (expr);
+              if (type == error_mark_node)
+                return error_mark_node;
+              else if (expr == current_class_ptr)
+                /* If the expression is just "this", we want the
+                   cv-unqualified pointer for the "this" type.  */
+                type = TYPE_MAIN_VARIANT (type);
+              else if (real_lvalue_p (expr))
+                {
+                  if (TREE_CODE (type) != REFERENCE_TYPE)
+                    type = build_reference_type (type);
+                }
+              else
+                type = non_reference (type);
+            }
+        }
+    }
+
+  if (!type || type == unknown_type_node)
+    {
+      error ("type of %qE is unknown", expr);
+      return error_mark_node;
+    }
+
+  return type;
+}
+
+/* Called from trait_expr_value to evaluate either __has_nothrow_assign or 
+   __has_nothrow_copy, depending on assign_p.  */
+
+static bool
+classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
+{
+  tree fns;
+
+  if (assign_p)
+    {
+      int ix;
+      ix = lookup_fnfields_1 (type, ansi_assopname (NOP_EXPR));
+      if (ix < 0)
+       return false;
+      fns = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), ix);
+    } 
+  else if (TYPE_HAS_INIT_REF (type))
+    {
+      /* If construction of the copy constructor was postponed, create
+        it now.  */
+      if (CLASSTYPE_LAZY_COPY_CTOR (type))
+       lazily_declare_fn (sfk_copy_constructor, type);
+      fns = CLASSTYPE_CONSTRUCTORS (type);
+    }
+  else
+    return false;
+
+  for (; fns; fns = OVL_NEXT (fns))
+    if (!TREE_NOTHROW (OVL_CURRENT (fns)))
+      return false;
+
+  return true;
+}
+
+/* Actually evaluates the trait.  */
+
+static bool
+trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
+{
+  enum tree_code type_code1;
+  tree t;
+
+  type_code1 = TREE_CODE (type1);
+
+  switch (kind)
+    {
+    case CPTK_HAS_NOTHROW_ASSIGN:
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+             && (trait_expr_value (CPTK_HAS_TRIVIAL_ASSIGN, type1, type2)
+                 || (CLASS_TYPE_P (type1)
+                     && classtype_has_nothrow_assign_or_copy_p (type1,
+                                                                true))));
+
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+             && (pod_type_p (type1)
+                   || (CLASS_TYPE_P (type1)
+                       && TYPE_HAS_TRIVIAL_ASSIGN_REF (type1))));
+
+    case CPTK_HAS_NOTHROW_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2) 
+             || (CLASS_TYPE_P (type1)
+                 && (t = locate_ctor (type1, NULL)) && TREE_NOTHROW (t)));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (pod_type_p (type1)
+             || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
+    case CPTK_HAS_NOTHROW_COPY:
+      return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
+             || (CLASS_TYPE_P (type1)
+                 && classtype_has_nothrow_assign_or_copy_p (type1, false)));
+
+    case CPTK_HAS_TRIVIAL_COPY:
+      return (pod_type_p (type1) || type_code1 == REFERENCE_TYPE
+             || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_INIT_REF (type1)));
+
+    case CPTK_HAS_TRIVIAL_DESTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (pod_type_p (type1)
+             || (CLASS_TYPE_P (type1)
+                 && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
+
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return (CLASS_TYPE_P (type1)
+             && (t = locate_dtor (type1, NULL)) && DECL_VIRTUAL_P (t));
+
+    case CPTK_IS_ABSTRACT:
+      return (CLASS_TYPE_P (type1) && CLASSTYPE_PURE_VIRTUALS (type1));
+
+    case CPTK_IS_BASE_OF:
+      return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
+             && DERIVED_FROM_P (type1, type2));
+
+    case CPTK_IS_CLASS:
+      return (NON_UNION_CLASS_TYPE_P (type1));
+
+    case CPTK_IS_CONVERTIBLE_TO:
+      /* TODO  */
+      return false;
+
+    case CPTK_IS_EMPTY:
+      return (NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1));
+
+    case CPTK_IS_ENUM:
+      return (type_code1 == ENUMERAL_TYPE);
+
+    case CPTK_IS_POD:
+      return (pod_type_p (type1));
+
+    case CPTK_IS_POLYMORPHIC:
+      return (CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1));
+
+    case CPTK_IS_UNION:
+      return (type_code1 == UNION_TYPE);
+
+    default:
+      gcc_unreachable ();
+      return false;
+    }
+}
+
+/* Process a trait expression.  */
+
+tree
+finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
+{
+  gcc_assert (kind == CPTK_HAS_NOTHROW_ASSIGN
+             || kind == CPTK_HAS_NOTHROW_CONSTRUCTOR
+             || kind == CPTK_HAS_NOTHROW_COPY
+             || kind == CPTK_HAS_TRIVIAL_ASSIGN
+             || kind == CPTK_HAS_TRIVIAL_CONSTRUCTOR
+             || kind == CPTK_HAS_TRIVIAL_COPY
+             || kind == CPTK_HAS_TRIVIAL_DESTRUCTOR
+             || kind == CPTK_HAS_VIRTUAL_DESTRUCTOR          
+             || kind == CPTK_IS_ABSTRACT
+             || kind == CPTK_IS_BASE_OF
+             || kind == CPTK_IS_CLASS
+             || kind == CPTK_IS_CONVERTIBLE_TO
+             || kind == CPTK_IS_EMPTY
+             || kind == CPTK_IS_ENUM
+             || kind == CPTK_IS_POD
+             || kind == CPTK_IS_POLYMORPHIC
+             || kind == CPTK_IS_UNION);
+
+  if (kind == CPTK_IS_CONVERTIBLE_TO)
+    {
+      sorry ("__is_convertible_to");
+      return error_mark_node;
+    }
+
+  if (type1 == error_mark_node
+      || ((kind == CPTK_IS_BASE_OF || kind == CPTK_IS_CONVERTIBLE_TO)
+         && type2 == error_mark_node))
+    return error_mark_node;
+
+  if (processing_template_decl)
+    {
+      tree trait_expr = make_node (TRAIT_EXPR);
+      TREE_TYPE (trait_expr) = boolean_type_node;
+      TRAIT_EXPR_TYPE1 (trait_expr) = type1;
+      TRAIT_EXPR_TYPE2 (trait_expr) = type2;
+      TRAIT_EXPR_KIND (trait_expr) = kind;
+      return trait_expr;
+    }
+
+  complete_type (type1);
+  if (type2)
+    complete_type (type2);
+
+  /* The only required diagnostic.  */
+  if (kind == CPTK_IS_BASE_OF
+      && NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
+      && !same_type_ignoring_top_level_qualifiers_p (type1, type2)
+      && !COMPLETE_TYPE_P (type2))
+    {
+      error ("incomplete type %qT not allowed", type2);
+      return error_mark_node;
+    }
+
+  return (trait_expr_value (kind, type1, type2)
+         ? boolean_true_node : boolean_false_node);
+}
 
 #include "gt-cp-semantics.h"