Commit 0a72704b by Mark Mitchell Committed by Mark Mitchell

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
parent ac3d7b44
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));
}
......
......@@ -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);
......
......@@ -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);
......
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
......
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();
}
// { dg-do run }
// { dg-do compile }
#include <typeinfo>
#include <iostream>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment