This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: PR 10841 and 18073
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 21 Oct 2004 14:25:35 -0700
- Subject: C++ PATCH: PR 10841 and 18073
- Reply-to: mark at codesourcery dot com
My recent conversion fixes caused a regression in the processing of
conversions to VECTOR_TYPEs. These were previously permitted by
C-style casts, but not reinterpret_casts, which makes no sense. When
I made C-style casts depend on the reinterpret_cast machinery, I
failed to add support for VECTOR_TYPE.
Also this patch fixes a problem with pointer-to-member conversions.
Tested on i686-pc-linux-gnu, applied on the mainline. Updating
Bugzilla will have to wait until after I give a talk; I'm due right now.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
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 Mark Mitchell <mark@codesourcery.com>
PR c++/10841
* g++.dg/conversion/cast1.C: New test.
* g++.dg/overload/pmf1.C: Adjust error marker.
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.515
diff -c -5 -p -r1.515 call.c
*** cp/call.c 20 Oct 2004 13:16:41 -0000 1.515
--- cp/call.c 21 Oct 2004 21:20:01 -0000
*************** struct conversion {
*** 90,101 ****
BOOL_BITFIELD need_temporary_p : 1;
/* If KIND is ck_identity or ck_base_conv, true to indicate that the
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 {
/* The next conversion in the chain. Since the conversions are
--- 90,101 ----
BOOL_BITFIELD need_temporary_p : 1;
/* If KIND is ck_identity or ck_base_conv, true to indicate that the
copy constructor must be accessible, even though it is not being
used. */
BOOL_BITFIELD check_copy_constructor_p : 1;
! /* 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;
union {
/* The next conversion in the chain. Since the conversions are
*************** standard_conversion (tree to, tree from,
*** 777,786 ****
--- 777,787 ----
from = build_method_type_directly (from,
TREE_TYPE (fromfn),
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)
{
/* [conv.bool]
*************** convert_like_real (conversion *convs, tr
*** 4268,4279 ****
subobject of EXPR. */
if (convs->check_copy_constructor_p)
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 = build_indirect_ref (expr, "implicit conversion");
return expr;
}
/* Copy-initialization where the cv-unqualified version of the source
--- 4269,4280 ----
subobject of EXPR. */
if (convs->check_copy_constructor_p)
check_constructor_callable (TREE_TYPE (expr), expr);
/* Build an expression for `*((base*) &expr)'. */
expr = build_unary_op (ADDR_EXPR, expr, 0);
! expr = convert_to_base (expr, build_pointer_type (totype),
! !c_cast_p, /*nonnull=*/true);
expr = build_indirect_ref (expr, "implicit conversion");
return expr;
}
/* Copy-initialization where the cv-unqualified version of the source
*************** convert_like_real (conversion *convs, tr
*** 4336,4358 ****
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;
}
return ocp_convert (totype, expr, CONV_IMPLICIT,
LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
--- 4337,4354 ----
string_conv_p (totype, expr, 1);
break;
case ck_ptr:
if (convs->base_p)
! 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;
}
return ocp_convert (totype, expr, CONV_IMPLICIT,
LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.685
diff -c -5 -p -r1.685 class.c
*** cp/class.c 18 Oct 2004 17:21:26 -0000 1.685
--- cp/class.c 21 Oct 2004 21:20:01 -0000
*************** build_simple_base_path (tree expr, tree
*** 424,449 ****
/* Didn't find the base field?!? */
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. */
tree
! convert_to_base (tree object, tree type, bool check_access)
{
tree binfo;
! binfo = lookup_base (TREE_TYPE (object), 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);
}
/* EXPR is an expression with unqualified class type. BASE is a base
binfo of that class type. Returns EXPR, converted to the BASE
type. This function assumes that EXPR is the most derived class;
--- 424,461 ----
/* Didn't find the base field?!? */
gcc_unreachable ();
}
! /* 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, bool nonnull)
{
tree binfo;
+ tree 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);
}
/* EXPR is an expression with unqualified class type. BASE is a base
binfo of that class type. Returns EXPR, converted to the BASE
type. This function assumes that EXPR is the most derived class;
*************** build_vfield_ref (tree datum, tree type)
*** 483,493 ****
if (TREE_CODE (TREE_TYPE (datum)) == REFERENCE_TYPE)
datum = convert_from_reference (datum);
/* 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);
/* 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
convert_to_base here, because VCONTEXT may appear more than once
in the inheritance hierarchy of TYPE, and thus direct conversion
--- 495,506 ----
if (TREE_CODE (TREE_TYPE (datum)) == REFERENCE_TYPE)
datum = convert_from_reference (datum);
/* 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,
! /*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
convert_to_base here, because VCONTEXT may appear more than once
in the inheritance hierarchy of TYPE, and thus direct conversion
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1066
diff -c -5 -p -r1.1066 cp-tree.h
*** cp/cp-tree.h 20 Oct 2004 16:20:36 -0000 1.1066
--- cp/cp-tree.h 21 Oct 2004 21:20:01 -0000
*************** extern tree build_cxx_call (tree, tree);
*** 3592,3602 ****
extern void validate_conversion_obstack (void);
#endif /* ENABLE_CHECKING */
/* 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_statically (tree, tree);
extern tree build_vtbl_ref (tree, tree);
extern tree build_vfn_ref (tree, tree);
extern tree get_vtable_decl (tree, int);
extern void resort_type_method_vec
--- 3592,3602 ----
extern void validate_conversion_obstack (void);
#endif /* ENABLE_CHECKING */
/* in class.c */
extern tree build_base_path (enum tree_code, tree, tree, int);
! 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);
extern tree get_vtable_decl (tree, int);
extern void resort_type_method_vec
*************** extern tree build_x_modify_expr (tree,
*** 4265,4275 ****
extern tree build_modify_expr (tree, enum tree_code, tree);
extern tree dubious_conversion_warnings (tree, tree, const char *, tree, int);
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 int cp_type_quals (tree);
extern bool cp_has_mutable_p (tree);
extern bool at_least_as_qualified_p (tree, tree);
extern bool more_qualified_p (tree, tree);
extern tree build_ptrmemfunc1 (tree, tree, tree);
--- 4265,4275 ----
extern tree build_modify_expr (tree, enum tree_code, tree);
extern tree dubious_conversion_warnings (tree, tree, const char *, tree, int);
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, bool);
extern int cp_type_quals (tree);
extern bool cp_has_mutable_p (tree);
extern bool at_least_as_qualified_p (tree, tree);
extern bool more_qualified_p (tree, tree);
extern tree build_ptrmemfunc1 (tree, tree, tree);
*************** extern tree build_address
*** 4289,4298 ****
--- 4289,4299 ----
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);
+ extern tree convert_ptrmem (tree, tree, bool, bool);
/* in typeck2.c */
extern void require_complete_eh_spec_types (tree, tree);
extern void cxx_incomplete_type_diagnostic (tree, tree, int);
#undef cxx_incomplete_type_error
Index: cp/cvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cvt.c,v
retrieving revision 1.169
diff -c -5 -p -r1.169 cvt.c
*** cp/cvt.c 19 Oct 2004 23:24:18 -0000 1.169
--- cp/cvt.c 21 Oct 2004 21:20:01 -0000
*************** cp_convert_to_pointer (tree type, tree e
*** 215,225 ****
build_nop (sizetype, expr),
BINFO_OFFSET (binfo));
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);
else if (TYPE_PTRMEMFUNC_P (intype))
{
if (!warn_pmf2ptr)
{
if (TREE_CODE (expr) == PTRMEM_CST)
--- 215,226 ----
build_nop (sizetype, expr),
BINFO_OFFSET (binfo));
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,
! /*c_cast_p=*/false);
else if (TYPE_PTRMEMFUNC_P (intype))
{
if (!warn_pmf2ptr)
{
if (TREE_CODE (expr) == PTRMEM_CST)
*************** cp_convert_to_pointer (tree type, tree e
*** 239,249 ****
}
if (integer_zerop (expr))
{
if (TYPE_PTRMEMFUNC_P (type))
! return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0);
if (TYPE_PTRMEM_P (type))
{
/* A NULL pointer-to-member is represented by -1, not by
zero. */
--- 240,251 ----
}
if (integer_zerop (expr))
{
if (TYPE_PTRMEMFUNC_P (type))
! return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
! /*c_cast_p=*/false);
if (TYPE_PTRMEM_P (type))
{
/* A NULL pointer-to-member is represented by -1, not by
zero. */
*************** convert_force (tree type, tree expr, int
*** 958,971 ****
&& TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (TREE_TYPE (e))) == METHOD_TYPE)
|| 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);
! }
return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
}
/* Convert an aggregate EXPR to type XTYPE. If a conversion
--- 960,972 ----
&& TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (TREE_TYPE (e))) == METHOD_TYPE)
|| 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,
! /*c_cast_p=*/1);
return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
}
/* Convert an aggregate EXPR to type XTYPE. If a conversion
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.587
diff -c -5 -p -r1.587 typeck.c
*** cp/typeck.c 21 Oct 2004 12:59:00 -0000 1.587
--- cp/typeck.c 21 Oct 2004 21:20:01 -0000
*************** static int comp_ptr_ttypes_real (tree, t
*** 50,60 ****
static int comp_ptr_ttypes_const (tree, tree);
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 void casts_away_constness_r (tree *, tree *);
static bool casts_away_constness (tree, tree);
static void maybe_warn_about_returning_address_of_local (tree);
static tree lookup_destructor (tree, tree, tree);
--- 50,60 ----
static int comp_ptr_ttypes_const (tree, tree);
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, 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);
static tree lookup_destructor (tree, tree, tree);
*************** build_unary_op (enum tree_code code, tre
*** 4144,4154 ****
if (TREE_CODE (argtype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
{
build_ptrmemfunc_type (argtype);
! addr = build_ptrmemfunc (argtype, addr, 0);
}
return addr;
}
--- 4144,4155 ----
if (TREE_CODE (argtype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
{
build_ptrmemfunc_type (argtype);
! addr = build_ptrmemfunc (argtype, addr, 0,
! /*c_cast_p=*/false);
}
return addr;
}
*************** check_for_casting_away_constness (tree s
*** 4483,4492 ****
--- 4484,4525 ----
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);
}
+ /* 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
classes is not considered, and it is OK to cast away
constness.) Return the result of the cast. *VALID_P is set to
*************** build_static_cast_1 (tree type, tree exp
*** 4689,4715 ****
t2 = type;
}
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);
}
}
/* [expr.static.cast]
--- 4722,4735 ----
t2 = type;
}
if (can_convert (t1, t2))
{
if (!c_cast_p)
! check_for_casting_away_constness (intype, type, diag_fn,
! desc);
! return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
! c_cast_p);
}
}
/* [expr.static.cast]
*************** build_reinterpret_cast_1 (tree type, tre
*** 4943,4952 ****
--- 4963,4974 ----
}
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)
*valid_p = false;
error ("invalid cast from type %qT to type %qT", intype, type);
*************** build_x_modify_expr (tree lhs, enum tree
*** 5544,5584 ****
}
/* 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.
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
this way because we call this function to find out how to convert from
a pointer to member of FROM to a pointer to member of TO. */
static tree
! get_delta_difference (tree from, tree to, int force)
{
tree binfo;
tree virt_binfo;
base_kind kind;
tree result;
/* Assume no conversion is required. */
result = integer_zero_node;
! binfo = lookup_base (to, from, ba_check, &kind);
if (kind == bk_inaccessible || kind == bk_ambig)
error (" in pointer to member function conversion");
else if (!binfo)
{
! if (!force)
{
error_not_base_type (from, to);
error (" in pointer to member conversion");
}
else
{
! binfo = lookup_base (from, to, ba_check, &kind);
if (binfo)
{
virt_binfo = binfo_from_vbase (binfo);
if (virt_binfo)
/* This is a reinterpret cast, we choose to do nothing. */
--- 5566,5611 ----
}
/* 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
! 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
this way because we call this function to find out how to convert from
a pointer to member of FROM to a pointer to member of TO. */
static tree
! get_delta_difference (tree from, tree to,
! bool allow_inverse_p,
! bool c_cast_p)
{
tree binfo;
tree virt_binfo;
base_kind kind;
tree result;
/* Assume no conversion is required. */
result = integer_zero_node;
! 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 (!allow_inverse_p)
{
error_not_base_type (from, to);
error (" in pointer to member conversion");
}
else
{
! binfo = lookup_base (from, to, c_cast_p ? ba_unique : ba_check,
! &kind);
if (binfo)
{
virt_binfo = binfo_from_vbase (binfo);
if (virt_binfo)
/* This is a reinterpret cast, we choose to do nothing. */
*************** get_delta_difference (tree from, tree to
*** 5595,5605 ****
if (!virt_binfo)
result = BINFO_OFFSET (binfo);
else
{
/* This is a reinterpret cast, we choose to do nothing. */
! if (force)
warning ("pointer to member cast via virtual base %qT",
BINFO_TYPE (virt_binfo));
else
error ("pointer to member conversion via virtual base %qT",
BINFO_TYPE (virt_binfo));
--- 5622,5632 ----
if (!virt_binfo)
result = BINFO_OFFSET (binfo);
else
{
/* This is a reinterpret cast, we choose to do nothing. */
! if (allow_inverse_p)
warning ("pointer to member cast via virtual base %qT",
BINFO_TYPE (virt_binfo));
else
error ("pointer to member conversion via virtual base %qT",
BINFO_TYPE (virt_binfo));
*************** build_ptrmemfunc1 (tree type, tree delta
*** 5646,5661 ****
as a value in expressions. TYPE is the POINTER to METHOD_TYPE we
want to be.
If FORCE is nonzero, then force this conversion, even if
we would rather not do it. Usually set when using an explicit
! cast.
Return error_mark_node, if something goes wrong. */
tree
! build_ptrmemfunc (tree type, tree pfn, int force)
{
tree fn;
tree pfn_type;
tree to_type;
--- 5673,5688 ----
as a value in expressions. TYPE is the POINTER to METHOD_TYPE we
want to be.
If FORCE is nonzero, then force this conversion, even if
we would rather not do it. Usually set when using an explicit
! 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, bool c_cast_p)
{
tree fn;
tree pfn_type;
tree to_type;
*************** build_ptrmemfunc (tree type, tree pfn, i
*** 5677,5687 ****
error ("invalid conversion to type %qT from type %qT",
to_type, pfn_type);
n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
! force);
/* We don't have to do any conversion to convert a
pointer-to-member to its own type. But, we don't want to
just return a PTRMEM_CST if there's an explicit cast; that
cast should make the expression an invalid template argument. */
--- 5704,5715 ----
error ("invalid conversion to type %qT from type %qT",
to_type, pfn_type);
n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
! 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
just return a PTRMEM_CST if there's an explicit cast; that
cast should make the expression an invalid template argument. */
*************** expand_ptrmemfunc_cst (tree cst, tree *d
*** 5752,5762 ****
/* The class that we're creating a pointer to member of. */
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);
if (!DECL_VIRTUAL_P (fn))
*pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
else
{
--- 5780,5791 ----
/* The class that we're creating a pointer to member of. */
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,
! /*c_cast_p=*/0);
if (!DECL_VIRTUAL_P (fn))
*pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
else
{
Index: testsuite/g++.dg/conversion/cast1.C
===================================================================
RCS file: testsuite/g++.dg/conversion/cast1.C
diff -N testsuite/g++.dg/conversion/cast1.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/conversion/cast1.C 21 Oct 2004 21:20:20 -0000
***************
*** 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;
+ }
+
Index: testsuite/g++.dg/overload/pmf1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/overload/pmf1.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 pmf1.C
*** testsuite/g++.dg/overload/pmf1.C 10 Oct 2004 21:36:41 -0000 1.2
--- testsuite/g++.dg/overload/pmf1.C 21 Oct 2004 21:20:20 -0000
*************** int A::*aip = &A::i;
*** 15,21 ****
void f (int B::*) {} // should choose this, even though it's ill-formed
void f (C) {} // even though this would be well-formed
int main ()
{
! f (aip); // { dg-error "'A' is an inaccessible base of 'B'" "" }
}
--- 15,21 ----
void f (int B::*) {} // should choose this, even though it's ill-formed
void f (C) {} // even though this would be well-formed
int main ()
{
! f (aip); // { dg-error "'A' is an inaccessible base of 'B'|conversion" "" }
}