From patchwork Fri Aug 6 19:32:16 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 61133 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 486A8B6F14 for ; Sat, 7 Aug 2010 05:32:35 +1000 (EST) Received: (qmail 345 invoked by alias); 6 Aug 2010 19:32:32 -0000 Received: (qmail 32734 invoked by uid 22791); 6 Aug 2010 19:32:30 -0000 X-SWARE-Spam-Status: No, hits=-6.0 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_VF, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 06 Aug 2010 19:32:22 +0000 Received: from int-mx04.intmail.prod.int.phx2.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.17]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o76JWKuD024866 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 6 Aug 2010 15:32:20 -0400 Received: from [IPv6:::1] (ovpn-113-50.phx2.redhat.com [10.3.113.50]) by int-mx04.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o76JWI9i006262 for ; Fri, 6 Aug 2010 15:32:19 -0400 Message-ID: <4C5C6340.9040407@redhat.com> Date: Fri, 06 Aug 2010 21:32:16 +0200 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.11) Gecko/20100802 Lightning/1.0b1 Shredder/3.0.7pre MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for more SFINAE issues 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 More cases where we needed to pass complain down: build_value_init and complete_type_or_else. Tested x86_64-pc-linux-gnu, applied to trunk. commit 4a26c5a7e6e4e443ca3c37347fe8ede7f1259406 Author: Jason Merrill Date: Wed Aug 4 13:35:31 2010 +0200 * typeck.c (complete_type_or_maybe_complain): Split out from... (complete_type_or_else): Here. (build_class_member_access_expr): Call it. (finish_class_member_access_expr): Likewise. * call.c (build_special_member_call): Likewise. * cvt.c (build_expr_type_conversion): Likewise. * init.c (build_new): Likewise. * typeck2.c (build_functional_cast): Likewise. * cp-tree.h: Declare it. * init.c (build_value_init): Add complain parm. (build_value_init_noctor): Likewise. (perform_member_init): Pass it. (expand_aggr_init_1): Likewise. (build_new_1): Likewise. (build_vec_init): Likewise. * pt.c (tsubst_expr): Likewise. * typeck2.c (build_functional_cast): Likewise. * cp-tree.h: Adjust. * tree.c (build_target_expr_with_type): Handle error_mark_node. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 0bc99bf..fbf98f1 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -6189,7 +6189,7 @@ build_special_member_call (tree instance, tree name, VEC(tree,gc) **args, if (TYPE_P (binfo)) { /* Resolve the name. */ - if (!complete_type_or_else (binfo, NULL_TREE)) + if (!complete_type_or_maybe_complain (binfo, NULL_TREE, complain)) return error_mark_node; binfo = TYPE_BINFO (binfo); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 155db4c..baa6656 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4915,8 +4915,8 @@ extern tree build_aggr_init (tree, tree, int, extern int is_class_type (tree, int); extern tree get_type_value (tree); extern tree build_zero_init (tree, tree, bool); -extern tree build_value_init (tree); -extern tree build_value_init_noctor (tree); +extern tree build_value_init (tree, tsubst_flags_t); +extern tree build_value_init_noctor (tree, tsubst_flags_t); extern tree build_offset_ref (tree, tree, bool); extern tree build_new (VEC(tree,gc) **, tree, tree, VEC(tree,gc) **, int, @@ -5419,6 +5419,7 @@ extern tree condition_conversion (tree); extern tree require_complete_type (tree); extern tree complete_type (tree); extern tree complete_type_or_else (tree, tree); +extern tree complete_type_or_maybe_complain (tree, tree, tsubst_flags_t); extern int type_unknown_p (const_tree); enum { ce_derived, ce_normal, ce_exact }; extern bool comp_except_specs (const_tree, const_tree, int); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 26c4442..ab2b6bf 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -1468,7 +1468,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain) /* The code for conversions from class type is currently only used for delete expressions. Other expressions are handled by build_new_op. */ - if (!complete_type_or_else (basetype, expr)) + if (!complete_type_or_maybe_complain (basetype, expr, complain)) return error_mark_node; if (!TYPE_HAS_CONVERSION (basetype)) return NULL_TREE; diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 0edb800..8555fad 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -269,7 +269,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) TYPE, as described in [dcl.init]. */ tree -build_value_init (tree type) +build_value_init (tree type, tsubst_flags_t complain) { /* [dcl.init] @@ -302,7 +302,7 @@ build_value_init (tree type) (type, build_special_member_call (NULL_TREE, complete_ctor_identifier, NULL, type, LOOKUP_NORMAL, - tf_warning_or_error)); + complain)); else if (TREE_CODE (type) != UNION_TYPE && TYPE_NEEDS_CONSTRUCTING (type)) { /* This is a class that needs constructing, but doesn't have @@ -311,21 +311,21 @@ build_value_init (tree type) This will be handled in simplify_aggr_init_expr. */ tree ctor = build_special_member_call (NULL_TREE, complete_ctor_identifier, - NULL, type, LOOKUP_NORMAL, tf_warning_or_error); + NULL, type, LOOKUP_NORMAL, complain); ctor = build_aggr_init_expr (type, ctor); AGGR_INIT_ZERO_FIRST (ctor) = 1; return ctor; } } - return build_value_init_noctor (type); + return build_value_init_noctor (type, complain); } /* Like build_value_init, but don't call the constructor for TYPE. Used for base initializers. */ tree -build_value_init_noctor (tree type) +build_value_init_noctor (tree type, tsubst_flags_t complain) { if (CLASS_TYPE_P (type)) { @@ -347,7 +347,12 @@ build_value_init_noctor (tree type) ftype = TREE_TYPE (field); if (TREE_CODE (ftype) == REFERENCE_TYPE) - error ("value-initialization of reference"); + { + if (complain & tf_error) + error ("value-initialization of reference"); + else + return error_mark_node; + } /* We could skip vfields and fields of types with user-defined constructors, but I think that won't improve @@ -359,7 +364,7 @@ build_value_init_noctor (tree type) corresponding to base classes as well. Thus, iterating over TYPE_FIELDs will result in correct initialization of all of the subobjects. */ - value = build_value_init (ftype); + value = build_value_init (ftype, complain); if (value) CONSTRUCTOR_APPEND_ELT(v, field, value); @@ -401,7 +406,7 @@ build_value_init_noctor (tree type) ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node, max_index); - ce->value = build_value_init (TREE_TYPE (type)); + ce->value = build_value_init (TREE_TYPE (type), complain); /* The gimplifier can't deal with a RANGE_EXPR of TARGET_EXPRs. */ gcc_assert (TREE_CODE (ce->value) != TARGET_EXPR @@ -459,7 +464,8 @@ perform_member_init (tree member, tree init) member); else { - init = build2 (INIT_EXPR, type, decl, build_value_init (type)); + init = build2 (INIT_EXPR, type, decl, + build_value_init (type, tf_warning_or_error)); finish_expr_stmt (init); } } @@ -1473,7 +1479,8 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, then just zero out the object and we're done. */ else { - init = build2 (INIT_EXPR, type, exp, build_value_init_noctor (type)); + init = build2 (INIT_EXPR, type, exp, + build_value_init_noctor (type, complain)); finish_expr_stmt (init); return; } @@ -2314,8 +2321,10 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, else if (explicit_value_init_p) { /* Something like `new int()'. */ - init_expr = build2 (INIT_EXPR, type, - init_expr, build_value_init (type)); + tree val = build_value_init (type, complain); + if (val == error_mark_node) + return error_mark_node; + init_expr = build2 (INIT_EXPR, type, init_expr, val); } else { @@ -2534,7 +2543,7 @@ build_new (VEC(tree,gc) **placement, tree type, tree nelts, /* The type allocated must be complete. If the new-type-id was "T[N]" then we are just checking that "T" is complete here, but that is equivalent, since the value of "N" doesn't matter. */ - if (!complete_type_or_else (type, NULL_TREE)) + if (!complete_type_or_maybe_complain (type, NULL_TREE, complain)) return error_mark_node; rval = build_new_1 (placement, type, nelts, init, use_global_new, complain); @@ -3041,8 +3050,13 @@ build_vec_init (tree base, tree maxindex, tree init, 0, complain); } else if (explicit_value_init_p) - elt_init = build2 (INIT_EXPR, type, to, - build_value_init (type)); + { + elt_init = build_value_init (type, complain); + if (elt_init == error_mark_node) + return error_mark_node; + else + elt_init = build2 (INIT_EXPR, type, to, elt_init); + } else { gcc_assert (TYPE_NEEDS_CONSTRUCTING (type)); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2777ab7..bb6b1a0 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11705,7 +11705,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, pack expansion where the parameter packs used in that expansion were of length zero. */ - init = build_value_init (TREE_TYPE (decl)); + init = build_value_init (TREE_TYPE (decl), + complain); if (TREE_CODE (init) == AGGR_INIT_EXPR) init = get_target_expr (init); } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 450b9e8..5441448 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -477,7 +477,8 @@ build_target_expr_with_type (tree init, tree type) { gcc_assert (!VOID_TYPE_P (type)); - if (TREE_CODE (init) == TARGET_EXPR) + if (TREE_CODE (init) == TARGET_EXPR + || init == error_mark_node) return init; else if (CLASS_TYPE_P (type) && type_has_nontrivial_copy_init (type) && !VOID_TYPE_P (TREE_TYPE (init)) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 177f4bb..03e7297 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -135,7 +135,7 @@ complete_type (tree type) Returns NULL_TREE if the type cannot be made complete. */ tree -complete_type_or_else (tree type, tree value) +complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain) { type = complete_type (type); if (type == error_mark_node) @@ -143,13 +143,20 @@ complete_type_or_else (tree type, tree value) return NULL_TREE; else if (!COMPLETE_TYPE_P (type)) { - cxx_incomplete_type_diagnostic (value, type, DK_ERROR); + if (complain & tf_error) + cxx_incomplete_type_diagnostic (value, type, DK_ERROR); return NULL_TREE; } else return type; } +tree +complete_type_or_else (tree type, tree value) +{ + return complete_type_or_maybe_complain (type, value, tf_warning_or_error); +} + /* Return truthvalue of whether type of EXP is instantiated. */ int @@ -2209,7 +2216,7 @@ build_class_member_access_expr (tree object, tree member, complete type). */ object_type = TREE_TYPE (object); if (!currently_open_class (object_type) - && !complete_type_or_else (object_type, object)) + && !complete_type_or_maybe_complain (object_type, object, complain)) return error_mark_node; if (!CLASS_TYPE_P (object_type)) { @@ -2585,7 +2592,7 @@ finish_class_member_access_expr (tree object, tree name, bool template_p, The type of the first expression shall be "class object" (of a complete type). */ if (!currently_open_class (object_type) - && !complete_type_or_else (object_type, object)) + && !complete_type_or_maybe_complain (object_type, object, complain)) return error_mark_node; if (!CLASS_TYPE_P (object_type)) { diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index ce83d7c..59b9c40 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1606,7 +1606,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain) then the slot being initialized will be filled in. */ - if (!complete_type_or_else (type, NULL_TREE)) + if (!complete_type_or_maybe_complain (type, NULL_TREE, complain)) return error_mark_node; if (abstract_virtuals_error (NULL_TREE, type)) return error_mark_node; @@ -1631,7 +1631,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain) just calling the constructor, so fall through. */ && !TYPE_HAS_USER_CONSTRUCTOR (type)) { - exp = build_value_init (type); + exp = build_value_init (type, complain); return get_target_expr (exp); } diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae3.C b/gcc/testsuite/g++.dg/cpp0x/sfinae3.C new file mode 100644 index 0000000..8582ba7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae3.C @@ -0,0 +1,56 @@ +// { dg-options -std=c++0x } + +namespace std { template T&& declval(); } + +template + class is_constructible_mini + { + typedef char __one; + typedef struct { char __arr[2]; } __two; + + template + static decltype(::new _Tp1(std::declval<_Args1>()...), __one()) + __test(int); + + template + static __two __test(...); + + public: + static const bool value = sizeof(__test<_Tp, _Args...>(0)) == 1; + }; + +/* +template + class is_constructible_mini<_Tp> + { + typedef char __one; + typedef struct { char __arr[2]; } __two; + + template + static decltype(::new _Tp1, __one()) __test(int); + + template + static __two __test(...); + + public: + static const bool value + = sizeof(__test::type>(0)) == 1; + }; +*/ + +struct A +{ + A(int); +}; + +struct B { }; + +static_assert( is_constructible_mini::value, ""); +static_assert( is_constructible_mini::value, ""); +static_assert( !is_constructible_mini::value, ""); + +static_assert( !is_constructible_mini::value, ""); // doesn't compile without the + // partial specialization + +static_assert( is_constructible_mini::value, ""); +static_assert( is_constructible_mini::value, ""); diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae4.C b/gcc/testsuite/g++.dg/cpp0x/sfinae4.C new file mode 100644 index 0000000..b664831 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae4.C @@ -0,0 +1,23 @@ +// { dg-options -std=c++0x } + +namespace std { template T&& declval(); } + +template + class is_constructible_mini + { + typedef char __one; + typedef struct { char __arr[2]; } __two; + + template + static decltype(::new _Tp1(std::declval<_Args1>()...), __one()) + __test(int); + + template + static __two __test(...); + + public: + static const bool value = sizeof(__test<_Tp, _Args...>(0)) == 1; + }; + +static_assert( !is_constructible_mini::value, ""); +static_assert( !is_constructible_mini::value, "");