OSDN Git Service

2001-11-12 H.J. Lu <hjl@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / cp / cvt.c
index 99289e8..81d0577 100644 (file)
@@ -1,5 +1,6 @@
 /* Language-level data type conversion for GNU C++.
-   Copyright (C) 1987, 88, 92-96, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 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.
@@ -31,12 +32,13 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "cp-tree.h"
 #include "convert.h"
+#include "toplev.h"
+#include "decl.h"
 
-extern tree static_aggregates;
-
-static tree cp_convert_to_pointer PROTO((tree, tree));
-static tree convert_to_pointer_force PROTO((tree, tree));
-static tree build_up_reference PROTO((tree, tree, int, int));
+static tree cp_convert_to_pointer PARAMS ((tree, tree, int));
+static tree convert_to_pointer_force PARAMS ((tree, tree));
+static tree build_up_reference PARAMS ((tree, tree, int, tree));
+static void warn_ref_binding PARAMS ((tree, tree, tree));
 
 /* Change of width--truncation and extension of integers or reals--
    is represented with NOP_EXPR.  Proper functioning of many things
@@ -65,11 +67,14 @@ static tree build_up_reference PROTO((tree, tree, int, int));
      else if dealing with method pointers, delegate
      else convert blindly
    else if converting class, pass off to build_type_conversion
-   else try C-style pointer conversion  */
+   else try C-style pointer conversion.  If FORCE is true then allow
+   conversions via virtual bases (these are permitted by reinterpret_cast,
+   but not static_cast).  */
 
 static tree
-cp_convert_to_pointer (type, expr)
+cp_convert_to_pointer (type, expr, force)
      tree type, expr;
+     int force;
 {
   register tree intype = TREE_TYPE (expr);
   register enum tree_code form;
@@ -78,14 +83,14 @@ cp_convert_to_pointer (type, expr)
   if (IS_AGGR_TYPE (intype))
     {
       intype = complete_type (intype);
-      if (TYPE_SIZE (intype) == NULL_TREE)
+      if (!COMPLETE_TYPE_P (intype))
        {
          cp_error ("can't convert from incomplete type `%T' to `%T'",
                    intype, type);
          return error_mark_node;
        }
 
-      rval = build_type_conversion (CONVERT_EXPR, type, expr, 1);
+      rval = build_type_conversion (type, expr, 1);
       if (rval)
        {
          if (rval == error_mark_node)
@@ -95,33 +100,17 @@ cp_convert_to_pointer (type, expr)
        }
     }
 
-  if (TYPE_PTRMEMFUNC_P (type))
-    type = TYPE_PTRMEMFUNC_FN_TYPE (type);
-
   /* Handle anachronistic conversions from (::*)() to cv void* or (*)().  */
   if (TREE_CODE (type) == POINTER_TYPE
       && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
-         || TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node))
+         || VOID_TYPE_P (TREE_TYPE (type))))
     {
       /* Allow an implicit this pointer for pointer to member
         functions.  */
       if (TYPE_PTRMEMFUNC_P (intype))
        {
-         tree decl, basebinfo;
          tree fntype = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (intype));
-         tree t = TYPE_METHOD_BASETYPE (fntype);
-
-         if (current_class_type == 0
-             || get_base_distance (t, current_class_type, 0, &basebinfo)
-             == -1)
-           {
-             decl = build1 (NOP_EXPR, t, error_mark_node);
-           }
-         else if (current_class_ptr == 0)
-           decl = build1 (NOP_EXPR, t, error_mark_node);
-         else
-           decl = current_class_ref;
-
+         tree decl = maybe_dummy_object (TYPE_METHOD_BASETYPE (fntype), 0);
          expr = build (OFFSET_REF, fntype, decl, expr);
        }
 
@@ -141,16 +130,14 @@ cp_convert_to_pointer (type, expr)
       intype = TREE_TYPE (expr);
     }
 
-  if (TYPE_PTRMEMFUNC_P (intype))
-    intype = TYPE_PTRMEMFUNC_FN_TYPE (intype);
-
   form = TREE_CODE (intype);
 
-  if (form == POINTER_TYPE || form == REFERENCE_TYPE)
+  if (POINTER_TYPE_P (intype))
     {
       intype = TYPE_MAIN_VARIANT (intype);
 
       if (TYPE_MAIN_VARIANT (type) != intype
+         && TREE_CODE (type) == POINTER_TYPE
          && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
          && IS_AGGR_TYPE (TREE_TYPE (type))
          && IS_AGGR_TYPE (TREE_TYPE (intype))
@@ -194,34 +181,57 @@ cp_convert_to_pointer (type, expr)
                }
            }
        }
-      if (TREE_CODE (TREE_TYPE (intype)) == METHOD_TYPE
-         && TREE_CODE (type) == POINTER_TYPE
-         && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
-       return build_ptrmemfunc (type, expr, 1);
 
-      if (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE
-         && TREE_CODE (TREE_TYPE (intype)) == OFFSET_TYPE)
+      if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
        {
-         tree b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));
-         tree b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));
-         tree binfo = get_binfo (b2, b1, 1);
-         enum tree_code code = PLUS_EXPR;
+         tree b1; 
+         tree b2;
+         tree binfo;
+         tree virt_binfo;
+         enum tree_code code;
+
+         b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));
+         b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));
+         binfo = get_binfo (b2, b1, 1);
 
          if (binfo == NULL_TREE)
            {
              binfo = get_binfo (b1, b2, 1);
              code = MINUS_EXPR;
            }
+         else
+           code = PLUS_EXPR;
 
          if (binfo == error_mark_node)
            return error_mark_node;
-         if (binfo && ! TREE_VIA_VIRTUAL (binfo))
-           expr = size_binop (code, expr, BINFO_OFFSET (binfo));
-       }
 
-      if (TREE_CODE (TREE_TYPE (intype)) == METHOD_TYPE
-         || (TREE_CODE (type) == POINTER_TYPE
-             && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE))
+          virt_binfo = binfo_from_vbase (binfo);
+          if (virt_binfo)
+           {
+             if (force)
+               cp_warning ("pointer to member cast via virtual base `%T' of `%T'",
+                           BINFO_TYPE (virt_binfo),
+                            BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+              else
+                {
+                 cp_error ("pointer to member cast via virtual base `%T' of `%T'",
+                           BINFO_TYPE (virt_binfo),
+                            BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+                 return error_mark_node;
+               }
+             /* This is a reinterpret cast, whose result is unspecified.
+                We choose to do nothing.  */
+             return build1 (NOP_EXPR, type, expr);
+           }
+             
+         if (TREE_CODE (expr) == PTRMEM_CST)
+           expr = cplus_expand_constant (expr);
+
+         if (binfo)
+           expr = size_binop (code, convert (sizetype, expr),
+                              BINFO_OFFSET (binfo));
+       }
+      else if (TYPE_PTRMEMFUNC_P (type))
        {
          cp_error ("cannot convert `%E' from type `%T' to type `%T'",
                    expr, intype, type);
@@ -232,18 +242,28 @@ cp_convert_to_pointer (type, expr)
       TREE_CONSTANT (rval) = TREE_CONSTANT (expr);
       return rval;
     }
+  else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))
+    return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
+  else if (TYPE_PTRMEMFUNC_P (intype))
+    {
+      cp_error ("cannot convert `%E' from type `%T' to type `%T'",
+               expr, intype, type);
+      return error_mark_node;
+    }
 
   my_friendly_assert (form != OFFSET_TYPE, 186);
 
-  if (TYPE_LANG_SPECIFIC (intype)
-      && (IS_SIGNATURE_POINTER (intype) || IS_SIGNATURE_REFERENCE (intype)))
-    return convert_to_pointer (type, build_optr_ref (expr));
-
   if (integer_zerop (expr))
     {
-      if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
-       return build_ptrmemfunc (type, expr, 0);
-      expr = build_int_2 (0, 0);
+      if (TYPE_PTRMEMFUNC_P (type))
+       return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
+
+      if (TYPE_PTRMEM_P (type))
+       /* A NULL pointer-to-member is represented by -1, not by
+          zero.  */
+       expr = build_int_2 (-1, -1);
+      else
+       expr = build_int_2 (0, 0);
       TREE_TYPE (expr) = type;
       return expr;
     }
@@ -262,6 +282,9 @@ cp_convert_to_pointer (type, expr)
       return convert_to_pointer (type, expr);
     }
 
+  if (type_unknown_p (expr))
+    return instantiate_type (type, expr, itf_complain);
+
   cp_error ("cannot convert `%E' from type `%T' to type `%T'",
            expr, intype, type);
   return error_mark_node;
@@ -285,15 +308,6 @@ convert_to_pointer_force (type, expr)
       return expr;
     }
 
-  /* Convert signature pointer/reference to `void *' first.  */
-  if (form == RECORD_TYPE
-      && (IS_SIGNATURE_POINTER (intype) || IS_SIGNATURE_REFERENCE (intype)))
-    {
-      expr = build_optr_ref (expr);
-      intype = TREE_TYPE (expr);
-      form = TREE_CODE (intype);
-    }
-
   if (form == POINTER_TYPE)
     {
       intype = TYPE_MAIN_VARIANT (intype);
@@ -310,10 +324,9 @@ convert_to_pointer_force (type, expr)
                                            TREE_TYPE (intype), 0, &path);
          if (distance == -2)
            {
-           ambig:
-             cp_error ("type `%T' is ambiguous baseclass of `%s'",
+             cp_error ("type `%T' is ambiguous base of `%T'",
                        TREE_TYPE (type),
-                       TYPE_NAME_STRING (TREE_TYPE (intype)));
+                       TREE_TYPE (intype));
              return error_mark_node;
            }
          if (distance == -1)
@@ -321,7 +334,12 @@ convert_to_pointer_force (type, expr)
              distance = get_base_distance (TREE_TYPE (intype),
                                            TREE_TYPE (type), 0, &path);
              if (distance == -2)
-               goto ambig;
+               {
+                 cp_error ("type `%T' is ambiguous base of `%T'",
+                           TREE_TYPE (intype),
+                           TREE_TYPE (type));
+                 return error_mark_node;
+               }
              if (distance < 0)
                /* Doesn't need any special help from us.  */
                return build1 (NOP_EXPR, type, expr);
@@ -332,7 +350,7 @@ convert_to_pointer_force (type, expr)
        }
     }
 
-  return cp_convert_to_pointer (type, expr);
+  return cp_convert_to_pointer (type, expr, 1);
 }
 
 /* We are passing something to a function which requires a reference.
@@ -340,43 +358,62 @@ convert_to_pointer_force (type, expr)
    value we have to begin with is in ARG.
 
    FLAGS controls how we manage access checking.
-   DIRECT_BIND in FLAGS controls how any temporaries are generated.  */
+   DIRECT_BIND in FLAGS controls how any temporaries are generated.
+     If DIRECT_BIND is set, DECL is the reference we're binding to.  */
 
 static tree
-build_up_reference (type, arg, flags, checkconst)
-     tree type, arg;
-     int flags, checkconst;
+build_up_reference (type, arg, flags, decl)
+     tree type, arg, decl;
+     int flags;
 {
   tree rval;
   tree argtype = TREE_TYPE (arg);
   tree target_type = TREE_TYPE (type);
+  tree stmt_expr = NULL_TREE;
 
   my_friendly_assert (TREE_CODE (type) == REFERENCE_TYPE, 187);
 
   if ((flags & DIRECT_BIND) && ! real_lvalue_p (arg))
     {
+      /* Create a new temporary variable.  We can't just use a TARGET_EXPR
+        here because it needs to live as long as DECL.  */
       tree targ = arg;
-      if (toplevel_bindings_p ())
-       arg = get_temp_name (argtype, 1);
+
+      arg = build_decl (VAR_DECL, NULL_TREE, argtype);
+      DECL_ARTIFICIAL (arg) = 1;
+      TREE_USED (arg) = 1;
+      TREE_STATIC (arg) = TREE_STATIC (decl);
+
+      if (TREE_STATIC (decl))
+       {
+         /* Namespace-scope or local static; give it a mangled name.  */
+         tree name = mangle_ref_init_variable (decl);
+         DECL_NAME (arg) = name;
+         SET_DECL_ASSEMBLER_NAME (arg, name);
+         arg = pushdecl_top_level (arg);
+       }
       else
        {
-         arg = pushdecl (build_decl (VAR_DECL, NULL_TREE, argtype));
-         DECL_ARTIFICIAL (arg) = 1;
+         /* Automatic; make sure we handle the cleanup properly.  */
+         maybe_push_cleanup_level (argtype);
+         arg = pushdecl (arg);
        }
+
+      /* Process the initializer for the declaration.  */
       DECL_INITIAL (arg) = targ;
-      cp_finish_decl (arg, targ, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
+      cp_finish_decl (arg, targ, NULL_TREE, 
+                     LOOKUP_ONLYCONVERTING|DIRECT_BIND);
     }
   else if (!(flags & DIRECT_BIND) && ! lvalue_p (arg))
-    {
-      tree slot = build_decl (VAR_DECL, NULL_TREE, argtype);
-      arg = build (TARGET_EXPR, argtype, slot, arg, NULL_TREE, NULL_TREE);
-      TREE_SIDE_EFFECTS (arg) = 1;
-    }
+    return get_target_expr (arg);
 
-  /* If we had a way to wrap this up, and say, if we ever needed it's
+  /* If we had a way to wrap this up, and say, if we ever needed its
      address, transform all occurrences of the register, into a memory
      reference we could win better.  */
   rval = build_unary_op (ADDR_EXPR, arg, 1);
+  if (rval == error_mark_node)
+    return error_mark_node;
+
   if ((flags & LOOKUP_PROTECT)
       && TYPE_MAIN_VARIANT (argtype) != TYPE_MAIN_VARIANT (target_type)
       && IS_AGGR_TYPE (argtype)
@@ -395,9 +432,47 @@ build_up_reference (type, arg, flags, checkconst)
       = convert_to_pointer_force (build_pointer_type (target_type), rval);
   rval = build1 (NOP_EXPR, type, rval);
   TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0));
+
+  /* If we created and initialized a new temporary variable, add the
+     representation of that initialization to the RVAL.  */
+  if (stmt_expr)
+    rval = build (COMPOUND_EXPR, TREE_TYPE (rval), stmt_expr, rval);
+
+  /* And return the result.  */
   return rval;
 }
 
+/* Subroutine of convert_to_reference. REFTYPE is the target reference type.
+   INTYPE is the original rvalue type and DECL is an optional _DECL node
+   for diagnostics.
+   
+   [dcl.init.ref] says that if an rvalue is used to
+   initialize a reference, then the reference must be to a
+   non-volatile const type.  */
+
+static void
+warn_ref_binding (reftype, intype, decl)
+     tree reftype, intype, decl;
+{
+  tree ttl = TREE_TYPE (reftype);
+  
+  if (!CP_TYPE_CONST_NON_VOLATILE_P (ttl))
+    {
+      const char *msg;
+
+      if (CP_TYPE_VOLATILE_P (ttl) && decl)
+         msg = "initialization of volatile reference type `%#T' from rvalue of type `%T'";
+      else if (CP_TYPE_VOLATILE_P (ttl))
+         msg = "conversion to volatile reference type `%#T' from rvalue of type `%T'";
+      else if (decl)
+         msg = "initialization of non-const reference type `%#T' from rvalue of type `%T'";
+      else
+         msg = "conversion to non-const reference type `%#T' from rvalue of type `%T'";
+
+      cp_pedwarn (msg, reftype, intype);
+    }
+}
+
 /* For C++: Only need to do one-level references, but cannot
    get tripped up on signed/unsigned differences.
 
@@ -417,6 +492,17 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
   tree rval_as_conversion = NULL_TREE;
   int i;
 
+  if (TREE_CODE (type) == FUNCTION_TYPE && intype == unknown_type_node)
+    {
+      expr = instantiate_type (type, expr, 
+                              (flags & LOOKUP_COMPLAIN)
+                              ? itf_complain : itf_none);
+      if (expr == error_mark_node)
+       return error_mark_node;
+
+      intype = TREE_TYPE (expr);
+    }
+
   if (TREE_CODE (intype) == REFERENCE_TYPE)
     my_friendly_abort (364);
 
@@ -430,7 +516,7 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
       /* Look for a user-defined conversion to lvalue that we can use.  */
 
       rval_as_conversion
-       = build_type_conversion (CONVERT_EXPR, reftype, expr, 1);
+       = build_type_conversion (reftype, expr, 1);
 
       if (rval_as_conversion && rval_as_conversion != error_mark_node
          && real_lvalue_p (rval_as_conversion))
@@ -450,29 +536,16 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
          tree ttl = TREE_TYPE (reftype);
          tree ttr = lvalue_type (expr);
 
-         if (! real_lvalue_p (expr) && ! TYPE_READONLY (ttl))
-           {
-             if (decl)
-               /* Ensure semantics of [dcl.init.ref] */
-               cp_pedwarn ("initialization of non-const reference `%#T' from rvalue `%T'",
-                           reftype, intype);
-             else
-               cp_pedwarn ("conversion to non-const `%T' from rvalue `%T'",
-                           reftype, intype);
-           }
-         else if (! (convtype & CONV_CONST))
-           {
-             if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
-               cp_pedwarn ("conversion from `%T' to `%T' discards const",
-                           ttr, reftype);
-             else if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
-               cp_pedwarn ("conversion from `%T' to `%T' discards volatile",
-                           ttr, reftype);
-           }
+         if (! real_lvalue_p (expr))
+           warn_ref_binding (reftype, intype, decl);
+         
+         if (! (convtype & CONV_CONST)
+                  && !at_least_as_qualified_p (ttl, ttr))
+           cp_pedwarn ("conversion from `%T' to `%T' discards qualifiers",
+                       ttr, reftype);
        }
 
-      return build_up_reference (reftype, expr, flags,
-                                ! (convtype & CONV_CONST));
+      return build_up_reference (reftype, expr, flags, decl);
     }
   else if ((convtype & CONV_REINTERPRET) && lvalue_p (expr))
     {
@@ -484,7 +557,8 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
       /* B* bp; A& ar = (A&)bp; is valid, but it's probably not what they
          meant.  */
       if (TREE_CODE (intype) == POINTER_TYPE
-         && (comptypes (TREE_TYPE (intype), type, -1)))
+         && (comptypes (TREE_TYPE (intype), type, 
+                        COMPARE_BASE | COMPARE_RELAXED )))
        cp_warning ("casting `%T' to `%T' does not dereference pointer",
                    intype, reftype);
          
@@ -499,13 +573,10 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
     {
       rval = convert_for_initialization (NULL_TREE, type, expr, flags,
                                         "converting", 0, 0);
-      if (rval == error_mark_node)
-       return error_mark_node;
-      rval = build_up_reference (reftype, rval, flags, 1);
-
-      if (rval && ! TYPE_READONLY (TREE_TYPE (reftype)))
-       cp_pedwarn ("initializing non-const `%T' with `%T' will use a temporary",
-                   reftype, intype);
+      if (rval == NULL_TREE || rval == error_mark_node)
+       return rval;
+      warn_ref_binding (reftype, intype, decl);
+      rval = build_up_reference (reftype, rval, flags, decl);
     }
 
   if (rval)
@@ -537,9 +608,23 @@ convert_from_reference (val)
   if (TREE_CODE (type) == OFFSET_TYPE)
     type = TREE_TYPE (type);
   if (TREE_CODE (type) == REFERENCE_TYPE)
-    return build_indirect_ref (val, NULL_PTR);
+    return build_indirect_ref (val, NULL);
   return val;
 }
+
+/* Implicitly convert the lvalue EXPR to another lvalue of type TOTYPE,
+   preserving cv-qualification.  */
+
+tree
+convert_lvalue (totype, expr)
+     tree totype, expr;
+{
+  totype = cp_build_qualified_type (totype, TYPE_QUALS (TREE_TYPE (expr)));
+  totype = build_reference_type (totype);
+  expr = convert_to_reference (totype, expr, CONV_IMPLICIT, LOOKUP_NORMAL,
+                              NULL_TREE);
+  return convert_from_reference (expr);
+}
 \f
 /* Call this when we know (for any reason) that expr is not, in fact,
    zero.  This routine is like convert_pointer_to, but it pays
@@ -571,29 +656,29 @@ convert_pointer_to_real (binfo, expr)
       binfo = NULL_TREE;
     }
 
-  ptr_type = cp_build_type_variant (type, TYPE_READONLY (TREE_TYPE (intype)),
-                                   TYPE_VOLATILE (TREE_TYPE (intype)));
+  ptr_type = cp_build_qualified_type (type,
+                                     CP_TYPE_QUALS (TREE_TYPE (intype)));
   ptr_type = build_pointer_type (ptr_type);
-  if (ptr_type == TYPE_MAIN_VARIANT (intype))
+  if (same_type_p (ptr_type, TYPE_MAIN_VARIANT (intype)))
     return expr;
 
   my_friendly_assert (!integer_zerop (expr), 191);
 
+  intype = TYPE_MAIN_VARIANT (TREE_TYPE (intype));
   if (TREE_CODE (type) == RECORD_TYPE
-      && TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE
-      && type != TYPE_MAIN_VARIANT (TREE_TYPE (intype)))
+      && TREE_CODE (intype) == RECORD_TYPE
+      && type != intype)
     {
       tree path;
       int distance
-       = get_base_distance (binfo, TYPE_MAIN_VARIANT (TREE_TYPE (intype)),
-                            0, &path);
+       = get_base_distance (binfo, intype, 0, &path);
 
       /* This function shouldn't be called with unqualified arguments
         but if it is, give them an error message that they can read.  */
       if (distance < 0)
        {
          cp_error ("cannot convert a pointer of type `%T' to a pointer of type `%T'",
-                   TREE_TYPE (intype), type);
+                   intype, type);
 
          if (distance == -2)
            cp_error ("because `%T' is an ambiguous base class", type);
@@ -619,15 +704,7 @@ tree
 convert_pointer_to (binfo, expr)
      tree binfo, expr;
 {
-  tree type;
-
-  if (TREE_CODE (binfo) == TREE_VEC)
-    type = BINFO_TYPE (binfo);
-  else if (IS_AGGR_TYPE (binfo))
-      type = binfo;
-  else
-      type = binfo;
-  return convert_pointer_to_real (type, expr);
+  return convert_pointer_to_real (binfo, expr);
 }
 \f
 /* C++ conversions, preference to static cast conversions.  */
@@ -655,8 +732,10 @@ ocp_convert (type, expr, convtype, flags)
       || TREE_TYPE (e) == error_mark_node)
     return error_mark_node;
 
-  if (TREE_READONLY_DECL_P (e))
-    e = decl_constant_value (e);
+  complete_type (type);
+  complete_type (TREE_TYPE (expr));
+
+  e = decl_constant_value (e);
 
   if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP)
       /* Some internal structures (vtable_entry_type, sigtbl_ptr_type)
@@ -665,18 +744,28 @@ ocp_convert (type, expr, convtype, flags)
       && TYPE_HAS_CONSTRUCTOR (type))
     /* We need a new temporary; don't take this shortcut.  */;
   else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e)))
-    /* Trivial conversion: cv-qualifiers do not matter on rvalues.  */
-    return fold (build1 (NOP_EXPR, type, e));
-  
-  if (code == VOID_TYPE && (convtype & CONV_STATIC))
-    return build1 (CONVERT_EXPR, type, e);
+    {
+      if (same_type_p (type, TREE_TYPE (e)))
+       /* The call to fold will not always remove the NOP_EXPR as
+          might be expected, since if one of the types is a typedef;
+          the comparsion in fold is just equality of pointers, not a
+          call to comptypes.  We don't call fold in this case because
+          that can result in infinite recursion; fold will call
+          convert, which will call ocp_convert, etc.  */
+       return e;
+      /* For complex data types, we need to perform componentwise
+         conversion.  */
+      else if (TREE_CODE (type) == COMPLEX_TYPE)
+        return fold (convert_to_complex (type, e));
+      else
+       return fold (build1 (NOP_EXPR, type, e));
+    }
 
-#if 0
-  /* This is incorrect.  A truncation can't be stripped this way.
-     Extensions will be stripped by the use of get_unwidened.  */
-  if (TREE_CODE (e) == NOP_EXPR)
-    return cp_convert (type, TREE_OPERAND (e, 0));
-#endif
+  if (code == VOID_TYPE && (convtype & CONV_STATIC))
+    {
+      e = convert_to_void (e, /*implicit=*/NULL);
+      return e;
+    }
 
   /* Just convert to the type of the member.  */
   if (code == OFFSET_TYPE)
@@ -685,13 +774,6 @@ ocp_convert (type, expr, convtype, flags)
       code = TREE_CODE (type);
     }
 
-#if 0
-  if (code == REFERENCE_TYPE)
-    return fold (convert_to_reference (type, e, convtype, flags, NULL_TREE));
-  else if (TREE_CODE (TREE_TYPE (e)) == REFERENCE_TYPE)
-    e = convert_from_reference (e);
-#endif
-
   if (TREE_CODE (e) == OFFSET_REF)
     e = resolve_offset_ref (e);
 
@@ -700,8 +782,7 @@ ocp_convert (type, expr, convtype, flags)
       tree intype = TREE_TYPE (e);
       /* enum = enum, enum = int, enum = float, (enum)pointer are all
          errors.  */
-      if (flag_int_enum_equivalence == 0
-         && TREE_CODE (type) == ENUMERAL_TYPE
+      if (TREE_CODE (type) == ENUMERAL_TYPE
          && ((ARITHMETIC_TYPE_P (intype) && ! (convtype & CONV_STATIC))
              || (TREE_CODE (intype) == POINTER_TYPE)))
        {
@@ -713,7 +794,7 @@ ocp_convert (type, expr, convtype, flags)
       if (IS_AGGR_TYPE (intype))
        {
          tree rval;
-         rval = build_type_conversion (CONVERT_EXPR, type, e, 1);
+         rval = build_type_conversion (type, e, 1);
          if (rval)
            return rval;
          if (flags & LOOKUP_COMPLAIN)
@@ -724,23 +805,32 @@ ocp_convert (type, expr, convtype, flags)
        }
       if (code == BOOLEAN_TYPE)
        {
+         tree fn = NULL_TREE;
+
          /* Common Ada/Pascal programmer's mistake.  We always warn
              about this since it is so bad.  */
          if (TREE_CODE (expr) == FUNCTION_DECL)
-           cp_warning ("the address of `%D', will always be `true'", expr);
-         return truthvalue_conversion (e);
+           fn = expr;
+         else if (TREE_CODE (expr) == ADDR_EXPR 
+                  && TREE_CODE (TREE_OPERAND (expr, 0)) == FUNCTION_DECL)
+           fn = TREE_OPERAND (expr, 0);
+         if (fn && !DECL_WEAK (fn))
+           cp_warning ("the address of `%D', will always be `true'", fn);
+         return cp_truthvalue_conversion (e);
        }
       return fold (convert_to_integer (type, e));
     }
   if (code == POINTER_TYPE || code == REFERENCE_TYPE
       || TYPE_PTRMEMFUNC_P (type))
-    return fold (cp_convert_to_pointer (type, e));
+    return fold (cp_convert_to_pointer (type, e, 0));
+  if (code == VECTOR_TYPE)
+    return fold (convert_to_vector (type, e));
   if (code == REAL_TYPE || code == COMPLEX_TYPE)
     {
       if (IS_AGGR_TYPE (TREE_TYPE (e)))
        {
          tree rval;
-         rval = build_type_conversion (CONVERT_EXPR, type, e, 1);
+         rval = build_type_conversion (type, e, 1);
          if (rval)
            return rval;
          else
@@ -764,29 +854,6 @@ ocp_convert (type, expr, convtype, flags)
 
       dtype = TYPE_MAIN_VARIANT (dtype);
 
-      /* Conversion of object pointers or signature pointers/references
-        to signature pointers/references.  */
-
-      if (TYPE_LANG_SPECIFIC (type)
-         && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
-       {
-         tree constructor = build_signature_pointer_constructor (type, expr);
-         tree sig_ty = SIGNATURE_TYPE (type);
-         tree sig_ptr;
-
-         if (constructor == error_mark_node)
-           return error_mark_node;
-
-         sig_ptr = get_temp_name (type, 1);
-         DECL_INITIAL (sig_ptr) = constructor;
-         CLEAR_SIGNATURE (sig_ty);
-         cp_finish_decl (sig_ptr, constructor, NULL_TREE, 0, 0);
-         SET_SIGNATURE (sig_ty);
-         TREE_READONLY (sig_ptr) = 1;
-
-         return sig_ptr;
-       }
-
       /* Conversion between aggregate types.  New C++ semantics allow
         objects of derived type to be cast to objects of base type.
         Old semantics only allowed this between pointers.
@@ -796,15 +863,19 @@ ocp_convert (type, expr, convtype, flags)
 
       ctor = e;
 
+      if (abstract_virtuals_error (NULL_TREE, type))
+       return error_mark_node;
+
       if ((flags & LOOKUP_ONLYCONVERTING)
          && ! (IS_AGGR_TYPE (dtype) && DERIVED_FROM_P (type, dtype)))
        /* For copy-initialization, first we create a temp of the proper type
           with a user-defined conversion sequence, then we direct-initialize
           the target with the temp (see [dcl.init]).  */
        ctor = build_user_type_conversion (type, ctor, flags);
-      if (ctor)
-       ctor = build_method_call (NULL_TREE, ctor_identifier,
-                                 build_expr_list (NULL_TREE, ctor),
+      else
+       ctor = build_method_call (NULL_TREE, 
+                                 complete_ctor_identifier,
+                                 build_tree_list (NULL_TREE, ctor),
                                  TYPE_BINFO (type), flags);
       if (ctor)
        return build_cplus_new (type, ctor);
@@ -826,6 +897,147 @@ ocp_convert (type, expr, convtype, flags)
   return error_mark_node;
 }
 
+/* When an expression is used in a void context, its value is discarded and
+   no lvalue-rvalue and similar conversions happen [expr.static.cast/4,
+   stmt.expr/1, expr.comma/1].  This permits dereferencing an incomplete type
+   in a void context. The C++ standard does not define what an `access' to an
+   object is, but there is reason to beleive that it is the lvalue to rvalue
+   conversion -- if it were not, `*&*p = 1' would violate [expr]/4 in that it
+   accesses `*p' not to calculate the value to be stored. But, dcl.type.cv/8
+   indicates that volatile semantics should be the same between C and C++
+   where ever possible. C leaves it implementation defined as to what
+   constitutes an access to a volatile. So, we interpret `*vp' as a read of
+   the volatile object `vp' points to, unless that is an incomplete type. For
+   volatile references we do not do this interpretation, because that would
+   make it impossible to ignore the reference return value from functions. We
+   issue warnings in the confusing cases.
+   
+   IMPLICIT is tells us the context of an implicit void conversion.  */
+
+tree
+convert_to_void (expr, implicit)
+     tree expr;
+     const char *implicit;
+{
+  if (expr == error_mark_node 
+      || TREE_TYPE (expr) == error_mark_node)
+    return error_mark_node;
+  if (!TREE_TYPE (expr))
+    return expr;
+  if (VOID_TYPE_P (TREE_TYPE (expr)))
+    return expr;
+  switch (TREE_CODE (expr))
+    {
+    case COND_EXPR:
+      {
+        /* The two parts of a cond expr might be separate lvalues.  */
+        tree op1 = TREE_OPERAND (expr,1);
+        tree op2 = TREE_OPERAND (expr,2);
+        tree new_op1 = convert_to_void (op1, implicit);
+        tree new_op2 = convert_to_void (op2, implicit);
+        
+        if (new_op1 != op1 || new_op2 != op2)
+          expr = build (COND_EXPR,
+                        implicit ? TREE_TYPE (expr) : void_type_node,
+                        TREE_OPERAND (expr, 0), new_op1, new_op2);
+        break;
+      }
+    
+    case COMPOUND_EXPR:
+      {
+        /* The second part of a compound expr contains the value.  */
+        tree op1 = TREE_OPERAND (expr,1);
+        tree new_op1 = convert_to_void (op1, implicit);
+        
+        if (new_op1 != op1)
+         {
+           tree t = build (COMPOUND_EXPR, TREE_TYPE (new_op1),
+                           TREE_OPERAND (expr, 0), new_op1);
+           TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (expr);
+           expr = t;
+         }
+
+        break;
+      }
+    
+    case NON_LVALUE_EXPR:
+    case NOP_EXPR:
+      /* These have already decayed to rvalue. */
+      break;
+    
+    case CALL_EXPR:   /* we have a special meaning for volatile void fn() */
+      break;
+    
+    case INDIRECT_REF:
+      {
+        tree type = TREE_TYPE (expr);
+        int is_reference = TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0)))
+                           == REFERENCE_TYPE;
+        int is_volatile = TYPE_VOLATILE (type);
+        int is_complete = COMPLETE_TYPE_P (complete_type (type));
+        
+        if (is_volatile && !is_complete)
+          cp_warning ("object of incomplete type `%T' will not be accessed in %s",
+                      type, implicit ? implicit : "void context");
+        else if (is_reference && is_volatile)
+          cp_warning ("object of type `%T' will not be accessed in %s",
+                      TREE_TYPE (TREE_OPERAND (expr, 0)),
+                      implicit ? implicit : "void context");
+        if (is_reference || !is_volatile || !is_complete)
+          expr = TREE_OPERAND (expr, 0);
+      
+        break;
+      }
+    
+    case VAR_DECL:
+      {
+        /* External variables might be incomplete.  */
+        tree type = TREE_TYPE (expr);
+        int is_complete = COMPLETE_TYPE_P (complete_type (type));
+        
+        if (TYPE_VOLATILE (type) && !is_complete)
+          cp_warning ("object `%E' of incomplete type `%T' will not be accessed in %s",
+                      expr, type, implicit ? implicit : "void context");
+        break;
+      }
+
+    case OFFSET_REF:
+      expr = resolve_offset_ref (expr);
+      break;
+
+    default:;
+    }
+  {
+    tree probe = expr;
+  
+    if (TREE_CODE (probe) == ADDR_EXPR)
+      probe = TREE_OPERAND (expr, 0);
+    if (type_unknown_p (probe))
+      {
+       /* [over.over] enumerates the places where we can take the address
+          of an overloaded function, and this is not one of them.  */
+       cp_pedwarn ("%s cannot resolve address of overloaded function",
+                   implicit ? implicit : "void cast");
+      }
+    else if (implicit && probe == expr && is_overloaded_fn (probe))
+      /* Only warn when there is no &.  */
+      cp_warning ("%s is a reference, not call, to function `%E'",
+                 implicit, expr);
+  }
+  
+  if (expr != error_mark_node && !VOID_TYPE_P (TREE_TYPE (expr)))
+    {
+      /* FIXME: This is where we should check for expressions with no
+         effects.  At the moment we do that in both build_x_component_expr
+         and expand_expr_stmt -- inconsistently too.  For the moment
+         leave implicit void conversions unadorned so that expand_expr_stmt
+         has a chance of detecting some of the cases.  */
+      if (!implicit)
+        expr = build1 (CONVERT_EXPR, void_type_node, expr);
+    }
+  return expr;
+}
+
 /* Create an expression whose value is that of EXPR,
    converted to type TYPE.  The TREE_TYPE of the value
    is always TYPE.  This function implements all reasonable
@@ -838,7 +1050,7 @@ ocp_convert (type, expr, convtype, flags)
    conversions to/from basetypes may involve memory references
    (vbases) and adding or subtracting small values (multiple
    inheritance), but it calls convert from the constant folding code
-   on subtrees of already build trees after it has ripped them apart.
+   on subtrees of already built trees after it has ripped them apart.
 
    Also, if we ever support range variables, we'll probably also have to
    do a little bit more work.  */
@@ -856,8 +1068,7 @@ convert (type, expr)
 
   if (POINTER_TYPE_P (type) && POINTER_TYPE_P (intype))
     {
-      if (TREE_READONLY_DECL_P (expr))
-       expr = decl_constant_value (expr);
+      expr = decl_constant_value (expr);
       return fold (build1 (NOP_EXPR, type, expr));
     }
 
@@ -920,8 +1131,7 @@ convert_force (type, expr, convtype)
    (jason 8/9/95)  */
 
 tree
-build_type_conversion (code, xtype, expr, for_sure)
-     enum tree_code code;
+build_type_conversion (xtype, expr, for_sure)
      tree xtype, expr;
      int for_sure;
 {
@@ -943,7 +1153,7 @@ build_expr_type_conversion (desires, expr, complain)
      int complain;
 {
   tree basetype = TREE_TYPE (expr);
-  tree conv;
+  tree conv = NULL_TREE;
   tree winner = NULL_TREE;
 
   if (expr == null_node 
@@ -951,11 +1161,14 @@ build_expr_type_conversion (desires, expr, complain)
       && !(desires & WANT_NULL))
     cp_warning ("converting NULL to non-pointer type");
     
-  if (TREE_CODE (basetype) == OFFSET_TYPE)
+  if (TREE_CODE (expr) == OFFSET_REF)
     expr = resolve_offset_ref (expr);
   expr = convert_from_reference (expr);
   basetype = TREE_TYPE (expr);
 
+  if (basetype == error_mark_node)
+    return error_mark_node;
+
   if (! IS_AGGR_TYPE (basetype))
     switch (TREE_CODE (basetype))
       {
@@ -1051,13 +1264,12 @@ tree
 type_promotes_to (type)
      tree type;
 {
-  int constp, volatilep;
+  int type_quals;
 
   if (type == error_mark_node)
     return error_mark_node;
 
-  constp = TYPE_READONLY (type);
-  volatilep = TYPE_VOLATILE (type);
+  type_quals = CP_TYPE_QUALS (type);
   type = TYPE_MAIN_VARIANT (type);
 
   /* bool always promotes to int (not unsigned), even if it's the same
@@ -1079,7 +1291,7 @@ type_promotes_to (type)
       else
        type = totype;
     }
-  else if (C_PROMOTING_INTEGER_TYPE_P (type))
+  else if (c_promoting_integer_type_p (type))
     {
       /* Retain unsignedness if really not getting bigger.  */
       if (TREE_UNSIGNED (type)
@@ -1091,10 +1303,9 @@ type_promotes_to (type)
   else if (type == float_type_node)
     type = double_type_node;
 
-  return cp_build_type_variant (type, constp, volatilep);
+  return cp_build_qualified_type (type, type_quals);
 }
 
-
 /* The routines below this point are carefully written to conform to
    the standard.  They use the same terminology, and follow the rules
    closely.  Although they are used only in pt.c at the moment, they
@@ -1109,7 +1320,9 @@ perform_qualification_conversions (type, expr)
      tree type;
      tree expr;
 {
-  if (comp_target_types (type, TREE_TYPE (expr), 0) == 1)
+  if (TREE_CODE (type) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
+      && comp_ptr_ttypes (TREE_TYPE (type), TREE_TYPE (TREE_TYPE (expr))))
     return build1 (NOP_EXPR, type, expr);
   else
     return error_mark_node;