diff options
author | Paolo Carlini <paolo.carlini@oracle.com> | 2010-07-13 11:47:58 +0000 |
---|---|---|
committer | Paolo Carlini <paolo@gcc.gnu.org> | 2010-07-13 11:47:58 +0000 |
commit | 135d47df2157e1f04f519f18e893b4fb68e3d341 (patch) | |
tree | f22cdbec5caa431704f8cc4c895d9644d5bf307c /gcc | |
parent | 2eb0b984b67816b22c98b2287d7bd3cabf017b30 (diff) | |
download | gcc-135d47df2157e1f04f519f18e893b4fb68e3d341.zip gcc-135d47df2157e1f04f519f18e893b4fb68e3d341.tar.gz gcc-135d47df2157e1f04f519f18e893b4fb68e3d341.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 23 | ||||
-rw-r--r-- | gcc/cp/call.c | 2 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 6 | ||||
-rw-r--r-- | gcc/cp/cvt.c | 6 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 89 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/sfinae21.C | 40 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/sfinae22.C | 39 |
8 files changed, 178 insertions, 33 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 27061ad..4e2c0e4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +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 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index ca34a6c..1c64149 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 08398aa..cf128dc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 4fcba45..26c4442 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -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); } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index fd8221c..d5e43de 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1,6 +1,6 @@ /* 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)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9e53f92..186a4c6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +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. diff --git a/gcc/testsuite/g++.dg/template/sfinae21.C b/gcc/testsuite/g++.dg/template/sfinae21.C new file mode 100644 index 0000000..6086f2f --- /dev/null +++ b/gcc/testsuite/g++.dg/template/sfinae21.C @@ -0,0 +1,40 @@ +// 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]; diff --git a/gcc/testsuite/g++.dg/template/sfinae22.C b/gcc/testsuite/g++.dg/template/sfinae22.C new file mode 100644 index 0000000..cdac99d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/sfinae22.C @@ -0,0 +1,39 @@ +// 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, ""); |