From patchwork Thu Apr 7 21:32:43 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 90235 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 6490DB6F83 for ; Fri, 8 Apr 2011 07:33:13 +1000 (EST) Received: (qmail 17213 invoked by alias); 7 Apr 2011 21:33:10 -0000 Received: (qmail 17138 invoked by uid 22791); 7 Apr 2011 21:33:00 -0000 X-SWARE-Spam-Status: No, hits=-6.2 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_CX, TW_VF, TW_WR, 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; Thu, 07 Apr 2011 21:32:46 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p37LWjl9008868 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 7 Apr 2011 17:32:45 -0400 Received: from [127.0.0.1] (ovpn-113-53.phx2.redhat.com [10.3.113.53]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p37LWiX6031528 for ; Thu, 7 Apr 2011 17:32:44 -0400 Message-ID: <4D9E2D7B.508@redhat.com> Date: Thu, 07 Apr 2011 17:32:43 -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: Many C++ PATCHes for SFINAE fixes 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 People have been finding other places where we haven't been handling SFINAE properly. In many cases, there are two patches for each fix; the first one fixes the bug conservatively (for possible application to 4.6), and the second one reorganizes things to be cleaner. Tested x86_64-pc-linux-gnu, applying to trunk. commit 441f2c6d80756bed9c72aba05a315c34f2db2343 Author: Jason Merrill Date: Sun Apr 3 11:42:47 2011 -0400 * semantics.c (finish_decltype_type): Add complain parm. * cp-tree.h: Adjust. * parser.c (cp_parser_decltype): Adjust. * pt.c (tsubst): Adjust. commit c02c3cbfe41af41ffdb8a729c763b395c14979b3 Author: Jason Merrill Date: Mon Apr 4 17:18:38 2011 -0400 * semantics.c (finish_decltype_type): Simplify handling of unknown type. diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 80ec028..5cbba33 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4788,7 +4788,6 @@ tree finish_decltype_type (tree expr, bool id_expression_or_member_access_p, tsubst_flags_t complain) { - tree orig_expr = expr; tree type = NULL_TREE; if (!expr || error_operand_p (expr)) @@ -4826,6 +4825,13 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, expr = resolve_nondeduced_context (expr); + if (type_unknown_p (expr)) + { + if (complain & tf_error) + error ("decltype cannot resolve address of overloaded function"); + return error_mark_node; + } + /* To get the size of a static data member declared as an array of unknown bound, we need to instantiate it. */ if (TREE_CODE (expr) == VAR_DECL @@ -4855,28 +4861,9 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, expr = TREE_OPERAND (expr, 1); if (TREE_CODE (expr) == BASELINK) - /* See through BASELINK nodes to the underlying functions. */ + /* See through BASELINK nodes to the underlying function. */ expr = BASELINK_FUNCTIONS (expr); - if (TREE_CODE (expr) == TEMPLATE_ID_EXPR) - expr = TREE_OPERAND (expr, 0); - - if (TREE_CODE (expr) == OVERLOAD) - { - if (OVL_CHAIN (expr) - || TREE_CODE (OVL_FUNCTION (expr)) == TEMPLATE_DECL) - { - if (complain & tf_error) - error ("%qE refers to a set of overloaded functions", - orig_expr); - return error_mark_node; - } - else - /* An overload set containing only one function: just look - at that function. */ - expr = OVL_FUNCTION (expr); - } - switch (TREE_CODE (expr)) { case FIELD_DECL: @@ -4918,10 +4905,7 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, break; default: - gcc_assert (TYPE_P (expr) || DECL_P (expr) - || TREE_CODE (expr) == SCOPE_REF); - if (complain & tf_error) - error ("argument to decltype must be an expression"); + gcc_unreachable (); return error_mark_node; } } @@ -4957,13 +4941,6 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, } } - if (!type || type == unknown_type_node) - { - if (complain & tf_error) - error ("type of %qE is unknown", expr); - return error_mark_node; - } - return type; } commit a4a17314e1356211a523d0673e0d3a83a11b2338 Author: Jason Merrill Date: Mon Apr 4 20:48:54 2011 -0400 PR c++/48449 * typeck2.c (build_functional_cast): Check complain consistently. Use build_value_init and abstract_virtuals_error_sfinae. (abstract_virtuals_error_sfinae): Split out. * cp-tree.h: Declare it. * init.c (build_new_1): Use it. (build_value_init_noctor): Handle FUNCTION_TYPE. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 06b0b3e..94bd3ce 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5596,6 +5596,7 @@ extern tree binfo_or_else (tree, tree); extern void cxx_readonly_error (tree, enum lvalue_use); extern void complete_type_check_abstract (tree); extern int abstract_virtuals_error (tree, tree); +extern int abstract_virtuals_error_sfinae (tree, tree, tsubst_flags_t); extern tree store_init_value (tree, tree, int); extern void check_narrowing (tree, tree); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index e1961c8..2e9eb680 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -458,6 +458,12 @@ build_value_init_noctor (tree type, tsubst_flags_t complain) /* Build a constructor to contain the initializations. */ return build_constructor (type, v); } + else if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (complain & tf_error) + error ("value-initialization of function type %qT", type); + return error_mark_node; + } return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false); } @@ -2030,7 +2036,7 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, return error_mark_node; } - if (abstract_virtuals_error (NULL_TREE, elt_type)) + if (abstract_virtuals_error_sfinae (NULL_TREE, elt_type, complain)) return error_mark_node; is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || *init != NULL); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 82218f0..f2046f7 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -250,7 +250,7 @@ complete_type_check_abstract (tree type) occurred; zero if all was well. */ int -abstract_virtuals_error (tree decl, tree type) +abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain) { VEC(tree,gc) *pure; @@ -301,11 +301,14 @@ abstract_virtuals_error (tree decl, tree type) if (!pure) return 0; + if (decl && TREE_CODE (decl) == RESULT_DECL) + return 0; + + if (!(complain & tf_error)) + return 1; + if (decl) { - if (TREE_CODE (decl) == RESULT_DECL) - return 0; - if (TREE_CODE (decl) == VAR_DECL) error ("cannot declare variable %q+D to be of abstract " "type %qT", decl, type); @@ -354,6 +357,14 @@ abstract_virtuals_error (tree decl, tree type) return 1; } +/* Wrapper for the above function in the common case of wanting errors. */ + +int +abstract_virtuals_error (tree decl, tree type) +{ + return abstract_virtuals_error_sfinae (decl, type, tf_warning_or_error); +} + /* Print an error message for invalid use of an incomplete type. VALUE is the expression that was used (or 0 if that isn't known) and TYPE is the type that was invalid. DIAG_KIND indicates the @@ -1527,7 +1538,8 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain) if (TREE_CODE (type) == REFERENCE_TYPE && !parms) { - error ("invalid value-initialization of reference type"); + if (complain & tf_error) + error ("invalid value-initialization of reference type"); return error_mark_node; } @@ -1542,7 +1554,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain) if (! MAYBE_CLASS_TYPE_P (type)) { if (parms == NULL_TREE) - return cp_convert (type, integer_zero_node); + return build_value_init (type, complain); /* This must build a C cast. */ parms = build_x_compound_expr_from_list (parms, ELK_FUNC_CAST, complain); @@ -1558,7 +1570,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain) if (!complete_type_or_maybe_complain (type, NULL_TREE, complain)) return error_mark_node; - if (abstract_virtuals_error (NULL_TREE, type)) + if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain)) return error_mark_node; /* [expr.type.conv] diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae8.C b/gcc/testsuite/g++.dg/cpp0x/sfinae8.C new file mode 100644 index 0000000..7f3012f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae8.C @@ -0,0 +1,14 @@ +// PR c++/48449 +// { dg-options -std=c++0x } + +template +char f(int); + +template +char (&f(...))[2]; + +struct A { virtual ~A() = 0; }; + +static_assert(sizeof(f(0)) != 1, "Error"); +static_assert(sizeof(f(0)) != 1, "Error"); +static_assert(sizeof(f(0)) != 1, "Error"); commit d8489e38cc7e65238665e0321650f356509cb03e Author: Jason Merrill Date: Thu Apr 7 17:11:44 2011 -0400 * init.c (build_value_init_noctor): Handle REFERENCE_TYPE at top level. (perform_member_init): Not here. * typeck2.c (build_functional_cast): Limit REFERENCE_TYPE special case to templates. (abstract_virtuals_error_sfinae): Remove RESULT_DECL special case. diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 2e9eb680..005f8d6 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -388,14 +388,6 @@ build_value_init_noctor (tree type, tsubst_flags_t complain) ftype = TREE_TYPE (field); - if (TREE_CODE (ftype) == REFERENCE_TYPE) - { - 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 performance at all; it should be simpler in general just @@ -408,6 +400,9 @@ build_value_init_noctor (tree type, tsubst_flags_t complain) all of the subobjects. */ value = build_value_init (ftype, complain); + if (value == error_mark_node) + return error_mark_node; + if (value) CONSTRUCTOR_APPEND_ELT(v, field, value); } @@ -450,6 +445,9 @@ build_value_init_noctor (tree type, tsubst_flags_t complain) ce->value = build_value_init (TREE_TYPE (type), complain); + if (ce->value == error_mark_node) + return error_mark_node; + /* The gimplifier can't deal with a RANGE_EXPR of TARGET_EXPRs. */ gcc_assert (TREE_CODE (ce->value) != TARGET_EXPR && TREE_CODE (ce->value) != AGGR_INIT_EXPR); @@ -464,6 +462,12 @@ build_value_init_noctor (tree type, tsubst_flags_t complain) error ("value-initialization of function type %qT", type); return error_mark_node; } + else if (TREE_CODE (type) == REFERENCE_TYPE) + { + if (complain & tf_error) + error ("value-initialization of reference type %qT", type); + return error_mark_node; + } return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false); } @@ -504,16 +508,9 @@ perform_member_init (tree member, tree init) } else { - if (TREE_CODE (type) == REFERENCE_TYPE) - permerror (DECL_SOURCE_LOCATION (current_function_decl), - "value-initialization of %q#D, which has reference type", - member); - else - { - init = build2 (INIT_EXPR, type, decl, - build_value_init (type, tf_warning_or_error)); - finish_expr_stmt (init); - } + init = build2 (INIT_EXPR, type, decl, + build_value_init (type, tf_warning_or_error)); + finish_expr_stmt (init); } } /* Deal with this here, as we will get confused if we try to call the diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index f2046f7..f3a0079 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -301,9 +301,6 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain) if (!pure) return 0; - if (decl && TREE_CODE (decl) == RESULT_DECL) - return 0; - if (!(complain & tf_error)) return 1; @@ -1536,16 +1533,21 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain) else type = exp; - if (TREE_CODE (type) == REFERENCE_TYPE && !parms) - { - if (complain & tf_error) - error ("invalid value-initialization of reference type"); - return error_mark_node; - } - if (processing_template_decl) { - tree t = build_min (CAST_EXPR, type, parms); + tree t; + + /* Diagnose this even in a template. We could also try harder + to give all the usual errors when the type and args are + non-dependent... */ + if (TREE_CODE (type) == REFERENCE_TYPE && !parms) + { + if (complain & tf_error) + error ("invalid value-initialization of reference type"); + return error_mark_node; + } + + t = build_min (CAST_EXPR, type, parms); /* We don't know if it will or will not have side effects. */ TREE_SIDE_EFFECTS (t) = 1; return t; commit c1fb6653e14d8922f140569b606d681906779984 Author: Jason Merrill Date: Tue Apr 5 14:19:56 2011 -0400 PR c++/48450 * tree.c (build_cplus_new, build_aggr_init_expr): Take complain. (bot_manip): Adjust. * cp-tree.h: Adjust. * call.c (convert_like_real, build_cxx_call): Adjust. (perform_direct_initialization_if_possible): Adjust. * cvt.c (ocp_convert): Adjust. * init.c (build_value_init): Adjust. * semantics.c (maybe_add_lambda_conv_op): Adjust. * typeck.c (unary_complex_lvalue, cp_build_modify_expr): Adjust. * typeck2.c (build_functional_cast): Adjust. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index ad2de43..c273027 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5414,7 +5414,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, we need to build up a TARGET_EXPR. */ if (DECL_CONSTRUCTOR_P (convfn)) { - expr = build_cplus_new (totype, expr); + expr = build_cplus_new (totype, expr, complain); /* Remember that this was list-initialization. */ if (convs->check_narrowing) @@ -5559,7 +5559,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, else if (diag_kind == DK_ERROR) return error_mark_node; } - return build_cplus_new (totype, expr); + return build_cplus_new (totype, expr, complain); case ck_ref_bind: { @@ -6476,7 +6476,7 @@ build_cxx_call (tree fn, int nargs, tree *argarray) return error_mark_node; if (MAYBE_CLASS_TYPE_P (TREE_TYPE (fn))) - fn = build_cplus_new (TREE_TYPE (fn), fn); + fn = build_cplus_new (TREE_TYPE (fn), fn, tf_warning_or_error); return convert_from_reference (fn); } @@ -8119,7 +8119,7 @@ perform_direct_initialization_if_possible (tree type, expr = build_special_member_call (NULL_TREE, complete_ctor_identifier, &args, type, LOOKUP_NORMAL, complain); release_tree_vector (args); - return build_cplus_new (type, expr); + return build_cplus_new (type, expr, complain); } /* Get the high-water mark for the CONVERSION_OBSTACK. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 94bd3ce..ea251a8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5395,8 +5395,8 @@ extern tree build_min (enum tree_code, tree, ...); extern tree build_min_nt (enum tree_code, ...); extern tree build_min_non_dep (enum tree_code, tree, ...); extern tree build_min_non_dep_call_vec (tree, tree, VEC(tree,gc) *); -extern tree build_cplus_new (tree, tree); -extern tree build_aggr_init_expr (tree, tree); +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 build_cplus_array_type (tree, tree); extern tree build_array_of_n_type (tree, int); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 8ab0001..46c6eb4 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -813,7 +813,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags) release_tree_vector (ctor_vec); } if (ctor) - return build_cplus_new (type, ctor); + return build_cplus_new (type, ctor, tf_warning_or_error); } if (flags & LOOKUP_COMPLAIN) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 005f8d6..3131690 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -342,7 +342,8 @@ build_value_init (tree type, tsubst_flags_t complain) (type, build_special_member_call (NULL_TREE, complete_ctor_identifier, NULL, type, LOOKUP_NORMAL, - complain)); + complain), + complain); else if (TREE_CODE (type) != UNION_TYPE && TYPE_NEEDS_CONSTRUCTING (type)) { /* This is a class that needs constructing, but doesn't have @@ -354,7 +355,7 @@ build_value_init (tree type, tsubst_flags_t complain) NULL, type, LOOKUP_NORMAL, complain); if (ctor != error_mark_node) { - ctor = build_aggr_init_expr (type, ctor); + ctor = build_aggr_init_expr (type, ctor, complain); AGGR_INIT_ZERO_FIRST (ctor) = 1; } return ctor; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 5cbba33..30175af 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8429,7 +8429,7 @@ maybe_add_lambda_conv_op (tree type) VEC_address (tree, argvec)); CALL_FROM_THUNK_P (call) = 1; if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call))) - call = build_cplus_new (TREE_TYPE (call), call); + call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error); call = convert_from_reference (call); finish_return_stmt (call); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 070ba81..c2aa389 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -373,7 +373,7 @@ build_aggr_init_array (tree return_type, tree fn, tree slot, int nargs, callable. */ tree -build_aggr_init_expr (tree type, tree init) +build_aggr_init_expr (tree type, tree init, tsubst_flags_t complain) { tree fn; tree slot; @@ -382,7 +382,9 @@ build_aggr_init_expr (tree type, tree init) /* Make sure that we're not trying to create an instance of an abstract class. */ - abstract_virtuals_error (NULL_TREE, type); + if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain) + && !(complain & tf_error)) + return error_mark_node; if (TREE_CODE (init) == CALL_EXPR) fn = CALL_EXPR_FN (init); @@ -437,9 +439,9 @@ build_aggr_init_expr (tree type, tree init) and language-specific expression expanders. */ tree -build_cplus_new (tree type, tree init) +build_cplus_new (tree type, tree init, tsubst_flags_t complain) { - tree rval = build_aggr_init_expr (type, init); + tree rval = build_aggr_init_expr (type, init, complain); tree slot; if (TREE_CODE (rval) == AGGR_INIT_EXPR) @@ -1805,7 +1807,8 @@ bot_manip (tree* tp, int* walk_subtrees, void* data) tree u; if (TREE_CODE (TREE_OPERAND (t, 1)) == AGGR_INIT_EXPR) - u = build_cplus_new (TREE_TYPE (t), TREE_OPERAND (t, 1)); + 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)); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index a45ed2d..71cfd8c 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5320,7 +5320,7 @@ unary_complex_lvalue (enum tree_code code, tree arg) if (TREE_CODE (arg) == SAVE_EXPR) targ = arg; else - targ = build_cplus_new (TREE_TYPE (arg), arg); + targ = build_cplus_new (TREE_TYPE (arg), arg, tf_warning_or_error); return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (arg)), targ); } @@ -6742,7 +6742,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs, { if (TREE_CODE (newrhs) == CALL_EXPR && TYPE_NEEDS_CONSTRUCTING (lhstype)) - newrhs = build_cplus_new (lhstype, newrhs); + newrhs = build_cplus_new (lhstype, newrhs, complain); /* Can't initialize directly from a TARGET_EXPR, since that would cause the lhs to be constructed twice, and possibly result in diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index f3a0079..f67073b 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1614,7 +1614,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain) if (exp == error_mark_node) return error_mark_node; - return build_cplus_new (type, exp); + return build_cplus_new (type, exp, complain); } commit a6b0d17f42b4bb62fe638253cb8e032d416eb883 Author: Jason Merrill Date: Wed Apr 6 00:27:18 2011 -0400 * tree.c (build_aggr_init_expr): Always return error_mark_node on abstract violation. diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index c2aa389..014986d 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -382,8 +382,7 @@ build_aggr_init_expr (tree type, tree init, tsubst_flags_t complain) /* Make sure that we're not trying to create an instance of an abstract class. */ - if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain) - && !(complain & tf_error)) + if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain)) return error_mark_node; if (TREE_CODE (init) == CALL_EXPR) commit e55c94447e50bdfaa1ca5c06ce57896364cbfeaf Author: Jason Merrill Date: Tue Apr 5 14:28:59 2011 -0400 PR c++/48450 * typeck.c (check_for_casting_away_constness): Take complain. (build_static_cast_1, build_reinterpret_cast_1): Pass it. (build_const_cast_1): Pass it. Take full complain parm. (build_const_cast, cp_build_c_cast): Adjust. diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 71cfd8c..8e3796e 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5579,42 +5579,47 @@ cp_build_compound_expr (tree lhs, tree rhs, tsubst_flags_t complain) } /* Issue a diagnostic message if casting from SRC_TYPE to DEST_TYPE - casts away constness. CAST gives the type of cast. + casts away constness. CAST gives the type of cast. Returns true + if the cast is ill-formed, false if it is well-formed. ??? This function warns for casting away any qualifier not just const. We would like to specify exactly what qualifiers are casted away. */ -static void +static bool check_for_casting_away_constness (tree src_type, tree dest_type, - enum tree_code cast) + enum tree_code cast, tsubst_flags_t complain) { /* C-style casts are allowed to cast away constness. With WARN_CAST_QUAL, we still want to issue a warning. */ if (cast == CAST_EXPR && !warn_cast_qual) - return; + return false; if (!casts_away_constness (src_type, dest_type)) - return; + return false; switch (cast) { case CAST_EXPR: - warning (OPT_Wcast_qual, - "cast from type %qT to type %qT casts away qualifiers", - src_type, dest_type); - return; + if (complain & tf_warning) + warning (OPT_Wcast_qual, + "cast from type %qT to type %qT casts away qualifiers", + src_type, dest_type); + return false; case STATIC_CAST_EXPR: - error ("static_cast from type %qT to type %qT casts away qualifiers", - src_type, dest_type); - return; + if (complain & tf_error) + error ("static_cast from type %qT to type %qT casts away qualifiers", + src_type, dest_type); + return true; case REINTERPRET_CAST_EXPR: - error ("reinterpret_cast from type %qT to type %qT casts away qualifiers", - src_type, dest_type); - return; + if (complain & tf_error) + error ("reinterpret_cast from type %qT to type %qT casts away qualifiers", + src_type, dest_type); + return true; + default: gcc_unreachable(); } @@ -5832,8 +5837,10 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p, { tree base; - if (!c_cast_p) - check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR); + if (!c_cast_p + && check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR, + complain)) + return error_mark_node; base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), c_cast_p ? ba_unique : ba_check, NULL); @@ -5868,10 +5875,13 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p, } if (can_convert (t1, t2) || can_convert (t2, t1)) { - if (!c_cast_p) - check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR); + if (!c_cast_p + && check_for_casting_away_constness (intype, type, + STATIC_CAST_EXPR, + complain)) + return error_mark_node; return convert_ptrmem (type, expr, /*allow_inverse_p=*/1, - c_cast_p, tf_warning_or_error); + c_cast_p, complain); } } @@ -5885,8 +5895,10 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p, && VOID_TYPE_P (TREE_TYPE (intype)) && TYPE_PTROB_P (type)) { - if (!c_cast_p) - check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR); + if (!c_cast_p + && check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR, + complain)) + return error_mark_node; return build_nop (type, expr); } @@ -6090,8 +6102,11 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, { tree sexpr = expr; - if (!c_cast_p) - check_for_casting_away_constness (intype, type, REINTERPRET_CAST_EXPR); + if (!c_cast_p + && check_for_casting_away_constness (intype, type, + REINTERPRET_CAST_EXPR, + complain)) + return error_mark_node; /* Warn about possible alignment problems. */ if (STRICT_ALIGNMENT && warn_cast_align && (complain & tf_warning) @@ -6168,7 +6183,7 @@ build_reinterpret_cast (tree type, tree expr, tsubst_flags_t complain) whether or not the conversion succeeded. */ static tree -build_const_cast_1 (tree dst_type, tree expr, bool complain, +build_const_cast_1 (tree dst_type, tree expr, tsubst_flags_t complain, bool *valid_p) { tree src_type; @@ -6187,7 +6202,7 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain, if (!POINTER_TYPE_P (dst_type) && !TYPE_PTRMEM_P (dst_type)) { - if (complain) + if (complain & tf_error) error ("invalid use of const_cast with type %qT, " "which is not a pointer, " "reference, nor a pointer-to-data-member type", dst_type); @@ -6196,7 +6211,7 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain, if (TREE_CODE (TREE_TYPE (dst_type)) == FUNCTION_TYPE) { - if (complain) + if (complain & tf_error) error ("invalid use of const_cast with type %qT, which is a pointer " "or reference to a function type", dst_type); return error_mark_node; @@ -6221,7 +6236,7 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain, reference_type = dst_type; if (! real_lvalue_p (expr)) { - if (complain) + if (complain & tf_error) error ("invalid const_cast of an rvalue of type %qT to type %qT", src_type, dst_type); return error_mark_node; @@ -6248,12 +6263,12 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain, *valid_p = true; /* This cast is actually a C-style cast. Issue a warning if the user is making a potentially unsafe cast. */ - check_for_casting_away_constness (src_type, dst_type, CAST_EXPR); + check_for_casting_away_constness (src_type, dst_type, CAST_EXPR, + complain); } if (reference_type) { - expr = cp_build_addr_expr (expr, - complain ? tf_warning_or_error : tf_none); + expr = cp_build_addr_expr (expr, complain); expr = build_nop (reference_type, expr); return convert_from_reference (expr); } @@ -6270,7 +6285,7 @@ build_const_cast_1 (tree dst_type, tree expr, bool complain, } } - if (complain) + if (complain & tf_error) error ("invalid const_cast from type %qT to type %qT", src_type, dst_type); return error_mark_node; @@ -6293,7 +6308,7 @@ build_const_cast (tree type, tree expr, tsubst_flags_t complain) return convert_from_reference (t); } - return build_const_cast_1 (type, expr, complain & tf_error, + return build_const_cast_1 (type, expr, complain, /*valid_p=*/NULL); } @@ -6379,7 +6394,7 @@ cp_build_c_cast (tree type, tree expr, tsubst_flags_t complain) "cast to pointer from integer of different size"); /* A C-style cast can be a const_cast. */ - result = build_const_cast_1 (type, value, /*complain=*/false, + result = build_const_cast_1 (type, value, complain & tf_warning, &valid_p); if (valid_p) return result; diff --git a/gcc/testsuite/c-c++-common/Wcast-qual-1.c b/gcc/testsuite/c-c++-common/Wcast-qual-1.c new file mode 100644 index 0000000..640e4f0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wcast-qual-1.c @@ -0,0 +1,162 @@ +/* { dg-do compile } */ +/* { dg-options "-Wcast-qual" } */ + +void +f1 (void *bar) +{ + const void *p1 = (const void *) bar; + const char *p2 = (const char *) bar; + const void **p3 = (const void **) bar; + const char **p4 = (const char **) bar; + const void * const *p5 = (const void * const *) bar; + const char * const *p6 = (const char * const *) bar; + void * const *p7 = (void * const *) bar; + char * const *p8 = (char * const *) bar; + const void ***p9 = (const void ***) bar; + const char ***p10 = (const char ***) bar; + void * const **p11 = (void * const **) bar; + char * const **p12 = (char * const **) bar; + void ** const *p13 = (void ** const *) bar; + char ** const *p14 = (char ** const *) bar; + const void * const **p15 = (const void * const **) bar; + const char * const **p16 = (const char * const **) bar; + const void ** const *p17 = (const void ** const *) bar; + const char ** const *p18 = (const char ** const *) bar; + void * const * const * p19 = (void * const * const *) bar; + char * const * const * p20 = (char * const * const *) bar; + const void * const * const *p21 = (const void * const * const *) bar; + const char * const * const *p22 = (const char * const * const *) bar; +} + +void +f2 (void **bar) +{ + const void *p1 = (const void *) bar; + const char *p2 = (const char *) bar; + const void **p3 = (const void **) bar; /* { dg-warning "cast" } */ + const char **p4 = (const char **) bar; + const void * const *p5 = (const void * const *) bar; + const char * const *p6 = (const char * const *) bar; + void * const *p7 = (void * const *) bar; + char * const *p8 = (char * const *) bar; + const void ***p9 = (const void ***) bar; + const char ***p10 = (const char ***) bar; + void * const **p11 = (void * const **) bar; + char * const **p12 = (char * const **) bar; + void ** const *p13 = (void ** const *) bar; + char ** const *p14 = (char ** const *) bar; + const void * const **p15 = (const void * const **) bar; + const char * const **p16 = (const char * const **) bar; + const void ** const *p17 = (const void ** const *) bar; + const char ** const *p18 = (const char ** const *) bar; + void * const * const * p19 = (void * const * const *) bar; + char * const * const * p20 = (char * const * const *) bar; + const void * const * const *p21 = (const void * const * const *) bar; + const char * const * const *p22 = (const char * const * const *) bar; +} + +void +f3 (void ***bar) +{ + const void *p1 = (const void *) bar; + const char *p2 = (const char *) bar; + const void **p3 = (const void **) bar; + const char **p4 = (const char **) bar; + const void * const *p5 = (const void * const *) bar; + const char * const *p6 = (const char * const *) bar; + void * const *p7 = (void * const *) bar; + char * const *p8 = (char * const *) bar; + const void ***p9 = (const void ***) bar; /* { dg-warning "cast" } */ + const char ***p10 = (const char ***) bar; + void * const **p11 = (void * const **) bar; /* { dg-warning "cast" } */ + char * const **p12 = (char * const **) bar; + void ** const *p13 = (void ** const *) bar; + char ** const *p14 = (char ** const *) bar; + const void * const **p15 = (const void * const **) bar; /* { dg-warning "cast" } */ + const char * const **p16 = (const char * const **) bar; + const void ** const *p17 = (const void ** const *) bar; /* { dg-warning "cast" } */ + const char ** const *p18 = (const char ** const *) bar; + void * const * const * p19 = (void * const * const *) bar; + char * const * const * p20 = (char * const * const *) bar; + const void * const * const *p21 = (const void * const * const *) bar; + const char * const * const *p22 = (const char * const * const *) bar; +} + +void +f4 (void * const **bar) +{ + const void ***p9 = (const void ***) bar; /* { dg-warning "cast" } */ + void * const **p11 = (void * const **) bar; + void ** const *p13 = (void ** const *) bar; /* { dg-warning "cast" } */ + const void * const **p15 = (const void * const **) bar; /* { dg-warning "cast" } */ + const void ** const *p17 = (const void ** const *) bar; /* { dg-warning "cast" } */ + void * const * const * p19 = (void * const * const *) bar; + const void * const * const *p21 = (const void * const * const *) bar; +} + +void +f5 (char ***bar) +{ + volatile const char ***p9 = (volatile const char ***) bar; /* { dg-warning "cast" } */ + volatile char * const **p11 = (volatile char * const **) bar; /* { dg-warning "cast" } */ + volatile char ** const *p13 = (volatile char ** const *) bar; /* { dg-warning "cast" } */ + volatile const char * const **p15 = (volatile const char * const **) bar; /* { dg-warning "cast" } */ + volatile const char ** const *p17 = (volatile const char ** const *) bar; /* { dg-warning "cast" } */ + volatile char * const * const * p19 = (volatile char * const * const *) bar; + volatile const char * const * const *p21 = (volatile const char * const * const *) bar; +} + +void +f6 (char ***bar) +{ + const char * volatile **p9 = (const char * volatile **) bar; /* { dg-warning "cast" } */ + char * volatile const **p11 = (char * volatile const **) bar; /* { dg-warning "cast" } */ + char * volatile * const *p13 = (char * volatile * const *) bar; + const char * volatile const **p15 = (const char * volatile const **) bar; /* { dg-warning "cast" } */ + const char * volatile * const *p17 = (const char * volatile * const *) bar; /* { dg-warning "cast" } */ + char * volatile const * const * p19 = (char * volatile const * const *) bar; + const char * volatile const * const *p21 = (const char * volatile const * const *) bar; +} + +void +f7 (char ***bar) +{ + const char ** volatile *p9 = (const char ** volatile *) bar; /* { dg-warning "cast" } */ + char * const * volatile *p11 = (char * const * volatile *) bar; /* { dg-warning "cast" } */ + char ** volatile const *p13 = (char ** volatile const *) bar; + const char * const * volatile *p15 = (const char * const * volatile *) bar; /* { dg-warning "cast" } */ + const char ** volatile const *p17 = (const char ** volatile const *) bar; /* { dg-warning "cast" } */ + char * const * volatile const * p19 = (char * const * volatile const *) bar; + const char * const * volatile const *p21 = (const char * const * volatile const *) bar; +} + +typedef int (intfn) (int); +typedef intfn *pintfn; +typedef const intfn *constfn; + +void +f8 (constfn ***bar) +{ + const constfn *p1 = (const constfn *) bar; + const pintfn *p2 = (const pintfn *) bar; + const constfn **p3 = (const constfn **) bar; + const pintfn **p4 = (const pintfn **) bar; + const constfn * const *p5 = (const constfn * const *) bar; + const pintfn * const *p6 = (const pintfn * const *) bar; + constfn * const *p7 = (constfn * const *) bar; + pintfn * const *p8 = (pintfn * const *) bar; + const constfn ***p9 = (const constfn ***) bar; /* { dg-warning "cast" } */ + const pintfn ***p10 = (const pintfn ***) bar; /* { dg-warning "cast" } */ + constfn * const **p11 = (constfn * const **) bar; /* { dg-warning "cast" } */ + pintfn * const **p12 = (pintfn * const **) bar; /* { dg-warning "cast" } */ + constfn ** const *p13 = (constfn ** const *) bar; + pintfn ** const *p14 = (pintfn ** const *) bar; + const constfn * const **p15 = (const constfn * const **) bar; /* { dg-warning "cast" } */ + const pintfn * const **p16 = (const pintfn * const **) bar; /* { dg-warning "cast" } */ + const constfn ** const *p17 = (const constfn ** const *) bar; /* { dg-warning "cast" } */ + const pintfn ** const *p18 = (const pintfn ** const *) bar; /* { dg-warning "cast" } */ + constfn * const * const * p19 = (constfn * const * const *) bar; + pintfn * const * const * p20 = (pintfn * const * const *) bar; + const constfn * const * const *p21 = (const constfn * const * const *) bar; + const pintfn * const * const *p22 = (const pintfn * const * const *) bar; +} diff --git a/gcc/testsuite/g++.dg/warn/Wcast-qual2.C b/gcc/testsuite/g++.dg/warn/Wcast-qual2.C deleted file mode 100644 index 88fdcfb..0000000 --- a/gcc/testsuite/g++.dg/warn/Wcast-qual2.C +++ /dev/null @@ -1,167 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-Wcast-qual" } */ - -/* The files gcc.dg/cast-qual-3.c and g++.dg/warn/Wcast-qual2.c are - duals. they are intended to show that gcc -Wcast-qual and g++ - -Wcast-qual emit warnings in the same cases. If you change this - file, please also change the other one. */ - -void -f1 (void *bar) -{ - const void *p1 = (const void *) bar; - const char *p2 = (const char *) bar; - const void **p3 = (const void **) bar; - const char **p4 = (const char **) bar; - const void * const *p5 = (const void * const *) bar; - const char * const *p6 = (const char * const *) bar; - void * const *p7 = (void * const *) bar; - char * const *p8 = (char * const *) bar; - const void ***p9 = (const void ***) bar; - const char ***p10 = (const char ***) bar; - void * const **p11 = (void * const **) bar; - char * const **p12 = (char * const **) bar; - void ** const *p13 = (void ** const *) bar; - char ** const *p14 = (char ** const *) bar; - const void * const **p15 = (const void * const **) bar; - const char * const **p16 = (const char * const **) bar; - const void ** const *p17 = (const void ** const *) bar; - const char ** const *p18 = (const char ** const *) bar; - void * const * const * p19 = (void * const * const *) bar; - char * const * const * p20 = (char * const * const *) bar; - const void * const * const *p21 = (const void * const * const *) bar; - const char * const * const *p22 = (const char * const * const *) bar; -} - -void -f2 (void **bar) -{ - const void *p1 = (const void *) bar; - const char *p2 = (const char *) bar; - const void **p3 = (const void **) bar; /* { dg-warning "cast" } */ - const char **p4 = (const char **) bar; - const void * const *p5 = (const void * const *) bar; - const char * const *p6 = (const char * const *) bar; - void * const *p7 = (void * const *) bar; - char * const *p8 = (char * const *) bar; - const void ***p9 = (const void ***) bar; - const char ***p10 = (const char ***) bar; - void * const **p11 = (void * const **) bar; - char * const **p12 = (char * const **) bar; - void ** const *p13 = (void ** const *) bar; - char ** const *p14 = (char ** const *) bar; - const void * const **p15 = (const void * const **) bar; - const char * const **p16 = (const char * const **) bar; - const void ** const *p17 = (const void ** const *) bar; - const char ** const *p18 = (const char ** const *) bar; - void * const * const * p19 = (void * const * const *) bar; - char * const * const * p20 = (char * const * const *) bar; - const void * const * const *p21 = (const void * const * const *) bar; - const char * const * const *p22 = (const char * const * const *) bar; -} - -void -f3 (void ***bar) -{ - const void *p1 = (const void *) bar; - const char *p2 = (const char *) bar; - const void **p3 = (const void **) bar; - const char **p4 = (const char **) bar; - const void * const *p5 = (const void * const *) bar; - const char * const *p6 = (const char * const *) bar; - void * const *p7 = (void * const *) bar; - char * const *p8 = (char * const *) bar; - const void ***p9 = (const void ***) bar; /* { dg-warning "cast" } */ - const char ***p10 = (const char ***) bar; - void * const **p11 = (void * const **) bar; /* { dg-warning "cast" } */ - char * const **p12 = (char * const **) bar; - void ** const *p13 = (void ** const *) bar; - char ** const *p14 = (char ** const *) bar; - const void * const **p15 = (const void * const **) bar; /* { dg-warning "cast" } */ - const char * const **p16 = (const char * const **) bar; - const void ** const *p17 = (const void ** const *) bar; /* { dg-warning "cast" } */ - const char ** const *p18 = (const char ** const *) bar; - void * const * const * p19 = (void * const * const *) bar; - char * const * const * p20 = (char * const * const *) bar; - const void * const * const *p21 = (const void * const * const *) bar; - const char * const * const *p22 = (const char * const * const *) bar; -} - -void -f4 (void * const **bar) -{ - const void ***p9 = (const void ***) bar; /* { dg-warning "cast" } */ - void * const **p11 = (void * const **) bar; - void ** const *p13 = (void ** const *) bar; /* { dg-warning "cast" } */ - const void * const **p15 = (const void * const **) bar; /* { dg-warning "cast" } */ - const void ** const *p17 = (const void ** const *) bar; /* { dg-warning "cast" } */ - void * const * const * p19 = (void * const * const *) bar; - const void * const * const *p21 = (const void * const * const *) bar; -} - -void -f5 (char ***bar) -{ - volatile const char ***p9 = (volatile const char ***) bar; /* { dg-warning "cast" } */ - volatile char * const **p11 = (volatile char * const **) bar; /* { dg-warning "cast" } */ - volatile char ** const *p13 = (volatile char ** const *) bar; /* { dg-warning "cast" } */ - volatile const char * const **p15 = (volatile const char * const **) bar; /* { dg-warning "cast" } */ - volatile const char ** const *p17 = (volatile const char ** const *) bar; /* { dg-warning "cast" } */ - volatile char * const * const * p19 = (volatile char * const * const *) bar; - volatile const char * const * const *p21 = (volatile const char * const * const *) bar; -} - -void -f6 (char ***bar) -{ - const char * volatile **p9 = (const char * volatile **) bar; /* { dg-warning "cast" } */ - char * volatile const **p11 = (char * volatile const **) bar; /* { dg-warning "cast" } */ - char * volatile * const *p13 = (char * volatile * const *) bar; - const char * volatile const **p15 = (const char * volatile const **) bar; /* { dg-warning "cast" } */ - const char * volatile * const *p17 = (const char * volatile * const *) bar; /* { dg-warning "cast" } */ - char * volatile const * const * p19 = (char * volatile const * const *) bar; - const char * volatile const * const *p21 = (const char * volatile const * const *) bar; -} - -void -f7 (char ***bar) -{ - const char ** volatile *p9 = (const char ** volatile *) bar; /* { dg-warning "cast" } */ - char * const * volatile *p11 = (char * const * volatile *) bar; /* { dg-warning "cast" } */ - char ** volatile const *p13 = (char ** volatile const *) bar; - const char * const * volatile *p15 = (const char * const * volatile *) bar; /* { dg-warning "cast" } */ - const char ** volatile const *p17 = (const char ** volatile const *) bar; /* { dg-warning "cast" } */ - char * const * volatile const * p19 = (char * const * volatile const *) bar; - const char * const * volatile const *p21 = (const char * const * volatile const *) bar; -} - -typedef int (intfn) (int); -typedef intfn *pintfn; -typedef const intfn *constfn; - -void -f8 (constfn ***bar) -{ - const constfn *p1 = (const constfn *) bar; - const pintfn *p2 = (const pintfn *) bar; - const constfn **p3 = (const constfn **) bar; - const pintfn **p4 = (const pintfn **) bar; - const constfn * const *p5 = (const constfn * const *) bar; - const pintfn * const *p6 = (const pintfn * const *) bar; - constfn * const *p7 = (constfn * const *) bar; - pintfn * const *p8 = (pintfn * const *) bar; - const constfn ***p9 = (const constfn ***) bar; /* { dg-warning "cast" } */ - const pintfn ***p10 = (const pintfn ***) bar; /* { dg-warning "cast" } */ - constfn * const **p11 = (constfn * const **) bar; /* { dg-warning "cast" } */ - pintfn * const **p12 = (pintfn * const **) bar; /* { dg-warning "cast" } */ - constfn ** const *p13 = (constfn ** const *) bar; - pintfn ** const *p14 = (pintfn ** const *) bar; - const constfn * const **p15 = (const constfn * const **) bar; /* { dg-warning "cast" } */ - const pintfn * const **p16 = (const pintfn * const **) bar; /* { dg-warning "cast" } */ - const constfn ** const *p17 = (const constfn ** const *) bar; /* { dg-warning "cast" } */ - const pintfn ** const *p18 = (const pintfn ** const *) bar; /* { dg-warning "cast" } */ - constfn * const * const * p19 = (constfn * const * const *) bar; - pintfn * const * const * p20 = (pintfn * const * const *) bar; - const constfn * const * const *p21 = (const constfn * const * const *) bar; - const pintfn * const * const *p22 = (const pintfn * const * const *) bar; -} diff --git a/gcc/testsuite/gcc.dg/cast-qual-3.c b/gcc/testsuite/gcc.dg/cast-qual-3.c deleted file mode 100644 index 88fdcfb..0000000 --- a/gcc/testsuite/gcc.dg/cast-qual-3.c +++ /dev/null @@ -1,167 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-Wcast-qual" } */ - -/* The files gcc.dg/cast-qual-3.c and g++.dg/warn/Wcast-qual2.c are - duals. they are intended to show that gcc -Wcast-qual and g++ - -Wcast-qual emit warnings in the same cases. If you change this - file, please also change the other one. */ - -void -f1 (void *bar) -{ - const void *p1 = (const void *) bar; - const char *p2 = (const char *) bar; - const void **p3 = (const void **) bar; - const char **p4 = (const char **) bar; - const void * const *p5 = (const void * const *) bar; - const char * const *p6 = (const char * const *) bar; - void * const *p7 = (void * const *) bar; - char * const *p8 = (char * const *) bar; - const void ***p9 = (const void ***) bar; - const char ***p10 = (const char ***) bar; - void * const **p11 = (void * const **) bar; - char * const **p12 = (char * const **) bar; - void ** const *p13 = (void ** const *) bar; - char ** const *p14 = (char ** const *) bar; - const void * const **p15 = (const void * const **) bar; - const char * const **p16 = (const char * const **) bar; - const void ** const *p17 = (const void ** const *) bar; - const char ** const *p18 = (const char ** const *) bar; - void * const * const * p19 = (void * const * const *) bar; - char * const * const * p20 = (char * const * const *) bar; - const void * const * const *p21 = (const void * const * const *) bar; - const char * const * const *p22 = (const char * const * const *) bar; -} - -void -f2 (void **bar) -{ - const void *p1 = (const void *) bar; - const char *p2 = (const char *) bar; - const void **p3 = (const void **) bar; /* { dg-warning "cast" } */ - const char **p4 = (const char **) bar; - const void * const *p5 = (const void * const *) bar; - const char * const *p6 = (const char * const *) bar; - void * const *p7 = (void * const *) bar; - char * const *p8 = (char * const *) bar; - const void ***p9 = (const void ***) bar; - const char ***p10 = (const char ***) bar; - void * const **p11 = (void * const **) bar; - char * const **p12 = (char * const **) bar; - void ** const *p13 = (void ** const *) bar; - char ** const *p14 = (char ** const *) bar; - const void * const **p15 = (const void * const **) bar; - const char * const **p16 = (const char * const **) bar; - const void ** const *p17 = (const void ** const *) bar; - const char ** const *p18 = (const char ** const *) bar; - void * const * const * p19 = (void * const * const *) bar; - char * const * const * p20 = (char * const * const *) bar; - const void * const * const *p21 = (const void * const * const *) bar; - const char * const * const *p22 = (const char * const * const *) bar; -} - -void -f3 (void ***bar) -{ - const void *p1 = (const void *) bar; - const char *p2 = (const char *) bar; - const void **p3 = (const void **) bar; - const char **p4 = (const char **) bar; - const void * const *p5 = (const void * const *) bar; - const char * const *p6 = (const char * const *) bar; - void * const *p7 = (void * const *) bar; - char * const *p8 = (char * const *) bar; - const void ***p9 = (const void ***) bar; /* { dg-warning "cast" } */ - const char ***p10 = (const char ***) bar; - void * const **p11 = (void * const **) bar; /* { dg-warning "cast" } */ - char * const **p12 = (char * const **) bar; - void ** const *p13 = (void ** const *) bar; - char ** const *p14 = (char ** const *) bar; - const void * const **p15 = (const void * const **) bar; /* { dg-warning "cast" } */ - const char * const **p16 = (const char * const **) bar; - const void ** const *p17 = (const void ** const *) bar; /* { dg-warning "cast" } */ - const char ** const *p18 = (const char ** const *) bar; - void * const * const * p19 = (void * const * const *) bar; - char * const * const * p20 = (char * const * const *) bar; - const void * const * const *p21 = (const void * const * const *) bar; - const char * const * const *p22 = (const char * const * const *) bar; -} - -void -f4 (void * const **bar) -{ - const void ***p9 = (const void ***) bar; /* { dg-warning "cast" } */ - void * const **p11 = (void * const **) bar; - void ** const *p13 = (void ** const *) bar; /* { dg-warning "cast" } */ - const void * const **p15 = (const void * const **) bar; /* { dg-warning "cast" } */ - const void ** const *p17 = (const void ** const *) bar; /* { dg-warning "cast" } */ - void * const * const * p19 = (void * const * const *) bar; - const void * const * const *p21 = (const void * const * const *) bar; -} - -void -f5 (char ***bar) -{ - volatile const char ***p9 = (volatile const char ***) bar; /* { dg-warning "cast" } */ - volatile char * const **p11 = (volatile char * const **) bar; /* { dg-warning "cast" } */ - volatile char ** const *p13 = (volatile char ** const *) bar; /* { dg-warning "cast" } */ - volatile const char * const **p15 = (volatile const char * const **) bar; /* { dg-warning "cast" } */ - volatile const char ** const *p17 = (volatile const char ** const *) bar; /* { dg-warning "cast" } */ - volatile char * const * const * p19 = (volatile char * const * const *) bar; - volatile const char * const * const *p21 = (volatile const char * const * const *) bar; -} - -void -f6 (char ***bar) -{ - const char * volatile **p9 = (const char * volatile **) bar; /* { dg-warning "cast" } */ - char * volatile const **p11 = (char * volatile const **) bar; /* { dg-warning "cast" } */ - char * volatile * const *p13 = (char * volatile * const *) bar; - const char * volatile const **p15 = (const char * volatile const **) bar; /* { dg-warning "cast" } */ - const char * volatile * const *p17 = (const char * volatile * const *) bar; /* { dg-warning "cast" } */ - char * volatile const * const * p19 = (char * volatile const * const *) bar; - const char * volatile const * const *p21 = (const char * volatile const * const *) bar; -} - -void -f7 (char ***bar) -{ - const char ** volatile *p9 = (const char ** volatile *) bar; /* { dg-warning "cast" } */ - char * const * volatile *p11 = (char * const * volatile *) bar; /* { dg-warning "cast" } */ - char ** volatile const *p13 = (char ** volatile const *) bar; - const char * const * volatile *p15 = (const char * const * volatile *) bar; /* { dg-warning "cast" } */ - const char ** volatile const *p17 = (const char ** volatile const *) bar; /* { dg-warning "cast" } */ - char * const * volatile const * p19 = (char * const * volatile const *) bar; - const char * const * volatile const *p21 = (const char * const * volatile const *) bar; -} - -typedef int (intfn) (int); -typedef intfn *pintfn; -typedef const intfn *constfn; - -void -f8 (constfn ***bar) -{ - const constfn *p1 = (const constfn *) bar; - const pintfn *p2 = (const pintfn *) bar; - const constfn **p3 = (const constfn **) bar; - const pintfn **p4 = (const pintfn **) bar; - const constfn * const *p5 = (const constfn * const *) bar; - const pintfn * const *p6 = (const pintfn * const *) bar; - constfn * const *p7 = (constfn * const *) bar; - pintfn * const *p8 = (pintfn * const *) bar; - const constfn ***p9 = (const constfn ***) bar; /* { dg-warning "cast" } */ - const pintfn ***p10 = (const pintfn ***) bar; /* { dg-warning "cast" } */ - constfn * const **p11 = (constfn * const **) bar; /* { dg-warning "cast" } */ - pintfn * const **p12 = (pintfn * const **) bar; /* { dg-warning "cast" } */ - constfn ** const *p13 = (constfn ** const *) bar; - pintfn ** const *p14 = (pintfn ** const *) bar; - const constfn * const **p15 = (const constfn * const **) bar; /* { dg-warning "cast" } */ - const pintfn * const **p16 = (const pintfn * const **) bar; /* { dg-warning "cast" } */ - const constfn ** const *p17 = (const constfn ** const *) bar; /* { dg-warning "cast" } */ - const pintfn ** const *p18 = (const pintfn ** const *) bar; /* { dg-warning "cast" } */ - constfn * const * const * p19 = (constfn * const * const *) bar; - pintfn * const * const * p20 = (pintfn * const * const *) bar; - const constfn * const * const *p21 = (const constfn * const * const *) bar; - const pintfn * const * const *p22 = (const pintfn * const * const *) bar; -} commit dae42c0509e234d0cbcb148d35b9aeb35b3cf5fa Author: Jason Merrill Date: Tue Apr 5 14:31:54 2011 -0400 PR c++/48450 * call.c (resolve_args): Take complain. (build_new_function_call, build_operator_new_call): Pass it. (build_op_call, build_new_op, build_new_method_call): Pass it. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index c273027..f283bd1 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -155,7 +155,6 @@ static tree convert_like_real (conversion *, tree, tree, int, int, bool, bool, tsubst_flags_t); static void op_error (enum tree_code, enum tree_code, tree, tree, tree, bool); -static VEC(tree,gc) *resolve_args (VEC(tree,gc) *); static struct z_candidate *build_user_type_conversion_1 (tree, tree, int); static void print_z_candidate (const char *, struct z_candidate *); static void print_z_candidates (location_t, struct z_candidate *); @@ -3525,7 +3524,7 @@ build_integral_nontype_arg_conv (tree type, tree expr, tsubst_flags_t complain) /* Do any initial processing on the arguments to a function call. */ static VEC(tree,gc) * -resolve_args (VEC(tree,gc) *args) +resolve_args (VEC(tree,gc) *args, tsubst_flags_t complain) { unsigned int ix; tree arg; @@ -3536,7 +3535,8 @@ resolve_args (VEC(tree,gc) *args) return NULL; else if (VOID_TYPE_P (TREE_TYPE (arg))) { - error ("invalid use of void expression"); + if (complain & tf_error) + error ("invalid use of void expression"); return NULL; } else if (invalid_nonstatic_memfn_p (arg, tf_warning_or_error)) @@ -3636,7 +3636,7 @@ build_new_function_call (tree fn, VEC(tree,gc) **args, bool koenig_p, if (args != NULL && *args != NULL) { - *args = resolve_args (*args); + *args = resolve_args (*args, complain); if (*args == NULL) return error_mark_node; } @@ -3707,7 +3707,7 @@ build_operator_new_call (tree fnname, VEC(tree,gc) **args, if (fn) *fn = NULL_TREE; VEC_safe_insert (tree, gc, *args, 0, *size); - *args = resolve_args (*args); + *args = resolve_args (*args, tf_warning_or_error); if (*args == NULL) return error_mark_node; @@ -3820,7 +3820,7 @@ build_op_call (tree obj, VEC(tree,gc) **args, tsubst_flags_t complain) if (args != NULL && *args != NULL) { - *args = resolve_args (*args); + *args = resolve_args (*args, complain); if (*args == NULL) return error_mark_node; } @@ -4864,7 +4864,7 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, if (overloaded_p) *overloaded_p = true; - if (resolve_args (arglist) == NULL) + if (resolve_args (arglist, complain) == NULL) result = error_mark_node; else result = build_over_call (cand, LOOKUP_NORMAL, complain); @@ -6850,7 +6850,7 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args, /* Process the argument list. */ if (args != NULL && *args != NULL) { - *args = resolve_args (*args); + *args = resolve_args (*args, complain); if (*args == NULL) return error_mark_node; } commit 9690fccd312c95916260a0ba5f07e397af811b37 Author: Jason Merrill Date: Tue Apr 5 22:02:35 2011 -0400 PR c++/48452 * typeck.c (build_x_compound_expr_from_list): Return error_mark_node in SFINAE context. diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 8e3796e..ecd7d41 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5472,6 +5472,8 @@ build_x_compound_expr_from_list (tree list, expr_list_kind exp, default: gcc_unreachable (); } + else + return error_mark_node; for (list = TREE_CHAIN (list); list; list = TREE_CHAIN (list)) expr = build_x_compound_expr (expr, TREE_VALUE (list), diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae10.C b/gcc/testsuite/g++.dg/cpp0x/sfinae10.C new file mode 100644 index 0000000..ede8b70 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae10.C @@ -0,0 +1,18 @@ +// PR c++/48452 +// { dg-options -std=c++0x } +namespace std { + template T&& declval(); +} + +template +decltype(T(std::declval()...), char()) f(int); + +template +char (&f(...))[2]; + +struct A { virtual ~A() = 0; }; +struct B {}; + +static_assert(sizeof(f(0)) != 1, "Error"); // a +static_assert(sizeof(f(0)) != 1, "Error"); // b +static_assert(sizeof(f(0)) != 1, "Error"); // c commit 6248bb19d8ddf86496da79db44ec14f7cca6dcef Author: Jason Merrill Date: Wed Apr 6 09:39:28 2011 -0400 PR c++/48468 * except.c (build_noexcept_spec): Propagate error_mark_node. (finish_noexcept_expr): Likewise. diff --git a/gcc/cp/except.c b/gcc/cp/except.c index a814d67..874f111 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1125,6 +1125,9 @@ finish_noexcept_expr (tree expr, tsubst_flags_t complain) { tree fn; + if (expr == error_mark_node) + return error_mark_node; + if (processing_template_decl) return build_min (NOEXCEPT_EXPR, boolean_type_node, expr); @@ -1212,6 +1215,8 @@ build_noexcept_spec (tree expr, int complain) return noexcept_true_spec; else if (expr == boolean_false_node) return noexcept_false_spec; + else if (expr == error_mark_node) + return error_mark_node; else { gcc_assert (processing_template_decl || expr == error_mark_node); diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept02.C b/gcc/testsuite/g++.dg/cpp0x/noexcept02.C index be6fa00..60015e7 100644 --- a/gcc/testsuite/g++.dg/cpp0x/noexcept02.C +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept02.C @@ -46,7 +46,9 @@ SA(!noexcept(f3(A()))); template void f (T1, T2) noexcept(noexcept(T1(), T2())); -SA(noexcept(f3(1,1))); +struct B { }; + +SA(noexcept(f3(1,B()))); SA(!noexcept(f3(1,A()))); SA(!noexcept(f3(A(),1))); SA(!noexcept(f3(A(),A()))); diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae11.C b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C new file mode 100644 index 0000000..a3ffc34 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C @@ -0,0 +1,56 @@ +// PR c++/48468 +// { dg-options -std=c++0x } +// { dg-prune-output "note" } + +template +T&& declval() noexcept; + +template< class T > +inline void f1( T& x ) noexcept( noexcept( declval().foo() ) ) +{ + x.foo(); +} + +template< class T, + bool Noexcept = noexcept( declval().foo() ) +> +inline void f2( T& x ) noexcept( Noexcept ) +{ + x.foo(); +} + +// a common and trivial mistake +template< class T > +inline void f3( T& x ) noexcept( declval().foo() ) +{ + x.foo(); +} + +struct X +{ + void foo(); +}; + +struct Y +{ + void foo() noexcept; +}; + +struct Z {}; + +int main() +{ + X x; Y y; Z z; + + static_assert( !noexcept( f1(x) ), "OK." ); + static_assert( !noexcept( f2(x) ), "OK." ); + // static_assert( !noexcept( f3(x) ), "shall be ill-formed(OK)." ); + + static_assert( noexcept( f1(y) ), "OK." ); + static_assert( noexcept( f2(y) ), "OK." ); + // static_assert( noexcept( f3(y) ), "shall be ill-formed(OK)." ); + + static_assert( noexcept( f1(z) ), "shall be ill-formed." ); // { dg-error "no match" } + static_assert( noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "no match" } + static_assert( !noexcept( f3(z) ), "shall be ill-formed." ); // { dg-error "no match" } +} diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6ef6e6e..06b0b3e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5346,7 +5346,7 @@ extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, bool); extern tree describable_type (tree); -extern tree finish_decltype_type (tree, bool); +extern tree finish_decltype_type (tree, bool, tsubst_flags_t); extern tree finish_trait_expr (enum cp_trait_kind, tree, tree); extern tree build_lambda_expr (void); extern tree build_lambda_object (tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 9ed3a1f..607e9b8 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -10197,7 +10197,8 @@ cp_parser_decltype (cp_parser *parser) return error_mark_node; } - return finish_decltype_type (expr, id_expression_or_member_access_p); + return finish_decltype_type (expr, id_expression_or_member_access_p, + tf_warning_or_error); } /* Special member functions [gram.special] */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5960e46..66db880 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11025,7 +11025,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) type = lambda_return_type (type); else type = finish_decltype_type - (type, DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t)); + (type, DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t), complain); return cp_build_qualified_type_real (type, cp_type_quals (t) | cp_type_quals (type), diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index a15740a..80ec028 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4785,7 +4785,8 @@ describable_type (tree expr) a full expression. */ tree -finish_decltype_type (tree expr, bool id_expression_or_member_access_p) +finish_decltype_type (tree expr, bool id_expression_or_member_access_p, + tsubst_flags_t complain) { tree orig_expr = expr; tree type = NULL_TREE; @@ -4798,7 +4799,8 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) || (TREE_CODE (expr) == BIT_NOT_EXPR && TYPE_P (TREE_OPERAND (expr, 0)))) { - error ("argument to decltype must be an expression"); + if (complain & tf_error) + error ("argument to decltype must be an expression"); return error_mark_node; } @@ -4864,7 +4866,9 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) if (OVL_CHAIN (expr) || TREE_CODE (OVL_FUNCTION (expr)) == TEMPLATE_DECL) { - error ("%qE refers to a set of overloaded functions", orig_expr); + if (complain & tf_error) + error ("%qE refers to a set of overloaded functions", + orig_expr); return error_mark_node; } else @@ -4916,7 +4920,8 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) default: gcc_assert (TYPE_P (expr) || DECL_P (expr) || TREE_CODE (expr) == SCOPE_REF); - error ("argument to decltype must be an expression"); + if (complain & tf_error) + error ("argument to decltype must be an expression"); return error_mark_node; } } @@ -4954,7 +4959,8 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) if (!type || type == unknown_type_node) { - error ("type of %qE is unknown", expr); + if (complain & tf_error) + error ("type of %qE is unknown", expr); return error_mark_node; } diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae7.C b/gcc/testsuite/g++.dg/cpp0x/sfinae7.C new file mode 100644 index 0000000..0a95a96 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae7.C @@ -0,0 +1,20 @@ +// { dg-options -std=c++0x } + +struct A +{ + void f(); + void f(int); + typedef int g; +}; + +template decltype (T::f) f(); +template void f(); + +template decltype (T::g) g(); +template void g(); + +int main() +{ + f(); + g(); +}