From a7a64a77ef33be210374003a0b84dd8d60f75a49 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Mon, 26 Jul 1999 08:18:19 +0000 Subject: [PATCH] cp-tree.h (CP_INTEGRAL_TYPE_P): New macro. * 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 --- gcc/cp/ChangeLog | 49 + gcc/cp/call.c | 503 +++++++- gcc/cp/class.c | 3 +- gcc/cp/cp-tree.h | 25 +- gcc/cp/cvt.c | 7 +- gcc/cp/decl.c | 28 +- gcc/cp/init.c | 8 +- gcc/cp/pt.c | 26 +- gcc/cp/search.c | 4 + gcc/cp/typeck.c | 1053 +++++------------ gcc/cp/typeck2.c | 25 +- .../g++.old-deja/g++.brendan/crash19.C | 6 +- .../g++.old-deja/g++.jason/typedef.C | 3 +- gcc/testsuite/g++.old-deja/g++.mike/p10769a.C | 4 +- gcc/testsuite/g++.old-deja/g++.other/cond1.C | 26 + gcc/testsuite/g++.old-deja/g++.other/conv5.C | 2 +- .../g++.old-deja/g++.other/overload10.C | 11 + 17 files changed, 891 insertions(+), 892 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.other/cond1.C create mode 100644 gcc/testsuite/g++.old-deja/g++.other/overload10.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b0efd31110f..4dba90246fb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,52 @@ +1999-07-26 Mark Mitchell + + * 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 * decl.c (ptr_type_node, va_list_type_node): New. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 6e75e94dd0b..cd5e77d6a2c 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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. */ diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 41f1d79a914..a4cc5a507ac 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 50d28ca9f1d..4e13392a98a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)) diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index d24dbf1f4ec..e5c106426f1 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -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))) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 21b1143ea10..1dc070b108d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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. */ diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 8469fe6ab1b..b3b9dcb0bc9 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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)) { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 06b6c1343a8..ef84f74714a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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; diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 6cde6905c12..b7f3e18453b 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -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); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 7add5504459..c4bb18f801f 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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); } /* 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. diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index fbd3d27db87..d1e96eda779 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -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)); diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash19.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash19.C index 1738c736297..de46668484b 100644 --- a/gcc/testsuite/g++.old-deja/g++.brendan/crash19.C +++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash19.C @@ -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; diff --git a/gcc/testsuite/g++.old-deja/g++.jason/typedef.C b/gcc/testsuite/g++.old-deja/g++.jason/typedef.C index fac78cebeaf..c681c82d08d 100644 --- a/gcc/testsuite/g++.old-deja/g++.jason/typedef.C +++ b/gcc/testsuite/g++.old-deja/g++.jason/typedef.C @@ -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 }; diff --git a/gcc/testsuite/g++.old-deja/g++.mike/p10769a.C b/gcc/testsuite/g++.old-deja/g++.mike/p10769a.C index f5ff345a3fd..3dd5dc27e0a 100644 --- a/gcc/testsuite/g++.old-deja/g++.mike/p10769a.C +++ b/gcc/testsuite/g++.old-deja/g++.mike/p10769a.C @@ -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 index 00000000000..c025beb3ffd --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/cond1.C @@ -0,0 +1,26 @@ +// Build don't run: +// Origin: Mark Mitchell + +template +void f (T&) ; + +template <> +void f (void (&)()) +{ +} + +void g () +{ +} + +void h () +{ +} + +bool b; + +int main () +{ + f (b ? g : h); +} + diff --git a/gcc/testsuite/g++.old-deja/g++.other/conv5.C b/gcc/testsuite/g++.old-deja/g++.other/conv5.C index 97bf23889a9..28c8e3b686d 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/conv5.C +++ b/gcc/testsuite/g++.old-deja/g++.other/conv5.C @@ -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 index 00000000000..50ae8a91f15 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/overload10.C @@ -0,0 +1,11 @@ +// Build don't link: +// Origin: Jason Merrill + + const char *pc; + enum A { x } a; + int i; + + int main() + { + return i ? *pc : a; + } -- 2.30.2