aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2003-07-06 03:30:57 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2003-07-06 03:30:57 +0000
commit0a72704b04e73d1173ae5e1c99464bea55a698b4 (patch)
tree056d5a4f42966fc1a6672ee25eb4c64a77754dbf /gcc
parentac3d7b441379a5992280022a730eb5b1a57e0784 (diff)
downloadgcc-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/ChangeLog31
-rw-r--r--gcc/cp/call.c25
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/cvt.c9
-rw-r--r--gcc/cp/decl.c10
-rw-r--r--gcc/cp/init.c4
-rw-r--r--gcc/cp/semantics.c7
-rw-r--r--gcc/cp/typeck.c111
-rw-r--r--gcc/cp/typeck2.c2
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/g++.dg/expr/static_cast3.C24
-rw-r--r--gcc/testsuite/g++.old-deja/g++.jason/typeid1.C2
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>