aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2003-06-26 00:07:09 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2003-06-26 00:07:09 +0000
commit3fe18f1d4722d2cc202978537ec28ba3668e5cc8 (patch)
tree281a1acd47d7c8c8c2b28917010ced8fb26b4b98 /gcc/cp
parent22c7c85ebc1408ab528f400094e5dc513e51dcdc (diff)
downloadgcc-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/ChangeLog11
-rw-r--r--gcc/cp/call.c53
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/typeck.c220
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;