OSDN Git Service

* class.c (build_base_path): Use build_address directly.
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck2.c
index 48caade..0a8ac75 100644 (file)
@@ -1,23 +1,24 @@
 /* Report error messages, build initializers, and perform
    some front-end optimizations for C++ compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2004
+   Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
+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)
 any later version.
 
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
+along with GCC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
@@ -25,14 +26,12 @@ Boston, MA 02111-1307, USA.  */
 /* This file is part of the C++ front end.
    It contains routines to build C++ expressions given their operands,
    including computing the types of the result, C and C++ specific error
-   checks, and some optimization.
-
-   There are also routines to build RETURN_STMT nodes and CASE_STMT nodes,
-   and to process initializations in declarations (since they work
-   like a strange sort of assignment).  */
+   checks, and some optimization.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "cp-tree.h"
 #include "flags.h"
@@ -40,14 +39,13 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "diagnostic.h"
 
-static tree process_init_constructor PARAMS ((tree, tree, tree *));
+static tree process_init_constructor (tree, tree, tree *);
 
 /* Print an error message stemming from an attempt to use
    BASETYPE as a base class for TYPE.  */
 
 tree
-error_not_base_type (basetype, type)
-     tree basetype, type;
+error_not_base_type (tree basetype, tree type)
 {
   if (TREE_CODE (basetype) == FUNCTION_DECL)
     basetype = DECL_CONTEXT (basetype);
@@ -56,8 +54,7 @@ error_not_base_type (basetype, type)
 }
 
 tree
-binfo_or_else (base, type)
-     tree base, type;
+binfo_or_else (tree base, tree type)
 {
   tree binfo = lookup_base (type, base, ba_ignore, NULL);
 
@@ -74,13 +71,10 @@ binfo_or_else (base, type)
    example, conversions to references.)  */
 
 void
-readonly_error (arg, string, soft)
-     tree arg;
-     const char *string;
-     int soft;
+readonly_error (tree arg, const char* string, int soft)
 {
   const char *fmt;
-  void (*fn) PARAMS ((const char *, ...));
+  void (*fn) (const char *, ...);
 
   if (soft)
     fn = pedwarn;
@@ -120,20 +114,168 @@ readonly_error (arg, string, soft)
     (*fn) ("%s of read-only location", string);
 }
 
+\f
+/* Structure that holds information about declarations whose type was
+   incomplete and we could not check whether it was abstract or not.  */
+
+struct pending_abstract_type GTY((chain_next ("%h.next")))
+{
+  /* Declaration which we are checking for abstractness. It is either
+     a DECL node, or an IDENTIFIER_NODE if we do not have a full
+     declaration available.  */
+  tree decl;
+
+  /* Type which will be checked for abstractness.  */
+  tree type;
+
+  /* Position of the declaration. This is only needed for IDENTIFIER_NODEs,
+     because DECLs already carry locus information.  */
+  location_t locus;
+
+  /* Link to the next element in list.  */
+  struct pending_abstract_type* next;
+};
+
+
+/* Compute the hash value of the node VAL. This function is used by the
+   hash table abstract_pending_vars.  */
+
+static hashval_t
+pat_calc_hash (const void* val)
+{
+  const struct pending_abstract_type* pat = val;
+  return (hashval_t) TYPE_UID (pat->type);
+}
+
+
+/* Compare node VAL1 with the type VAL2. This function is used by the
+   hash table abstract_pending_vars.  */
+
+static int
+pat_compare (const void* val1, const void* val2)
+{
+  const struct pending_abstract_type* pat1 = val1;
+  tree type2 = (tree)val2;
+
+  return (pat1->type == type2);
+}
+
+/* Hash table that maintains pending_abstract_type nodes, for which we still
+   need to check for type abstractness.  The key of the table is the type
+   of the declaration.  */
+static GTY ((param_is (struct pending_abstract_type)))
+htab_t abstract_pending_vars = NULL;
+
+
+/* This function is called after TYPE is completed, and will check if there
+   are pending declarations for which we still need to verify the abstractness
+   of TYPE, and emit a diagnostic (through abstract_virtuals_error) if TYPE
+   turned out to be incomplete.  */
+
+void
+complete_type_check_abstract (tree type)
+{
+  void **slot;
+  struct pending_abstract_type *pat;
+  location_t cur_loc = input_location;
+
+  gcc_assert (COMPLETE_TYPE_P (type));
+
+  if (!abstract_pending_vars)
+    return;
+
+  /* Retrieve the list of pending declarations for this type.  */
+  slot = htab_find_slot_with_hash (abstract_pending_vars, type,
+                                  (hashval_t)TYPE_UID (type), NO_INSERT);
+  if (!slot)
+    return;
+  pat = (struct pending_abstract_type*)*slot;
+  gcc_assert (pat);
+
+  /* If the type is not abstract, do not do anything.  */
+  if (CLASSTYPE_PURE_VIRTUALS (type))
+    {
+      struct pending_abstract_type *prev = 0, *next;
+
+      /* Reverse the list to emit the errors in top-down order.  */
+      for (; pat; pat = next)
+       {
+         next = pat->next;
+         pat->next = prev;
+         prev = pat;
+       }
+      pat = prev;
+
+      /* Go through the list, and call abstract_virtuals_error for each
+       element: it will issue a diagostic if the type is abstract.  */
+      while (pat)
+       {
+         gcc_assert (type == pat->type);
+
+         /* Tweak input_location so that the diagnostic appears at the correct
+           location. Notice that this is only needed if the decl is an
+           IDENTIFIER_NODE, otherwise cp_error_at. */
+         input_location = pat->locus;
+         abstract_virtuals_error (pat->decl, pat->type);
+         pat = pat->next;
+       }
+    }
+
+  htab_clear_slot (abstract_pending_vars, slot);
+
+  input_location = cur_loc;
+}
+
+
 /* If TYPE has abstract virtual functions, issue an error about trying
    to create an object of that type.  DECL is the object declared, or
    NULL_TREE if the declaration is unavailable.  Returns 1 if an error
    occurred; zero if all was well.  */
 
 int
-abstract_virtuals_error (decl, type)
-     tree decl;
-     tree type;
+abstract_virtuals_error (tree decl, tree type)
 {
   tree u;
   tree tu;
 
-  if (!CLASS_TYPE_P (type) || !CLASSTYPE_PURE_VIRTUALS (type))
+  /* This function applies only to classes. Any other entity can never
+     be abstract.  */
+  if (!CLASS_TYPE_P (type))
+    return 0;
+
+  /* If the type is incomplete, we register it within a hash table,
+     so that we can check again once it is completed. This makes sense
+     only for objects for which we have a declaration or at least a
+     name.  */
+  if (!COMPLETE_TYPE_P (type))
+    {
+      void **slot;
+      struct pending_abstract_type *pat;
+
+      gcc_assert (!decl || DECL_P (decl) 
+                 || TREE_CODE (decl) == IDENTIFIER_NODE);
+
+      if (!abstract_pending_vars)
+       abstract_pending_vars = htab_create_ggc (31, &pat_calc_hash, 
+                                               &pat_compare, NULL);
+
+      slot = htab_find_slot_with_hash (abstract_pending_vars, type,
+                                     (hashval_t)TYPE_UID (type), INSERT);
+
+      pat = GGC_NEW (struct pending_abstract_type);
+      pat->type = type;
+      pat->decl = decl;
+      pat->locus = ((decl && DECL_P (decl))
+                   ? DECL_SOURCE_LOCATION (decl)
+                   : input_location);
+
+      pat->next = *slot;
+      *slot = pat;
+
+      return 0;
+    }
+
+  if (!CLASSTYPE_PURE_VIRTUALS (type))
     return 0;
 
   if (!TYPE_SIZE (type))
@@ -148,60 +290,90 @@ abstract_virtuals_error (decl, type)
        return 0;
 
       if (TREE_CODE (decl) == VAR_DECL)
-       error ("cannot declare variable `%D' to be of type `%T'",
-                   decl, type);
+       cp_error_at ("cannot declare variable `%+D' to be of abstract "
+                    "type `%T'", decl, type);
       else if (TREE_CODE (decl) == PARM_DECL)
-       error ("cannot declare parameter `%D' to be of type `%T'",
-                   decl, type);
+       cp_error_at ("cannot declare parameter `%+D' to be of abstract "
+                    "type `%T'", decl, type);
       else if (TREE_CODE (decl) == FIELD_DECL)
-       error ("cannot declare field `%D' to be of type `%T'",
-                   decl, type);
+       cp_error_at ("cannot declare field `%+D' to be of abstract "
+                    "type `%T'", decl, type);
       else if (TREE_CODE (decl) == FUNCTION_DECL
               && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
-       error ("invalid return type for member function `%#D'", decl);
+       cp_error_at ("invalid abstract return type for member function `%+#D'",
+                    decl);
       else if (TREE_CODE (decl) == FUNCTION_DECL)
-       error ("invalid return type for function `%#D'", decl);
+       cp_error_at ("invalid abstract return type for function `%+#D'", 
+                    decl);
+      else if (TREE_CODE (decl) == IDENTIFIER_NODE)
+       /* Here we do not have location information, so use error instead
+          of cp_error_at.  */
+       error ("invalid abstract type `%T' for `%E'", type, decl);
+      else
+       cp_error_at ("invalid abstract type for `%+D'", decl);
     }
   else
-    error ("cannot allocate an object of type `%T'", type);
+    error ("cannot allocate an object of abstract type `%T'", type);
 
   /* Only go through this once.  */
   if (TREE_PURPOSE (u) == NULL_TREE)
     {
       TREE_PURPOSE (u) = error_mark_node;
 
-      error ("  because the following virtual functions are abstract:");
+      inform ("%J  because the following virtual functions are pure "
+             "within `%T':", TYPE_MAIN_DECL (type), type);
+
       for (tu = u; tu; tu = TREE_CHAIN (tu))
-       cp_error_at ("\t%#D", TREE_VALUE (tu));
+       inform ("%J\t%#D", TREE_VALUE (tu), TREE_VALUE (tu));
     }
   else
-    error ("  since type `%T' has abstract virtual functions", type);
+    inform ("%J  since type `%T' has pure virtual functions", 
+           TYPE_MAIN_DECL (type), type);
 
   return 1;
 }
 
 /* Print an error message for invalid use of an incomplete type.
    VALUE is the expression that was used (or 0 if that isn't known)
-   and TYPE is the type that was invalid.  */
+   and TYPE is the type that was invalid.  DIAG_TYPE indicates the
+   type of diagnostic:  0 for an error, 1 for a warning, 2 for a
+   pedwarn.  */
 
 void
-incomplete_type_error (value, type)
-     tree value;
-     tree type;
+cxx_incomplete_type_diagnostic (tree value, tree type, int diag_type)
 {
   int decl = 0;
+  void (*p_msg) (const char *, ...);
+  void (*p_msg_at) (const char *, ...);
+
+  if (diag_type == 1)
+    {
+      p_msg = warning;
+      p_msg_at = cp_warning_at;
+    }
+  else if (diag_type == 2)
+    {
+      p_msg = pedwarn;
+      p_msg_at = cp_pedwarn_at;
+    }
+  else
+    {
+      p_msg = error;
+      p_msg_at = cp_error_at;
+    }
   
   /* Avoid duplicate error message.  */
   if (TREE_CODE (type) == ERROR_MARK)
     return;
 
   if (value != 0 && (TREE_CODE (value) == VAR_DECL
-                    || TREE_CODE (value) == PARM_DECL))
+                    || TREE_CODE (value) == PARM_DECL
+                    || TREE_CODE (value) == FIELD_DECL))
     {
-      cp_error_at ("`%D' has incomplete type", value);
+      (*p_msg_at) ("`%D' has incomplete type", value);
       decl = 1;
     }
-retry:
+ retry:
   /* We must print an error message.  Be clever about what it says.  */
 
   switch (TREE_CODE (type))
@@ -210,12 +382,15 @@ retry:
     case UNION_TYPE:
     case ENUMERAL_TYPE:
       if (!decl)
-        error ("invalid use of undefined type `%#T'", type);
-      cp_error_at ("forward declaration of `%#T'", type);
+        (*p_msg) ("invalid use of undefined type `%#T'", type);
+      if (!TYPE_TEMPLATE_INFO (type))
+       (*p_msg_at) ("forward declaration of `%#T'", type);
+      else
+       (*p_msg_at) ("declaration of `%#T'", type);
       break;
 
     case VOID_TYPE:
-      error ("invalid use of `%T'", type);
+      (*p_msg) ("invalid use of `%T'", type);
       break;
 
     case ARRAY_TYPE:
@@ -224,35 +399,144 @@ retry:
           type = TREE_TYPE (type);
           goto retry;
         }
-      error ("invalid use of array with unspecified bounds");
+      (*p_msg) ("invalid use of array with unspecified bounds");
       break;
 
     case OFFSET_TYPE:
     bad_member:
-      error ("invalid use of member (did you forget the `&' ?)");
+      (*p_msg) ("invalid use of member (did you forget the `&' ?)");
       break;
 
     case TEMPLATE_TYPE_PARM:
-      error ("invalid use of template type parameter");
+      (*p_msg) ("invalid use of template type parameter");
       break;
 
     case UNKNOWN_TYPE:
       if (value && TREE_CODE (value) == COMPONENT_REF)
         goto bad_member;
       else if (value && TREE_CODE (value) == ADDR_EXPR)
-        error ("address of overloaded function with no contextual type information");
+        (*p_msg) ("address of overloaded function with no contextual type information");
       else if (value && TREE_CODE (value) == OVERLOAD)
-        error ("overloaded function with no contextual type information");
+        (*p_msg) ("overloaded function with no contextual type information");
       else
-        error ("insufficient contextual information to determine type");
+        (*p_msg) ("insufficient contextual information to determine type");
       break;
     
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
+/* Backward-compatibility interface to incomplete_type_diagnostic;
+   required by ../tree.c.  */
+#undef cxx_incomplete_type_error
+void
+cxx_incomplete_type_error (tree value, tree type)
+{
+  cxx_incomplete_type_diagnostic (value, type, 0);
+}
+
 \f
+/* The recursive part of split_nonconstant_init.  DEST is an lvalue
+   expression to which INIT should be assigned.  INIT is a CONSTRUCTOR.  */
+
+static void
+split_nonconstant_init_1 (tree dest, tree init)
+{
+  tree *pelt, elt, type = TREE_TYPE (dest);
+  tree sub, code, inner_type = NULL;
+  bool array_type_p = false;
+
+  pelt = &CONSTRUCTOR_ELTS (init);
+  switch (TREE_CODE (type))
+    {
+    case ARRAY_TYPE:
+      inner_type = TREE_TYPE (type);
+      array_type_p = true;
+      /* FALLTHRU */
+
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      while ((elt = *pelt))
+       {
+         tree field_index = TREE_PURPOSE (elt);
+         tree value = TREE_VALUE (elt);
+
+         if (!array_type_p)
+           inner_type = TREE_TYPE (field_index);
+
+         if (TREE_CODE (value) == CONSTRUCTOR)
+           {
+             if (array_type_p)
+               sub = build4 (ARRAY_REF, inner_type, dest, field_index,
+                             NULL_TREE, NULL_TREE);
+             else
+               sub = build3 (COMPONENT_REF, inner_type, dest, field_index,
+                             NULL_TREE);
+
+             split_nonconstant_init_1 (sub, value);
+           }
+         else if (!initializer_constant_valid_p (value, inner_type))
+           {
+             *pelt = TREE_CHAIN (elt);
+
+             if (array_type_p)
+               sub = build4 (ARRAY_REF, inner_type, dest, field_index,
+                             NULL_TREE, NULL_TREE);
+             else
+               sub = build3 (COMPONENT_REF, inner_type, dest, field_index,
+                             NULL_TREE);
+
+             code = build2 (MODIFY_EXPR, inner_type, sub, value);
+             code = build_stmt (EXPR_STMT, code);
+             add_stmt (code);
+             continue;
+           }
+
+         pelt = &TREE_CHAIN (elt);
+       }
+      break;
+
+    case VECTOR_TYPE:
+      if (!initializer_constant_valid_p (init, type))
+       {
+         CONSTRUCTOR_ELTS (init) = NULL;
+         code = build2 (MODIFY_EXPR, type, dest, init);
+         code = build_stmt (EXPR_STMT, code);
+         add_stmt (code);
+       }
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* A subroutine of store_init_value.  Splits non-constant static 
+   initializer INIT into a constant part and generates code to
+   perform the non-constant part of the initialization to DEST.
+   Returns the code for the runtime init.  */
+
+static tree
+split_nonconstant_init (tree dest, tree init)
+{
+  tree code;
+
+  if (TREE_CODE (init) == CONSTRUCTOR)
+    {
+      code = push_stmt_list ();
+      split_nonconstant_init_1 (dest, init);
+      code = pop_stmt_list (code);
+      DECL_INITIAL (dest) = init;
+      TREE_READONLY (dest) = 0;
+    }
+  else
+    code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init);
+
+  return code;
+}
+
 /* Perform appropriate conversions on the initial value of a variable,
    store it in the declaration DECL,
    and print any error messages that are appropriate.
@@ -268,15 +552,13 @@ retry:
    into a CONSTRUCTOR and use standard initialization techniques.
    Perhaps a warning should be generated?
 
-   Returns value of initializer if initialization could not be
-   performed for static variable.  In that case, caller must do
-   the storing.  */
+   Returns code to be executed if initialization could not be performed
+   for static variable.  In that case, caller must emit the code.  */
 
 tree
-store_init_value (decl, init)
-     tree decl, init;
+store_init_value (tree decl, tree init)
 {
-  register tree value, type;
+  tree value, type;
 
   /* If variable's type was invalidly declared, just ignore it.  */
 
@@ -284,66 +566,23 @@ store_init_value (decl, init)
   if (TREE_CODE (type) == ERROR_MARK)
     return NULL_TREE;
 
-#if 0
-  /* This breaks arrays, and should not have any effect for other decls.  */
-  /* Take care of C++ business up here.  */
-  type = TYPE_MAIN_VARIANT (type);
-#endif
-
   if (IS_AGGR_TYPE (type))
     {
-      if (! TYPE_HAS_TRIVIAL_INIT_REF (type)
-         && TREE_CODE (init) != CONSTRUCTOR)
-       abort ();
+      gcc_assert (TYPE_HAS_TRIVIAL_INIT_REF (type)
+                 || TREE_CODE (init) == CONSTRUCTOR);
 
       if (TREE_CODE (init) == TREE_LIST)
        {
          error ("constructor syntax used, but no constructor declared for type `%T'", type);
-         init = build_nt (CONSTRUCTOR, NULL_TREE, nreverse (init));
-       }
-#if 0
-      if (TREE_CODE (init) == CONSTRUCTOR)
-       {
-         tree field;
-
-         /* Check that we're really an aggregate as ARM 8.4.1 defines it.  */
-         if (CLASSTYPE_N_BASECLASSES (type))
-           cp_error_at ("initializer list construction invalid for derived class object `%D'", decl);
-         if (CLASSTYPE_VTBL_PTR (type))
-           cp_error_at ("initializer list construction invalid for polymorphic class object `%D'", decl);
-         if (TYPE_NEEDS_CONSTRUCTING (type))
-           {
-             cp_error_at ("initializer list construction invalid for `%D'", decl);
-             error ("due to the presence of a constructor");
-           }
-         for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
-           if (TREE_PRIVATE (field) || TREE_PROTECTED (field))
-             {
-               cp_error_at ("initializer list construction invalid for `%D'", decl);
-               cp_error_at ("due to non-public access of member `%D'", field);
-             }
-         for (field = TYPE_METHODS (type); field; field = TREE_CHAIN (field))
-           if (TREE_PRIVATE (field) || TREE_PROTECTED (field))
-             {
-               cp_error_at ("initializer list construction invalid for `%D'", decl);
-               cp_error_at ("due to non-public access of member `%D'", field);
-             }
+         init = build_constructor (NULL_TREE, nreverse (init));
        }
-#endif
     }
   else if (TREE_CODE (init) == TREE_LIST
           && TREE_TYPE (init) != unknown_type_node)
     {
       if (TREE_CODE (decl) == RESULT_DECL)
-       {
-         if (TREE_CHAIN (init))
-           {
-             warning ("comma expression used to initialize return value");
-             init = build_compound_expr (init);
-           }
-         else
-           init = TREE_VALUE (init);
-       }
+       init = build_x_compound_expr_from_list (init,
+                                               "return value initializer");
       else if (TREE_CODE (init) == TREE_LIST
               && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
        {
@@ -351,30 +590,14 @@ store_init_value (decl, init)
          return NULL_TREE;
        }
       else
-       {
-         /* We get here with code like `int a (2);' */
-            
-         if (TREE_CHAIN (init) != NULL_TREE)
-           {
-             pedwarn ("initializer list being treated as compound expression");
-             init = build_compound_expr (init);
-           }
-         else
-           init = TREE_VALUE (init);
-       }
+       /* We get here with code like `int a (2);' */
+       init = build_x_compound_expr_from_list (init, "initializer");
     }
 
   /* End of special C++ code.  */
 
-  /* We might have already run this bracketed initializer through
-     digest_init.  Don't do so again.  */
-  if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init)
-      && TREE_TYPE (init)
-      && TYPE_MAIN_VARIANT (TREE_TYPE (init)) == TYPE_MAIN_VARIANT (type))
-    value = init;
-  else
-    /* Digest the specified initializer into an expression.  */
-    value = digest_init (type, init, (tree *) 0);
+  /* Digest the specified initializer into an expression.  */
+  value = digest_init (type, init, (tree *) 0);
 
   /* Store the expression if valid; else report error.  */
 
@@ -384,35 +607,11 @@ store_init_value (decl, init)
      constructing never make it into DECL_INITIAL, and passes 'init' to
      build_aggr_init without checking DECL_INITIAL.  So just return.  */
   else if (TYPE_NEEDS_CONSTRUCTING (type))
-    return value;
+    return build2 (INIT_EXPR, type, decl, value);
   else if (TREE_STATIC (decl)
-          && (! TREE_CONSTANT (value)
-              || ! initializer_constant_valid_p (value, TREE_TYPE (value))
-#if 0
-              /* A STATIC PUBLIC int variable doesn't have to be
-                 run time inited when doing pic.  (mrs) */
-              /* Since ctors and dtors are the only things that can
-                 reference vtables, and they are always written down
-                 the vtable definition, we can leave the
-                 vtables in initialized data space.
-                 However, other initialized data cannot be initialized
-                 this way.  Instead a global file-level initializer
-                 must do the job.  */
-              || (flag_pic && !DECL_VIRTUAL_P (decl) && TREE_PUBLIC (decl))
-#endif
-              ))
-
-    return value;
-#if 0 /* No, that's C.  jason 9/19/94 */
-  else
-    {
-      if (pedantic && TREE_CODE (value) == CONSTRUCTOR)
-       {
-         if (! TREE_CONSTANT (value) || ! TREE_STATIC (value))
-           pedwarn ("ISO C++ forbids non-constant aggregate initializer expressions");
-       }
-    }
-#endif
+          && (TREE_SIDE_EFFECTS (value)
+              || ! initializer_constant_valid_p (value, TREE_TYPE (value))))
+    return split_nonconstant_init (decl, value);
   
   /* Store the VALUE in DECL_INITIAL.  If we're building a
      statement-tree we will actually expand the initialization later
@@ -420,6 +619,7 @@ store_init_value (decl, init)
   DECL_INITIAL (decl) = value;
   return NULL_TREE;
 }
+
 \f
 /* Digest the parser output INIT as an initializer for type TYPE.
    Return a C expression of type TYPE to represent the initial value.
@@ -431,15 +631,11 @@ store_init_value (decl, init)
    TYPE is an aggregate and INIT is not a constructor.  */
 
 tree
-digest_init (type, init, tail)
-     tree type, init, *tail;
+digest_init (tree type, tree init, tree* tail)
 {
   enum tree_code code = TREE_CODE (type);
   tree element = NULL_TREE;
   tree old_tail_contents = NULL_TREE;
-  /* Nonzero if INIT is a braced grouping, which comes in as a CONSTRUCTOR
-     tree node which has no TREE_TYPE.  */
-  int raw_constructor;
 
   /* By default, assume we use one element from a list.
      We correct this later in the sole case where it is not true.  */
@@ -456,7 +652,7 @@ digest_init (type, init, tail)
 
   if (TREE_CODE (init) == ERROR_MARK)
     /* __PRETTY_FUNCTION__'s initializer is a bogus expression inside
-       a template function. This gets substituted during instantiation. */
+       a template function. This gets substituted during instantiation.  */
     return init;
 
   /* We must strip the outermost array type when completing the type,
@@ -469,12 +665,7 @@ digest_init (type, init, tail)
   if (TREE_CODE (init) == NON_LVALUE_EXPR)
     init = TREE_OPERAND (init, 0);
 
-  if (TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == type)
-    return init;
-
-  raw_constructor = TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == 0;
-
-  if (raw_constructor
+  if (BRACE_ENCLOSED_INITIALIZER_P (init)
       && CONSTRUCTOR_ELTS (init) != 0
       && TREE_CHAIN (CONSTRUCTOR_ELTS (init)) == 0)
     {
@@ -525,8 +716,7 @@ digest_init (type, init, tail)
          if (TYPE_DOMAIN (type) != 0
              && TREE_CONSTANT (TYPE_SIZE (type)))
            {
-             register int size
-               = TREE_INT_CST_LOW (TYPE_SIZE (type));
+             int size = TREE_INT_CST_LOW (TYPE_SIZE (type));
              size = (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
              /* In C it is ok to subtract 1 from the length of the string
                 because it's ok to ignore the terminating null char that is
@@ -545,9 +735,9 @@ digest_init (type, init, tail)
   if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE
       || code == ENUMERAL_TYPE || code == REFERENCE_TYPE
       || code == BOOLEAN_TYPE || code == COMPLEX_TYPE
-      || TYPE_PTRMEMFUNC_P (type))
+      || TYPE_PTR_TO_MEMBER_P (type))
     {
-      if (raw_constructor)
+      if (BRACE_ENCLOSED_INITIALIZER_P (init))
        {
          if (element == 0)
            {
@@ -556,7 +746,7 @@ digest_init (type, init, tail)
            }
          init = element;
        }
-      while (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init))
+      while (BRACE_ENCLOSED_INITIALIZER_P (init))
        {
          pedwarn ("braces around scalar initializer for `%T'", type);
          init = CONSTRUCTOR_ELTS (init);
@@ -580,15 +770,16 @@ digest_init (type, init, tail)
 
   if (code == ARRAY_TYPE || code == VECTOR_TYPE || IS_AGGR_TYPE_CODE (code))
     {
-      if (raw_constructor && TYPE_NON_AGGREGATE_CLASS (type)
-         && TREE_HAS_CONSTRUCTOR (init))
+      if (BRACE_ENCLOSED_INITIALIZER_P (init))
        {
-         error ("subobject of type `%T' must be initialized by constructor, not by `%E'",
-                   type, init);
-         return error_mark_node;
+         if (TYPE_NON_AGGREGATE_CLASS (type))
+           {
+             error ("subobject of type `%T' must be initialized by constructor, not by `%E'",
+                    type, init);
+             return error_mark_node;
+           }
+         return process_init_constructor (type, init, (tree *)0);
        }
-      else if (raw_constructor)
-       return process_init_constructor (type, init, (tree *)0);
       else if (can_convert_arg (type, TREE_TYPE (init), init)
               || TYPE_NON_AGGREGATE_CLASS (type))
        /* These are never initialized from multiple constructor elements.  */;
@@ -630,14 +821,13 @@ digest_init (type, init, tail)
    constants that the assembler and linker can compute them.  */
 
 static tree
-process_init_constructor (type, init, elts)
-     tree type, init, *elts;
+process_init_constructor (tree type, tree init, tree* elts)
 {
-  register tree tail;
+  tree tail;
   /* List of the elements of the result constructor,
      in reverse order.  */
-  register tree members = NULL;
-  register tree next1;
+  tree members = NULL;
+  tree next1;
   tree result;
   int allconstant = 1;
   int allsimple = 1;
@@ -661,8 +851,8 @@ process_init_constructor (type, init, elts)
 
   if (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == VECTOR_TYPE)
     {
-      register long len;
-      register int i;
+      long len;
+      int i;
 
       if (TREE_CODE (type) == ARRAY_TYPE)
        {
@@ -672,7 +862,7 @@ process_init_constructor (type, init, elts)
                   - TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain))
                   + 1);
          else
-           len = -1;  /* Take as many as there are */
+           len = -1;  /* Take as many as there are */
        }
       else
        {
@@ -696,12 +886,9 @@ process_init_constructor (type, init, elts)
                                       TREE_VALUE (tail), &tail1);
                  if (next1 == error_mark_node)
                    return next1;
-                 my_friendly_assert
-                   (same_type_ignoring_top_level_qualifiers_p
-                    (TREE_TYPE (type), TREE_TYPE (next1)),
-                    981123);
-                 my_friendly_assert (tail1 == 0
-                                     || TREE_CODE (tail1) == TREE_LIST, 319);
+                 gcc_assert (same_type_ignoring_top_level_qualifiers_p
+                             (TREE_TYPE (type), TREE_TYPE (next1)));
+                 gcc_assert (!tail1 || TREE_CODE (tail1) == TREE_LIST);
                  if (tail == tail1 && len < 0)
                    {
                      error ("non-empty initializer for array of empty elements");
@@ -729,9 +916,13 @@ process_init_constructor (type, init, elts)
              if (IS_AGGR_TYPE (TREE_TYPE (type)))
                next1 = build_functional_cast (TREE_TYPE (type), NULL_TREE);
              else
-               next1 = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, NULL_TREE);
+               next1 = build_constructor (NULL_TREE, NULL_TREE);
              next1 = digest_init (TREE_TYPE (type), next1, 0);
            }
+         else if (! zero_init_p (TREE_TYPE (type)))
+           next1 = build_zero_init (TREE_TYPE (type),
+                                    /*nelts=*/NULL_TREE,
+                                    /*static_storage_p=*/false);
          else
            /* The default zero-initialization is fine for us; don't
               add anything to the CONSTRUCTOR.  */
@@ -748,7 +939,7 @@ process_init_constructor (type, init, elts)
     }
   else if (TREE_CODE (type) == RECORD_TYPE)
     {
-      register tree field;
+      tree field;
 
       if (tail)
        {
@@ -758,7 +949,7 @@ process_init_constructor (type, init, elts)
              return error_mark_node;
            }
 
-         if (TYPE_BINFO_BASETYPES (type))
+         if (TYPE_BINFO (type) && BINFO_N_BASE_BINFOS (TYPE_BINFO (type)))
            {
              sorry ("initializer list for object of class with base classes");
              return error_mark_node;
@@ -780,7 +971,7 @@ process_init_constructor (type, init, elts)
              continue;
            }
 
-         if (TREE_CODE (field) != FIELD_DECL)
+         if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
            continue;
 
          if (tail)
@@ -796,8 +987,7 @@ process_init_constructor (type, init, elts)
 
                  next1 = digest_init (TREE_TYPE (field),
                                       TREE_VALUE (tail), &tail1);
-                 my_friendly_assert (tail1 == 0
-                                     || TREE_CODE (tail1) == TREE_LIST, 320);
+                 gcc_assert (!tail1 || TREE_CODE (tail1) == TREE_LIST);
                  tail = tail1;
                }
              else
@@ -818,8 +1008,7 @@ process_init_constructor (type, init, elts)
                                               NULL_TREE);
              else
                {
-                 next1 = build (CONSTRUCTOR, NULL_TREE, NULL_TREE,
-                                NULL_TREE);
+                 next1 = build_constructor (NULL_TREE, NULL_TREE);
                   if (init)
                     TREE_HAS_CONSTRUCTOR (next1)
                        = TREE_HAS_CONSTRUCTOR (init);
@@ -827,16 +1016,15 @@ process_init_constructor (type, init, elts)
              next1 = digest_init (TREE_TYPE (field), next1, 0);
 
              /* Warn when some struct elements are implicitly initialized.  */
-             if (extra_warnings
-                 && (!init || TREE_HAS_CONSTRUCTOR (init)))
+             if (warn_missing_field_initializers
+                 && (!init || BRACE_ENCLOSED_INITIALIZER_P (init)))
                warning ("missing initializer for member `%D'", field);
            }
          else
            {
              if (TREE_READONLY (field))
                error ("uninitialized const member `%D'", field);
-             else if (TYPE_LANG_SPECIFIC (TREE_TYPE (field))
-                      && CLASSTYPE_READONLY_FIELDS_NEED_INIT (TREE_TYPE (field)))
+             else if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (TREE_TYPE (field)))
                error ("member `%D' with uninitialized const fields",
                          field);
              else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE)
@@ -844,13 +1032,18 @@ process_init_constructor (type, init, elts)
 
              /* Warn when some struct elements are implicitly initialized
                 to zero.  */
-             if (extra_warnings
-                 && (!init || TREE_HAS_CONSTRUCTOR (init)))
+             if (warn_missing_field_initializers
+                 && (!init || BRACE_ENCLOSED_INITIALIZER_P (init)))
                warning ("missing initializer for member `%D'", field);
 
-             /* The default zero-initialization is fine for us; don't
-                add anything to the CONSTRUCTOR.  */
-             continue;
+             if (! zero_init_p (TREE_TYPE (field)))
+               next1 = build_zero_init (TREE_TYPE (field),
+                                        /*nelts=*/NULL_TREE,
+                                        /*static_storage_p=*/false);
+             else
+               /* The default zero-initialization is fine for us; don't
+                  add anything to the CONSTRUCTOR.  */
+               continue;
            }
 
          if (next1 == error_mark_node)
@@ -866,12 +1059,11 @@ process_init_constructor (type, init, elts)
           /* If the initializer was empty, use default zero initialization.  */
           && tail)
     {
-      register tree field = TYPE_FIELDS (type);
+      tree field = TYPE_FIELDS (type);
 
       /* Find the first named field.  ANSI decided in September 1990
         that only named fields count here.  */
-      while (field && (DECL_NAME (field) == 0
-                      || TREE_CODE (field) != FIELD_DECL))
+      while (field && (!DECL_NAME (field) || TREE_CODE (field) != FIELD_DECL))
        field = TREE_CHAIN (field);
 
       /* If this element specifies a field, initialize via that field.  */
@@ -914,8 +1106,7 @@ process_init_constructor (type, init, elts)
 
          next1 = digest_init (TREE_TYPE (field),
                               TREE_VALUE (tail), &tail1);
-         if (tail1 != 0 && TREE_CODE (tail1) != TREE_LIST)
-           abort ();
+         gcc_assert (!tail1 || TREE_CODE (tail1) == TREE_LIST);
          tail = tail1;
        }
       else
@@ -944,17 +1135,24 @@ process_init_constructor (type, init, elts)
   if (erroneous)
     return error_mark_node;
 
-  result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (members));
+  result = build_constructor (type, nreverse (members));
+  if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == NULL_TREE)
+    complete_array_type (type, result, /*do_default=*/0);
   if (init)
     TREE_HAS_CONSTRUCTOR (result) = TREE_HAS_CONSTRUCTOR (init);
-  if (allconstant) TREE_CONSTANT (result) = 1;
-  if (allconstant && allsimple) TREE_STATIC (result) = 1;
+  if (allconstant)
+    {
+      TREE_CONSTANT (result) = 1;
+      TREE_INVARIANT (result) = 1;
+      if (allsimple)
+       TREE_STATIC (result) = 1;
+    }
   return result;
 }
 \f
 /* Given a structure or union value DATUM, construct and return
    the structure or union component which results from narrowing
-   that value by the type specified in BASETYPE.  For example, given the
+   that value to the base specified in BASETYPE.  For example, given the
    hierarchy
 
    class L { int ii; };
@@ -975,29 +1173,33 @@ process_init_constructor (type, init, elts)
    I used to think that this was nonconformant, that the standard specified
    that first we look up ii in A, then convert x to an L& and pull out the
    ii part.  But in fact, it does say that we convert x to an A&; A here
-   is known as the "naming class".  (jason 2000-12-19) */
+   is known as the "naming class".  (jason 2000-12-19)
+
+   BINFO_P points to a variable initialized either to NULL_TREE or to the
+   binfo for the specific base subobject we want to convert to.  */
 
 tree
-build_scoped_ref (datum, basetype)
-     tree datum;
-     tree basetype;
+build_scoped_ref (tree datum, tree basetype, tree* binfo_p)
 {
-  tree ref;
   tree binfo;
 
   if (datum == error_mark_node)
     return error_mark_node;
-  binfo = lookup_base (TREE_TYPE (datum), basetype, ba_check, NULL);
+  if (*binfo_p)
+    binfo = *binfo_p;
+  else
+    binfo = lookup_base (TREE_TYPE (datum), basetype, ba_check, NULL);
 
-  if (binfo == error_mark_node)
-    return error_mark_node;
-  if (!binfo)
-    return error_not_base_type (TREE_TYPE (datum), basetype);
-  
-  ref = build_unary_op (ADDR_EXPR, datum, 0);
-  ref = build_base_path (PLUS_EXPR, ref, binfo, 1);
+  if (!binfo || binfo == error_mark_node)
+    {
+      *binfo_p = NULL_TREE;
+      if (!binfo)
+       error_not_base_type (basetype, TREE_TYPE (datum));
+      return error_mark_node;
+    }
 
-  return build_indirect_ref (ref, "(compiler error in build_scoped_ref)");
+  *binfo_p = binfo;
+  return build_base_path (PLUS_EXPR, datum, binfo, 1);
 }
 
 /* Build a reference to an object specified by the C++ `->' operator.
@@ -1008,51 +1210,49 @@ build_scoped_ref (datum, basetype)
    delegation is detected.  */
 
 tree
-build_x_arrow (datum)
-     tree datum;
+build_x_arrow (tree expr)
 {
+  tree orig_expr = expr;
   tree types_memoized = NULL_TREE;
-  register tree rval = datum;
-  tree type = TREE_TYPE (rval);
+  tree type = TREE_TYPE (expr);
   tree last_rval = NULL_TREE;
 
   if (type == error_mark_node)
     return error_mark_node;
 
   if (processing_template_decl)
-    return build_min_nt (ARROW_EXPR, rval);
-
-  if (TREE_CODE (rval) == OFFSET_REF)
     {
-      rval = resolve_offset_ref (datum);
-      type = TREE_TYPE (rval);
+      if (type_dependent_expression_p (expr))
+       return build_min_nt (ARROW_EXPR, expr);
+      expr = build_non_dependent_expr (expr);
     }
 
   if (TREE_CODE (type) == REFERENCE_TYPE)
     {
-      rval = convert_from_reference (rval);
-      type = TREE_TYPE (rval);
+      expr = convert_from_reference (expr);
+      type = TREE_TYPE (expr);
     }
 
   if (IS_AGGR_TYPE (type))
     {
-      while ((rval = build_opfncall (COMPONENT_REF, LOOKUP_NORMAL, rval,
-                                    NULL_TREE, NULL_TREE)))
+      while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr,
+                                  NULL_TREE, NULL_TREE,
+                                  /*overloaded_p=*/NULL)))
        {
-         if (rval == error_mark_node)
+         if (expr == error_mark_node)
            return error_mark_node;
 
-         if (value_member (TREE_TYPE (rval), types_memoized))
+         if (value_member (TREE_TYPE (expr), types_memoized))
            {
              error ("circular pointer delegation detected");
              return error_mark_node;
            }
          else
            {
-             types_memoized = tree_cons (NULL_TREE, TREE_TYPE (rval),
+             types_memoized = tree_cons (NULL_TREE, TREE_TYPE (expr),
                                          types_memoized);
            }
-         last_rval = rval;
+         last_rval = expr;
        }     
 
       if (last_rval == NULL_TREE)
@@ -1065,10 +1265,20 @@ build_x_arrow (datum)
        last_rval = convert_from_reference (last_rval);
     }
   else
-    last_rval = default_conversion (rval);
+    last_rval = decay_conversion (expr);
 
   if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE)
-    return build_indirect_ref (last_rval, NULL);
+    {
+      if (processing_template_decl)
+       {
+         expr = build_min_non_dep (ARROW_EXPR, last_rval, orig_expr);
+         /* It will be dereferenced.  */
+         TREE_TYPE (expr) = TREE_TYPE (TREE_TYPE (last_rval));
+         return expr;
+       }
+
+      return build_indirect_ref (last_rval, NULL);
+    }
 
   if (types_memoized)
     error ("result of `operator->()' yields non-pointer result");
@@ -1077,73 +1287,32 @@ build_x_arrow (datum)
   return error_mark_node;
 }
 
-/* Make an expression to refer to the COMPONENT field of
-   structure or union value DATUM.  COMPONENT is an arbitrary
-   expression.  DATUM has not already been checked out to be of
-   aggregate type.
-
-   For C++, COMPONENT may be a TREE_LIST.  This happens when we must
-   return an object of member type to a method of the current class,
-   but there is not yet enough typing information to know which one.
-   As a special case, if there is only one method by that name,
-   it is returned.  Otherwise we return an expression which other
-   routines will have to know how to deal with later.  */
+/* Return an expression for "DATUM .* COMPONENT".  DATUM has not
+   already been checked out to be of aggregate type.  */
 
 tree
-build_m_component_ref (datum, component)
-     tree datum, component;
+build_m_component_ref (tree datum, tree component)
 {
-  tree type;
+  tree ptrmem_type;
   tree objtype;
-  tree field_type;
-  int type_quals;
+  tree type;
   tree binfo;
-
-  if (processing_template_decl)
-    return build_min_nt (DOTSTAR_EXPR, datum, component);
+  tree ctype;
 
   datum = decay_conversion (datum);
 
   if (datum == error_mark_node || component == error_mark_node)
     return error_mark_node;
 
-  objtype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));  
-
-  if (TYPE_PTRMEMFUNC_P (TREE_TYPE (component)))
-    {
-      type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (component)));
-      field_type = type;
-    }
-  else if (TYPE_PTRMEM_P (TREE_TYPE (component)))
-    {
-      type = TREE_TYPE (TREE_TYPE (component));
-      field_type = TREE_TYPE (type);
-      
-      /* Compute the type of the field, as described in [expr.ref].  */
-      type_quals = TYPE_UNQUALIFIED;
-      if (TREE_CODE (field_type) == REFERENCE_TYPE)
-       /* The standard says that the type of the result should be the
-                  type referred to by the reference.  But for now, at least,
-                  we do the conversion from reference type later.  */
-       ;
-      else
-       {
-         type_quals = (cp_type_quals (field_type)  
-                       | cp_type_quals (TREE_TYPE (datum)));
-
-         /* There's no such thing as a mutable pointer-to-member, so
-            we don't need to deal with that here like we do in
-            build_component_ref.  */
-         field_type = cp_build_qualified_type (field_type, type_quals);
-       }
-    }
-  else
+  ptrmem_type = TREE_TYPE (component);
+  if (!TYPE_PTR_TO_MEMBER_P (ptrmem_type))
     {
       error ("`%E' cannot be used as a member pointer, since it is of type `%T'", 
-               component, TREE_TYPE (component));
+            component, ptrmem_type);
       return error_mark_node;
     }
-
+    
+  objtype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));  
   if (! IS_AGGR_TYPE (objtype))
     {
       error ("cannot apply member pointer `%E' to `%E', which is of non-aggregate type `%T'",
@@ -1151,29 +1320,60 @@ build_m_component_ref (datum, component)
       return error_mark_node;
     }
 
-  binfo = lookup_base (objtype, TYPE_METHOD_BASETYPE (type),
-                      ba_check, NULL);
-  if (!binfo)
+  type = TYPE_PTRMEM_POINTED_TO_TYPE (ptrmem_type);
+  ctype = complete_type (TYPE_PTRMEM_CLASS_TYPE (ptrmem_type));
+
+  if (!COMPLETE_TYPE_P (ctype))
     {
-      error ("member type `%T::' incompatible with object type `%T'",
-               TYPE_METHOD_BASETYPE (type), objtype);
-      return error_mark_node;
+      if (!same_type_p (ctype, objtype))
+       goto mismatch;
+      binfo = NULL;
+    }
+  else
+    {
+      binfo = lookup_base (objtype, ctype, ba_check, NULL);
+      
+      if (!binfo)
+       {
+       mismatch:
+         error ("pointer to member type `%T' incompatible with object type `%T'",
+                type, objtype);
+         return error_mark_node;
+       }
+      else if (binfo == error_mark_node)
+       return error_mark_node;
     }
-  else if (binfo == error_mark_node)
-    return error_mark_node;
 
-  component = build (OFFSET_REF, field_type, datum, component);
-  if (TREE_CODE (type) == OFFSET_TYPE)
-    component = resolve_offset_ref (component);
-  return component;
+  if (TYPE_PTRMEM_P (ptrmem_type))
+    {
+      /* Compute the type of the field, as described in [expr.ref].
+        There's no such thing as a mutable pointer-to-member, so
+        things are not as complex as they are for references to
+        non-static data members.  */
+      type = cp_build_qualified_type (type,
+                                     (cp_type_quals (type)  
+                                      | cp_type_quals (TREE_TYPE (datum))));
+
+      datum = build_address (datum);
+      
+      /* Convert object to the correct base.  */
+      if (binfo)
+       datum = build_base_path (PLUS_EXPR, datum, binfo, 1);
+      
+      /* Build an expression for "object + offset" where offset is the
+        value stored in the pointer-to-data-member.  */
+      datum = build2 (PLUS_EXPR, build_pointer_type (type),
+                     datum, build_nop (ptrdiff_type_node, component));
+      return build_indirect_ref (datum, 0);
+    }
+  else
+    return build2 (OFFSET_REF, type, datum, component);
 }
 
 /* Return a tree node for the expression TYPENAME '(' PARMS ')'.  */
 
 tree
-build_functional_cast (exp, parms)
-     tree exp;
-     tree parms;
+build_functional_cast (tree exp, tree parms)
 {
   /* This is either a call to a constructor,
      or a C cast in C++'s `functional' notation.  */
@@ -1182,41 +1382,26 @@ build_functional_cast (exp, parms)
   if (exp == error_mark_node || parms == error_mark_node)
     return error_mark_node;
 
-  if (TREE_CODE (exp) == IDENTIFIER_NODE)
-    {
-      if (IDENTIFIER_HAS_TYPE_VALUE (exp))
-       /* Either an enum or an aggregate type.  */
-       type = IDENTIFIER_TYPE_VALUE (exp);
-      else
-       {
-         type = lookup_name (exp, 1);
-         if (!type || TREE_CODE (type) != TYPE_DECL)
-           {
-             error ("`%T' fails to be a typedef or built-in type", exp);
-             return error_mark_node;
-           }
-         type = TREE_TYPE (type);
-       }
-    }
-  else if (TREE_CODE (exp) == TYPE_DECL)
+  if (TREE_CODE (exp) == TYPE_DECL)
     type = TREE_TYPE (exp);
   else
     type = exp;
 
   if (processing_template_decl)
-    return build_min (CAST_EXPR, type, parms);
+    {
+      tree t = build_min (CAST_EXPR, type, parms);
+      /* We don't know if it will or will not have side effects.  */
+      TREE_SIDE_EFFECTS (t) = 1;
+      return t;
+    }
 
   if (! IS_AGGR_TYPE (type))
     {
-      /* this must build a C cast */
+      /* This must build a C cast.  */
       if (parms == NULL_TREE)
        parms = integer_zero_node;
       else
-       {
-         if (TREE_CHAIN (parms) != NULL_TREE)
-           pedwarn ("initializer list being treated as compound expression");
-         parms = build_compound_expr (parms);
-       }
+       parms = build_x_compound_expr_from_list (parms, "functional cast");
 
       return build_c_cast (type, parms);
     }
@@ -1241,12 +1426,12 @@ build_functional_cast (exp, parms)
   if (parms == NULL_TREE && !TYPE_NEEDS_CONSTRUCTING (type)
       && TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
     {
-      exp = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+      exp = build_constructor (type, NULL_TREE);
       return get_target_expr (exp);
     }
 
-  exp = build_method_call (NULL_TREE, complete_ctor_identifier, parms,
-                          TYPE_BINFO (type), LOOKUP_NORMAL);
+  exp = build_special_member_call (NULL_TREE, complete_ctor_identifier, parms,
+                                  type, LOOKUP_NORMAL);
 
   if (exp == error_mark_node)
     return error_mark_node;
@@ -1255,37 +1440,23 @@ build_functional_cast (exp, parms)
 }
 \f
 
-/* Complain about defining new types in inappropriate places.  We give an
-   exception for C-style casts, to accommodate GNU C stylings.  */
-
-void
-check_for_new_type (string, inptree)
-     const char *string;
-     flagged_type_tree inptree;
-{
-  if (inptree.new_type_flag
-      && (pedantic || strcmp (string, "cast") != 0))
-    pedwarn ("ISO C++ forbids defining types within %s", string);
-}
-
 /* Add new exception specifier SPEC, to the LIST we currently have.
    If it's already in LIST then do nothing.
    Moan if it's bad and we're allowed to. COMPLAIN < 0 means we
    know what we're doing.  */
 
 tree
-add_exception_specifier (list, spec, complain)
-     tree list, spec;
-     int complain;
+add_exception_specifier (tree list, tree spec, int complain)
 {
-  int ok;
+  bool ok;
   tree core = spec;
-  int is_ptr;
+  bool is_ptr;
+  int diag_type = -1; /* none */
   
   if (spec == error_mark_node)
     return list;
   
-  my_friendly_assert (spec && (!list || TREE_VALUE (list)), 19990317);
+  gcc_assert (spec && (!list || TREE_VALUE (list)));
   
   /* [except.spec] 1, type in an exception specifier shall not be
      incomplete, or pointer or ref to incomplete other than pointer
@@ -1294,15 +1465,23 @@ add_exception_specifier (list, spec, complain)
   if (is_ptr || TREE_CODE (core) == REFERENCE_TYPE)
     core = TREE_TYPE (core);
   if (complain < 0)
-    ok = 1;
+    ok = true;
   else if (VOID_TYPE_P (core))
     ok = is_ptr;
   else if (TREE_CODE (core) == TEMPLATE_TYPE_PARM)
-    ok = 1;
+    ok = true;
   else if (processing_template_decl)
-    ok = 1;
+    ok = true;
   else
-    ok = COMPLETE_TYPE_P (complete_type (core));
+    {
+      ok = true;
+      /* 15.4/1 says that types in an exception specifier must be complete,
+         but it seems more reasonable to only require this on definitions
+         and calls.  So just give a pedwarn at this point; we will give an
+         error later if we hit one of those two cases.  */
+      if (!COMPLETE_TYPE_P (complete_type (core)))
+       diag_type = 2; /* pedwarn */
+    }
 
   if (ok)
     {
@@ -1312,23 +1491,22 @@ add_exception_specifier (list, spec, complain)
         if (same_type_p (TREE_VALUE (probe), spec))
           break;
       if (!probe)
-        {
-          spec = build_tree_list (NULL_TREE, spec);
-          TREE_CHAIN (spec) = list;
-          list = spec;
-        }
+       list = tree_cons (NULL_TREE, spec, list);
     }
-  else if (complain)
-    incomplete_type_error (NULL_TREE, core);
+  else
+    diag_type = 0; /* error */
+    
+  if (diag_type >= 0 && complain)
+    cxx_incomplete_type_diagnostic (NULL_TREE, core, diag_type);
+
   return list;
 }
 
 /* Combine the two exceptions specifier lists LIST and ADD, and return
-   their union. */
+   their union.  */
 
 tree
-merge_exception_specifiers (list, add)
-     tree list, add;
+merge_exception_specifiers (tree list, tree add)
 {
   if (!list || !add)
     return NULL_TREE;
@@ -1358,3 +1536,36 @@ merge_exception_specifiers (list, add)
     }
   return list;
 }
+
+/* Subroutine of build_call.  Ensure that each of the types in the
+   exception specification is complete.  Technically, 15.4/1 says that
+   they need to be complete when we see a declaration of the function,
+   but we should be able to get away with only requiring this when the
+   function is defined or called.  See also add_exception_specifier.  */
+
+void
+require_complete_eh_spec_types (tree fntype, tree decl)
+{
+  tree raises;
+  /* Don't complain about calls to op new.  */
+  if (decl && DECL_ARTIFICIAL (decl))
+    return;
+  for (raises = TYPE_RAISES_EXCEPTIONS (fntype); raises;
+       raises = TREE_CHAIN (raises))
+    {
+      tree type = TREE_VALUE (raises);
+      if (type && !COMPLETE_TYPE_P (type))
+       {
+         if (decl)
+           error
+             ("call to function `%D' which throws incomplete type `%#T'",
+              decl, type);
+         else
+           error ("call to function which throws incomplete type `%#T'",
+                  decl);
+       }
+    }
+}
+
+\f
+#include "gt-cp-typeck2.h"