From patchwork Sat Nov 18 21:12:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 166650 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:9910:0:b0:403:3b70:6f57 with SMTP id i16csp1371048vqn; Sat, 18 Nov 2023 13:13:05 -0800 (PST) X-Google-Smtp-Source: AGHT+IFgZp+8soduJklt96yuk7g0oqNmwoxDDpXY2Tm2aIBvITGoO5VyG+ijx+O7p8r2kij0ZePm X-Received: by 2002:a05:622a:181c:b0:421:b37c:43d with SMTP id t28-20020a05622a181c00b00421b37c043dmr4980478qtc.10.1700341984975; Sat, 18 Nov 2023 13:13:04 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1700341984; cv=pass; d=google.com; s=arc-20160816; b=I04vw86PFfL1JLQWLHpDWLIZ0itllHVwN9aUdG/cmGO5yPm7Jfbm9eKVhcFxaOgY9I Ocfl07PxTJSmwR5VxUqE4hqC+obD/4XgSDvYAsnWlFUojrDjO/0df86z/VArN7vtNn9g ttMMGFDlelNrHQ/Yv3jRg1LS53+i31p0jmZQxHqrMy7fb5erkwnDtkbAyt0l6Gd8CkSO 8lGlQO7D61YMK50O1Guv5SYt53QM1ByMiiL3ZTpHyUMDQ4po0wM+Jt1qsTJsbUAZAtPc 6Q8tYeRRrEveoehlEerg0IIFlFCmEw+H9MdpU0mmKptM4wP2RLBnWQByO5GXh43yqkpu YUHw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:mime-version:user-agent :content-transfer-encoding:references:in-reply-to:date:cc:to:from :subject:message-id:dkim-signature:arc-filter:dmarc-filter :delivered-to; bh=Vaw17kOC5vMtR4Z6d7SMWEFG43/OgT9M3PL/YV5c7xI=; fh=k5BQ3iYuwFTza1Z/H+kMrb8l2Z70j0hdnX84UNatFtM=; b=b4mwcGS+FGpEYtId+wxjVAxdwo3EjKl0bFs62Zg9jPJrcGBiSHfOpcziT5Hc37Ctpy kSCUmrGm9N2zZ42l8eCit//PERXv0xwJuLtr3Vn20BWkfGYEdgXapC9MnDW9LxHo+tLv yFSZ7pVcd5inQVvgoUQxIU6dNvW7Ndduh2c3UPPaWri+875/2lDfJUb5Tfs7B6dmdIZ1 Zkaqb6kV2viRnmXmOBr5Kr+rGzUVxgPOuckyfnlRiYy97WHLUSRTqF25jMBGEQTHMqDe xXQss5SBtLvZnTQ3aS1dAfJAhYELAZHRPzoLy2ZrUJADhbRUOzirokToFfYvLYONu5Ve WiMg== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@tugraz.at header.s=mailrelay header.b=qp3p+fyG; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=tugraz.at Received: from server2.sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id g19-20020ac87d13000000b004181127a232si4472249qtb.651.2023.11.18.13.13.04 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 18 Nov 2023 13:13:04 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@tugraz.at header.s=mailrelay header.b=qp3p+fyG; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=tugraz.at Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B239C3858401 for ; Sat, 18 Nov 2023 21:13:04 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mailrelay.tugraz.at (mailrelay.tugraz.at [129.27.2.202]) by sourceware.org (Postfix) with ESMTPS id 680C63858D32 for ; Sat, 18 Nov 2023 21:12:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 680C63858D32 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=tugraz.at Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tugraz.at ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 680C63858D32 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=129.27.2.202 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700341961; cv=none; b=pUuyoLvSEO/D4GTzOY1ZlInDt4J6JCvx5op2hpj5Tzt+iPlIPiFX2ngMwqP+r6+DTC701jsORNW0SH+xrxfovUWkBk0qaf2iKvy1cowaxaym/uKzW3mROetG0puglnhiknxWaofejlRN2v8vFaePpADj66dzJFss6JShBnrblcg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700341961; c=relaxed/simple; bh=td2EfvD41TU0YA+MbHH20/j2vTJfZn/qUvqIDHQfw5A=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=rEQaambWfOe4VDmUvVBtx1A6SzOq7h3GXT/ajR7kKOjG9Rqw5zLsrLSwhTTSFTU3ODWNE8UZFkpBcDOkdwtNggWZTOh6+e9+lnzJEOTCpPLHWTAmV4antcAtT+9ZNTwcSfm/h/MdnO3MbtiTiQd7O0SXoV2jgX0EhA+WoTDNCXc= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from vra-173-60.tugraz.at (vra-173-60.tugraz.at [129.27.173.60]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4SXmgh5JZ5z3wVZ; Sat, 18 Nov 2023 22:12:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1700341952; bh=Vaw17kOC5vMtR4Z6d7SMWEFG43/OgT9M3PL/YV5c7xI=; h=Subject:From:To:Cc:Date:In-Reply-To:References; b=qp3p+fyG0Pn6p1Pf/DJfehAnttSz5ApZpeDehDpwgZp7OmbS+d8ZAyEqCzxy6MqFZ eM8DWzdy7KxovuRy5Y4ZbbNfSnwe2TukTiu7ZdGVAP1bGb9x9XhuhketKLSV7amqWk 4Bk0m+L7qI2Gk7tlt3nKXHnwUcJRKR+pDt/WfTqA= Message-ID: Subject: [PATCH 1/4] c: runtime checking for assigment of VM types 1/4 From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 18 Nov 2023 22:12:32 +0100 In-Reply-To: <45b668e3f0d58d6a5977397218a963bbde37ee83.camel@tugraz.at> References: <45b668e3f0d58d6a5977397218a963bbde37ee83.camel@tugraz.at> User-Agent: Evolution 3.46.4-2 MIME-Version: 1.0 X-TUG-Backscatter-control: G/VXY7/6zeyuAY/PU2/0qw X-Spam-Scanner: SpamAssassin 3.003001 X-Spam-Score-relay: -1.9 X-Scanned-By: MIMEDefang 2.74 on 129.27.10.117 X-Spam-Status: No, score=-10.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1782937797328410749 X-GMAIL-MSGID: 1782937797328410749 When checking compatibility of types during assignment, collect all pairs of types where the outermost bound needs to match at run-time. This list is then processed to add runtime checks for each bound. gcc/c-family: * c-opt (fvla-bounds): New flag. gcc/c: * c-typeck.cc (struct instrument_data): New structure. (comp_target_types_instr convert_for_assignment_instrument): New interfaces for existing functions. (struct comptypes_data): Add instrumentation. (comptypes_check_enum_int_intr): New interface. (comptypes_check_enum_int): Old interface (calls new). (comptypes_internal): Collect VLA types needed for UBSan. (comp_target_types_instr): New interface. (comp_target_types): Old interface (calls new). (function_types_compatible_p): No instrumentation for function arguments. (process_vm_constraints): New function. (convert_argument): Adapt. (convert_for_assignment_instrument): New interface. (convert_for_assignment): Instrument assignments. (c_instrument_vm_assign): Helper function. (process_vm_constraints): Helper function. gcc/doc/: * invoke.texi (fvla-bounds): Document new flag. gcc/testsuite: * gcc.dg/vla-bounds-1.c: New test. * gcc.dg/vla-bounds-assign-1.c: New test. * gcc.dg/vla-bounds-assign-2.c: New test. * gcc.dg/vla-bounds-assign-3.c: New test. * gcc.dg/vla-bounds-assign-4.c: New test. * gcc.dg/vla-bounds-func-1.c: New test. * gcc.dg/vla-bounds-init-1.c: New test. * gcc.dg/vla-bounds-init-2.c: New test. * gcc.dg/vla-bounds-init-3.c: New test. * gcc.dg/vla-bounds-init-4.c: New test. * gcc.dg/vla-bounds-nest-1.c: New test. * gcc.dg/vla-bounds-nest-2.c: New test. * gcc.dg/vla-bounds-ret-1.c: New test. * gcc.dg/vla-bounds-ret-2.c: New test. --- gcc/c-family/c.opt | 4 + gcc/c/c-typeck.cc | 171 ++++++++++++++++++--- gcc/doc/invoke.texi | 15 ++ gcc/testsuite/gcc.dg/vla-bounds-1.c | 85 ++++++++++ gcc/testsuite/gcc.dg/vla-bounds-assign-1.c | 126 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-assign-2.c | 126 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-assign-3.c | 126 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-assign-4.c | 133 ++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-1.c | 56 +++++++ gcc/testsuite/gcc.dg/vla-bounds-init-1.c | 125 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-init-2.c | 125 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-init-3.c | 126 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-init-4.c | 125 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-nest-1.c | 39 +++++ gcc/testsuite/gcc.dg/vla-bounds-nest-2.c | 33 ++++ gcc/testsuite/gcc.dg/vla-bounds-ret-1.c | 132 ++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-ret-2.c | 133 ++++++++++++++++ 17 files changed, 1661 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-2.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-3.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-4.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-2.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-3.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-4.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-2.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-2.c diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index b10c6057cd1..29bc0956181 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -2280,6 +2280,10 @@ fvisibility-ms-compat C++ ObjC++ Var(flag_visibility_ms_compat) Changes visibility to match Microsoft Visual Studio by default. +fvla-bounds +C Var(flag_vla_bounds) +Emit run-time consistency checks for variably-modified types. + fvtable-gc C++ ObjC++ WarnRemoved No longer supported. diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 1dbb4471a88..cb5887b6255 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -93,11 +93,13 @@ static tree qualify_type (tree, tree); struct comptypes_data; static bool tagged_types_tu_compatible_p (const_tree, const_tree, struct comptypes_data *); -static bool comp_target_types (location_t, tree, tree); static bool function_types_compatible_p (const_tree, const_tree, struct comptypes_data *); static bool type_lists_compatible_p (const_tree, const_tree, struct comptypes_data *); + +static bool comp_target_types_instr (location_t, tree, tree, + struct instrument_data **); static tree lookup_field (tree, tree); static int convert_arguments (location_t, vec, tree, vec *, vec *, tree, @@ -106,6 +108,9 @@ static tree pointer_diff (location_t, tree, tree, tree *); static tree convert_for_assignment (location_t, location_t, tree, tree, tree, enum impl_conv, bool, tree, tree, int, int = 0); +static tree convert_for_assignment_instrument (location_t, location_t, tree, tree, tree, + enum impl_conv, bool, tree, tree, int, int, + struct instrument_data **); static tree valid_compound_expr_initializer (tree, tree); static void push_string (const char *); static void push_member_name (tree); @@ -1058,6 +1063,38 @@ common_type (tree t1, tree t2) return c_common_type (t1, t2); } + +/* Instrument assignment of variably modified types. */ + +static tree +c_instrument_vm_assign (location_t loc, tree a, tree b) +{ + gcc_assert (flag_vla_bounds); + + gcc_assert (TREE_CODE (a) == ARRAY_TYPE); + gcc_assert (TREE_CODE (b) == ARRAY_TYPE); + + tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (a)); + tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (b)); + + as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node); + bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node); + + tree t = build2 (NE_EXPR, boolean_type_node, as, bs); + tree tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); + + return build3 (COND_EXPR, void_type_node, t, tt, void_node); +} + + + +struct instrument_data { + + tree t1; + tree t2; + struct instrument_data *next; +}; + struct comptypes_data { bool enum_and_int_p; bool different_types_p; @@ -1065,6 +1102,8 @@ struct comptypes_data { bool anon_field; const struct tagged_tu_seen_cache* cache; + + struct instrument_data **instr_vec; }; /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment @@ -1083,16 +1122,25 @@ comptypes (tree type1, tree type2) /* Like comptypes, but if it returns non-zero because enum and int are compatible, it sets *ENUM_AND_INT_P to true. */ -int -comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) +static int +comptypes_check_enum_int_instr (tree type1, tree type2, bool *enum_and_int_p, + struct instrument_data **instr_vec) { struct comptypes_data data = { }; + data.instr_vec = instr_vec; bool ret = comptypes_internal (type1, type2, &data); + *enum_and_int_p = data.enum_and_int_p; return ret ? (data.warning_needed ? 2 : 1) : 0; } +int +comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) +{ + return comptypes_check_enum_int_instr (type1, type2, enum_and_int_p, NULL); +} + /* Like comptypes, but if it returns nonzero for different types, it sets *DIFFERENT_TYPES_P to true. */ @@ -1252,7 +1300,18 @@ comptypes_internal (const_tree type1, const_tree type2, if (d1_variable != d2_variable) data->different_types_p = true; if (d1_variable || d2_variable) - return true; + { + if (NULL != data->instr_vec) + { + struct instrument_data *id + = (struct instrument_data *)xmalloc (sizeof *id);; + id->t1 = TYPE_MAIN_VARIANT (t2); + id->t2 = TYPE_MAIN_VARIANT (t1); + id->next = *data->instr_vec; + *data->instr_vec = id; + } + return true; + } if (d1_zero && d2_zero) return true; if (d1_zero || d2_zero @@ -1288,7 +1347,8 @@ comptypes_internal (const_tree type1, const_tree type2, subset of the other. */ static bool -comp_target_types (location_t location, tree ttl, tree ttr) +comp_target_types_instr (location_t location, tree ttl, tree ttr, + struct instrument_data **instr_vec) { int val; int val_ped; @@ -1322,8 +1382,7 @@ comp_target_types (location_t location, tree ttl, tree ttr) ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC) : TYPE_MAIN_VARIANT (mvr)); - enum_and_int_p = false; - val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p); + val = comptypes_check_enum_int_instr (mvl, mvr, &enum_and_int_p, instr_vec); if (val == 1 && val_ped != 1) pedwarn_c11 (location, OPT_Wpedantic, "invalid use of pointers to arrays with different qualifiers " @@ -1338,6 +1397,13 @@ comp_target_types (location_t location, tree ttl, tree ttr) return val; } + +static int +comp_target_types (location_t location, tree ttl, tree ttr) +{ + return comp_target_types_instr (location, ttl, ttr, NULL); +} + /* Subroutines of `comptypes'. */ @@ -1551,8 +1617,13 @@ function_types_compatible_p (const_tree f1, const_tree f2, return val; } - /* Both types have argument lists: compare them and propagate results. */ + /* Both types have argument lists: compare them and propagate results. + Turn off instrumentation for bounds as these are all arrays of + unspecified size. */ + auto instr_vec_tmp = data->instr_vec; + data->instr_vec = NULL; val1 = type_lists_compatible_p (args1, args2, data); + data->instr_vec = instr_vec_tmp; return val1; } @@ -3371,10 +3442,11 @@ convert_argument (location_t ploc, tree function, tree fundecl, if (excess_precision) val = build1 (EXCESS_PRECISION_EXPR, valtype, val); - tree parmval = convert_for_assignment (ploc, ploc, type, - val, origtype, ic_argpass, - npc, fundecl, function, - parmnum + 1, warnopt); + tree parmval = convert_for_assignment_instrument (ploc, ploc, type, + val, origtype, ic_argpass, + npc, fundecl, function, + parmnum + 1, warnopt, + NULL); if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0) && INTEGRAL_TYPE_P (type) @@ -3384,6 +3456,24 @@ convert_argument (location_t ploc, tree function, tree fundecl, return parmval; } + +/* Process all constraints for variably-modified types. */ + +static tree +process_vm_constraints (location_t location, + struct instrument_data **instr_vec) +{ + tree instr_expr = void_node; + + for (struct instrument_data* d = *instr_vec; d; d = d->next) + { + tree in = c_instrument_vm_assign (location, d->t1, d->t2); + instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, in, instr_expr); + } + return instr_expr; +} + + /* Convert the argument expressions in the vector VALUES to the types in the list TYPELIST. @@ -6741,7 +6831,50 @@ static tree convert_for_assignment (location_t location, location_t expr_loc, tree type, tree rhs, tree origtype, enum impl_conv errtype, bool null_pointer_constant, tree fundecl, - tree function, int parmnum, int warnopt /* = 0 */) + tree function, int parmnum, int warnopt) +{ + struct instrument_data *instr_first = NULL; + struct instrument_data **instr_vec = NULL; + + if (flag_vla_bounds && (ic_init_const != errtype)) + instr_vec = &instr_first; + + tree ret = convert_for_assignment_instrument (location, expr_loc, type, + rhs, origtype, errtype, + null_pointer_constant, fundecl, + function, parmnum, warnopt, + instr_vec); + if (instr_vec) + { + if (ret && error_mark_node != ret && instr_first != NULL) + { + /* We have to make sure that the rhs is evaluated first, + because we may use size expressions in it to check bounds. */ + tree instr_expr = process_vm_constraints (location, instr_vec); + if (void_node != instr_expr) + { + ret = save_expr (ret); + instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, ret, instr_expr); + ret = fold_build2 (COMPOUND_EXPR, TREE_TYPE (ret), instr_expr, ret); + } + } + while (instr_first) + { + struct instrument_data *next = instr_first->next; + free (instr_first); + instr_first = next; + } + instr_vec = NULL; + } + return ret; +} + +static tree +convert_for_assignment_instrument (location_t location, location_t expr_loc, tree type, + tree rhs, tree origtype, enum impl_conv errtype, + bool null_pointer_constant, tree fundecl, + tree function, int parmnum, int warnopt, + struct instrument_data **instr_vec) { enum tree_code codel = TREE_CODE (type); tree orig_rhs = rhs; @@ -6985,11 +7118,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs); SET_EXPR_LOCATION (rhs, location); - rhs = convert_for_assignment (location, expr_loc, - build_pointer_type (TREE_TYPE (type)), - rhs, origtype, errtype, - null_pointer_constant, fundecl, function, - parmnum, warnopt); + rhs = convert_for_assignment_instrument (location, expr_loc, + build_pointer_type (TREE_TYPE (type)), + rhs, origtype, errtype, + null_pointer_constant, fundecl, function, + parmnum, warnopt, instr_vec); if (rhs == error_mark_node) return error_mark_node; @@ -7400,7 +7533,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, Meanwhile, the lhs target must have all the qualifiers of the rhs. */ if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl)) || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr)) - || (target_cmp = comp_target_types (location, type, rhstype)) + || (target_cmp = comp_target_types_instr (location, type, rhstype, instr_vec)) || is_opaque_pointer || ((c_common_unsigned_type (mvl) == c_common_unsigned_type (mvr)) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 1748afdbfe0..c94ca59086b 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10269,6 +10269,13 @@ void g (int n) @option{-Warray-parameter} option triggers warnings for similar problems involving ordinary array arguments. +@opindex Wvla-parameter-missing-check +@item -Wvla-parameter-missing-check +Warn when function calls can not be instrumented with the use of +@option{-fvla-bounds} to detect inconsistencies between the bounds of +VLA parameters at runtime. + + @opindex Wvolatile-register-var @opindex Wno-volatile-register-var @item -Wvolatile-register-var @@ -20052,6 +20059,14 @@ computing CRC32). The @var{string} should be different for every file you compile. +@opindex fvla-bounds +@item -fvla-bounds +This option is only available when compiling C code. If activated, +additional code is emitted that verifies at run time for assignments +involving variably-modified types that corresponding size expressions +evaluate to the same value. + + @opindex save-temps @item -save-temps Store the usual ``temporary'' intermediate files permanently; name them diff --git a/gcc/testsuite/gcc.dg/vla-bounds-1.c b/gcc/testsuite/gcc.dg/vla-bounds-1.c new file mode 100644 index 00000000000..7f71c1abbe5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-1.c @@ -0,0 +1,85 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +/* test return types */ + +int main() +{ + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; + + char d[u][v]; + char (*pd0)[4][3] = &d; + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; + + /* assignment */ + + pa = &a; + + pb = &b; + + pc0 = &c; + + pc1 = &c; + + pc2 = &c; + + pd0 = &d; + + pd1 = &d; + + pd2 = &d; + + pd3 = &d; + + pe0 = &e; + + pf = &f; + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c new file mode 100644 index 00000000000..40232925341 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c @@ -0,0 +1,126 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +TRY( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c new file mode 100644 index 00000000000..f1f98704a1e --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c @@ -0,0 +1,126 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +TRY( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c new file mode 100644 index 00000000000..0a811de5ffc --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c @@ -0,0 +1,126 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +TRY( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c new file mode 100644 index 00000000000..3d8553c6426 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c @@ -0,0 +1,133 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int m, n; + +static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; } +static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; } +static char (*z2(void))[5][5] { char (*p)[m][5] = 0; return p; } + + +int main() +{ + signal(SIGILL, handler); + + m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +TRY( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c new file mode 100644 index 00000000000..e4856017419 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-options "-fcheck-vla-bounds" } */ + +// make sure we do not ICE on any of these + +const char* name = "hallo"; + + +typedef void (*ht)(int n, int m, char x[n][m]); +void e(ht) { } + +int n, m; +static void f0(char a[n][m]) { } +static void f1(int u, int v, char a[u][v]) { } +static void f2(int u, int v, char a[u][v]) { } + +void f(void) +{ + int x = 1; + int (*m)[x] = 0; + m = ({ long* d2; (int (*)[d2[0]])(0); }); + + /* function pointer assignments */ + + void (*gp)(char x[4][3]) = f0; + void (*hp)(int n, int m, char x[n][m]) = f1; + ht hp2 = f1; + e(f1); + + /* composite type */ + + int u = 3; int v = 4; + char a[u][v]; + (1 ? f1 : f2)(u, v, a); +} + +/* size expression in parameter */ + +extern void a(long N, char (*a)[N]); + +static void b(void) +{ + a(1, ({ int d = 0; (char (*)[d])0; }) ); +} + +/* composite type */ + +int c(int u, char (*a)[u]); +int c(int u, char (*a)[u]) { } + +int d(void) +{ + char a[3]; + c(3, &a); +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-1.c b/gcc/testsuite/gcc.dg/vla-bounds-init-1.c new file mode 100644 index 00000000000..9c9d959ee9e --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-1.c @@ -0,0 +1,125 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +TRY( char (*qa)[v] = &a; ) // 3 != 4 + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-2.c b/gcc/testsuite/gcc.dg/vla-bounds-init-2.c new file mode 100644 index 00000000000..8fb4ad8a3ea --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-2.c @@ -0,0 +1,125 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort(); + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +TRY( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-3.c b/gcc/testsuite/gcc.dg/vla-bounds-init-3.c new file mode 100644 index 00000000000..83df5796942 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-3.c @@ -0,0 +1,126 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort(); + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +TRY( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-4.c b/gcc/testsuite/gcc.dg/vla-bounds-init-4.c new file mode 100644 index 00000000000..81d252e3957 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-4.c @@ -0,0 +1,125 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort(); + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +TRY( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c b/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c new file mode 100644 index 00000000000..30b0496107c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ +/* { dg-require-effective-target trampolines } */ + +#include +#include + +void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort() + +static char bb[4][4]; +static char (*g())[4][4] { return &bb; } + +int main() +{ + signal(SIGILL, handler); + + int n = 3; + char b[4]; + char (*f())[++n] { return &b; } + + if (4 != sizeof(*f())) + __builtin_abort(); + + TRY( char (*(*p)())[++n] = &f; ); + + if (5 != sizeof(*(*p)())) + __builtin_abort(); + + char (*(*q)())[++n][4]; + + if (6 * 4 != sizeof(*(*q)())) + __builtin_abort(); + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c b/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c new file mode 100644 index 00000000000..d871051225a --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c @@ -0,0 +1,33 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ +/* { dg-require-effective-target trampolines } */ + +#include +#include + +void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort(); + +static char bb[4][4]; +static char (*g())[4][4] { return &bb; } + +int main() +{ + signal(SIGILL, handler); + + int n = 3; + char b[4]; + char (*f())[++n] { return &b; } + + if (4 != sizeof(*f())) + __builtin_abort(); + + char (*(*p)())[++n] ERROR( = &f ); + +TRY( char (*(*q)())[++n][4] = &g; ); + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c b/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c new file mode 100644 index 00000000000..beb7dd414ed --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c @@ -0,0 +1,132 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int m, n; + +static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; } +static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; } +static char (*z2(void))[5][5] { char (*p)[m][5] = 0; return p; } + +int main() +{ + signal(SIGILL, handler); + + m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +TRY( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c b/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c new file mode 100644 index 00000000000..2df515e557f --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c @@ -0,0 +1,133 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort(); + +int n, m; + +static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; } +static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; } +static char (*z2(void))[5][5] { char (*p)[m][5] = 0; return p; } + + +int main() +{ + signal(SIGILL, handler); + + m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +TRY( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} +