diff options
author | Mark Mitchell <mark@codesourcery.com> | 2003-06-26 00:07:09 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2003-06-26 00:07:09 +0000 |
commit | 3fe18f1d4722d2cc202978537ec28ba3668e5cc8 (patch) | |
tree | 281a1acd47d7c8c8c2b28917010ced8fb26b4b98 /gcc/cp | |
parent | 22c7c85ebc1408ab528f400094e5dc513e51dcdc (diff) | |
download | gcc-3fe18f1d4722d2cc202978537ec28ba3668e5cc8.zip gcc-3fe18f1d4722d2cc202978537ec28ba3668e5cc8.tar.gz gcc-3fe18f1d4722d2cc202978537ec28ba3668e5cc8.tar.bz2 |
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
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/cp/call.c | 53 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 220 |
4 files changed, 199 insertions, 86 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 65ca03d..d624446 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 77ed3e8..41ad02d 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1527aa4..0e3a971 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index be53d45..c84cc84 100644 --- a/gcc/cp/typeck.c +++ b/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; - } + intype = TREE_TYPE (expr); - if (TREE_CODE (type) == REFERENCE_TYPE) - return (convert_from_reference - (convert_to_reference (type, expr, CONV_STATIC|CONV_IMPLICIT, - LOOKUP_COMPLAIN, NULL_TREE))); + /* [expr.static.cast] - 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))); + 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; - 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; - 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] + + 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)) + { + /* 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); + } /* [expr.static.cast] - The static_cast operator shall not be used to cast away - constness. */ - if (ok && casts_away_constness (intype, type)) - { - error ("static_cast from type `%T' to type `%T' casts away constness", - intype, type); - return error_mark_node; + 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] - if (ok) - return build_c_cast (type, expr); + 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; |