]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/cp/typeck2.c
typeck2.c (add_exception_specifier): Only require complete type if not in processing...
[gcc.git] / gcc / cp / typeck2.c
index f7b34c3efbc0079ecc5357da4f9e8220ab341b2a..5ba46111cc06a4bf3bf0ebd16f3be800552f24be 100644 (file)
@@ -1,6 +1,7 @@
 /* Report error messages, build initializers, and perform
    some front-end optimizations for C++ compiler.
-   Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -36,11 +37,10 @@ Boston, MA 02111-1307, USA.  */
 #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 *));
-
-extern int errorcount;
-extern int sorrycount;
+static tree process_init_constructor PARAMS ((tree, tree, tree *));
 
 /* Print an error message stemming from an attempt to use
    BASETYPE as a base class for TYPE.  */
@@ -50,7 +50,7 @@ error_not_base_type (basetype, type)
      tree basetype, type;
 {
   if (TREE_CODE (basetype) == FUNCTION_DECL)
-    basetype = DECL_CLASS_CONTEXT (basetype);
+    basetype = DECL_CONTEXT (basetype);
   cp_error ("type `%T' is not a base type for type `%T'", basetype, type);
   return error_mark_node;
 }
@@ -80,11 +80,11 @@ binfo_or_else (parent_or_type, type)
 void
 readonly_error (arg, string, soft)
      tree arg;
-     char *string;
+     const char *string;
      int soft;
 {
-  char *fmt;
-  void (*fn)();
+  const char *fmt;
+  void (*fn) PARAMS ((const char *, ...));
 
   if (soft)
     fn = cp_pedwarn;
@@ -94,9 +94,9 @@ readonly_error (arg, string, soft)
   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)
@@ -118,47 +118,33 @@ readonly_error (arg, string, soft)
     (*fn) ("%s of read-only reference `%D'", string, TREE_OPERAND (arg, 0));
   else if (TREE_CODE (arg) == RESULT_DECL)
     (*fn) ("%s of read-only named return value `%D'", string, arg);
-  else        
+  else if (TREE_CODE (arg) == FUNCTION_DECL)
+    (*fn) ("%s of function `%D'", string, arg);
+  else
     (*fn) ("%s of read-only location", string);
 }
 
-/* Print an error message for invalid use of a type which declares
-   virtual functions which are not inheritable.  */
+/* 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.  */
 
-void
+int
 abstract_virtuals_error (decl, type)
      tree decl;
      tree type;
 {
-  tree u = CLASSTYPE_ABSTRACT_VIRTUALS (type);
-  int has_abstract_virtuals, needs_final_overriders;
+  tree u;
   tree tu;
 
-  /* Count how many abstract methods need to be defined.  */
-  for (has_abstract_virtuals = 0, tu = u; tu; tu = TREE_CHAIN (tu))
-    {
-      if (DECL_ABSTRACT_VIRTUAL_P (TREE_VALUE (tu))
-         && ! DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu)))
-       {
-         has_abstract_virtuals = 1;
-         break;
-       }
-    }
-
-  /* Count how many virtual methods need a final overrider.  */
-  for (needs_final_overriders = 0, tu = u; tu; tu = TREE_CHAIN (tu))
-    {
-      if (DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu)))
-       {
-         needs_final_overriders = 1;
-         break;
-       }
-    }
+  if (!CLASS_TYPE_P (type) || !CLASSTYPE_PURE_VIRTUALS (type))
+    return 0;
 
+  u = CLASSTYPE_PURE_VIRTUALS (type);
   if (decl)
     {
       if (TREE_CODE (decl) == RESULT_DECL)
-       return;
+       return 0;
 
       if (TREE_CODE (decl) == VAR_DECL)
        cp_error ("cannot declare variable `%D' to be of type `%T'",
@@ -171,7 +157,7 @@ abstract_virtuals_error (decl, type)
                    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);
+       cp_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);
     }
@@ -183,77 +169,14 @@ abstract_virtuals_error (decl, type)
     {
       TREE_PURPOSE (u) = error_mark_node;
 
-      if (has_abstract_virtuals)
-       error ("  since the following virtual functions are abstract:");
-      tu = u;
-      while (tu)
-       {
-         if (DECL_ABSTRACT_VIRTUAL_P (TREE_VALUE (tu))
-             && ! DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu)))
-           cp_error ("\t%#D", TREE_VALUE (tu));
-         tu = TREE_CHAIN (tu);
-       }
-
-      if (needs_final_overriders)
-       {
-         if (has_abstract_virtuals)
-           error ("  and the following virtual functions need a final overrider:");
-         else
-           error ("  since the following virtual functions need a final overrider:");
-       }
-      tu = u;
-      while (tu)
-       {
-         if (DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu)))
-           cp_error ("\t%#D", TREE_VALUE (tu));
-         tu = TREE_CHAIN (tu);
-       }
+      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
-    {
-      if (has_abstract_virtuals)
-       {
-         if (needs_final_overriders)
-           cp_error ("  since type `%T' has abstract virtual functions and must override virtual functions", type);
-         else
-           cp_error ("  since type `%T' has abstract virtual functions", type);
-       }
-      else
-       cp_error ("  since type `%T' must override virtual functions", type);
-    }
-}
-
-/* Print an error message for invalid use of a signature type.
-   Signatures are treated similar to abstract classes here, they
-   cannot be instantiated.  */
+    cp_error ("  since type `%T' has abstract virtual functions", type);
 
-void
-signature_error (decl, type)
-     tree decl;
-     tree type;
-{
-  if (decl)
-    {
-      if (TREE_CODE (decl) == RESULT_DECL)
-       return;
-
-      if (TREE_CODE (decl) == VAR_DECL)
-       cp_error ("cannot declare variable `%D' to be of signature type `%T'",
-                 decl, type);
-      else if (TREE_CODE (decl) == PARM_DECL)
-       cp_error ("cannot declare parameter `%D' to be of signature type `%T'",
-                 decl, type);
-      else if (TREE_CODE (decl) == FIELD_DECL)
-       cp_error ("cannot declare field `%D' to be of signature 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);
-      else if (TREE_CODE (decl) == FUNCTION_DECL)
-       cp_error ("invalid return type for function `%#D'", decl);
-    }
-  else
-    cp_error ("cannot allocate an object of signature type `%T'", type);
+  return 1;
 }
 
 /* Print an error message for invalid use of an incomplete type.
@@ -265,282 +188,93 @@ incomplete_type_error (value, type)
      tree value;
      tree type;
 {
-  char *errmsg = 0;
-
+  int decl = 0;
+  
   /* Avoid duplicate error message.  */
   if (TREE_CODE (type) == ERROR_MARK)
     return;
 
   if (value != 0 && (TREE_CODE (value) == VAR_DECL
                     || TREE_CODE (value) == PARM_DECL))
-    cp_error ("`%D' has incomplete type", value);
-  else
     {
-    retry:
-      /* We must print an error message.  Be clever about what it says.  */
-
-      switch (TREE_CODE (type))
-       {
-       case RECORD_TYPE:
-       case UNION_TYPE:
-       case ENUMERAL_TYPE:
-         errmsg = "invalid use of undefined type `%#T'";
-         break;
-
-       case VOID_TYPE:
-         error ("invalid use of void expression");
-         return;
-
-       case ARRAY_TYPE:
-         if (TYPE_DOMAIN (type))
-           {
-             type = TREE_TYPE (type);
-             goto retry;
-           }
-         error ("invalid use of array with unspecified bounds");
-         return;
-
-       case OFFSET_TYPE:
-         error ("invalid use of member type (did you forget the `&' ?)");
-         return;
-
-       case TEMPLATE_TYPE_PARM:
-         error ("invalid use of template type parameter");
-         return;
+      cp_error_at ("`%D' has incomplete type", value);
+      decl = 1;
+    }
+retry:
+  /* We must print an error message.  Be clever about what it says.  */
 
-       default:
-         my_friendly_abort (108);
-       }
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case ENUMERAL_TYPE:
+      if (!decl)
+        cp_error ("invalid use of undefined type `%#T'", type);
+      cp_error_at ("forward declaration of `%#T'", type);
+      break;
 
-      cp_error (errmsg, type);
-    }
-}
+    case VOID_TYPE:
+      cp_error ("invalid use of `%T'", type);
+      break;
 
-/* Like error(), but don't call report_error_function().  */
+    case ARRAY_TYPE:
+      if (TYPE_DOMAIN (type))
+        {
+          type = TREE_TYPE (type);
+          goto retry;
+        }
+      cp_error ("invalid use of array with unspecified bounds");
+      break;
 
-static void
-ack (s, v, v2)
-     char *s;
-     HOST_WIDE_INT v;
-     HOST_WIDE_INT v2;
-{
-  extern char * progname;
-  
-  if (input_filename)
-    fprintf (stderr, "%s:%d: ", input_filename, lineno);
-  else
-    fprintf (stderr, "%s: ", progname);
+    case OFFSET_TYPE:
+    bad_member:
+      cp_error ("invalid use of member (did you forget the `&' ?)");
+      break;
 
-  fprintf (stderr, s, v, v2);
-  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.
-
-   Note, there will be no more calls in the C++ front end to abort,
-   because the C++ front end is so unreliable still.  The C front end
-   can get away with calling abort, because for most of the calls to
-   abort on most machines, it, I suspect, can be proven that it is
-   impossible to ever call abort.  The same is not yet true for C++,
-   one day, maybe it will be.
-
-   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).  */
-
-/* First used: 0 (reserved), Last used: 369.  Free: */
-
-static int abortcount = 0;
+    case TEMPLATE_TYPE_PARM:
+      cp_error ("invalid use of template type parameter");
+      break;
 
-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 (i == 0)
-           ack ("Internal compiler error.");
-         else
-           ack ("Internal compiler error %d.", i);
-         ack ("Please submit a full bug report to `egcs-bugs@cygnus.com'.");
-       }
+    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");
+      else if (value && TREE_CODE (value) == OVERLOAD)
+        cp_error ("overloaded function with no contextual type information");
       else
-       error ("confused by earlier errors, bailing out");
-      
-      exit (34);
+        cp_error ("insufficient contextual information to determine type");
+      break;
+    
+    default:
+      my_friendly_abort (108);
     }
-  ++abortcount;
-
-  if (i == 0)
-    error ("Internal compiler error.");
-  else
-    error ("Internal compiler error %d.", i);
-
-  fatal ("Please submit a full bug report to `egcs-bugs@cygnus.com'.");
 }
 
+/* This is a wrapper around fancy_abort, as used in the back end and
+   other front ends.  It will also report the magic number assigned to
+   this particular abort.  That is for backward compatibility with the
+   old C++ abort handler, which would just report the magic number.  */
 void
-my_friendly_assert (cond, where)
-     int cond, where;
-{
-  if (cond == 0)
-    my_friendly_abort (where);
-}
-\f
-/* Return nonzero if VALUE is a valid constant-valued expression
-   for use in initializing a static variable; one that can be an
-   element of a "constant" initializer.
-
-   Return null_pointer_node if the value is absolute;
-   if it is relocatable, return the variable that determines the relocation.
-   We assume that VALUE has been folded as much as possible;
-   therefore, we do not need to check for such things as
-   arithmetic-combinations of integers.  */
-
-tree
-initializer_constant_valid_p (value, endtype)
-     tree value;
-     tree endtype;
+friendly_abort (where, file, line, func)
+     int where;
+     const char *file;
+     int line;
+     const char *func;
 {
-  switch (TREE_CODE (value))
+  if (errorcount > 0 || sorrycount > 0)
+    /* Say nothing.  */;
+  else if (where > 0)
     {
-    case CONSTRUCTOR:
-      if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
-         && TREE_CONSTANT (value))
-       return
-         initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
-                                       endtype);
-       
-      return TREE_STATIC (value) ? null_pointer_node : 0;
-
-    case INTEGER_CST:
-    case REAL_CST:
-    case STRING_CST:
-    case COMPLEX_CST:
-      return null_pointer_node;
-
-    case ADDR_EXPR:
-      return TREE_OPERAND (value, 0);
-
-    case NON_LVALUE_EXPR:
-      return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
-    case CONVERT_EXPR:
-    case NOP_EXPR:
-      /* Allow conversions between pointer types.  */
-      if (POINTER_TYPE_P (TREE_TYPE (value))
-         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
-      /* Allow conversions between real types.  */
-      if (TREE_CODE (TREE_TYPE (value)) == REAL_TYPE
-         && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == REAL_TYPE)
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
-      /* Allow length-preserving conversions between integer types.  */
-      if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
-         && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE
-         && (TYPE_PRECISION (TREE_TYPE (value))
-             == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
-      /* Allow conversions between other integer types only if
-        explicit value.  */
-      if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
-         && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE)
-       {
-         tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                                    endtype);
-         if (inner == null_pointer_node)
-           return null_pointer_node;
-         return 0;
-       }
-
-      /* Allow (int) &foo provided int is as wide as a pointer.  */
-      if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
-         && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE
-         && (TYPE_PRECISION (TREE_TYPE (value))
-             >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                            endtype);
-
-      /* Likewise conversions from int to pointers.  */
-      if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE
-         && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE
-         && (TYPE_PRECISION (TREE_TYPE (value))
-             <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                            endtype);
-
-      /* Allow conversions to union types if the value inside is okay.  */
-      if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                            endtype);
-      return 0;
-
-    case PLUS_EXPR:
-      if ((TREE_CODE (endtype) == INTEGER_TYPE)
-         && (TYPE_PRECISION (endtype) < POINTER_SIZE))
-       return 0;
-      {
-       tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                                   endtype);
-       tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
-                                                   endtype);
-       /* If either term is absolute, use the other terms relocation.  */
-       if (valid0 == null_pointer_node)
-         return valid1;
-       if (valid1 == null_pointer_node)
-         return valid0;
-       return 0;
-      }
-
-    case MINUS_EXPR:
-      if ((TREE_CODE (endtype) == INTEGER_TYPE)
-         && (TYPE_PRECISION (endtype) < POINTER_SIZE))
-       return 0;
-      {
-       tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
-                                                   endtype);
-       tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
-                                                   endtype);
-       /* Win if second argument is absolute.  */
-       if (valid1 == null_pointer_node)
-         return valid0;
-       /* Win if both arguments have the same relocation.
-          Then the value is absolute.  */
-       if (valid0 == valid1)
-         return null_pointer_node;
-       return 0;
-      }
+      error ("Internal error #%d.", where);
 
-    default:
-      break;
+      /* Uncount this error, so internal_error will do the right thing.  */
+      --errorcount;
     }
 
-  return 0;
+  fancy_abort (file, line, func);
 }
+
 \f
 /* Perform appropriate conversions on the initial value of a variable,
    store it in the declaration DECL,
@@ -585,17 +319,7 @@ store_init_value (decl, init)
          && TREE_CODE (init) != CONSTRUCTOR)
        my_friendly_abort (109);
 
-      /* Although we are not allowed to declare variables of signature
-        type, we complain about a possible constructor call in such a
-        declaration as well.  */
-      if (TREE_CODE (init) == TREE_LIST
-         && IS_SIGNATURE (type))
-       {
-         cp_error ("constructor syntax cannot be used with signature type `%T'",
-                   type);
-         init = error_mark_node;
-       }
-      else if (TREE_CODE (init) == TREE_LIST)
+      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));
@@ -643,13 +367,6 @@ store_init_value (decl, init)
          else
            init = TREE_VALUE (init);
        }
-      else if (TREE_TYPE (init) != 0
-              && TREE_CODE (TREE_TYPE (init)) == OFFSET_TYPE)
-       {
-         /* Use the type of our variable to instantiate
-            the type of our initializer.  */
-         init = instantiate_type (type, init, 1);
-       }
       else if (TREE_CODE (init) == TREE_LIST
               && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
        {
@@ -682,7 +399,7 @@ store_init_value (decl, init)
     ;
   /* Other code expects that initializers for objects of types that need
      constructing never make it into DECL_INITIAL, and passes 'init' to
-     expand_aggr_init without checking DECL_INITIAL.  So just return.  */
+     build_aggr_init without checking DECL_INITIAL.  So just return.  */
   else if (TYPE_NEEDS_CONSTRUCTING (type))
     return value;
   else if (TREE_STATIC (decl)
@@ -693,7 +410,7 @@ store_init_value (decl, init)
                  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 the vtable definition, we can leave the
+                 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
@@ -706,19 +423,17 @@ store_init_value (decl, init)
 #if 0 /* No, that's C.  jason 9/19/94 */
   else
     {
-      if (pedantic && TREE_CODE (value) == CONSTRUCTOR
-         /* Don't complain about non-constant initializers of
-            signature tables and signature pointers/references.  */
-         && ! (TYPE_LANG_SPECIFIC (type)
-               && (IS_SIGNATURE (type)
-                   || IS_SIGNATURE_POINTER (type)
-                   || IS_SIGNATURE_REFERENCE (type))))
+      if (pedantic && TREE_CODE (value) == CONSTRUCTOR)
        {
          if (! TREE_CONSTANT (value) || ! TREE_STATIC (value))
            pedwarn ("ANSI C++ forbids non-constant aggregate initializer expressions");
        }
     }
 #endif
+  
+  /* 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;
 }
@@ -756,10 +471,18 @@ 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;
+  
   /* 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
@@ -779,12 +502,16 @@ digest_init (type, init, tail)
 
   if (code == ARRAY_TYPE)
     {
-      tree 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)
+      tree typ1;
+
+      if (TREE_CODE (init) == TREE_LIST)
+       {
+         error ("initializing array with parameter list");
+         return error_mark_node;
+       }
+
+      typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+      if (char_type_p (typ1)
          && ((init && TREE_CODE (init) == STRING_CST)
              || (element && TREE_CODE (element) == STRING_CST)))
        {
@@ -828,10 +555,8 @@ 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)
-      || (code == RECORD_TYPE && ! raw_constructor
-         && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type))))
+      || code == BOOLEAN_TYPE || code == COMPLEX_TYPE || code == VECTOR_TYPE
+      || TYPE_PTRMEMFUNC_P (type))
     {
       if (raw_constructor)
        {
@@ -857,16 +582,17 @@ 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",
                type);
       return error_mark_node;
     }
 
-  if (code == ARRAY_TYPE || code == RECORD_TYPE || code == UNION_TYPE)
+  if (code == ARRAY_TYPE || IS_AGGR_TYPE_CODE (code))
     {
-      if (raw_constructor && TYPE_NON_AGGREGATE_CLASS (type))
+      if (raw_constructor && TYPE_NON_AGGREGATE_CLASS (type)
+         && TREE_HAS_CONSTRUCTOR (init))
        {
          cp_error ("subobject of type `%T' must be initialized by constructor, not by `%E'",
                    type, init);
@@ -922,6 +648,7 @@ process_init_constructor (type, init, elts)
   /* List of the elements of the result constructor,
      in reverse order.  */
   register tree members = NULL;
+  register tree next1;
   tree result;
   int allconstant = 1;
   int allsimple = 1;
@@ -956,42 +683,62 @@ process_init_constructor (type, init, elts)
       else
        len = -1;  /* Take as many as there are */
 
-      for (i = 0; (len < 0 || i < len) && tail != 0; i++)
+      for (i = 0; len < 0 || i < len; i++)
        {
-         register tree next1;
-
-         if (TREE_PURPOSE (tail)
-             && (TREE_CODE (TREE_PURPOSE (tail)) != INTEGER_CST
-                 || TREE_INT_CST_LOW (TREE_PURPOSE (tail)) != i))
-           sorry ("non-trivial labeled initializers");
-
-         if (TREE_VALUE (tail) != 0)
+         if (tail)
            {
-             tree tail1 = tail;
-             next1 = digest_init (TREE_TYPE (type),
-                                  TREE_VALUE (tail), &tail1);
-             if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (type))
-                 && TYPE_MAIN_VARIANT (TREE_TYPE (type)) != TYPE_MAIN_VARIANT (TREE_TYPE (next1)))
+             if (TREE_PURPOSE (tail)
+                 && (TREE_CODE (TREE_PURPOSE (tail)) != INTEGER_CST
+                     || compare_tree_int (TREE_PURPOSE (tail), i) != 0))
+               sorry ("non-trivial labeled initializers");
+
+             if (TREE_VALUE (tail) != 0)
                {
-                 /* The fact this needs to be done suggests this code needs
-                    to be totally rewritten.  */
-                 next1 = convert_for_initialization (NULL_TREE, TREE_TYPE (type), next1, LOOKUP_NORMAL, "initialization", NULL_TREE, 0);
+                 tree tail1 = tail;
+                 next1 = digest_init (TREE_TYPE (type),
+                                      TREE_VALUE (tail), &tail1);
+                 if (next1 == error_mark_node)
+                   return next1;
+                 my_friendly_assert
+                   (same_type_ignoring_top_level_qualifiers_p
+                    (TREE_TYPE (type), TREE_TYPE (next1)),
+                    981123);
+                 my_friendly_assert (tail1 == 0
+                                     || TREE_CODE (tail1) == TREE_LIST, 319);
+                 if (tail == tail1 && len < 0)
+                   {
+                     error ("non-empty initializer for array of empty elements");
+                     /* Just ignore what we were supposed to use.  */
+                     tail1 = NULL_TREE;
+                   }
+                 tail = tail1;
                }
-             my_friendly_assert (tail1 == 0
-                                 || TREE_CODE (tail1) == TREE_LIST, 319);
-             if (tail == tail1 && len < 0)
+             else
                {
-                 error ("non-empty initializer for array of empty elements");
-                 /* Just ignore what we were supposed to use.  */
-                 tail1 = NULL_TREE;
+                 next1 = error_mark_node;
+                 tail = TREE_CHAIN (tail);
                }
-             tail = tail1;
            }
-         else
+         else if (len < 0)
+           /* We're done.  */
+           break;
+         else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (type)))
            {
-             next1 = error_mark_node;
-             tail = TREE_CHAIN (tail);
+             /* If this type needs constructors run for
+                default-initialization, we can't rely on the backend to do it
+                for us, so build up TARGET_EXPRs.  If the type in question is
+                a class, just build one up; if it's an array, recurse.  */
+
+             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 = digest_init (TREE_TYPE (type), next1, 0);
            }
+         else
+           /* The default zero-initialization is fine for us; don't
+              add anything to the CONSTRUCTOR.  */
+           break;
 
          if (next1 == error_mark_node)
            erroneous = 1;
@@ -999,10 +746,10 @@ 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);
        }
     }
-  if (TREE_CODE (type) == RECORD_TYPE)
+  else if (TREE_CODE (type) == RECORD_TYPE)
     {
       register tree field;
 
@@ -1010,56 +757,103 @@ process_init_constructor (type, init, elts)
        {
          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;
            }
        }
 
-      for (field = TYPE_FIELDS (type); field && tail;
+      for (field = TYPE_FIELDS (type); field;
           field = TREE_CHAIN (field))
        {
-         register tree next1;
-
-         if (! DECL_NAME (field))
+         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)
            continue;
 
-         if (TREE_PURPOSE (tail)
-             && TREE_PURPOSE (tail) != field
-             && TREE_PURPOSE (tail) != DECL_NAME (field))
-           sorry ("non-trivial labeled initializers");
-
-         if (TREE_VALUE (tail) != 0)
+         if (tail)
            {
-             tree tail1 = tail;
+             if (TREE_PURPOSE (tail)
+                 && TREE_PURPOSE (tail) != field
+                 && TREE_PURPOSE (tail) != DECL_NAME (field))
+               sorry ("non-trivial labeled initializers");
 
-             next1 = digest_init (TREE_TYPE (field),
-                                  TREE_VALUE (tail), &tail1);
-             my_friendly_assert (tail1 == 0
-                                 || TREE_CODE (tail1) == TREE_LIST, 320);
-             tail = tail1;
+             if (TREE_VALUE (tail) != 0)
+               {
+                 tree tail1 = tail;
+
+                 next1 = digest_init (TREE_TYPE (field),
+                                      TREE_VALUE (tail), &tail1);
+                 my_friendly_assert (tail1 == 0
+                                     || TREE_CODE (tail1) == TREE_LIST, 320);
+                 tail = tail1;
+               }
+             else
+               {
+                 next1 = error_mark_node;
+                 tail = TREE_CHAIN (tail);
+               }
+           }
+         else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field)))
+           {
+             /* If this type needs constructors run for
+                default-initialization, we can't rely on the backend to do it
+                for us, so build up TARGET_EXPRs.  If the type in question is
+                a class, just build one up; if it's an array, recurse.  */
+
+             if (IS_AGGR_TYPE (TREE_TYPE (field)))
+               next1 = build_functional_cast (TREE_TYPE (field),
+                                              NULL_TREE);
+             else
+               {
+                 next1 = build (CONSTRUCTOR, NULL_TREE, 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
+                 && (!init || TREE_HAS_CONSTRUCTOR (init)))
+               cp_warning ("missing initializer for member `%D'", field);
            }
          else
            {
-             next1 = error_mark_node;
-             tail = TREE_CHAIN (tail);
+             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",
+                         field);
+             else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE)
+               cp_error ("member `%D' is uninitialized reference", field);
+
+             /* Warn when some struct elements are implicitly initialized
+                to zero.  */
+             if (extra_warnings
+                 && (!init || TREE_HAS_CONSTRUCTOR (init)))
+               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 (next1 == error_mark_node)
@@ -1068,42 +862,14 @@ 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);
-       }
-      for (; field; field = TREE_CHAIN (field))
-       {
-         if (TREE_CODE (field) != FIELD_DECL)
-           continue;
-
-         /* Does this field have a default initialization?  */
-         if (DECL_INITIAL (field))
-           {
-             register tree next1 = DECL_INITIAL (field);
-             if (TREE_CODE (next1) == ERROR_MARK)
-               erroneous = 1;
-             else if (!TREE_CONSTANT (next1))
-               allconstant = 0;
-             else if (! initializer_constant_valid_p (next1, TREE_TYPE (next1)))
-               allsimple = 0;
-             members = expr_tree_cons (field, next1, members);
-           }
-         else if (TREE_READONLY (field))
-           error ("uninitialized const member `%s'",
-                  IDENTIFIER_POINTER (DECL_NAME (field)));
-         else if (TYPE_LANG_SPECIFIC (TREE_TYPE (field))
-                  && CLASSTYPE_READONLY_FIELDS_NEED_INIT (TREE_TYPE (field)))
-           error ("member `%s' with uninitialized const fields",
-                  IDENTIFIER_POINTER (DECL_NAME (field)));
-         else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE)
-           error ("member `%s' is uninitialized reference",
-                  IDENTIFIER_POINTER (DECL_NAME (field)));
+         members = tree_cons (field, next1, members);
        }
     }
-
-  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);
-      register tree next1;
 
       /* Find the first named field.  ANSI decided in September 1990
         that only named fields count here.  */
@@ -1132,8 +898,8 @@ process_init_constructor (type, init, elts)
              if (temp)
                field = temp, win = 1;
              else
-               error ("no field `%s' in union being initialized",
-                      IDENTIFIER_POINTER (TREE_PURPOSE (tail)));
+               cp_error ("no field `%D' in union being initialized",
+                         TREE_PURPOSE (tail));
            }
          if (!win)
            TREE_VALUE (tail) = error_mark_node;
@@ -1167,7 +933,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.  */
@@ -1206,8 +972,13 @@ process_init_constructor (type, init, elts)
    then the expression
 
    x.A::ii refers to the ii member of the L part of
-   of A part of the C object named by X.  In this case,
-   DATUM would be x, and BASETYPE would be A.  */
+   the A part of the C object named by X.  In this case,
+   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) */
 
 tree
 build_scoped_ref (datum, basetype)
@@ -1215,48 +986,14 @@ build_scoped_ref (datum, basetype)
      tree basetype;
 {
   tree ref;
-  tree type = TREE_TYPE (datum);
 
   if (datum == error_mark_node)
     return error_mark_node;
 
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    type = TREE_TYPE (type);
+  ref = build_unary_op (ADDR_EXPR, datum, 0);
+  ref = convert_pointer_to (basetype, ref);
 
-  type = TYPE_MAIN_VARIANT (type);
-
-  /* This is an easy conversion.  */
-  if (is_aggr_type (basetype, 1))
-    {
-      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)");
-    }
-  return error_mark_node;
+  return build_indirect_ref (ref, "(compiler error in build_scoped_ref)");
 }
 
 /* Build a reference to an object specified by the C++ `->' operator.
@@ -1326,13 +1063,8 @@ build_x_arrow (datum)
   else
     last_rval = default_conversion (rval);
 
-  /* Signature pointers are not dereferenced.  */
-  if (TYPE_LANG_SPECIFIC (TREE_TYPE (last_rval))
-      && IS_SIGNATURE_POINTER (TREE_TYPE (last_rval)))
-    return last_rval;
-
   if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE)
-    return build_indirect_ref (last_rval, NULL_PTR);
+    return build_indirect_ref (last_rval, NULL);
 
   if (types_memoized)
     error ("result of `operator->()' yields non-pointer result");
@@ -1358,38 +1090,38 @@ build_m_component_ref (datum, component)
      tree datum, component;
 {
   tree type;
-  tree objtype = TREE_TYPE (datum);
-  tree rettype;
+  tree objtype;
+  tree field_type;
+  int type_quals;
   tree binfo;
 
   if (processing_template_decl)
     return build_min_nt (DOTSTAR_EXPR, datum, component);
 
+  datum = decay_conversion (datum);
+
+  if (datum == error_mark_node || component == error_mark_node)
+    return error_mark_node;
+
+  objtype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));  
+
   if (TYPE_PTRMEMFUNC_P (TREE_TYPE (component)))
     {
       type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (component)));
-      rettype = type;
+      field_type = type;
     }
-  else
+  else if (TYPE_PTRMEM_P (TREE_TYPE (component)))
     {
-      component = build_indirect_ref (component, NULL_PTR);
-      type = TREE_TYPE (component);
-      rettype = TREE_TYPE (type);
+      type = TREE_TYPE (TREE_TYPE (component));
+      field_type = TREE_TYPE (type);
     }
-
-  if (datum == error_mark_node || component == error_mark_node)
-    return error_mark_node;
-
-  if (TREE_CODE (type) != OFFSET_TYPE && TREE_CODE (type) != METHOD_TYPE)
+  else
     {
-      cp_error ("`%E' cannot be used as a member pointer, since it is of type `%T'", component, type);
+      cp_error ("`%E' cannot be used as a member pointer, since it is of type `%T'", 
+               component, TREE_TYPE (component));
       return error_mark_node;
     }
 
-  if (TREE_CODE (objtype) == REFERENCE_TYPE)
-    objtype = TREE_TYPE (objtype);
-  objtype = TYPE_MAIN_VARIANT (objtype);
-
   if (! IS_AGGR_TYPE (objtype))
     {
       cp_error ("cannot apply member pointer `%E' to `%E'", component, datum);
@@ -1407,7 +1139,24 @@ build_m_component_ref (datum, component)
   else if (binfo == error_mark_node)
     return error_mark_node;
 
-  component = build (OFFSET_REF, rettype, datum, component);
+  /* Compute the type of the field, as described in [expr.ref].  */
+  type_quals = TYPE_UNQUALIFIED;
+  if (TREE_CODE (field_type) == REFERENCE_TYPE)
+    /* The standard says that the type of the result should be the
+       type referred to by the reference.  But for now, at least, we
+       do the conversion from reference type later.  */
+    ;
+  else
+    {
+      type_quals = (CP_TYPE_QUALS (field_type)  
+                   | CP_TYPE_QUALS (TREE_TYPE (datum)));
+
+      /* There's no such thing as a mutable pointer-to-member, so we don't
+        need to deal with that here like we do in build_component_ref.  */
+      field_type = cp_build_qualified_type (field_type, type_quals);
+    }
+
+  component = build (OFFSET_REF, field_type, datum, component);
   if (TREE_CODE (type) == OFFSET_TYPE)
     component = resolve_offset_ref (component);
   return component;
@@ -1451,12 +1200,6 @@ build_functional_cast (exp, parms)
   if (processing_template_decl)
     return build_min (CAST_EXPR, type, parms);
 
-  if (IS_SIGNATURE (type))
-    {
-      error ("signature type not allowed in cast or constructor expression");
-      return error_mark_node;
-    }
-
   if (! IS_AGGR_TYPE (type))
     {
       /* this must build a C cast */
@@ -1479,16 +1222,24 @@ 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;
 
   if (parms && TREE_CHAIN (parms) == NULL_TREE)
     return build_c_cast (type, TREE_VALUE (parms));
 
-  exp = build_method_call (NULL_TREE, ctor_identifier, parms,
+  /* We need to zero-initialize POD types.  Let's do that for everything
+     that doesn't need a constructor.  */
+  if (parms == NULL_TREE && !TYPE_NEEDS_CONSTRUCTING (type)
+      && TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+    {
+      exp = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+      return get_target_expr (exp);
+    }
+
+  exp = build_method_call (NULL_TREE, complete_ctor_identifier, parms,
                           TYPE_BINFO (type), LOOKUP_NORMAL);
 
   if (exp == error_mark_node)
@@ -1497,144 +1248,107 @@ 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));
+/* Complain about defining new types in inappropriate places.  We give an
+   exception for C-style casts, to accommodate GNU C stylings.  */
 
-      /* Value must have been cast.  */
-      sprintf (buf, "(enum %s)%d",
-              TYPE_NAME_STRING (type), intval);
-      return buf;
-    }
-  return IDENTIFIER_POINTER (TREE_PURPOSE (values));
+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);
 }
 
-#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.  */
+/* Add new exception specifier SPEC, to the LIST we currently have.
+   If it's already in LIST then do nothing.
+   Moan if it's bad and we're allowed to. COMPLAIN < 0 means we
+   know what we're doing.  */
 
-void
-report_case_error (code, type, new_value, old_value)
-     int code;
-     tree type;
-     tree new_value, old_value;
+tree
+add_exception_specifier (list, spec, complain)
+     tree list, spec;
+     int complain;
 {
-  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)
+  int ok;
+  tree core = spec;
+  int is_ptr;
+  
+  if (spec == error_mark_node)
+    return list;
+  
+  my_friendly_assert (spec && (!list || TREE_VALUE (list)), 19990317);
+  
+  /* [except.spec] 1, type in an exception specifier shall not be
+     incomplete, or pointer or ref to incomplete other than pointer
+     to cv void.  */
+  is_ptr = TREE_CODE (core) == POINTER_TYPE;
+  if (is_ptr || TREE_CODE (core) == REFERENCE_TYPE)
+    core = TREE_TYPE (core);
+  if (complain < 0)
+    ok = 1;
+  else if (VOID_TYPE_P (core))
+    ok = is_ptr;
+  else if (TREE_CODE (core) == TEMPLATE_TYPE_PARM)
+    ok = 1;
+  else if (processing_template_decl)
+    ok = 1;
+  else
+    ok = COMPLETE_TYPE_P (complete_type (core));
+
+  if (ok)
     {
-      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");
+      tree probe;
+      
+      for (probe = 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;
 }
-#endif
 
-void
-check_for_new_type (string, inptree)
-     char *string;
-     flagged_type_tree inptree;
+/* Combine the two exceptions specifier lists LIST and ADD, and return
+   their union. */
+
+tree
+merge_exception_specifiers (list, add)
+     tree list, add;
 {
-  if (pedantic && inptree.new_type_flag)
-    pedwarn ("ANSI C++ forbids defining types within %s",string);
+  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))
+        {
+          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;
+            }
+        }
+    }
+  return list;
 }
This page took 0.062402 seconds and 5 git commands to generate.