summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog25
-rw-r--r--gcc/cp/call.c26
-rw-r--r--gcc/cp/class.c27
-rw-r--r--gcc/cp/cp-tree.h5
-rw-r--r--gcc/cp/cvt.c13
-rw-r--r--gcc/cp/typeck.c89
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/conversion/cast1.C22
-rw-r--r--gcc/testsuite/g++.dg/overload/pmf1.C2
9 files changed, 154 insertions, 61 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3adc303036d..2c78f23b265 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,28 @@
+2004-10-21 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/18073
+ PR c++/10841
+ * cp-tree.h (convert_to_base): Change prototype.
+ (build_ptrmemfunc): Likewise.
+ (convert_ptrmem): New function.
+ * call.c (struct conversion): Adjust documentation for base_p.
+ (standard_conversion): Set base_p for ck_pmem conversions as
+ appropriate.
+ (convert_like_real): Use convert_to_base for ck_pmem and ck_ptr
+ conversions.
+ * class.c (convert_to_base): Handle both pointers and objects.
+ Add nonnull parameter.
+ (build_vfield_ref): Adjust call to convert_to_base.
+ * cvt.c (cp_convert_to_pointer): Adjust call to build_ptrmemfunc.
+ (convert_force): Likewise.
+ * typeck.c (build_unary_op): Likewise.
+ (convert_ptrmem): New function.
+ (build_static_cast_1): Use it.
+ (build_reinterpret_cast): Allow conversions to vector types.
+ (get_delta_difference): Add c_cast_p parameter.
+ (build_ptrmemfunc): Likewise. Adjust calls to
+ get_delta_difference.
+
2004-10-21 Andrew Pinski <pinskia@physics.uc.edu>
PR c++/13560
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 46b270e3ff3..aedc9278b9d 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -92,8 +92,8 @@ 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. */
+ /* If KIND is ck_ptr or ck_pmem, 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;
@@ -779,6 +779,7 @@ standard_conversion (tree to, tree from, tree expr)
TREE_CHAIN (TYPE_ARG_TYPES (fromfn)));
from = build_ptrmemfunc_type (build_pointer_type (from));
conv = build_conv (ck_pmem, from, conv);
+ conv->base_p = true;
}
else if (tcode == BOOLEAN_TYPE)
{
@@ -4270,8 +4271,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
check_constructor_callable (TREE_TYPE (expr), expr);
/* Build an expression for `*((base*) &expr)'. */
expr = build_unary_op (ADDR_EXPR, expr, 0);
- expr = perform_implicit_conversion (build_pointer_type (totype),
- expr);
+ expr = convert_to_base (expr, build_pointer_type (totype),
+ !c_cast_p, /*nonnull=*/true);
expr = build_indirect_ref (expr, "implicit conversion");
return expr;
}
@@ -4338,19 +4339,14 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
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);
- }
+ expr = convert_to_base (expr, totype, !c_cast_p,
+ /*nonnull=*/false);
return build_nop (totype, expr);
+ case ck_pmem:
+ return convert_ptrmem (totype, expr, /*allow_inverse_p=*/false,
+ c_cast_p);
+
default:
break;
}
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index a0a2ed48bce..15ca26ad460 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -426,22 +426,34 @@ build_simple_base_path (tree expr, tree binfo)
gcc_unreachable ();
}
-/* Convert OBJECT to the base TYPE. If CHECK_ACCESS is true, an error
- message is emitted if TYPE is inaccessible. OBJECT is assumed to
- be non-NULL. */
+/* Convert OBJECT to the base TYPE. OBJECT is an expression whose
+ type is a class type or a pointer to a class type. In the former
+ case, TYPE is also a class type; in the latter it is another
+ pointer type. If CHECK_ACCESS is true, an error message is emitted
+ if TYPE is inaccessible. If OBJECT has pointer type, the value is
+ assumed to be non-NULL. */
tree
-convert_to_base (tree object, tree type, bool check_access)
+convert_to_base (tree object, tree type, bool check_access, bool nonnull)
{
tree binfo;
+ tree object_type;
- binfo = lookup_base (TREE_TYPE (object), type,
+ if (TYPE_PTR_P (TREE_TYPE (object)))
+ {
+ object_type = TREE_TYPE (TREE_TYPE (object));
+ type = TREE_TYPE (type);
+ }
+ else
+ object_type = TREE_TYPE (object);
+
+ binfo = lookup_base (object_type, type,
check_access ? ba_check : ba_unique,
NULL);
if (!binfo || binfo == error_mark_node)
return error_mark_node;
- return build_base_path (PLUS_EXPR, object, binfo, /*nonnull=*/1);
+ return build_base_path (PLUS_EXPR, object, binfo, nonnull);
}
/* EXPR is an expression with unqualified class type. BASE is a base
@@ -485,7 +497,8 @@ build_vfield_ref (tree datum, tree type)
/* First, convert to the requested type. */
if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (datum), type))
- datum = convert_to_base (datum, type, /*check_access=*/false);
+ datum = convert_to_base (datum, type, /*check_access=*/false,
+ /*nonnull=*/true);
/* Second, the requested type may not be the owner of its own vptr.
If not, convert to the base class that owns it. We cannot use
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0f75fce3812..580a73b4db8 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3594,7 +3594,7 @@ extern void validate_conversion_obstack (void);
/* in class.c */
extern tree build_base_path (enum tree_code, tree, tree, int);
-extern tree convert_to_base (tree, tree, bool);
+extern tree convert_to_base (tree, tree, bool, bool);
extern tree convert_to_base_statically (tree, tree);
extern tree build_vtbl_ref (tree, tree);
extern tree build_vfn_ref (tree, tree);
@@ -4267,7 +4267,7 @@ extern tree dubious_conversion_warnings (tree, tree, const char *, tree,
extern tree convert_for_initialization (tree, tree, tree, int, const char *, tree, int);
extern int comp_ptr_ttypes (tree, tree);
extern int ptr_reasonably_similar (tree, tree);
-extern tree build_ptrmemfunc (tree, tree, int);
+extern tree build_ptrmemfunc (tree, tree, int, bool);
extern int cp_type_quals (tree);
extern bool cp_has_mutable_p (tree);
extern bool at_least_as_qualified_p (tree, tree);
@@ -4291,6 +4291,7 @@ 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);
+extern tree convert_ptrmem (tree, tree, bool, bool);
/* 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 02230301117..7f0f64c9c46 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -217,7 +217,8 @@ cp_convert_to_pointer (tree type, tree expr, bool force)
return build_nop (type, expr);
}
else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype))
- return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
+ return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
+ /*c_cast_p=*/false);
else if (TYPE_PTRMEMFUNC_P (intype))
{
if (!warn_pmf2ptr)
@@ -241,7 +242,8 @@ cp_convert_to_pointer (tree type, tree expr, bool force)
if (integer_zerop (expr))
{
if (TYPE_PTRMEMFUNC_P (type))
- return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
+ return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
+ /*c_cast_p=*/false);
if (TYPE_PTRMEM_P (type))
{
@@ -960,10 +962,9 @@ convert_force (tree type, tree expr, int convtype)
|| integer_zerop (e)
|| TYPE_PTRMEMFUNC_P (TREE_TYPE (e)))
&& TYPE_PTRMEMFUNC_P (type))
- {
- /* compatible pointer to member functions. */
- return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1);
- }
+ /* compatible pointer to member functions. */
+ return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1,
+ /*c_cast_p=*/1);
return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
}
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 0f6f65b4188..cc91b653aae 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -52,7 +52,7 @@ static bool comp_except_types (tree, tree, bool);
static bool comp_array_types (tree, tree, bool);
static tree common_base_type (tree, tree);
static tree pointer_diff (tree, tree, tree);
-static tree get_delta_difference (tree, tree, int);
+static tree get_delta_difference (tree, tree, bool, bool);
static void casts_away_constness_r (tree *, tree *);
static bool casts_away_constness (tree, tree);
static void maybe_warn_about_returning_address_of_local (tree);
@@ -4146,7 +4146,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
&& TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
{
build_ptrmemfunc_type (argtype);
- addr = build_ptrmemfunc (argtype, addr, 0);
+ addr = build_ptrmemfunc (argtype, addr, 0,
+ /*c_cast_p=*/false);
}
return addr;
@@ -4485,6 +4486,38 @@ check_for_casting_away_constness (tree src_type, tree dest_type,
description, src_type, dest_type);
}
+/* Convert EXPR (an expression with pointer-to-member type) to TYPE
+ (another pointer-to-member type in the same hierarchy) and return
+ the converted expression. If ALLOW_INVERSE_P is permitted, a
+ pointer-to-derived may be converted to pointer-to-base; otherwise,
+ only the other direction is permitted. If C_CAST_P is true, this
+ conversion is taking place as part of a C-style cast. */
+
+tree
+convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
+ bool c_cast_p)
+{
+ if (TYPE_PTRMEM_P (type))
+ {
+ tree delta;
+
+ if (TREE_CODE (expr) == PTRMEM_CST)
+ expr = cplus_expand_constant (expr);
+ delta = get_delta_difference (TYPE_PTRMEM_CLASS_TYPE (TREE_TYPE (expr)),
+ TYPE_PTRMEM_CLASS_TYPE (type),
+ allow_inverse_p,
+ c_cast_p);
+ if (!integer_zerop (delta))
+ expr = cp_build_binary_op (PLUS_EXPR,
+ build_nop (ptrdiff_type_node, expr),
+ delta);
+ return build_nop (type, expr);
+ }
+ else
+ return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr,
+ allow_inverse_p, c_cast_p);
+}
+
/* 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
@@ -4691,23 +4724,10 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
if (can_convert (t1, t2))
{
if (!c_cast_p)
- check_for_casting_away_constness (intype, type, diag_fn, desc);
- if (TYPE_PTRMEM_P (type))
- {
- tree delta;
-
- if (TREE_CODE (expr) == PTRMEM_CST)
- expr = cplus_expand_constant (expr);
- delta = get_delta_difference (c1, c2, /*force=*/1);
- if (!integer_zerop (delta))
- expr = cp_build_binary_op (PLUS_EXPR,
- build_nop (ptrdiff_type_node, expr),
- delta);
- return build_nop (type, expr);
- }
- else
- return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr,
- /*force=*/1);
+ check_for_casting_away_constness (intype, type, diag_fn,
+ desc);
+ return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
+ c_cast_p);
}
}
@@ -4945,6 +4965,8 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
expr = decl_constant_value (expr);
return fold_if_not_in_template (build_nop (type, expr));
}
+ else if (TREE_CODE (type) == VECTOR_TYPE)
+ return fold_if_not_in_template (convert_to_vector (type, expr));
else
{
if (valid_p)
@@ -5546,8 +5568,10 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
/* Get difference in deltas for different pointer to member function
types. Returns an integer constant of type PTRDIFF_TYPE_NODE. If
- the conversion is invalid, the constant is zero. If FORCE is true,
- then allow reverse conversions as well.
+ the conversion is invalid, the constant is zero. If
+ ALLOW_INVERSE_P is true, then allow reverse conversions as well.
+ If C_CAST_P is true this conversion is taking place as part of a
+ C-style cast.
Note that the naming of FROM and TO is kind of backwards; the return
value is what we add to a TO in order to get a FROM. They are named
@@ -5555,7 +5579,9 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
a pointer to member of FROM to a pointer to member of TO. */
static tree
-get_delta_difference (tree from, tree to, int force)
+get_delta_difference (tree from, tree to,
+ bool allow_inverse_p,
+ bool c_cast_p)
{
tree binfo;
tree virt_binfo;
@@ -5564,19 +5590,20 @@ get_delta_difference (tree from, tree to, int force)
/* Assume no conversion is required. */
result = integer_zero_node;
- binfo = lookup_base (to, from, ba_check, &kind);
+ binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
if (kind == bk_inaccessible || kind == bk_ambig)
error (" in pointer to member function conversion");
else if (!binfo)
{
- if (!force)
+ if (!allow_inverse_p)
{
error_not_base_type (from, to);
error (" in pointer to member conversion");
}
else
{
- binfo = lookup_base (from, to, ba_check, &kind);
+ binfo = lookup_base (from, to, c_cast_p ? ba_unique : ba_check,
+ &kind);
if (binfo)
{
virt_binfo = binfo_from_vbase (binfo);
@@ -5597,7 +5624,7 @@ get_delta_difference (tree from, tree to, int force)
else
{
/* This is a reinterpret cast, we choose to do nothing. */
- if (force)
+ if (allow_inverse_p)
warning ("pointer to member cast via virtual base %qT",
BINFO_TYPE (virt_binfo));
else
@@ -5648,12 +5675,12 @@ build_ptrmemfunc1 (tree type, tree delta, tree pfn)
If FORCE is nonzero, then force this conversion, even if
we would rather not do it. Usually set when using an explicit
- cast.
+ cast. A C-style cast is being processed iff C_CAST_P is true.
Return error_mark_node, if something goes wrong. */
tree
-build_ptrmemfunc (tree type, tree pfn, int force)
+build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
{
tree fn;
tree pfn_type;
@@ -5679,7 +5706,8 @@ build_ptrmemfunc (tree type, tree pfn, int force)
n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
- force);
+ force,
+ c_cast_p);
/* We don't have to do any conversion to convert a
pointer-to-member to its own type. But, we don't want to
@@ -5754,7 +5782,8 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
/* First, calculate the adjustment to the function's class. */
- *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0);
+ *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0,
+ /*c_cast_p=*/0);
if (!DECL_VIRTUAL_P (fn))
*pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b7f25ddf4dd..ae6231295cb 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2004-10-21 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/10841
+ * g++.dg/conversion/cast1.C: New test.
+ * g++.dg/overload/pmf1.C: Adjust error marker.
+
2004-10-21 Andrew Pinski <pinskia@physics.uc.edu>
PR objc/17923
diff --git a/gcc/testsuite/g++.dg/conversion/cast1.C b/gcc/testsuite/g++.dg/conversion/cast1.C
new file mode 100644
index 00000000000..f90b42165a8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/cast1.C
@@ -0,0 +1,22 @@
+// PR c++/10841
+
+int main() {
+ class Base {
+ public:
+ int i, j, k;
+ void f(); };
+
+ class Derived : private Base {
+ public:
+ int m, n, p;
+ void g();
+ };
+
+ Derived derived;
+ Base &base = (Base &)derived;
+ (int Base::*)&Derived::n;
+ (int Derived::*)&Base::j;
+ (void (Base::*)(void))&Derived::g;
+ (void (Derived::*)(void))&Base::f;
+}
+
diff --git a/gcc/testsuite/g++.dg/overload/pmf1.C b/gcc/testsuite/g++.dg/overload/pmf1.C
index b97f64e764b..d2007493179 100644
--- a/gcc/testsuite/g++.dg/overload/pmf1.C
+++ b/gcc/testsuite/g++.dg/overload/pmf1.C
@@ -17,5 +17,5 @@ void f (C) {} // even though this would be well-formed
int main ()
{
- f (aip); // { dg-error "'A' is an inaccessible base of 'B'" "" }
+ f (aip); // { dg-error "'A' is an inaccessible base of 'B'|conversion" "" }
}