cp-tree.h (CP_INTEGRAL_TYPE_P): New macro.
authorMark Mitchell <mark@codesourcery.com>
Mon, 26 Jul 1999 08:18:19 +0000 (08:18 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Mon, 26 Jul 1999 08:18:19 +0000 (08:18 +0000)
* cp-tree.h (CP_INTEGRAL_TYPE_P): New macro.
(ARITHMETIC_TYPE_P): Adjust definition for standard conformance.
(strip_top_quals): Declare.
(ncp_convert): Likewise.
(type_after_usual_arithmetic_converions): Likewise.
(composite_pointer_type): Likewise.
* call.c (strip_top_quals): Don't make it static.
(promoted_arithmetic_type_p): New function.
(conditional_conversion): Likewise.
(null_ptr_cst_p): Allow `false' as a NULL pointer constant.
(standard_conversion): Use same_type_p.  Don't build BASE_CONVs
for converting a type to itself.
(reference_binding): Honor LOOKUP_NO_TEMP_BIND.
(implicit_conversion): Make sure the from and to types are
complete.
(add_builtin_candidate): Correct handling of ?: operator.
(add_builtin_candidates): Improve documentation.
(build_conditional_expr): New function.
(can_convert): Implement in terms of can_convert_arg.
(ncp_convert): New function.
* typeck.c (type_after_usual_arithmetic_conversions): New
function, split out from common_type.
(composite_pointer_type): New function, split out from
build_conditional_expr.
(common_type): Use type_after_usual_arithmetic_conversions.
Remove redundant attribute merging.
(comptypes): Tidy.  Handle COMPLEX_TYPE.
(build_binary_op_nodefault): Use null_ptr_cst_p.
(build_conditional_expr): Remove.
(convert_for_assignment): Use new conversion functions.

* cp-tree.h (abstract_virtuals_error): Change declaration.
* typeck2.c (abstract_virtuals_error): Check to see if an error
ocurred, and return a boolean value accordingly.
(build_functional_cast): Adjust accordingly.
* class.c (finish_struct_1): Likewise.
* cvt.c (ocp_convert): Likewise.
* decl.c (cp_finish_decl): Likewise.
(grokparams): Likewise.
(grok_op_properties): Likewise.
(start_function): Likewise.
* init.c (build_new_1): Likewise.

* pt.c (unify): Don't get confused by pointers-to-member functions.

* search.c (build_cplus_new): Robustify.

From-SVN: r28262

17 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/init.c
gcc/cp/pt.c
gcc/cp/search.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/g++.old-deja/g++.brendan/crash19.C
gcc/testsuite/g++.old-deja/g++.jason/typedef.C
gcc/testsuite/g++.old-deja/g++.mike/p10769a.C
gcc/testsuite/g++.old-deja/g++.other/cond1.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.other/conv5.C
gcc/testsuite/g++.old-deja/g++.other/overload10.C [new file with mode: 0644]

index b0efd31110fe631cc1468912ffa75afe389fa026..4dba90246fbf1eb1b3466671ab654aaf31c093c0 100644 (file)
@@ -1,3 +1,52 @@
+1999-07-26  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp-tree.h (CP_INTEGRAL_TYPE_P): New macro.
+       (ARITHMETIC_TYPE_P): Adjust definition for standard conformance.
+       (strip_top_quals): Declare.
+       (ncp_convert): Likewise.
+       (type_after_usual_arithmetic_converions): Likewise.
+       (composite_pointer_type): Likewise.
+       * call.c (strip_top_quals): Don't make it static.
+       (promoted_arithmetic_type_p): New function.
+       (conditional_conversion): Likewise.
+       (null_ptr_cst_p): Allow `false' as a NULL pointer constant.
+       (standard_conversion): Use same_type_p.  Don't build BASE_CONVs
+       for converting a type to itself.
+       (reference_binding): Honor LOOKUP_NO_TEMP_BIND.
+       (implicit_conversion): Make sure the from and to types are
+       complete.
+       (add_builtin_candidate): Correct handling of ?: operator.
+       (add_builtin_candidates): Improve documentation.
+       (build_conditional_expr): New function.
+       (can_convert): Implement in terms of can_convert_arg.
+       (ncp_convert): New function.
+       * typeck.c (type_after_usual_arithmetic_conversions): New
+       function, split out from common_type.
+       (composite_pointer_type): New function, split out from
+       build_conditional_expr.
+       (common_type): Use type_after_usual_arithmetic_conversions.
+       Remove redundant attribute merging.
+       (comptypes): Tidy.  Handle COMPLEX_TYPE.
+       (build_binary_op_nodefault): Use null_ptr_cst_p.
+       (build_conditional_expr): Remove.
+       (convert_for_assignment): Use new conversion functions.
+       
+       * cp-tree.h (abstract_virtuals_error): Change declaration.
+       * typeck2.c (abstract_virtuals_error): Check to see if an error
+       ocurred, and return a boolean value accordingly.
+       (build_functional_cast): Adjust accordingly.
+       * class.c (finish_struct_1): Likewise.
+       * cvt.c (ocp_convert): Likewise.
+       * decl.c (cp_finish_decl): Likewise.
+       (grokparams): Likewise.
+       (grok_op_properties): Likewise.
+       (start_function): Likewise.
+       * init.c (build_new_1): Likewise.
+
+       * pt.c (unify): Don't get confused by pointers-to-member functions.
+
+       * search.c (build_cplus_new): Robustify.
+       
 1999-07-24  Richard Henderson  <rth@cygnus.com>
 
        * decl.c (ptr_type_node, va_list_type_node): New.
index 6e75e94dd0b2ea3a51dca746490642710ef0208f..cd5e77d6a2c5e323999f7e89d7031800c420756e 100644 (file)
@@ -82,7 +82,6 @@ static struct z_candidate * add_function_candidate
 static tree implicit_conversion PROTO((tree, tree, tree, int));
 static tree standard_conversion PROTO((tree, tree, tree));
 static tree reference_binding PROTO((tree, tree, tree, int));
-static tree strip_top_quals PROTO((tree));
 static tree non_reference PROTO((tree));
 static tree build_conv PROTO((enum tree_code, tree, tree));
 static int is_subseq PROTO((tree, tree));
@@ -96,6 +95,8 @@ static int reference_related_p PROTO ((tree, tree));
 static int reference_compatible_p PROTO ((tree, tree));
 static tree convert_class_to_reference PROTO ((tree, tree, tree));
 static tree direct_reference_binding PROTO ((tree, tree));
+static int promoted_arithmetic_type_p PROTO ((tree));
+static tree conditional_conversion PROTO ((tree, tree));
 
 tree
 build_vfield_ref (datum, type)
@@ -550,8 +551,12 @@ int
 null_ptr_cst_p (t)
      tree t;
 {
+  /* [conv.ptr]
+
+     A null pointer constant is an integral constant expression
+     (_expr.const_) rvalue of integer type that evaluates to zero.  */
   if (t == null_node
-      || (integer_zerop (t) && TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE))
+      || (CP_INTEGRAL_TYPE_P (TREE_TYPE (t)) && integer_zerop (t)))
     return 1;
   return 0;
 }
@@ -595,7 +600,7 @@ non_reference (t)
   return t;
 }
 
-static tree
+tree
 strip_top_quals (t)
      tree t;
 {
@@ -655,7 +660,7 @@ standard_conversion (to, from, expr)
   else if (fromref || (expr && real_lvalue_p (expr)))
     conv = build_conv (RVALUE_CONV, from, conv);
 
-  if (from == to)
+  if (same_type_p (from, to))
     return conv;
 
   if ((tcode == POINTER_TYPE || TYPE_PTRMEMFUNC_P (to))
@@ -770,7 +775,7 @@ standard_conversion (to, from, expr)
        ICS_STD_RANK (conv) = PROMO_RANK;
     }
   else if (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
-          && DERIVED_FROM_P (to, from))
+          && is_properly_derived_from (from, to))
     {
       if (TREE_CODE (conv) == RVALUE_CONV)
        conv = TREE_OPERAND (conv, 0);
@@ -1069,6 +1074,11 @@ reference_binding (rto, rfrom, expr, flags)
        return direct_reference_binding (rto, conv);
     }
 
+  /* From this point on, we conceptually need temporaries, even if we
+     elide them.  Only the cases above are "direct bindings".  */
+  if (flags & LOOKUP_NO_TEMP_BIND)
+    return NULL_TREE;
+
   /* [over.ics.rank]
      
      When a parameter of reference type is not bound directly to an
@@ -1141,6 +1151,9 @@ implicit_conversion (to, from, expr, flags)
   tree conv;
   struct z_candidate *cand;
 
+  complete_type (from);
+  complete_type (to);
+
   if (TREE_CODE (to) == REFERENCE_TYPE)
     conv = reference_binding (to, from, expr, flags);
   else
@@ -1461,6 +1474,24 @@ is_complete (t)
   return TYPE_SIZE (complete_type (t)) != NULL_TREE;
 }
 
+/* Returns non-zero if TYPE is a promoted arithmetic type.  */
+
+static int
+promoted_arithmetic_type_p (type)
+     tree type;
+{
+  /* [over.built]
+
+     In this section, the term promoted integral type is used to refer
+     to those integral types which are preserved by integral promotion
+     (including e.g.  int and long but excluding e.g.  char).
+     Similarly, the term promoted arithmetic type refers to promoted
+     integral types plus floating types.  */
+  return ((INTEGRAL_TYPE_P (type)
+          && same_type_p (type_promotes_to (type), type))
+         || TREE_CODE (type) == REAL_TYPE);
+}
+
 /* Create any builtin operator overload candidates for the operator in
    question given the converted operand types TYPE1 and TYPE2.  The other
    args are passed through from add_builtin_candidates to
@@ -1800,43 +1831,41 @@ add_builtin_candidate (candidates, code, code2, fnname, type1, type2,
       break;
 
     case COND_EXPR:
-      /* Kludge around broken overloading rules whereby
-        bool ? const char& : enum is ambiguous
-        (between int and const char&).  */
-      flags |= LOOKUP_NO_TEMP_BIND;
+      /* [over.builtin]
+
+        For every pair of promoted arithmetic types L and R, there
+        exist candidate operator functions of the form 
 
-      /* Extension: Support ?: of enumeral type.  Hopefully this will not
-         be an extension for long.  */
-      if (TREE_CODE (type1) == ENUMERAL_TYPE && type1 == type2)
+        LR operator?(bool, L, R); 
+
+        where LR is the result of the usual arithmetic conversions
+        between types L and R.
+
+        For every type T, where T is a pointer or pointer-to-member
+        type, there exist candidate operator functions of the form T
+        operator?(bool, T, T);  */
+
+      if (promoted_arithmetic_type_p (type1)
+         && promoted_arithmetic_type_p (type2))
+       /* That's OK.  */
        break;
-      else if (TREE_CODE (type1) == ENUMERAL_TYPE
-              || TREE_CODE (type2) == ENUMERAL_TYPE)
+
+      /* Otherwise, the types should be pointers.  */
+      if (!(TREE_CODE (type1) == POINTER_TYPE
+           || TYPE_PTRMEM_P (type1)
+           || TYPE_PTRMEMFUNC_P (type1))
+         || !(TREE_CODE (type2) == POINTER_TYPE
+              || TYPE_PTRMEM_P (type2)
+              || TYPE_PTRMEMFUNC_P (type2)))
        return candidates;
-      if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
-       break;
-      if (TREE_CODE (type1) == TREE_CODE (type2)
-         && (TREE_CODE (type1) == REFERENCE_TYPE
-             || TREE_CODE (type1) == POINTER_TYPE
-             || TYPE_PTRMEMFUNC_P (type1)
-             || IS_AGGR_TYPE (type1)))
+      
+      /* We don't check that the two types are the same; the logic
+        below will actually create two candidates; one in which both
+        parameter types are TYPE1, and one in which both parameter
+        types are TYPE2.  */
        break;
-      if (TREE_CODE (type1) == REFERENCE_TYPE
-         || TREE_CODE (type2) == REFERENCE_TYPE)
-       return candidates;
-      if (((TYPE_PTRMEMFUNC_P (type1) || TREE_CODE (type1) == POINTER_TYPE)
-          && null_ptr_cst_p (args[1]))
-         || IS_AGGR_TYPE (type1))
-       {
-         type2 = type1;
-         break;
-       }
-      if (((TYPE_PTRMEMFUNC_P (type2) || TREE_CODE (type2) == POINTER_TYPE)
-          && null_ptr_cst_p (args[0]))
-         || IS_AGGR_TYPE (type2))
-       {
-         type1 = type2;
-         break;
-       }
+
+      /* These arguments do not make for a legal overloaded operator.  */
       return candidates;
 
     default:
@@ -1845,7 +1874,7 @@ add_builtin_candidate (candidates, code, code2, fnname, type1, type2,
 
   /* If we're dealing with two pointer types, we need candidates
      for both of them.  */
-  if (type2 && type1 != type2
+  if (type2 && !same_type_p (type1, type2)
       && TREE_CODE (type1) == TREE_CODE (type2)
       && (TREE_CODE (type1) == REFERENCE_TYPE
          || (TREE_CODE (type1) == POINTER_TYPE
@@ -1890,7 +1919,12 @@ add_builtin_candidates (candidates, code, code2, fnname, args, flags)
      int flags;
 {
   int ref1, i;
-  tree type, argtypes[3], types[2];
+  tree type, argtypes[3];
+  /* TYPES[i] is the set of possible builtin-operator parameter types
+     we will consider for the Ith argument.  These are represented as
+     a TREE_LIST; the TREE_VALUE of each node is the potential
+     parameter type.  */
+  tree types[2];
 
   for (i = 0; i < 3; ++i)
     {
@@ -2012,6 +2046,8 @@ add_builtin_candidates (candidates, code, code2, fnname, args, flags)
        }
     }
 
+  /* Run through the possible parameter types of both arguments,
+     creating candidates with those parameter types.  */
   for (; types[0]; types[0] = TREE_CHAIN (types[0]))
     {
       if (types[1])
@@ -2635,6 +2671,374 @@ op_error (code, code2, arg1, arg2, arg3, problem)
     }
 }
 
+/* Return the implicit conversion sequence that could be used to
+   convert E1 to E2 in [expr.cond].  */
+
+static tree
+conditional_conversion (e1, e2)
+     tree e1;
+     tree e2;
+{
+  tree t1 = non_reference (TREE_TYPE (e1));
+  tree t2 = non_reference (TREE_TYPE (e2));
+  tree conv;
+
+  /* [expr.cond]
+
+     If E2 is an lvalue: E1 can be converted to match E2 if E1 can be
+     implicitly converted (clause _conv_) to the type "reference to
+     T2", subject to the constraint that in the conversion the
+     reference must bind directly (_dcl.init.ref_) to E1.  */
+  if (real_lvalue_p (e2))
+    {
+      conv = implicit_conversion (build_reference_type (t2), 
+                                 t1,
+                                 e1,
+                                 LOOKUP_NO_TEMP_BIND);
+      if (conv)
+       return conv;
+    }
+
+  /* [expr.cond]
+
+     If E1 and E2 have class type, and the underlying class types are
+     the same or one is a base class of the other: E1 can be converted
+     to match E2 if the class of T2 is the same type as, or a base
+     class of, the class of T1, and the cv-qualification of T2 is the
+     same cv-qualification as, or a greater cv-qualification than, the
+     cv-qualification of T1.  If the conversion is applied, E1 is
+     changed to an rvalue of type T2 that still refers to the original
+     source class object (or the appropriate subobject thereof).  */
+  if (CLASS_TYPE_P (t1) && CLASS_TYPE_P (t2)
+      && same_or_base_type_p (TYPE_MAIN_VARIANT (t2), 
+                             TYPE_MAIN_VARIANT (t1)))
+    {
+      if (at_least_as_qualified_p (t2, t1))
+       {
+         conv = build1 (IDENTITY_CONV, t1, e1);
+         conv = build_conv (BASE_CONV, t2, conv);
+         return conv;
+       }
+      else
+       return NULL_TREE;
+    }
+
+  /* [expr.cond]
+
+     E1 can be converted to match E2 if E1 can be implicitly converted
+     to the type that expression E2 would have if E2 were converted to
+     an rvalue (or the type it has, if E2 is an rvalue).  */
+  return implicit_conversion (t2, t1, e1, LOOKUP_NORMAL);
+}
+
+/* Implement [expr.cond].  ARG1, ARG2, and ARG3 are the three
+   arguments to the conditional expression.  As an extension, g++
+   allows users to overload the ?: operator.  By the time this
+   function is called, any suitable candidate functions are included
+   in CANDIDATES.  */
+
+tree
+build_conditional_expr (arg1, arg2, arg3)
+     tree arg1;
+     tree arg2;
+     tree arg3;
+{
+  tree arg2_type;
+  tree arg3_type;
+  tree result;
+  tree result_type = NULL_TREE;
+  int lvalue_p = 1;
+  struct z_candidate *candidates = 0;
+  struct z_candidate *cand;
+
+  /* As a G++ extension, the second argument to the conditional can be
+     omitted.  (So that `a ? : c' is roughly equivalent to `a ? a :
+     c'.)  If second operand is omitted, make sure it is calculated
+     only once.  */
+  if (!arg2)
+    {
+      if (pedantic)
+       pedwarn ("ANSI C++ forbids omitting the middle term of a ?: expression");
+      arg1 = arg2 = save_expr (arg1);
+    }
+
+  /* If something has already gone wrong, just pass that fact up the
+     tree.  */
+  if (arg1 == error_mark_node 
+      || arg2 == error_mark_node 
+      || arg3 == error_mark_node 
+      || TREE_TYPE (arg1) == error_mark_node
+      || TREE_TYPE (arg2) == error_mark_node
+      || TREE_TYPE (arg3) == error_mark_node)
+    return error_mark_node;
+
+  /* [expr.cond]
+  
+     The first expr ession is implicitly converted to bool (clause
+     _conv_).  */
+  arg1 = cp_convert (boolean_type_node, arg1);
+
+  /* [expr.cond]
+
+     If either the second or the third operand has type (possibly
+     cv-qualified) void, then the lvalue-to-rvalue (_conv.lval_),
+     array-to-pointer (_conv.array_), and function-to-pointer
+     (_conv.func_) standard conversions are performed on the second
+     and third operands.  */
+  arg2_type = TREE_TYPE (arg2);
+  arg3_type = TREE_TYPE (arg3);
+  if (same_type_p (TYPE_MAIN_VARIANT (arg2_type), void_type_node)
+      || same_type_p (TYPE_MAIN_VARIANT (arg3_type), void_type_node))
+    {
+      int arg2_void_p;
+      int arg3_void_p;
+
+      /* Do the conversions.  We don't these for `void' type arguments
+        since it can't have any effect and since decay_conversion
+        does not handle that case gracefully.  */
+      if (!same_type_p (TYPE_MAIN_VARIANT (arg2_type), void_type_node))
+       arg2 = decay_conversion (arg2);
+      if (!same_type_p (TYPE_MAIN_VARIANT (arg3_type), void_type_node))
+       arg3 = decay_conversion (arg3);
+      arg2_type = TREE_TYPE (arg2);
+      arg3_type = TREE_TYPE (arg3);
+
+      arg2_void_p = same_type_p (TYPE_MAIN_VARIANT (arg2_type),
+                                void_type_node);
+      arg3_void_p = same_type_p (TYPE_MAIN_VARIANT (arg3_type),
+                                void_type_node);
+
+      /* [expr.cond]
+
+        One of the following shall hold:
+
+        --The second or the third operand (but not both) is a
+          throw-expression (_except.throw_); the result is of the
+          type of the other and is an rvalue.
+
+        --Both the second and the third operands have type void; the
+          result is of type void and is an rvalue.   */
+      if ((TREE_CODE (arg2) == THROW_EXPR)
+         ^ (TREE_CODE (arg3) == THROW_EXPR))
+       result_type = ((TREE_CODE (arg2) == THROW_EXPR) 
+                      ? arg2_type : arg3_type);
+      else if (arg2_void_p && arg3_void_p)
+       result_type = void_type_node;
+      else
+       {
+         cp_error ("`%E' has type `void' and is not a throw-expression",
+                   arg2_void_p ? arg2 : arg3);
+         return error_mark_node;
+       }
+
+      lvalue_p = 0;
+      goto valid_operands;
+    }
+  /* [expr.cond]
+
+     Otherwise, if the second and third operand have different types,
+     and either has (possibly cv-qualified) class type, an attempt is
+     made to convert each of those operands to the type of the other.  */
+  else if (!same_type_p (arg2_type, arg3_type)
+          && (CLASS_TYPE_P (arg2_type) || CLASS_TYPE_P (arg3_type)))
+    {
+      tree conv2 = conditional_conversion (arg2, arg3);
+      tree conv3 = conditional_conversion (arg3, arg2);
+      
+      /* [expr.cond]
+
+        If both can be converted, or one can be converted but the
+        conversion is ambiguous, the program is ill-formed.  If
+        neither can be converted, the operands are left unchanged and
+        further checking is performed as described below.  If exactly
+        one conversion is possible, that conversion is applied to the
+        chosen operand and the converted operand is used in place of
+        the original operand for the remainder of this section.  */
+      if ((conv2 && !ICS_BAD_FLAG (conv2) 
+          && conv3 && !ICS_BAD_FLAG (conv3))
+         || (conv2 && TREE_CODE (conv2) == AMBIG_CONV)
+         || (conv3 && TREE_CODE (conv3) == AMBIG_CONV))
+       {
+         cp_error ("operands to ?: have different types");
+         return error_mark_node;
+       }
+      else if (conv2 && !ICS_BAD_FLAG (conv2))
+       {
+         arg2 = convert_like (conv2, arg2);
+         arg2_type = TREE_TYPE (arg2);
+       }
+      else if (conv3 && !ICS_BAD_FLAG (conv3))
+       {
+         arg3 = convert_like (conv3, arg3);
+         arg3_type = TREE_TYPE (arg3);
+       }
+    }
+
+  /* [expr.cond]
+
+     If the second and third operands are lvalues and have the same
+     type, the result is of that type and is an lvalue.  */
+  arg2_type = non_reference (arg2_type);
+  arg3_type = non_reference (arg3_type);
+  if (real_lvalue_p (arg2) && real_lvalue_p (arg3) && 
+      same_type_p (arg2_type, arg3_type))
+    {
+      result_type = arg2_type;
+      goto valid_operands;
+    }
+
+  /* [expr.cond]
+
+     Otherwise, the result is an rvalue.  If the second and third
+     operand do not have the same type, and either has (possibly
+     cv-qualified) class type, overload resolution is used to
+     determine the conversions (if any) to be applied to the operands
+     (_over.match.oper_, _over.built_).  */
+  lvalue_p = 0;
+  if (!same_type_p (arg2_type, arg3_type)
+      && (CLASS_TYPE_P (arg2_type) || CLASS_TYPE_P (arg3_type)))
+    {
+      tree args[3];
+      tree conv;
+
+      /* Rearrange the arguments so that add_builtin_candidate only has
+        to know about two args.  In build_builtin_candidates, the
+        arguments are unscrambled.  */
+      args[0] = arg2;
+      args[1] = arg3;
+      args[2] = arg1;
+      candidates = add_builtin_candidates (candidates, 
+                                          COND_EXPR, 
+                                          NOP_EXPR,
+                                          ansi_opname[COND_EXPR],
+                                          args,
+                                          LOOKUP_NORMAL);
+
+      /* [expr.cond]
+
+        If the overload resolution fails, the program is
+        ill-formed.  */
+      if (!any_viable (candidates))
+       {
+         op_error (COND_EXPR, NOP_EXPR, arg1, arg2, arg3, "no match");
+         print_z_candidates (candidates);
+         return error_mark_node;
+       }
+      candidates = splice_viable (candidates);
+      cand = tourney (candidates);
+      if (!cand)
+       {
+         op_error (COND_EXPR, NOP_EXPR, arg1, arg2, arg3, "no match");
+         print_z_candidates (candidates);
+         return error_mark_node;
+       }
+
+      /* [expr.cond]
+
+        Otherwise, the conversions thus determined are applied, and
+        the converted operands are used in place of the original
+        operands for the remainder of this section.  */
+      conv = TREE_VEC_ELT (cand->convs, 0);
+      arg1 = convert_like (conv, arg1);
+      conv = TREE_VEC_ELT (cand->convs, 1);
+      arg2 = convert_like (conv, arg2);
+      conv = TREE_VEC_ELT (cand->convs, 2);
+      arg3 = convert_like (conv, arg3);
+    }
+
+  /* [expr.cond]
+
+     Lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_),
+     and function-to-pointer (_conv.func_) standard conversions are
+     performed on the second and third operands.  */
+  arg2 = decay_conversion (arg2);
+  arg2_type = TREE_TYPE (arg2);
+  arg3 = decay_conversion (arg3);
+  arg3_type = TREE_TYPE (arg3);
+
+  /* [expr.cond]
+     
+     After those conversions, one of the following shall hold:
+
+     --The second and third operands have the same type; the result  is  of
+       that type.  */
+  if (same_type_p (arg2_type, arg3_type))
+    result_type = arg2_type;
+  /* [expr.cond]
+
+     --The second and third operands have arithmetic or enumeration
+       type; the usual arithmetic conversions are performed to bring
+       them to a common type, and the result is of that type.  */
+  else if ((ARITHMETIC_TYPE_P (arg2_type) 
+           || TREE_CODE (arg2_type) == ENUMERAL_TYPE)
+          && (ARITHMETIC_TYPE_P (arg3_type)
+              || TREE_CODE (arg3_type) == ENUMERAL_TYPE))
+    {
+      /* In this case, there is always a common type.  */
+      result_type = type_after_usual_arithmetic_conversions (arg2_type, 
+                                                            arg3_type);
+      arg2 = ncp_convert (result_type, arg2);
+      arg3 = ncp_convert (result_type, arg3);
+    }
+  /* [expr.cond]
+
+     --The second and third operands have pointer type, or one has
+       pointer type and the other is a null pointer constant; pointer
+       conversions (_conv.ptr_) and qualification conversions
+       (_conv.qual_) are performed to bring them to their composite
+       pointer type (_expr.rel_).  The result is of the composite
+       pointer type.
+
+     --The second and third operands have pointer to member type, or
+       one has pointer to member type and the other is a null pointer
+       constant; pointer to member conversions (_conv.mem_) and
+       qualification conversions (_conv.qual_) are performed to bring
+       them to a common type, whose cv-qualification shall match the
+       cv-qualification of either the second or the third operand.
+       The result is of the common type.   */
+  else if ((null_ptr_cst_p (arg2) 
+           && (TYPE_PTR_P (arg3_type) || TYPE_PTRMEM_P (arg3_type)
+               || TYPE_PTRMEMFUNC_P (arg3_type)))
+          || (null_ptr_cst_p (arg3) 
+              && (TYPE_PTR_P (arg2_type) || TYPE_PTRMEM_P (arg2_type)
+               || TYPE_PTRMEMFUNC_P (arg2_type)))
+          || (TYPE_PTR_P (arg2_type) && TYPE_PTR_P (arg3_type))
+          || (TYPE_PTRMEM_P (arg2_type) && TYPE_PTRMEM_P (arg3_type))
+          || (TYPE_PTRMEMFUNC_P (arg2_type) 
+              && TYPE_PTRMEMFUNC_P (arg3_type)))
+    {
+      result_type = composite_pointer_type (arg2_type, arg3_type, arg2,
+                                           arg3, "conditional expression");
+      arg2 = ncp_convert (result_type, arg2);
+      arg3 = ncp_convert (result_type, arg3);
+    }
+
+  if (!result_type)
+    {
+      cp_error ("operands to ?: have different types");
+      return error_mark_node;
+    }
+
+ valid_operands:
+  result = fold (build (COND_EXPR, result_type, arg1, arg2, arg3));
+  /* Expand both sides into the same slot, hopefully the target of the
+     ?: expression.  */
+  if (TREE_CODE (arg2) == TARGET_EXPR && TREE_CODE (arg3) == TARGET_EXPR)
+    {
+      tree slot = build (VAR_DECL, result_type);
+      layout_decl (slot, 0);
+      result = build (TARGET_EXPR, result_type,
+                     slot, result, NULL_TREE, NULL_TREE);
+    }
+  
+  /* If this expression is an rvalue, but might be mistaken for an
+     lvalue, we must add a NON_LVALUE_EXPR.  */
+  if (!lvalue_p && real_lvalue_p (result))
+    result = build1 (NON_LVALUE_EXPR, result_type, result);
+
+  return result;
+}
+
 tree
 build_new_op (code, flags, arg1, arg2, arg3)
      enum tree_code code;
@@ -4660,8 +5064,7 @@ int
 can_convert (to, from)
      tree to, from;
 {
-  tree t = implicit_conversion (to, from, NULL_TREE, LOOKUP_NORMAL);
-  return (t && ! ICS_BAD_FLAG (t));
+  return can_convert_arg (to, from, NULL_TREE);
 }
 
 int
@@ -4672,6 +5075,22 @@ can_convert_arg (to, from, arg)
   return (t && ! ICS_BAD_FLAG (t));
 }
 
+tree
+ncp_convert (type, expr)
+     tree type;
+     tree expr;
+{
+  tree conv = implicit_conversion (type, TREE_TYPE (expr), expr,
+                                  LOOKUP_NORMAL);
+  if (!conv || ICS_BAD_FLAG (conv))
+    {
+      cp_error ("could not convert `%E' to `%T'", expr, type);
+      return error_mark_node;
+    }
+
+  return convert_like (conv, expr);
+}
+
 /* Convert EXPR to the indicated reference TYPE, in a way suitable for
    initializing a variable of that TYPE.  Return the converted
    expression.  */
index 41f1d79a914410d1b9cfd1059e46ea94dc78e992..a4cc5a507ace92c7035dd631819ea9bfc125b6d4 100644 (file)
@@ -3619,8 +3619,7 @@ finish_struct_1 (t)
            {
              /* Never let anything with uninheritable virtuals
                 make it through without complaint.  */
-             if (CLASSTYPE_ABSTRACT_VIRTUALS (type))
-               abstract_virtuals_error (x, type);
+             abstract_virtuals_error (x, type);
                      
              /* Don't let signatures make it through either.  */
              if (IS_SIGNATURE (type))
index 50d28ca9f1d7f8f3ebcd2a38fd4c03518a775c2c..4e13392a98ac861e603bd78a9d49255b86f5d1eb 100644 (file)
@@ -1660,7 +1660,24 @@ extern int flag_new_for_scope;
 
 #define INTEGRAL_CODE_P(CODE) \
   (CODE == INTEGER_TYPE || CODE == ENUMERAL_TYPE || CODE == BOOLEAN_TYPE)
-#define ARITHMETIC_TYPE_P(TYPE) (INTEGRAL_TYPE_P (TYPE) || FLOAT_TYPE_P (TYPE))
+
+/* [basic.fundamental]
+
+   Types  bool, char, wchar_t, and the signed and unsigned integer types
+   are collectively called integral types.  
+
+   Note that INTEGRAL_TYPE_P, as defined in tree.h, allows enumeration
+   types as well, which is incorrect in C++.  */
+#define CP_INTEGRAL_TYPE_P(TYPE)               \
+  (TREE_CODE ((TYPE)) == BOOLEAN_TYPE          \
+   || TREE_CODE ((TYPE)) == INTEGER_TYPE)
+
+/* [basic.fundamental]
+
+   Integral and floating types are collectively called arithmetic
+   types.  */
+#define ARITHMETIC_TYPE_P(TYPE) \
+  (CP_INTEGRAL_TYPE_P (TYPE) || TREE_CODE (TYPE) == REAL_TYPE)
 
 /* Mark which labels are explicitly declared.
    These may be shadowed, and may be referenced from nested functions.  */
@@ -2767,6 +2784,8 @@ extern tree convert_default_arg                 PROTO((tree, tree, tree));
 extern tree convert_arg_to_ellipsis             PROTO((tree));
 extern int is_properly_derived_from             PROTO((tree, tree));
 extern tree initialize_reference                PROTO((tree, tree));
+extern tree strip_top_quals                     PROTO((tree));
+extern tree ncp_convert                         PROTO((tree, tree));
 
 /* in class.c */
 extern tree build_vbase_path                   PROTO((enum tree_code, tree, tree, tree, int));
@@ -3534,12 +3553,14 @@ extern tree build_ptrmemfunc1                   PROTO((tree, tree, tree, tree, t
 extern void expand_ptrmemfunc_cst               PROTO((tree, tree *, tree *, tree *, tree *));
 extern tree delta2_from_ptrmemfunc              PROTO((tree));
 extern tree pfn_from_ptrmemfunc                 PROTO((tree));
+extern tree type_after_usual_arithmetic_conversions PROTO((tree, tree));
+extern tree composite_pointer_type              PROTO((tree, tree, tree, tree, char*));
 
 /* in typeck2.c */
 extern tree error_not_base_type                        PROTO((tree, tree));
 extern tree binfo_or_else                      PROTO((tree, tree));
 extern void readonly_error                     PROTO((tree, const char *, int));
-extern void abstract_virtuals_error            PROTO((tree, tree));
+extern int abstract_virtuals_error             PROTO((tree, tree));
 extern void signature_error                    PROTO((tree, tree));
 extern void incomplete_type_error              PROTO((tree, tree));
 extern void my_friendly_abort                  PROTO((int))
index d24dbf1f4ecab598a4afe60b2c0482a759adb0fd..e5c106426f1ead6d398b35b674d1c741dcccc2aa 100644 (file)
@@ -826,11 +826,8 @@ ocp_convert (type, expr, convtype, flags)
 
       ctor = e;
 
-      if (IS_AGGR_TYPE (type) && CLASSTYPE_ABSTRACT_VIRTUALS (type))
-       {
-         abstract_virtuals_error (NULL_TREE, type);
-         return error_mark_node;
-       }
+      if (abstract_virtuals_error (NULL_TREE, type))
+       return error_mark_node;
 
       if ((flags & LOOKUP_ONLYCONVERTING)
          && ! (IS_AGGR_TYPE (dtype) && DERIVED_FROM_P (type, dtype)))
index 21b1143ea10e15470af89c7096e6bba5de329fce..1dc070b108dfac5477e9d6ef67b5a2771772bcc0 100644 (file)
@@ -7857,14 +7857,9 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
       if (was_temp)
        resume_temporary_allocation ();
 
-      if (type != error_mark_node
-         && TYPE_LANG_SPECIFIC (core_type)
-         && CLASSTYPE_ABSTRACT_VIRTUALS (core_type))
-       abstract_virtuals_error (decl, core_type);
-      else if ((TREE_CODE (type) == FUNCTION_TYPE
-               || TREE_CODE (type) == METHOD_TYPE)
-              && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
-              && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (type)))
+      if (!abstract_virtuals_error (decl, core_type)
+         && (TREE_CODE (type) == FUNCTION_TYPE
+             || TREE_CODE (type) == METHOD_TYPE))
        abstract_virtuals_error (decl, TREE_TYPE (type));
 
       if (TYPE_LANG_SPECIFIC (core_type) && IS_SIGNATURE (core_type))
@@ -11614,13 +11609,8 @@ grokparms (first_parm, funcdef_flag)
                      type = build_pointer_type (type);
                      TREE_TYPE (decl) = type;
                    }
-                  else if (TREE_CODE (type) == RECORD_TYPE
-                           && TYPE_LANG_SPECIFIC (type)
-                           && CLASSTYPE_ABSTRACT_VIRTUALS (type))
-                    {
-                      abstract_virtuals_error (decl, type);
-                      any_error = 1;  /* Seems like a good idea. */
-                    }
+                  else if (abstract_virtuals_error (decl, type))
+                   any_error = 1;  /* Seems like a good idea. */
                   else if (TREE_CODE (type) == RECORD_TYPE
                            && TYPE_LANG_SPECIFIC (type)
                            && IS_SIGNATURE (type))
@@ -12033,9 +12023,7 @@ grok_op_properties (decl, virtualp, friendp)
       else if (name == ansi_opname[(int) COND_EXPR])
        {
          /* 13.4.0.3 */
-         pedwarn ("ANSI C++ prohibits overloading operator ?:");
-         if (list_length (argtypes) != 4)
-           cp_error ("`%D' must take exactly three arguments", decl);
+         cp_error ("ANSI C++ prohibits overloading operator ?:");
        }         
       else if (ambi_op_p (name))
        {
@@ -13113,9 +13101,7 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
            = CP_TYPE_VOLATILE_P (TREE_TYPE (fntype));
        }
 
-      if (TYPE_LANG_SPECIFIC (TREE_TYPE (fntype))
-         && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (fntype)))
-       abstract_virtuals_error (decl1, TREE_TYPE (fntype));
+      abstract_virtuals_error (decl1, TREE_TYPE (fntype));
     }
 
   /* Effective C++ rule 15.  See also c_expand_return.  */
index 8469fe6ab1bca9c085d3d6a5a3bb6d90a36aeea1..b3b9dcb0bc97f18af690083bf59b9ec992f58762 100644 (file)
@@ -2206,12 +2206,8 @@ build_new_1 (exp)
       return error_mark_node;
     }
 
-  if (TYPE_LANG_SPECIFIC (true_type)
-      && CLASSTYPE_ABSTRACT_VIRTUALS (true_type))
-    {
-      abstract_virtuals_error (NULL_TREE, true_type);
-      return error_mark_node;
-    }
+  if (abstract_virtuals_error (NULL_TREE, true_type))
+    return error_mark_node;
 
   if (TYPE_LANG_SPECIFIC (true_type) && IS_SIGNATURE (true_type))
     {
index 06b6c1343a857803c878d34f8fab27fd20b8aacd..ef84f74714ae1dfbf07344de250525d23c382c45 100644 (file)
@@ -8338,10 +8338,6 @@ unify (tparms, targs, parm, arg, strict)
       {
        int sub_strict;
 
-       if (TREE_CODE (arg) == RECORD_TYPE && TYPE_PTRMEMFUNC_FLAG (arg))
-         return (unify (tparms, targs, parm, 
-                        TYPE_PTRMEMFUNC_FN_TYPE (arg), strict));
-       
        if (TREE_CODE (arg) != POINTER_TYPE)
          return 1;
        
@@ -8361,14 +8357,13 @@ unify (tparms, targs, parm, arg, strict)
           this is probably OK.  */
        sub_strict = strict;
        
-       if (TREE_CODE (TREE_TYPE (arg)) != RECORD_TYPE
-           || TYPE_PTRMEMFUNC_FLAG (TREE_TYPE (arg)))
+       if (TREE_CODE (TREE_TYPE (arg)) != RECORD_TYPE)
          /* The derived-to-base conversion only persists through one
             level of pointers.  */
          sub_strict &= ~UNIFY_ALLOW_DERIVED;
 
-       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE
-                     (arg), sub_strict);
+       return unify (tparms, targs, TREE_TYPE (parm), 
+                     TREE_TYPE (arg), sub_strict);
       }
 
     case REFERENCE_TYPE:
@@ -8448,13 +8443,20 @@ unify (tparms, targs, parm, arg, strict)
 
     case RECORD_TYPE:
     case UNION_TYPE:
-      if (TYPE_PTRMEMFUNC_FLAG (parm))
-       return unify (tparms, targs, TYPE_PTRMEMFUNC_FN_TYPE (parm),
-                     arg, strict);
-
       if (TREE_CODE (arg) != TREE_CODE (parm))
        return 1;
   
+      if (TYPE_PTRMEMFUNC_P (parm))
+       {
+         if (!TYPE_PTRMEMFUNC_P (arg))
+           return 1;
+
+         return unify (tparms, targs, 
+                       TYPE_PTRMEMFUNC_FN_TYPE (parm),
+                       TYPE_PTRMEMFUNC_FN_TYPE (arg),
+                       strict);
+       }
+
       if (CLASSTYPE_TEMPLATE_INFO (parm))
        {
          tree t = NULL_TREE;
index 6cde6905c12910de95f9f613b83c25c65cb0a90a..b7f3e18453ba2182e7673a155aa3858c871059d0 100644 (file)
@@ -3130,6 +3130,10 @@ add_conversions (binfo, data)
   tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
   tree *conversions = (tree *) data;
 
+  /* Some builtin types have no method vector, not even an empty one.  */
+  if (!method_vec)
+    return NULL_TREE;
+
   for (i = 2; i < TREE_VEC_LENGTH (method_vec); ++i)
     {
       tree tmp = TREE_VEC_ELT (method_vec, i);
index 7add55044596c71339f703454d6fd0a6406b7cf1..c4bb18f801f103fb2a01a5b094954f0a9964c073 100644 (file)
@@ -403,6 +403,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;
+     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.
@@ -435,44 +620,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)
@@ -510,51 +664,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:
@@ -797,17 +910,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;
 
@@ -969,6 +1081,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;
     }
@@ -3536,11 +3651,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)
        {
@@ -3552,15 +3665,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;
@@ -4967,326 +5078,7 @@ 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);
-}
-
-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);
-    }
-
-  type1 = TREE_TYPE (op1);
-  code1 = TREE_CODE (type1);
-  type2 = TREE_TYPE (op2);
-  code2 = TREE_CODE (type2);
-  if (op1 == error_mark_node || op2 == error_mark_node
-      || type1 == error_mark_node || type2 == error_mark_node)
-    return error_mark_node;
-
-  ifexp = cp_convert (boolean_type_node, ifexp);
-
-  if (TREE_CODE (ifexp) == ERROR_MARK)
-    return error_mark_node;
-
-  /* C++: REFERENCE_TYPES must be dereferenced.  */
-  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)));
+  return build_conditional_expr (ifexp, op1, op2);
 }
 \f
 /* Handle overloading of the ',' operator when needed.  Otherwise,
@@ -6628,18 +6420,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)
@@ -6662,388 +6447,86 @@ 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.  */
   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);
        }
-      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);
+      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-converions 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);
+      /* If the right-hand side has unknown type, then it is an
+        overloaded function.  Call instantiate_type to get error
+        messages.  */
+      else 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_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;
+       cp_error ("cannot convert `%T' to `%T' in %s", rhstype, type, 
+                 errtype);
+      return error_mark_node;
     }
-  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 ncp_convert (strip_top_quals (type), rhs);
 }
 
 /* Convert RHS to be of type TYPE.
index fbd3d27db875db93a8caa4622d64a86ab2763333..d1e96eda7799813101b0b1768f0004603663eaf3 100644 (file)
@@ -125,21 +125,27 @@ readonly_error (arg, string, soft)
     (*fn) ("%s of read-only location", string);
 }
 
-/* Print an error message for invalid use of a type which declares
-   virtual functions which are not inheritable.  */
+/* If TYPE has abstract virtual functions, issue an error about trying
+   to create an object of that type.  DECL is the object declared, or
+   NULL_TREE if the declaration is unavailable.  Returns 1 if an error
+   occurred; zero if all was well.  */
 
-void
+int
 abstract_virtuals_error (decl, type)
      tree decl;
      tree type;
 {
-  tree u = CLASSTYPE_ABSTRACT_VIRTUALS (type);
+  tree u;
   tree tu;
 
+  if (!CLASS_TYPE_P (type) || !CLASSTYPE_ABSTRACT_VIRTUALS (type))
+    return 0;
+
+  u = CLASSTYPE_ABSTRACT_VIRTUALS (type);
   if (decl)
     {
       if (TREE_CODE (decl) == RESULT_DECL)
-       return;
+       return 0;
 
       if (TREE_CODE (decl) == VAR_DECL)
        cp_error ("cannot declare variable `%D' to be of type `%T'",
@@ -170,6 +176,8 @@ abstract_virtuals_error (decl, type)
     }
   else
     cp_error ("  since type `%T' has abstract virtual functions", type);
+
+  return 1;
 }
 
 /* Print an error message for invalid use of a signature type.
@@ -1486,11 +1494,8 @@ build_functional_cast (exp, parms)
       cp_error ("type `%T' is not yet defined", type);
       return error_mark_node;
     }
-  if (IS_AGGR_TYPE (type) && CLASSTYPE_ABSTRACT_VIRTUALS (type))
-    {
-      abstract_virtuals_error (NULL_TREE, type);
-      return error_mark_node;
-    }
+  if (abstract_virtuals_error (NULL_TREE, type))
+    return error_mark_node;
 
   if (parms && TREE_CHAIN (parms) == NULL_TREE)
     return build_c_cast (type, TREE_VALUE (parms));
index 1738c736297c8c55b6b54bbafdeaec0c77e55c29..de46668484bcdee3093bb425fe7468fa276fbf37 100644 (file)
@@ -1168,8 +1168,8 @@ class dict : public object {
                         DISPLAYER displayer, STRINGER str_f)
                {// ERROR - candidate for bad call
                        if (799  >=  800 ) cout <<  "Creating new dictionary..."  << '\n'; ;
-                       if (cmp == __null )       cmp = &default_compare;
-                       if (displayer == __null ) displayer = &default_displayer;
+                       if (cmp == __null )       cmp = (COMPARE) &default_compare;
+                       if (displayer == __null ) displayer = (DISPLAYER) &default_displayer;
                        if (str_f == __null )     str_f = &default_stringer;
                        compare_f = cmp;
                        display_f = displayer;
@@ -1417,7 +1417,7 @@ class queue : public object {
                         DISPLAYER displayer, STRINGER str_f)
                {// ERROR - candidate for bad call
                        if (799  >=  800 ) cout <<  "Creating new queue..."  << '\n'; ;
-                       if (displayer == __null ) displayer = &default_displayer;
+                       if (displayer == __null ) displayer = (DISPLAYER) &default_displayer;
                        if (str_f == __null )     str_f = &default_stringer;
                        display_f = displayer;
                        destroy_f = destroyer;
index fac78cebeaf0f52875848201ea60a032fbee04ad..c681c82d08d2baec74eee3443760c928d8137ae8 100644 (file)
@@ -2,8 +2,9 @@
 // Bug: g++ misinterprets typedefs of function type in class scope.
 // Build don't link:
 
+typedef int (*F1) ();
 struct A {
    typedef int F();
    F *fp;
-   void* g() { return fp; }    // gets bogus error - typing
+   F1 g() { return fp; }       // gets bogus error - typing
 };
index f5ff345a3fd36e3a03d5b1b1d019308561861e2a..3dd5dc27e0a692887da326be7fd107000663506a 100644 (file)
@@ -11,11 +11,11 @@ public:
   void f1b() { ok += 5; }
   void f2a() { ok += 7; }      // gets bogus error XFAIL *-*-*
   void f2b() { }
-  const static void (*table[2][2])();
+  static void (*table[2][2])();
   void main();
 } a;
 
-const void (*A::table[2][2])()
+void (*A::table[2][2])()
   = { { PMF2PF(&A::f1a), PMF2PF(&A::f1b) },
       { PMF2PF(&A::f2a), PMF2PF(&A::f1b) },
   };
diff --git a/gcc/testsuite/g++.old-deja/g++.other/cond1.C b/gcc/testsuite/g++.old-deja/g++.other/cond1.C
new file mode 100644 (file)
index 0000000..c025beb
--- /dev/null
@@ -0,0 +1,26 @@
+// Build don't run:
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+template <class T>
+void f (T&) ;
+
+template <>
+void f (void (&)()) 
+{
+}
+
+void g () 
+{
+}
+
+void h ()
+{
+}
+
+bool b;
+
+int main ()
+{
+  f (b ? g : h);
+}
+
index 97bf23889a9be7fb0a27e9fe805efbdbeee4f039..28c8e3b686d875486289e8f6c892acdf29ae4b38 100644 (file)
@@ -5,4 +5,4 @@
 // Special g++ Options:
 
 int foo();
-const int (*bar)() = foo; // ERROR - adding const - XFAIL *-*-*
+const int (*bar)() = foo; // ERROR - adding const
diff --git a/gcc/testsuite/g++.old-deja/g++.other/overload10.C b/gcc/testsuite/g++.old-deja/g++.other/overload10.C
new file mode 100644 (file)
index 0000000..50ae8a9
--- /dev/null
@@ -0,0 +1,11 @@
+// Build don't link:
+// Origin: Jason Merrill <jason@cygnus.com>
+
+  const char *pc;
+  enum A { x } a;
+  int i;
+
+  int main()
+  {
+     return i ? *pc : a;
+  }