aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2004-10-19 23:24:20 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2004-10-19 23:24:20 +0000
commit33c25e5c5a69b096d8aafef5599bf93672dd3659 (patch)
treed0037995674537cc4efa3c0fd0c2f61cfe82efed /gcc/cp
parentb55d57460298a5e0f675b1e7a2af84690cb14f4d (diff)
downloadgcc-33c25e5c5a69b096d8aafef5599bf93672dd3659.zip
gcc-33c25e5c5a69b096d8aafef5599bf93672dd3659.tar.gz
gcc-33c25e5c5a69b096d8aafef5599bf93672dd3659.tar.bz2
call.c (struct conversion): Add base_p.
* call.c (struct conversion): Add base_p. (convert_like): Add c_cast_p argument. (convert_like_with_conversion): Likewise. (build_conv): Clear base_p. (standard_conversion): Set it, for derived-to-base conversions. (convert_like_real): Add c_cast_p parameter. Handle pointer conversions directly rather than relying on ocp_convert. (perform_direct_initialization_if_possible): Add c_cast_p parameter. * cp-tree.h (perform_direct_initialization_if_possible): Change prototype. (convert_member_func_to_ptr): New function. * typeck.c (check_for_casting_away_constness): Add diag_fn parameter. (build_static_cast_1): New function, split out from ... (build_static_cast): ... here. Use build_static_cast_1. (build_reinterpret_cast_1): New function, split out from ... (build_reinterpret_cast): ... here. Use build_reinterpret_cast_1. (build_const_cast_1): New function, split out from ... (build_const_cast): ... here. Use build_const_cast_1. (build_c_cast): Rewrite to use build_const_cast_1, build_static_cast_1, and build_reinterpret_cast_1. (convert_member_func_to_ptr): New function. * g++.dg/conversion/reinterpret1.C: Adjust error markers. * g++.dg/conversion/const2.C: New test. * g++.dg/expr/reinterpret2.C: New test. * g++.dg/expr/reinterpret3.C: New test. * g++.dg/expr/cast2.C: New test. * g++.dg/expr/copy1.C: New test. * g++.dg/other/conversion1.C: Change error message. * g++.dg/parse/comma1.C: Use __extension__ to allow casts from function pointers to void *. * g++.old-deja/g++.mike/p10148.C: Likewise. From-SVN: r89300
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog27
-rw-r--r--gcc/cp/call.c66
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/cvt.c25
-rw-r--r--gcc/cp/typeck.c603
5 files changed, 469 insertions, 255 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 325fbf3..0247ca5 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,30 @@
+2004-10-19 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/14035
+ * call.c (struct conversion): Add base_p.
+ (convert_like): Add c_cast_p argument.
+ (convert_like_with_conversion): Likewise.
+ (build_conv): Clear base_p.
+ (standard_conversion): Set it, for derived-to-base conversions.
+ (convert_like_real): Add c_cast_p parameter. Handle pointer
+ conversions directly rather than relying on ocp_convert.
+ (perform_direct_initialization_if_possible): Add c_cast_p
+ parameter.
+ * cp-tree.h (perform_direct_initialization_if_possible): Change
+ prototype.
+ (convert_member_func_to_ptr): New function.
+ * typeck.c (check_for_casting_away_constness): Add diag_fn
+ parameter.
+ (build_static_cast_1): New function, split out from ...
+ (build_static_cast): ... here. Use build_static_cast_1.
+ (build_reinterpret_cast_1): New function, split out from ...
+ (build_reinterpret_cast): ... here. Use build_reinterpret_cast_1.
+ (build_const_cast_1): New function, split out from ...
+ (build_const_cast): ... here. Use build_const_cast_1.
+ (build_c_cast): Rewrite to use build_const_cast_1,
+ build_static_cast_1, and build_reinterpret_cast_1.
+ (convert_member_func_to_ptr): New function.
+
2004-10-19 Paolo Bonzini <bonzini@gnu.org>
PR c++/18047
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index f15fd2c..c535cba 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -92,6 +92,9 @@ struct conversion {
copy constructor must be accessible, even though it is not being
used. */
BOOL_BITFIELD check_copy_constructor_p : 1;
+ /* If KIND is ck_ptr, true to indicate that a conversion from a
+ pointer-to-derived to pointer-to-base is being performed. */
+ BOOL_BITFIELD base_p : 1;
/* The type of the expression resulting from the conversion. */
tree type;
union {
@@ -125,12 +128,15 @@ static int compare_ics (conversion *, conversion *);
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, \
- /*issue_conversion_warnings=*/true)
+ convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0, \
+ /*issue_conversion_warnings=*/true, \
+ /*c_cast_p=*/false)
#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 (conversion *, tree, tree, int, int, bool);
+ convert_like_real ((CONV), (EXPR), (FN), (ARGNO), 0, \
+ /*issue_conversion_warnings=*/true, \
+ /*c_cast_p=*/false)
+static tree convert_like_real (conversion *, tree, tree, int, int, bool,
+ bool);
static void op_error (enum tree_code, enum tree_code, tree, tree,
tree, const char *);
static tree build_object_call (tree, tree);
@@ -528,6 +534,7 @@ build_conv (conversion_kind code, tree type, conversion *from)
t->rank = rank;
t->user_conv_p = (code == ck_user || from->user_conv_p);
t->bad_p = from->bad_p;
+ t->base_p = false;
return t;
}
@@ -721,6 +728,7 @@ standard_conversion (tree to, tree from, tree expr)
cp_type_quals (TREE_TYPE (from)));
from = build_pointer_type (from);
conv = build_conv (ck_ptr, from, conv);
+ conv->base_p = true;
}
if (tcode == POINTER_TYPE)
@@ -4113,11 +4121,14 @@ build_temp (tree expr, tree type, int flags,
being called to continue a conversion chain. It is negative when a
reference binding will be applied, positive otherwise. If
ISSUE_CONVERSION_WARNINGS is true, warnings about suspicious
- conversions will be emitted if appropriate. */
+ conversions will be emitted if appropriate. If C_CAST_P is true,
+ this conversion is coming from a C-style cast; in that case,
+ conversions to inaccessible bases are permitted. */
static tree
convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
- int inner, bool issue_conversion_warnings)
+ int inner, bool issue_conversion_warnings,
+ bool c_cast_p)
{
tree totype = convs->type;
void (*diagnostic_fn)(const char *, ...);
@@ -4133,12 +4144,14 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
if (t->kind == ck_user || !t->bad_p)
{
expr = convert_like_real (t, expr, fn, argnum, 1,
- /*issue_conversion_warnings=*/false);
+ /*issue_conversion_warnings=*/false,
+ /*c_cast_p=*/false);
break;
}
else if (t->kind == ck_ambig)
return convert_like_real (t, expr, fn, argnum, 1,
- /*issue_conversion_warnings=*/false);
+ /*issue_conversion_warnings=*/false,
+ /*c_cast_p=*/false);
else if (t->kind == ck_identity)
break;
}
@@ -4237,7 +4250,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
expr = convert_like_real (convs->u.next, expr, fn, argnum,
convs->kind == ck_ref_bind ? -1 : 1,
- /*issue_conversion_warnings=*/false);
+ /*issue_conversion_warnings=*/false,
+ c_cast_p);
if (expr == error_mark_node)
return error_mark_node;
@@ -4321,7 +4335,22 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
/* Warn about deprecated conversion if appropriate. */
string_conv_p (totype, expr, 1);
break;
-
+
+ case ck_ptr:
+ if (convs->base_p)
+ {
+ tree binfo;
+
+ binfo = lookup_base (TREE_TYPE (TREE_TYPE (expr)),
+ TREE_TYPE (totype),
+ c_cast_p ? ba_unique : ba_check,
+ NULL);
+ if (binfo == error_mark_node)
+ return error_mark_node;
+ expr = build_base_path (PLUS_EXPR, expr, binfo, /*nonnull=*/0);
+ }
+ return build_nop (totype, expr);
+
default:
break;
}
@@ -6273,10 +6302,15 @@ perform_implicit_conversion (tree type, tree 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, except in the case
- that TYPE is a class type; in that case, an error is issued. */
+ that TYPE is a class type; in that case, an error is issued. If
+ C_CAST_P is ttrue, then this direction initialization is taking
+ place as part of a static_cast being attempted as part of a C-style
+ cast. */
tree
-perform_direct_initialization_if_possible (tree type, tree expr)
+perform_direct_initialization_if_possible (tree type,
+ tree expr,
+ bool c_cast_p)
{
conversion *conv;
void *p;
@@ -6308,7 +6342,8 @@ perform_direct_initialization_if_possible (tree type, tree expr)
expr = NULL_TREE;
else
expr = convert_like_real (conv, expr, NULL_TREE, 0, 0,
- /*issue_conversion_warnings=*/false);
+ /*issue_conversion_warnings=*/false,
+ c_cast_p);
/* Free all the conversions we allocated. */
obstack_free (&conversion_obstack, p);
@@ -6449,7 +6484,8 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup)
expr = convert_like_real (conv, expr,
/*fn=*/NULL_TREE, /*argnum=*/0,
/*inner=*/-1,
- /*issue_conversion_warnings=*/true);
+ /*issue_conversion_warnings=*/true,
+ /*c_cast_p=*/false);
if (!real_lvalue_p (expr))
{
tree init;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b6c976b..6534170 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3585,7 +3585,7 @@ extern tree initialize_reference (tree, 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 perform_direct_initialization_if_possible (tree, tree, bool);
extern tree in_charge_arg_for_name (tree);
extern tree build_cxx_call (tree, tree);
#ifdef ENABLE_CHECKING
@@ -4290,6 +4290,7 @@ extern tree build_nop (tree, tree);
extern tree non_reference (tree);
extern tree lookup_anon_field (tree, tree);
extern bool invalid_nonstatic_memfn_p (tree);
+extern tree convert_member_func_to_ptr (tree, tree);
/* in typeck2.c */
extern void require_complete_eh_spec_types (tree, tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 8e9cb95..0223030 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -107,28 +107,9 @@ cp_convert_to_pointer (tree type, tree expr, bool force)
&& (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
|| VOID_TYPE_P (TREE_TYPE (type))))
{
- /* Allow an implicit this pointer for pointer to member
- functions. */
- if (TYPE_PTRMEMFUNC_P (intype))
- {
- if (pedantic || warn_pmf2ptr)
- pedwarn ("converting from `%T' to `%T'", intype, type);
- if (TREE_CODE (expr) == PTRMEM_CST)
- expr = build_address (PTRMEM_CST_MEMBER (expr));
- else
- {
- tree decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype),
- 0);
- decl = build_address (decl);
- expr = get_member_function_from_ptrfunc (&decl, expr);
- }
- }
- else if (TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE)
- {
- if (pedantic || warn_pmf2ptr)
- pedwarn ("converting from `%T' to `%T'", intype, type);
- expr = build_addr_func (expr);
- }
+ if (TYPE_PTRMEMFUNC_P (intype)
+ || TREE_CODE (intype) == METHOD_TYPE)
+ return convert_member_func_to_ptr (type, expr);
if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
return build_nop (type, expr);
intype = TREE_TYPE (expr);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index cb5a254..bff5c34 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -4468,47 +4468,58 @@ build_compound_expr (tree lhs, tree rhs)
return build2 (COMPOUND_EXPR, TREE_TYPE (rhs), lhs, rhs);
}
-/* Issue an error message if casting from SRC_TYPE to DEST_TYPE casts
- away constness. DESCRIPTION explains what operation is taking
- place. */
+/* Issue a diagnostic message if casting from SRC_TYPE to DEST_TYPE
+ casts away constness. DIAG_FN gives the function to call if we
+ need to issue a diagnostic; if it is NULL, no diagnostic will be
+ issued. DESCRIPTION explains what operation is taking place. */
static void
check_for_casting_away_constness (tree src_type, tree dest_type,
+ void (*diag_fn)(const char *, ...),
const char *description)
{
- if (casts_away_constness (src_type, dest_type))
+ if (diag_fn && casts_away_constness (src_type, dest_type))
error ("%s from type %qT to type %qT casts away constness",
description, src_type, dest_type);
}
-/* Return an expression representing static_cast<TYPE>(EXPR). */
+/* Perform a static_cast from EXPR to TYPE. When C_CAST_P is true,
+ this static_cast is being attempted as one of the possible casts
+ allowed by a C-style cast. (In that case, accessibility of base
+ classes is not considered, and it is OK to cast away
+ constness.) Return the result of the cast. *VALID_P is set to
+ indicate whether or not the cast was valid. */
-tree
-build_static_cast (tree type, tree expr)
+static tree
+build_static_cast_1 (tree type, tree expr, bool c_cast_p,
+ bool *valid_p)
{
tree intype;
tree result;
+ tree orig;
+ void (*diag_fn)(const char*, ...);
+ const char *desc;
- if (type == error_mark_node || expr == error_mark_node)
- return error_mark_node;
-
- if (processing_template_decl)
- {
- expr = build_min (STATIC_CAST_EXPR, type, expr);
- /* We don't know if it will or will not have side effects. */
- TREE_SIDE_EFFECTS (expr) = 1;
- return expr;
- }
-
- /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
- Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
- if (TREE_CODE (type) != REFERENCE_TYPE
- && TREE_CODE (expr) == NOP_EXPR
- && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
- expr = TREE_OPERAND (expr, 0);
+ /* Assume the cast is valid. */
+ *valid_p = true;
intype = TREE_TYPE (expr);
+ /* Determine what to do when casting away constness. */
+ if (c_cast_p)
+ {
+ /* C-style casts are allowed to cast away constness. With
+ WARN_CAST_QUAL, we still want to issue a warning. */
+ diag_fn = warn_cast_qual ? warning : NULL;
+ desc = "cast";
+ }
+ else
+ {
+ /* A static_cast may not cast away constness. */
+ diag_fn = error;
+ desc = "static_cast";
+ }
+
/* [expr.static.cast]
An lvalue of type "cv1 B", where B is a class type, can be cast
@@ -4536,12 +4547,20 @@ build_static_cast (tree type, tree expr)
&& 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))
+ && (c_cast_p
+ || at_least_as_qualified_p (TREE_TYPE (type), intype)))
{
+ tree base;
+
/* There is a standard conversion from "D*" to "B*" even if "B"
- is ambiguous or inaccessible. Therefore, we ask lookup_base
- to check these conditions. */
- tree base = lookup_base (TREE_TYPE (type), intype, ba_check, NULL);
+ is ambiguous or inaccessible. If this is really a
+ static_cast, then we check both for inaccessibility and
+ ambiguity. However, if this is a static_cast being performed
+ because the user wrote a C-style cast, then accessibility is
+ not considered. */
+ base = lookup_base (TREE_TYPE (type), intype,
+ c_cast_p ? ba_unique : ba_check,
+ NULL);
/* Convert from "B*" to "D*". This function will check that "B"
is not a virtual base of "D". */
@@ -4552,16 +4571,28 @@ build_static_cast (tree type, tree expr)
return convert_from_reference (build_nop (type, expr));
}
+ orig = 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);
+ result = perform_direct_initialization_if_possible (type, expr,
+ c_cast_p);
if (result)
{
result = convert_from_reference (result);
+
+ /* Ignore any integer overflow caused by the cast. */
+ if (TREE_CODE (result) == INTEGER_CST
+ && CONSTANT_CLASS_P (orig))
+ {
+ TREE_OVERFLOW (result) = TREE_OVERFLOW (orig);
+ TREE_CONSTANT_OVERFLOW (result)
+ = TREE_CONSTANT_OVERFLOW (orig);
+ }
/* [expr.static.cast]
If T is a reference type, the result is an lvalue; otherwise,
@@ -4598,10 +4629,20 @@ build_static_cast (tree type, tree expr)
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);
-
+ {
+ expr = decl_constant_value (expr);
+ expr = ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
+
+ /* Ignore any integer overflow caused by the cast. */
+ if (TREE_CODE (expr) == INTEGER_CST
+ && CONSTANT_CLASS_P (orig))
+ {
+ TREE_OVERFLOW (expr) = TREE_OVERFLOW (orig);
+ TREE_CONSTANT_OVERFLOW (expr) = TREE_CONSTANT_OVERFLOW (orig);
+ }
+ return expr;
+ }
+
if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
&& CLASS_TYPE_P (TREE_TYPE (type))
&& CLASS_TYPE_P (TREE_TYPE (intype))
@@ -4612,8 +4653,10 @@ build_static_cast (tree type, tree expr)
{
tree base;
- check_for_casting_away_constness (intype, type, "static_cast");
- base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), ba_check,
+ if (!c_cast_p)
+ check_for_casting_away_constness (intype, type, diag_fn, desc);
+ base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
+ c_cast_p ? ba_unique : ba_check,
NULL);
return build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
}
@@ -4645,7 +4688,8 @@ build_static_cast (tree type, tree expr)
}
if (can_convert (t1, t2))
{
- check_for_casting_away_constness (intype, type, "static_cast");
+ if (!c_cast_p)
+ check_for_casting_away_constness (intype, type, diag_fn, desc);
if (TYPE_PTRMEM_P (type))
{
tree delta;
@@ -4675,77 +4719,180 @@ build_static_cast (tree type, tree expr)
&& VOID_TYPE_P (TREE_TYPE (intype))
&& TYPE_PTROB_P (type))
{
- check_for_casting_away_constness (intype, type, "static_cast");
+ if (!c_cast_p)
+ check_for_casting_away_constness (intype, type, diag_fn, desc);
return build_nop (type, expr);
}
- error ("invalid static_cast from type %qT to type %qT", intype, type);
+ *valid_p = false;
return error_mark_node;
}
+/* Return an expression representing static_cast<TYPE>(EXPR). */
+
tree
-build_reinterpret_cast (tree type, tree expr)
+build_static_cast (tree type, tree expr)
{
- tree intype;
+ tree result;
+ bool valid_p;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
if (processing_template_decl)
{
- tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
-
- if (!TREE_SIDE_EFFECTS (t)
- && type_dependent_expression_p (expr))
- /* There might turn out to be side effects inside expr. */
- TREE_SIDE_EFFECTS (t) = 1;
- return t;
+ expr = build_min (STATIC_CAST_EXPR, type, expr);
+ /* We don't know if it will or will not have side effects. */
+ TREE_SIDE_EFFECTS (expr) = 1;
+ return expr;
}
- if (TREE_CODE (type) != REFERENCE_TYPE)
- {
- expr = decay_conversion (expr);
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (type) != REFERENCE_TYPE
+ && TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
- /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
- Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
- if (TREE_CODE (expr) == NOP_EXPR
- && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
- expr = TREE_OPERAND (expr, 0);
- }
+ result = build_static_cast_1 (type, expr, /*c_cast_p=*/false, &valid_p);
+ if (valid_p)
+ return result;
+
+ error ("invalid static_cast from type %qT to type %qT",
+ TREE_TYPE (expr), type);
+ return error_mark_node;
+}
+
+/* EXPR is an expression with member function or pointer-to-member
+ function type. TYPE is a pointer type. Converting EXPR to TYPE is
+ not permitted by ISO C++, but we accept it in some modes. If we
+ are not in one of those modes, issue a diagnostic. Return the
+ converted expression. */
+
+tree
+convert_member_func_to_ptr (tree type, tree expr)
+{
+ tree intype;
+ tree decl;
intype = TREE_TYPE (expr);
+ gcc_assert (TYPE_PTRMEMFUNC_P (intype)
+ || TREE_CODE (intype) == METHOD_TYPE);
- if (intype == error_mark_node)
+ if (pedantic || warn_pmf2ptr)
+ pedwarn ("converting from `%T' to `%T'", intype, type);
+
+ if (TREE_CODE (intype) == METHOD_TYPE)
+ expr = build_addr_func (expr);
+ else if (TREE_CODE (expr) == PTRMEM_CST)
+ expr = build_address (PTRMEM_CST_MEMBER (expr));
+ else
+ {
+ decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 0);
+ decl = build_address (decl);
+ expr = get_member_function_from_ptrfunc (&decl, expr);
+ }
+
+ return build_nop (type, expr);
+}
+
+/* Return a representation for a reinterpret_cast from EXPR to TYPE.
+ If C_CAST_P is true, this reinterpret cast is being done as part of
+ a C-style cast. If VALID_P is non-NULL, *VALID_P is set to
+ indicate whether or not reinterpret_cast was valid. */
+
+static tree
+build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
+ bool *valid_p)
+{
+ tree intype;
+
+ /* Assume the cast is invalid. */
+ if (valid_p)
+ *valid_p = true;
+
+ if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
+ intype = TREE_TYPE (expr);
+
+ /* [expr.reinterpret.cast]
+ An lvalue expression of type T1 can be cast to the type
+ "reference to T2" if an expression of type "pointer to T1" can be
+ explicitly converted to the type "pointer to T2" using a
+ reinterpret_cast. */
if (TREE_CODE (type) == REFERENCE_TYPE)
{
if (! real_lvalue_p (expr))
{
- error ("invalid reinterpret_cast of an rvalue expression of type "
- "%qT to type %qT", intype, type);
+ error ("invalid cast of an rvalue expression of type "
+ "%qT to type %qT",
+ intype, type);
return error_mark_node;
}
+
+ /* Warn about a reinterpret_cast from "A*" to "B&" if "A" and
+ "B" are related class types; the reinterpret_cast does not
+ adjust the pointer. */
+ if (TYPE_PTR_P (intype)
+ && (comptypes (TREE_TYPE (intype), TREE_TYPE (type),
+ COMPARE_BASE | COMPARE_DERIVED)))
+ warning ("casting `%T' to `%T' does not dereference pointer",
+ intype, type);
+
expr = build_unary_op (ADDR_EXPR, expr, 0);
if (expr != error_mark_node)
- expr = build_reinterpret_cast
- (build_pointer_type (TREE_TYPE (type)), expr);
+ expr = build_reinterpret_cast_1
+ (build_pointer_type (TREE_TYPE (type)), expr, c_cast_p,
+ valid_p);
if (expr != error_mark_node)
expr = build_indirect_ref (expr, 0);
return expr;
}
- else if (same_type_ignoring_top_level_qualifiers_p (intype, type))
- return build_static_cast (type, expr);
- if (TYPE_PTR_P (type) && (TREE_CODE (intype) == INTEGER_TYPE
- || TREE_CODE (intype) == ENUMERAL_TYPE))
- /* OK */;
- else if (TREE_CODE (type) == INTEGER_TYPE && TYPE_PTR_P (intype))
+ /* As a G++ extension, we consider conversions from member
+ functions, and pointers to member functions to
+ pointer-to-function and pointer-to-void types. If
+ -Wno-pmf-conversions has not been specified,
+ convert_member_func_to_ptr will issue an error message. */
+ if ((TYPE_PTRMEMFUNC_P (intype)
+ || TREE_CODE (intype) == METHOD_TYPE)
+ && TYPE_PTR_P (type)
+ && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+ || VOID_TYPE_P (TREE_TYPE (type))))
+ return convert_member_func_to_ptr (type, expr);
+
+ /* If the cast is not to a reference type, the lvalue-to-rvale,
+ array-to-pointer, and function-to-pointer conversions are
+ performed. */
+ expr = decay_conversion (expr);
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
+
+ if (error_operand_p (expr))
+ return error_mark_node;
+
+ intype = TREE_TYPE (expr);
+
+ /* [expr.reinterpret.cast]
+ A pointer can be converted to any integral type large enough to
+ hold it. */
+ if (CP_INTEGRAL_TYPE_P (type) && TYPE_PTR_P (intype))
{
if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
- pedwarn ("reinterpret_cast from %qT to %qT loses precision",
+ pedwarn ("cast from %qT to %qT loses precision",
intype, type);
}
+ /* [expr.reinterpret.cast]
+ A value of integral or enumeration type can be explicitly
+ converted to a pointer. */
+ else if (TYPE_PTR_P (type) && INTEGRAL_OR_ENUMERATION_TYPE_P (intype))
+ /* OK */
+ ;
else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
{
@@ -4755,21 +4902,35 @@ build_reinterpret_cast (tree type, tree expr)
else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|| (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
{
- check_for_casting_away_constness (intype, type, "reinterpret_cast");
+ if (!c_cast_p)
+ check_for_casting_away_constness (intype, type, error,
+ "reinterpret_cast");
+ /* Warn about possible alignment problems. */
+ if (STRICT_ALIGNMENT && warn_cast_align
+ && !VOID_TYPE_P (type)
+ && TREE_CODE (TREE_TYPE (intype)) != FUNCTION_TYPE
+ && COMPLETE_TYPE_P (TREE_TYPE (type))
+ && COMPLETE_TYPE_P (TREE_TYPE (intype))
+ && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (intype)))
+ warning ("cast from %qT to %qT increases required alignment of "
+ "target type",
+ intype, type);
expr = decl_constant_value (expr);
return fold_if_not_in_template (build_nop (type, expr));
}
else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
|| (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
{
- pedwarn ("ISO C++ forbids casting between pointer-to-function and pointer-to-object");
+ if (pedantic || !c_cast_p)
+ pedwarn ("ISO C++ forbids casting between pointer-to-function and pointer-to-object");
expr = decl_constant_value (expr);
return fold_if_not_in_template (build_nop (type, expr));
}
else
{
- error ("invalid reinterpret_cast from type %qT to type %qT",
- intype, type);
+ if (valid_p)
+ *valid_p = false;
+ error ("invalid cast from type %qT to type %qT", intype, type);
return error_mark_node;
}
@@ -4777,16 +4938,14 @@ build_reinterpret_cast (tree type, tree expr)
}
tree
-build_const_cast (tree type, tree expr)
+build_reinterpret_cast (tree type, tree expr)
{
- tree intype;
-
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
if (processing_template_decl)
{
- tree t = build_min (CONST_CAST_EXPR, type, expr);
+ tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
if (!TREE_SIDE_EFFECTS (t)
&& type_dependent_expression_p (expr))
@@ -4795,69 +4954,149 @@ build_const_cast (tree type, tree expr)
return t;
}
- if (!POINTER_TYPE_P (type) && !TYPE_PTRMEM_P (type))
- error ("invalid use of const_cast with type %qT, which is not a pointer, "
- "reference, nor a pointer-to-data-member type", type);
- else if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
- {
- error ("invalid use of const_cast with type %qT, which is a pointer "
- "or reference to a function type", type);
+ return build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false,
+ /*valid_p=*/NULL);
+}
+
+/* Perform a const_cast from EXPR to TYPE. If the cast is valid,
+ return an appropriate expression. Otherwise, return
+ error_mark_node. If the cast is not valid, and COMPLAIN is true,
+ then a diagnostic will be issued. If VALID_P is non-NULL, its
+ value upon return will indicate whether or not the conversion
+ succeeded. */
+
+static tree
+build_const_cast_1 (tree dst_type, tree expr, bool complain,
+ bool *valid_p)
+{
+ tree src_type;
+ tree reference_type;
+
+ /* Callers are responsible for handling error_mark_node as a
+ destination type. */
+ gcc_assert (dst_type != error_mark_node);
+ /* In a template, callers should be building syntactic
+ representations of casts, not using this machinery. */
+ gcc_assert (!processing_template_decl);
+
+ /* Assume the conversion is invalid. */
+ if (valid_p)
+ *valid_p = false;
+
+ if (!POINTER_TYPE_P (dst_type) && !TYPE_PTRMEM_P (dst_type))
+ {
+ if (complain)
+ error ("invalid use of const_cast with type %qT, "
+ "which is not a pointer, "
+ "reference, nor a pointer-to-data-member type", dst_type);
return error_mark_node;
}
- if (TREE_CODE (type) != REFERENCE_TYPE)
+ if (TREE_CODE (TREE_TYPE (dst_type)) == FUNCTION_TYPE)
{
- expr = decay_conversion (expr);
-
- /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
- Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
- if (TREE_CODE (expr) == NOP_EXPR
- && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
- expr = TREE_OPERAND (expr, 0);
+ if (complain)
+ error ("invalid use of const_cast with type %qT, which is a pointer "
+ "or reference to a function type", dst_type);
+ return error_mark_node;
}
- intype = TREE_TYPE (expr);
-
- if (same_type_ignoring_top_level_qualifiers_p (intype, type))
- return build_static_cast (type, expr);
- else if (TREE_CODE (type) == REFERENCE_TYPE)
+ src_type = TREE_TYPE (expr);
+ /* Expressions do not really have reference types. */
+ if (TREE_CODE (src_type) == REFERENCE_TYPE)
+ src_type = TREE_TYPE (src_type);
+
+ /* [expr.const.cast]
+
+ An lvalue of type T1 can be explicitly converted to an lvalue of
+ type T2 using the cast const_cast<T2&> (where T1 and T2 are object
+ types) if a pointer to T1 can be explicitly converted to the type
+ pointer to T2 using a const_cast. */
+ if (TREE_CODE (dst_type) == REFERENCE_TYPE)
{
+ reference_type = dst_type;
if (! real_lvalue_p (expr))
{
- error ("invalid const_cast of an rvalue of type %qT to type %qT",
- intype, type);
+ if (complain)
+ error ("invalid const_cast of an rvalue of type %qT to type %qT",
+ src_type, dst_type);
return error_mark_node;
}
+ dst_type = build_pointer_type (TREE_TYPE (dst_type));
+ src_type = build_pointer_type (src_type);
+ }
+ else
+ {
+ reference_type = NULL_TREE;
+ /* If the destination type is not a reference type, the
+ lvalue-to-rvalue, array-to-pointer, and function-to-pointer
+ conversions are performed. */
+ src_type = type_decays_to (src_type);
+ if (src_type == error_mark_node)
+ return error_mark_node;
+ }
- if (comp_ptr_ttypes_const (TREE_TYPE (type), intype))
+ if ((TYPE_PTR_P (src_type) || TYPE_PTRMEM_P (src_type))
+ && comp_ptr_ttypes_const (dst_type, src_type))
+ {
+ if (valid_p)
+ *valid_p = true;
+ if (reference_type)
{
expr = build_unary_op (ADDR_EXPR, expr, 0);
- expr = build1 (NOP_EXPR, type, expr);
+ expr = build_nop (reference_type, expr);
return convert_from_reference (expr);
}
+ else
+ {
+ expr = decay_conversion (expr);
+ /* build_c_cast puts on a NOP_EXPR to make the result not an
+ lvalue. Strip such NOP_EXPRs if VALUE is being used in
+ non-lvalue context. */
+ if (TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
+ return build_nop (dst_type, expr);
+ }
}
- else if (((TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (intype) == POINTER_TYPE)
- || (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)))
- && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
- return cp_convert (type, expr);
- error ("invalid const_cast from type %qT to type %qT", intype, type);
+ if (complain)
+ error ("invalid const_cast from type %qT to type %qT",
+ src_type, dst_type);
return error_mark_node;
}
-/* Build an expression representing a cast to type TYPE of expression EXPR.
+tree
+build_const_cast (tree type, tree expr)
+{
+ if (type == error_mark_node || expr == error_mark_node)
+ return error_mark_node;
- ALLOW_NONCONVERTING is true if we should allow non-converting constructors
- when doing the cast. */
+ if (processing_template_decl)
+ {
+ tree t = build_min (CONST_CAST_EXPR, type, expr);
+
+ if (!TREE_SIDE_EFFECTS (t)
+ && type_dependent_expression_p (expr))
+ /* There might turn out to be side effects inside expr. */
+ TREE_SIDE_EFFECTS (t) = 1;
+ return t;
+ }
+
+ return build_const_cast_1 (type, expr, /*complain=*/true,
+ /*valid_p=*/NULL);
+}
+
+/* Build an expression representing an explicit C-style cast to type
+ TYPE of expression EXPR. */
tree
build_c_cast (tree type, tree expr)
{
tree value = expr;
- tree otype;
+ tree result;
+ bool valid_p;
- if (type == error_mark_node || expr == error_mark_node)
+ if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
if (processing_template_decl)
@@ -4906,118 +5145,48 @@ build_c_cast (tree type, tree expr)
return error_mark_node;
}
- if (TREE_CODE (type) == VOID_TYPE)
- {
- /* Conversion to void does not cause any of the normal function to
- * pointer, array to pointer and lvalue to rvalue decays. */
-
- value = convert_to_void (value, /*implicit=*/NULL);
- return value;
- }
-
- if (!complete_type_or_else (type, NULL_TREE))
- return error_mark_node;
-
- /* Convert functions and arrays to pointers and
- convert references to their expanded types,
- but don't convert any other types. If, however, we are
- casting to a class type, there's no reason to do this: the
- cast will only succeed if there is a converting constructor,
- and the default conversions will be done at that point. In
- fact, doing the default conversion here is actually harmful
- in cases like this:
-
- typedef int A[2];
- struct S { S(const A&); };
-
- since we don't want the array-to-pointer conversion done. */
- if (!IS_AGGR_TYPE (type))
- {
- if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
- || (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
- /* Don't do the default conversion on a ->* expression. */
- && ! (TREE_CODE (type) == POINTER_TYPE
- && bound_pmf_p (value)))
- || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
- value = decay_conversion (value);
- }
- else if (TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
- /* However, even for class types, we still need to strip away
- the reference type, since the call to convert_force below
- does not expect the input expression to be of reference
- type. */
- value = convert_from_reference (value);
-
- otype = TREE_TYPE (value);
-
- /* Optionally warn about potentially worrisome casts. */
-
- if (warn_cast_qual
- && TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (otype) == POINTER_TYPE
- && !at_least_as_qualified_p (TREE_TYPE (type),
- TREE_TYPE (otype)))
- warning ("cast from %qT to %qT discards qualifiers from pointer "
- "target type",
- otype, type);
-
- if (TREE_CODE (type) == INTEGER_TYPE
- && TYPE_PTR_P (otype)
- && TYPE_PRECISION (type) != TYPE_PRECISION (otype))
- warning ("cast from pointer to integer of different size");
-
- if (TYPE_PTR_P (type)
- && TREE_CODE (otype) == INTEGER_TYPE
- && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
- /* Don't warn about converting any constant. */
- && !TREE_CONSTANT (value))
- warning ("cast to pointer from integer of different size");
+ /* A C-style cast can be a const_cast. */
+ result = build_const_cast_1 (type, value, /*complain=*/false,
+ &valid_p);
+ if (valid_p)
+ return result;
- if (TREE_CODE (type) == REFERENCE_TYPE)
- value = (convert_from_reference
- (convert_to_reference (type, value, CONV_C_CAST,
- LOOKUP_COMPLAIN, NULL_TREE)));
- else
+ /* Or a static cast. */
+ result = build_static_cast_1 (type, value, /*c_cast_p=*/true,
+ &valid_p);
+ /* Or a reinterpret_cast. */
+ if (!valid_p)
+ result = build_reinterpret_cast_1 (type, value, /*c_cast_p=*/true,
+ &valid_p);
+ /* The static_cast or reinterpret_cast may be followed by a
+ const_cast. */
+ if (valid_p
+ /* A valid cast may result in errors if, for example, a
+ conversion to am ambiguous base class is required. */
+ && !error_operand_p (result))
{
- tree ovalue;
-
- value = decl_constant_value (value);
-
- ovalue = value;
- value = convert_force (type, value, CONV_C_CAST);
+ tree result_type;
- /* Ignore any integer overflow caused by the cast. */
- if (TREE_CODE (value) == INTEGER_CST)
+ /* Non-class rvalues always have cv-unqualified type. */
+ if (!CLASS_TYPE_P (type))
+ type = TYPE_MAIN_VARIANT (type);
+ result_type = TREE_TYPE (result);
+ if (!CLASS_TYPE_P (result_type))
+ result_type = TYPE_MAIN_VARIANT (result_type);
+ /* If the type of RESULT does not match TYPE, perform a
+ const_cast to make it match. If the static_cast or
+ reinterpret_cast succeeded, we will differ by at most
+ cv-qualification, so the follow-on const_cast is guaranteed
+ to succeed. */
+ if (!same_type_p (non_reference (type), non_reference (result_type)))
{
- TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
-
- if (CONSTANT_CLASS_P (ovalue))
- TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+ result = build_const_cast_1 (type, result, false, &valid_p);
+ gcc_assert (valid_p);
}
+ return result;
}
- /* Warn about possible alignment problems. Do this here when we will have
- instantiated any necessary template types. */
- if (STRICT_ALIGNMENT && warn_cast_align
- && TREE_CODE (type) == POINTER_TYPE
- && TREE_CODE (otype) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
- && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
- && COMPLETE_TYPE_P (TREE_TYPE (otype))
- && COMPLETE_TYPE_P (TREE_TYPE (type))
- && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
- warning ("cast from %qT to %qT increases required alignment of "
- "target type",
- otype, type);
-
- /* Always produce some operator for an explicit cast,
- so we can tell (for -pedantic) that the cast is no lvalue. */
- if (TREE_CODE (type) != REFERENCE_TYPE && value == expr
- && real_lvalue_p (value))
- value = non_lvalue (value);
-
- return value;
+ return error_mark_node;
}
/* Build an assignment expression of lvalue LHS from value RHS.
@@ -6260,7 +6429,7 @@ cp_has_mutable_p (tree type)
}
/* Subroutine of casts_away_constness. Make T1 and T2 point at
- exemplar types such that casting T1 to T2 is casting away castness
+ exemplar types such that casting T1 to T2 is casting away constness
if and only if there is no implicit conversion from T1 to T2. */
static void