From patchwork Fri Jul 9 13:02:47 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Carlini X-Patchwork-Id: 58401 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 26ABB1007F3 for ; Fri, 9 Jul 2010 23:03:06 +1000 (EST) Received: (qmail 18483 invoked by alias); 9 Jul 2010 13:03:05 -0000 Received: (qmail 17564 invoked by uid 22791); 9 Jul 2010 13:03:00 -0000 X-SWARE-Spam-Status: No, hits=-0.4 required=5.0 tests=AWL, BAYES_50, RCVD_IN_DNSWL_NONE, TW_CX, TW_NV X-Spam-Check-By: sourceware.org Received: from vsmtp12.tin.it (HELO vsmtp12.tin.it) (212.216.176.206) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 09 Jul 2010 13:02:51 +0000 Received: from [192.168.0.4] (79.33.217.201) by vsmtp12.tin.it (8.5.113) id 4BC85B97080CA9CB; Fri, 9 Jul 2010 15:02:47 +0200 Message-ID: <4C371DF7.90701@oracle.com> Date: Fri, 09 Jul 2010 15:02:47 +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] Implement __is_convertible_to 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 all, hi Jason, thus, this is my current best try at the code I have been working on the last days. Actually, most of the changes are pretty straightforward, but compared to the previous drafts I made efforts to decouple as much as possible the implementation from the existing functionalities of the C++ front-end: now I'm pretty sure now that we should not be at risk of creating regressions elsewhere outside __is_convertible_to. Anyway, the patch as-is regtests ok, in the library too, where we have a good amount of additional testcases for std::is_convertible, also exercising corner cases pointed out by Howard time ago. What else... I wish I could figure out something a little less "low level" than exploiting force_target_expr, but everything else I tried failed, in particular compile-time errors when the from type has deleted constructors, etc (with force_target_expr we get, properly, correct boolean values for the trait, no compile-time errors, as far as I can see). Also note that the trait_is_convertible_to function itself lives in call.c, not in semantics.c, due to its use of facilities, like convert_like_real, local to that file. Tested x86_64-linux. Is the patch Ok for mainline? Thanks, Paolo. /////////////////// cp/ 2010-07-09 Paolo Carlini * call.c (trait_is_convertible_to): Add. (convert_like_real): Update prototype, add a flags parameter; adjust convert_like_real, build_over_call, build_temp, and convert_ptrmem calls. (perform_implicit_conversion_flags, initialize_reference): Adjust convert_like_real call. (convert_like, convert_like_with_context): Adjust, (build_temp): Update prototype, add a tsubst_flags_t parameter. * semantics.c (trait_expr_value): Call trait_is_convertible_to. (finish_trait_expr): Remove __is_convertible_to sorry message; check its arguments. * cp-tree.h: Declare trait_is_convertible_to; update build_ptrmemfunc and convert_ptrmem prototypes. * cvt.c (cp_convert_to_pointer, convert_force): Adjust convert_ptrmem and build_ptrmemfunc calls. * 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. testsuite/ 2010-07-09 Paolo Carlini * g++.dg/ext/is_convertible_to.C: New. * g++.dg/ext/is_class_error2.C: Adjust. libstdc++-v3 2010-07-09 Paolo Carlini * include/std/type_traits (is_convertible): Use __is_convertible_to. * testsuite/20_util/make_signed/requirements/typedefs_neg.cc: Adjust dg-error line numbers. * testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: Likewise. * testsuite/20_util/declval/requirements/1_neg.cc: Likewise. Index: gcc/testsuite/g++.dg/ext/is_class_error2.C =================================================================== --- gcc/testsuite/g++.dg/ext/is_class_error2.C (revision 161990) +++ gcc/testsuite/g++.dg/ext/is_class_error2.C (working copy) @@ -13,7 +13,7 @@ template void foo() __is_abstract(int)(); // { dg-error "'__is_abstract\\(int\\)' cannot be used" } __is_base_of(int, float)(); // { dg-error "'__is_base_of\\(int, float\\)' cannot be used" } __is_class(int)(); // { dg-error "'__is_class\\(int\\)' cannot be used" } - __is_convertible_to(int, float)(); // { dg-message "unimplemented" } + __is_convertible_to(int, float)(); // { dg-error "'__is_convertible_to\\(int, float\\)' cannot be used" } __is_empty(int)(); // { dg-error "'__is_empty\\(int\\)' cannot be used" } __is_enum(int)(); // { dg-error "'__is_enum\\(int\\)' cannot be used" } __is_pod(int)(); // { dg-error "'__is_pod\\(int\\)' cannot be used" } Index: gcc/testsuite/g++.dg/ext/is_convertible_to.C =================================================================== --- gcc/testsuite/g++.dg/ext/is_convertible_to.C (revision 0) +++ gcc/testsuite/g++.dg/ext/is_convertible_to.C (revision 0) @@ -0,0 +1,142 @@ +// { dg-do "run" } +#include + +class A +{ }; + +class B +: public A { }; + +class C +: public A { }; + +enum E +{ + e0 +}; + +class D +: public B, public C { }; + +class F +: private A { }; + +class G +: public virtual A { }; + +struct X +{ + operator int(); +}; + +struct Y +{ + operator X(); +}; + +class Z +{ + operator int(); +}; + +template + bool + f() + { return __is_convertible_to(T, U); } + +template + class My + { + public: + bool + f() + { return !!__is_convertible_to(T, U); } + }; + +template + class My2 + { + public: + static const bool trait = __is_convertible_to(T, U); + }; + +template + const bool My2::trait; + +template + struct My3_help + { static const bool trait = b; }; + +template + const bool My3_help::trait; + +template + class My3 + { + public: + bool + f() + { return My3_help::trait; } + }; + +#define PTEST(T, U) (__is_convertible_to(T, U) && f() \ + && My().f() && My2::trait && My3().f()) + +#define NTEST(T, U) (!__is_convertible_to(T, U) && !f() \ + && !My().f() && !My2::trait \ + && !My3().f()) + +int main() +{ + assert (NTEST (int, void)); + assert (NTEST (void, int)); + assert (PTEST (void, void)); + assert (PTEST (int, float)); + assert (PTEST (float, int)); + assert (PTEST (int*, const int*)); + assert (NTEST (const int*, int*)); + assert (PTEST (int*, void*)); + assert (NTEST (void*, int*)); + assert (NTEST (int*, float*)); + assert (PTEST (int&, const int&)); + assert (NTEST (const int&, int&)); + assert (PTEST (int&, int)); + assert (NTEST (int, int&)); + assert (PTEST (const int, const int&)); + assert (NTEST (volatile int, volatile int&)); + assert (NTEST (const volatile int, const volatile int&)); + assert (NTEST (int (int), int (int))); + assert (NTEST (int[], int[])); + assert (PTEST (int[], int*)); + assert (PTEST (int (int), int (*) (int))); + assert (NTEST (int (int), int (&) (int))); + assert (PTEST (A, A)); + assert (NTEST (int, A)); + assert (NTEST (A, int)); + assert (PTEST (B, A)); + assert (NTEST (A, B)); + assert (PTEST (B*, A*)); + assert (NTEST (A*, B*)); + assert (PTEST (B&, A&)); + assert (NTEST (A&, B&)); + assert (PTEST (int (A::*), int (B::*))); + assert (NTEST (int (B::*), int (A::*))); + assert (PTEST (int (A::*) (int), int (B::*) (int))); + assert (NTEST (int (B::*) (int), int (A::*) (int))); + assert (PTEST (E, int)); + assert (NTEST (int, E)); + assert (NTEST (D, A)); + assert (NTEST (F, A)); + assert (NTEST (F*, A*)); + assert (NTEST (F&, A&)); + assert (NTEST (int (A::*), int (F::*))); + assert (NTEST (int (A::*) (int), int (F::*) (int))); + assert (NTEST (int (A::*), int (G::*))); + assert (NTEST (int (A::*) (int), int (G::*) (int))); + assert (PTEST (X, int)); + assert (NTEST (Y, int)); + assert (PTEST (Y, X)); + assert (NTEST (Z, int)); + + return 0; +} Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c (revision 161990) +++ gcc/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,30 @@ 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; - binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind); + if (complain & tf_error) + binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind); + else + binfo = lookup_base (to, from, + ba_quiet | (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 +6894,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 +6923,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 +6931,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 +7020,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 +7048,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 +7133,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: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c (revision 161990) +++ gcc/cp/semantics.c (working copy) @@ -5039,8 +5039,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, return (NON_UNION_CLASS_TYPE_P (type1)); case CPTK_IS_CONVERTIBLE_TO: - /* TODO */ - return false; + return trait_is_convertible_to (type1, type2); case CPTK_IS_EMPTY: return (NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1)); @@ -5113,12 +5112,6 @@ finish_trait_expr (cp_trait_kind kind, tree type1, || kind == CPTK_IS_TRIVIAL || kind == CPTK_IS_UNION); - if (kind == CPTK_IS_CONVERTIBLE_TO) - { - sorry ("__is_convertible_to"); - return error_mark_node; - } - if (type1 == error_mark_node || ((kind == CPTK_IS_BASE_OF || kind == CPTK_IS_CONVERTIBLE_TO) && type2 == error_mark_node)) @@ -5171,12 +5164,24 @@ finish_trait_expr (cp_trait_kind kind, tree type1, } break; + case CPTK_IS_CONVERTIBLE_TO: + if (!check_trait_type (type1)) + { + error ("incomplete type %qT not allowed", type1); + return error_mark_node; + } + if (!check_trait_type (type2)) + { + error ("incomplete type %qT not allowed", type2); + return error_mark_node; + } + break; + case CPTK_IS_CLASS: case CPTK_IS_ENUM: case CPTK_IS_UNION: break; - case CPTK_IS_CONVERTIBLE_TO: default: gcc_unreachable (); } Index: gcc/cp/call.c =================================================================== --- gcc/cp/call.c (revision 161990) +++ gcc/cp/call.c (working copy) @@ -139,13 +139,13 @@ static tree build_java_interface_fn_ref (tree, tre #define convert_like(CONV, EXPR, COMPLAIN) \ convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0, \ /*issue_conversion_warnings=*/true, \ - /*c_cast_p=*/false, (COMPLAIN)) + /*c_cast_p=*/false, (COMPLAIN), LOOKUP_NORMAL) #define convert_like_with_context(CONV, EXPR, FN, ARGNO, COMPLAIN ) \ convert_like_real ((CONV), (EXPR), (FN), (ARGNO), 0, \ /*issue_conversion_warnings=*/true, \ - /*c_cast_p=*/false, (COMPLAIN)) + /*c_cast_p=*/false, (COMPLAIN), LOOKUP_NORMAL) static tree convert_like_real (conversion *, tree, tree, int, int, bool, - bool, tsubst_flags_t); + bool, tsubst_flags_t, int); static void op_error (enum tree_code, enum tree_code, tree, tree, tree, bool); static VEC(tree,gc) *resolve_args (VEC(tree,gc) *); @@ -204,7 +204,7 @@ static void add_candidates (tree, tree, const VEC( tree, tree, int, struct z_candidate **); static conversion *merge_conversion_sequences (conversion *, conversion *); static bool magic_varargs_p (tree); -static tree build_temp (tree, tree, int, diagnostic_t *); +static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t); /* Returns nonzero iff the destructor name specified in NAME matches BASETYPE. NAME can take many forms... */ @@ -4851,7 +4851,7 @@ enforce_access (tree basetype_path, tree decl, tre static tree build_temp (tree expr, tree type, int flags, - diagnostic_t *diagnostic_kind) + diagnostic_t *diagnostic_kind, tsubst_flags_t complain) { int savew, savee; VEC(tree,gc) *args; @@ -4859,7 +4859,7 @@ build_temp (tree expr, tree type, int flags, savew = warningcount, savee = errorcount; args = make_tree_vector_single (expr); expr = build_special_member_call (NULL_TREE, complete_ctor_identifier, - &args, type, flags, tf_warning_or_error); + &args, type, flags, complain); release_tree_vector (args); if (warningcount > savew) *diagnostic_kind = DK_WARNING; @@ -4911,11 +4911,10 @@ conversion_null_warnings (tree totype, tree expr, static tree convert_like_real (conversion *convs, tree expr, tree fn, int argnum, int inner, bool issue_conversion_warnings, - bool c_cast_p, tsubst_flags_t complain) + bool c_cast_p, tsubst_flags_t complain, int flags) { tree totype = convs->type; diagnostic_t diag_kind; - int flags; if (convs->bad_p && convs->kind != ck_user @@ -4941,14 +4940,14 @@ convert_like_real (conversion *convs, tree expr, t expr = convert_like_real (t, expr, fn, argnum, 1, /*issue_conversion_warnings=*/false, /*c_cast_p=*/false, - complain); + complain, flags); break; } else if (t->kind == ck_ambig) return convert_like_real (t, expr, fn, argnum, 1, /*issue_conversion_warnings=*/false, /*c_cast_p=*/false, - complain); + complain, flags); else if (t->kind == ck_identity) break; } @@ -4997,7 +4996,7 @@ convert_like_real (conversion *convs, tree expr, t for (i = 0; i < cand->num_convs; ++i) cand->convs[i]->user_conv_p = true; - expr = build_over_call (cand, LOOKUP_NORMAL, complain); + expr = build_over_call (cand, flags, complain); /* If this is a constructor or a function returning an aggr type, we need to build up a TARGET_EXPR. */ @@ -5064,7 +5063,7 @@ convert_like_real (conversion *convs, tree expr, t FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val) { tree sub = convert_like_real (convs->u.list[ix], val, fn, argnum, - 1, false, false, complain); + 1, false, false, complain, flags); if (sub == error_mark_node) return sub; check_narrowing (TREE_TYPE (sub), val); @@ -5099,7 +5098,8 @@ convert_like_real (conversion *convs, tree expr, t convs->kind == ck_ref_bind ? -1 : 1, convs->kind == ck_ref_bind ? issue_conversion_warnings : false, c_cast_p, - complain); + complain, + LOOKUP_NORMAL); if (expr == error_mark_node) return error_mark_node; @@ -5132,7 +5132,7 @@ convert_like_real (conversion *convs, tree expr, t conversion (i.e. the second step of copy-initialization), so don't allow any more. */ flags |= LOOKUP_NO_CONVERSION; - expr = build_temp (expr, totype, flags, &diag_kind); + expr = build_temp (expr, totype, flags, &diag_kind, complain); if (diag_kind && fn) { if ((complain & tf_error)) @@ -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; @@ -7597,7 +7597,8 @@ can_convert_arg_bad (tree to, tree from, tree arg, doing a bad conversion, convert_like will complain. */ tree -perform_implicit_conversion_flags (tree type, tree expr, tsubst_flags_t complain, int flags) +perform_implicit_conversion_flags (tree type, tree expr, + tsubst_flags_t complain, int flags) { conversion *conv; void *p; @@ -7698,7 +7699,8 @@ perform_direct_initialization_if_possible (tree ty expr = convert_like_real (conv, expr, NULL_TREE, 0, 0, /*issue_conversion_warnings=*/false, c_cast_p, - complain); + complain, + LOOKUP_NORMAL); /* Free all the conversions we allocated. */ obstack_free (&conversion_obstack, p); @@ -7706,6 +7708,43 @@ perform_direct_initialization_if_possible (tree ty return expr; } +/* Called from trait_expr_value to evaluate __is_convertible_to. */ + +bool +trait_is_convertible_to (tree from, tree to) +{ + if (error_operand_p (from) || error_operand_p (to)) + return false; + + if (VOID_TYPE_P (from)) + return VOID_TYPE_P (to) ? true : false; + else + { + tree expr = force_target_expr (from, build_dummy_object (from)); + conversion *conv; + void *p; + + /* Get the high-water mark for the CONVERSION_OBSTACK. */ + p = conversion_obstack_alloc (0); + + conv = implicit_conversion (to, TREE_TYPE (expr), expr, + /*c_cast_p=*/false, + LOOKUP_SPECULATIVE); + if (!conv) + expr = error_mark_node; + else + expr = convert_like_real (conv, expr, NULL_TREE, 0, 0, + /*issue_conversion_warnings=*/true, + /*c_cast_p=*/false, tf_none, + LOOKUP_SPECULATIVE); + + /* Free all the conversions we allocated. */ + obstack_free (&conversion_obstack, p); + + return expr == error_mark_node ? false : true; + } +} + /* DECL is a VAR_DECL whose type is a REFERENCE_TYPE. The reference is being bound to a temporary. Create and return a new VAR_DECL with the indicated TYPE; this variable will store the value to @@ -7909,7 +7948,8 @@ initialize_reference (tree type, tree expr, tree d /*inner=*/-1, /*issue_conversion_warnings=*/true, /*c_cast_p=*/false, - tf_warning_or_error); + tf_warning_or_error, + LOOKUP_NORMAL); if (error_operand_p (expr)) expr = error_mark_node; else Index: gcc/cp/cvt.c =================================================================== --- gcc/cp/cvt.c (revision 161990) +++ gcc/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: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h (revision 161990) +++ gcc/cp/cp-tree.h (working copy) @@ -4629,6 +4629,7 @@ extern tree perform_implicit_conversion (tree, tr extern tree perform_implicit_conversion_flags (tree, tree, tsubst_flags_t, int); extern tree perform_direct_initialization_if_possible (tree, tree, bool, tsubst_flags_t); +extern bool trait_is_convertible_to (tree, tree); extern tree in_charge_arg_for_name (tree); extern tree build_cxx_call (tree, int, tree *); extern bool is_std_init_list (tree); @@ -5483,7 +5484,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); @@ -5512,7 +5514,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); Index: libstdc++-v3/include/std/type_traits =================================================================== --- libstdc++-v3/include/std/type_traits (revision 161990) +++ libstdc++-v3/include/std/type_traits (working copy) @@ -306,31 +306,10 @@ namespace std : public integral_constant { }; - template::value || is_void<_To>::value - || is_function<_To>::value || is_array<_To>::value)> - struct __is_convertible_helper - { static const bool __value = (is_void<_From>::value - && is_void<_To>::value); }; - - template - class __is_convertible_helper<_From, _To, false> - : public __sfinae_types - { - static __one __test(_To); - static __two __test(...); - - public: - static const bool __value = sizeof(__test(declval<_From>())) == 1; - }; - /// is_convertible - // XXX FIXME - // The C++0x specifications require front-end support, see N2255. template struct is_convertible - : public integral_constant::__value> + : public integral_constant { }; /// is_explicitly_convertible Index: libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc =================================================================== --- libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc (revision 161990) +++ libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc (working copy) @@ -48,5 +48,5 @@ void test01() // { dg-error "instantiated from here" "" { target *-*-* } 40 } // { dg-error "instantiated from here" "" { target *-*-* } 42 } -// { dg-error "invalid use of incomplete type" "" { target *-*-* } 639 } -// { dg-error "declaration of" "" { target *-*-* } 603 } +// { dg-error "invalid use of incomplete type" "" { target *-*-* } 618 } +// { dg-error "declaration of" "" { target *-*-* } 582 } Index: libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc =================================================================== --- libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc (revision 161990) +++ libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc (working copy) @@ -48,5 +48,5 @@ void test01() // { dg-error "instantiated from here" "" { target *-*-* } 40 } // { dg-error "instantiated from here" "" { target *-*-* } 42 } -// { dg-error "invalid use of incomplete type" "" { target *-*-* } 562 } -// { dg-error "declaration of" "" { target *-*-* } 526 } +// { dg-error "invalid use of incomplete type" "" { target *-*-* } 541 } +// { dg-error "declaration of" "" { target *-*-* } 505 } Index: libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc =================================================================== --- libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc (revision 161990) +++ libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc (working copy) @@ -19,7 +19,7 @@ // with this library; see the file COPYING3. If not see // . -// { dg-error "static assertion failed" "" { target *-*-* } 676 } +// { dg-error "static assertion failed" "" { target *-*-* } 655 } #include