Commit 3fe18f1d by Mark Mitchell Committed by Mark Mitchell

re PR c++/10931 (valid conversion static_cast<const unsigned int&>(lvalue-of-type-int) is rejected)

	PR c++/10931
	* g++.dg/expr/static_cast1.C: New test.

	PR c++/10931
	* call.c (convert_like): Pass issue_conversion_warnings.
	(convert_like_with_context): Likewise.
	(convert_like_real): Add issue_conversion_warnings parameter.
	(perform_direct_initialization_if_possible): New function.
	* cp-tree.h (perform_direct_initialization_if_possible): Declare it.
	* typeck.c (check_for_casting_away_constness): New function.
	(build_static_cast): Rewrite.

From-SVN: r68506
parent 22c7c85e
2003-06-25 Mark Mitchell <mark@codesourcery.com>
PR c++/10931
* call.c (convert_like): Pass issue_conversion_warnings.
(convert_like_with_context): Likewise.
(convert_like_real): Add issue_conversion_warnings parameter.
(perform_direct_initialization_if_possible): New function.
* cp-tree.h (perform_direct_initialization_if_possible): Declare it.
* typeck.c (check_for_casting_away_constness): New function.
(build_static_cast): Rewrite.
2003-06-24 Nathan Sidwell <nathan@codesourcery.com> 2003-06-24 Nathan Sidwell <nathan@codesourcery.com>
* call.c (enforce_access): Assert we get a binfo. * call.c (enforce_access): Assert we get a binfo.
......
...@@ -45,11 +45,13 @@ static int joust (struct z_candidate *, struct z_candidate *, bool); ...@@ -45,11 +45,13 @@ static int joust (struct z_candidate *, struct z_candidate *, bool);
static int compare_ics (tree, tree); static int compare_ics (tree, tree);
static tree build_over_call (struct z_candidate *, int); static tree build_over_call (struct z_candidate *, int);
static tree build_java_interface_fn_ref (tree, tree); static tree build_java_interface_fn_ref (tree, tree);
#define convert_like(CONV, EXPR) \ #define convert_like(CONV, EXPR) \
convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0) convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0, \
#define convert_like_with_context(CONV, EXPR, FN, ARGNO) \ /*issue_conversion_warnings=*/true)
convert_like_real ((CONV), (EXPR), (FN), (ARGNO), 0) #define convert_like_with_context(CONV, EXPR, FN, ARGNO) \
static tree convert_like_real (tree, tree, tree, int, int); convert_like_real ((CONV), (EXPR), (FN), (ARGNO), 0, \
/*issue_conversion_warnings=*/true)
static tree convert_like_real (tree, tree, tree, int, int, bool);
static void op_error (enum tree_code, enum tree_code, tree, tree, static void op_error (enum tree_code, enum tree_code, tree, tree,
tree, const char *); tree, const char *);
static tree build_object_call (tree, tree); static tree build_object_call (tree, tree);
...@@ -4115,14 +4117,17 @@ enforce_access (tree basetype_path, tree decl) ...@@ -4115,14 +4117,17 @@ enforce_access (tree basetype_path, tree decl)
return true; return true;
} }
/* Perform the conversions in CONVS on the expression EXPR. /* Perform the conversions in CONVS on the expression EXPR. FN and
FN and ARGNUM are used for diagnostics. ARGNUM is zero based, -1 ARGNUM are used for diagnostics. ARGNUM is zero based, -1
indicates the `this' argument of a method. INNER is nonzero when indicates the `this' argument of a method. INNER is nonzero when
being called to continue a conversion chain. It is negative when a being called to continue a conversion chain. It is negative when a
reference binding will be applied, positive otherwise. */ reference binding will be applied, positive otherwise. If
ISSUE_CONVERSION_WARNINGS is true, warnings about suspicious
conversions will be emitted if appropriate. */
static tree static tree
convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner) convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner,
bool issue_conversion_warnings)
{ {
int savew, savee; int savew, savee;
...@@ -4138,11 +4143,13 @@ convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner) ...@@ -4138,11 +4143,13 @@ convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner)
{ {
if (TREE_CODE (t) == USER_CONV || !ICS_BAD_FLAG (t)) if (TREE_CODE (t) == USER_CONV || !ICS_BAD_FLAG (t))
{ {
expr = convert_like_real (t, expr, fn, argnum, 1); expr = convert_like_real (t, expr, fn, argnum, 1,
/*issue_conversion_warnings=*/false);
break; break;
} }
else if (TREE_CODE (t) == AMBIG_CONV) else if (TREE_CODE (t) == AMBIG_CONV)
return convert_like_real (t, expr, fn, argnum, 1); return convert_like_real (t, expr, fn, argnum, 1,
/*issue_conversion_warnings=*/false);
else if (TREE_CODE (t) == IDENTITY_CONV) else if (TREE_CODE (t) == IDENTITY_CONV)
break; break;
} }
...@@ -4152,7 +4159,7 @@ convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner) ...@@ -4152,7 +4159,7 @@ convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner)
return cp_convert (totype, expr); return cp_convert (totype, expr);
} }
if (!inner) if (issue_conversion_warnings)
expr = dubious_conversion_warnings expr = dubious_conversion_warnings
(totype, expr, "argument", fn, argnum); (totype, expr, "argument", fn, argnum);
switch (TREE_CODE (convs)) switch (TREE_CODE (convs))
...@@ -4250,7 +4257,8 @@ convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner) ...@@ -4250,7 +4257,8 @@ convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner)
}; };
expr = convert_like_real (TREE_OPERAND (convs, 0), expr, fn, argnum, expr = convert_like_real (TREE_OPERAND (convs, 0), expr, fn, argnum,
TREE_CODE (convs) == REF_BIND ? -1 : 1); TREE_CODE (convs) == REF_BIND ? -1 : 1,
/*issue_conversion_warnings=*/false);
if (expr == error_mark_node) if (expr == error_mark_node)
return error_mark_node; return error_mark_node;
...@@ -6058,6 +6066,25 @@ perform_implicit_conversion (tree type, tree expr) ...@@ -6058,6 +6066,25 @@ perform_implicit_conversion (tree type, tree expr)
return convert_like (conv, expr); return convert_like (conv, expr);
} }
/* Convert EXPR to TYPE (as a direct-initialization) if that is
permitted. If the conversion is valid, the converted expression is
returned. Otherwise, NULL_TREE is returned. */
tree
perform_direct_initialization_if_possible (tree type, tree expr)
{
tree conv;
if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
conv = implicit_conversion (type, TREE_TYPE (expr), expr,
LOOKUP_NORMAL);
if (!conv || ICS_BAD_FLAG (conv))
return NULL_TREE;
return convert_like_real (conv, expr, NULL_TREE, 0, 0,
/*issue_conversion_warnings=*/false);
}
/* DECL is a VAR_DECL whose type is a REFERENCE_TYPE. The reference /* DECL is a VAR_DECL whose type is a REFERENCE_TYPE. The reference
is being bound to a temporary. Create and return a new VAR_DECL is being bound to a temporary. Create and return a new VAR_DECL
with the indicated TYPE; this variable will store the value to with the indicated TYPE; this variable will store the value to
......
...@@ -3525,6 +3525,7 @@ extern tree initialize_reference (tree, tree, tree); ...@@ -3525,6 +3525,7 @@ extern tree initialize_reference (tree, tree, tree);
extern tree make_temporary_var_for_ref_to_temp (tree, tree); extern tree make_temporary_var_for_ref_to_temp (tree, tree);
extern tree strip_top_quals (tree); extern tree strip_top_quals (tree);
extern tree perform_implicit_conversion (tree, tree); extern tree perform_implicit_conversion (tree, tree);
extern tree perform_direct_initialization_if_possible (tree, tree);
extern tree in_charge_arg_for_name (tree); extern tree in_charge_arg_for_name (tree);
extern tree build_cxx_call (tree, tree, tree); extern tree build_cxx_call (tree, tree, tree);
......
...@@ -4766,11 +4766,24 @@ build_compound_expr (tree list) ...@@ -4766,11 +4766,24 @@ build_compound_expr (tree list)
return build (COMPOUND_EXPR, TREE_TYPE (rest), first, rest); return build (COMPOUND_EXPR, TREE_TYPE (rest), first, rest);
} }
/* Issue an error message if casting from SRC_TYPE to DEST_TYPE casts
away constness. */
static void
check_for_casting_away_constness (tree src_type, tree dest_type)
{
if (casts_away_constness (src_type, dest_type))
error ("static_cast from type `%T' to type `%T' casts away constness",
src_type, dest_type);
}
/* Return an expression representing static_cast<TYPE>(EXPR). */
tree tree
build_static_cast (tree type, tree expr) build_static_cast (tree type, tree expr)
{ {
tree intype; tree intype;
int ok; tree result;
if (type == error_mark_node || expr == error_mark_node) if (type == error_mark_node || expr == error_mark_node)
return error_mark_node; return error_mark_node;
...@@ -4791,88 +4804,149 @@ build_static_cast (tree type, tree expr) ...@@ -4791,88 +4804,149 @@ build_static_cast (tree type, tree expr)
&& TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0))) && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
expr = TREE_OPERAND (expr, 0); expr = TREE_OPERAND (expr, 0);
if (TREE_CODE (type) == VOID_TYPE) intype = TREE_TYPE (expr);
{
expr = convert_to_void (expr, /*implicit=*/NULL);
return expr;
}
if (TREE_CODE (type) == REFERENCE_TYPE) /* [expr.static.cast]
return (convert_from_reference
(convert_to_reference (type, expr, CONV_STATIC|CONV_IMPLICIT,
LOOKUP_COMPLAIN, NULL_TREE)));
if (IS_AGGR_TYPE (type)) An expression e can be explicitly converted to a type T using a
return build_cplus_new (type, (build_special_member_call static_cast of the form static_cast<T>(e) if the declaration T
(NULL_TREE, complete_ctor_identifier, t(e);" is well-formed, for some invented temporary variable
build_tree_list (NULL_TREE, expr), t. */
TYPE_BINFO (type), LOOKUP_NORMAL))); result = perform_direct_initialization_if_possible (type, expr);
if (result)
return result;
intype = TREE_TYPE (expr); /* [expr.static.cast]
/* FIXME handle casting to array type. */ Any expression can be explicitly converted to type cv void. */
if (TREE_CODE (type) == VOID_TYPE)
return convert_to_void (expr, /*implicit=*/NULL);
ok = 0; /* [expr.static.cast]
if (IS_AGGR_TYPE (intype)
? can_convert_arg (type, intype, expr) An lvalue of type "cv1 B", where B is a class type, can be cast
: can_convert_arg (strip_all_pointer_quals (type), to type "reference to cv2 D", where D is a class derived (clause
strip_all_pointer_quals (intype), expr)) _class.derived_) from B, if a valid standard conversion from
/* This is a standard conversion. */ "pointer to D" to "pointer to B" exists (_conv.ptr_), cv2 is the
ok = 1; same cv-qualification as, or greater cv-qualification than, cv1,
else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype)) and B is not a virtual base class of D. */
{ if (TREE_CODE (type) == REFERENCE_TYPE
/* They're pointers to objects. They must be aggregates that && CLASS_TYPE_P (TREE_TYPE (type))
are related non-virtually. */ && CLASS_TYPE_P (intype)
base_kind kind; && real_non_cast_lvalue_p (expr)
&& DERIVED_FROM_P (intype, TREE_TYPE (type))
if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype)) && can_convert (build_pointer_type (TYPE_MAIN_VARIANT (intype)),
&& lookup_base (TREE_TYPE (type), TREE_TYPE (intype), build_pointer_type (TYPE_MAIN_VARIANT
ba_ignore | ba_quiet, &kind) (TREE_TYPE (type))))
&& kind != bk_via_virtual) && at_least_as_qualified_p (TREE_TYPE (type), intype))
ok = 1; {
} /* At this point we have checked all of the conditions except
else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)) that B is not a virtual base class of D. That will be
{ checked by build_base_path. */
/* They're pointers to members. The pointed to objects must be tree base = lookup_base (TREE_TYPE (type), intype, ba_any, NULL);
the same (ignoring CV qualifiers), and the containing classes
must be related non-virtually. */ /* Convert from B* to D*. */
base_kind kind; expr = build_base_path (MINUS_EXPR, build_address (expr),
base, /*nonnull=*/false);
if (same_type_p /* Convert the pointer to a reference. */
(strip_all_pointer_quals (TREE_TYPE (TREE_TYPE (type))), return build_nop (type, expr);
strip_all_pointer_quals (TREE_TYPE (TREE_TYPE (intype)))) }
&& (lookup_base (TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)),
TYPE_OFFSET_BASETYPE (TREE_TYPE (type)),
ba_ignore | ba_quiet, &kind))
&& kind != bk_via_virtual)
ok = 1;
}
else if (TREE_CODE (intype) != BOOLEAN_TYPE
&& TREE_CODE (type) != ARRAY_TYPE
&& TREE_CODE (type) != FUNCTION_TYPE
&& can_convert (intype, strip_all_pointer_quals (type)))
ok = 1;
else if (TREE_CODE (intype) == ENUMERAL_TYPE
&& TREE_CODE (type) == ENUMERAL_TYPE)
/* DR 128: "A value of integral _or enumeration_ type can be explicitly
converted to an enumeration type."
The integral to enumeration will be accepted by the previous clause.
We need to explicitly check for enumeration to enumeration. */
ok = 1;
/* [expr.static.cast] /* [expr.static.cast]
The static_cast operator shall not be used to cast away The inverse of any standard conversion sequence (clause _conv_),
constness. */ other than the lvalue-to-rvalue (_conv.lval_), array-to-pointer
if (ok && casts_away_constness (intype, type)) (_conv.array_), function-to-pointer (_conv.func_), and boolean
{ (_conv.bool_) conversions, can be performed explicitly using
error ("static_cast from type `%T' to type `%T' casts away constness", static_cast subject to the restriction that the explicit
intype, type); conversion does not cast away constness (_expr.const.cast_), and
return error_mark_node; the following additional rules for specific cases: */
/* For reference, the conversions not excluded are: integral
promotions, floating point promotion, integral conversions,
floating point conversions, floating-integral conversions,
pointer conversions, and pointer to member conversions. */
if ((ARITHMETIC_TYPE_P (type) && ARITHMETIC_TYPE_P (intype))
/* DR 128
A value of integral _or enumeration_ type can be explicitly
converted to an enumeration type. */
|| (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
&& INTEGRAL_OR_ENUMERATION_TYPE_P (intype)))
/* Really, build_c_cast should defer to this function rather
than the other way around. */
return build_c_cast (type, expr);
if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
&& CLASS_TYPE_P (TREE_TYPE (type))
&& CLASS_TYPE_P (TREE_TYPE (intype))
&& can_convert (build_pointer_type (TYPE_MAIN_VARIANT
(TREE_TYPE (intype))),
build_pointer_type (TYPE_MAIN_VARIANT
(TREE_TYPE (type)))))
{
tree base;
check_for_casting_away_constness (intype, type);
base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
ba_check | ba_quiet, NULL);
return build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
}
if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
{
tree c1;
tree c2;
tree t1;
tree t2;
c1 = TYPE_PTRMEM_CLASS_TYPE (intype);
c2 = TYPE_PTRMEM_CLASS_TYPE (type);
if (TYPE_PTRMEM_P (type))
{
t1 = (build_ptrmem_type
(c1,
TYPE_MAIN_VARIANT (TYPE_PTRMEM_POINTED_TO_TYPE (intype))));
t2 = (build_ptrmem_type
(c2,
TYPE_MAIN_VARIANT (TYPE_PTRMEM_POINTED_TO_TYPE (type))));
}
else
{
t1 = intype;
t2 = type;
}
if (can_convert (t1, t2))
{
check_for_casting_away_constness (intype, type);
if (TYPE_PTRMEM_P (type))
{
if (TREE_CODE (expr) == PTRMEM_CST)
expr = cplus_expand_constant (expr);
expr = cp_build_binary_op (PLUS_EXPR,
cp_convert (ptrdiff_type_node, expr),
get_delta_difference (c1, c2,
/*force=*/1));
return build_nop (type, expr);
}
else
return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr,
/*force=*/1);
}
} }
/* [expr.static.cast]
if (ok) An rvalue of type "pointer to cv void" can be explicitly
return build_c_cast (type, expr); converted to a pointer to object type. A value of type pointer
to object converted to "pointer to cv void" and back to the
original pointer type will have its original value. */
if (TREE_CODE (intype) == POINTER_TYPE
&& VOID_TYPE_P (TREE_TYPE (intype))
&& TYPE_PTROB_P (type))
{
check_for_casting_away_constness (intype, type);
return build_nop (type, expr);
}
error ("invalid static_cast from type `%T' to type `%T'", intype, type); error ("invalid static_cast from type `%T' to type `%T'", intype, type);
return error_mark_node; return error_mark_node;
......
2003-06-25 Mark Mitchell <mark@codesourcery.com>
PR c++/10931
* g++.dg/expr/static_cast1.C: New test.
2003-06-25 Josef Zlomek <zlomekj@suse.cz> 2003-06-25 Josef Zlomek <zlomekj@suse.cz>
* gcc.dg/20030625-1.c: New test. * gcc.dg/20030625-1.c: New test.
......
void foo(int x)
{
static_cast<const unsigned int&>(x);
}
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