mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-25 03:04:01 +08:00
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
This commit is contained in:
parent
22c7c85ebc
commit
3fe18f1d47
@ -1,3 +1,14 @@
|
||||
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>
|
||||
|
||||
* call.c (enforce_access): Assert we get a binfo.
|
||||
|
@ -45,11 +45,13 @@ static int joust (struct z_candidate *, struct z_candidate *, bool);
|
||||
static int compare_ics (tree, tree);
|
||||
static tree build_over_call (struct z_candidate *, int);
|
||||
static tree build_java_interface_fn_ref (tree, tree);
|
||||
#define convert_like(CONV, EXPR) \
|
||||
convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0)
|
||||
#define convert_like_with_context(CONV, EXPR, FN, ARGNO) \
|
||||
convert_like_real ((CONV), (EXPR), (FN), (ARGNO), 0)
|
||||
static tree convert_like_real (tree, tree, tree, int, int);
|
||||
#define convert_like(CONV, EXPR) \
|
||||
convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0, \
|
||||
/*issue_conversion_warnings=*/true)
|
||||
#define convert_like_with_context(CONV, EXPR, FN, ARGNO) \
|
||||
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,
|
||||
tree, const char *);
|
||||
static tree build_object_call (tree, tree);
|
||||
@ -4115,14 +4117,17 @@ enforce_access (tree basetype_path, tree decl)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Perform the conversions in CONVS on the expression EXPR.
|
||||
FN and ARGNUM are used for diagnostics. ARGNUM is zero based, -1
|
||||
/* Perform the conversions in CONVS on the expression EXPR. FN and
|
||||
ARGNUM are used for diagnostics. ARGNUM is zero based, -1
|
||||
indicates the `this' argument of a method. INNER is nonzero when
|
||||
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
|
||||
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;
|
||||
|
||||
@ -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))
|
||||
{
|
||||
expr = convert_like_real (t, expr, fn, argnum, 1);
|
||||
expr = convert_like_real (t, expr, fn, argnum, 1,
|
||||
/*issue_conversion_warnings=*/false);
|
||||
break;
|
||||
}
|
||||
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)
|
||||
break;
|
||||
}
|
||||
@ -4152,7 +4159,7 @@ convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner)
|
||||
return cp_convert (totype, expr);
|
||||
}
|
||||
|
||||
if (!inner)
|
||||
if (issue_conversion_warnings)
|
||||
expr = dubious_conversion_warnings
|
||||
(totype, expr, "argument", fn, argnum);
|
||||
switch (TREE_CODE (convs))
|
||||
@ -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,
|
||||
TREE_CODE (convs) == REF_BIND ? -1 : 1);
|
||||
TREE_CODE (convs) == REF_BIND ? -1 : 1,
|
||||
/*issue_conversion_warnings=*/false);
|
||||
if (expr == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
@ -6058,6 +6066,25 @@ perform_implicit_conversion (tree type, tree 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
|
||||
is being bound to a temporary. Create and return a new VAR_DECL
|
||||
with the indicated TYPE; this variable will store the value to
|
||||
|
@ -3525,6 +3525,7 @@ extern tree initialize_reference (tree, tree, tree);
|
||||
extern tree make_temporary_var_for_ref_to_temp (tree, tree);
|
||||
extern tree strip_top_quals (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 build_cxx_call (tree, tree, tree);
|
||||
|
||||
|
226
gcc/cp/typeck.c
226
gcc/cp/typeck.c
@ -4766,11 +4766,24 @@ build_compound_expr (tree list)
|
||||
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
|
||||
build_static_cast (tree type, tree expr)
|
||||
{
|
||||
tree intype;
|
||||
int ok;
|
||||
tree result;
|
||||
|
||||
if (type == error_mark_node || expr == error_mark_node)
|
||||
return error_mark_node;
|
||||
@ -4791,88 +4804,149 @@ build_static_cast (tree type, tree expr)
|
||||
&& TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
|
||||
expr = TREE_OPERAND (expr, 0);
|
||||
|
||||
if (TREE_CODE (type) == VOID_TYPE)
|
||||
{
|
||||
expr = convert_to_void (expr, /*implicit=*/NULL);
|
||||
return expr;
|
||||
}
|
||||
|
||||
if (TREE_CODE (type) == REFERENCE_TYPE)
|
||||
return (convert_from_reference
|
||||
(convert_to_reference (type, expr, CONV_STATIC|CONV_IMPLICIT,
|
||||
LOOKUP_COMPLAIN, NULL_TREE)));
|
||||
|
||||
if (IS_AGGR_TYPE (type))
|
||||
return build_cplus_new (type, (build_special_member_call
|
||||
(NULL_TREE, complete_ctor_identifier,
|
||||
build_tree_list (NULL_TREE, expr),
|
||||
TYPE_BINFO (type), LOOKUP_NORMAL)));
|
||||
|
||||
intype = TREE_TYPE (expr);
|
||||
|
||||
/* FIXME handle casting to array type. */
|
||||
|
||||
ok = 0;
|
||||
if (IS_AGGR_TYPE (intype)
|
||||
? can_convert_arg (type, intype, expr)
|
||||
: can_convert_arg (strip_all_pointer_quals (type),
|
||||
strip_all_pointer_quals (intype), expr))
|
||||
/* This is a standard conversion. */
|
||||
ok = 1;
|
||||
else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
|
||||
{
|
||||
/* They're pointers to objects. They must be aggregates that
|
||||
are related non-virtually. */
|
||||
base_kind kind;
|
||||
|
||||
if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
|
||||
&& lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
|
||||
ba_ignore | ba_quiet, &kind)
|
||||
&& kind != bk_via_virtual)
|
||||
ok = 1;
|
||||
}
|
||||
else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|
||||
{
|
||||
/* They're pointers to members. The pointed to objects must be
|
||||
the same (ignoring CV qualifiers), and the containing classes
|
||||
must be related non-virtually. */
|
||||
base_kind kind;
|
||||
|
||||
if (same_type_p
|
||||
(strip_all_pointer_quals (TREE_TYPE (TREE_TYPE (type))),
|
||||
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]
|
||||
|
||||
The static_cast operator shall not be used to cast away
|
||||
constness. */
|
||||
if (ok && casts_away_constness (intype, type))
|
||||
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 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. */
|
||||
if (TREE_CODE (type) == REFERENCE_TYPE
|
||||
&& CLASS_TYPE_P (TREE_TYPE (type))
|
||||
&& CLASS_TYPE_P (intype)
|
||||
&& real_non_cast_lvalue_p (expr)
|
||||
&& DERIVED_FROM_P (intype, TREE_TYPE (type))
|
||||
&& can_convert (build_pointer_type (TYPE_MAIN_VARIANT (intype)),
|
||||
build_pointer_type (TYPE_MAIN_VARIANT
|
||||
(TREE_TYPE (type))))
|
||||
&& at_least_as_qualified_p (TREE_TYPE (type), intype))
|
||||
{
|
||||
error ("static_cast from type `%T' to type `%T' casts away constness",
|
||||
intype, type);
|
||||
return error_mark_node;
|
||||
/* At this point we have checked all of the conditions except
|
||||
that B is not a virtual base class of D. That will be
|
||||
checked by build_base_path. */
|
||||
tree base = lookup_base (TREE_TYPE (type), intype, ba_any, NULL);
|
||||
|
||||
/* Convert from B* to D*. */
|
||||
expr = build_base_path (MINUS_EXPR, build_address (expr),
|
||||
base, /*nonnull=*/false);
|
||||
/* Convert the pointer to a reference. */
|
||||
return build_nop (type, expr);
|
||||
}
|
||||
|
||||
if (ok)
|
||||
return build_c_cast (type, expr);
|
||||
/* [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
|
||||
(_conv.bool_) conversions, can be performed explicitly using
|
||||
static_cast subject to the restriction that the explicit
|
||||
conversion does not cast away constness (_expr.const.cast_), and
|
||||
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]
|
||||
|
||||
An rvalue of type "pointer to cv void" can be explicitly
|
||||
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);
|
||||
return error_mark_node;
|
||||
|
@ -1,3 +1,8 @@
|
||||
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>
|
||||
|
||||
* gcc.dg/20030625-1.c: New test.
|
||||
|
5
gcc/testsuite/g++.dg/expr/static_cast1.C
Normal file
5
gcc/testsuite/g++.dg/expr/static_cast1.C
Normal file
@ -0,0 +1,5 @@
|
||||
void foo(int x)
|
||||
{
|
||||
static_cast<const unsigned int&>(x);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user