OSDN Git Service

2004-06-09 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck2.c
index 1e7c402..2c6b843 100644 (file)
@@ -1,22 +1,24 @@
 /* Report error messages, build initializers, and perform
    some front-end optimizations for C++ compiler.
-   Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   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.  */
 
@@ -32,42 +34,39 @@ Boston, MA 02111-1307, USA.  */
 
 #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 PROTO((tree, tree, tree *));
-static void ack PVPROTO ((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_CLASS_CONTEXT (basetype);
-  cp_error ("type `%T' is not a base type for type `%T'", basetype, type);
+    basetype = DECL_CONTEXT (basetype);
+  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
@@ -76,25 +75,22 @@ 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) PVPROTO ((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)
     {
       if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
-        fmt = "%s of member `%D' in read-only structure";
+        fmt = "%s of data-member `%D' in read-only structure";
       else
-        fmt = "%s of read-only member `%D'";
+        fmt = "%s of read-only data-member `%D'";
       (*fn) (fmt, string, TREE_OPERAND (arg, 1));
     }
   else if (TREE_CODE (arg) == VAR_DECL)
@@ -128,68 +124,103 @@ readonly_error (arg, string, soft)
    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_ABSTRACT_VIRTUALS (type))
+  if (!CLASS_TYPE_P (type) || !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_ABSTRACT_VIRTUALS (type);
+  if (dependent_type_p (type))
+    /* For a dependent type, we do not yet know which functions are pure
+       virtuals.  */
+    return 0;
+
+  u = CLASSTYPE_PURE_VIRTUALS (type);
   if (decl)
     {
       if (TREE_CODE (decl) == RESULT_DECL)
        return 0;
 
       if (TREE_CODE (decl) == VAR_DECL)
-       cp_error ("cannot declare variable `%D' to be of type `%T'",
+       error ("cannot declare variable `%D' to be of type `%T'",
                    decl, type);
       else if (TREE_CODE (decl) == PARM_DECL)
-       cp_error ("cannot declare parameter `%D' to be of type `%T'",
+       error ("cannot declare parameter `%D' to be of type `%T'",
                    decl, type);
       else if (TREE_CODE (decl) == FIELD_DECL)
-       cp_error ("cannot declare field `%D' to be of type `%T'",
+       error ("cannot declare field `%D' to be of type `%T'",
                    decl, type);
       else if (TREE_CODE (decl) == FUNCTION_DECL
               && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
-       cp_error ("invalid return type for method `%#D'", decl);
+       error ("invalid return type for member function `%#D'", decl);
       else if (TREE_CODE (decl) == FUNCTION_DECL)
-       cp_error ("invalid return type for function `%#D'", decl);
+       error ("invalid return type for function `%#D'", decl);
     }
   else
-    cp_error ("cannot allocate an object of type `%T'", type);
+    error ("cannot allocate an object of 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:");
+      error ("  because the following virtual functions are abstract:");
       for (tu = u; tu; tu = TREE_CHAIN (tu))
        cp_error_at ("\t%#D", TREE_VALUE (tu));
     }
   else
-    cp_error ("  since type `%T' has abstract virtual functions", type);
+    error ("  since type `%T' has abstract virtual functions", 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) == 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.  */
 
@@ -198,12 +229,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:
@@ -212,136 +247,147 @@ 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);
+      abort ();
     }
-
-  if (value != 0 && (TREE_CODE (value) == VAR_DECL
-                    || TREE_CODE (value) == PARM_DECL))
-    cp_error_at ("incomplete `%D' defined here", value);
 }
 
-/* Like error(), but don't call report_error_function().  */
-
-static void
-ack VPROTO ((const char *msg, ...))
+/* 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)
 {
-#ifndef ANSI_PROTOTYPES
-  const char *msg;
-#endif
-  va_list ap;
-  extern char * progname;
-  
-  VA_START (ap, msg);
-
-#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);
-
-  vfprintf (stderr, msg, ap);
-  va_end (ap);
-  
-  fprintf (stderr, "\n");
+  cxx_incomplete_type_diagnostic (value, type, 0);
 }
-  
-/* 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;
 
-void
-my_friendly_abort (i)
-     int i;
+\f
+/* The recursive part of split_nonconstant_init.  DEST is an lvalue
+   expression to which INIT should be assigned.  INIT is a CONSTRUCTOR.
+   PCODE is a pointer to the tail of a chain of statements being emitted.
+   The return value is the new tail of that chain after new statements
+   are generated.  */
+
+static tree *
+split_nonconstant_init_1 (tree dest, tree init, tree *pcode)
 {
-  /* 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)
+  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))
     {
-      if (abortcount > 1)
+    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))
        {
-         if (i == 0)
-           ack ("Internal compiler error.");
-         else
-           ack ("Internal compiler error %d.", i);
-         ack ("Please submit a full bug report.");
-         ack ("See <URL:http://www.gnu.org/software/gcc/faq.html#bugreport> for instructions.");
+         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 = build (ARRAY_REF, inner_type, dest, field_index);
+             else
+               sub = build (COMPONENT_REF, inner_type, dest, field_index);
+
+             pcode = split_nonconstant_init_1 (sub, value, pcode);
+           }
+         else if (!initializer_constant_valid_p (value, inner_type))
+           {
+             *pelt = TREE_CHAIN (elt);
+
+             if (array_type_p)
+               sub = build (ARRAY_REF, inner_type, dest, field_index);
+             else
+               sub = build (COMPONENT_REF, inner_type, dest, field_index);
+
+             code = build (MODIFY_EXPR, inner_type, sub, value);
+             code = build_stmt (EXPR_STMT, code);
+
+             *pcode = code;
+             pcode = &TREE_CHAIN (code);
+             continue;
+           }
+         pelt = &TREE_CHAIN (elt);
        }
-      else
-       error ("confused by earlier errors, bailing out");
-      
-      exit (34);
-    }
-  ++abortcount;
+      break;
 
-  if (i == 0)
-    error ("Internal compiler error.");
-  else
-    error ("Internal compiler error %d.", i);
+    case VECTOR_TYPE:
+      if (!initializer_constant_valid_p (init, type))
+       {
+         CONSTRUCTOR_ELTS (init) = NULL;
+         code = build (MODIFY_EXPR, type, dest, init);
+         code = build_stmt (EXPR_STMT, code);
+         pcode = &TREE_CHAIN (code);
+       }
+      break;
+
+    default:
+      abort ();
+    }
 
-  error ("Please submit a full bug report.");
-  fatal ("See <URL:http://www.gnu.org/software/gcc/faq.html#bugreport> for instructions.");
+  return pcode;
 }
 
-void
-my_friendly_assert (cond, where)
-     int cond, where;
+/* 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)
 {
-  if (cond == 0)
-    my_friendly_abort (where);
+  tree code;
+
+  if (TREE_CODE (init) == CONSTRUCTOR)
+    {
+      code = build_stmt (COMPOUND_STMT, NULL_TREE);
+      split_nonconstant_init_1 (dest, init, &COMPOUND_BODY (code));
+      code = build1 (STMT_EXPR, void_type_node, code);
+      TREE_SIDE_EFFECTS (code) = 1;
+      DECL_INITIAL (dest) = init;
+      TREE_READONLY (dest) = 0;
+    }
+  else
+    code = build (INIT_EXPR, TREE_TYPE (dest), dest, init);
+
+  return code;
 }
-\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.
@@ -357,15 +403,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.  */
 
@@ -373,66 +417,24 @@ 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);
+       abort ();
 
       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));
-       }
-#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);
-             }
+         error ("constructor syntax used, but no constructor declared for type `%T'", type);
+         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)
        {
@@ -440,23 +442,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.  */
@@ -467,38 +459,19 @@ 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 build (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
+              || ! 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
+     when we output this function.  */
   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.
@@ -510,15 +483,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.  */
@@ -533,16 +502,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)
     {
@@ -568,11 +543,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)))
        {
@@ -597,8 +568,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
@@ -617,9 +587,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)
            {
@@ -628,12 +598,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);
        }
 
@@ -643,23 +613,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.  */;
@@ -701,14 +673,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;
@@ -730,18 +701,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++)
        {
@@ -749,7 +728,7 @@ process_init_constructor (type, init, elts)
            {
              if (TREE_PURPOSE (tail)
                  && (TREE_CODE (TREE_PURPOSE (tail)) != INTEGER_CST
-                     || TREE_INT_CST_LOW (TREE_PURPOSE (tail)) != i))
+                     || compare_tree_int (TREE_PURPOSE (tail), i) != 0))
                sorry ("non-trivial labeled initializers");
 
              if (TREE_VALUE (tail) != 0)
@@ -760,8 +739,8 @@ process_init_constructor (type, init, elts)
                  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))),
+                   (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);
@@ -792,9 +771,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.  */
@@ -806,28 +789,28 @@ process_init_constructor (type, init, elts)
            allconstant = 0;
          else if (! initializer_constant_valid_p (next1, TREE_TYPE (next1)))
            allsimple = 0;
-         members = expr_tree_cons (NULL_TREE, next1, members);
+         members = tree_cons (size_int (i), next1, members);
        }
     }
   else if (TREE_CODE (type) == RECORD_TYPE)
     {
-      register tree field;
+      tree field;
 
       if (tail)
        {
          if (TYPE_USES_VIRTUAL_BASECLASSES (type))
            {
-             sorry ("initializer list for object of class with virtual baseclasses");
+             sorry ("initializer list for object of class with virtual base classes");
              return error_mark_node;
            }
 
          if (TYPE_BINFO_BASETYPES (type))
            {
-             sorry ("initializer list for object of class with baseclasses");
+             sorry ("initializer list for object of class with base classes");
              return error_mark_node;
            }
 
-         if (TYPE_VIRTUAL_P (type))
+         if (TYPE_POLYMORPHIC_P (type))
            {
              sorry ("initializer list for object using virtual functions");
              return error_mark_node;
@@ -839,11 +822,11 @@ process_init_constructor (type, init, elts)
        {
          if (! DECL_NAME (field) && DECL_C_BIT_FIELD (field))
            {
-             members = expr_tree_cons (field, integer_zero_node, members);
+             members = tree_cons (field, integer_zero_node, members);
              continue;
            }
 
-         if (TREE_CODE (field) != FIELD_DECL)
+         if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
            continue;
 
          if (tail)
@@ -880,33 +863,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 (extra_warnings
+                 && (!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 (extra_warnings
+                 && (!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)
@@ -915,17 +908,18 @@ process_init_constructor (type, init, elts)
            allconstant = 0;
          else if (! initializer_constant_valid_p (next1, TREE_TYPE (next1)))
            allsimple = 0;
-         members = expr_tree_cons (field, next1, members);
+         members = tree_cons (field, next1, members);
        }
     }
-  else if (TREE_CODE (type) == UNION_TYPE)
+  else if (TREE_CODE (type) == UNION_TYPE
+          /* 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.  */
@@ -949,7 +943,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)
@@ -957,7 +951,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;
        }
@@ -969,7 +963,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);
+           abort ();
          tail = tail1;
        }
       else
@@ -984,7 +978,7 @@ process_init_constructor (type, init, elts)
        allconstant = 0;
       else if (initializer_constant_valid_p (next1, TREE_TYPE (next1)) == 0)
        allsimple = 0;
-      members = expr_tree_cons (field, next1, members);
+      members = tree_cons (field, next1, members);
     }
 
   /* If arguments were specified as a list, just remove the ones we used.  */
@@ -998,17 +992,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; };
@@ -1024,56 +1025,38 @@ process_init_constructor (type, init, elts)
 
    x.A::ii refers to the ii member of the L part of
    the A part of the C object named by X.  In this case,
-   DATUM would be x, and BASETYPE would be A.  */
+   DATUM would be x, and BASETYPE would be A.
+
+   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);
 
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
-
-  type = TYPE_MAIN_VARIANT (type);
-
-  /* This is an easy conversion.  */
-  if (is_aggr_type (basetype, 1))
+  if (!binfo || binfo == error_mark_node)
     {
-      tree binfo = TYPE_BINFO (basetype);
-      if (binfo != TYPE_BINFO (type))
-       {
-         binfo = get_binfo (binfo, type, 1);
-         if (binfo == error_mark_node)
-           return error_mark_node;
-         if (binfo == 0)
-           return error_not_base_type (basetype, type);
-       }
-
-      switch (TREE_CODE (datum))
-       {
-       case NOP_EXPR:
-       case CONVERT_EXPR:
-       case FLOAT_EXPR:
-       case FIX_TRUNC_EXPR:
-       case FIX_FLOOR_EXPR:
-       case FIX_ROUND_EXPR:
-       case FIX_CEIL_EXPR:
-         ref = convert_pointer_to (binfo,
-                                   build_unary_op (ADDR_EXPR, TREE_OPERAND (datum, 0), 0));
-         break;
-       default:
-         ref = convert_pointer_to (binfo,
-                                   build_unary_op (ADDR_EXPR, datum, 0));
-       }
-      return build_indirect_ref (ref, "(compiler error in build_scoped_ref)");
+      *binfo_p = NULL_TREE;
+      if (!binfo)
+       error_not_base_type (basetype, TREE_TYPE (datum));
+      return error_mark_node;
     }
-  return error_mark_node;
+
+  *binfo_p = binfo;
+  return build_base_path (PLUS_EXPR, datum, binfo, 1);
 }
 
 /* Build a reference to an object specified by the C++ `->' operator.
@@ -1084,56 +1067,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;
        }
 
@@ -1141,10 +1122,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");
@@ -1153,83 +1144,75 @@ 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;
 
-  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);
+  binfo = lookup_base (objtype, TYPE_PTRMEM_CLASS_TYPE (ptrmem_type),
+                      ba_check, NULL);
+  if (!binfo)
     {
-      cp_error ("member type `%T::' incompatible with object type `%T'",
-               TYPE_METHOD_BASETYPE (type), objtype);
+      error ("member type `%T::' incompatible with object type `%T'",
+            type, objtype);
       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))));
+      /* Build an expression for "object + offset" where offset is the
+        value stored in the pointer-to-data-member.  */
+      datum = build (PLUS_EXPR, build_pointer_type (type),
+                    build_base_path (PLUS_EXPR, build_address (datum), 
+                                     binfo, 1),
+                    build_nop (ptrdiff_type_node, component));
+      return build_indirect_ref (datum, 0);
+    }
+  else
+    return build (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.  */
@@ -1238,41 +1221,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);
     }
@@ -1284,11 +1252,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;
 
@@ -1300,12 +1265,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_BINFO (type), LOOKUP_NORMAL);
 
   if (exp == error_mark_node)
     return error_mark_node;
@@ -1313,151 +1278,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);
-  register HOST_WIDE_INT intval = TREE_INT_CST_LOW (value);
-
-  my_friendly_assert (TREE_CODE (type) == ENUMERAL_TYPE, 324);
-  while (values
-        && TREE_INT_CST_LOW (TREE_VALUE (values)) != intval)
-    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) intval);
-      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 ("ANSI 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.
@@ -1465,13 +1285,12 @@ 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;
@@ -1485,14 +1304,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;
@@ -1501,13 +1330,78 @@ 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);
+       }
+    }
+}