OSDN Git Service

* class.c (build_base_path): Use build_address directly.
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck2.c
index e3614d7..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,51 +26,43 @@ 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"
 #include "toplev.h"
 #include "output.h"
+#include "diagnostic.h"
 
-static tree process_init_constructor PARAMS ((tree, tree, tree *));
-static void ack PARAMS ((const char *, ...)) ATTRIBUTE_PRINTF_1;
+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);
-  cp_error ("type `%T' is not a base type for type `%T'", basetype, type);
+  error ("type `%T' is not a base type for type `%T'", basetype, type);
   return error_mark_node;
 }
 
 tree
-binfo_or_else (parent_or_type, type)
-     tree parent_or_type, type;
+binfo_or_else (tree base, tree type)
 {
-  tree binfo;
-  if (TYPE_MAIN_VARIANT (parent_or_type) == TYPE_MAIN_VARIANT (type))
-    return TYPE_BINFO (parent_or_type);
-  if ((binfo = get_binfo (parent_or_type, TYPE_MAIN_VARIANT (type), 0)))
-    {
-      if (binfo == error_mark_node)
-       return NULL_TREE;
-      return binfo;
-    }
-  error_not_base_type (parent_or_type, type);
-  return NULL_TREE;
+  tree binfo = lookup_base (type, base, ba_ignore, NULL);
+
+  if (binfo == error_mark_node)
+    return NULL_TREE;
+  else if (!binfo)
+    error_not_base_type (base, type);
+  return binfo;
 }
 
 /* According to ARM $7.1.6, "A `const' object may be initialized, but its
@@ -78,18 +71,15 @@ binfo_or_else (parent_or_type, 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 = cp_pedwarn;
+    fn = pedwarn;
   else
-    fn = cp_error;
+    fn = error;
 
   if (TREE_CODE (arg) == COMPONENT_REF)
     {
@@ -124,20 +114,173 @@ 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))
+    /* TYPE is being defined, and during that time
+       CLASSTYPE_PURE_VIRTUALS holds the inline friends.  */
     return 0;
 
   u = CLASSTYPE_PURE_VIRTUALS (type);
@@ -147,52 +290,90 @@ abstract_virtuals_error (decl, type)
        return 0;
 
       if (TREE_CODE (decl) == VAR_DECL)
-       cp_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)
-       cp_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)
-       cp_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)
-       cp_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)
-       cp_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
-    cp_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 ("  since 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
-    cp_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;
 
-retry:
+  if (value != 0 && (TREE_CODE (value) == VAR_DECL
+                    || TREE_CODE (value) == PARM_DECL
+                    || TREE_CODE (value) == FIELD_DECL))
+    {
+      (*p_msg_at) ("`%D' has incomplete type", value);
+      decl = 1;
+    }
+ retry:
   /* We must print an error message.  Be clever about what it says.  */
 
   switch (TREE_CODE (type))
@@ -200,12 +381,16 @@ retry:
     case RECORD_TYPE:
     case UNION_TYPE:
     case ENUMERAL_TYPE:
-      cp_error ("invalid use of undefined type `%#T'", type);
-      cp_error_at ("forward declaration of `%#T'", type);
+      if (!decl)
+        (*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:
-      cp_error ("invalid use of void expression");
+      (*p_msg) ("invalid use of `%T'", type);
       break;
 
     case ARRAY_TYPE:
@@ -214,135 +399,144 @@ retry:
           type = TREE_TYPE (type);
           goto retry;
         }
-      cp_error ("invalid use of array with unspecified bounds");
+      (*p_msg) ("invalid use of array with unspecified bounds");
       break;
 
     case OFFSET_TYPE:
     bad_member:
-      cp_error ("invalid use of member (did you forget the `&' ?)");
+      (*p_msg) ("invalid use of member (did you forget the `&' ?)");
       break;
 
     case TEMPLATE_TYPE_PARM:
-      cp_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)
-        cp_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)
-        cp_error ("overloaded function with no contextual type information");
+        (*p_msg) ("overloaded function with no contextual type information");
       else
-        cp_error ("insufficient contextual information to determine type");
+        (*p_msg) ("insufficient contextual information to determine type");
       break;
     
     default:
-      my_friendly_abort (108);
+      gcc_unreachable ();
     }
+}
 
-  if (value != 0 && (TREE_CODE (value) == VAR_DECL
-                    || TREE_CODE (value) == PARM_DECL))
-    cp_error_at ("incomplete `%D' defined here", value);
+/* 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);
 }
 
-/* Like error(), but don't call report_error_function().  */
+\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
-ack VPARAMS ((const char *msg, ...))
+split_nonconstant_init_1 (tree dest, tree init)
 {
-#ifndef ANSI_PROTOTYPES
-  const char *msg;
-#endif
-  va_list ap;
-  
-  VA_START (ap, msg);
+  tree *pelt, elt, type = TREE_TYPE (dest);
+  tree sub, code, inner_type = NULL;
+  bool array_type_p = false;
 
-#ifndef ANSI_PROTOTYPES
-  msg = va_arg (ap, const char *);
-#endif
-  
-  if (input_filename)
-    fprintf (stderr, "%s:%d: ", input_filename, lineno);
-  else
-    fprintf (stderr, "%s: ", progname);
+  pelt = &CONSTRUCTOR_ELTS (init);
+  switch (TREE_CODE (type))
+    {
+    case ARRAY_TYPE:
+      inner_type = TREE_TYPE (type);
+      array_type_p = true;
+      /* FALLTHRU */
 
-  vfprintf (stderr, msg, ap);
-  va_end (ap);
-  
-  fprintf (stderr, "\n");
-}
-  
-/* There are times when the compiler can get very confused, confused
-   to the point of giving up by aborting, simply because of previous
-   input errors.  It is much better to have the user go back and
-   correct those errors first, and see if it makes us happier, than it
-   is to abort on him.  This is because when one has a 10,000 line
-   program, and the compiler comes back with ``core dump'', the user
-   is left not knowing even where to begin to fix things and no place
-   to even try and work around things.
-
-   The parameter is to uniquely identify the problem to the user, so
-   that they can say, I am having problem 59, and know that fix 7 will
-   probably solve their problem.  Or, we can document what problem
-   59 is, so they can understand how to work around it, should they
-   ever run into it.
-
-   We used to tell people to "fix the above error[s] and try recompiling
-   the program" via a call to fatal, but that message tended to look
-   silly.  So instead, we just do the equivalent of a call to fatal in the
-   same situation (call exit).
-
-   We used to assign sequential numbers for the aborts; now we use an
-   encoding of the date the abort was added, since that has more meaning
-   when we only see the error message.  */
-
-static int abortcount = 0;
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      while ((elt = *pelt))
+       {
+         tree field_index = TREE_PURPOSE (elt);
+         tree value = TREE_VALUE (elt);
 
-void
-my_friendly_abort (i)
-     int i;
-{
-  /* if the previous error came through here, i.e. report_error_function
-     ended up calling us again, don't just exit; we want a diagnostic of
-     some kind.  */
-  if (abortcount == 1)
-    current_function_decl = NULL_TREE;
-  else if (errorcount > 0 || sorrycount > 0)
-    {
-      if (abortcount > 1)
+         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))
        {
-         if (i == 0)
-           ack ("Internal compiler error.");
-         else
-           ack ("Internal compiler error %d.", i);
-         ack ("Please submit a full bug report.");
-         ack ("See %s for instructions.", GCCBUGURL);
+         CONSTRUCTOR_ELTS (init) = NULL;
+         code = build2 (MODIFY_EXPR, type, dest, init);
+         code = build_stmt (EXPR_STMT, code);
+         add_stmt (code);
        }
-      else
-       error ("confused by earlier errors, bailing out");
-      
-      exit (34);
+      break;
+
+    default:
+      gcc_unreachable ();
     }
-  ++abortcount;
+}
+
+/* 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 (i == 0)
-    error ("Internal compiler error.");
+  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
-    error ("Internal compiler error %d.", i);
+    code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init);
 
-  error ("Please submit a full bug report.");
-  fatal ("See %s for instructions.", GCCBUGURL);
+  return code;
 }
 
-void
-my_friendly_assert (cond, where)
-     int cond, where;
-{
-  if (cond == 0)
-    my_friendly_abort (where);
-}
-\f
 /* Perform appropriate conversions on the initial value of a variable,
    store it in the declaration DECL,
    and print any error messages that are appropriate.
@@ -358,15 +552,13 @@ my_friendly_assert (cond, where)
    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.  */
 
@@ -374,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)
-       my_friendly_abort (109);
+      gcc_assert (TYPE_HAS_TRIVIAL_INIT_REF (type)
+                 || TREE_CODE (init) == CONSTRUCTOR);
 
       if (TREE_CODE (init) == TREE_LIST)
        {
-         cp_error ("constructor syntax used, but no constructor declared for type `%T'", type);
-         init = build_nt (CONSTRUCTOR, NULL_TREE, nreverse (init));
+         error ("constructor syntax used, but no constructor declared for type `%T'", type);
+         init = build_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);
-             }
-       }
-#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)
        {
@@ -441,23 +590,13 @@ 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.  */
 
   /* Digest the specified initializer into an expression.  */
-
   value = digest_init (type, init, (tree *) 0);
 
   /* Store the expression if valid; else report error.  */
@@ -468,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 ("ANSI 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
@@ -504,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.
@@ -515,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.  */
@@ -538,16 +650,22 @@ digest_init (type, init, tail)
                                  && TREE_VALUE (init) == error_mark_node))
     return error_mark_node;
 
+  if (TREE_CODE (init) == ERROR_MARK)
+    /* __PRETTY_FUNCTION__'s initializer is a bogus expression inside
+       a template function. This gets substituted during instantiation.  */
+    return init;
+
+  /* We must strip the outermost array type when completing the type,
+     because the its bounds might be incomplete at the moment.  */
+  if (!complete_type_or_else (TREE_CODE (type) == ARRAY_TYPE
+                             ? TREE_TYPE (type) : type, NULL_TREE))
+    return error_mark_node;
+  
   /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
   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)
     {
@@ -573,11 +691,7 @@ digest_init (type, init, tail)
        }
 
       typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
-      if ((typ1 == char_type_node
-          || typ1 == signed_char_type_node
-          || typ1 == unsigned_char_type_node
-          || typ1 == unsigned_wchar_type_node
-          || typ1 == signed_wchar_type_node)
+      if (char_type_p (typ1)
          && ((init && TREE_CODE (init) == STRING_CST)
              || (element && TREE_CODE (element) == STRING_CST)))
        {
@@ -602,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
@@ -622,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)
            {
@@ -633,12 +746,12 @@ digest_init (type, init, tail)
            }
          init = element;
        }
-      while (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init))
+      while (BRACE_ENCLOSED_INITIALIZER_P (init))
        {
-         cp_pedwarn ("braces around scalar initializer for `%T'", type);
+         pedwarn ("braces around scalar initializer for `%T'", type);
          init = CONSTRUCTOR_ELTS (init);
          if (TREE_CHAIN (init))
-           cp_pedwarn ("ignoring extra initializers for `%T'", type);
+           pedwarn ("ignoring extra initializers for `%T'", type);
          init = TREE_VALUE (init);
        }
 
@@ -648,23 +761,25 @@ digest_init (type, init, tail)
 
   /* Come here only for records and arrays (and unions with constructors).  */
 
-  if (TYPE_SIZE (type) && ! TREE_CONSTANT (TYPE_SIZE (type)))
+  if (COMPLETE_TYPE_P (type) && ! TREE_CONSTANT (TYPE_SIZE (type)))
     {
-      cp_error ("variable-sized object of type `%T' may not be initialized",
+      error ("variable-sized object of type `%T' may not be initialized",
                type);
       return error_mark_node;
     }
 
-  if (code == ARRAY_TYPE || IS_AGGR_TYPE_CODE (code))
+  if (code == ARRAY_TYPE || code == VECTOR_TYPE || IS_AGGR_TYPE_CODE (code))
     {
-      if (raw_constructor && TYPE_NON_AGGREGATE_CLASS (type))
+      if (BRACE_ENCLOSED_INITIALIZER_P (init))
        {
-         cp_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.  */;
@@ -706,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;
@@ -735,18 +849,26 @@ process_init_constructor (type, init, elts)
      for each element of this aggregate.  Chain them together in result.
      If there are too few, use 0 for each scalar ultimate component.  */
 
-  if (TREE_CODE (type) == ARRAY_TYPE)
+  if (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == VECTOR_TYPE)
     {
-      tree domain = TYPE_DOMAIN (type);
-      register long len;
-      register int i;
-
-      if (domain)
-       len = (TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain))
-              - TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain))
-              + 1);
+      long len;
+      int i;
+
+      if (TREE_CODE (type) == ARRAY_TYPE)
+       {
+         tree domain = TYPE_DOMAIN (type);
+         if (domain)
+           len = (TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain))
+                  - TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain))
+                  + 1);
+         else
+           len = -1;  /* Take as many as there are.  */
+       }
       else
-       len = -1;  /* Take as many as there are */
+       {
+         /* Vectors are like simple fixed-size arrays.  */
+         len = TYPE_VECTOR_SUBPARTS (type);
+       }
 
       for (i = 0; len < 0 || i < len; i++)
        {
@@ -764,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_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)),
-                                 TYPE_MAIN_VARIANT (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");
@@ -797,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.  */
@@ -816,7 +939,7 @@ process_init_constructor (type, init, elts)
     }
   else if (TREE_CODE (type) == RECORD_TYPE)
     {
-      register tree field;
+      tree field;
 
       if (tail)
        {
@@ -826,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;
@@ -848,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)
@@ -864,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
@@ -885,33 +1007,43 @@ process_init_constructor (type, init, elts)
                next1 = build_functional_cast (TREE_TYPE (field),
                                               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);
+                }
              next1 = digest_init (TREE_TYPE (field), next1, 0);
 
              /* Warn when some struct elements are implicitly initialized.  */
-             if (extra_warnings)
-               cp_warning ("missing initializer for member `%D'", field);
+             if (warn_missing_field_initializers
+                 && (!init || BRACE_ENCLOSED_INITIALIZER_P (init)))
+               warning ("missing initializer for member `%D'", field);
            }
          else
            {
              if (TREE_READONLY (field))
-               cp_error ("uninitialized const member `%D'", field);
-             else if (TYPE_LANG_SPECIFIC (TREE_TYPE (field))
-                      && CLASSTYPE_READONLY_FIELDS_NEED_INIT (TREE_TYPE (field)))
-               cp_error ("member `%D' with uninitialized const fields",
+               error ("uninitialized const member `%D'", 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)
-               cp_error ("member `%D' is uninitialized reference", field);
+               error ("member `%D' is uninitialized reference", field);
 
              /* Warn when some struct elements are implicitly initialized
                 to zero.  */
-             if (extra_warnings)
-               cp_warning ("missing initializer for member `%D'", field);
-
-             /* The default zero-initialization is fine for us; don't
-                add anything to the CONSTRUCTOR.  */
-             continue;
+             if (warn_missing_field_initializers
+                 && (!init || BRACE_ENCLOSED_INITIALIZER_P (init)))
+               warning ("missing initializer for member `%D'", field);
+
+             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)
@@ -927,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.  */
@@ -956,7 +1087,7 @@ process_init_constructor (type, init, elts)
              if (temp)
                field = temp, win = 1;
              else
-               cp_error ("no field `%D' in union being initialized",
+               error ("no field `%D' in union being initialized",
                          TREE_PURPOSE (tail));
            }
          if (!win)
@@ -964,7 +1095,7 @@ process_init_constructor (type, init, elts)
        }
       else if (field == 0)
        {
-         cp_error ("union `%T' with no named members cannot be initialized",
+         error ("union `%T' with no named members cannot be initialized",
                    type);
          TREE_VALUE (tail) = error_mark_node;
        }
@@ -975,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)
-           my_friendly_abort (357);
+         gcc_assert (!tail1 || TREE_CODE (tail1) == TREE_LIST);
          tail = tail1;
        }
       else
@@ -1005,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; };
@@ -1033,30 +1170,36 @@ process_init_constructor (type, init, elts)
    the A part of the C object named by X.  In this case,
    DATUM would be x, and BASETYPE would be A.
 
-   Note that this is nonconformant; the standard specifies that first
-   we look up ii in A, then convert x to an L& and pull out the ii part.
-   But narrowing seems to be standard practice, so let's do it anyway.  */
+   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)
+
+   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 type = TREE_TYPE (datum);
+  tree binfo;
 
   if (datum == error_mark_node)
     return error_mark_node;
+  if (*binfo_p)
+    binfo = *binfo_p;
+  else
+    binfo = lookup_base (TREE_TYPE (datum), basetype, ba_check, NULL);
 
-  /* Don't do this if it would cause an error or if we're being pedantic.  */
-  if (! ACCESSIBLY_UNIQUELY_DERIVED_P (basetype, type)
-      || pedantic)
-    return datum;
-
-  ref = build_unary_op (ADDR_EXPR, datum, 0);
-  ref = convert_pointer_to (basetype, ref);
+  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.
@@ -1067,56 +1210,54 @@ 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)
        {
-         cp_error ("base operand of `->' has non-pointer type `%T'", type);
+         error ("base operand of `->' has non-pointer type `%T'", type);
          return error_mark_node;
        }
 
@@ -1124,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_PTR);
+    {
+      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");
@@ -1136,83 +1287,93 @@ 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 ptrmem_type;
+  tree objtype;
   tree type;
-  tree objtype = TREE_TYPE (datum);
-  tree rettype;
   tree binfo;
+  tree ctype;
 
-  if (processing_template_decl)
-    return build_min_nt (DOTSTAR_EXPR, datum, component);
-
-  if (TYPE_PTRMEMFUNC_P (TREE_TYPE (component)))
-    {
-      type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (component)));
-      rettype = type;
-    }
-  else
-    {
-      type = TREE_TYPE (TREE_TYPE (component));
-      rettype = TREE_TYPE (type);
-    }
+  datum = decay_conversion (datum);
 
   if (datum == error_mark_node || component == error_mark_node)
     return error_mark_node;
 
-  if (TREE_CODE (type) != OFFSET_TYPE && TREE_CODE (type) != METHOD_TYPE)
+  ptrmem_type = TREE_TYPE (component);
+  if (!TYPE_PTR_TO_MEMBER_P (ptrmem_type))
     {
-      cp_error ("`%E' cannot be used as a member pointer, since it is of type `%T'", component, type);
+      error ("`%E' cannot be used as a member pointer, since it is of type `%T'", 
+            component, ptrmem_type);
       return error_mark_node;
     }
-
-  if (TREE_CODE (objtype) == REFERENCE_TYPE)
-    objtype = TREE_TYPE (objtype);
-  objtype = TYPE_MAIN_VARIANT (objtype);
-
+    
+  objtype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));  
   if (! IS_AGGR_TYPE (objtype))
     {
-      cp_error ("cannot apply member pointer `%E' to `%E'", component, datum);
-      cp_error ("which is of non-aggregate type `%T'", objtype);
+      error ("cannot apply member pointer `%E' to `%E', which is of non-aggregate type `%T'",
+               component, datum, objtype);
       return error_mark_node;
     }
 
-  binfo = get_binfo (TYPE_METHOD_BASETYPE (type), objtype, 1);
-  if (binfo == NULL_TREE)
+  type = TYPE_PTRMEM_POINTED_TO_TYPE (ptrmem_type);
+  ctype = complete_type (TYPE_PTRMEM_CLASS_TYPE (ptrmem_type));
+
+  if (!COMPLETE_TYPE_P (ctype))
     {
-      cp_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, rettype, 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.  */
@@ -1221,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)
-           {
-             cp_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);
     }
@@ -1267,11 +1413,8 @@ build_functional_cast (exp, parms)
         
      then the slot being initialized will be filled in.  */
 
-  if (TYPE_SIZE (complete_type (type)) == NULL_TREE)
-    {
-      cp_error ("type `%T' is not yet defined", type);
-      return error_mark_node;
-    }
+  if (!complete_type_or_else (type, NULL_TREE))
+    return error_mark_node;
   if (abstract_virtuals_error (NULL_TREE, type))
     return error_mark_node;
 
@@ -1283,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, 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;
@@ -1296,151 +1439,6 @@ build_functional_cast (exp, parms)
   return build_cplus_new (type, exp);
 }
 \f
-/* Return the character string for the name that encodes the
-   enumeral value VALUE in the domain TYPE.  */
-
-char *
-enum_name_string (value, type)
-     tree value;
-     tree type;
-{
-  register tree values = TYPE_VALUES (type);
-
-  my_friendly_assert (TREE_CODE (type) == ENUMERAL_TYPE, 324);
-
-  while (values && ! tree_int_cst_equal (TREE_VALUE (values), value))
-    values = TREE_CHAIN (values);
-
-  if (values == NULL_TREE)
-    {
-      char *buf = (char *) oballoc (16 + TYPE_NAME_LENGTH (type));
-
-      /* Value must have been cast.  */
-      sprintf (buf, "(enum %s)%ld",
-              TYPE_NAME_STRING (type), (long) TREE_INT_CST_LOW (value));
-      return buf;
-    }
-  return IDENTIFIER_POINTER (TREE_PURPOSE (values));
-}
-
-#if 0
-/* Print out a language-specific error message for
-   (Pascal) case or (C) switch statements.
-   CODE tells what sort of message to print. 
-   TYPE is the type of the switch index expression.
-   NEW is the new value that we were trying to add.
-   OLD is the old value that stopped us from adding it.  */
-
-void
-report_case_error (code, type, new_value, old_value)
-     int code;
-     tree type;
-     tree new_value, old_value;
-{
-  if (code == 1)
-    {
-      if (new_value)
-       error ("case label not within a switch statement");
-      else
-       error ("default label not within a switch statement");
-    }
-  else if (code == 2)
-    {
-      if (new_value == 0)
-       {
-         error ("multiple default labels in one switch");
-         return;
-       }
-      if (TREE_CODE (new_value) == RANGE_EXPR)
-       if (TREE_CODE (old_value) == RANGE_EXPR)
-         {
-           char *buf = (char *)alloca (4 * (8 + TYPE_NAME_LENGTH (type)));
-           if (TREE_CODE (type) == ENUMERAL_TYPE)
-             sprintf (buf, "overlapping ranges [%s..%s], [%s..%s] in case expression",
-                      enum_name_string (TREE_OPERAND (new_value, 0), type),
-                      enum_name_string (TREE_OPERAND (new_value, 1), type),
-                      enum_name_string (TREE_OPERAND (old_value, 0), type),
-                      enum_name_string (TREE_OPERAND (old_value, 1), type));
-           else
-             sprintf (buf, "overlapping ranges [%d..%d], [%d..%d] in case expression",
-                      TREE_INT_CST_LOW (TREE_OPERAND (new_value, 0)),
-                      TREE_INT_CST_LOW (TREE_OPERAND (new_value, 1)),
-                      TREE_INT_CST_LOW (TREE_OPERAND (old_value, 0)),
-                      TREE_INT_CST_LOW (TREE_OPERAND (old_value, 1)));
-           error (buf);
-         }
-       else
-         {
-           char *buf = (char *)alloca (4 * (8 + TYPE_NAME_LENGTH (type)));
-           if (TREE_CODE (type) == ENUMERAL_TYPE)
-             sprintf (buf, "range [%s..%s] includes element `%s' in case expression",
-                      enum_name_string (TREE_OPERAND (new_value, 0), type),
-                      enum_name_string (TREE_OPERAND (new_value, 1), type),
-                      enum_name_string (old_value, type));
-           else
-             sprintf (buf, "range [%d..%d] includes (%d) in case expression",
-                      TREE_INT_CST_LOW (TREE_OPERAND (new_value, 0)),
-                      TREE_INT_CST_LOW (TREE_OPERAND (new_value, 1)),
-                      TREE_INT_CST_LOW (old_value));
-           error (buf);
-         }
-      else if (TREE_CODE (old_value) == RANGE_EXPR)
-       {
-         char *buf = (char *)alloca (4 * (8 + TYPE_NAME_LENGTH (type)));
-         if (TREE_CODE (type) == ENUMERAL_TYPE)
-           sprintf (buf, "range [%s..%s] includes element `%s' in case expression",
-                    enum_name_string (TREE_OPERAND (old_value, 0), type),
-                    enum_name_string (TREE_OPERAND (old_value, 1), type),
-                    enum_name_string (new_value, type));
-         else
-           sprintf (buf, "range [%d..%d] includes (%d) in case expression",
-                    TREE_INT_CST_LOW (TREE_OPERAND (old_value, 0)),
-                    TREE_INT_CST_LOW (TREE_OPERAND (old_value, 1)),
-                    TREE_INT_CST_LOW (new_value));
-         error (buf);
-       }
-      else
-       {
-         if (TREE_CODE (type) == ENUMERAL_TYPE)
-           error ("duplicate label `%s' in switch statement",
-                  enum_name_string (new_value, type));
-         else
-           error ("duplicate label (%d) in switch statement",
-                  TREE_INT_CST_LOW (new_value));
-       }
-    }
-  else if (code == 3)
-    {
-      if (TREE_CODE (type) == ENUMERAL_TYPE)
-       warning ("case value out of range for enum %s",
-                TYPE_NAME_STRING (type));
-      else
-       warning ("case value out of range");
-    }
-  else if (code == 4)
-    {
-      if (TREE_CODE (type) == ENUMERAL_TYPE)
-       error ("range values `%s' and `%s' reversed",
-              enum_name_string (new_value, type),
-              enum_name_string (old_value, type));
-      else
-       error ("range values reversed");
-    }
-}
-#endif
-
-/* 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.
@@ -1448,18 +1446,17 @@ check_for_new_type (string, inptree)
    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
@@ -1468,14 +1465,24 @@ add_exception_specifier (list, spec, complain)
   if (is_ptr || TREE_CODE (core) == REFERENCE_TYPE)
     core = TREE_TYPE (core);
   if (complain < 0)
-    ok = 1;
-  else if (TYPE_MAIN_VARIANT (core) == void_type_node)
+    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 = true;
   else
-    ok = TYPE_SIZE (complete_type (core)) != NULL_TREE;
-  
+    {
+      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)
     {
       tree probe;
@@ -1484,13 +1491,81 @@ add_exception_specifier (list, spec, complain)
         if (same_type_p (TREE_VALUE (probe), spec))
           break;
       if (!probe)
+       list = tree_cons (NULL_TREE, spec, list);
+    }
+  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.  */
+
+tree
+merge_exception_specifiers (tree list, tree add)
+{
+  if (!list || !add)
+    return NULL_TREE;
+  else if (!TREE_VALUE (list))
+    return add;
+  else if (!TREE_VALUE (add))
+    return list;
+  else
+    {
+      tree orig_list = list;
+      
+      for (; add; add = TREE_CHAIN (add))
         {
-          spec = build_decl_list (NULL_TREE, spec);
-          TREE_CHAIN (spec) = list;
-          list = spec;
+          tree spec = TREE_VALUE (add);
+          tree probe;
+          
+          for (probe = orig_list; probe; probe = TREE_CHAIN (probe))
+            if (same_type_p (TREE_VALUE (probe), spec))
+              break;
+          if (!probe)
+            {
+              spec = build_tree_list (NULL_TREE, spec);
+              TREE_CHAIN (spec) = list;
+              list = spec;
+            }
         }
     }
-  else if (complain)
-    incomplete_type_error (NULL_TREE, core);
   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"