Commit 135d47df by Paolo Carlini Committed by Paolo Carlini

re PR c++/44908 (SFINAE vs pointer to member via virtual base)

cp/
2010-07-13  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/44908
	* call.c (convert_like_real): Adjust convert_ptrmem call, pass
	complain argument.
	* typeck.c (get_delta_difference): Update prototype, add a
	tsubst_flags_t parameter; update get_delta_difference_1 calls and
	add checks for error_mark_node.
	(get_delta_difference_1): Update prototype, add a tsubst_flags_t
	parameter; update lookup_base call.
	(build_ptrmemfunc): Update prototype, add a tsubst_flags_t
	parameter; update get_delta_difference call and add check for
	error_mark_node.
	(convert_ptrmem): Update prototype, add a tsubst_flags_t
	parameter; update get_delta_difference call and add check for
	error_mark_node;  update build_ptrmemfunc call.
	(build_static_cast_1): Adjust convert_ptrmem call.
	(expand_ptrmemfunc_cst): Adjust get_delta_difference call.
	(cp_build_unary_op): Adjust build_ptrmemfunc call.
	* cvt.c (cp_convert_to_pointer, convert_force): Adjust convert_ptrmem
	and build_ptrmemfunc calls.
	* cp-tree.h: Update build_ptrmemfunc and convert_ptrmem prototypes.

testsuite/
2010-07-13  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/44908
	* g++.dg/template/sfinae21.C: New.
	* g++.dg/template/sfinae22.C: Likewise.

From-SVN: r162138
parent 2eb0b984
2010-07-13 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/44908
* call.c (convert_like_real): Adjust convert_ptrmem call, pass
complain argument.
* typeck.c (get_delta_difference): Update prototype, add a
tsubst_flags_t parameter; update get_delta_difference_1 calls and
add checks for error_mark_node.
(get_delta_difference_1): Update prototype, add a tsubst_flags_t
parameter; update lookup_base call.
(build_ptrmemfunc): Update prototype, add a tsubst_flags_t
parameter; update get_delta_difference call and add check for
error_mark_node.
(convert_ptrmem): Update prototype, add a tsubst_flags_t
parameter; update get_delta_difference call and add check for
error_mark_node; update build_ptrmemfunc call.
(build_static_cast_1): Adjust convert_ptrmem call.
(expand_ptrmemfunc_cst): Adjust get_delta_difference call.
(cp_build_unary_op): Adjust build_ptrmemfunc call.
* cvt.c (cp_convert_to_pointer, convert_force): Adjust convert_ptrmem
and build_ptrmemfunc calls.
* cp-tree.h: Update build_ptrmemfunc and convert_ptrmem prototypes.
2010-07-12 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/44907
......
......@@ -5246,7 +5246,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
case ck_pmem:
return convert_ptrmem (totype, expr, /*allow_inverse_p=*/false,
c_cast_p);
c_cast_p, complain);
default:
break;
......
......@@ -5488,7 +5488,8 @@ extern int comp_ptr_ttypes (tree, tree);
extern bool comp_ptr_ttypes_const (tree, tree);
extern bool error_type_p (const_tree);
extern int ptr_reasonably_similar (const_tree, const_tree);
extern tree build_ptrmemfunc (tree, tree, int, bool);
extern tree build_ptrmemfunc (tree, tree, int, bool,
tsubst_flags_t);
extern int cp_type_quals (const_tree);
extern int type_memfn_quals (const_tree);
extern tree apply_memfn_quals (tree, cp_cv_quals);
......@@ -5517,7 +5518,8 @@ extern tree non_reference (tree);
extern tree lookup_anon_field (tree, tree);
extern bool invalid_nonstatic_memfn_p (const_tree, tsubst_flags_t);
extern tree convert_member_func_to_ptr (tree, tree);
extern tree convert_ptrmem (tree, tree, bool, bool);
extern tree convert_ptrmem (tree, tree, bool, bool,
tsubst_flags_t);
extern int lvalue_or_else (tree, enum lvalue_use,
tsubst_flags_t);
extern void check_template_keyword (tree);
......
......@@ -176,7 +176,7 @@ cp_convert_to_pointer (tree type, tree expr)
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);
/*c_cast_p=*/false, tf_warning_or_error);
else if (TYPE_PTRMEMFUNC_P (intype))
{
if (!warn_pmf2ptr)
......@@ -200,7 +200,7 @@ cp_convert_to_pointer (tree type, tree expr)
{
if (TYPE_PTRMEMFUNC_P (type))
return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
/*c_cast_p=*/false);
/*c_cast_p=*/false, tf_warning_or_error);
if (TYPE_PTRMEM_P (type))
{
......@@ -1376,7 +1376,7 @@ convert_force (tree type, tree expr, int convtype)
&& TYPE_PTRMEMFUNC_P (type))
/* compatible pointer to member functions. */
return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1,
/*c_cast_p=*/1);
/*c_cast_p=*/1, tf_warning_or_error);
return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
}
......
/* Build expressions with type checking for C++ compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
......@@ -53,7 +53,7 @@ static int comp_ptr_ttypes_real (tree, tree, int);
static bool comp_except_types (tree, tree, bool);
static bool comp_array_types (const_tree, const_tree, bool);
static tree pointer_diff (tree, tree, tree);
static tree get_delta_difference (tree, tree, bool, bool);
static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
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);
......@@ -5254,7 +5254,8 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
{
build_ptrmemfunc_type (argtype);
val = build_ptrmemfunc (argtype, val, 0,
/*c_cast_p=*/false);
/*c_cast_p=*/false,
tf_warning_or_error);
}
return val;
......@@ -5669,7 +5670,7 @@ check_for_casting_away_constness (tree src_type, tree dest_type,
tree
convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
bool c_cast_p)
bool c_cast_p, tsubst_flags_t complain)
{
if (TYPE_PTRMEM_P (type))
{
......@@ -5680,7 +5681,10 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
delta = get_delta_difference (TYPE_PTRMEM_CLASS_TYPE (TREE_TYPE (expr)),
TYPE_PTRMEM_CLASS_TYPE (type),
allow_inverse_p,
c_cast_p);
c_cast_p, complain);
if (delta == error_mark_node)
return error_mark_node;
if (!integer_zerop (delta))
{
tree cond, op1, op2;
......@@ -5704,7 +5708,7 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
}
else
return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr,
allow_inverse_p, c_cast_p);
allow_inverse_p, c_cast_p, complain);
}
/* If EXPR is an INTEGER_CST and ORIG is an arithmetic constant, return
......@@ -5940,7 +5944,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
if (!c_cast_p)
check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
c_cast_p);
c_cast_p, tf_warning_or_error);
}
}
......@@ -6855,20 +6859,32 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree 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,
of FROM to pointer-to-member of TO. If the conversion is invalid and
tf_error is not set in COMPLAIN returns error_mark_node, otherwise
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. */
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)
get_delta_difference_1 (tree from, tree to, bool c_cast_p,
tsubst_flags_t complain)
{
tree binfo;
base_kind kind;
base_access access = c_cast_p ? ba_unique : ba_check;
/* Note: ba_quiet does not distinguish between access control and
ambiguity. */
if (!(complain & tf_error))
access |= ba_quiet;
binfo = lookup_base (to, from, access, &kind);
binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
if (kind == bk_inaccessible || kind == bk_ambig)
{
if (!(complain & tf_error))
return error_mark_node;
error (" in pointer to member function conversion");
return size_zero_node;
}
......@@ -6880,22 +6896,26 @@ get_delta_difference_1 (tree from, tree to, bool c_cast_p)
/* FROM is a virtual base class of TO. Issue an error or warning
depending on whether or not this is a reinterpret cast. */
{
if (!(complain & tf_error))
return error_mark_node;
error ("pointer to member conversion via virtual base %qT",
BINFO_TYPE (binfo_from_vbase (binfo)));
return size_zero_node;
}
}
else
return NULL_TREE;
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
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.
types. If the conversion is invalid and tf_error is not set in
COMPLAIN, returns error_mark_node, otherwise returns an integer
constant of type PTRDIFF_TYPE_NODE and its value is zero if the
conversion is invalid. 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
......@@ -6905,7 +6925,7 @@ get_delta_difference_1 (tree from, tree to, bool c_cast_p)
static tree
get_delta_difference (tree from, tree to,
bool allow_inverse_p,
bool c_cast_p)
bool c_cast_p, tsubst_flags_t complain)
{
tree result;
......@@ -6913,25 +6933,37 @@ get_delta_difference (tree from, tree to,
/* Pointer to member of incomplete class is permitted*/
result = size_zero_node;
else
result = get_delta_difference_1 (from, to, c_cast_p);
result = get_delta_difference_1 (from, to, c_cast_p, complain);
if (result == error_mark_node)
return error_mark_node;
if (!result)
{
if (!allow_inverse_p)
{
if (!(complain & tf_error))
return error_mark_node;
error_not_base_type (from, to);
error (" in pointer to member conversion");
result = size_zero_node;
result = size_zero_node;
}
else
{
result = get_delta_difference_1 (to, from, c_cast_p);
result = get_delta_difference_1 (to, from, c_cast_p, complain);
if (result == error_mark_node)
return error_mark_node;
if (result)
result = size_diffop_loc (input_location,
size_zero_node, result);
size_zero_node, result);
else
{
if (!(complain & tf_error))
return error_mark_node;
error_not_base_type (from, to);
error (" in pointer to member conversion");
result = size_zero_node;
......@@ -6990,7 +7022,8 @@ build_ptrmemfunc1 (tree type, tree delta, tree pfn)
Return error_mark_node, if something goes wrong. */
tree
build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p,
tsubst_flags_t complain)
{
tree fn;
tree pfn_type;
......@@ -7017,7 +7050,9 @@ build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
force,
c_cast_p);
c_cast_p, complain);
if (n == error_mark_node)
return error_mark_node;
/* We don't have to do any conversion to convert a
pointer-to-member to its own type. But, we don't want to
......@@ -7100,7 +7135,7 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
/* First, calculate the adjustment to the function's class. */
*delta = get_delta_difference (fn_class, ptr_class, /*force=*/0,
/*c_cast_p=*/0);
/*c_cast_p=*/0, tf_warning_or_error);
if (!DECL_VIRTUAL_P (fn))
*pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
......
2010-07-13 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/44908
* g++.dg/template/sfinae21.C: New.
* g++.dg/template/sfinae22.C: Likewise.
2010-07-13 Kaz Kojima <kkojima@gcc.gnu.org>
* gcc.c-torture/execute/pr44683.x: New.
......
// PR c++/44908
struct A { };
struct B
: public virtual A { };
template<bool, typename T = void> struct enable_if { typedef T type; };
template<typename T> struct enable_if<false, T> { };
template<typename From, typename To>
class mini_is_convertible
{
typedef char one;
typedef struct { char arr[2]; } two;
template<typename To1>
static void test_aux(To1);
template<typename To1, typename From1>
static typename
enable_if<(sizeof(test_aux<To1>(From1()), 1) > 0), one>::type
test(int);
template<typename, typename>
static two test(...);
public:
static const bool value = sizeof(test<To, From>(0)) == 1;
};
template<typename From, typename To>
const bool mini_is_convertible<From, To>::value;
int Test1[mini_is_convertible<int (B::*) (int),
int (A::*) (int)>::value ? -1 : 1];
int Test2[mini_is_convertible<int (B::*), int (A::*)>::value ? -1 : 1];
int Test3[mini_is_convertible<int (A::*) (int),
int (B::*) (int)>::value ? -1 : 1];
int Test4[mini_is_convertible<int (A::*), int (B::*)>::value ? -1 : 1];
// PR c++/44908
// { dg-options "-std=c++0x" }
#include <utility>
struct A { };
struct B
: public virtual A { };
template<typename From, typename To>
class mini_is_convertible
{
typedef char one;
typedef struct { char arr[2]; } two;
template<typename To1>
static void test_aux(To1);
template<typename To1, typename From1>
static decltype(test_aux<To1>(std::declval<From1>()), one())
test(int);
template<typename, typename>
static two test(...);
public:
static const bool value = sizeof(test<To, From>(0)) == 1;
};
template<typename From, typename To>
const bool mini_is_convertible<From, To>::value;
static_assert (!mini_is_convertible<int (B::*) (int),
int (A::*) (int)>::value, "");
static_assert (!mini_is_convertible<int (B::*), int (A::*)>::value, "");
static_assert (!mini_is_convertible<int (A::*) (int),
int (B::*) (int)>::value, "");
static_assert (!mini_is_convertible<int (A::*), int (B::*)>::value, "");
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