OSDN Git Service

2008-04-28 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / cp / semantics.c
index e016b0a..7881a9f 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, 2006, 2007
-   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"
@@ -55,7 +54,6 @@
 
 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 *);
 
 
@@ -383,9 +381,7 @@ add_stmt (tree t)
   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 to which statements are currently being added.  */
 
 stmt_tree
 current_stmt_tree (void)
@@ -437,7 +433,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);
 }
@@ -510,7 +506,8 @@ finish_cond (tree *cond_p, tree expr)
       if (TREE_CODE (cond) == DECL_EXPR)
        expr = cond;
 
-      check_for_bare_parameter_packs (expr);
+      if (check_for_bare_parameter_packs (expr))
+        *cond_p = error_mark_node;
     }
   *cond_p = expr;
 }
@@ -537,7 +534,7 @@ simplify_loop_decl_cond (tree *cond_p, tree body)
   *cond_p = boolean_true_node;
 
   if_stmt = begin_if_stmt ();
-  cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
+  cond = cp_build_unary_op (TRUTH_NOT_EXPR, cond, 0, tf_warning_or_error);
   finish_if_stmt_cond (cond, if_stmt);
   finish_break_stmt ();
   finish_then_clause (if_stmt);
@@ -615,12 +612,14 @@ finish_expr_stmt (tree expr)
        {
          if (warn_sequence_point)
            verify_sequence_points (expr);
-         expr = convert_to_void (expr, "statement");
+         expr = convert_to_void (expr, "statement", tf_warning_or_error);
        }
       else if (!type_dependent_expression_p (expr))
-       convert_to_void (build_non_dependent_expr (expr), "statement");
+       convert_to_void (build_non_dependent_expr (expr), "statement", 
+                         tf_warning_or_error);
 
-      check_for_bare_parameter_packs (expr);
+      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.  */
@@ -701,7 +700,7 @@ finish_if_stmt (tree 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));
+  empty_if_body_warning (THEN_CLAUSE (if_stmt), ELSE_CLAUSE (if_stmt));
 }
 
 /* Begin a while-statement.  Returns a newly created WHILE_STMT if
@@ -754,7 +753,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
@@ -865,12 +871,15 @@ finish_for_expr (tree expr, tree for_stmt)
     {
       if (warn_sequence_point)
        verify_sequence_points (expr);
-      expr = convert_to_void (expr, "3rd expression in for");
+      expr = convert_to_void (expr, "3rd expression in for",
+                              tf_warning_or_error);
     }
   else if (!type_dependent_expression_p (expr))
-    convert_to_void (build_non_dependent_expr (expr), "3rd expression in for");
+    convert_to_void (build_non_dependent_expr (expr), "3rd expression in for",
+                     tf_warning_or_error);
   expr = maybe_cleanup_point_expr_void (expr);
-  check_for_bare_parameter_packs (expr);
+  if (check_for_bare_parameter_packs (expr))
+    expr = error_mark_node;
   FOR_EXPR (for_stmt) = expr;
 }
 
@@ -966,12 +975,13 @@ 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);
   push_switch (switch_stmt);
   SWITCH_STMT_BODY (switch_stmt) = push_stmt_list ();
-  check_for_bare_parameter_packs (cond);
 }
 
 /* Finish the body of a switch-statement, which may be given by
@@ -1238,7 +1248,7 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands,
             otherwise we'll get an error.  Gross, but ...  */
          STRIP_NOPS (operand);
 
-         if (!lvalue_or_else (operand, lv_asm))
+         if (!lvalue_or_else (operand, lv_asm, tf_warning_or_error))
            operand = error_mark_node;
 
          if (operand != error_mark_node
@@ -1336,8 +1346,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.  */
@@ -1378,8 +1393,9 @@ finish_mem_initializers (tree mem_inits)
              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));
+          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));
@@ -1490,7 +1506,8 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
 
       return build_class_member_access_expr (object, decl,
                                             /*access_path=*/NULL_TREE,
-                                            /*preserve_reference=*/false);
+                                            /*preserve_reference=*/false,
+                                            tf_warning_or_error);
     }
 }
 
@@ -1605,8 +1622,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;
@@ -1624,7 +1645,8 @@ finish_qualified_id_expr (tree qualifying_class,
                (maybe_dummy_object (qualifying_class, NULL),
                 expr,
                 BASELINK_ACCESS_BINFO (expr),
-                /*preserve_reference=*/false));
+                /*preserve_reference=*/false,
+                tf_warning_or_error));
       else if (done)
        /* The expression is a qualified name whose address is not
           being taken.  */
@@ -1717,7 +1739,10 @@ finish_stmt_expr (tree stmt_expr, bool has_no_scope)
   tree result;
 
   if (error_operand_p (stmt_expr))
-    return error_mark_node;
+    {
+      pop_stmt_list (stmt_expr);
+      return error_mark_node;
+    }
 
   gcc_assert (TREE_CODE (stmt_expr) == STATEMENT_LIST);
 
@@ -1743,6 +1768,25 @@ finish_stmt_expr (tree stmt_expr, bool has_no_scope)
   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
@@ -1794,7 +1838,8 @@ perform_koenig_lookup (tree fn, tree args)
    Returns code for the call.  */
 
 tree
-finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
+finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p,
+                 tsubst_flags_t complain)
 {
   tree result;
   tree orig_fn;
@@ -1817,6 +1862,20 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
        {
          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)
@@ -1879,7 +1938,8 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
       result = build_new_method_call (object, fn, args, NULL_TREE,
                                      (disallow_virtual
                                       ? LOOKUP_NONVIRTUAL : 0),
-                                     /*fn_p=*/NULL);
+                                     /*fn_p=*/NULL,
+                                     complain);
     }
   else if (is_overloaded_fn (fn))
     {
@@ -1891,7 +1951,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
 
       if (!result)
        /* A call to a namespace-scope function.  */
-       result = build_new_function_call (fn, args, koenig_p);
+       result = build_new_function_call (fn, args, koenig_p, complain);
     }
   else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
     {
@@ -1908,11 +1968,11 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
     /* If the "function" is really an object of class type, it might
        have an overloaded `operator ()'.  */
     result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE,
-                          /*overloaded_p=*/NULL);
+                          /*overloaded_p=*/NULL, complain);
 
   if (!result)
     /* A call where the function is unknown.  */
-    result = build_function_call (fn, args);
+    result = cp_build_function_call (fn, args, complain);
 
   if (processing_template_decl)
     {
@@ -1929,7 +1989,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
 tree
 finish_increment_expr (tree expr, enum tree_code code)
 {
-  return build_x_unary_op (code, expr);
+  return build_x_unary_op (code, expr, tf_warning_or_error);
 }
 
 /* Finish a use of `this'.  Returns an expression for `this'.  */
@@ -1969,7 +2029,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));
@@ -2018,7 +2078,7 @@ finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
 tree
 finish_unary_op_expr (enum tree_code code, tree expr)
 {
-  tree result = build_x_unary_op (code, expr);
+  tree result = build_x_unary_op (code, expr, tf_warning_or_error);
   /* Inside a template, build_x_unary_op does not fold the
      expression. So check whether the result is folded before
      setting TREE_NEGATED_INT.  */
@@ -2044,7 +2104,6 @@ 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))
@@ -2063,30 +2122,12 @@ finish_compound_literal (tree type, VEC(constructor_elt,gc) *initializer_list)
       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;
+  type = complete_type (type);
+  compound_literal = reshape_init (type, compound_literal);
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    cp_complete_array_type (&type, compound_literal, false);
+  compound_literal = digest_init (type, compound_literal);
+  return get_target_expr (compound_literal);
 }
 
 /* Return the declaration for the function-name variable indicated by
@@ -2148,6 +2189,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);
 }
 
@@ -2198,9 +2243,9 @@ begin_class_definition (tree t, tree attributes)
       t = error_mark_node;
     }
 
-  if (t == error_mark_node || ! IS_AGGR_TYPE (t))
+  if (t == error_mark_node || ! MAYBE_CLASS_TYPE_P (t))
     {
-      t = make_aggr_type (RECORD_TYPE);
+      t = make_class_type (RECORD_TYPE);
       pushtag (make_anon_name (), t, /*tag_scope=*/ts_current);
     }
 
@@ -2209,7 +2254,7 @@ begin_class_definition (tree t, tree attributes)
 
   if (TYPE_BEING_DEFINED (t))
     {
-      t = make_aggr_type (TREE_CODE (t));
+      t = make_class_type (TREE_CODE (t));
       pushtag (TYPE_IDENTIFIER (t), t, /*tag_scope=*/ts_current);
     }
   maybe_process_partial_specialization (t);
@@ -2276,6 +2321,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
@@ -2404,8 +2458,11 @@ finish_base_specifier (tree base, tree access, bool virtual_p)
       error ("invalid base-class specification");
       result = NULL_TREE;
     }
-  else if (! is_aggr_type (base, 1))
-    result = NULL_TREE;
+  else if (! MAYBE_CLASS_TYPE_P (base))
+    {
+      error ("%qT is not a class type", base);
+      result = NULL_TREE;
+    }
   else
     {
       if (cp_type_quals (base) != 0)
@@ -2884,7 +2941,8 @@ finish_id_expression (tree id_expression,
              /* A set of member functions.  */
              decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
              return finish_class_member_access_expr (decl, id_expression,
-                                                     /*template_p=*/false);
+                                                     /*template_p=*/false,
+                                                     tf_warning_or_error);
            }
 
          decl = baselink_for_fns (decl);
@@ -2892,13 +2950,15 @@ finish_id_expression (tree id_expression,
       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, 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);
@@ -2921,8 +2981,9 @@ finish_typeof (tree expr)
 
   if (type_dependent_expression_p (expr))
     {
-      type = make_aggr_type (TYPEOF_TYPE);
+      type = cxx_make_type (TYPEOF_TYPE);
       TYPEOF_TYPE_EXPR (type) = expr;
+      SET_TYPE_STRUCTURAL_EQUALITY (type);
 
       return type;
     }
@@ -2960,6 +3021,8 @@ finish_offsetof (tree expr)
       error ("cannot apply %<offsetof%> to member function %qD", expr);
       return error_mark_node;
     }
+  if (TREE_CODE (expr) == INDIRECT_REF && REFERENCE_REF_P (expr))
+    expr = TREE_OPERAND (expr, 0);
   return fold_offsetof (expr, NULL_TREE);
 }
 
@@ -3048,7 +3111,8 @@ simplify_aggr_init_expr (tree *tp)
         SLOT.  */
       push_deferring_access_checks (dk_no_check);
       call_expr = build_aggr_init (slot, call_expr,
-                                  DIRECT_BIND | LOOKUP_ONLYCONVERTING);
+                                  DIRECT_BIND | LOOKUP_ONLYCONVERTING,
+                                   tf_warning_or_error);
       pop_deferring_access_checks ();
       call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (slot), call_expr, slot);
     }
@@ -3058,7 +3122,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
@@ -3093,62 +3157,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);
-
-  c_expand_body (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
@@ -3167,9 +3175,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.  */
@@ -3181,10 +3189,6 @@ expand_or_defer_fn (tree fn)
       return;
     }
 
-  /* Keep track of functions declared with the "constructor" and
-     "destructor" attribute.  */
-  c_record_cdtor_fn (fn);
-
   /* 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
@@ -3323,7 +3327,7 @@ 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
@@ -3369,14 +3373,17 @@ finish_omp_clauses (tree clauses)
            {
              if (processing_template_decl)
                break;
-             error ("%qE is not a variable in clause %qs", t, name);
+             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 ("%qE appears more than once in data clauses", t);
+             error ("%qD appears more than once in data clauses", t);
              remove = true;
            }
          else
@@ -3389,13 +3396,16 @@ finish_omp_clauses (tree clauses)
            {
              if (processing_template_decl)
                break;
-             error ("%qE is not a variable in clause %<firstprivate%>", t);
+             if (DECL_P (t))
+               error ("%qD is not a variable in clause %<firstprivate%>", t);
+             else
+               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);
+             error ("%qD appears more than once in data clauses", t);
              remove = true;
            }
          else
@@ -3408,13 +3418,16 @@ finish_omp_clauses (tree clauses)
            {
              if (processing_template_decl)
                break;
-             error ("%qE is not a variable in clause %<lastprivate%>", t);
+             if (DECL_P (t))
+               error ("%qD is not a variable in clause %<lastprivate%>", t);
+             else
+               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);
+             error ("%qD appears more than once in data clauses", t);
              remove = true;
            }
          else
@@ -3433,8 +3446,8 @@ finish_omp_clauses (tree clauses)
          t = OMP_CLAUSE_NUM_THREADS_EXPR (c);
          if (t == error_mark_node)
            remove = true;
-         else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
-                  && !type_dependent_expression_p (t))
+         else if (!type_dependent_expression_p (t)
+                  && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
            {
              error ("num_threads expression must be integral");
              remove = true;
@@ -3447,8 +3460,8 @@ finish_omp_clauses (tree clauses)
            ;
          else if (t == error_mark_node)
            remove = true;
-         else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
-                  && !type_dependent_expression_p (t))
+         else if (!type_dependent_expression_p (t)
+                  && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
            {
              error ("schedule chunk size expression must be integral");
              remove = true;
@@ -3620,7 +3633,8 @@ finish_omp_clauses (tree clauses)
         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))
+         && (need_default_ctor || need_copy_ctor || need_copy_assignment)
+         && !type_dependent_expression_p (t))
        {
          int save_errorcount = errorcount;
          tree info;
@@ -3647,7 +3661,19 @@ finish_omp_clauses (tree clauses)
                }
              t = build_special_member_call (NULL_TREE,
                                             complete_ctor_identifier,
-                                            t, inner_type, LOOKUP_NORMAL);
+                                            t, inner_type, LOOKUP_NORMAL,
+                                             tf_warning_or_error);
+
+             if (targetm.cxx.cdtor_returns_this () || errorcount)
+               /* 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;
            }
@@ -3658,7 +3684,19 @@ finish_omp_clauses (tree clauses)
              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);
+                                            NULL, inner_type, LOOKUP_NORMAL,
+                                             tf_warning_or_error);
+
+             if (targetm.cxx.cdtor_returns_this () || errorcount)
+               /* 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;
            }
@@ -3670,7 +3708,8 @@ finish_omp_clauses (tree clauses)
              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);
+                                            inner_type, LOOKUP_NORMAL,
+                                             tf_warning_or_error);
 
              /* We'll have called convert_from_reference on the call, which
                 may well have added an indirect_ref.  It's unneeded here,
@@ -3708,9 +3747,14 @@ finish_omp_threadprivate (tree vars)
     {
       tree v = TREE_PURPOSE (t);
 
+      if (error_operand_p (v))
+       ;
+      else if (TREE_CODE (v) != VAR_DECL)
+       error ("%<threadprivate%> %qD is not file, namespace "
+              "or block scope variable", v);
       /* If V had already been marked threadprivate, it doesn't matter
         whether it had been used prior to this point.  */
-      if (TREE_USED (v)
+      else if (TREE_USED (v)
          && (DECL_LANG_SPECIFIC (v) == NULL
              || !CP_DECL_THREADPRIVATE_P (v)))
        error ("%qE declared %<threadprivate%> after first use", v);
@@ -3797,6 +3841,8 @@ 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)
@@ -3867,6 +3913,16 @@ finish_omp_for (location_t locus, tree decl, tree init, tree cond,
       return NULL;
     }
 
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)))
+    {
+      location_t elocus = locus;
+
+      if (EXPR_HAS_LOCATION (init))
+       elocus = EXPR_LOCATION (init);
+      error ("%Hinvalid type for iteration variable %qE", &elocus, decl);
+      return NULL;
+    }
+
   if (pre_body == NULL || IS_EMPTY_STMT (pre_body))
     pre_body = NULL;
   else if (! processing_template_decl)
@@ -3874,42 +3930,79 @@ finish_omp_for (location_t locus, tree decl, tree init, tree cond,
       add_stmt (pre_body);
       pre_body = NULL;
     }
-  init = build_modify_expr (decl, NOP_EXPR, init);
-  return c_finish_omp_for (locus, decl, init, cond, incr, body, pre_body);
+
+  if (!processing_template_decl)
+    init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
+  init = cp_build_modify_expr (decl, NOP_EXPR, init, tf_warning_or_error);
+  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;
+
+      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;
 
-  if (processing_template_decl
-      && (type_dependent_expression_p (lhs) 
-         || type_dependent_expression_p (rhs)))
-    stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node,
-                  build2 (code, void_type_node, lhs, rhs));
-  else
+  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)
     {
-      /* 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 (stmt != error_mark_node)
-    add_stmt (stmt);
+  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);
+  tree stmt = finish_call_expr (fn, NULL, false, false, tf_warning_or_error);
   finish_expr_stmt (stmt);
 }
 
@@ -3917,7 +4010,7 @@ void
 finish_omp_flush (void)
 {
   tree fn = built_in_decls[BUILT_IN_SYNCHRONIZE];
-  tree stmt = finish_call_expr (fn, NULL, false, false);
+  tree stmt = finish_call_expr (fn, NULL, false, false, tf_warning_or_error);
   finish_expr_stmt (stmt);
 }
 
@@ -3936,7 +4029,7 @@ cxx_omp_predetermined_sharing (tree decl)
   if (TREE_STATIC (decl))
     {
       tree ctx = CP_DECL_CONTEXT (decl);
-      if (TYPE_P (ctx) && IS_AGGR_TYPE (ctx))
+      if (TYPE_P (ctx) && MAYBE_CLASS_TYPE_P (ctx))
        return OMP_CLAUSE_DEFAULT_SHARED;
     }
 
@@ -3956,6 +4049,9 @@ 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))
     {
@@ -3999,5 +4095,378 @@ finish_static_assert (tree condition, tree message, location_t location,
       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 = cxx_make_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_BIT_FIELD_TYPE (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"