From patchwork Mon Jul 12 23:28:53 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Carlini X-Patchwork-Id: 58693 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 6953CB6EED for ; Tue, 13 Jul 2010 09:29:08 +1000 (EST) Received: (qmail 8293 invoked by alias); 12 Jul 2010 23:29:07 -0000 Received: (qmail 8280 invoked by uid 22791); 12 Jul 2010 23:29:05 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE X-Spam-Check-By: sourceware.org Received: from vsmtp2.tin.it (HELO vsmtp2.tin.it) (212.216.176.222) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 12 Jul 2010 23:28:56 +0000 Received: from [192.168.0.4] (79.17.190.246) by vsmtp2.tin.it (8.0.022) id 49F5BE4223DA18B0; Tue, 13 Jul 2010 01:28:53 +0200 Message-ID: <4C3BA535.6060307@oracle.com> Date: Tue, 13 Jul 2010 01:28:53 +0200 From: Paolo Carlini User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.10) Gecko/20100520 SUSE/3.0.5 Thunderbird/3.0.5 MIME-Version: 1.0 To: "gcc-patches@gcc.gnu.org" CC: Jason Merrill Subject: [C++ Patch] PR 44908 (SFINAE vs pointer to member via virtual base) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hi again, these further bits from my __is_convertible_to work fix the SFINAE issue with pointers to members when virtual inheritance is involved. Even if the patch seems large, is indeed largely mechanical and ultimately very focused on propagating tf_none to get_delta_difference_1 in case of SFINAE. Tested x86_64-linux. Ok for mainline? Thanks, Paolo. //////////////////// cp/ 2010-07-13 Paolo Carlini 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 PR c++/44908 * g++.dg/template/sfinae21.C: New. * g++.dg/template/sfinae22.C: Likewise. Index: testsuite/g++.dg/template/sfinae21.C =================================================================== --- testsuite/g++.dg/template/sfinae21.C (revision 0) +++ testsuite/g++.dg/template/sfinae21.C (revision 0) @@ -0,0 +1,40 @@ +// PR c++/44908 + +struct A { }; + +struct B +: public virtual A { }; + +template struct enable_if { typedef T type; }; +template struct enable_if { }; + +template + class mini_is_convertible + { + typedef char one; + typedef struct { char arr[2]; } two; + + template + static void test_aux(To1); + + template + static typename + enable_if<(sizeof(test_aux(From1()), 1) > 0), one>::type + test(int); + + template + static two test(...); + + public: + static const bool value = sizeof(test(0)) == 1; + }; + +template + const bool mini_is_convertible::value; + +int Test1[mini_is_convertible::value ? -1 : 1]; +int Test2[mini_is_convertible::value ? -1 : 1]; +int Test3[mini_is_convertible::value ? -1 : 1]; +int Test4[mini_is_convertible::value ? -1 : 1]; Index: testsuite/g++.dg/template/sfinae22.C =================================================================== --- testsuite/g++.dg/template/sfinae22.C (revision 0) +++ testsuite/g++.dg/template/sfinae22.C (revision 0) @@ -0,0 +1,39 @@ +// PR c++/44908 +// { dg-options "-std=c++0x" } + +#include + +struct A { }; + +struct B +: public virtual A { }; + +template + class mini_is_convertible + { + typedef char one; + typedef struct { char arr[2]; } two; + + template + static void test_aux(To1); + + template + static decltype(test_aux(std::declval()), one()) + test(int); + + template + static two test(...); + + public: + static const bool value = sizeof(test(0)) == 1; + }; + +template + const bool mini_is_convertible::value; + +static_assert (!mini_is_convertible::value, ""); +static_assert (!mini_is_convertible::value, ""); +static_assert (!mini_is_convertible::value, ""); +static_assert (!mini_is_convertible::value, ""); Index: cp/typeck.c =================================================================== --- cp/typeck.c (revision 162112) +++ cp/typeck.c (working copy) @@ -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, { 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, t 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_i 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_i } 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_ 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 modi /* 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; - binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind); + /* 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); + 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 @@ static tree /* 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 @@ static tree 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 @@ tree 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 /* 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)); Index: cp/call.c =================================================================== --- cp/call.c (revision 162113) +++ cp/call.c (working copy) @@ -5246,7 +5246,7 @@ convert_like_real (conversion *convs, tree expr, t case ck_pmem: return convert_ptrmem (totype, expr, /*allow_inverse_p=*/false, - c_cast_p); + c_cast_p, complain); default: break; Index: cp/cvt.c =================================================================== --- cp/cvt.c (revision 162112) +++ cp/cvt.c (working copy) @@ -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); } Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 162112) +++ cp/cp-tree.h (working copy) @@ -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);