From patchwork Tue Apr 26 18:59:18 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 92950 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 AD98BB6F12 for ; Wed, 27 Apr 2011 04:59:49 +1000 (EST) Received: (qmail 553 invoked by alias); 26 Apr 2011 18:59:46 -0000 Received: (qmail 487 invoked by uid 22791); 26 Apr 2011 18:59:39 -0000 X-SWARE-Spam-Status: No, hits=-4.9 required=5.0 tests=AWL, BAYES_50, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_TM, TW_VT, 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; Tue, 26 Apr 2011 18:59:20 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p3QIxJNL000821 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 26 Apr 2011 14:59:19 -0400 Received: from [127.0.0.1] (ovpn-113-113.phx2.redhat.com [10.3.113.113]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p3QIxIhJ015476 for ; Tue, 26 Apr 2011 14:59:19 -0400 Message-ID: <4DB71606.6040500@redhat.com> Date: Tue, 26 Apr 2011 14:59:18 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.15) Gecko/20110307 Fedora/3.1.9-0.39.b3pre.fc14 Lightning/1.0b2 Thunderbird/3.1.9 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for c++/48530 (hard errors with deleted destructors) 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 Daniel Krugler has been doing well at ferreting out parts of the compiler that haven't been properly SFINAE'd yet... Tested x86_64-pc-linux-gnu, applied to trunk. commit 93016efbbb141f1bd917c4032b4a94b2b4c85516 Author: Jason Merrill Date: Mon Apr 25 20:07:15 2011 -0400 PR c++/48530 * decl.c (cxx_maybe_build_cleanup): Add complain parm. * tree.c (force_target_expr): Add complain parm. (build_target_expr_with_type): Likewise. (get_target_expr_sfinae): Split out. (build_vec_init_expr, bot_manip): Adjust. * init.c (build_vec_delete, build_vec_delete_1): Add complain parm. (build_delete, build_dtor_call): Likewise. (perform_direct_initialization_if_possible): Adjust. (build_vec_init): Handle error return. * cvt.c (force_rvalue): Add complain parm. Call build_special_member_call directly. * decl2.c (delete_sanity): Add complain parm. (build_cleanup): Adjust. * pt.c (tsubst_copy_and_build, tsubst_expr): Adjust. * semantics.c (finish_stmt_expr_expr): Adjust. (finish_compound_literal): Adjust. * parser.c (cp_parser_delete_expression): Adjust. * typeck2.c (build_functional_cast): Adjust. * cp-tree.h: Adjust. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index cf8e1a5..10efd1c 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4144,7 +4144,11 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3, && TREE_CODE (arg3) != THROW_EXPR) { if (!VOID_TYPE_P (arg3_type)) - arg3 = force_rvalue (arg3); + { + arg3 = force_rvalue (arg3, complain); + if (arg3 == error_mark_node) + return error_mark_node; + } arg3_type = TREE_TYPE (arg3); result_type = arg3_type; } @@ -4152,7 +4156,11 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3, && TREE_CODE (arg3) == THROW_EXPR) { if (!VOID_TYPE_P (arg2_type)) - arg2 = force_rvalue (arg2); + { + arg2 = force_rvalue (arg2, complain); + if (arg2 == error_mark_node) + return error_mark_node; + } arg2_type = TREE_TYPE (arg2); result_type = arg2_type; } @@ -4359,11 +4367,11 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3, that isn't wrapped with a TARGET_EXPR plays havoc with exception regions. */ - arg2 = force_rvalue (arg2); + arg2 = force_rvalue (arg2, complain); if (!CLASS_TYPE_P (arg2_type)) arg2_type = TREE_TYPE (arg2); - arg3 = force_rvalue (arg3); + arg3 = force_rvalue (arg3, complain); if (!CLASS_TYPE_P (arg3_type)) arg3_type = TREE_TYPE (arg3); @@ -5642,7 +5650,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, expr = convert_bitfield_to_declared_type (expr); expr = fold_convert (type, expr); } - expr = build_target_expr_with_type (expr, type); + expr = build_target_expr_with_type (expr, type, complain); } /* Take the address of the thing to which we will bind the @@ -6341,7 +6349,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) if (TREE_CODE (arg) == TARGET_EXPR) return arg; else if (trivial) - return force_target_expr (DECL_CONTEXT (fn), arg); + return force_target_expr (DECL_CONTEXT (fn), arg, complain); } else if (TREE_CODE (arg) == TARGET_EXPR || trivial) { @@ -8246,7 +8254,7 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp) if (TREE_STATIC (var)) init = add_stmt_to_compound (init, register_dtor_fn (var)); else - *cleanup = cxx_maybe_build_cleanup (var); + *cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error); /* We must be careful to destroy the temporary only after its initialization has taken place. If the diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 66ac4e8..228e33c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4740,7 +4740,7 @@ extern void adjust_clone_args (tree); /* in cvt.c */ extern tree convert_to_reference (tree, tree, int, int, tree); extern tree convert_from_reference (tree); -extern tree force_rvalue (tree); +extern tree force_rvalue (tree, tsubst_flags_t); extern tree ocp_convert (tree, tree, int, int); extern tree cp_convert (tree, tree); extern tree cp_convert_and_check (tree, tree); @@ -4854,7 +4854,7 @@ extern tree next_initializable_field (tree); extern bool defer_mark_used_calls; extern GTY(()) VEC(tree, gc) *deferred_mark_used_calls; extern tree finish_case_label (location_t, tree, tree); -extern tree cxx_maybe_build_cleanup (tree); +extern tree cxx_maybe_build_cleanup (tree, tsubst_flags_t); /* in decl2.c */ extern bool check_java_method (tree); @@ -4866,7 +4866,7 @@ extern bool vague_linkage_p (tree); extern void grokclassfn (tree, tree, enum overload_flags); extern tree grok_array_decl (tree, tree); -extern tree delete_sanity (tree, tree, bool, int); +extern tree delete_sanity (tree, tree, bool, int, tsubst_flags_t); extern tree check_classfn (tree, tree, tree); extern void check_member_template (tree); extern tree grokfield (const cp_declarator *, cp_decl_specifier_seq *, @@ -4973,10 +4973,11 @@ extern tree build_vec_init (tree, tree, tree, bool, int, tsubst_flags_t); extern tree build_delete (tree, tree, special_function_kind, - int, int); + int, int, tsubst_flags_t); extern void push_base_cleanups (void); extern tree build_vec_delete (tree, tree, - special_function_kind, int); + special_function_kind, int, + tsubst_flags_t); extern tree create_temporary_var (tree); extern void initialize_vtbl_ptrs (tree); extern tree build_java_class_ref (tree); @@ -5374,8 +5375,8 @@ extern void maybe_add_lambda_conv_op (tree); /* in tree.c */ void cp_free_lang_data (tree t); -extern tree force_target_expr (tree, tree); -extern tree build_target_expr_with_type (tree, tree); +extern tree force_target_expr (tree, tree, tsubst_flags_t); +extern tree build_target_expr_with_type (tree, tree, tsubst_flags_t); extern void lang_check_failed (const char *, int, const char *) ATTRIBUTE_NORETURN; extern tree stabilize_expr (tree, tree *); @@ -5408,6 +5409,7 @@ extern tree build_min_non_dep_call_vec (tree, tree, VEC(tree,gc) *); extern tree build_cplus_new (tree, tree, tsubst_flags_t); extern tree build_aggr_init_expr (tree, tree, tsubst_flags_t); extern tree get_target_expr (tree); +extern tree get_target_expr_sfinae (tree, tsubst_flags_t); extern tree build_cplus_array_type (tree, tree); extern tree build_array_of_n_type (tree, int); extern tree build_array_copy (tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index de981bc..64fe871 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -531,11 +531,17 @@ convert_from_reference (tree val) argument of class type into a temporary. */ tree -force_rvalue (tree expr) +force_rvalue (tree expr, tsubst_flags_t complain) { - if (MAYBE_CLASS_TYPE_P (TREE_TYPE (expr)) && TREE_CODE (expr) != TARGET_EXPR) - expr = ocp_convert (TREE_TYPE (expr), expr, - CONV_IMPLICIT|CONV_FORCE_TEMP, LOOKUP_NORMAL); + tree type = TREE_TYPE (expr); + if (MAYBE_CLASS_TYPE_P (type) && TREE_CODE (expr) != TARGET_EXPR) + { + VEC(tree,gc) *args = make_tree_vector_single (expr); + expr = build_special_member_call (NULL_TREE, complete_ctor_identifier, + &args, type, LOOKUP_NORMAL, complain); + release_tree_vector (args); + expr = build_cplus_new (type, expr, complain); + } else expr = decay_conversion (expr); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index dcd18ab..ccc5fd0 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5640,7 +5640,7 @@ initialize_local_var (tree decl, tree init) DECL_READ_P (decl) = 1; /* Generate a cleanup, if necessary. */ - cleanup = cxx_maybe_build_cleanup (decl); + cleanup = cxx_maybe_build_cleanup (decl, tf_warning_or_error); /* Perform the initialization. */ if (init) @@ -13309,7 +13309,7 @@ complete_vars (tree type) cleanup need be done. */ tree -cxx_maybe_build_cleanup (tree decl) +cxx_maybe_build_cleanup (tree decl, tsubst_flags_t complain) { tree type; tree attr; @@ -13344,8 +13344,9 @@ cxx_maybe_build_cleanup (tree decl) fn = lookup_name (id); arg = build_address (decl); mark_used (decl); - cleanup = cp_build_function_call_nary (fn, tf_warning_or_error, - arg, NULL_TREE); + cleanup = cp_build_function_call_nary (fn, complain, arg, NULL_TREE); + if (cleanup == error_mark_node) + return error_mark_node; } /* Handle ordinary C++ destructors. */ type = TREE_TYPE (decl); @@ -13367,9 +13368,11 @@ cxx_maybe_build_cleanup (tree decl) flags |= LOOKUP_NONVIRTUAL; call = build_delete (TREE_TYPE (addr), addr, - sfk_complete_destructor, flags, 0); - if (cleanup) - cleanup = build_compound_expr (input_location, cleanup, call); + sfk_complete_destructor, flags, 0, complain); + if (call == error_mark_node) + cleanup = error_mark_node; + else if (cleanup) + cleanup = cp_build_compound_expr (cleanup, call, complain); else cleanup = call; } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index a9c2455..d1b252d 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -419,7 +419,8 @@ grok_array_decl (tree array_expr, tree index_exp) Implements ARM $5.3.4. This is called from the parser. */ tree -delete_sanity (tree exp, tree size, bool doing_vec, int use_global_delete) +delete_sanity (tree exp, tree size, bool doing_vec, int use_global_delete, + tsubst_flags_t complain) { tree t, type; @@ -475,10 +476,11 @@ delete_sanity (tree exp, tree size, bool doing_vec, int use_global_delete) if (doing_vec) return build_vec_delete (t, /*maxindex=*/NULL_TREE, sfk_deleting_destructor, - use_global_delete); + use_global_delete, complain); else return build_delete (type, t, sfk_deleting_destructor, - LOOKUP_NORMAL, use_global_delete); + LOOKUP_NORMAL, use_global_delete, + complain); } /* Report an error if the indicated template declaration is not the @@ -2594,7 +2596,8 @@ build_cleanup (tree decl) temp = build_address (decl); temp = build_delete (TREE_TYPE (temp), temp, sfk_complete_destructor, - LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); + LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0, + tf_warning_or_error); return temp; } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 04d2bb2..25beba8 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -37,7 +37,6 @@ static tree finish_init_stmts (bool, tree, tree); static void construct_virtual_base (tree, tree); static void expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t); static void expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t); -static tree build_vec_delete_1 (tree, tree, tree, special_function_kind, int); static void perform_member_init (tree, tree); static tree build_builtin_delete_call (tree); static int member_init_ok_or_else (tree, tree, tree); @@ -46,7 +45,6 @@ static tree sort_mem_initializers (tree, tree); static tree initializing_context (tree); static void expand_cleanup_for_base (tree, tree); static tree dfs_initialize_vtbl_ptrs (tree, void *); -static tree build_dtor_call (tree, special_function_kind, int); static tree build_field_list (tree, tree, int *); static tree build_vtbl_address (tree); static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool); @@ -620,7 +618,8 @@ perform_member_init (tree member, tree init) /*preserve_reference=*/false, tf_warning_or_error); expr = build_delete (type, expr, sfk_complete_destructor, - LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); + LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0, + tf_warning_or_error); if (expr != error_mark_node) finish_eh_cleanup (expr); @@ -2720,7 +2719,8 @@ build_java_class_ref (tree type) static tree build_vec_delete_1 (tree base, tree maxindex, tree type, - special_function_kind auto_delete_vec, int use_global_delete) + special_function_kind auto_delete_vec, + int use_global_delete, tsubst_flags_t complain) { tree virtual_size; tree ptype = build_pointer_type (type = complete_type (type)); @@ -2749,6 +2749,9 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, /* We should only have 1-D arrays here. */ gcc_assert (TREE_CODE (type) != ARRAY_TYPE); + if (base == error_mark_node || maxindex == error_mark_node) + return error_mark_node; + if (! MAYBE_CLASS_TYPE_P (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) goto no_destructor; @@ -2762,7 +2765,9 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, POINTER_PLUS_EXPR, ptype, fold_convert (ptype, base), virtual_size), - tf_warning_or_error); + complain); + if (tbase_init == error_mark_node) + return error_mark_node; controller = build3 (BIND_EXPR, void_type_node, tbase, NULL_TREE, NULL_TREE); TREE_SIDE_EFFECTS (controller) = 1; @@ -2771,15 +2776,17 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, build2 (EQ_EXPR, boolean_type_node, tbase, fold_convert (ptype, base))); tmp = fold_build1_loc (input_location, NEGATE_EXPR, sizetype, size_exp); - body = build_compound_expr - (input_location, - body, cp_build_modify_expr (tbase, NOP_EXPR, - build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp), - tf_warning_or_error)); - body = build_compound_expr - (input_location, - body, build_delete (ptype, tbase, sfk_complete_destructor, - LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1)); + tmp = build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp); + tmp = cp_build_modify_expr (tbase, NOP_EXPR, tmp, complain); + if (tmp == error_mark_node) + return error_mark_node; + body = build_compound_expr (input_location, body, tmp); + tmp = build_delete (ptype, tbase, sfk_complete_destructor, + LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1, + complain); + if (tmp == error_mark_node) + return error_mark_node; + body = build_compound_expr (input_location, body, tmp); loop = build1 (LOOP_EXPR, void_type_node, body); loop = build_compound_expr (input_location, tbase_init, loop); @@ -2803,14 +2810,15 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, tree cookie_size; cookie_size = targetm.cxx.get_cookie_size (type); - base_tbd - = cp_convert (ptype, - cp_build_binary_op (input_location, - MINUS_EXPR, - cp_convert (string_type_node, - base), - cookie_size, - tf_warning_or_error)); + base_tbd = cp_build_binary_op (input_location, + MINUS_EXPR, + cp_convert (string_type_node, + base), + cookie_size, + complain); + if (base_tbd == error_mark_node) + return error_mark_node; + base_tbd = cp_convert (ptype, base_tbd); /* True size with header. */ virtual_size = size_binop (PLUS_EXPR, virtual_size, cookie_size); } @@ -2853,7 +2861,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, /* Pre-evaluate the SAVE_EXPR outside of the BIND_EXPR. */ body = build2 (COMPOUND_EXPR, void_type_node, base, body); - return convert_to_void (body, ICV_CAST, tf_warning_or_error); + return convert_to_void (body, ICV_CAST, complain); } /* Create an unnamed variable of the indicated TYPE. */ @@ -2942,6 +2950,7 @@ build_vec_init (tree base, tree maxindex, tree init, tree const_init = NULL_TREE; tree obase = base; bool xvalue = false; + bool errors = false; if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype)) maxindex = array_type_nelts (atype); @@ -3087,7 +3096,8 @@ build_vec_init (tree base, tree maxindex, tree init, else one_init = cp_build_modify_expr (baseref, NOP_EXPR, elt, complain); - + if (one_init == error_mark_node) + errors = true; if (try_const) { tree e = one_init; @@ -3120,10 +3130,18 @@ build_vec_init (tree base, tree maxindex, tree init, finish_expr_stmt (one_init); current_stmt_tree ()->stmts_are_full_exprs_p = 0; - finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0, - complain)); - finish_expr_stmt (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0, - complain)); + one_init = cp_build_unary_op (PREINCREMENT_EXPR, base, 0, complain); + if (one_init == error_mark_node) + errors = true; + else + finish_expr_stmt (one_init); + + one_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0, + complain); + if (one_init == error_mark_node) + errors = true; + else + finish_expr_stmt (one_init); } if (try_const) @@ -3149,7 +3167,7 @@ build_vec_init (tree base, tree maxindex, tree init, { if (complain & tf_error) error ("initializer ends prematurely"); - return error_mark_node; + errors = true; } } @@ -3176,9 +3194,11 @@ build_vec_init (tree base, tree maxindex, tree init, finish_for_cond (build2 (NE_EXPR, boolean_type_node, iterator, build_int_cst (TREE_TYPE (iterator), -1)), for_stmt); - finish_for_expr (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0, - complain), - for_stmt); + elt_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0, + complain); + if (elt_init == error_mark_node) + errors = true; + finish_for_expr (elt_init, for_stmt); to = build1 (INDIRECT_REF, type, base); @@ -3219,9 +3239,7 @@ build_vec_init (tree base, tree maxindex, tree init, else if (explicit_value_init_p) { elt_init = build_value_init (type, complain); - if (elt_init == error_mark_node) - return error_mark_node; - else + if (elt_init != error_mark_node) elt_init = build2 (INIT_EXPR, type, to, elt_init); } else @@ -3230,6 +3248,9 @@ build_vec_init (tree base, tree maxindex, tree init, elt_init = build_aggr_init (to, init, 0, complain); } + if (elt_init == error_mark_node) + errors = true; + current_stmt_tree ()->stmts_are_full_exprs_p = 1; finish_expr_stmt (elt_init); current_stmt_tree ()->stmts_are_full_exprs_p = 0; @@ -3263,7 +3284,9 @@ build_vec_init (tree base, tree maxindex, tree init, finish_cleanup_try_block (try_block); e = build_vec_delete_1 (rval, m, inner_elt_type, sfk_base_destructor, - /*use_global_delete=*/0); + /*use_global_delete=*/0, complain); + if (e == error_mark_node) + errors = true; finish_cleanup (e, try_block); } @@ -3286,6 +3309,8 @@ build_vec_init (tree base, tree maxindex, tree init, if (const_init) return build2 (INIT_EXPR, atype, obase, const_init); + if (errors) + return error_mark_node; return stmt_expr; } @@ -3293,7 +3318,8 @@ build_vec_init (tree base, tree maxindex, tree init, build_delete. */ static tree -build_dtor_call (tree exp, special_function_kind dtor_kind, int flags) +build_dtor_call (tree exp, special_function_kind dtor_kind, int flags, + tsubst_flags_t complain) { tree name; tree fn; @@ -3320,7 +3346,7 @@ build_dtor_call (tree exp, special_function_kind dtor_kind, int flags) /*conversion_path=*/NULL_TREE, flags, /*fn_p=*/NULL, - tf_warning_or_error); + complain); } /* Generate a call to a destructor. TYPE is the type to cast ADDR to. @@ -3334,7 +3360,7 @@ build_dtor_call (tree exp, special_function_kind dtor_kind, int flags) tree build_delete (tree type, tree addr, special_function_kind auto_delete, - int flags, int use_global_delete) + int flags, int use_global_delete, tsubst_flags_t complain) { tree expr; @@ -3369,8 +3395,9 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, complete_type (type); if (!COMPLETE_TYPE_P (type)) { - if (warning (0, "possible problem detected in invocation of " - "delete operator:")) + if ((complain & tf_warning) + && warning (0, "possible problem detected in invocation of " + "delete operator:")) { cxx_incomplete_type_diagnostic (addr, type, DK_WARNING); inform (input_location, "neither the destructor nor the class-specific " @@ -3395,18 +3422,21 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, if (TYPE_DOMAIN (type) == NULL_TREE) { - error ("unknown array size in delete"); + if (complain & tf_error) + error ("unknown array size in delete"); return error_mark_node; } return build_vec_delete (addr, array_type_nelts (type), - auto_delete, use_global_delete); + auto_delete, use_global_delete, complain); } else { /* Don't check PROTECT here; leave that decision to the destructor. If the destructor is accessible, call it, else report error. */ - addr = cp_build_addr_expr (addr, tf_warning_or_error); + addr = cp_build_addr_expr (addr, complain); + if (addr == error_mark_node) + return error_mark_node; if (TREE_SIDE_EFFECTS (addr)) addr = save_expr (addr); @@ -3478,9 +3508,10 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, /*alloc_fn=*/NULL_TREE); } - expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL, - tf_warning_or_error), - auto_delete, flags); + expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL, complain), + auto_delete, flags, complain); + if (expr == error_mark_node) + return error_mark_node; if (do_delete) expr = build2 (COMPOUND_EXPR, void_type_node, expr, do_delete); @@ -3492,10 +3523,14 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, /* Explicit destructor call; don't check for null pointer. */ ifexp = integer_one_node; else - /* Handle deleting a null pointer. */ - ifexp = fold (cp_build_binary_op (input_location, - NE_EXPR, addr, integer_zero_node, - tf_warning_or_error)); + { + /* Handle deleting a null pointer. */ + ifexp = fold (cp_build_binary_op (input_location, + NE_EXPR, addr, integer_zero_node, + complain)); + if (ifexp == error_mark_node) + return error_mark_node; + } if (ifexp != integer_one_node) expr = build3 (COND_EXPR, void_type_node, @@ -3588,7 +3623,7 @@ push_base_cleanups (void) expr = build_delete (this_type, this_member, sfk_complete_destructor, LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, - 0); + 0, tf_warning_or_error); finish_decl_cleanup (NULL_TREE, expr); } } @@ -3612,7 +3647,8 @@ push_base_cleanups (void) tree build_vec_delete (tree base, tree maxindex, - special_function_kind auto_delete_vec, int use_global_delete) + special_function_kind auto_delete_vec, + int use_global_delete, tsubst_flags_t complain) { tree type; tree rval; @@ -3638,7 +3674,7 @@ build_vec_delete (tree base, tree maxindex, size_ptr_type, fold_convert (size_ptr_type, base), cookie_addr); - maxindex = cp_build_indirect_ref (cookie_addr, RO_NULL, tf_warning_or_error); + maxindex = cp_build_indirect_ref (cookie_addr, RO_NULL, complain); } else if (TREE_CODE (type) == ARRAY_TYPE) { @@ -3646,7 +3682,9 @@ build_vec_delete (tree base, tree maxindex, bad name. */ maxindex = array_type_nelts_total (type); type = strip_array_types (type); - base = cp_build_addr_expr (base, tf_warning_or_error); + base = cp_build_addr_expr (base, complain); + if (base == error_mark_node) + return error_mark_node; if (TREE_SIDE_EFFECTS (base)) { base_init = get_target_expr (base); @@ -3655,14 +3693,14 @@ build_vec_delete (tree base, tree maxindex, } else { - if (base != error_mark_node) + if (base != error_mark_node && !(complain & tf_error)) error ("type to vector delete is neither pointer or array type"); return error_mark_node; } rval = build_vec_delete_1 (base, maxindex, type, auto_delete_vec, - use_global_delete); - if (base_init) + use_global_delete, complain); + if (base_init && rval != error_mark_node) rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), base_init, rval); return rval; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7d3121c..85d5ab5 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -6294,7 +6294,8 @@ cp_parser_delete_expression (cp_parser* parser) if (cp_parser_non_integral_constant_expression (parser, NIC_DEL)) return error_mark_node; - return delete_sanity (expression, NULL_TREE, array_p, global_scope_p); + return delete_sanity (expression, NULL_TREE, array_p, global_scope_p, + tf_warning_or_error); } /* Returns true if TOKEN may start a cast-expression and false diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 70fcbba..db71cd5 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12094,7 +12094,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, init = build_value_init (TREE_TYPE (decl), complain); if (TREE_CODE (init) == AGGR_INIT_EXPR) - init = get_target_expr (init); + init = get_target_expr_sfinae (init, complain); } else init = t; @@ -12838,7 +12838,8 @@ tsubst_copy_and_build (tree t, (RECUR (TREE_OPERAND (t, 0)), RECUR (TREE_OPERAND (t, 1)), DELETE_EXPR_USE_VEC (t), - DELETE_EXPR_USE_GLOBAL (t)); + DELETE_EXPR_USE_GLOBAL (t), + complain); case COMPOUND_EXPR: return build_x_compound_expr (RECUR (TREE_OPERAND (t, 0)), diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 7763ae0..7dd489d 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1835,7 +1835,7 @@ finish_stmt_expr_expr (tree expr, tree stmt_expr) /* It actually has a value we need to deal with. First, force it to be an rvalue so that we won't need to build up a copy constructor call later when we try to assign it to something. */ - expr = force_rvalue (expr); + expr = force_rvalue (expr, tf_warning_or_error); if (error_operand_p (expr)) return error_mark_node; @@ -1892,7 +1892,7 @@ finish_stmt_expr (tree stmt_expr, bool has_no_scope) temporary object created by the final expression is destroyed at the end of the full-expression containing the statement-expression. */ - result = force_target_expr (type, result); + result = force_target_expr (type, result, tf_warning_or_error); } return result; @@ -2407,7 +2407,7 @@ finish_compound_literal (tree type, tree compound_literal, return decl; } else - return get_target_expr (compound_literal); + return get_target_expr_sfinae (compound_literal, complain); } /* Return the declaration for the function-name variable indicated by @@ -7957,7 +7957,7 @@ build_lambda_object (tree lambda_expr) There's normally no way to express direct-initialization from an element of a CONSTRUCTOR, so we build up a special TARGET_EXPR to bypass the usual copy-initialization. */ - val = force_rvalue (val); + val = force_rvalue (val, tf_warning_or_error); if (TREE_CODE (val) == TARGET_EXPR) TARGET_EXPR_DIRECT_INIT_P (val) = true; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 23daa6c..151e084 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -39,7 +39,7 @@ static tree bot_replace (tree *, int *, void *); static int list_hash_eq (const void *, const void *); static hashval_t list_hash_pieces (tree, tree, tree); static hashval_t list_hash (const void *); -static tree build_target_expr (tree, tree); +static tree build_target_expr (tree, tree, tsubst_flags_t); static tree count_trees_r (tree *, int *, void *); static tree verify_stmt_tree_r (tree *, int *, void *); static tree build_local_temp (tree); @@ -281,7 +281,7 @@ builtin_valid_in_constant_expr_p (const_tree decl) /* Build a TARGET_EXPR, initializing the DECL with the VALUE. */ static tree -build_target_expr (tree decl, tree value) +build_target_expr (tree decl, tree value, tsubst_flags_t complain) { tree t; @@ -292,8 +292,10 @@ build_target_expr (tree decl, tree value) TREE_TYPE (value))); #endif - t = build4 (TARGET_EXPR, TREE_TYPE (decl), decl, value, - cxx_maybe_build_cleanup (decl), NULL_TREE); + t = cxx_maybe_build_cleanup (decl, complain); + if (t == error_mark_node) + return error_mark_node; + t = build4 (TARGET_EXPR, TREE_TYPE (decl), decl, value, t, NULL_TREE); /* We always set TREE_SIDE_EFFECTS so that expand_expr does not ignore the TARGET_EXPR. If there really turn out to be no side-effects, then the optimizer should be able to get rid of @@ -453,7 +455,7 @@ build_cplus_new (tree type, tree init, tsubst_flags_t complain) else return rval; - rval = build_target_expr (slot, rval); + rval = build_target_expr (slot, rval, complain); TARGET_EXPR_IMPLICIT_P (rval) = 1; return rval; @@ -526,7 +528,7 @@ build_vec_init_expr (tree type, tree init) VEC_INIT_EXPR_IS_CONSTEXPR (init) = true; VEC_INIT_EXPR_VALUE_INIT (init) = value_init; - init = build_target_expr (slot, init); + init = build_target_expr (slot, init, tf_warning_or_error); TARGET_EXPR_IMPLICIT_P (init) = 1; return init; @@ -559,7 +561,7 @@ build_array_copy (tree init) indicated TYPE. */ tree -build_target_expr_with_type (tree init, tree type) +build_target_expr_with_type (tree init, tree type, tsubst_flags_t complain) { gcc_assert (!VOID_TYPE_P (type)); @@ -577,9 +579,9 @@ build_target_expr_with_type (tree init, tree type) another one here. A CONSTRUCTOR is aggregate initialization, which is handled separately. A VA_ARG_EXPR is magic creation of an aggregate; there's no additional work to be done. */ - return force_rvalue (init); + return force_rvalue (init, complain); - return force_target_expr (type, init); + return force_target_expr (type, init, complain); } /* Like the above function, but without the checking. This function should @@ -588,27 +590,33 @@ build_target_expr_with_type (tree init, tree type) infinite recursion. */ tree -force_target_expr (tree type, tree init) +force_target_expr (tree type, tree init, tsubst_flags_t complain) { tree slot; gcc_assert (!VOID_TYPE_P (type)); slot = build_local_temp (type); - return build_target_expr (slot, init); + return build_target_expr (slot, init, complain); } /* Like build_target_expr_with_type, but use the type of INIT. */ tree -get_target_expr (tree init) +get_target_expr_sfinae (tree init, tsubst_flags_t complain) { if (TREE_CODE (init) == AGGR_INIT_EXPR) - return build_target_expr (AGGR_INIT_EXPR_SLOT (init), init); + return build_target_expr (AGGR_INIT_EXPR_SLOT (init), init, complain); else if (TREE_CODE (init) == VEC_INIT_EXPR) - return build_target_expr (VEC_INIT_EXPR_SLOT (init), init); + return build_target_expr (VEC_INIT_EXPR_SLOT (init), init, complain); else - return build_target_expr_with_type (init, TREE_TYPE (init)); + return build_target_expr_with_type (init, TREE_TYPE (init), complain); +} + +tree +get_target_expr (tree init) +{ + return get_target_expr_sfinae (init, tf_warning_or_error); } /* If EXPR is a bitfield reference, convert it to the declared type of @@ -1810,7 +1818,8 @@ bot_manip (tree* tp, int* walk_subtrees, void* data) u = build_cplus_new (TREE_TYPE (t), TREE_OPERAND (t, 1), tf_warning_or_error); else - u = build_target_expr_with_type (TREE_OPERAND (t, 1), TREE_TYPE (t)); + u = build_target_expr_with_type (TREE_OPERAND (t, 1), TREE_TYPE (t), + tf_warning_or_error); /* Map the old variable to the new one. */ splay_tree_insert (target_remap, diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 49f4e7e..5522868 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1610,7 +1610,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain) && !TYPE_HAS_USER_CONSTRUCTOR (type)) { exp = build_value_init (type, complain); - exp = get_target_expr (exp); + exp = get_target_expr_sfinae (exp, complain); /* FIXME this is wrong */ if (literal_type_p (type)) TREE_CONSTANT (exp) = true; diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae17.C b/gcc/testsuite/g++.dg/cpp0x/sfinae17.C new file mode 100644 index 0000000..dbbd9ef --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae17.C @@ -0,0 +1,31 @@ +// PR c++/48530 +// { dg-options -std=c++0x } + +template +char f(int); + +template +char (&f(...))[2]; + +struct DelDtor { + ~DelDtor() = delete; +}; + +static_assert(sizeof(f(0)) != 1, "Error"); + +struct A +{ + static DelDtor *p; +}; + +template +char g(int); + +template +char (&g(...))[2]; + +static_assert(sizeof(g(0)) != 1, "Error");