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
This commit is contained in:
parent
ac3d7b4413
commit
0a72704b04
12 changed files with 164 additions and 70 deletions
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
111
gcc/cp/typeck.c
111
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:
|
||||
|
@ -4778,22 +4790,6 @@ build_static_cast (tree type, tree expr)
|
|||
|
||||
intype = TREE_TYPE (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
|
||||
|
@ -4802,6 +4798,17 @@ build_static_cast (tree type, tree expr)
|
|||
"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)
|
||||
|
@ -4825,6 +4832,22 @@ build_static_cast (tree type, tree expr)
|
|||
return convert_from_reference (build_nop (type, 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_),
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
24
gcc/testsuite/g++.dg/expr/static_cast3.C
Normal file
24
gcc/testsuite/g++.dg/expr/static_cast3.C
Normal file
|
@ -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();
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// { dg-do run }
|
||||
// { dg-do compile }
|
||||
#include <typeinfo>
|
||||
#include <iostream>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue