Commit 6e03b280 by Ollie Wild Committed by Ollie Wild

cvt.c (cp_convert_to_pointer): Remove force parameter.

	gcc/cp/
	* cvt.c (cp_convert_to_pointer): Remove force parameter. Call
	convert_ptrmem for pointer to member conversions.
	(convert_to_pointer_force): Update cp_convert_to_pointer call.
	(ocp_convert): Update cp_convert_to_pointer call.
	* typeck.c (convert_ptrmem): Add conditional for null pointers to
	members.
	(build_static_cast_1): Check can_convert for conversions in either
	direction.
	(get_delta_difference_1): New function.
	(get_delta_difference): Refactor to call get_delta_difference_1.

	gcc/testsuite/
	g++.dg/conversion/ptrmem2.C: New test.
	g++.dg/conversion/ptrmem3.C: New test.
	g++.dg/conversion/ptrmem4.C: New test.
	g++.dg/conversion/ptrmem5.C: New test.
	g++.dg/conversion/ptrmem6.C: New test.
	g++.dg/conversion/ptrmem7.C: New test.
	g++.dg/conversion/ptrmem8.C: New test.

From-SVN: r127953
parent 2710d6d7
2007-08-30 Ollie Wild <aaw@google.com>
* cvt.c (cp_convert_to_pointer): Remove force parameter. Call
convert_ptrmem for pointer to member conversions.
(convert_to_pointer_force): Update cp_convert_to_pointer call.
(ocp_convert): Update cp_convert_to_pointer call.
* typeck.c (convert_ptrmem): Add conditional for null pointers to
members.
(build_static_cast_1): Check can_convert for conversions in either
direction.
(get_delta_difference_1): New function.
(get_delta_difference): Refactor to call get_delta_difference_1.
2007-08-28 Paolo Carlini <pcarlini@suse.de>
PR c++/33209
......
......@@ -38,7 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "decl.h"
#include "target.h"
static tree cp_convert_to_pointer (tree, tree, bool);
static tree cp_convert_to_pointer (tree, tree);
static tree convert_to_pointer_force (tree, tree);
static tree build_type_conversion (tree, tree);
static tree build_up_reference (tree, tree, int, tree);
......@@ -71,12 +71,10 @@ static void warn_ref_binding (tree, tree, tree);
else if dealing with method pointers, delegate
else convert blindly
else if converting class, pass off to build_type_conversion
else try C-style pointer conversion. If FORCE is true then allow
conversions via virtual bases (these are permitted by reinterpret_cast,
but not static_cast). */
else try C-style pointer conversion. */
static tree
cp_convert_to_pointer (tree type, tree expr, bool force)
cp_convert_to_pointer (tree type, tree expr)
{
tree intype = TREE_TYPE (expr);
enum tree_code form;
......@@ -174,61 +172,17 @@ cp_convert_to_pointer (tree type, tree expr, bool force)
return build_nop (type, expr);
}
else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
{
tree b1;
tree b2;
tree binfo;
enum tree_code code = PLUS_EXPR;
base_kind bk;
b1 = TYPE_PTRMEM_CLASS_TYPE (type);
b2 = TYPE_PTRMEM_CLASS_TYPE (intype);
binfo = lookup_base (b1, b2, ba_check, &bk);
if (!binfo)
{
binfo = lookup_base (b2, b1, ba_check, &bk);
code = MINUS_EXPR;
}
if (binfo == error_mark_node)
return error_mark_node;
if (bk == bk_via_virtual)
{
if (force)
warning (0, "pointer to member cast from %qT to %qT is via"
" virtual base", intype, type);
else
{
error ("pointer to member cast from %qT to %qT is"
" via virtual base", intype, type);
return error_mark_node;
}
/* This is a reinterpret cast, whose result is unspecified.
We choose to do nothing. */
return build1 (NOP_EXPR, type, expr);
}
if (TREE_CODE (expr) == PTRMEM_CST)
expr = cplus_expand_constant (expr);
if (binfo && !integer_zerop (BINFO_OFFSET (binfo)))
expr = size_binop (code,
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_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
return convert_ptrmem (type, expr, /*allow_inverse_p=*/false,
/*c_cast_p=*/false);
else if (TYPE_PTRMEMFUNC_P (intype))
{
if (!warn_pmf2ptr)
{
if (TREE_CODE (expr) == PTRMEM_CST)
return cp_convert_to_pointer (type,
PTRMEM_CST_MEMBER (expr),
force);
PTRMEM_CST_MEMBER (expr));
else if (TREE_CODE (expr) == OFFSET_REF)
{
tree object = TREE_OPERAND (expr, 0);
......@@ -333,7 +287,7 @@ convert_to_pointer_force (tree type, tree expr)
}
}
return cp_convert_to_pointer (type, expr, true);
return cp_convert_to_pointer (type, expr);
}
/* We are passing something to a function which requires a reference.
......@@ -720,7 +674,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
return fold_if_not_in_template (convert_to_integer (type, e));
}
if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type))
return fold_if_not_in_template (cp_convert_to_pointer (type, e, false));
return fold_if_not_in_template (cp_convert_to_pointer (type, e));
if (code == VECTOR_TYPE)
{
tree in_vtype = TREE_TYPE (e);
......
......@@ -4868,9 +4868,19 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
allow_inverse_p,
c_cast_p);
if (!integer_zerop (delta))
expr = cp_build_binary_op (PLUS_EXPR,
build_nop (ptrdiff_type_node, expr),
delta);
{
tree cond, op1, op2;
cond = cp_build_binary_op (EQ_EXPR,
expr,
build_int_cst (TREE_TYPE (expr), -1));
op1 = build_nop (ptrdiff_type_node, expr);
op2 = cp_build_binary_op (PLUS_EXPR, op1, delta);
expr = fold_build3 (COND_EXPR, ptrdiff_type_node, cond, op1, op2);
}
return build_nop (type, expr);
}
else
......@@ -5101,7 +5111,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
t1 = intype;
t2 = type;
}
if (can_convert (t1, t2))
if (can_convert (t1, t2) || can_convert (t2, t1))
{
if (!c_cast_p)
check_for_casting_away_constness (intype, type, diag_fn,
......@@ -5967,7 +5977,43 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
return build_modify_expr (lhs, modifycode, rhs);
}
/* Helper function for get_delta_difference which assumes FROM is a base
class of TO. Returns a delta for the conversion of pointer-to-member
of FROM to pointer-to-member of TO. If the conversion is invalid,
returns zero. If FROM is not a base class of TO, returns NULL_TREE.
If C_CAST_P is true, this conversion is taking place as part of a C-style
cast. */
static tree
get_delta_difference_1 (tree from, tree to, bool c_cast_p)
{
tree binfo;
base_kind 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");
return size_zero_node;
}
else if (binfo)
{
if (kind != bk_via_virtual)
return BINFO_OFFSET (binfo);
else
/* FROM is a virtual base class of TO. Issue an error or warning
depending on whether or not this is a reinterpret cast. */
{
error ("pointer to member conversion via virtual base %qT",
BINFO_TYPE (binfo_from_vbase (binfo)));
return size_zero_node;
}
}
else
return NULL_TREE;
}
/* 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
......@@ -5985,56 +6031,36 @@ get_delta_difference (tree from, tree to,
bool allow_inverse_p,
bool c_cast_p)
{
tree 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 (kind != bk_via_virtual)
result = BINFO_OFFSET (binfo);
else
{
tree virt_binfo = binfo_from_vbase (binfo);
/* This is a reinterpret cast, we choose to do nothing. */
if (allow_inverse_p)
warning (0, "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));
}
}
else if (same_type_ignoring_top_level_qualifiers_p (from, to))
/* Pointer to member of incomplete class is permitted*/;
else if (!allow_inverse_p)
{
error_not_base_type (from, to);
error (" in pointer to member conversion");
}
if (same_type_ignoring_top_level_qualifiers_p (from, to))
/* Pointer to member of incomplete class is permitted*/
result = size_zero_node;
else
{
binfo = lookup_base (from, to, c_cast_p ? ba_unique : ba_check, &kind);
if (binfo)
{
if (kind != bk_via_virtual)
result = size_diffop (size_zero_node, BINFO_OFFSET (binfo));
else
{
/* This is a reinterpret cast, we choose to do nothing. */
tree virt_binfo = binfo_from_vbase (binfo);
result = get_delta_difference_1 (from, to, c_cast_p);
warning (0, "pointer to member cast via virtual base %qT",
BINFO_TYPE (virt_binfo));
}
}
}
if (!result)
{
if (!allow_inverse_p)
{
error_not_base_type (from, to);
error (" in pointer to member conversion");
result = size_zero_node;
}
else
{
result = get_delta_difference_1 (to, from, c_cast_p);
if (result)
result = size_diffop (size_zero_node, result);
else
{
error_not_base_type (from, to);
error (" in pointer to member conversion");
result = size_zero_node;
}
}
}
return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node,
result));
......
2007-08-30 Ollie Wild <aaw@google.com>
g++.dg/conversion/ptrmem2.C: New test.
g++.dg/conversion/ptrmem3.C: New test.
g++.dg/conversion/ptrmem4.C: New test.
g++.dg/conversion/ptrmem5.C: New test.
g++.dg/conversion/ptrmem6.C: New test.
g++.dg/conversion/ptrmem7.C: New test.
g++.dg/conversion/ptrmem8.C: New test.
2007-08-31 Paul Thomas <pault@gcc.gnu.org>
PR fortran/31879
// Copyright (C) 2007 Free Software Foundation
// Contributed by Ollie Wild <aaw@google.com>
// { dg-do compile }
// Assorted pointer to data member static cast tests.
struct A { int x; };
struct B : A { int x; };
struct P : A { int x; };
struct V { int x; };
struct D : B, virtual V, private P { int x; };
// Valid static casts.
int B::*p1 = static_cast<int B::*>(&D::x);
int D::*p2 = static_cast<int D::*>(&B::x);
// Virtual base class.
int V::*p3 = static_cast<int V::*>(&D::x); // { dg-error "" }
int D::*p4 = static_cast<int D::*>(&V::x); // { dg-error "" }
// Inaccessible base class.
int P::*p5 = static_cast<int P::*>(&D::x); // { dg-error "" }
int D::*p6 = static_cast<int D::*>(&P::x); // { dg-error "" }
// Ambiguous base class.
int A::*p7 = static_cast<int A::*>(&D::x); // { dg-error "" }
int D::*p8 = static_cast<int D::*>(&A::x); // { dg-error "" }
// Valid conversions which increase cv-qualification.
const int B::*p9 = static_cast<const int B::*>(&D::x);
const int D::*p10 = static_cast<const int D::*>(&B::x);
// Invalid conversions which decrease cv-qualification.
int B::*p11 = static_cast<int B::*>(p10); // { dg-error "casts away constness" }
int D::*p12 = static_cast<int D::*>(p9); // { dg-error "casts away constness" }
// Attempts to change member type.
float B::*p13 = static_cast<float B::*>(&D::x); // { dg-error "" }
float D::*p14 = static_cast<float D::*>(&B::x); // { dg-error "" }
// Copyright (C) 2007 Free Software Foundation
// Contributed by Ollie Wild <aaw@google.com>
// { dg-do compile }
// Assorted pointer to member function static cast tests.
struct A { int f (); };
struct B : A { int f (); };
struct P : A { int f (); };
struct V { int f (); };
struct D : B, virtual V, private P { int f (); };
// Valid static casts.
int (B::*p1)() = static_cast<int (B::*)()>(&D::f);
int (D::*p2)() = static_cast<int (D::*)()>(&B::f);
// Virtual base class.
int (V::*p3)() = static_cast<int (V::*)()>(&D::f); // { dg-error "" }
int (D::*p4)() = static_cast<int (D::*)()>(&V::f); // { dg-error "" }
// Inaccessible base class.
int (P::*p5)() = static_cast<int (P::*)()>(&D::f); // { dg-error "" }
int (D::*p6)() = static_cast<int (D::*)()>(&P::f); // { dg-error "" }
// Ambiguous base class.
int (A::*p7)() = static_cast<int (A::*)()>(&D::f); // { dg-error "" }
int (D::*p8)() = static_cast<int (D::*)()>(&A::f); // { dg-error "" }
// Attempts to change member type.
float (B::*p13)() = static_cast<float (B::*)()>(&D::f); // { dg-error "" }
float (D::*p14)() = static_cast<float (D::*)()>(&B::f); // { dg-error "" }
// Copyright (C) 2007 Free Software Foundation
// Contributed by Ollie Wild <aaw@google.com>
// { dg-do compile }
// Assorted pointer to data member c-style cast tests.
struct X {};
struct A { int x; };
struct B : A { int x; };
struct P : A { int x; };
struct V { int x; };
struct D : B, virtual V, private P { int x; };
// Accessible, non-virtual, non-ambiguous base clas.
int B::*p1 = (int B::*)&D::x;
int D::*p2 = (int D::*)&B::x;
// Virtual base class.
int V::*p3 = (int V::*)&D::x; // { dg-error "" }
int D::*p4 = (int D::*)&V::x; // { dg-error "" }
// Inaccessible base class.
int P::*p5 = (int P::*)&D::x;
int D::*p6 = (int D::*)&P::x;
// Ambiguous base class.
int A::*p7 = (int A::*)&D::x; // { dg-error "" }
int D::*p8 = (int D::*)&A::x; // { dg-error "" }
// Valid conversions which increase cv-qualification.
const int B::*p9 = (const int B::*)&D::x;
const int D::*p10 = (const int D::*)&B::x;
// Valid conversions which decrease cv-qualification.
int B::*p11 = (int B::*)p10;
int D::*p12 = (int D::*)p9;
// Attempts to change member type allowed via reinterpret_cast.
float B::*p13 = (float B::*)&D::x;
float D::*p14 = (float D::*)&B::x;
// Conversion via unrelated classes allwed via reinterpret_cast.
int X::*p15 = (int X::*)&D::x;
// Copyright (C) 2007 Free Software Foundation
// Contributed by Ollie Wild <aaw@google.com>
// { dg-do compile }
// Assorted pointer to member function c-style cast tests.
struct X {};
struct A { int f (); };
struct B : A { int f (); };
struct P : A { int f (); };
struct V { int f (); };
struct D : B, virtual V, private P { int f (); };
// Accessible, non-virtual, non-ambiguous base clas.
int (B::*p1)() = (int (B::*)())&D::f;
int (D::*p2)() = (int (D::*)())&B::f;
// Virtual base class.
int (V::*p3)() = (int (V::*)())&D::f; // { dg-error "" }
int (D::*p4)() = (int (D::*)())&V::f; // { dg-error "" }
// Inaccessible base class.
int (P::*p5)() = (int (P::*)())&D::f;
int (D::*p6)() = (int (D::*)())&P::f;
// Ambiguous base class.
int (A::*p7)() = (int (A::*)())&D::f; // { dg-error "" }
int (D::*p8)() = (int (D::*)())&A::f; // { dg-error "" }
// Attempts to change member type allowed via reinterpret_cast.
float (B::*p13)() = (float (B::*)())&D::f;
float (D::*p14)() = (float (D::*)())&B::f;
// Conversion via unrelated classes allwed via reinterpret_cast.
int (X::*p15)() = (int (X::*)())&D::f;
// Copyright (C) 2007 Free Software Foundation
// Contributed by Ollie Wild <aaw@google.com>
// { dg-do compile }
// Assorted pointer to data member implicit cast tests.
struct A { int x; };
struct B : A { int x; };
struct P : A { int x; };
struct V { int x; };
struct D : B, virtual V, private P { int x; };
// Valid.
int D::*p1 = &B::x;
// Derived class.
int B::*p2 = &D::x; // { dg-error "" }
// Virtual base class.
int D::*p3 = &V::x; // { dg-error "" }
// Inaccessible base class.
int D::*p4 = &P::x; // { dg-error "" }
// Ambiguous base class.
int D::*p5 = &A::x; // { dg-error "" }
// Increases cv-qualification.
const int D::*p6 = &B::x;
// Decreases cv-qualification.
int D::*p7 = static_cast<const int D::*>(&D::x); // { dg-error "" }
// Different member type.
float D::*p8 = &B::x; // { dg-error "" }
// Copyright (C) 2007 Free Software Foundation
// Contributed by Ollie Wild <aaw@google.com>
// { dg-do compile }
// Assorted pointer to member function implicit cast tests.
struct A { int f (); };
struct B : A { int f (); };
struct P : A { int f (); };
struct V { int f (); };
struct D : B, virtual V, private P { int f (); };
// Valid.
int (D::*p1)() = &B::f;
// Derived class.
int (B::*p2)() = &D::f; // { dg-error "" }
// Virtual base class.
int (D::*p3)() = &V::f; // { dg-error "" }
// Inaccessible base class.
int (D::*p4)() = &P::f; // { dg-error "" }
// Ambiguous base class.
int (D::*p5)() = &A::f; // { dg-error "" }
// Different member type.
float (D::*p6)() = &B::f; // { dg-error "" }
// Copyright (C) 2007 Free Software Foundation
// Contributed by Ollie Wild <aaw@google.com>
// { dg-do run }
// Test for proper conversion of null pointers to data members.
struct B1 {
int x;
};
struct B2 {
int x;
};
struct D : B1, B2 {
int x;
};
int main ()
{
int D::*pd = 0;
int B2::*pb2 = 0;
return pd != pb2;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment