OSDN Git Service

1999-11-25 Mark Mitchell <mark@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index 6ca5adc..0bfb99c 100644 (file)
@@ -34,10 +34,12 @@ Boston, MA 02111-1307, USA.  */
 #include "tree.h"
 #include "rtl.h"
 #include "cp-tree.h"
+#include "tm_p.h"
 #include "flags.h"
 #include "output.h"
 #include "expr.h"
 #include "toplev.h"
+#include "defaults.h"
 
 static tree convert_for_assignment PROTO((tree, tree, const char *, tree,
                                          int));
@@ -47,6 +49,7 @@ static int comp_target_parms PROTO((tree, tree, int));
 static int comp_ptr_ttypes_real PROTO((tree, tree, int));
 static int comp_ptr_ttypes_const PROTO((tree, tree));
 static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
+static int comp_except_types PROTO((tree, tree, int));
 static int comp_array_types PROTO((int (*) (tree, tree, int), tree,
                                   tree, int));
 static tree common_base_type PROTO((tree, tree));
@@ -59,8 +62,11 @@ static tree build_component_addr PROTO((tree, tree));
 static tree qualify_type PROTO((tree, tree));
 static tree get_delta_difference PROTO((tree, tree, int));
 static int comp_cv_target_types PROTO((tree, tree, int));
+static void casts_away_constness_r PROTO((tree *, tree *));
+static int casts_away_constness PROTO ((tree, tree));
+static void maybe_warn_about_returning_address_of_local PROTO ((tree));
 
-/* Return the target type of TYPE, which meas return T for:
+/* Return the target type of TYPE, which means return T for:
    T*, T&, T[], T (...), and otherwise, just T.  */
 
 tree
@@ -99,10 +105,7 @@ require_complete_type (value)
 
   /* First, detect a valid value with a complete type.  */
   if (TYPE_SIZE (type) != 0
-      && TYPE_SIZE (type) != size_zero_node
-      && ! (TYPE_LANG_SPECIFIC (type)
-           && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type))
-           && TYPE_SIZE (SIGNATURE_TYPE (type)) == 0))
+      && TYPE_SIZE (type) != size_zero_node)
     return value;
 
   /* If we see X::Y, we build an OFFSET_TYPE which has
@@ -127,99 +130,6 @@ require_complete_type (value)
     return error_mark_node;
 }
 
-/* Makes sure EXPR is a complete type when used in a void context, like a
-   whole expression, or lhs of a comma operator. Issue a diagnostic and
-   return error_mark_node on failure. This is a little tricky, because some
-   valid void types look stunningly similar to invalid void types. We err on
-   the side of caution */
-
-tree
-require_complete_type_in_void (expr)
-     tree expr;
-{
-  switch (TREE_CODE (expr))
-    {
-    case COND_EXPR:
-      {
-        tree op;
-        
-        op = TREE_OPERAND (expr,2);
-        op = require_complete_type_in_void (op);
-        TREE_OPERAND (expr,2) = op;
-        if (op == error_mark_node)
-          {
-            expr = op;
-            break;
-          }
-        
-        /* fallthrough */
-      }
-    
-    case COMPOUND_EXPR:
-      {
-        tree op;
-        
-        op = TREE_OPERAND (expr,1);
-        op = require_complete_type_in_void (op);
-        TREE_OPERAND (expr,1) = op;
-        if (op == error_mark_node)
-          {
-            expr = op;
-            break;
-          }
-        
-        break;
-      }
-    
-    case NON_LVALUE_EXPR:
-    case NOP_EXPR:
-      {
-        tree op;
-        
-        op = TREE_OPERAND (expr,0);
-        op = require_complete_type_in_void (op);
-        TREE_OPERAND (expr,0) = op;
-        if (op == error_mark_node)
-          {
-            expr = op;
-            break;
-          }
-        break;
-      }
-    
-    case CALL_EXPR:   /* function call return can be ignored */
-    case RTL_EXPR:    /* RTL nodes have no value */
-    case DELETE_EXPR: /* delete expressions have no type */
-    case VEC_DELETE_EXPR:
-    case INTEGER_CST: /* used for null pointer */
-    case EXIT_EXPR:   /* have no return */
-    case LOOP_EXPR:   /* have no return */
-    case BIND_EXPR:   /* have no return */
-    case THROW_EXPR:  /* have no return */
-    case MODIFY_EXPR: /* sometimes this has a void type, but that's ok */
-    case CONVERT_EXPR:  /* sometimes has a void type */
-      break;
-    
-    case INDIRECT_REF:
-      {
-        tree op = TREE_OPERAND (expr,0);
-        
-        /* Calling a function returning a reference has an implicit
-           dereference applied. We don't want to make that an error. */
-        if (TREE_CODE (op) == CALL_EXPR
-            && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE)
-          break;
-        /* else fallthrough */
-      }
-    
-    default:
-      expr = require_complete_type (expr);
-      break;
-    }
-
-  return expr;
-}
-
 /* Try to complete TYPE, if it is incomplete.  For example, if TYPE is
    a template instantiation, do the instantiation.  Returns TYPE,
    whether or not it could be completed, unless something goes
@@ -401,6 +311,191 @@ original_type (t)
   return t;
 }
 
+/* T1 and T2 are arithmetic or enumeration types.  Return the type
+   that will result from the "usual arithmetic converions" on T1 and
+   T2 as described in [expr].  */
+
+tree
+type_after_usual_arithmetic_conversions (t1, t2)
+     tree t1;
+     tree t2;
+{
+  enum tree_code code1 = TREE_CODE (t1);
+  enum tree_code code2 = TREE_CODE (t2);
+  tree attributes;
+
+  /* FIXME: Attributes.  */
+  my_friendly_assert (ARITHMETIC_TYPE_P (t1) 
+                     || TREE_CODE (t1) == ENUMERAL_TYPE,
+                     19990725);
+  my_friendly_assert (ARITHMETIC_TYPE_P (t2) 
+                     || TREE_CODE (t2) == ENUMERAL_TYPE,
+                     19990725);
+
+  /* In what follows, we slightly generalize the rules given in [expr]
+     so as to deal with `long long'.  First, merge the attributes.  */
+  attributes = merge_machine_type_attributes (t1, t2);
+
+  /* If only one is real, use it as the result.  */
+  if (code1 == REAL_TYPE && code2 != REAL_TYPE)
+    return build_type_attribute_variant (t1, attributes);
+  if (code2 == REAL_TYPE && code1 != REAL_TYPE)
+    return build_type_attribute_variant (t2, attributes);
+
+  /* Perform the integral promotions.  */
+  if (code1 != REAL_TYPE)
+    {
+      t1 = type_promotes_to (t1);
+      t2 = type_promotes_to (t2);
+    }
+
+  /* Both real or both integers; use the one with greater precision.  */
+  if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
+    return build_type_attribute_variant (t1, attributes);
+  else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
+    return build_type_attribute_variant (t2, attributes);
+
+  if (code1 != REAL_TYPE)
+    {
+      /* If one is unsigned long long, then convert the other to unsigned
+        long long.  */
+      if (same_type_p (TYPE_MAIN_VARIANT (t1), long_long_unsigned_type_node)
+         || same_type_p (TYPE_MAIN_VARIANT (t2), long_long_unsigned_type_node))
+       return build_type_attribute_variant (long_long_unsigned_type_node,
+                                            attributes);
+      /* If one is a long long, and the other is an unsigned long, and
+        long long can represent all the values of an unsigned long, then
+        convert to a long long.  Otherwise, convert to an unsigned long
+        long.  Otherwise, if either operand is long long, convert the
+        other to long long.
+        
+        Since we're here, we know the TYPE_PRECISION is the same;
+        therefore converting to long long cannot represent all the values
+        of an unsigned long, so we choose unsigned long long in that
+        case.  */
+      if (same_type_p (TYPE_MAIN_VARIANT (t1), long_long_integer_type_node)
+         || same_type_p (TYPE_MAIN_VARIANT (t2), long_long_integer_type_node))
+       {
+         tree t = ((TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
+                   ? long_long_unsigned_type_node 
+                   : long_long_integer_type_node);
+         return build_type_attribute_variant (t, attributes);
+       }
+      
+      /* Go through the same procedure, but for longs.  */
+      if (same_type_p (TYPE_MAIN_VARIANT (t1), long_unsigned_type_node)
+         || same_type_p (TYPE_MAIN_VARIANT (t2), long_unsigned_type_node))
+       return build_type_attribute_variant (long_unsigned_type_node,
+                                            attributes);
+      if (same_type_p (TYPE_MAIN_VARIANT (t1), long_integer_type_node)
+         || same_type_p (TYPE_MAIN_VARIANT (t2), long_integer_type_node))
+       {
+         tree t = ((TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
+                   ? long_unsigned_type_node : long_integer_type_node);
+         return build_type_attribute_variant (t, attributes);
+       }
+      /* Otherwise prefer the unsigned one.  */
+      if (TREE_UNSIGNED (t1))
+       return build_type_attribute_variant (t1, attributes);
+      else
+       return build_type_attribute_variant (t2, attributes);
+    }
+  else
+    {
+      if (same_type_p (TYPE_MAIN_VARIANT (t1), long_double_type_node)
+         || same_type_p (TYPE_MAIN_VARIANT (t2), long_double_type_node))
+       return build_type_attribute_variant (long_double_type_node,
+                                            attributes);
+      if (same_type_p (TYPE_MAIN_VARIANT (t1), double_type_node)
+         || same_type_p (TYPE_MAIN_VARIANT (t2), double_type_node))
+       return build_type_attribute_variant (double_type_node,
+                                            attributes);
+      else 
+       return build_type_attribute_variant (float_type_node,
+                                            attributes);
+    }
+}
+
+/* Return the composite pointer type (see [expr.rel]) for T1 and T2.
+   ARG1 and ARG2 are the values with those types.  The LOCATION is a
+   string describing the current location, in case an error occurs.  */
+
+tree 
+composite_pointer_type (t1, t2, arg1, arg2, location)
+     tree t1;
+     tree t2;
+     tree arg1;
+     tree arg2;
+     const char* location;
+{
+  tree result_type;
+
+  /* [expr.rel]
+
+     If one operand is a null pointer constant, the composite pointer
+     type is the type of the other operand.  */
+  if (null_ptr_cst_p (arg1))
+    return t2;
+  if (null_ptr_cst_p (arg2))
+    return t1;
+  /* Deal with pointer-to-member functions in the same way as we deal
+     with pointers to functions. */
+  if (TYPE_PTRMEMFUNC_P (t1))
+    t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+  if (TYPE_PTRMEMFUNC_P (t2))
+    t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+  
+  if (comp_target_types (t1, t2, 1))
+    result_type = common_type (t1, t2);
+  else if (TYPE_MAIN_VARIANT (TREE_TYPE (t1)) == void_type_node)
+    {
+      if (pedantic && TREE_CODE (t2) == FUNCTION_TYPE)
+       pedwarn ("ANSI C++ forbids %s between `void *' and function pointer",
+                location);
+      result_type = qualify_type (t1, t2);
+    }
+  else if (TYPE_MAIN_VARIANT (TREE_TYPE (t2)) == void_type_node)
+    {
+      if (pedantic && TREE_CODE (t1) == FUNCTION_TYPE)
+       pedwarn ("ANSI C++ forbids %s between `void *' and function pointer",
+                location);
+      result_type = qualify_type (t2, t1);
+    }
+  /* C++ */
+  else if (same_or_base_type_p (t2, t1))
+    result_type = t2;
+  else if (IS_AGGR_TYPE (TREE_TYPE (t1))
+          && IS_AGGR_TYPE (TREE_TYPE (t2))
+          && (result_type = common_base_type (TREE_TYPE (t1),
+                                              TREE_TYPE (t2))))
+    {
+      if (result_type == error_mark_node)
+       {
+         cp_error ("common base type of types `%T' and `%T' is ambiguous",
+                   TREE_TYPE (t1), TREE_TYPE (t2));
+         result_type = ptr_type_node;
+       }
+      else
+       {
+         if (pedantic
+             && result_type != TREE_TYPE (t1)
+             && result_type != TREE_TYPE (t2))
+           cp_pedwarn ("`%T' and `%T' converted to `%T *' in %s",
+                       t1, t2, result_type, location);
+         
+         result_type = build_pointer_type (result_type);
+       }
+    }
+  else
+    {
+      cp_pedwarn ("pointer type mismatch in %s", location);
+      result_type = ptr_type_node;
+    }
+
+  return result_type;
+}
+
 /* Return the common type of two types.
    We assume that comptypes has already been done and returned 1;
    if that isn't so, this may crash.
@@ -433,44 +528,13 @@ common_type (t1, t2)
   if (t2 == error_mark_node)
     return t1;
 
+  if ((ARITHMETIC_TYPE_P (t1) || TREE_CODE (t1) == ENUMERAL_TYPE)
+      && (ARITHMETIC_TYPE_P (t2) || TREE_CODE (t2) == ENUMERAL_TYPE))
+    return type_after_usual_arithmetic_conversions (t1, t2);
+
   /* Merge the attributes.  */
   attributes = merge_machine_type_attributes (t1, t2);
 
-  { register tree a1, a2;
-    a1 = TYPE_ATTRIBUTES (t1);
-    a2 = TYPE_ATTRIBUTES (t2);
-
-    /* Either one unset?  Take the set one.  */
-
-    if (!(attributes = a1))
-       attributes = a2;
-
-    /* One that completely contains the other?  Take it.  */
-
-    else if (a2 && !attribute_list_contained (a1, a2))
-      {
-       if (attribute_list_contained (a2, a1))
-         attributes = a2;
-       else
-         {
-           /* Pick the longest list, and hang on the other list.  */
-           /* ??? For the moment we punt on the issue of attrs with args.  */
-       
-           if (list_length (a1) < list_length (a2))
-             attributes = a2, a2 = a1;
-
-           for (; a2; a2 = TREE_CHAIN (a2))
-             if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
-                                   attributes) == NULL_TREE)
-               {
-                 a1 = copy_node (a2);
-                 TREE_CHAIN (a1) = attributes;
-                 attributes = a1;
-               }
-         }
-      }
-  }
-
   /* Treat an enum type as the unsigned integer type of the same width.  */
 
   if (TREE_CODE (t1) == ENUMERAL_TYPE)
@@ -508,51 +572,10 @@ common_type (t1, t2)
     {
     case INTEGER_TYPE:
     case REAL_TYPE:
-      /* If only one is real, use it as the result.  */
-
-      if (code1 == REAL_TYPE && code2 != REAL_TYPE)
-       return build_type_attribute_variant (t1, attributes);
-
-      if (code2 == REAL_TYPE && code1 != REAL_TYPE)
-        return build_type_attribute_variant (t2, attributes);
-
-      /* Both real or both integers; use the one with greater precision.  */
-
-      if (TYPE_PRECISION (t1) > TYPE_PRECISION (t2))
-       return build_type_attribute_variant (t1, attributes);
-      else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
-        return build_type_attribute_variant (t2, attributes);
-
-      /* Same precision.  Prefer longs to ints even when same size.  */
-  
-      if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
-         || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node)
-        return build_type_attribute_variant (long_unsigned_type_node,
-                                            attributes);
-
-      if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node
-         || TYPE_MAIN_VARIANT (t2) == long_integer_type_node)
-       {
-         /* But preserve unsignedness from the other type,
-            since long cannot hold all the values of an unsigned int.  */
-         if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
-            t1 = long_unsigned_type_node;
-         else
-            t1 = long_integer_type_node;
-         return build_type_attribute_variant (t1, attributes);
-       }
-
-      if (TYPE_MAIN_VARIANT (t1) == long_double_type_node
-         || TYPE_MAIN_VARIANT (t2) == long_double_type_node)
-       return build_type_attribute_variant (long_double_type_node,
-                                            attributes);         
-
-      /* Otherwise prefer the unsigned one.  */
-
-      if (TREE_UNSIGNED (t1))
-       return build_type_attribute_variant (t1, attributes);
-      else
-       return build_type_attribute_variant (t2, attributes);
+      /* We should have called type_after_usual_arithmetic_conversions
+        above.  */
+      my_friendly_abort (19990725);
+      break;
 
     case POINTER_TYPE:
     case REFERENCE_TYPE:
@@ -584,11 +607,6 @@ common_type (t1, t2)
 
        if (tt1 == tt2)
          target = tt1;
-       else if (b1)
-         {
-           compiler_error ("common_type called with uncommon member types");
-           target = tt1;
-         }
        else if (tt1 == void_type_node || tt2 == void_type_node)
          target = void_type_node;
        else if (tt1 == unknown_type_node)
@@ -737,13 +755,102 @@ common_type (t1, t2)
     }
 }
 \f
-/* Return 1 if TYPE1 and TYPE2 raise the same exceptions.  */
+/* Compare two exception specifier types for exactness or subsetness, if
+   allowed. Returns 0 for mismatch, 1 for same, 2 if B is allowed by A.
+   [except.spec] "If a class X ... objects of class X or any class publicly
+   and unambigously derrived from X. Similarly, if a pointer type Y * ...
+   exceptions of type Y * or that are pointers to any type publicly and
+   unambigously derrived from Y. Otherwise a function only allows exceptions
+   that have the same type ..."
+   This does not mention cv qualifiers and is different to what throw
+   [except.throw] and catch [except.catch] will do. They will ignore the
+   top level cv qualifiers, and allow qualifiers in the pointer to class
+   example.
+   
+   We implement the letter of the standard.  */
+
+static int
+comp_except_types (a, b, exact)
+     tree a, b;
+     int exact;
+{
+  if (same_type_p (a, b))
+    return 1;
+  else if (!exact)
+    {
+      if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
+        return 0;
+      
+      if (TREE_CODE (a) == POINTER_TYPE
+          && TREE_CODE (b) == POINTER_TYPE)
+        {
+          a = TREE_TYPE (a);
+          b = TREE_TYPE (b);
+          if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
+            return 0;
+        }
+      
+      if (TREE_CODE (a) != RECORD_TYPE
+          || TREE_CODE (b) != RECORD_TYPE)
+        return 0;
+      
+      if (ACCESSIBLY_UNIQUELY_DERIVED_P (a, b))
+        return 2;
+    }
+  return 0;
+}
+
+/* Return 1 if TYPE1 and TYPE2 are equivalent exception specifiers.
+   If EXACT is 0, T2 can be a subset of T1 (according to 15.4/7),
+   otherwise it must be exact. Exception lists are unordered, but
+   we've already filtered out duplicates. Most lists will be in order,
+   we should try to make use of that.  */
 
 int
-compexcepttypes (t1, t2)
+comp_except_specs (t1, t2, exact)
      tree t1, t2;
+     int exact;
 {
-  return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
+  tree probe;
+  tree base;
+  int  length = 0;
+
+  if (t1 == t2)
+    return 1;
+  
+  if (t1 == NULL_TREE)              /* T1 is ... */
+    return t2 == NULL_TREE || !exact;
+  if (!TREE_VALUE (t1)) /* t1 is EMPTY */
+    return t2 != NULL_TREE && !TREE_VALUE (t2);
+  if (t2 == NULL_TREE)              /* T2 is ... */
+    return 0;
+  if (TREE_VALUE(t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
+    return !exact;
+  
+  /* Neither set is ... or EMPTY, make sure each part of T2 is in T1.
+     Count how many we find, to determine exactness. For exact matching and
+     ordered T1, T2, this is an O(n) operation, otherwise its worst case is
+     O(nm).  */
+  for (base = t1; t2 != NULL_TREE; t2 = TREE_CHAIN (t2))
+    {
+      for (probe = base; probe != NULL_TREE; probe = TREE_CHAIN (probe))
+        {
+          tree a = TREE_VALUE (probe);
+          tree b = TREE_VALUE (t2);
+          
+          if (comp_except_types (a, b, exact))
+            {
+              if (probe == base && exact)
+                base = TREE_CHAIN (probe);
+              length++;
+              break;
+            }
+        }
+      if (probe == NULL_TREE)
+        return 0;
+    }
+  return !exact || base == NULL_TREE || length == list_length (t1);
 }
 
 /* Compare the array types T1 and T2, using CMP as the type comparison
@@ -795,17 +902,16 @@ comp_array_types (cmp, t1, t2, strict)
                            TYPE_MAX_VALUE (d2)));
 }
 
-/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
-   or various other operations.  STRICT is a bitwise-or of the
-   COMPARE_* flags.  */
+/* Return 1 if T1 and T2 are compatible types for assignment or
+   various other operations.  STRICT is a bitwise-or of the COMPARE_*
+   flags.  */
 
 int
-comptypes (type1, type2, strict)
-     tree type1, type2;
+comptypes (t1, t2, strict)
+     tree t1;
+     tree t2;
      int strict;
 {
-  register tree t1 = type1;
-  register tree t2 = type2;
   int attrval, val;
   int orig_strict = strict;
 
@@ -904,15 +1010,9 @@ comptypes (type1, type2, strict)
                                  TYPE_TI_ARGS (t2));
     look_hard:
       if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2))
-       {
-         val = 1;
-         break;
-       }
-      if ((strict & COMPARE_RELAXED) && DERIVED_FROM_P (t2, t1))
-       {
-         val = 1;
-         break;
-       }
+       val = 1;
+      else if ((strict & COMPARE_RELAXED) && DERIVED_FROM_P (t2, t1))
+       val = 1;
       break;
 
     case OFFSET_TYPE:
@@ -922,7 +1022,8 @@ comptypes (type1, type2, strict)
       break;
 
     case METHOD_TYPE:
-      if (! compexcepttypes (t1, t2))
+      if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
+                              TYPE_RAISES_EXCEPTIONS (t2), 1))
        return 0;
 
       /* This case is anti-symmetrical!
@@ -949,7 +1050,8 @@ comptypes (type1, type2, strict)
       break;
 
     case FUNCTION_TYPE:
-      if (! compexcepttypes (t1, t2))
+      if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
+                              TYPE_RAISES_EXCEPTIONS (t2), 1))
        return 0;
 
       val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
@@ -973,6 +1075,9 @@ comptypes (type1, type2, strict)
        return 0;
       return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
 
+    case COMPLEX_TYPE:
+      return same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+
     default:
       break;
     }
@@ -1355,8 +1460,13 @@ comp_target_parms (parms1, parms2, strict)
 
   if (t1 == 0 && t2 != 0)
     {
-      cp_pedwarn ("ANSI C++ prohibits conversion from `(%#T)' to `(...)'",
-                 parms2);
+      if (! flag_strict_prototype && t2 == void_list_node)
+       /* t1 might be the arglist of a function pointer in extern "C"
+          declared to take (), which we fudged to (...).  Don't make the
+          user pay for our mistake.  */;
+      else
+       cp_pedwarn ("ANSI C++ prohibits conversion from `%#T' to `(...)'",
+                   parms2);
       return self_promoting_args_p (t2);
     }
   if (t2 == 0)
@@ -1421,128 +1531,7 @@ comp_target_parms (parms1, parms2, strict)
     }
   return warn_contravariance ? -1 : 1;
 }
-
-/* Return 1 if PARMS specifies a fixed number of parameters
-   and none of their types is affected by default promotions.  */
-
-int
-self_promoting_args_p (parms)
-     tree parms;
-{
-  register tree t;
-  for (t = parms; t; t = TREE_CHAIN (t))
-    {
-      register tree type = TREE_VALUE (t);
-
-      if (TREE_CHAIN (t) == 0 && type != void_type_node)
-       return 0;
-
-      if (type == 0)
-       return 0;
-
-      if (TYPE_MAIN_VARIANT (type) == float_type_node)
-       return 0;
-
-      if (C_PROMOTING_INTEGER_TYPE_P (type))
-       return 0;
-    }
-  return 1;
-}
 \f
-/* Return an unsigned type the same as TYPE in other respects.
-
-   C++: must make these work for type variants as well.  */
-
-tree
-unsigned_type (type)
-     tree type;
-{
-  tree type1 = TYPE_MAIN_VARIANT (type);
-  if (type1 == signed_char_type_node || type1 == char_type_node)
-    return unsigned_char_type_node;
-  if (type1 == integer_type_node)
-    return unsigned_type_node;
-  if (type1 == short_integer_type_node)
-    return short_unsigned_type_node;
-  if (type1 == long_integer_type_node)
-    return long_unsigned_type_node;
-  if (type1 == long_long_integer_type_node)
-    return long_long_unsigned_type_node;
-#if HOST_BITS_PER_WIDE_INT >= 64
-  if (type1 == intTI_type_node)
-    return unsigned_intTI_type_node;
-#endif
-  if (type1 == intDI_type_node)
-    return unsigned_intDI_type_node;
-  if (type1 == intSI_type_node)
-    return unsigned_intSI_type_node;
-  if (type1 == intHI_type_node)
-    return unsigned_intHI_type_node;
-  if (type1 == intQI_type_node)
-    return unsigned_intQI_type_node;
-
-  return signed_or_unsigned_type (1, type);
-}
-
-/* Return a signed type the same as TYPE in other respects.  */
-
-tree
-signed_type (type)
-     tree type;
-{
-  tree type1 = TYPE_MAIN_VARIANT (type);
-  if (type1 == unsigned_char_type_node || type1 == char_type_node)
-    return signed_char_type_node;
-  if (type1 == unsigned_type_node)
-    return integer_type_node;
-  if (type1 == short_unsigned_type_node)
-    return short_integer_type_node;
-  if (type1 == long_unsigned_type_node)
-    return long_integer_type_node;
-  if (type1 == long_long_unsigned_type_node)
-    return long_long_integer_type_node;
-#if HOST_BITS_PER_WIDE_INT >= 64
-  if (type1 == unsigned_intTI_type_node)
-    return intTI_type_node;
-#endif
-  if (type1 == unsigned_intDI_type_node)
-    return intDI_type_node;
-  if (type1 == unsigned_intSI_type_node)
-    return intSI_type_node;
-  if (type1 == unsigned_intHI_type_node)
-    return intHI_type_node;
-  if (type1 == unsigned_intQI_type_node)
-    return intQI_type_node;
-
-  return signed_or_unsigned_type (0, type);
-}
-
-/* Return a type the same as TYPE except unsigned or
-   signed according to UNSIGNEDP.  */
-
-tree
-signed_or_unsigned_type (unsignedp, type)
-     int unsignedp;
-     tree type;
-{
-  if (! INTEGRAL_TYPE_P (type)
-      || TREE_UNSIGNED (type) == unsignedp)
-    return type;
-
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
-    return unsignedp ? unsigned_char_type_node : signed_char_type_node;
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) 
-    return unsignedp ? unsigned_type_node : integer_type_node;
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node)) 
-    return unsignedp ? short_unsigned_type_node : short_integer_type_node;
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node)) 
-    return unsignedp ? long_unsigned_type_node : long_integer_type_node;
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node)) 
-    return (unsignedp ? long_long_unsigned_type_node
-           : long_long_integer_type_node);
-  return type;
-}
-
 /* Compute the value of the `sizeof' operator.  */
 
 tree
@@ -1581,21 +1570,9 @@ c_sizeof (type)
   if (code == REFERENCE_TYPE)
     type = TREE_TYPE (type);
 
-  /* We couldn't find anything in the ARM or the draft standard that says,
-     one way or the other, if doing sizeof on something that doesn't have
-     an object associated with it is correct or incorrect.  For example, if
-     you declare `struct S { char str[16]; };', and in your program do
-     a `sizeof (S::str)', should we flag that as an error or should we give
-     the size of it?  Since it seems like a reasonable thing to do, we'll go
-     with giving the value.  */
   if (code == OFFSET_TYPE)
-    type = TREE_TYPE (type);
-
-  /* @@ This also produces an error for a signature ref.
-        In that case we should be able to do better.  */
-  if (IS_SIGNATURE (type))
     {
-      error ("`sizeof' applied to a signature type");
+      cp_error ("`sizeof' applied to non-static member");
       return size_int (0);
     }
 
@@ -1625,15 +1602,7 @@ expr_sizeof (e)
   if (TREE_CODE (e) == COMPONENT_REF
       && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
     error ("sizeof applied to a bit-field");
-  /* ANSI says arrays and functions are converted inside comma.
-     But we can't really convert them in build_compound_expr
-     because that would break commas in lvalues.
-     So do the conversion here if operand was a comma.  */
-  if (TREE_CODE (e) == COMPOUND_EXPR
-      && (TREE_CODE (TREE_TYPE (e)) == ARRAY_TYPE
-         || TREE_CODE (TREE_TYPE (e)) == FUNCTION_TYPE))
-    e = default_conversion (e);
-  else if (is_overloaded_fn (e))
+  if (is_overloaded_fn (e))
     {
       pedwarn ("ANSI C++ forbids taking the sizeof a function type");
       return size_int (1);
@@ -1643,6 +1612,14 @@ expr_sizeof (e)
       incomplete_type_error (e, TREE_TYPE (e));
       return size_int (1);
     }
+  /* It's illegal to say `sizeof (X::i)' for `i' a non-static data
+     member unless you're in a non-static member of X.  So hand off to
+     resolve_offset_ref.  [expr.prim]  */
+  else if (TREE_CODE (e) == OFFSET_REF)
+    e = resolve_offset_ref (e);
+
+  if (e == error_mark_node)
+    return e;
 
   return c_sizeof (TREE_TYPE (e));
 }
@@ -1696,14 +1673,6 @@ c_alignof (type)
   if (code == REFERENCE_TYPE)
     type = TREE_TYPE (type);
 
-  /* @@ This also produces an error for a signature ref.
-        In that case we should be able to do better.  */
-  if (IS_SIGNATURE (type))
-    {
-      error ("`__alignof' applied to a signature type");
-      return size_int (1);
-    }
-
   t = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
   force_fit_type (t, 0);
   return t;
@@ -1820,6 +1789,11 @@ decay_conversion (exp)
       return cp_convert (ptrtype, adr);
     }
 
+  /* [basic.lval]: Class rvalues can have cv-qualified types; non-class
+     rvalues always have cv-unqualified types.  */
+  if (! CLASS_TYPE_P (type))
+    exp = cp_convert (TYPE_MAIN_VARIANT (type), exp);
+
   return exp;
 }
 
@@ -1918,11 +1892,6 @@ build_object_ref (datum, basetype, field)
                basetype, field, dtype);
       return error_mark_node;
     }
-  else if (IS_SIGNATURE (basetype))
-    {
-      warning ("signature name in scope resolution ignored");
-      return build_component_ref (datum, field, NULL_TREE, 1);
-    }
   else if (is_aggr_type (basetype, 1))
     {
       tree binfo = binfo_or_else (basetype, dtype);
@@ -2125,12 +2094,12 @@ build_component_ref (datum, component, basetype_path, protect)
     }
 
   /* Look up component name in the structure type definition.  */
-  if (CLASSTYPE_VFIELD (basetype)
-      && DECL_NAME (CLASSTYPE_VFIELD (basetype)) == component)
+  if (TYPE_VFIELD (basetype)
+      && DECL_NAME (TYPE_VFIELD (basetype)) == component)
     /* Special-case this because if we use normal lookups in an ambiguous
        hierarchy, the compiler will abort (because vptr lookups are
        not supposed to be ambiguous.  */
-    field = CLASSTYPE_VFIELD (basetype);
+    field = TYPE_VFIELD (basetype);
   else if (TREE_CODE (component) == FIELD_DECL)
     field = component;
   else if (TREE_CODE (component) == TYPE_DECL)
@@ -2138,11 +2107,19 @@ build_component_ref (datum, component, basetype_path, protect)
       cp_error ("invalid use of type decl `%#D' as expression", component);
       return error_mark_node;
     }
+  else if (TREE_CODE (component) == TEMPLATE_DECL)
+    {
+      cp_error ("invalid use of template `%#D' as expression", component);
+      return error_mark_node;
+    }
   else
     {
       tree name = component;
       if (TREE_CODE (component) == VAR_DECL)
        name = DECL_NAME (component);
+      if (TREE_CODE (component) == NAMESPACE_DECL)
+        /* Source is in error, but produce a sensible diagnostic.  */
+        name = DECL_NAME (component);
       if (basetype_path == NULL_TREE)
        basetype_path = TYPE_BINFO (basetype);
       field = lookup_field (basetype_path, name,
@@ -2273,8 +2250,7 @@ build_component_ref (datum, component, basetype_path, protect)
         not const, even within a const object.  */
       if (DECL_LANG_SPECIFIC (field) && DECL_MUTABLE_P (field))
        type_quals &= ~TYPE_QUAL_CONST;
-      if (!IS_SIGNATURE (field_type))
-       field_type = cp_build_qualified_type (field_type, type_quals);
+      field_type = cp_build_qualified_type (field_type, type_quals);
     }
 
   ref = fold (build (COMPONENT_REF, field_type,
@@ -2360,7 +2336,14 @@ build_indirect_ref (ptr, errorstring)
         types.  */
       tree t = canonical_type_variant (TREE_TYPE (type));
 
-      if (TREE_CODE (pointer) == ADDR_EXPR
+      if (same_type_p (TYPE_MAIN_VARIANT (t), void_type_node))
+        {
+          /* A pointer to incomplete type (other than cv void) can be
+             dereferenced [expr.unary.op]/1  */
+          cp_error ("`%T' is not a pointer-to-object type", type);
+          return error_mark_node;
+        }
+      else if (TREE_CODE (pointer) == ADDR_EXPR
          && !flag_volatile
          && same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
        /* The POINTER was something like `&x'.  We simplify `*&x' to
@@ -2385,9 +2368,6 @@ build_indirect_ref (ptr, errorstring)
      pointer to member, so it's cool to check for this here.  */
   else if (TYPE_PTRMEM_P (type) || TYPE_PTRMEMFUNC_P (type))
     error ("invalid use of `%s' on pointer to member", errorstring);
-  else if (TREE_CODE (type) == RECORD_TYPE
-          && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
-    error ("cannot dereference signature pointer/reference");
   else if (pointer != error_mark_node)
     {
       if (errorstring)
@@ -2757,7 +2737,7 @@ build_x_function_call (function, params, decl)
        function = TREE_OPERAND (function, 1);
 
       function = get_member_function_from_ptrfunc (&decl_addr, function);
-      params = expr_tree_cons (NULL_TREE, decl_addr, params);
+      params = tree_cons (NULL_TREE, decl_addr, params);
       return build_function_call (function, params);
     }
 
@@ -2808,7 +2788,7 @@ build_x_function_call (function, params, decl)
        }
       else
        decl = build_c_cast (ctypeptr, decl);
-      params = expr_tree_cons (NULL_TREE, decl, params);
+      params = tree_cons (NULL_TREE, decl, params);
     }
 
   return build_function_call (function, params);
@@ -2834,6 +2814,17 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
 
       tree instance_ptr = *instance_ptrptr;
 
+      if (instance_ptr == error_mark_node
+         && TREE_CODE (function) == PTRMEM_CST)
+       {
+         /* Extracting the function address from a pmf is only
+            allowed with -Wno-pmf-conversions. It only works for
+            pmf constants. */
+         e1 = build_addr_func (PTRMEM_CST_MEMBER (function));
+         e1 = convert (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function)), e1);
+         return e1;
+       }
+
       if (TREE_SIDE_EFFECTS (instance_ptr))
        instance_ptr = save_expr (instance_ptr);
 
@@ -2848,67 +2839,66 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
                                               NULL_TREE, 0));
       e3 = PFN_FROM_PTRMEMFUNC (function);
 
-      if (TYPE_SIZE (basetype) != NULL_TREE
-         && ! TYPE_VIRTUAL_P (basetype))
-       /* If basetype doesn't have virtual functions, don't emit code to
-          handle that case.  */
-       e1 = e3;
-      else
-       {
-         /* Promoting idx before saving it improves performance on RISC
-            targets.  Without promoting, the first compare used
-            load-with-sign-extend, while the second used normal load then
-            shift to sign-extend.  An optimizer flaw, perhaps, but it's
-            easier to make this change.  */
-         idx = save_expr (default_conversion
-                          (build_component_ref (function,
-                                                index_identifier,
-                                                NULL_TREE, 0)));
-         e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
-
-         /* Convert down to the right base, before using the instance.  */
-         instance = convert_pointer_to_real (basetype, instance_ptr);
-         if (instance == error_mark_node && instance_ptr != error_mark_node)
-           return instance;
-
-         vtbl = convert_pointer_to (ptr_type_node, instance);
-         delta2 = DELTA2_FROM_PTRMEMFUNC (function);
-         vtbl = build
+      /* This used to avoid checking for virtual functions if basetype
+        has no virtual functions, according to an earlier ANSI draft.
+        With the final ISO C++ rules, such an optimization is
+        incorrect: A pointer to a derived member can be static_cast
+        to pointer-to-base-member, as long as the dynamic object
+        later has the right member. */
+
+      /* Promoting idx before saving it improves performance on RISC
+        targets.  Without promoting, the first compare used
+        load-with-sign-extend, while the second used normal load then
+        shift to sign-extend.  An optimizer flaw, perhaps, but it's
+        easier to make this change.  */
+      idx = save_expr (default_conversion
+                      (build_component_ref (function,
+                                            index_identifier,
+                                            NULL_TREE, 0)));
+      e1 = build_binary_op (GE_EXPR, idx, integer_zero_node);
+
+      /* Convert down to the right base, before using the instance.  */
+      instance = convert_pointer_to_real (basetype, instance_ptr);
+      if (instance == error_mark_node && instance_ptr != error_mark_node)
+       return instance;
+
+      vtbl = convert_pointer_to (ptr_type_node, instance);
+      delta2 = DELTA2_FROM_PTRMEMFUNC (function);
+      vtbl = build
+       (PLUS_EXPR,
+        build_pointer_type (build_pointer_type (vtable_entry_type)),
+        vtbl, cp_convert (ptrdiff_type_node, delta2));
+      vtbl = build_indirect_ref (vtbl, NULL_PTR);
+      aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
+                                                    idx,
+                                                    integer_one_node));
+      if (! flag_vtable_thunks)
+       {
+         aref = save_expr (aref);
+         
+         delta = build_binary_op
            (PLUS_EXPR,
-            build_pointer_type (build_pointer_type (vtable_entry_type)),
-            vtbl, cp_convert (ptrdiff_type_node, delta2));
-         vtbl = build_indirect_ref (vtbl, NULL_PTR);
-         aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
-                                                        idx,
-                                                        integer_one_node));
-         if (! flag_vtable_thunks)
-           {
-             aref = save_expr (aref);
-
-             delta = build_binary_op
-               (PLUS_EXPR,
-                build_conditional_expr (e1,
-                                        build_component_ref (aref,
-                                                             delta_identifier,
-                                                             NULL_TREE, 0),
-                                        integer_zero_node),
-                delta);
-           }
-
-         if (flag_vtable_thunks)
-           e2 = aref;
-         else
-           e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
-         TREE_TYPE (e2) = TREE_TYPE (e3);
-         e1 = build_conditional_expr (e1, e2, e3);
-
-         /* Make sure this doesn't get evaluated first inside one of the
-            branches of the COND_EXPR.  */
-         if (TREE_CODE (instance_ptr) == SAVE_EXPR)
-           e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
-                       instance_ptr, e1);
+            build_conditional_expr (e1,
+                                    build_component_ref (aref,
+                                                         delta_identifier,
+                                                         NULL_TREE, 0),
+                                    integer_zero_node),
+            delta);
        }
 
+      if (flag_vtable_thunks)
+       e2 = aref;
+      else
+       e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
+      TREE_TYPE (e2) = TREE_TYPE (e3);
+      e1 = build_conditional_expr (e1, e2, e3);
+      
+      /* Make sure this doesn't get evaluated first inside one of the
+        branches of the COND_EXPR.  */
+      if (TREE_CODE (instance_ptr) == SAVE_EXPR)
+       e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
+                   instance_ptr, e1);
+
       *instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
                                instance_ptr, delta);
 
@@ -3027,7 +3017,8 @@ build_function_call_real (function, params, require_complete, flags)
 
   if (TREE_CODE (function) == ADDR_EXPR
       && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
-      && DECL_BUILT_IN (TREE_OPERAND (function, 0)))
+      && DECL_BUILT_IN (TREE_OPERAND (function, 0))
+      && DECL_BUILT_IN_CLASS (TREE_OPERAND (function, 0)) == BUILT_IN_NORMAL)
     switch (DECL_FUNCTION_CODE (TREE_OPERAND (function, 0)))
       {
       case BUILT_IN_ABS:
@@ -3173,26 +3164,25 @@ convert_arguments (typelist, values, fndecl, flags)
              parmval = convert_for_initialization
                (NULL_TREE, type, val, flags,
                 "argument passing", fndecl, i);
-#ifdef PROMOTE_PROTOTYPES
-             if ((TREE_CODE (type) == INTEGER_TYPE
-                  || TREE_CODE (type) == ENUMERAL_TYPE)
+             if (PROMOTE_PROTOTYPES
+                 && (TREE_CODE (type) == INTEGER_TYPE
+                     || TREE_CODE (type) == ENUMERAL_TYPE)
                  && (TYPE_PRECISION (type)
                      < TYPE_PRECISION (integer_type_node)))
                parmval = default_conversion (parmval);
-#endif
            }
 
          if (parmval == error_mark_node)
            return error_mark_node;
 
-         result = expr_tree_cons (NULL_TREE, parmval, result);
+         result = tree_cons (NULL_TREE, parmval, result);
        }
       else
        {
          if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
            val = convert_from_reference (val);
 
-         result = expr_tree_cons (NULL_TREE,
+         result = tree_cons (NULL_TREE,
                                   convert_arg_to_ellipsis (val),
                                   result);
        }
@@ -3216,7 +3206,7 @@ convert_arguments (typelist, values, fndecl, flags)
              if (parmval == error_mark_node)
                return error_mark_node;
 
-             result = expr_tree_cons (0, parmval, result);
+             result = tree_cons (0, parmval, result);
              typetail = TREE_CHAIN (typetail);
              /* ends with `...'.  */
              if (typetail == NULL_TREE)
@@ -3590,6 +3580,9 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
 
     case EQ_EXPR:
     case NE_EXPR:
+      if (warn_float_equal && (code0 == REAL_TYPE || code1 == REAL_TYPE))
+       warning ("comparing floating point with == or != is unsafe");
+
       build_type = boolean_type_node; 
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
           || code0 == COMPLEX_TYPE)
@@ -3624,11 +3617,9 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
          if (result_type == NULL_TREE)
            result_type = ptr_type_node;
        }
-      else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
-              && integer_zerop (op1))
+      else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))
        result_type = type0;
-      else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
-              && integer_zerop (op0))
+      else if (code1 == POINTER_TYPE && null_ptr_cst_p (op0))
        result_type = type1;
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
        {
@@ -3640,15 +3631,13 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
          result_type = type1;
          error ("ANSI C++ forbids comparison between pointer and integer");
        }
-      else if (TYPE_PTRMEMFUNC_P (type0) && TREE_CODE (op1) == INTEGER_CST
-              && integer_zerop (op1))
+      else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
        {
          op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
          op1 = integer_zero_node;
          result_type = TREE_TYPE (op0);
        }
-      else if (TYPE_PTRMEMFUNC_P (type1) && TREE_CODE (op0) == INTEGER_CST
-              && integer_zerop (op0))
+      else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
        {
          op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0);
          op1 = integer_zero_node;
@@ -3709,8 +3698,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
                                   DECL_VINDEX (TREE_OPERAND (op1, 0)),
                                   integer_one_node);
              op1 = integer_zero_node;
-             delta21 = CLASSTYPE_VFIELD (TYPE_METHOD_BASETYPE
-                                         (TREE_TYPE (type1)));
+             delta21 = TYPE_VFIELD (TYPE_METHOD_BASETYPE
+                                    (TREE_TYPE (type1)));
              delta21 = DECL_FIELD_BITPOS (delta21);
              delta21 = size_binop (FLOOR_DIV_EXPR, delta21,
                                    size_int (BITS_PER_UNIT));
@@ -4359,7 +4348,7 @@ condition_conversion (expr)
   tree t;
   if (processing_template_decl)
     return expr;
-  t = cp_convert (boolean_type_node, expr);
+  t = perform_implicit_conversion (boolean_type_node, expr);
   t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
   return t;
 }
@@ -4579,7 +4568,6 @@ build_unary_op (code, xarg, noconvert)
                                     || code == POSTINCREMENT_EXPR)
                                    ? PLUS_EXPR : MINUS_EXPR),
                                   argtype, value, inc);
-             TREE_SIDE_EFFECTS (incremented) = 1;
 
              modify = build_modify_expr (arg, NOP_EXPR, incremented);
              compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
@@ -4617,7 +4605,6 @@ build_unary_op (code, xarg, noconvert)
                arg = stabilize_reference (arg);
                val = build (MODIFY_EXPR, TREE_TYPE (arg), arg,
                             boolean_true_node);
-               TREE_SIDE_EFFECTS (val) = 1;
                arg = save_expr (arg);
                val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
                val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
@@ -4699,21 +4686,29 @@ build_unary_op (code, xarg, noconvert)
          && OVL_NEXT (TREE_OPERAND (arg, 1)) == NULL_TREE)
        {
          /* They're trying to take the address of a unique non-static
-            member function.  This is ill-formed, but let's try to DTRT.  */
-         tree base, name;
+            member function.  This is ill-formed, but let's try to DTRT.
+            Note: We only handle unique functions here because we don't
+            want to complain if there's a static overload; non-unique
+            cases will be handled by instantiate_type.  But we need to
+            handle this case here to allow casts on the resulting PMF.  */
 
-         if (current_class_type
-             && TREE_OPERAND (arg, 0) == current_class_ref)
-           /* An expression like &memfn.  */
-           pedwarn ("taking the address of a non-static member function");
-         else
-           pedwarn ("taking the address of a bound member function");
+         tree base = TREE_TYPE (TREE_OPERAND (arg, 0));
+         tree name = DECL_NAME (OVL_CURRENT (TREE_OPERAND (arg, 1)));
+
+         if (! flag_ms_extensions)
+           {
+             if (current_class_type
+                 && TREE_OPERAND (arg, 0) == current_class_ref)
+               /* An expression like &memfn.  */
+               pedwarn ("taking the address of a non-static member function");
+             else
+               pedwarn ("taking the address of a bound member function");
 
-         base = TREE_TYPE (TREE_OPERAND (arg, 0));
-         name = DECL_NAME (OVL_CURRENT (TREE_OPERAND (arg, 1)));
+             cp_pedwarn
+               ("  to form a pointer to member function, say `&%T::%D'",
+                base, name);
+           }
 
-         cp_pedwarn ("  to form a pointer to member function, say `&%T::%D'",
-                     base, name);
          arg = build_offset_ref (base, name);
        }
 
@@ -4795,7 +4790,7 @@ build_unary_op (code, xarg, noconvert)
       return fold (build1 (code, argtype, arg));
     }
 
-  error (errstring);
+  error ("%s", errstring);
   return error_mark_node;
 }
 
@@ -4912,9 +4907,7 @@ unary_complex_lvalue (code, arg)
          type = build_offset_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
          type = build_pointer_type (type);
 
-         t = make_node (PTRMEM_CST);
-         TREE_TYPE (t) = type;
-         PTRMEM_CST_MEMBER (t) = TREE_OPERAND (arg, 1);
+         t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
          return t;
        }
     }
@@ -4986,11 +4979,6 @@ mark_addressable (exp)
            && DECL_RTL (x) != 0
            && ! DECL_IN_MEMORY_P (x))
          {
-           /* We thought this would make a good constant variable,
-              but we were wrong.  */
-           push_obstacks_nochange ();
-           end_temporary_allocation ();
-
            TREE_ASM_WRITTEN (x) = 0;
            DECL_RTL (x) = 0;
            rest_of_decl_compilation (x, 0, 
@@ -4998,8 +4986,6 @@ mark_addressable (exp)
                                      0);
            TREE_ADDRESSABLE (x) = 1;
 
-           pop_obstacks ();
-
            return 1;
          }
        /* Caller should not be trying to mark initialized
@@ -5015,8 +5001,10 @@ mark_addressable (exp)
            && !DECL_ARTIFICIAL (x) && extra_warnings)
          cp_warning ("address requested for `%D', which is declared `register'",
                      x);
-       put_var_into_stack (x);
        TREE_ADDRESSABLE (x) = 1;
+       TREE_USED (x) = 1;
+       if (current_function && expanding_p)
+         put_var_into_stack (x);
        return 1;
 
       case FUNCTION_DECL:
@@ -5057,331 +5045,15 @@ build_x_conditional_expr (ifexp, op1, op2)
   if (processing_template_decl)
     return build_min_nt (COND_EXPR, ifexp, op1, op2);
 
-  return build_new_op (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
+  return build_conditional_expr (ifexp, op1, op2);
 }
+\f
+/* Handle overloading of the ',' operator when needed.  Otherwise,
+   this function just builds an expression list.  */
 
 tree
-build_conditional_expr (ifexp, op1, op2)
-     tree ifexp, op1, op2;
-{
-  register tree type1;
-  register tree type2;
-  register enum tree_code code1;
-  register enum tree_code code2;
-  register tree result_type = NULL_TREE;
-
-  /* If second operand is omitted, it is the same as the first one;
-     make sure it is calculated only once.  */
-  if (op1 == 0)
-    {
-      if (pedantic)
-       pedwarn ("ANSI C++ forbids omitting the middle term of a ?: expression");
-      ifexp = op1 = save_expr (ifexp);
-    }
-
-  ifexp = cp_convert (boolean_type_node, ifexp);
-
-  if (TREE_CODE (ifexp) == ERROR_MARK)
-    return error_mark_node;
-
-  /* C++: REFERENCE_TYPES must be dereferenced.  */
-  type1 = TREE_TYPE (op1);
-  code1 = TREE_CODE (type1);
-  type2 = TREE_TYPE (op2);
-  code2 = TREE_CODE (type2);
-
-  if (code1 == REFERENCE_TYPE)
-    {
-      op1 = convert_from_reference (op1);
-      type1 = TREE_TYPE (op1);
-      code1 = TREE_CODE (type1);
-    }
-  if (code2 == REFERENCE_TYPE)
-    {
-      op2 = convert_from_reference (op2);
-      type2 = TREE_TYPE (op2);
-      code2 = TREE_CODE (type2);
-    }
-
-  /* Don't promote the operands separately if they promote
-     the same way.  Return the unpromoted type and let the combined
-     value get promoted if necessary.  */
-
-  if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)
-      && code2 != ARRAY_TYPE
-      && code2 != FUNCTION_TYPE
-      && code2 != METHOD_TYPE)
-    {
-      tree result;
-
-      if (TREE_CONSTANT (ifexp)
-         && (TREE_CODE (ifexp) == INTEGER_CST
-             || TREE_CODE (ifexp) == ADDR_EXPR))
-       return (integer_zerop (ifexp) ? op2 : op1);
-
-      if (TREE_CODE (op1) == CONST_DECL)
-       op1 = DECL_INITIAL (op1);
-      else if (TREE_READONLY_DECL_P (op1))
-       op1 = decl_constant_value (op1);
-      if (TREE_CODE (op2) == CONST_DECL)
-       op2 = DECL_INITIAL (op2);
-      else if (TREE_READONLY_DECL_P (op2))
-       op2 = decl_constant_value (op2);
-      if (type1 != type2)
-       type1 = cp_build_qualified_type
-         (type1, (CP_TYPE_QUALS (TREE_TYPE (op1)) 
-                  | CP_TYPE_QUALS (TREE_TYPE (op2))));
-      /* ??? This is a kludge to deal with the fact that
-        we don't sort out integers and enums properly, yet.  */
-      result = fold (build (COND_EXPR, type1, ifexp, op1, op2));
-      if (TREE_TYPE (result) != type1)
-       result = build1 (NOP_EXPR, type1, result);
-      /* Expand both sides into the same slot,
-        hopefully the target of the ?: expression.  */
-      if (TREE_CODE (op1) == TARGET_EXPR && TREE_CODE (op2) == TARGET_EXPR)
-       {
-         tree slot = build (VAR_DECL, TREE_TYPE (result));
-         layout_decl (slot, 0);
-         result = build (TARGET_EXPR, TREE_TYPE (result),
-                         slot, result, NULL_TREE, NULL_TREE);
-       }
-      return result;
-    }
-
-  /* They don't match; promote them both and then try to reconcile them.
-     But don't permit mismatching enum types.  */
-  if (code1 == ENUMERAL_TYPE)
-    {
-      if (code2 == ENUMERAL_TYPE)
-       {
-         cp_error ("enumeral mismatch in conditional expression: `%T' vs `%T'",
-                   type1, type2);
-         return error_mark_node;
-       }
-      else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2)
-              && type2 != type_promotes_to (type1))
-       warning ("enumeral and non-enumeral type in conditional expression");
-    }
-  else if (extra_warnings
-          && code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1)
-          && type1 != type_promotes_to (type2))
-    warning ("enumeral and non-enumeral type in conditional expression");
-
-  if (code1 != VOID_TYPE)
-    {
-      op1 = default_conversion (op1);
-      type1 = TREE_TYPE (op1);
-      if (TYPE_PTRMEMFUNC_P (type1))
-       type1 = TYPE_PTRMEMFUNC_FN_TYPE (type1);
-      code1 = TREE_CODE (type1);
-    }
-  if (code2 != VOID_TYPE)
-    {
-      op2 = default_conversion (op2);
-      type2 = TREE_TYPE (op2);
-      if (TYPE_PTRMEMFUNC_P (type2))
-       type2 = TYPE_PTRMEMFUNC_FN_TYPE (type2);
-      code2 = TREE_CODE (type2);
-    }
-
-  if (code1 == RECORD_TYPE && code2 == RECORD_TYPE
-      && real_lvalue_p (op1) && real_lvalue_p (op2)
-      && comptypes (type1, type2, COMPARE_BASE | COMPARE_RELAXED))
-    {
-      type1 = build_reference_type (type1);
-      type2 = build_reference_type (type2);
-      result_type = common_type (type1, type2);
-      op1 = convert_to_reference (result_type, op1, CONV_IMPLICIT,
-                                 LOOKUP_NORMAL, NULL_TREE);
-      op2 = convert_to_reference (result_type, op2, CONV_IMPLICIT,
-                                 LOOKUP_NORMAL, NULL_TREE);
-    }
-  /* Quickly detect the usual case where op1 and op2 have the same type
-     after promotion.  */
-  else if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
-    {
-      if (type1 == type2)
-       result_type = type1;
-      else
-       result_type = 
-         cp_build_qualified_type (type1,
-                                  CP_TYPE_QUALS (TREE_TYPE (op1))
-                                  | CP_TYPE_QUALS (TREE_TYPE (op2)));
-    }
-  else if ((code1 == INTEGER_TYPE || code1 == REAL_TYPE)
-           && (code2 == INTEGER_TYPE || code2 == REAL_TYPE))
-    {
-      result_type = common_type (type1, type2);
-    }
-  else if (code1 == VOID_TYPE || code2 == VOID_TYPE)
-    {
-      if (pedantic && (code1 != VOID_TYPE || code2 != VOID_TYPE))
-       pedwarn ("ANSI C++ forbids conditional expr with only one void side");
-      result_type = void_type_node;
-    }
-  else if (code1 == POINTER_TYPE && null_ptr_cst_p (op2))
-    result_type = qualify_type (type1, type2);
-  else if (code2 == POINTER_TYPE && null_ptr_cst_p (op1))
-    result_type = qualify_type (type2, type1);
-  else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
-    {
-      if (comp_target_types (type1, type2, 1))
-       result_type = common_type (type1, type2);
-      else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
-       {
-         if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
-           pedwarn ("ANSI C++ forbids conditional expr between `void *' and function pointer");
-         result_type = qualify_type (type1, type2);
-       }
-      else if (TYPE_MAIN_VARIANT (TREE_TYPE (type2)) == void_type_node)
-       {
-         if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
-           pedwarn ("ANSI C++ forbids conditional expr between `void *' and function pointer");
-         result_type = qualify_type (type2, type1);
-       }
-      /* C++ */
-      else if (same_or_base_type_p (type2, type1))
-       result_type = type2;
-      else if (IS_AGGR_TYPE (TREE_TYPE (type1))
-              && IS_AGGR_TYPE (TREE_TYPE (type2))
-              && (result_type = common_base_type (TREE_TYPE (type1),
-                                                  TREE_TYPE (type2))))
-       {
-         if (result_type == error_mark_node)
-           {
-             cp_error ("common base type of types `%T' and `%T' is ambiguous",
-                       TREE_TYPE (type1), TREE_TYPE (type2));
-             result_type = ptr_type_node;
-           }
-         else
-           {
-             if (pedantic
-                 && result_type != TREE_TYPE (type1)
-                 && result_type != TREE_TYPE (type2))
-               cp_pedwarn ("`%T' and `%T' converted to `%T *' in conditional expression",
-                           type1, type2, result_type);
-
-             result_type = build_pointer_type (result_type);
-           }
-       }
-      else
-       {
-         pedwarn ("pointer type mismatch in conditional expression");
-         result_type = ptr_type_node;
-       }
-    }
-  else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
-    {
-      pedwarn ("pointer/integer type mismatch in conditional expression");
-      result_type = type1;
-    }
-  else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
-    {
-      pedwarn ("pointer/integer type mismatch in conditional expression");
-      result_type = type2;
-    }
-  if (type2 == unknown_type_node)
-    result_type = type1;
-  else if (type1 == unknown_type_node)
-    result_type = type2;
-
-  if (!result_type)
-    {
-      /* The match does not look good.  If either is
-        an aggregate value, try converting to a scalar type.  */
-      if (code1 == RECORD_TYPE && code2 == RECORD_TYPE)
-       {
-         cp_error ("aggregate mismatch in conditional expression: `%T' vs `%T'",
-                   type1, type2);
-         return error_mark_node;
-       }
-      /* Warning: this code assumes that conversion between cv-variants of
-         a type is done using NOP_EXPRs.  */
-      if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1))
-       {
-         /* There are other types besides pointers and records.  */
-         tree tmp;
-         if (code2 == POINTER_TYPE)
-             tmp = build_pointer_type
-               (cp_build_qualified_type (TREE_TYPE (type2), 
-                                         TYPE_QUAL_CONST 
-                                         | TYPE_QUAL_VOLATILE
-                                         | TYPE_QUAL_RESTRICT));
-         else
-           tmp = type2;
-         tmp = build_type_conversion (tmp, op1, 0);
-         if (tmp == NULL_TREE)
-           {
-             cp_error ("incompatible types `%T' and `%T' in `?:'",
-                       type1, type2);
-             return error_mark_node;
-           }
-         if (tmp == error_mark_node)
-           error ("ambiguous pointer conversion");
-         else
-           STRIP_NOPS (tmp);
-         result_type = common_type (type2, TREE_TYPE (tmp));
-         op1 = tmp;
-       }
-      else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2))
-       {
-         tree tmp;
-         if (code1 == POINTER_TYPE)
-           tmp = build_pointer_type
-             (cp_build_qualified_type (TREE_TYPE (type1), 
-                                       TYPE_QUAL_CONST 
-                                       | TYPE_QUAL_VOLATILE
-                                       | TYPE_QUAL_RESTRICT));
-         else
-           tmp = type1;
-
-         tmp = build_type_conversion (tmp, op2, 0);
-         if (tmp == NULL_TREE)
-           {
-             cp_error ("incompatible types `%T' and `%T' in `?:'",
-                       type1, type2);
-             return error_mark_node;
-           }
-         if (tmp == error_mark_node)
-           error ("ambiguous pointer conversion");
-         else
-           STRIP_NOPS (tmp);
-         result_type = common_type (type1, TREE_TYPE (tmp));
-         op2 = tmp;
-       }
-      else if (flag_cond_mismatch)
-       result_type = void_type_node;
-      else
-       {
-         error ("type mismatch in conditional expression");
-         return error_mark_node;
-       }
-    }
-
-  if (TREE_CODE (result_type) == POINTER_TYPE
-      && TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
-    result_type = build_ptrmemfunc_type (result_type);
-
-  if (result_type != TREE_TYPE (op1))
-    op1 = convert_for_initialization
-      (NULL_TREE, result_type, op1, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
-  if (result_type != TREE_TYPE (op2))
-    op2 = convert_for_initialization
-      (NULL_TREE, result_type, op2, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
-
-  if (TREE_CODE (ifexp) == INTEGER_CST)
-    return integer_zerop (ifexp) ? op2 : op1;
-
-  return convert_from_reference
-    (fold (build (COND_EXPR, result_type, ifexp, op1, op2)));
-}
-\f
-/* Handle overloading of the ',' operator when needed.  Otherwise,
-   this function just builds an expression list.  */
-
-tree
-build_x_compound_expr (list)
-     tree list;
+build_x_compound_expr (list)
+     tree list;
 {
   tree rest = TREE_CHAIN (list);
   tree result;
@@ -5395,11 +5067,12 @@ build_x_compound_expr (list)
   result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL,
                           TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
   if (result)
-    return build_x_compound_expr (expr_tree_cons (NULL_TREE, result,
+    return build_x_compound_expr (tree_cons (NULL_TREE, result,
                                                  TREE_CHAIN (rest)));
 
   if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
     {
+      /* FIXME: This test should be in the implicit cast to void of the LHS. */
       /* the left-hand operand of a comma expression is like an expression
          statement: we should warn if it doesn't have any side-effects,
          unless it was explicitly cast to (void).  */
@@ -5414,7 +5087,7 @@ build_x_compound_expr (list)
 #endif
 
   return build_compound_expr
-    (expr_tree_cons (NULL_TREE, TREE_VALUE (list),
+    (tree_cons (NULL_TREE, TREE_VALUE (list),
                     build_expr_list (NULL_TREE,
                                      build_x_compound_expr (rest))));
 }
@@ -5439,16 +5112,12 @@ build_compound_expr (list)
       if (TREE_CODE (list) == NOP_EXPR
          && TREE_TYPE (list) == TREE_TYPE (TREE_OPERAND (list, 0)))
        list = TREE_OPERAND (list, 0);
-
-      /* Convert arrays to pointers.  */
-      if (TREE_CODE (TREE_TYPE (TREE_VALUE (list))) == ARRAY_TYPE)
-       return default_conversion (TREE_VALUE (list));
-      else
-       return TREE_VALUE (list);
+       
+      return TREE_VALUE (list);
     }
 
   first = TREE_VALUE (list);
-  first = require_complete_type_in_void (first);
+  first = convert_to_void (first, "lhs of comma");
   if (first == error_mark_node)
     return error_mark_node;
   
@@ -5479,8 +5148,7 @@ build_static_cast (type, expr)
 
   if (processing_template_decl)
     {
-      tree t = build_min (STATIC_CAST_EXPR, copy_to_permanent (type),
-                         expr); 
+      tree t = build_min (STATIC_CAST_EXPR, type, expr); 
       return t;
     }
 
@@ -5492,7 +5160,10 @@ build_static_cast (type, expr)
     expr = TREE_OPERAND (expr, 0);
 
   if (TREE_CODE (type) == VOID_TYPE)
-    return build1 (CONVERT_EXPR, type, expr);
+    {
+      expr = convert_to_void (expr, /*implicit=*/NULL);
+      return expr;
+    }
 
   if (TREE_CODE (type) == REFERENCE_TYPE)
     return (convert_from_reference
@@ -5540,6 +5211,17 @@ build_static_cast (type, expr)
           && can_convert (intype, type))
     ok = 1;
 
+  /* [expr.static.cast]
+
+     The static_cast operator shall not be used to cast away
+     constnes.  */
+  if (ok && casts_away_constness (intype, type))
+    {
+      cp_error ("static_cast from `%T' to `%T' casts away constness",
+               intype, type);
+      return error_mark_node;
+    }
+
   if (ok)
     return build_c_cast (type, expr);
 
@@ -5561,8 +5243,7 @@ build_reinterpret_cast (type, expr)
 
   if (processing_template_decl)
     {
-      tree t = build_min (REINTERPRET_CAST_EXPR, 
-                         copy_to_permanent (type), expr);
+      tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
       return t;
     }
 
@@ -5656,8 +5337,7 @@ build_const_cast (type, expr)
 
   if (processing_template_decl)
     {
-      tree t = build_min (CONST_CAST_EXPR, copy_to_permanent (type),
-                         expr);
+      tree t = build_min (CONST_CAST_EXPR, type, expr);
       return t;
     }
 
@@ -5764,12 +5444,6 @@ build_c_cast (type, expr)
       return error_mark_node;
     }
 
-  if (IS_SIGNATURE (type))
-    {
-      error ("cast specifies signature type");
-      return error_mark_node;
-    }
-
   if (processing_template_decl)
     {
       tree t = build_min (CAST_EXPR, type,
@@ -5777,6 +5451,14 @@ build_c_cast (type, expr)
       return t;
     }
 
+  if (TREE_CODE (type) == VOID_TYPE)
+    {
+      /* Conversion to void does not cause any of the normal function to
+       * pointer, array to pointer and lvalue to rvalue decays.  */
+      
+      value = convert_to_void (value, /*implicit=*/NULL);
+      return value;
+    }
   /* Convert functions and arrays to pointers and
      convert references to their expanded types,
      but don't convert any other types.  If, however, we are
@@ -5845,13 +5527,7 @@ build_c_cast (type, expr)
     warning ("cast to pointer from integer of different size");
 #endif
 
-  if (TREE_CODE (type) == VOID_TYPE)
-    {
-      value = require_complete_type_in_void (value);
-      if (value != error_mark_node)
-        value = build1 (CONVERT_EXPR, void_type_node, value);
-    }
-  else if (TREE_CODE (type) == REFERENCE_TYPE)
+  if (TREE_CODE (type) == REFERENCE_TYPE)
     value = (convert_from_reference
             (convert_to_reference (type, value, CONV_C_CAST,
                                    LOOKUP_COMPLAIN, NULL_TREE)));
@@ -5910,14 +5586,6 @@ build_modify_expr (lhs, modifycode, rhs)
 
   newrhs = rhs;
 
-  /* Handle assignment to signature pointers/refs.  */
-
-  if (TYPE_LANG_SPECIFIC (lhstype)
-      && (IS_SIGNATURE_POINTER (lhstype) || IS_SIGNATURE_REFERENCE (lhstype)))
-    {
-      return build_signature_pointer_constructor (lhs, rhs);
-    }
-
   /* Handle control structure constructs used as "lvalues".  */
 
   switch (TREE_CODE (lhs))
@@ -5956,12 +5624,22 @@ build_modify_expr (lhs, modifycode, rhs)
        /* Produce (a ? (b = rhs) : (c = rhs))
           except that the RHS goes through a save-expr
           so the code to compute it is only emitted once.  */
-       tree cond
-         = build_conditional_expr (TREE_OPERAND (lhs, 0),
-                                   build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)),
-                                                      modifycode, rhs),
-                                   build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
-                                                      modifycode, rhs));
+       tree cond;
+
+       /* Check this here to avoid odd errors when trying to convert
+          a throw to the type of the COND_EXPR.  */
+       if (!lvalue_or_else (lhs, "assignment"))
+         return error_mark_node;
+
+       cond = build_conditional_expr
+         (TREE_OPERAND (lhs, 0),
+          build_modify_expr (cp_convert (TREE_TYPE (lhs),
+                                         TREE_OPERAND (lhs, 1)),
+                             modifycode, rhs),
+          build_modify_expr (cp_convert (TREE_TYPE (lhs),
+                                         TREE_OPERAND (lhs, 2)),
+                             modifycode, rhs));
+
        if (cond == error_mark_node)
          return cond;
        /* Make sure the code to compute the rhs comes out
@@ -6107,11 +5785,6 @@ build_modify_expr (lhs, modifycode, rhs)
   /* Warn about storing in something that is `const'.  */
   /* For C++, don't warn if this is initialization.  */
   if (modifycode != INIT_EXPR
-      /* For assignment to `const' signature pointer/reference fields,
-        don't warn either, we already printed a better message before.  */
-      && ! (TREE_CODE (lhs) == COMPONENT_REF
-           && (IS_SIGNATURE_POINTER (TREE_TYPE (TREE_OPERAND (lhs, 0)))
-               || IS_SIGNATURE_REFERENCE (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
       && (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype)
          /* Functions are not modifiable, even though they are
             lvalues.  */
@@ -6144,17 +5817,6 @@ build_modify_expr (lhs, modifycode, rhs)
        }
     }
 
-  /* check to see if there is an assignment to `this' */
-  if (lhs == current_class_ptr)
-    {
-      if (flag_this_is_variable > 0
-         && DECL_NAME (current_function_decl) != NULL_TREE
-         && (DECL_NAME (current_function_decl)
-             != constructor_name (current_class_type)))
-       warning ("assignment to `this' not in constructor or destructor");
-      current_function_just_assigned_this = 1;
-    }
-
   if (modifycode != INIT_EXPR)
     {
       /* Make modifycode now either a NOP_EXPR or an INIT_EXPR.  */
@@ -6206,39 +5868,19 @@ build_modify_expr (lhs, modifycode, rhs)
       if (pedantic && ! DECL_ARTIFICIAL (current_function_decl))
        pedwarn ("ANSI C++ forbids assignment of arrays");
 
-      /* Have to wrap this in RTL_EXPR for two cases:
-        in base or member initialization and if we
-        are a branch of a ?: operator.  Since we
-        can't easily know the latter, just do it always.  */
-
-      result = make_node (RTL_EXPR);
-
-      TREE_TYPE (result) = void_type_node;
-      do_pending_stack_adjust ();
-      start_sequence_for_rtl_expr (result);
-
-      /* As a matter of principle, `start_sequence' should do this.  */
-      emit_note (0, -1);
-
       from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
                   ? 1 + (modifycode != INIT_EXPR): 0;
-      expand_vec_init (lhs, lhs, array_type_nelts (lhstype), newrhs,
-                      from_array);
-
-      do_pending_stack_adjust ();
-
-      TREE_SIDE_EFFECTS (result) = 1;
-      RTL_EXPR_SEQUENCE (result) = get_insns ();
-      RTL_EXPR_RTL (result) = const0_rtx;
-      end_sequence ();
-      return result;
+      return (build_vec_init
+             (lhs, lhs, array_type_nelts (lhstype), newrhs,
+              from_array));
     }
 
   if (modifycode == INIT_EXPR)
     {
       newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
                                           "assignment", NULL_TREE, 0);
-      if (lhs == DECL_RESULT (current_function_decl))
+      if (current_function_decl && 
+         lhs == DECL_RESULT (current_function_decl))
        {
          if (DECL_INITIAL (lhs))
            warning ("return value from function receives multiple initializations");
@@ -6358,7 +6000,12 @@ build_x_modify_expr (lhs, modifycode, rhs)
 \f
 /* Get difference in deltas for different pointer to member function
    types.  Return integer_zero_node, if FROM cannot be converted to a
-   TO type.  If FORCE is true, then allow reverse conversions as well.  */
+   TO type.  If FORCE is true, then allow reverse conversions as well.
+
+   Note that the naming of FROM and TO is kind of backwards; the return
+   value is what we add to a TO in order to get a FROM.  They are named
+   this way because we call this function to find out how to convert from
+   a pointer to member of FROM to a pointer to member of TO.  */
 
 static tree
 get_delta_difference (from, to, force)
@@ -6393,7 +6040,7 @@ get_delta_difference (from, to, force)
       binfo = get_binfo (to, from, 1);
       if (binfo == 0 || binfo == error_mark_node)
        return delta;
-      if (TREE_VIA_VIRTUAL (binfo))
+      if (binfo_from_vbase (binfo))
        {
          binfo = binfo_member (BINFO_TYPE (binfo),
                                CLASSTYPE_VBASECLASSES (from));
@@ -6409,7 +6056,7 @@ get_delta_difference (from, to, force)
                              delta);
     }
 
-  if (TREE_VIA_VIRTUAL (binfo))
+  if (binfo_from_vbase (binfo))
     {
       if (force)
        {
@@ -6439,18 +6086,18 @@ build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
   if (pfn)
     {
       u = build_nt (CONSTRUCTOR, NULL_TREE,
-                   expr_tree_cons (pfn_identifier, pfn, NULL_TREE));
+                   tree_cons (pfn_identifier, pfn, NULL_TREE));
     }
   else
     {
       u = build_nt (CONSTRUCTOR, NULL_TREE,
-                   expr_tree_cons (delta2_identifier, delta2, NULL_TREE));
+                   tree_cons (delta2_identifier, delta2, NULL_TREE));
     }
 
   u = build_nt (CONSTRUCTOR, NULL_TREE,
-               expr_tree_cons (NULL_TREE, delta,
-                          expr_tree_cons (NULL_TREE, idx,
-                                     expr_tree_cons (NULL_TREE, u, NULL_TREE))));
+               tree_cons (NULL_TREE, delta,
+                          tree_cons (NULL_TREE, idx,
+                                     tree_cons (NULL_TREE, u, NULL_TREE))));
 
   return digest_init (type, u, (tree*)0);
 #else
@@ -6469,14 +6116,14 @@ build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
     {
       allconstant = TREE_CONSTANT (pfn);
       allsimple = !! initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
-      u = expr_tree_cons (pfn_field, pfn, NULL_TREE);
+      u = tree_cons (pfn_field, pfn, NULL_TREE);
     }
   else
     {
       delta2 = convert_and_check (delta_type_node, delta2);
       allconstant = TREE_CONSTANT (delta2);
       allsimple = !! initializer_constant_valid_p (delta2, TREE_TYPE (delta2));
-      u = expr_tree_cons (delta2_field, delta2, NULL_TREE);
+      u = tree_cons (delta2_field, delta2, NULL_TREE);
     }
 
   delta = convert_and_check (delta_type_node, delta);
@@ -6488,9 +6135,9 @@ build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
       && initializer_constant_valid_p (idx, TREE_TYPE (idx));
 
   u = build (CONSTRUCTOR, subtype, NULL_TREE, u);
-  u = expr_tree_cons (delta_field, delta,
-                expr_tree_cons (idx_field, idx,
-                           expr_tree_cons (pfn_or_delta2_field, u, NULL_TREE)));
+  u = tree_cons (delta_field, delta,
+                tree_cons (idx_field, idx,
+                           tree_cons (pfn_or_delta2_field, u, NULL_TREE)));
   u = build (CONSTRUCTOR, type, NULL_TREE, u);
   TREE_CONSTANT (u) = allconstant;
   TREE_STATIC (u) = allconstant && allsimple;
@@ -6514,49 +6161,77 @@ build_ptrmemfunc (type, pfn, force)
      tree type, pfn;
      int force;
 {
-  tree idx = integer_zero_node;
-  tree delta = integer_zero_node;
-  tree delta2 = integer_zero_node;
-  tree npfn = NULL_TREE;
   tree fn;
-  
+  tree pfn_type = TREE_TYPE (pfn);
+  tree to_type = build_ptrmemfunc_type (type);
+
   /* Handle multiple conversions of pointer to member functions.  */
   if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
     {
+      tree idx = integer_zero_node;
+      tree delta = integer_zero_node;
+      tree delta2 = integer_zero_node;
+      tree npfn = NULL_TREE;
       tree ndelta, ndelta2;
       tree e1, e2, e3, n;
-      tree pfn_type;
 
-      /* Is is already the right type? */
-      if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
+      if (!force 
+         && !can_convert_arg (to_type, TREE_TYPE (pfn), pfn))
+       cp_error ("conversion to `%T' from `%T'", 
+                 to_type, pfn_type);
+
+      if (TREE_CODE (pfn) == PTRMEM_CST)
+       {
+         /* We could just build the resulting CONSTRUCTOR now, but we
+            don't, relying on the general machinery below, together
+            with constant-folding, to do the right thing.  We don't
+            want to return a PTRMEM_CST here, since a
+            pointer-to-member constant is no longer a valid template
+            argument once it is cast to any type, including its
+            original type.  */
+         expand_ptrmemfunc_cst (pfn, &ndelta, &idx, &npfn, &ndelta2);
+         if (npfn)
+           /* This constant points to a non-virtual function.
+              NDELTA2 will be NULL, but it's value doesn't really
+              matter since we won't use it anyhow.  */
+           ndelta2 = integer_zero_node;
+       }
+      else if (same_type_p (to_type, pfn_type))
+       /* We don't have to do any conversion.  Note that we do this
+          after checking for a PTRMEM_CST so that a PTRMEM_CST, cast
+          to its own type, will not be considered a legal non-type
+          template argument.  */
        return pfn;
+      else
+       {
+         ndelta = cp_convert (ptrdiff_type_node, 
+                              build_component_ref (pfn, 
+                                                   delta_identifier, 
+                                                   NULL_TREE, 0));
+         ndelta2 = cp_convert (ptrdiff_type_node, 
+                               DELTA2_FROM_PTRMEMFUNC (pfn));
+         idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0);
+       }
 
-      pfn_type = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn));
-      if (!force
-         && comp_target_types (type, pfn_type, 1) != 1)
-       cp_error ("conversion to `%T' from `%T'", type, pfn_type);
-
-      ndelta = cp_convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0));
-      ndelta2 = cp_convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
-      idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0);
-
-      n = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (pfn_type)),
-                               TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
+      n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
+                               TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
                                force);
-
       delta = build_binary_op (PLUS_EXPR, ndelta, n);
       delta2 = build_binary_op (PLUS_EXPR, ndelta2, n);
       e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node));
          
-      e2 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx,
+      /* If it's a virtual function, this is what we want.  */
+      e2 = build_ptrmemfunc1 (to_type, delta, idx,
                              NULL_TREE, delta2);
 
       pfn = PFN_FROM_PTRMEMFUNC (pfn);
       npfn = build1 (NOP_EXPR, type, pfn);
       TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
 
-      e3 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn,
-                             NULL_TREE);
+      /* But if it's a non-virtual function, or NULL, we use this
+        instead.  */
+      e3 = build_ptrmemfunc1 (to_type, delta,
+                             idx, npfn, NULL_TREE);
       return build_conditional_expr (e1, e2, e3);
     }
 
@@ -6564,7 +6239,7 @@ build_ptrmemfunc (type, pfn, force)
   if (integer_zerop (pfn))
     {
       pfn = build_c_cast (type, integer_zero_node);
-      return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type),
+      return build_ptrmemfunc1 (to_type,
                                integer_zero_node, integer_zero_node,
                                pfn, NULL_TREE);
     }
@@ -6574,10 +6249,7 @@ build_ptrmemfunc (type, pfn, force)
 
   fn = TREE_OPERAND (pfn, 0);
   my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
-  npfn = make_node (PTRMEM_CST);
-  TREE_TYPE (npfn) = build_ptrmemfunc_type (type);
-  PTRMEM_CST_MEMBER (npfn) = fn;
-  return npfn;
+  return make_ptrmem_cst (to_type, fn);
 }
 
 /* Return the DELTA, IDX, PFN, and DELTA2 values for the PTRMEM_CST
@@ -6593,38 +6265,41 @@ expand_ptrmemfunc_cst (cst, delta, idx, pfn, delta2)
 {
   tree type = TREE_TYPE (cst);
   tree fn = PTRMEM_CST_MEMBER (cst);
+  tree ptr_class, fn_class;
 
   my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
-  
-  *delta 
-    = get_delta_difference (TYPE_METHOD_BASETYPE 
-                           (TREE_TYPE (fn)),
-                           TYPE_PTRMEMFUNC_OBJECT_TYPE (type),
-                           /*force=*/0);
+
+  /* The class that the function belongs to.  */
+  fn_class = DECL_CLASS_CONTEXT (fn);
+
+  /* The class that we're creating a pointer to member of.  */
+  ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
+
+  /* First, calculate the adjustment to the function's class.  */
+  *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0);
+
   if (!DECL_VIRTUAL_P (fn))
     {
-      *idx = size_binop (MINUS_EXPR, integer_zero_node,
-                        integer_one_node);
-      *pfn = build_addr_func (fn);
-      if (!same_type_p (TYPE_METHOD_BASETYPE (TREE_TYPE (fn)),
-                       TYPE_PTRMEMFUNC_OBJECT_TYPE (type)))
-       *pfn = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type), 
-                      *pfn);
+      *idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
+      *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
       *delta2 = NULL_TREE;
     }
   else
     {
-      *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), 
-                        integer_one_node);
+      /* If we're dealing with a virtual function, we have to adjust 'this'
+         again, to point to the base which provides the vtable entry for
+         fn; the call will do the opposite adjustment.  */
+      tree orig_class = DECL_VIRTUAL_CONTEXT (fn);
+      tree binfo = binfo_or_else (orig_class, fn_class);
+      *delta = size_binop (PLUS_EXPR, *delta, BINFO_OFFSET (binfo));
+
+      /* Map everything down one to make room for the null PMF.  */
+      *idx = size_binop (PLUS_EXPR, DECL_VINDEX (fn), integer_one_node);
       *pfn = NULL_TREE;
-      *delta2 = get_binfo (DECL_CONTEXT (fn),
-                         DECL_CLASS_CONTEXT (fn),
-                         0);
-      *delta2 = get_vfield_offset (*delta2);
-      *delta2 = size_binop (PLUS_EXPR, *delta2,
-                          build_binary_op (PLUS_EXPR,
-                                           *delta, 
-                                           integer_zero_node));
+
+      /* Offset from an object of PTR_CLASS to the vptr for ORIG_CLASS.  */
+      *delta2 = size_binop (PLUS_EXPR, *delta,
+                           get_vfield_offset (TYPE_BINFO (orig_class)));
     }
 }
 
@@ -6680,18 +6355,11 @@ pfn_from_ptrmemfunc (t)
           pfn_identifier, NULL_TREE, 0)); 
 }
 
-/* Convert value RHS to type TYPE as preparation for an assignment
-   to an lvalue of type TYPE.
-   The real work of conversion is done by `convert'.
-   The purpose of this function is to generate error messages
-   for assignments that are not allowed in C.
-   ERRTYPE is a string to use in error messages:
-   "assignment", "return", etc.
-
-   C++: attempts to allow `convert' to find conversions involving
-   implicit type conversion between aggregate and scalar types
-   as per 8.5.6 of C++ manual.  Does not randomly dereference
-   pointers to aggregates!  */
+/* Convert value RHS to type TYPE as preparation for an assignment to
+   an lvalue of type TYPE.  ERRTYPE is a string to use in error
+   messages: "assignment", "return", etc.  If FNDECL is non-NULL, we
+   are doing the conversion in order to pass the PARMNUMth argument of
+   FNDECL.  */
 
 static tree
 convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
@@ -6714,388 +6382,92 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
   if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
     rhs = TREE_OPERAND (rhs, 0);
 
-  if (rhs == error_mark_node || TREE_TYPE (rhs) == error_mark_node)
+  rhstype = TREE_TYPE (rhs);
+  coder = TREE_CODE (rhstype);
+
+  if (rhs == error_mark_node || rhstype == error_mark_node)
     return error_mark_node;
   if (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node)
     return error_mark_node;
 
-  if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
-      || is_overloaded_fn (rhs))
-    rhs = default_conversion (rhs);
-  else if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
-    rhs = convert_from_reference (rhs);
-
-  /* If rhs is some sort of overloaded function, ocp_convert will either
-     do the right thing or complain; we don't need to check anything else.
-     So just hand off.  */
-  if (type_unknown_p (rhs))
-    return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
-
-  rhstype = TREE_TYPE (rhs);
-  coder = TREE_CODE (rhstype);
-
-  /* Issue warnings about peculiar, but legal, uses of NULL.  */
+  /* Issue warnings about peculiar, but legal, uses of NULL.  We
+     do this *before* the call to decl_constant_value so as to
+     avoid duplicate warnings on code like `const int I = NULL;
+     f(I);'.  */
   if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
     cp_warning ("converting NULL to non-pointer type");
 
-  /* This should no longer change types on us.  */
-  if (TREE_CODE (rhs) == CONST_DECL)
-    rhs = DECL_INITIAL (rhs);
-  else if (TREE_READONLY_DECL_P (rhs))
-    rhs = decl_constant_value (rhs);
-
-  if (same_type_p (type, rhstype))
-    {
-      overflow_warning (rhs);
-      return rhs;
-    }
-
+  /* The RHS of an assignment cannot have void type.  */
   if (coder == VOID_TYPE)
     {
       error ("void value not ignored as it ought to be");
       return error_mark_node;
     }
-  /* Arithmetic types all interconvert.  */
-  if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == BOOLEAN_TYPE
-       || codel == COMPLEX_TYPE)
-       && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE
-          || coder == COMPLEX_TYPE))
-    {
-      /* But we should warn if assigning REAL_TYPE to INTEGER_TYPE.  */
-      if (coder == REAL_TYPE && codel == INTEGER_TYPE)
-       {
-         if (fndecl)
-           cp_warning ("`%T' used for argument %P of `%D'",
-                       rhstype, parmnum, fndecl);
-         else
-           cp_warning ("%s to `%T' from `%T'", errtype, type, rhstype);
-       }
-      /* And we should warn if assigning a negative value to
-        an unsigned variable.  */
-      else if (TREE_UNSIGNED (type) && codel != BOOLEAN_TYPE)
-       {
-         if (TREE_CODE (rhs) == INTEGER_CST
-             && TREE_NEGATED_INT (rhs))
-           {
-             if (fndecl)
-               cp_warning ("negative value `%E' passed as argument %P of `%D'",
-                           rhs, parmnum, fndecl);
-             else
-               cp_warning ("%s of negative value `%E' to `%T'",
-                           errtype, rhs, type);
-           }
-         overflow_warning (rhs);
-         if (TREE_CONSTANT (rhs))
-           rhs = fold (rhs);
-       }
-
-      return convert_and_check (type, rhs);
-    }
-  /* Conversions involving enums.  */
-  else if ((codel == ENUMERAL_TYPE
-           && (INTEGRAL_CODE_P (coder) || coder == REAL_TYPE))
-          || (coder == ENUMERAL_TYPE
-              && (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE)))
-    {
-      return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
-    }
-  /* Conversions among pointers */
-  else if (codel == POINTER_TYPE
-          && (coder == POINTER_TYPE
-              || (coder == RECORD_TYPE
-                  && (IS_SIGNATURE_POINTER (rhstype)
-                      || IS_SIGNATURE_REFERENCE (rhstype)))))
-    {
-      register tree ttl = TREE_TYPE (type);
-      register tree ttr;
-      int ctt = 0;
-
-      if (coder == RECORD_TYPE)
-       {
-         rhs = build_optr_ref (rhs);
-         rhstype = TREE_TYPE (rhs);
-       }
-      ttr = TREE_TYPE (rhstype);
-
-      /* If both pointers are of aggregate type, then we
-        can give better error messages, and save some work
-        as well.  */
-      if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
-       {
-         tree binfo;
-
-         if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr)
-             || type == class_star_type_node
-             || rhstype == class_star_type_node)
-           binfo = TYPE_BINFO (ttl);
-         else
-           binfo = get_binfo (ttl, ttr, 1);
-
-         if (binfo == error_mark_node)
-           return error_mark_node;
-         if (binfo == 0)
-           return error_not_base_type (ttl, ttr);
 
-         if (!at_least_as_qualified_p (ttl, ttr))
-           {
-             if (fndecl)
-               cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
-                           rhstype, parmnum, fndecl);
-             else
-               cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
-                           errtype, type, rhstype);
-           }
-       }
-
-      /* Any non-function converts to a [const][volatile] void *
-        and vice versa; otherwise, targets must be the same.
-        Meanwhile, the lhs target must have all the qualifiers of the rhs.  */
-      else if (TYPE_MAIN_VARIANT (ttl) == void_type_node
-              || TYPE_MAIN_VARIANT (ttr) == void_type_node
-              || (ctt = comp_target_types (type, rhstype, 1))
-              || (unsigned_type (TYPE_MAIN_VARIANT (ttl))
-                  == unsigned_type (TYPE_MAIN_VARIANT (ttr))))
-       {
-         /* ARM $4.8, commentary on p39.  */
-         if (TYPE_MAIN_VARIANT (ttl) == void_type_node
-             && TREE_CODE (ttr) == OFFSET_TYPE)
-           {
-             cp_error ("no standard conversion from `%T' to `void *'", ttr);
-             return error_mark_node;
-           }
-
-         if (ctt < 0 && TYPE_MAIN_VARIANT (ttl) != TYPE_MAIN_VARIANT (ttr))
-           cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
-                       rhstype, type);
+  /* Simplify the RHS if possible.  */
+  if (TREE_CODE (rhs) == CONST_DECL)
+    rhs = DECL_INITIAL (rhs);
+  else if (TREE_READONLY_DECL_P (rhs))
+    rhs = decl_constant_value (rhs);
 
-         if (TYPE_MAIN_VARIANT (ttl) != void_type_node
-             && TYPE_MAIN_VARIANT (ttr) == void_type_node
-             && ! null_ptr_cst_p (rhs))
-           {
-             if (coder == RECORD_TYPE)
-               cp_pedwarn ("implicit conversion of signature pointer to type `%T'",
-                           type);
-             else
-               pedwarn ("ANSI C++ forbids implicit conversion from `void *' in %s",
-                        errtype);
-           }
-         /* Const and volatile mean something different for function types,
-            so the usual warnings are not appropriate.  */
-         else if ((TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttr) != METHOD_TYPE)
-                  || (TREE_CODE (ttl) != FUNCTION_TYPE && TREE_CODE (ttl) != METHOD_TYPE))
-           {
-             if (TREE_CODE (ttl) == OFFSET_TYPE
-                 && binfo_member (TYPE_OFFSET_BASETYPE (ttr),
-                                  CLASSTYPE_VBASECLASSES (TYPE_OFFSET_BASETYPE (ttl))))
-               {
-                 error ("%s between pointer to members converting across virtual baseclasses", errtype);
-                 return error_mark_node;
-               }
-             else if (!at_least_as_qualified_p (ttl, ttr))
-               {
-                 if (string_conv_p (type, rhs, 1))
-                   /* converting from string constant to char *, OK.  */;
-                 else if (fndecl)
-                   cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
-                               rhstype, parmnum, fndecl);
-                 else
-                   cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
-                               errtype, type, rhstype);
-               }
-             else if (TREE_CODE (ttl) == TREE_CODE (ttr)
-                      && ! comp_target_types (type, rhstype, 1))
-               {
-                 if (fndecl)
-                   cp_pedwarn ("passing `%T' as argument %P of `%D' changes signedness",
-                               rhstype, parmnum, fndecl);
-                 else
-                   cp_pedwarn ("%s to `%T' from `%T' changes signedness",
-                               errtype, type, rhstype);
-               }
-           }
-       }
+  /* Warn about assigning a floating-point type to an integer type.  */
+  if (coder == REAL_TYPE && codel == INTEGER_TYPE)
+    {
+      if (fndecl)
+       cp_warning ("`%T' used for argument %P of `%D'",
+                   rhstype, parmnum, fndecl);
       else
-       {
-         int add_quals = 0;
-         int drops_quals = 0;
-         int left_const = 1;
-         int unsigned_parity;
-         int nptrs = 0;
-
-         /* This code is basically a duplicate of comp_ptr_ttypes_real.  */
-         for (; ; ttl = TREE_TYPE (ttl), ttr = TREE_TYPE (ttr))
-           {
-             nptrs -= 1;
-             drops_quals |= !at_least_as_qualified_p (ttl, ttr);
-
-             if (! left_const
-                 && !at_least_as_qualified_p (ttr, ttl))
-               add_quals = 1;
-             left_const &= TYPE_READONLY (ttl);
-
-             if (TREE_CODE (ttl) != POINTER_TYPE
-                 || TREE_CODE (ttr) != POINTER_TYPE)
-               break;
-           }
-         unsigned_parity = TREE_UNSIGNED (ttl) - TREE_UNSIGNED (ttr);
-         if (unsigned_parity)
-           {
-             if (TREE_UNSIGNED (ttl))
-               ttr = unsigned_type (ttr);
-             else
-               ttl = unsigned_type (ttl);
-           }
-
-         if (comp_target_types (ttl, ttr, nptrs) > 0)
-           {
-             if (add_quals)
-               {
-                 if (fndecl)
-                   cp_pedwarn ("passing `%T' as argument %P of `%D' adds cv-quals without intervening `const'",
-                               rhstype, parmnum, fndecl);
-                 else
-                   cp_pedwarn ("%s to `%T' from `%T' adds cv-quals without intervening `const'",
-                               errtype, type, rhstype);
-               }
-             if (drops_quals)
-               {
-                 if (fndecl)
-                   cp_pedwarn ("passing `%T' as argument %P of `%D' discards qualifiers",
-                               rhstype, parmnum, fndecl);
-                 else
-                   cp_pedwarn ("%s to `%T' from `%T' discards qualifiers",
-                               errtype, type, rhstype);
-               }
-             if (unsigned_parity > 0)
-               {
-                 if (fndecl)
-                   cp_pedwarn ("passing `%T' as argument %P of `%D' changes signed to unsigned",
-                               rhstype, parmnum, fndecl);
-                 else
-                   cp_pedwarn ("%s to `%T' from `%T' changes signed to unsigned",
-                               errtype, type, rhstype);
-               }
-             else if (unsigned_parity < 0)
-               {
-                 if (fndecl)
-                   cp_pedwarn ("passing `%T' as argument %P of `%D' changes unsigned to signed",
-                               rhstype, parmnum, fndecl);
-                 else
-                   cp_pedwarn ("%s to `%T' from `%T' changes unsigned to signed",
-                               errtype, type, rhstype);
-               }
-
-             /* C++ is not so friendly about converting function and
-                member function pointers as C.  Emit warnings here.  */
-             if (TREE_CODE (ttl) == FUNCTION_TYPE
-                 || TREE_CODE (ttl) == METHOD_TYPE)
-               if (!same_or_base_type_p (ttl, ttr))
-                 {
-                   warning ("conflicting function types in %s:", errtype);
-                   cp_warning ("\t`%T' != `%T'", type, rhstype);
-                 }
-           }
-         else
-           {
-             if (fndecl)
-               cp_error ("passing `%T' as argument %P of `%D'",
-                         rhstype, parmnum, fndecl);
-             else
-               cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
-             return error_mark_node;
-           }
-       }
-      return cp_convert (type, rhs);
+       cp_warning ("%s to `%T' from `%T'", errtype, type, rhstype);
     }
-  else if (codel == POINTER_TYPE
-          && (coder == INTEGER_TYPE
-              || coder == BOOLEAN_TYPE))
+  /* And warn about assigning a negative value to an unsigned
+     variable.  */
+  else if (TREE_UNSIGNED (type) && codel != BOOLEAN_TYPE)
     {
-      /* An explicit constant 0 can convert to a pointer,
-         but not a 0 that results from casting or folding.  */
-      if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs)))
+      if (TREE_CODE (rhs) == INTEGER_CST
+         && TREE_NEGATED_INT (rhs))
        {
          if (fndecl)
-           cp_pedwarn ("passing `%T' to argument %P of `%D' lacks a cast",
-                       rhstype, parmnum, fndecl);
+           cp_warning ("negative value `%E' passed as argument %P of `%D'",
+                       rhs, parmnum, fndecl);
          else
-           cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
-                       errtype, type, rhstype);
+           cp_warning ("%s of negative value `%E' to `%T'",
+                       errtype, rhs, type);
+       }
+      overflow_warning (rhs);
+      if (TREE_CONSTANT (rhs))
+       rhs = fold (rhs);
+    }
+
+  /* [expr.ass]
+
+     The expression is implicitly converted (clause _conv_) to the
+     cv-unqualified type of the left operand.  */
+  if (!can_convert_arg (type, rhstype, rhs))
+    {
+      /* When -Wno-pmf-conversions is use, we just silently allow
+        conversions from pointers-to-members to plain pointers.  If
+        the conversion doesn't work, cp_convert will complain.  */
+      if (!warn_pmf2ptr 
+         && TYPE_PTR_P (type) 
+         && TYPE_PTRMEMFUNC_P (rhstype))
+       rhs = cp_convert (strip_top_quals (type), rhs);
+      else 
+       {
+         /* If the right-hand side has unknown type, then it is an
+            overloaded function.  Call instantiate_type to get error
+            messages.  */
+         if (rhstype == unknown_type_node)
+           instantiate_type (type, rhs, 1);
+         else if (fndecl)
+           cp_error ("cannot convert `%T' to `%T' for argument `%P' to `%D'",
+                     rhstype, type, parmnum, fndecl);
+         else
+           cp_error ("cannot convert `%T' to `%T' in %s", rhstype, type, 
+                     errtype);
+         return error_mark_node;
        }
-      return cp_convert (type, rhs);
-    }
-  else if (codel == INTEGER_TYPE
-          && (coder == POINTER_TYPE
-              || (coder == RECORD_TYPE
-                  && (IS_SIGNATURE_POINTER (rhstype)
-                      || TYPE_PTRMEMFUNC_FLAG (rhstype)
-                      || IS_SIGNATURE_REFERENCE (rhstype)))))
-    {
-      if (fndecl)
-       cp_pedwarn ("passing `%T' to argument %P of `%D' lacks a cast",
-                   rhstype, parmnum, fndecl);
-      else
-       cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
-                   errtype, type, rhstype);
-      return cp_convert (type, rhs);
-    }
-  else if (codel == BOOLEAN_TYPE
-          && (coder == POINTER_TYPE
-              || (coder == RECORD_TYPE
-                  && (IS_SIGNATURE_POINTER (rhstype)
-                      || TYPE_PTRMEMFUNC_FLAG (rhstype)
-                      || IS_SIGNATURE_REFERENCE (rhstype)))))
-    return cp_convert (type, rhs);
-
-  /* C++ */
-  else if (((coder == POINTER_TYPE
-            && TREE_CODE (TREE_TYPE (rhstype)) == METHOD_TYPE)
-           || integer_zerop (rhs)
-           || TYPE_PTRMEMFUNC_P (rhstype))
-          && TYPE_PTRMEMFUNC_P (type))
-    {
-      tree ttl = TYPE_PTRMEMFUNC_FN_TYPE (type);
-      tree ttr = (TYPE_PTRMEMFUNC_P (rhstype)
-                 ? TYPE_PTRMEMFUNC_FN_TYPE (rhstype)
-                 : rhstype);
-      int ctt = (TREE_CODE (rhstype) == INTEGER_TYPE ? 1
-                : comp_target_types (ttl, ttr, 1));
-
-      if (ctt < 0)
-       cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
-                   ttr, ttl);
-      else if (ctt == 0)
-       cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr);
-
-      /* compatible pointer to member functions.  */
-      return build_ptrmemfunc (ttl, rhs, 0);
-    }
-  else if (codel == ERROR_MARK || coder == ERROR_MARK)
-    return error_mark_node;
-
-  /* This should no longer happen.  References are initialized via
-     `convert_for_initialization'.  They should otherwise be
-     bashed before coming here.  */
-  else if (codel == REFERENCE_TYPE)
-    my_friendly_abort (317);
-  else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (rhs)))
-    {
-      tree nrhs = build1 (NOP_EXPR, type, rhs);
-      TREE_CONSTANT (nrhs) = TREE_CONSTANT (rhs);
-      return nrhs;
     }
-  else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
-    return cp_convert (type, rhs);
-  /* Handle anachronistic conversions from (::*)() to cv void* or (*)().  */
-  else if (TREE_CODE (type) == POINTER_TYPE
-          && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
-              || TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
-          && TREE_TYPE (rhs)
-          && TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
-    return cp_convert (type, rhs);
-
-  cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
-  return error_mark_node;
+  return perform_implicit_conversion (strip_top_quals (type), rhs);
 }
 
 /* Convert RHS to be of type TYPE.
@@ -7174,8 +6546,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
 
       if (fndecl)
        savew = warningcount, savee = errorcount;
-      rhs = convert_to_reference (type, rhs, CONV_IMPLICIT, flags,
-                                 exp ? exp : error_mark_node);
+      rhs = initialize_reference (type, rhs);
       if (fndecl)
        {
          if (warningcount > savew)
@@ -7196,28 +6567,9 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
 
   type = complete_type (type);
 
-  if (TYPE_LANG_SPECIFIC (type)
-      && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
-    return build_signature_pointer_constructor (type, rhs);
-
   if (IS_AGGR_TYPE (type))
     return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
 
-  if (type == TREE_TYPE (rhs))
-    {
-      /* Issue warnings about peculiar, but legal, uses of NULL.  We
-        do this *before* the call to decl_constant_value so as to
-        avoid duplicate warnings on code like `const int I = NULL;
-        f(I);'.  */
-      if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
-       cp_warning ("converting NULL to non-pointer type");
-
-      if (TREE_READONLY_DECL_P (rhs))
-       rhs = decl_constant_value (rhs);
-
-      return rhs;
-    }
-
   return convert_for_assignment (type, rhs, errtype, fndecl, parmnum);
 }
 \f
@@ -7277,95 +6629,168 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   emit_queue ();
 }
 \f
-/* Expand a C `return' statement.
-   RETVAL is the expression for what to return,
-   or a null pointer for `return;' with no value.
+/* If RETVAL is the address of, or a reference to, a local variable or
+   temporary give an appropraite warning.  */
 
-   C++: upon seeing a `return', we must call destructors on all
-   variables in scope which had constructors called on them.
-   This means that if in a destructor, the base class destructors
-   must be called before returning.
+static void
+maybe_warn_about_returning_address_of_local (retval)
+     tree retval;
+{
+  tree valtype = TREE_TYPE (DECL_RESULT (current_function_decl));
 
-   The RETURN statement in C++ has initialization semantics.  */
+  if (TREE_CODE (valtype) == REFERENCE_TYPE)
+    {
+      tree whats_returned;
 
-void
-c_expand_return (retval)
+      /* Sort through common things to see what it is
+        we are returning.  */
+      whats_returned = retval;
+      if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
+       {
+         whats_returned = TREE_OPERAND (whats_returned, 1);
+         if (TREE_CODE (whats_returned) == ADDR_EXPR)
+           whats_returned = TREE_OPERAND (whats_returned, 0);
+       }
+      while (TREE_CODE (whats_returned) == CONVERT_EXPR
+            || TREE_CODE (whats_returned) == NOP_EXPR)
+       whats_returned = TREE_OPERAND (whats_returned, 0);
+      if (TREE_CODE (whats_returned) == ADDR_EXPR)
+       {
+         whats_returned = TREE_OPERAND (whats_returned, 0);
+         while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
+                || TREE_CODE (whats_returned) == TARGET_EXPR)
+           {
+             /* Get the target.  */
+             whats_returned = TREE_OPERAND (whats_returned, 0);
+             warning ("returning reference to temporary");
+           }
+       }
+
+      if (TREE_CODE (whats_returned) == VAR_DECL 
+         && DECL_NAME (whats_returned))
+       {
+         if (TEMP_NAME_P (DECL_NAME (whats_returned)))
+           warning ("reference to non-lvalue returned");
+         else if (TREE_CODE (TREE_TYPE (whats_returned)) != REFERENCE_TYPE
+                  && DECL_FUNCTION_SCOPE_P (whats_returned)
+                  && !(TREE_STATIC (whats_returned)
+                       || TREE_PUBLIC (whats_returned)))
+           cp_warning_at ("reference to local variable `%D' returned", 
+                          whats_returned);
+       }
+    }
+  else if (TREE_CODE (retval) == ADDR_EXPR)
+    {
+      tree whats_returned = TREE_OPERAND (retval, 0);
+
+      if (TREE_CODE (whats_returned) == VAR_DECL
+         && DECL_NAME (whats_returned)
+         && DECL_FUNCTION_SCOPE_P (whats_returned)
+         && !(TREE_STATIC (whats_returned)
+              || TREE_PUBLIC (whats_returned)))
+       cp_warning_at ("address of local variable `%D' returned", 
+                      whats_returned);
+    }
+}
+
+/* Check that returning RETVAL from the current function is legal.
+   Return an expression explicitly showing all conversions required to
+   change RETVAL into the function return type, and to assign it to
+   the DECL_RESULT for the function.  */
+
+tree
+check_return_expr (retval)
      tree retval;
 {
-  extern struct nesting *cond_stack, *loop_stack, *case_stack;
-  extern tree dtor_label, ctor_label;
-  tree result = DECL_RESULT (current_function_decl);
-  tree valtype = TREE_TYPE (result);
-
+  tree result;
+  /* The type actually returned by the function, after any
+     promotions.  */
+  tree valtype;
+  int fn_returns_value_p;
+
+  /* A `volatile' function is one that isn't supposed to return, ever.
+     (This is a G++ extension, used to get better code for functions
+     that call the `volatile' function.)  */
   if (TREE_THIS_VOLATILE (current_function_decl))
     warning ("function declared `noreturn' has a `return' statement");
 
+  /* Check for various simple errors.  */
   if (retval == error_mark_node)
     {
+      /* If an error occurred, there's nothing to do.  */
       current_function_returns_null = 1;
-      return;
-    }
-
-  if (processing_template_decl)
-    {
-      add_tree (build_min_nt (RETURN_STMT, retval));
-      return;
+      return error_mark_node;
     }
-
-  if (dtor_label)
+  else if (dtor_label)
     {
       if (retval)
        error ("returning a value from a destructor");
+      return NULL_TREE;
+    }
+  else if (in_function_try_handler
+          && DECL_CONSTRUCTOR_P (current_function_decl))
+    {
+      /* If a return statement appears in a handler of the
+         function-try-block of a constructor, the program is ill-formed. */
+      error ("cannot return from a handler of a function-try-block of a constructor");
+      return error_mark_node;
+    }
+  else if (retval && DECL_CONSTRUCTOR_P (current_function_decl))
+    /* You can't return a value from a constructor.  */
+    error ("returning a value from a constructor");
+
+  /* Constructors actually always return `this', even though in C++
+     you can't return a value from a constructor.  */
+  if (DECL_CONSTRUCTOR_P (current_function_decl))
+    retval = current_class_ptr;
+
+  /* When no explicit return-value is given in a function with a named
+     return value, the named return value is used.  */
+  result = DECL_RESULT (current_function_decl);
+  valtype = TREE_TYPE (result);
+  my_friendly_assert (valtype != NULL_TREE, 19990924);
+  fn_returns_value_p = !same_type_p (valtype, void_type_node);
+  if (!retval && DECL_NAME (result) && fn_returns_value_p)
+    retval = result;
+
+  /* Check for a return statement with no return value in a function
+     that's supposed to return a value.  */
+  if (!retval && fn_returns_value_p)
+    {
+      pedwarn ("`return' with no value, in function returning non-void");
+      /* Clear this, so finish_function won't say that we reach the
+        end of a non-void function (which we don't, we gave a
+        return!).  */
+      current_function_returns_null = 0;
+    }
+  /* Check for a return statement with a value in a function that
+     isn't supposed to return a value.  */
+  else if (retval && !fn_returns_value_p)
+    {     
+      if (same_type_p (TREE_TYPE (retval), void_type_node))
+       /* You can return a `void' value from a function of `void'
+          type.  In that case, we have to evaluate the expression for
+          its side-effects.  */
+         finish_expr_stmt (retval);
+      else
+       pedwarn ("`return' with a value, in function returning void");
 
-      /* Can't just return from a destructor.  */
-      expand_goto (dtor_label);
-      return;
+      current_function_returns_null = 1;
+
+      /* There's really no value to return, after all.  */
+      return NULL_TREE;
     }
+  else if (!retval)
+    /* Remember that this function can sometimes return without a
+       value.  */
+    current_function_returns_null = 1;
 
   /* Only operator new(...) throw(), can return NULL [expr.new/13].  */
   if ((DECL_NAME (current_function_decl) == ansi_opname[(int) NEW_EXPR]
        || DECL_NAME (current_function_decl) == ansi_opname[(int) VEC_NEW_EXPR])
       && !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl))
       && null_ptr_cst_p (retval))
-    cp_pedwarn ("operator new should throw an exception, not return NULL");
-  
-  if (retval == NULL_TREE)
-    {
-      /* A non-named return value does not count.  */
-
-      if (DECL_CONSTRUCTOR_P (current_function_decl))
-       retval = current_class_ptr;
-      else if (DECL_NAME (result) != NULL_TREE
-              && TREE_CODE (valtype) != VOID_TYPE)
-       retval = result;
-      else
-       {
-         current_function_returns_null = 1;
-
-         if (valtype != NULL_TREE && TREE_CODE (valtype) != VOID_TYPE)
-           {
-             if (DECL_NAME (DECL_RESULT (current_function_decl)) == NULL_TREE)
-               {
-                 pedwarn ("`return' with no value, in function returning non-void");
-                 /* Clear this, so finish_function won't say that we
-                    reach the end of a non-void function (which we don't,
-                    we gave a return!).  */
-                 current_function_returns_null = 0;
-               }
-           }
-
-         expand_null_return ();
-         return;
-       }
-    }
-  else if (DECL_CONSTRUCTOR_P (current_function_decl))
-    {
-      if (flag_this_is_variable)
-       error ("return from a constructor: use `this = ...' instead");
-      else
-       error ("returning a value from a constructor");
-      retval = current_class_ptr;
-    }
+    cp_warning ("operator new should throw an exception, not return NULL");
 
   /* Effective C++ rule 15.  See also start_function.  */
   if (warn_ecpp
@@ -7373,137 +6798,73 @@ c_expand_return (retval)
       && retval != current_class_ref)
     cp_warning ("`operator=' should return a reference to `*this'");
 
-  if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
-    {
-      current_function_returns_null = 1;
-      if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
-       pedwarn ("`return' with a value, in function returning void");
-      expand_return (retval);
-      return;
-    }
-  
-  /* Now deal with possible C++ hair:
-     (1) Compute the return value.
-     (2) If there are aggregate values with destructors which
-     must be cleaned up, clean them (taking care
-     not to clobber the return value).
-     (3) If an X(X&) constructor is defined, the return
-     value must be returned via that.  */
-
-  if (retval == result
-      || DECL_CONSTRUCTOR_P (current_function_decl))
-    /* It's already done for us.  */;
-  else if (TREE_CODE (TREE_TYPE (retval)) == VOID_TYPE)
-    {
-      pedwarn ("return of void value in function returning non-void");
-      expand_expr_stmt (retval);
-      retval = 0;
-    }
+  /* We don't need to do any conversions when there's nothing being
+     returned.  */
+  if (!retval)
+    return NULL_TREE;
+
+  /* Do any required conversions.  */
+  if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl))
+    /* No conversions are required.  */
+    ;
   else
     {
+      /* The type the function is declared to return.  */
       tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
 
       /* First convert the value to the function's return type, then
         to the type of return value's location to handle the
          case that functype is thiner than the valtype. */
-
       retval = convert_for_initialization
        (NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
         "return", NULL_TREE, 0);
-
       retval = convert (valtype, retval);
 
+      /* If the conversion failed, treat this just like `return;'.  */
       if (retval == error_mark_node)
-       {
-         /* Avoid warning about control reaching end of function.  */
-         expand_null_return ();
-         return;
-       }
-
+       return NULL_TREE;
       /* We can't initialize a register from a AGGR_INIT_EXPR.  */
       else if (! current_function_returns_struct
               && TREE_CODE (retval) == TARGET_EXPR
               && TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
        retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
                        TREE_OPERAND (retval, 0));
+      else
+       maybe_warn_about_returning_address_of_local (retval);
+    }
+  
+  /* Actually copy the value returned into the appropriate location.  */
+  if (retval && retval != result)
+    retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
 
-      /* Add some useful error checking for C++.  */
-      else if (TREE_CODE (valtype) == REFERENCE_TYPE)
-       {
-         tree whats_returned;
-
-         /* Sort through common things to see what it is
-            we are returning.  */
-         whats_returned = retval;
-         if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
-           {
-             whats_returned = TREE_OPERAND (whats_returned, 1);
-             if (TREE_CODE (whats_returned) == ADDR_EXPR)
-               whats_returned = TREE_OPERAND (whats_returned, 0);
-           }
-         while (TREE_CODE (whats_returned) == CONVERT_EXPR
-                || TREE_CODE (whats_returned) == NOP_EXPR)
-           whats_returned = TREE_OPERAND (whats_returned, 0);
-         if (TREE_CODE (whats_returned) == ADDR_EXPR)
-           {
-             whats_returned = TREE_OPERAND (whats_returned, 0);
-             while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
-                    || TREE_CODE (whats_returned) == TARGET_EXPR)
-               {
-                 /* Get the target.  */
-                 whats_returned = TREE_OPERAND (whats_returned, 0);
-                 warning ("returning reference to temporary");
-               }
-           }
+  /* All done.  Remember that this function did return a value.  */
+  current_function_returns_value = 1;
+  return retval;
+}
 
-         if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned))
-           {
-             if (TEMP_NAME_P (DECL_NAME (whats_returned)))
-               warning ("reference to non-lvalue returned");
-             else if (TREE_CODE (TREE_TYPE (whats_returned)) != REFERENCE_TYPE
-                      && DECL_FUNCTION_SCOPE_P (whats_returned)
-                      && !(TREE_STATIC (whats_returned)
-                           || TREE_PUBLIC (whats_returned)))
-               cp_warning_at ("reference to local variable `%D' returned", whats_returned);
-           }
-       }
-      else if (TREE_CODE (retval) == ADDR_EXPR)
-       {
-         tree whats_returned = TREE_OPERAND (retval, 0);
-
-         if (TREE_CODE (whats_returned) == VAR_DECL
-             && DECL_NAME (whats_returned)
-             && DECL_FUNCTION_SCOPE_P (whats_returned)
-             && !(TREE_STATIC (whats_returned)
-                  || TREE_PUBLIC (whats_returned)))
-           cp_warning_at ("address of local variable `%D' returned", whats_returned);
-       }
-    }
+/* Expand a C `return' statement.
+   RETVAL is the expression for what to return,
+   or a null pointer for `return;' with no value.
 
-  if (retval != NULL_TREE
-      && TREE_CODE_CLASS (TREE_CODE (retval)) == 'd'
-      && cond_stack == 0 && loop_stack == 0 && case_stack == 0)
-    current_function_return_value = retval;
+   C++: upon seeing a `return', we must call destructors on all
+   variables in scope which had constructors called on them.
+   This means that if in a destructor, the base class destructors
+   must be called before returning.
 
-  if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
-    {
-      /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do.  */
-      expand_goto (ctor_label);
-    }
+   The RETURN statement in C++ has initialization semantics.  */
 
-  if (retval && retval != result)
+void
+c_expand_return (retval)
+     tree retval;
+{
+  if (!retval)
+    expand_null_return ();
+  else
     {
-      result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
-      TREE_SIDE_EFFECTS (result) = 1;
+      expand_start_target_temps ();
+      expand_return (retval);
+      expand_end_target_temps ();
     }
-
-  expand_start_target_temps ();
-
-  expand_return (result);
-
-  expand_end_target_temps ();
-
-  current_function_returns_value = 1;
 }
 \f
 /* Start a C switch statement, testing expression EXP.
@@ -7685,16 +7046,26 @@ comp_ptr_ttypes_reinterpret (to, from)
     }
 }
 
-/* Returns the type-qualifier set corresponding to TYPE.  */
+/* Recursively examines the array elements of TYPE, until a non-array
+   element type is found.  */
 
-int
-cp_type_quals (type)
+tree
+strip_array_types (type)
      tree type;
 {
   while (TREE_CODE (type) == ARRAY_TYPE)
     type = TREE_TYPE (type);
 
-  return TYPE_QUALS (type);
+  return type;
+}
+
+/* Returns the type-qualifier set corresponding to TYPE.  */
+
+int
+cp_type_quals (type)
+     tree type;
+{
+  return TYPE_QUALS (strip_array_types (type));
 }
 
 /* Returns non-zero if the TYPE contains a mutable member */
@@ -7708,3 +7079,115 @@ cp_has_mutable_p (type)
 
   return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
 }
+
+/* Subroutine of casts_away_constness.  Make T1 and T2 point at
+   exemplar types such that casting T1 to T2 is casting away castness
+   if and only if there is no implicit conversion from T1 to T2.  */
+
+static void
+casts_away_constness_r (t1, t2)
+     tree *t1;
+     tree *t2;
+{
+  int quals1;
+  int quals2;
+
+  /* [expr.const.cast]
+
+     For multi-level pointer to members and multi-level mixed pointers
+     and pointers to members (conv.qual), the "member" aspect of a
+     pointer to member level is ignored when determining if a const
+     cv-qualifier has been cast away.  */
+  if (TYPE_PTRMEM_P (*t1))
+    *t1 = build_pointer_type (TREE_TYPE (TREE_TYPE (*t1)));
+  if (TYPE_PTRMEM_P (*t2))
+    *t2 = build_pointer_type (TREE_TYPE (TREE_TYPE (*t2)));
+
+  /* [expr.const.cast]
+
+     For  two  pointer types:
+
+            X1 is T1cv1,1 * ... cv1,N *   where T1 is not a pointer type
+            X2 is T2cv2,1 * ... cv2,M *   where T2 is not a pointer type
+            K is min(N,M)
+
+     casting from X1 to X2 casts away constness if, for a non-pointer
+     type T there does not exist an implicit conversion (clause
+     _conv_) from:
+
+            Tcv1,(N-K+1) * cv1,(N-K+2) * ... cv1,N *
+      
+     to
+
+            Tcv2,(M-K+1) * cv2,(M-K+2) * ... cv2,M *.  */
+
+  if (TREE_CODE (*t1) != POINTER_TYPE
+      || TREE_CODE (*t2) != POINTER_TYPE)
+    {
+      *t1 = cp_build_qualified_type (void_type_node,
+                                    CP_TYPE_QUALS (*t1));
+      *t2 = cp_build_qualified_type (void_type_node,
+                                    CP_TYPE_QUALS (*t2));
+      return;
+    }
+  
+  quals1 = CP_TYPE_QUALS (*t1);
+  quals2 = CP_TYPE_QUALS (*t2);
+  *t1 = TREE_TYPE (*t1);
+  *t2 = TREE_TYPE (*t2);
+  casts_away_constness_r (t1, t2);
+  *t1 = build_pointer_type (*t1);
+  *t2 = build_pointer_type (*t2);
+  *t1 = cp_build_qualified_type (*t1, quals1);
+  *t2 = cp_build_qualified_type (*t2, quals2);
+}
+
+/* Returns non-zero if casting from TYPE1 to TYPE2 casts away
+   constness.  */
+
+static int
+casts_away_constness (t1, t2)
+     tree t1;
+     tree t2;
+{
+  if (TREE_CODE (t2) == REFERENCE_TYPE)
+    {
+      /* [expr.const.cast]
+        
+        Casting from an lvalue of type T1 to an lvalue of type T2
+        using a reference cast casts away constness if a cast from an
+        rvalue of type "pointer to T1" to the type "pointer to T2"
+        casts away constness.  */
+      t1 = (TREE_CODE (t1) == REFERENCE_TYPE
+           ? TREE_TYPE (t1) : t1);
+      return casts_away_constness (build_pointer_type (t1),
+                                  build_pointer_type (TREE_TYPE (t2)));
+    }
+
+  if (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2))
+    /* [expr.const.cast]
+       
+       Casting from an rvalue of type "pointer to data member of X
+       of type T1" to the type "pointer to data member of Y of type
+       T2" casts away constness if a cast from an rvalue of type
+       "poitner to T1" to the type "pointer to T2" casts away
+       constness.  */
+    return casts_away_constness
+      (build_pointer_type (TREE_TYPE (TREE_TYPE (t1))),
+       build_pointer_type (TREE_TYPE (TREE_TYPE (t2))));
+
+  /* Casting away constness is only something that makes sense for
+     pointer or reference types.  */
+  if (TREE_CODE (t1) != POINTER_TYPE 
+      || TREE_CODE (t2) != POINTER_TYPE)
+    return 0;
+
+  /* Top-level qualifiers don't matter.  */
+  t1 = TYPE_MAIN_VARIANT (t1);
+  t2 = TYPE_MAIN_VARIANT (t2);
+  casts_away_constness_r (&t1, &t2);
+  if (!can_convert (t2, t1))
+    return 1;
+
+  return 0;
+}