diff options
author | Mark Mitchell <mark@codesourcery.com> | 2003-07-06 03:30:57 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2003-07-06 03:30:57 +0000 |
commit | 0a72704b04e73d1173ae5e1c99464bea55a698b4 (patch) | |
tree | 056d5a4f42966fc1a6672ee25eb4c64a77754dbf /gcc | |
parent | ac3d7b441379a5992280022a730eb5b1a57e0784 (diff) | |
download | gcc-0a72704b04e73d1173ae5e1c99464bea55a698b4.zip gcc-0a72704b04e73d1173ae5e1c99464bea55a698b4.tar.gz gcc-0a72704b04e73d1173ae5e1c99464bea55a698b4.tar.bz2 |
re PR c++/11431 (static_cast behavior with subclasses when default constructor available)
PR c++/11431
* typeck.c (build_static_cast): Check for reference conversions
earlier.
* cp-tree.h (perform_integral_promotions): Declare.
* call.c (build_addr_func): Use decay_conversion.
(convert_arg_to_ellipsis): Likewise. Remove misleading comment.
(convert_for_arg_passing): Use perform_integral_promotions.
* cvt.c (build_expr_type_conversion): Use decay_conversion.
(type_promotes_to): Do not return a cv-qualified type.
* decl.c (grok_reference_init): Fix formatting.
(get_atexit_node): Use decay_conversion.
(build_enumerator): Use perform_integral_promotions.
* init.c (build_vec_init): Use decay_conversion.
* semantics.c (finish_expr_stmt): Likewise.
(finish_switch_cond): Use perform_integral_promotions.
* typeck.c (default_conversion): Likewise.
(perform_integral_promotions): New function.
(build_indirect_ref): Use decay_conversion.
(build_array_ref): Use perform_integral_promotions.
(convert_arguments): Use decay_conversion.
(build_unary_op): Use perform_integral_promotions.
(build_c_cast): Use decay_conversion.
(build_modify_expr): Likewise.
(convert_for_initialization): Likewise.
* typeck2.c (build_x_arrow): Likewise.
* g++.old-deja/g++.jason/typeid1.C: Make it a compile test, not a
run test.
PR c++/11431
* g++.dg/expr/static_cast3.C: New test.
From-SVN: r68989
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 31 | ||||
-rw-r--r-- | gcc/cp/call.c | 25 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/cvt.c | 9 | ||||
-rw-r--r-- | gcc/cp/decl.c | 10 | ||||
-rw-r--r-- | gcc/cp/init.c | 4 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 7 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 111 | ||||
-rw-r--r-- | gcc/cp/typeck2.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/expr/static_cast3.C | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.jason/typeid1.C | 2 |
12 files changed, 164 insertions, 70 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 768fe65..62d989d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,34 @@ +2003-07-05 Mark Mitchell <mark@codesourcery.com> + + PR c++/11431 + * typeck.c (build_static_cast): Check for reference conversions + earlier. + +2003-07-04 Mark Mitchell <mark@codesourcery.com> + + * cp-tree.h (perform_integral_promotions): Declare. + * call.c (build_addr_func): Use decay_conversion. + (convert_arg_to_ellipsis): Likewise. Remove misleading comment. + (convert_for_arg_passing): Use perform_integral_promotions. + * cvt.c (build_expr_type_conversion): Use decay_conversion. + (type_promotes_to): Do not return a cv-qualified type. + * decl.c (grok_reference_init): Fix formatting. + (get_atexit_node): Use decay_conversion. + (build_enumerator): Use perform_integral_promotions. + * init.c (build_vec_init): Use decay_conversion. + * semantics.c (finish_expr_stmt): Likewise. + (finish_switch_cond): Use perform_integral_promotions. + * typeck.c (default_conversion): Likewise. + (perform_integral_promotions): New function. + (build_indirect_ref): Use decay_conversion. + (build_array_ref): Use perform_integral_promotions. + (convert_arguments): Use decay_conversion. + (build_unary_op): Use perform_integral_promotions. + (build_c_cast): Use decay_conversion. + (build_modify_expr): Likewise. + (convert_for_initialization): Likewise. + * typeck2.c (build_x_arrow): Likewise. + 2003-07-04 Kazu Hirata <kazu@cs.umass.edu> * call.c: Fix comment typos. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 2ae1319..0832df7 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -326,7 +326,7 @@ build_addr_func (tree function) function = build_address (function); } else - function = default_conversion (function); + function = decay_conversion (function); return function; } @@ -4339,20 +4339,29 @@ call_builtin_trap (void) } /* ARG is being passed to a varargs function. Perform any conversions - required. Array/function to pointer decay must have already happened. - Return the converted value. */ + required. Return the converted value. */ tree convert_arg_to_ellipsis (tree arg) { + /* [expr.call] + + The lvalue-to-rvalue, array-to-pointer, and function-to-pointer + standard conversions are performed. */ + arg = decay_conversion (arg); + /* [expr.call] + + If the argument has integral or enumeration type that is subject + to the integral promotions (_conv.prom_), or a floating point + type that is subject to the floating point promotion + (_conv.fpprom_), the value of the argument is converted to the + promoted type before the call. */ if (TREE_CODE (TREE_TYPE (arg)) == REAL_TYPE && (TYPE_PRECISION (TREE_TYPE (arg)) < TYPE_PRECISION (double_type_node))) - /* Convert `float' to `double'. */ arg = cp_convert (double_type_node, arg); - else - /* Convert `short' and `char' to full-size `int'. */ - arg = default_conversion (arg); + else if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (arg))) + arg = perform_integral_promotions (arg); arg = require_complete_type (arg); @@ -4487,7 +4496,7 @@ convert_for_arg_passing (tree type, tree val) else if (PROMOTE_PROTOTYPES && INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) - val = default_conversion (val); + val = perform_integral_promotions (val); return val; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a8955f8..f58f8be 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4255,6 +4255,7 @@ extern tree cxx_sizeof_or_alignof_type (tree, enum tree_code, int); #define cxx_sizeof_nowarn(T) cxx_sizeof_or_alignof_type (T, SIZEOF_EXPR, false) extern tree inline_conversion (tree); extern tree decay_conversion (tree); +extern tree perform_integral_promotions (tree); extern tree build_class_member_access_expr (tree, tree, tree, bool); extern tree finish_class_member_access_expr (tree, tree); extern tree build_x_indirect_ref (tree, const char *); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 008ff4b..081d3b8 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -1056,7 +1056,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain) case FUNCTION_TYPE: case ARRAY_TYPE: - return (desires & WANT_POINTER) ? default_conversion (expr) + return (desires & WANT_POINTER) ? decay_conversion (expr) : NULL_TREE; default: return NULL_TREE; @@ -1131,12 +1131,9 @@ build_expr_type_conversion (int desires, tree expr, bool complain) tree type_promotes_to (tree type) { - int type_quals; - if (type == error_mark_node) return error_mark_node; - type_quals = cp_type_quals (type); type = TYPE_MAIN_VARIANT (type); /* bool always promotes to int (not unsigned), even if it's the same @@ -1169,8 +1166,8 @@ type_promotes_to (tree type) } else if (type == float_type_node) type = double_type_node; - - return cp_build_qualified_type (type, type_quals); + + return type; } /* The routines below this point are carefully written to conform to diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 9b1cdee..e44153e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7213,10 +7213,8 @@ grok_reference_init (tree decl, tree type, tree init) if (TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE) - { - /* Note: default conversion is only called in very special cases. */ - init = default_conversion (init); - } + /* Note: default conversion is only called in very special cases. */ + init = decay_conversion (init); /* Convert INIT to the reference type TYPE. This may involve the creation of a temporary, whose lifetime must be the same as that @@ -8356,7 +8354,7 @@ get_atexit_node (void) atexit_fndecl = build_library_fn_ptr (name, fn_type); mark_used (atexit_fndecl); pop_lang_context (); - atexit_node = default_conversion (atexit_fndecl); + atexit_node = decay_conversion (atexit_fndecl); return atexit_node; } @@ -13180,7 +13178,7 @@ build_enumerator (tree name, tree value, tree enumtype) if (TREE_CODE (value) == INTEGER_CST) { - value = default_conversion (value); + value = perform_integral_promotions (value); constant_expression_warning (value); } else diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 3d4d81b..18a4dcf 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2656,7 +2656,7 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array) ptype = build_pointer_type (type); size = size_in_bytes (type); if (TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE) - base = cp_convert (ptype, default_conversion (base)); + base = cp_convert (ptype, decay_conversion (base)); /* The code we are generating looks like: @@ -2739,7 +2739,7 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array) checking. */ if (init) { - base2 = default_conversion (init); + base2 = decay_conversion (init); itype = TREE_TYPE (base2); base2 = get_temp_regvar (itype, base2); itype = TREE_TYPE (itype); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index b7b5d85..d89aa5a 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -425,7 +425,7 @@ finish_expr_stmt (tree expr) && ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr)) || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)) - expr = default_conversion (expr); + expr = decay_conversion (expr); /* Remember the type of the expression. */ expr_type = TREE_TYPE (expr); @@ -748,7 +748,10 @@ finish_switch_cond (tree cond, tree switch_stmt) orig_type = TREE_TYPE (cond); if (cond != error_mark_node) { - cond = default_conversion (cond); + /* [stmt.switch] + + Integral promotions are performed. */ + cond = perform_integral_promotions (cond); cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond)); } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index cd3bc10..eef1781 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1483,11 +1483,11 @@ expr_sizeof (tree e) } -/* Perform the array-to-pointer and function-to-pointer conversions - for EXP. +/* Perform the conversions in [expr] that apply when an lvalue appears + in an rvalue context: the lvalue-to-rvalue, array-to-pointer, and + function-to-pointer conversions. - In addition, references are converted to lvalues and manifest - constants are replaced by their values. */ + In addition manifest constants are replaced by their values. */ tree decay_conversion (tree exp) @@ -1609,24 +1609,32 @@ decay_conversion (tree exp) tree default_conversion (tree exp) { - tree type; - enum tree_code code; - exp = decay_conversion (exp); - type = TREE_TYPE (exp); - code = TREE_CODE (type); - - if (INTEGRAL_CODE_P (code)) - { - tree t = type_promotes_to (type); - if (t != type) - return cp_convert (t, exp); - } + if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (exp))) + exp = perform_integral_promotions (exp); return exp; } +/* EXPR is an expression with an integral or enumeration type. + Perform the integral promotions in [conv.prom], and return the + converted value. */ + +tree +perform_integral_promotions (tree expr) +{ + tree type; + tree promoted_type; + + type = TREE_TYPE (expr); + my_friendly_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type), 20030703); + promoted_type = type_promotes_to (type); + if (type != promoted_type) + expr = cp_convert (promoted_type, expr); + return expr; +} + /* Take the address of an inline function without setting TREE_ADDRESSABLE or TREE_USED. */ @@ -2232,7 +2240,7 @@ build_indirect_ref (ptr, errorstring) return current_class_ref; pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE - ? ptr : default_conversion (ptr)); + ? ptr : decay_conversion (ptr)); type = TREE_TYPE (pointer); if (TYPE_PTR_P (type) || TREE_CODE (type) == REFERENCE_TYPE) @@ -2350,15 +2358,19 @@ build_array_ref (array, idx) && TYPE_MAIN_VARIANT (TREE_TYPE (idx)) == char_type_node) warning ("array subscript has type `char'"); - /* Apply default promotions *after* noticing character types. */ - idx = default_conversion (idx); - - if (TREE_CODE (TREE_TYPE (idx)) != INTEGER_TYPE) + if (!INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (idx))) { error ("array subscript is not an integer"); return error_mark_node; } + /* Apply integral promotions *after* noticing character types. + (It is unclear why we do these promotions -- the standard + does not say that we should. In fact, the natual thing would + seem to be to convert IDX to ptrdiff_t; we're performing + pointer arithmetic.) */ + idx = perform_integral_promotions (idx); + /* An array that is indexed by a non-constant cannot be stored in a register; we must be able to do address arithmetic on its address. @@ -2742,7 +2754,7 @@ convert_arguments (typelist, values, fndecl, flags) if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE) - val = default_conversion (val); + val = decay_conversion (val); } if (val == error_mark_node) @@ -4039,8 +4051,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) case NEGATE_EXPR: if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true))) errstring = "wrong type argument to unary minus"; - else if (!noconvert) - arg = default_conversion (arg); + else if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg))) + arg = perform_integral_promotions (arg); break; case BIT_NOT_EXPR: @@ -4054,7 +4066,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) arg, true))) errstring = "wrong type argument to bit-complement"; else if (!noconvert) - arg = default_conversion (arg); + arg = perform_integral_promotions (arg); break; case ABS_EXPR: @@ -4780,28 +4792,23 @@ build_static_cast (tree type, tree expr) /* [expr.static.cast] - An expression e can be explicitly converted to a type T using a - static_cast of the form static_cast<T>(e) if the declaration T - t(e);" is well-formed, for some invented temporary variable - t. */ - result = perform_direct_initialization_if_possible (type, expr); - if (result) - return convert_from_reference (result); - - /* [expr.static.cast] - - Any expression can be explicitly converted to type cv void. */ - if (TREE_CODE (type) == VOID_TYPE) - return convert_to_void (expr, /*implicit=*/NULL); - - /* [expr.static.cast] - An lvalue of type "cv1 B", where B is a class type, can be cast to type "reference to cv2 D", where D is a class derived (clause _class.derived_) from B, if a valid standard conversion from "pointer to D" to "pointer to B" exists (_conv.ptr_), cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is not a virtual base class of D. */ + /* We check this case before checking the validity of "TYPE t = + EXPR;" below because for this case: + + struct B {}; + struct D : public B { D(const B&); }; + extern B& b; + void f() { static_cast<const D&>(b); } + + we want to avoid constructing a new D. The standard is not + completely clear about this issue, but our interpretation is + consistent with other compilers. */ if (TREE_CODE (type) == REFERENCE_TYPE && CLASS_TYPE_P (TREE_TYPE (type)) && CLASS_TYPE_P (intype) @@ -4827,6 +4834,22 @@ build_static_cast (tree type, tree expr) /* [expr.static.cast] + An expression e can be explicitly converted to a type T using a + static_cast of the form static_cast<T>(e) if the declaration T + t(e);" is well-formed, for some invented temporary variable + t. */ + result = perform_direct_initialization_if_possible (type, expr); + if (result) + return convert_from_reference (result); + + /* [expr.static.cast] + + Any expression can be explicitly converted to type cv void. */ + if (TREE_CODE (type) == VOID_TYPE) + return convert_to_void (expr, /*implicit=*/NULL); + + /* [expr.static.cast] + The inverse of any standard conversion sequence (clause _conv_), other than the lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_), function-to-pointer (_conv.func_), and boolean @@ -5158,7 +5181,7 @@ build_c_cast (tree type, tree expr) && bound_pmf_p (value))) || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE) - value = default_conversion (value); + value = decay_conversion (value); } else if (TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE) /* However, even for class types, we still need to strip away @@ -5422,7 +5445,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE || TREE_CODE (TREE_TYPE (newrhs)) == METHOD_TYPE || TREE_CODE (TREE_TYPE (newrhs)) == OFFSET_TYPE) - newrhs = default_conversion (newrhs); + newrhs = decay_conversion (newrhs); /* ISO C++ 5.4/1: The result is an lvalue if T is a reference type, otherwise the result is an rvalue. */ @@ -6078,7 +6101,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags, && (TREE_CODE (type) != REFERENCE_TYPE || TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)) || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE) - rhs = default_conversion (rhs); + rhs = decay_conversion (rhs); rhstype = TREE_TYPE (rhs); coder = TREE_CODE (rhstype); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 9d9ade1..edb9f5d 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1030,7 +1030,7 @@ build_x_arrow (tree datum) last_rval = convert_from_reference (last_rval); } else - last_rval = default_conversion (rval); + last_rval = decay_conversion (rval); if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE) return build_indirect_ref (last_rval, NULL); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d67d0b7..3d067f5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2003-07-05 Mark Mitchell <mark@codesourcery.com> + + * g++.old-deja/g++.jason/typeid1.C: Make it a compile test, not a + run test. + + PR c++/11431 + * g++.dg/expr/static_cast3.C: New test. + 2003-07-04 Zack Weinberg <zack@codesourcery.com> * gcc.c-torture/execute/wchar_t-1.x: New file; XFAIL wchar_t-1.c diff --git a/gcc/testsuite/g++.dg/expr/static_cast3.C b/gcc/testsuite/g++.dg/expr/static_cast3.C new file mode 100644 index 0000000..744648c --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/static_cast3.C @@ -0,0 +1,24 @@ +template <class T> struct static_abort {}; + +template <class E> +struct any +{ + const E& self() const { return static_cast<const E&>(*this); } +}; + +struct range : public any<range> +{ + range() {} + + template <class U> + range(const U&) + { + typedef typename static_abort<U>::ret t; + } +}; + +int main() +{ + const any<range>& r = *new range(); + r.self(); +} diff --git a/gcc/testsuite/g++.old-deja/g++.jason/typeid1.C b/gcc/testsuite/g++.old-deja/g++.jason/typeid1.C index 678ab5fc..ec5156e 100644 --- a/gcc/testsuite/g++.old-deja/g++.jason/typeid1.C +++ b/gcc/testsuite/g++.old-deja/g++.jason/typeid1.C @@ -1,4 +1,4 @@ -// { dg-do run } +// { dg-do compile } #include <typeinfo> #include <iostream> |