From patchwork Sat Aug 26 16:20:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1826415 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=RjJ7y/Bv; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RY2Bb4tjJz1yZ9 for ; Sun, 27 Aug 2023 02:21:27 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0FB053858288 for ; Sat, 26 Aug 2023 16:21:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0FB053858288 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1693066884; bh=stcKgSyvKh1cj6ysTobFNzf7erqlu54V96Cslk3fS+o=; h=Subject:To:Cc:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=RjJ7y/BvY2swMMHEu4sw47123SZHsoLFfA9FXABaGxjmM/SxDB7cB5JlQNTCH6ALJ VJk8ZRISqh8xc4y7AYGchFTklUJzgy96vT6FcKyD1kdHGI17EX3Qdjyk/YTThPz1Xi 7e7uvCsl4fmsi4IIDxsLQ1jgVgR53t7yTQEBXHzI= 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 E83B93858C53 for ; Sat, 26 Aug 2023 16:21:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E83B93858C53 Received: from vra-173-28.tugraz.at (vra-173-28.tugraz.at [129.27.173.28]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4RY2B129jxz3wpZ; Sat, 26 Aug 2023 18:20:57 +0200 (CEST) Message-ID: <1df29de95ff41a02ffd218f4cd69f8f93df35321.camel@tugraz.at> Subject: [C PATCH 1/6] c: reorganize recursive type checking To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 26 Aug 2023 18:20:57 +0200 In-Reply-To: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.camel@tugraz.at> References: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.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=-11.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Martin Uecker via Gcc-patches From: Martin Uecker Reply-To: Martin Uecker Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Reorganize recursive type checking to use a structure to store information collected during the recursion and returned to the caller (warning_needed, enum_and_init_p, different_types_p). gcc/c: * c-typeck.cc (struct comptypes_data): Add structure. (tagged_types_tu_compatible_p, function_types_compatible_p, type_lists_compatible_p, comptypes_internal): Add structure to interface, change return type to bool, and adapt calls. (comptarget_types): Change return type too bool. (comptypes, comptypes_check_enum_int, comptypes_check_different_types): Adapt calls. --- gcc/c/c-typeck.cc | 266 ++++++++++++++++++++-------------------------- 1 file changed, 114 insertions(+), 152 deletions(-) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index e6ddf37d412..ed1520ed6ba 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -90,12 +90,14 @@ static bool require_constant_elements; static bool require_constexpr_value; static tree qualify_type (tree, tree); -static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *, - bool *); -static int comp_target_types (location_t, tree, tree); -static int function_types_compatible_p (const_tree, const_tree, bool *, - bool *); -static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *); +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 tree lookup_field (tree, tree); static int convert_arguments (location_t, vec, tree, vec *, vec *, tree, @@ -125,7 +127,8 @@ static tree find_init_member (tree, struct obstack *); static void readonly_warning (tree, enum lvalue_use); static int lvalue_or_else (location_t, const_tree, enum lvalue_use); static void record_maybe_used_decl (tree); -static int comptypes_internal (const_tree, const_tree, bool *, bool *); +static bool comptypes_internal (const_tree, const_tree, + struct comptypes_data *data); /* Return true if EXP is a null pointer constant, false otherwise. */ @@ -1039,6 +1042,13 @@ common_type (tree t1, tree t2) return c_common_type (t1, t2); } +struct comptypes_data { + + bool enum_and_int_p; + bool different_types_p; + bool warning_needed; +}; + /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment or various other operations. Return 2 if they are compatible but a warning may be needed if you use them together. */ @@ -1047,12 +1057,13 @@ int comptypes (tree type1, tree type2) { const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; - int val; - val = comptypes_internal (type1, type2, NULL, NULL); + struct comptypes_data data = { }; + bool ret = comptypes_internal (type1, type2, &data); + free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); - return val; + return ret ? (data.warning_needed ? 2 : 1) : 0; } /* Like comptypes, but if it returns non-zero because enum and int are @@ -1062,12 +1073,14 @@ int comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) { const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; - int val; - val = comptypes_internal (type1, type2, enum_and_int_p, NULL); + struct comptypes_data data = { }; + bool ret = comptypes_internal (type1, type2, &data); + *enum_and_int_p = data.enum_and_int_p; + free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); - return val; + return ret ? (data.warning_needed ? 2 : 1) : 0; } /* Like comptypes, but if it returns nonzero for different types, it @@ -1078,40 +1091,40 @@ comptypes_check_different_types (tree type1, tree type2, bool *different_types_p) { const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; - int val; - val = comptypes_internal (type1, type2, NULL, different_types_p); + struct comptypes_data data = { }; + bool ret = comptypes_internal (type1, type2, &data); + *different_types_p = data.different_types_p; + free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); - return val; + return ret ? (data.warning_needed ? 2 : 1) : 0; } -/* Return 1 if TYPE1 and TYPE2 are compatible types for assignment - or various other operations. Return 2 if they are compatible - but a warning may be needed if you use them together. If - ENUM_AND_INT_P is not NULL, and one type is an enum and the other a - compatible integer type, then this sets *ENUM_AND_INT_P to true; - *ENUM_AND_INT_P is never set to false. If DIFFERENT_TYPES_P is not - NULL, and the types are compatible but different enough not to be +/* Return true if TYPE1 and TYPE2 are compatible types for assignment + or various other operations. If they are compatible but a warning may + be needed if you use them together, 'warning_needed' in DATA is set. + If one type is an enum and the other a compatible integer type, then + this sets 'enum_and_int_p' in DATA to true (it is never set to + false). If the types are compatible but different enough not to be permitted in C11 typedef redeclarations, then this sets - *DIFFERENT_TYPES_P to true; *DIFFERENT_TYPES_P is never set to + 'different_types_p' in DATA to true; it is never set to false, but may or may not be set if the types are incompatible. This differs from comptypes, in that we don't free the seen types. */ -static int -comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, - bool *different_types_p) +static bool +comptypes_internal (const_tree type1, const_tree type2, + struct comptypes_data *data) { const_tree t1 = type1; const_tree t2 = type2; - int attrval, val; /* Suppress errors caused by previously reported errors. */ if (t1 == t2 || !t1 || !t2 || TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK) - return 1; + return true; /* Enumerated types are compatible with integer types, but this is not transitive: two enumerated types in the same translation unit @@ -1124,10 +1137,8 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, t1 = ENUM_UNDERLYING_TYPE (t1); if (TREE_CODE (t2) != VOID_TYPE) { - if (enum_and_int_p != NULL) - *enum_and_int_p = true; - if (different_types_p != NULL) - *different_types_p = true; + data->enum_and_int_p = true; + data->different_types_p = true; } } else if (TREE_CODE (t2) == ENUMERAL_TYPE @@ -1137,25 +1148,23 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, t2 = ENUM_UNDERLYING_TYPE (t2); if (TREE_CODE (t1) != VOID_TYPE) { - if (enum_and_int_p != NULL) - *enum_and_int_p = true; - if (different_types_p != NULL) - *different_types_p = true; + data->enum_and_int_p = true; + data->different_types_p = true; } } if (t1 == t2) - return 1; + return true; /* Different classes of types can't be compatible. */ if (TREE_CODE (t1) != TREE_CODE (t2)) - return 0; + return false; /* Qualifiers must match. C99 6.7.3p9 */ if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) - return 0; + return false; /* Allow for two different type nodes which have essentially the same definition. Note that we already checked for equality of the type @@ -1163,14 +1172,16 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, if (TREE_CODE (t1) != ARRAY_TYPE && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) - return 1; + return true; + + int attrval; /* 1 if no need for warning yet, 2 if warning cause has been seen. */ if (!(attrval = comp_type_attributes (t1, t2))) - return 0; + return false; - /* 1 if no need for warning yet, 2 if warning cause has been seen. */ - val = 0; + if (2 == attrval) + data->warning_needed = true; switch (TREE_CODE (t1)) { @@ -1196,16 +1207,11 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, case POINTER_TYPE: /* Do not remove mode information. */ if (TYPE_MODE (t1) != TYPE_MODE (t2)) - break; - val = (TREE_TYPE (t1) == TREE_TYPE (t2) - ? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), - enum_and_int_p, different_types_p)); - break; + return false; + return comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), data); case FUNCTION_TYPE: - val = function_types_compatible_p (t1, t2, enum_and_int_p, - different_types_p); - break; + return function_types_compatible_p (t1, t2, data); case ARRAY_TYPE: { @@ -1213,21 +1219,16 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, tree d2 = TYPE_DOMAIN (t2); bool d1_variable, d2_variable; bool d1_zero, d2_zero; - val = 1; /* Target types must match incl. qualifiers. */ - if (TREE_TYPE (t1) != TREE_TYPE (t2) - && (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), - enum_and_int_p, - different_types_p)) == 0) - return 0; - - if (different_types_p != NULL - && (d1 == NULL_TREE) != (d2 == NULL_TREE)) - *different_types_p = true; + if (!comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), data)) + return false; + + if ((d1 == NULL_TREE) != (d2 == NULL_TREE)) + data->different_types_p = true; /* Sizes must match unless one is missing or variable. */ if (d1 == NULL_TREE || d2 == NULL_TREE || d1 == d2) - break; + return true; d1_zero = !TYPE_MAX_VALUE (d1); d2_zero = !TYPE_MAX_VALUE (d2); @@ -1241,51 +1242,37 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, d1_variable = d1_variable || (d1_zero && C_TYPE_VARIABLE_SIZE (t1)); d2_variable = d2_variable || (d2_zero && C_TYPE_VARIABLE_SIZE (t2)); - if (different_types_p != NULL - && d1_variable != d2_variable) - *different_types_p = true; + if (d1_variable != d2_variable) + data->different_types_p = true; if (d1_variable || d2_variable) - break; + return true; if (d1_zero && d2_zero) - break; + return true; if (d1_zero || d2_zero || !tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2)) || !tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2))) - val = 0; + return false; - break; + return true; } case ENUMERAL_TYPE: case RECORD_TYPE: case UNION_TYPE: - if (val != 1 && false) + if (false) { - tree a1 = TYPE_ATTRIBUTES (t1); - tree a2 = TYPE_ATTRIBUTES (t2); - - if (! attribute_list_contained (a1, a2) - && ! attribute_list_contained (a2, a1)) - break; - - val = tagged_types_tu_compatible_p (t1, t2, enum_and_int_p, - different_types_p); - - if (attrval != 2) - return val; + return tagged_types_tu_compatible_p (t1, t2, data); } - break; + return false; case VECTOR_TYPE: - val = (known_eq (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2)) - && comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), - enum_and_int_p, different_types_p)); - break; + return known_eq (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2)) + && comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2), data); default: - break; + return false; } - return attrval == 2 && val == 1 ? 2 : val; + gcc_unreachable (); } /* Return 1 if TTL and TTR are pointers to types that are equivalent, ignoring @@ -1293,7 +1280,7 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, different named addresses, then we must determine if one address space is a subset of the other. */ -static int +static bool comp_target_types (location_t location, tree ttl, tree ttr) { int val; @@ -1395,17 +1382,13 @@ free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *tu_til) /* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are compatible. If the two types are not the same (which has been - checked earlier), this can only happen when multiple translation - units are being compiled. See C99 6.2.7 paragraph 1 for the exact - rules. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in - comptypes_internal. */ + checked earlier). */ -static int +static bool tagged_types_tu_compatible_p (const_tree t1, const_tree t2, - bool *enum_and_int_p, bool *different_types_p) + struct comptypes_data* data) { tree s1, s2; - bool needs_warning = false; /* We have to verify that the tags of the types are the same. This is harder than it looks because this may be a typedef, so we have @@ -1513,8 +1496,7 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, if (DECL_NAME (s1) != DECL_NAME (s2)) break; - result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), - enum_and_int_p, different_types_p); + result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data); if (result != 1 && !DECL_NAME (s1)) break; @@ -1523,8 +1505,6 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, tu->val = 0; return 0; } - if (result == 2) - needs_warning = true; if (TREE_CODE (s1) == FIELD_DECL && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), @@ -1536,7 +1516,6 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, } if (!s1 && !s2) { - tu->val = needs_warning ? 2 : 1; return tu->val; } @@ -1550,8 +1529,7 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, int result; result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), - enum_and_int_p, - different_types_p); + data); if (result != 1 && !DECL_NAME (s1)) continue; @@ -1560,8 +1538,6 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, tu->val = 0; return 0; } - if (result == 2) - needs_warning = true; if (TREE_CODE (s1) == FIELD_DECL && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), @@ -1577,7 +1553,6 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, return 0; } } - tu->val = needs_warning ? 2 : 1; return tu->val; } @@ -1599,12 +1574,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, if (TREE_CODE (s1) != TREE_CODE (s2) || DECL_NAME (s1) != DECL_NAME (s2)) break; - result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), - enum_and_int_p, different_types_p); + result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data); if (result == 0) break; - if (result == 2) - needs_warning = true; if (TREE_CODE (s1) == FIELD_DECL && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), @@ -1614,7 +1586,7 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, if (s1 && s2) tu->val = 0; else - tu->val = needs_warning ? 2 : 1; + tu->val = 1; return tu->val; } @@ -1631,9 +1603,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, Otherwise, the argument types must match. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in comptypes_internal. */ -static int +static bool function_types_compatible_p (const_tree f1, const_tree f2, - bool *enum_and_int_p, bool *different_types_p) + struct comptypes_data *data) { tree args1, args2; /* 1 if no need for warning yet, 2 if warning cause has been seen. */ @@ -1654,16 +1626,15 @@ function_types_compatible_p (const_tree f1, const_tree f2, if (TYPE_VOLATILE (ret2)) ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2), TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE); - val = comptypes_internal (ret1, ret2, enum_and_int_p, different_types_p); + val = comptypes_internal (ret1, ret2, data); if (val == 0) return 0; args1 = TYPE_ARG_TYPES (f1); args2 = TYPE_ARG_TYPES (f2); - if (different_types_p != NULL - && (args1 == NULL_TREE) != (args2 == NULL_TREE)) - *different_types_p = true; + if ((args1 == NULL_TREE) != (args2 == NULL_TREE)) + data->different_types_p = true; /* An unspecified parmlist matches any specified parmlist whose argument types don't need default promotions. */ @@ -1679,8 +1650,11 @@ function_types_compatible_p (const_tree f1, const_tree f2, If they don't match, ask for a warning (but no error). */ if (TYPE_ACTUAL_ARG_TYPES (f1) && type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1), - enum_and_int_p, different_types_p) != 1) - val = 2; + data) != 1) + { + val = 1; + data->warning_needed = true; + } return val; } if (args2 == NULL_TREE) @@ -1691,35 +1665,32 @@ function_types_compatible_p (const_tree f1, const_tree f2, return 0; if (TYPE_ACTUAL_ARG_TYPES (f2) && type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2), - enum_and_int_p, different_types_p) != 1) - val = 2; + data) != 1) + { + val = 1; + data->warning_needed = true; + } return val; } /* Both types have argument lists: compare them and propagate results. */ - val1 = type_lists_compatible_p (args1, args2, enum_and_int_p, - different_types_p); - return val1 != 1 ? val1 : val; + val1 = type_lists_compatible_p (args1, args2, data); + return val1; } /* Check two lists of types for compatibility, returning 0 for - incompatible, 1 for compatible, or 2 for compatible with - warning. ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in - comptypes_internal. */ + incompatible, 1 for compatible. ENUM_AND_INT_P and + DIFFERENT_TYPES_P are as in comptypes_internal. */ -static int +static bool type_lists_compatible_p (const_tree args1, const_tree args2, - bool *enum_and_int_p, bool *different_types_p) + struct comptypes_data *data) { - /* 1 if no need for warning yet, 2 if warning cause has been seen. */ - int val = 1; - int newval = 0; - while (1) { tree a1, mv1, a2, mv2; if (args1 == NULL_TREE && args2 == NULL_TREE) - return val; + return true; /* If one list is shorter than the other, they fail to match. */ if (args1 == NULL_TREE || args2 == NULL_TREE) @@ -1740,9 +1711,8 @@ type_lists_compatible_p (const_tree args1, const_tree args2, means there is supposed to be an argument but nothing is specified about what type it has. So match anything that self-promotes. */ - if (different_types_p != NULL - && (a1 == NULL_TREE) != (a2 == NULL_TREE)) - *different_types_p = true; + if ((a1 == NULL_TREE) != (a2 == NULL_TREE)) + data->different_types_p = true; if (a1 == NULL_TREE) { if (c_type_promotes_to (a2) != a2) @@ -1757,11 +1727,9 @@ type_lists_compatible_p (const_tree args1, const_tree args2, else if (TREE_CODE (a1) == ERROR_MARK || TREE_CODE (a2) == ERROR_MARK) ; - else if (!(newval = comptypes_internal (mv1, mv2, enum_and_int_p, - different_types_p))) + else if (!comptypes_internal (mv1, mv2, data)) { - if (different_types_p != NULL) - *different_types_p = true; + data->different_types_p = true; /* Allow wait (union {union wait *u; int *i} *) and wait (union wait *) to be compatible. */ if (TREE_CODE (a1) == UNION_TYPE @@ -1782,8 +1750,7 @@ type_lists_compatible_p (const_tree args1, const_tree args2, ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3), TYPE_QUAL_ATOMIC) : TYPE_MAIN_VARIANT (mv3)); - if (comptypes_internal (mv3, mv2, enum_and_int_p, - different_types_p)) + if (comptypes_internal (mv3, mv2, data)) break; } if (memb == NULL_TREE) @@ -1807,8 +1774,7 @@ type_lists_compatible_p (const_tree args1, const_tree args2, ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3), TYPE_QUAL_ATOMIC) : TYPE_MAIN_VARIANT (mv3)); - if (comptypes_internal (mv3, mv1, enum_and_int_p, - different_types_p)) + if (comptypes_internal (mv3, mv1, data)) break; } if (memb == NULL_TREE) @@ -1818,10 +1784,6 @@ type_lists_compatible_p (const_tree args1, const_tree args2, return 0; } - /* comptypes said ok, but record if it said to warn. */ - if (newval > val) - val = newval; - args1 = TREE_CHAIN (args1); args2 = TREE_CHAIN (args2); } @@ -7298,7 +7260,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, tree mvl = ttl; tree mvr = ttr; bool is_opaque_pointer; - int target_cmp = 0; /* Cache comp_target_types () result. */ + bool target_cmp = false; /* Cache comp_target_types () result. */ addr_space_t asl; addr_space_t asr; From patchwork Sat Aug 26 16:22:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1826416 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=XyyKJrFo; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RY2D44c5rz1yZ9 for ; Sun, 27 Aug 2023 02:22:44 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A60DA38582A1 for ; Sat, 26 Aug 2023 16:22:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A60DA38582A1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1693066962; bh=vVr8uSX2fWp+upVduvQ/jE5NYVeFzBdSMO+TarLmYGk=; h=Subject:To:Cc:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=XyyKJrFonRrBs7qgNWlcXCXklW1ds0WwCVzSxl44kEYTJl0IWS1FyX8OKKTHzYg8n gTwftiUvf9GJxslwwN+U3kw/w0igtWMRBQF1/VT+zxlCq+ahNlyEZxNQkrDEae5r7f tcQoflWHIqoExVjl9nroSAbpRoZsuEEPsPYZIFzE= 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 B8A5B3858C2C for ; Sat, 26 Aug 2023 16:22:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B8A5B3858C2C Received: from vra-173-28.tugraz.at (vra-173-28.tugraz.at [129.27.173.28]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4RY2CS2qbmz1LM0B; Sat, 26 Aug 2023 18:22:12 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 mailrelay.tugraz.at 4RY2CS2qbmz1LM0B Message-ID: <97de0d83b4ab5e463ed0e9206314d2aa97dc2ca4.camel@tugraz.at> Subject: [C PATCH 2/6] c23: recursive type checking of tagged type To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 26 Aug 2023 18:22:12 +0200 In-Reply-To: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.camel@tugraz.at> References: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.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.116 X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Martin Uecker via Gcc-patches From: Martin Uecker Reply-To: Martin Uecker Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Adapt the old and unused code for type checking for C23. gcc/c/: * c-typeck.c (struct comptypes_data): Add anon_field flag. (comptypes, comptypes_check_unum_int, comptypes_check_different_types): Remove old cache. (tagged_tu_types_compatible_p): Rewrite. --- gcc/c/c-typeck.cc | 261 +++++++++++----------------------------------- 1 file changed, 58 insertions(+), 203 deletions(-) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index ed1520ed6ba..41ef05f005c 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -190,20 +190,14 @@ remove_c_maybe_const_expr (tree expr) return expr; } - /* This is a cache to hold if two types are compatible or not. */ + /* This is a cache to hold if two types are seen. */ struct tagged_tu_seen_cache { const struct tagged_tu_seen_cache * next; const_tree t1; const_tree t2; - /* The return value of tagged_types_tu_compatible_p if we had seen - these two types already. */ - int val; }; -static const struct tagged_tu_seen_cache * tagged_tu_seen_base; -static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *); - /* Do `exp = require_complete_type (loc, exp);' to make sure exp does not have an incomplete type. (That includes void types.) LOC is the location of the use. */ @@ -1043,10 +1037,12 @@ common_type (tree t1, tree t2) } struct comptypes_data { - bool enum_and_int_p; bool different_types_p; bool warning_needed; + bool anon_field; + + const struct tagged_tu_seen_cache* cache; }; /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment @@ -1056,13 +1052,9 @@ struct comptypes_data { int comptypes (tree type1, tree type2) { - const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; - struct comptypes_data data = { }; bool ret = comptypes_internal (type1, type2, &data); - free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); - return ret ? (data.warning_needed ? 2 : 1) : 0; } @@ -1072,14 +1064,10 @@ comptypes (tree type1, tree type2) int comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) { - const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; - struct comptypes_data data = { }; bool ret = comptypes_internal (type1, type2, &data); *enum_and_int_p = data.enum_and_int_p; - free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); - return ret ? (data.warning_needed ? 2 : 1) : 0; } @@ -1090,14 +1078,10 @@ int comptypes_check_different_types (tree type1, tree type2, bool *different_types_p) { - const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; - struct comptypes_data data = { }; bool ret = comptypes_internal (type1, type2, &data); *different_types_p = data.different_types_p; - free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1); - return ret ? (data.warning_needed ? 2 : 1) : 0; } @@ -1334,53 +1318,7 @@ comp_target_types (location_t location, tree ttl, tree ttr) /* Subroutines of `comptypes'. */ - - -/* Allocate the seen two types, assuming that they are compatible. */ - -static struct tagged_tu_seen_cache * -alloc_tagged_tu_seen_cache (const_tree t1, const_tree t2) -{ - struct tagged_tu_seen_cache *tu = XNEW (struct tagged_tu_seen_cache); - tu->next = tagged_tu_seen_base; - tu->t1 = t1; - tu->t2 = t2; - - tagged_tu_seen_base = tu; - - /* The C standard says that two structures in different translation - units are compatible with each other only if the types of their - fields are compatible (among other things). We assume that they - are compatible until proven otherwise when building the cache. - An example where this can occur is: - struct a - { - struct a *next; - }; - If we are comparing this against a similar struct in another TU, - and did not assume they were compatible, we end up with an infinite - loop. */ - tu->val = 1; - return tu; -} - -/* Free the seen types until we get to TU_TIL. */ - -static void -free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *tu_til) -{ - const struct tagged_tu_seen_cache *tu = tagged_tu_seen_base; - while (tu != tu_til) - { - const struct tagged_tu_seen_cache *const tu1 - = (const struct tagged_tu_seen_cache *) tu; - tu = tu1->next; - XDELETE (CONST_CAST (struct tagged_tu_seen_cache *, tu1)); - } - tagged_tu_seen_base = tu_til; -} - -/* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are +/* Return true if two 'struct', 'union', or 'enum' types T1 and T2 are compatible. If the two types are not the same (which has been checked earlier). */ @@ -1406,189 +1344,106 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, && DECL_ORIGINAL_TYPE (TYPE_NAME (t2))) t2 = DECL_ORIGINAL_TYPE (TYPE_NAME (t2)); - /* C90 didn't have the requirement that the two tags be the same. */ - if (flag_isoc99 && TYPE_NAME (t1) != TYPE_NAME (t2)) - return 0; + if (TYPE_NAME (t1) != TYPE_NAME (t2)) + return false; - /* C90 didn't say what happened if one or both of the types were - incomplete; we choose to follow C99 rules here, which is that they - are compatible. */ - if (TYPE_SIZE (t1) == NULL - || TYPE_SIZE (t2) == NULL) - return 1; + if (!data->anon_field && NULL_TREE == TYPE_NAME (t1)) + return false; - { - const struct tagged_tu_seen_cache * tts_i; - for (tts_i = tagged_tu_seen_base; tts_i != NULL; tts_i = tts_i->next) - if (tts_i->t1 == t1 && tts_i->t2 == t2) - return tts_i->val; - } + if (!data->anon_field && TYPE_STUB_DECL (t1) != TYPE_STUB_DECL (t2)) + data->different_types_p = true; + + data->anon_field = false; + + /* Incomplete types are incompatible inside a TU. */ + if (TYPE_SIZE (t1) == NULL || TYPE_SIZE (t2) == NULL) + return false; + + if (ENUMERAL_TYPE != TREE_CODE (t1) + && (TYPE_REVERSE_STORAGE_ORDER (t1) + != TYPE_REVERSE_STORAGE_ORDER (t2))) + return false; + + /* For types already in being looked at in some active + invocation of this function, assume compatibility. + The cache is built as a linked list on the stack + with the head of the list past downwards. */ + for (const struct tagged_tu_seen_cache *t = data->cache; + t != NULL; t = t->next) + if (t->t1 == t1 && t->t2 == t2) + return true; + + const struct tagged_tu_seen_cache entry = { data->cache, t1, t2 }; switch (TREE_CODE (t1)) { case ENUMERAL_TYPE: { - struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); /* Speed up the case where the type values are in the same order. */ tree tv1 = TYPE_VALUES (t1); tree tv2 = TYPE_VALUES (t2); if (tv1 == tv2) - { - return 1; - } + return true; for (;tv1 && tv2; tv1 = TREE_CHAIN (tv1), tv2 = TREE_CHAIN (tv2)) { if (TREE_PURPOSE (tv1) != TREE_PURPOSE (tv2)) break; - if (simple_cst_equal (TREE_VALUE (tv1), TREE_VALUE (tv2)) != 1) - { - tu->val = 0; - return 0; - } + + if (simple_cst_equal (DECL_INITIAL (TREE_VALUE (tv1)), + DECL_INITIAL (TREE_VALUE (tv2))) != 1) + break; } if (tv1 == NULL_TREE && tv2 == NULL_TREE) - { - return 1; - } + return true; + if (tv1 == NULL_TREE || tv2 == NULL_TREE) - { - tu->val = 0; - return 0; - } + return false; if (list_length (TYPE_VALUES (t1)) != list_length (TYPE_VALUES (t2))) - { - tu->val = 0; - return 0; - } + return false; for (s1 = TYPE_VALUES (t1); s1; s1 = TREE_CHAIN (s1)) { s2 = purpose_member (TREE_PURPOSE (s1), TYPE_VALUES (t2)); - if (s2 == NULL - || simple_cst_equal (TREE_VALUE (s1), TREE_VALUE (s2)) != 1) - { - tu->val = 0; - return 0; - } - } - return 1; - } - - case UNION_TYPE: - { - struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); - - if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2))) - { - tu->val = 0; - return 0; - } - - /* Speed up the common case where the fields are in the same order. */ - for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2; - s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2)) - { - int result; - - if (DECL_NAME (s1) != DECL_NAME (s2)) - break; - result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data); - - if (result != 1 && !DECL_NAME (s1)) - break; - if (result == 0) - { - tu->val = 0; - return 0; - } - if (TREE_CODE (s1) == FIELD_DECL - && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), - DECL_FIELD_BIT_OFFSET (s2)) != 1) - { - tu->val = 0; - return 0; - } - } - if (!s1 && !s2) - { - return tu->val; + if (s2 == NULL + || simple_cst_equal (DECL_INITIAL (TREE_VALUE (s1)), DECL_INITIAL (TREE_VALUE (s2))) != 1) + return false; } - for (s1 = TYPE_FIELDS (t1); s1; s1 = DECL_CHAIN (s1)) - { - bool ok = false; - - for (s2 = TYPE_FIELDS (t2); s2; s2 = DECL_CHAIN (s2)) - if (DECL_NAME (s1) == DECL_NAME (s2)) - { - int result; - - result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), - data); - - if (result != 1 && !DECL_NAME (s1)) - continue; - if (result == 0) - { - tu->val = 0; - return 0; - } - - if (TREE_CODE (s1) == FIELD_DECL - && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), - DECL_FIELD_BIT_OFFSET (s2)) != 1) - break; - - ok = true; - break; - } - if (!ok) - { - tu->val = 0; - return 0; - } - } - return tu->val; + return true; } + case UNION_TYPE: case RECORD_TYPE: - { - struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2); if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2))) - { - tu->val = 0; - return 0; - } + return false; for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2; s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2)) { - int result; if (TREE_CODE (s1) != TREE_CODE (s2) || DECL_NAME (s1) != DECL_NAME (s2)) - break; - result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data); - if (result == 0) - break; + return false; + + if (!DECL_NAME (s1) && RECORD_OR_UNION_TYPE_P (TREE_TYPE (s1))) + data->anon_field = true; + + data->cache = &entry; + if (!comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data)) + return false; if (TREE_CODE (s1) == FIELD_DECL && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), DECL_FIELD_BIT_OFFSET (s2)) != 1) - break; + return false; } - if (s1 && s2) - tu->val = 0; - else - tu->val = 1; - return tu->val; - } + return true; default: gcc_unreachable (); From patchwork Sat Aug 26 16:23:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1826417 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=iYSa+iNO; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RY2FC5zZ0z1yZ9 for ; Sun, 27 Aug 2023 02:23:43 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D4B07385828D for ; Sat, 26 Aug 2023 16:23:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D4B07385828D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1693067021; bh=x426C35Ym19uYRSSSw4TSk00Xo8Z2aeZqGIojk5vs3E=; h=Subject:To:Cc:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=iYSa+iNOU/1Vbu54cko/OLNSk2fy9TDwQiItQu20lqBBbfy7RqEVyj/lamv0eZuWA sBi2l30Gu9ihok355Lr0n/JTb//ypSbRt9lQmVZo8CAy1klm2n9TpEL8ZtFzyxlVI2 /Hi6ZFIYD1s7Dy88EkbeMSTsKer+DqRE78PxjZpk= 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 0CB563858412 for ; Sat, 26 Aug 2023 16:23:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0CB563858412 Received: from vra-173-28.tugraz.at (vra-173-28.tugraz.at [129.27.173.28]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4RY2Db34DMz3whg; Sat, 26 Aug 2023 18:23:11 +0200 (CEST) Message-ID: <00f5c725f1e5234a8f5f396c393d4d09159c6eae.camel@tugraz.at> Subject: [C PATCH 3/6] c23: tag compatibility rules for struct and unions To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 26 Aug 2023 18:23:10 +0200 In-Reply-To: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.camel@tugraz.at> References: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.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=-11.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Martin Uecker via Gcc-patches From: Martin Uecker Reply-To: Martin Uecker Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Implement redeclaration and compatibility rules for structures and unions in C23. gcc/c/: * c-decl.cc (previous_tag): New function. (get_parm_info): Turn off warning for C2X. (start_struct): Allow redefinitons. (finish_struct): Diagnose conflicts. * c-tree.h (comptypes_same_p): Add prototype. * c-typeck.cc (comptypes_same_p): New function (comptypes_internal): Activate comparison of tagged types (convert_for_assignment): Ingore qualifiers. (digest_init): Add error. (initialized_elementwise_p): Allow compatible types. gcc/testsuite/: * gcc.dg/c2x-enum-7.c: Remove warning. * gcc.dg/c2x-tag-1.c: New test. * gcc.dg/c2x-tag-2.c: New test. * gcc.dg/c2x-tag-3.c: New test. * gcc.dg/c2x-tag-4.c: New test. * gcc.dg/c2x-tag-5.c: New test. * gcc.dg/c2x-tag-6.c: New test. * gcc.dg/c2x-tag-7.c: New test. * gcc.dg/c2x-tag-8.c: New test. * gcc.dg/c2x-tag-9.c: New test. * gcc.dg/c2x-tag-10.c: New test. --- gcc/c/c-decl.cc | 56 ++++++++++++++++++++++--- gcc/c/c-tree.h | 1 + gcc/c/c-typeck.cc | 38 +++++++++++++---- gcc/testsuite/gcc.dg/c2x-enum-7.c | 6 +-- gcc/testsuite/gcc.dg/c2x-tag-1.c | 68 +++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-10.c | 31 ++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-2.c | 43 +++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-3.c | 16 ++++++++ gcc/testsuite/gcc.dg/c2x-tag-4.c | 19 +++++++++ gcc/testsuite/gcc.dg/c2x-tag-5.c | 26 ++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-6.c | 34 ++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-7.c | 28 +++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-8.c | 25 ++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-9.c | 12 ++++++ 14 files changed, 387 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-1.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-10.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-2.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-3.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-4.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-5.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-6.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-7.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-8.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-9.c diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 1f9eb44dbaa..c5c6a853fa9 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -1993,6 +1993,24 @@ locate_old_decl (tree decl) decl, TREE_TYPE (decl)); } +static tree +previous_tag (tree type) +{ + struct c_binding *b = NULL; + tree name = TYPE_NAME (type); + + if (name) + b = I_TAG_BINDING (name); + + if (b) + b = b->shadowed; + + if (b && B_IN_CURRENT_SCOPE (b)) + return b->decl; + + return NULL_TREE; +} + /* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL. Returns true if the caller should proceed to merge the two, false if OLDDECL should simply be discarded. As a side effect, issues @@ -8442,11 +8460,14 @@ get_parm_info (bool ellipsis, tree expr) if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE) { if (b->id) - /* The %s will be one of 'struct', 'union', or 'enum'. */ - warning_at (b->locus, 0, - "%<%s %E%> declared inside parameter list" - " will not be visible outside of this definition or" - " declaration", keyword, b->id); + { + /* The %s will be one of 'struct', 'union', or 'enum'. */ + if (!flag_isoc2x) + warning_at (b->locus, 0, + "%<%s %E%> declared inside parameter list" + " will not be visible outside of this definition or" + " declaration", keyword, b->id); + } else /* The %s will be one of 'struct', 'union', or 'enum'. */ warning_at (b->locus, 0, @@ -8651,6 +8672,12 @@ start_struct (location_t loc, enum tree_code code, tree name, if (name != NULL_TREE) ref = lookup_tag (code, name, true, &refloc); + + /* For C2X, even if we already have a completed definition, + we do not use it. We will check for consistency later. */ + if (flag_isoc2x && ref && TYPE_SIZE (ref)) + ref = NULL_TREE; + if (ref && TREE_CODE (ref) == code) { if (TYPE_STUB_DECL (ref)) @@ -9439,6 +9466,25 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, warning_at (loc, 0, "union cannot be made transparent"); } + /* Check for consistency with previous definition */ + if (flag_isoc2x) + { + tree vistype = previous_tag (t); + if (vistype + && TREE_CODE (vistype) == TREE_CODE (t) + && !C_TYPE_BEING_DEFINED (vistype)) + { + TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (t); + if (c_type_variably_modified_p (t)) + error ("redefinition of struct or union %qT with variably " + "modified type", t); + else if (!comptypes_same_p (t, vistype)) + error ("redefinition of struct or union %qT", t); + } + } + + C_TYPE_BEING_DEFINED (t) = 0; + tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)); for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) { diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 7c5234e80fd..511fd9ee0e5 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -747,6 +747,7 @@ extern tree c_objc_common_truthvalue_conversion (location_t, tree); extern tree require_complete_type (location_t, tree); extern bool same_translation_unit_p (const_tree, const_tree); extern int comptypes (tree, tree); +extern bool comptypes_same_p (tree, tree); extern int comptypes_check_different_types (tree, tree, bool *); extern int comptypes_check_enum_int (tree, tree, bool *); extern bool c_mark_addressable (tree, bool = false); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 41ef05f005c..802c727d9d3 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1058,6 +1058,23 @@ comptypes (tree type1, tree type2) return ret ? (data.warning_needed ? 2 : 1) : 0; } + +/* Like comptypes, but it returns non-zero only for identical + types. */ + +bool +comptypes_same_p (tree type1, tree type2) +{ + struct comptypes_data data = { }; + bool ret = comptypes_internal (type1, type2, &data); + + if (data.different_types_p) + return false; + + return ret; +} + + /* Like comptypes, but if it returns non-zero because enum and int are compatible, it sets *ENUM_AND_INT_P to true. */ @@ -1243,11 +1260,11 @@ comptypes_internal (const_tree type1, const_tree type2, case ENUMERAL_TYPE: case RECORD_TYPE: case UNION_TYPE: - if (false) - { - return tagged_types_tu_compatible_p (t1, t2, data); - } - return false; + + if (!flag_isoc2x) + return false; + + return tagged_types_tu_compatible_p (t1, t2, data); case VECTOR_TYPE: return known_eq (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2)) @@ -6978,7 +6995,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, /* Aggregates in different TUs might need conversion. */ if ((codel == RECORD_TYPE || codel == UNION_TYPE) && codel == coder - && comptypes (type, rhstype)) + && comptypes (TYPE_MAIN_VARIANT (type), TYPE_MAIN_VARIANT (rhstype))) return convert_and_check (expr_loc != UNKNOWN_LOCATION ? expr_loc : location, type, rhs); @@ -8315,6 +8332,13 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, conversion. */ inside_init = convert (type, inside_init); + if ((code == RECORD_TYPE || code == UNION_TYPE) + && !comptypes (TYPE_MAIN_VARIANT (type), TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)))) + { + error_init (init_loc, "invalid initializer %qT %qT", type, TREE_TYPE (inside_init)); + return error_mark_node; + } + if (require_constant && TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR) { @@ -10399,7 +10423,7 @@ initialize_elementwise_p (tree type, tree value) return !VECTOR_TYPE_P (value_type); if (AGGREGATE_TYPE_P (type)) - return type != TYPE_MAIN_VARIANT (value_type); + return !comptypes (type, TYPE_MAIN_VARIANT (value_type)); return false; } diff --git a/gcc/testsuite/gcc.dg/c2x-enum-7.c b/gcc/testsuite/gcc.dg/c2x-enum-7.c index 08bae31d82c..d4ddcc821dc 100644 --- a/gcc/testsuite/gcc.dg/c2x-enum-7.c +++ b/gcc/testsuite/gcc.dg/c2x-enum-7.c @@ -26,17 +26,15 @@ enum e13 : short x13; /* { dg-error "'enum' underlying type may not be specified enum e14 : short f14 (); /* { dg-error "'enum' underlying type may not be specified here" } */ typeof (enum e15 : long) x15; /* { dg-error "'enum' underlying type may not be specified here" } */ int f16 (enum e16 : char p); /* { dg-error "'enum' underlying type may not be specified here" } */ -/* { dg-warning "will not be visible outside of this definition or declaration" "warning" { target *-*-* } .-1 } */ int f17 (enum e17 : char); /* { dg-error "'enum' underlying type may not be specified here" } */ -/* { dg-warning "will not be visible outside of this definition or declaration" "warning" { target *-*-* } .-1 } */ struct s18 { enum e18 : int x; }; /* { dg-error "'enum' underlying type may not be specified here" } */ /* But those are OK if the enum content is defined. */ enum e19 : short { E19 } x19; enum e20 : long { E20 } f20 (); typeof (enum e21 : long { E21 }) x21; -int f22 (enum e22 : long long { E22 } p); /* { dg-warning "will not be visible outside of this definition or declaration" } */ -int f23 (enum e23 : long long { E23 } p); /* { dg-warning "will not be visible outside of this definition or declaration" } */ +int f22 (enum e22 : long long { E22 } p); +int f23 (enum e23 : long long { E23 } p); struct s24 { enum e24 : int { E24 } x; }; /* Incompatible kinds of tags in the same scope are errors. */ diff --git a/gcc/testsuite/gcc.dg/c2x-tag-1.c b/gcc/testsuite/gcc.dg/c2x-tag-1.c new file mode 100644 index 00000000000..0cda7aa0c34 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-1.c @@ -0,0 +1,68 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// allowed and forbidden redefinitions of the same struct/union in the same scope + +typedef struct p { int a; } pd_t; +typedef struct p { int a; } pd_t; + +typedef struct bar { int x; } X; +typedef struct bar { float x; } Y; /* { dg-error "redefinition of struct or union" } */ + +void test(void) +{ + struct foo { int x; }; + struct foo { float x; }; /* { dg-error "redefinition of struct or union" } */ +} + +struct aa { int a; }; + +void f(void) +{ + typedef struct aa A; + struct bb { struct aa a; } x; + struct aa { int a; }; + typedef struct aa A; /* { dg-error "redefinition" } */ + struct bb { struct aa a; } y; /* { dg-error "redefinition of struct or union" } */ + (void)x; (void)y; +} + + + +void h(void) +{ + struct a2 { int a; }; + { + typedef struct a2 A; + struct b2 { struct a2 a; } x; + struct a2 { int a; }; + typedef struct a2 A; /* { dg-error "redefinition" } */ + struct b2 { struct a2 a; } y; /* { dg-error "redefinition of struct or union" } */ + (void)x; (void)y; + } +} + + +union cc { int x; float y; } z; +union cc { int x; float y; } z1; +union cc { float y; int x; } z2; /* { dg-error "redefinition of struct or union" } */ + +void g(void) +{ + struct s { int a; }; + struct s { int a; } x0; + struct p { struct s c; } y1 = { x0 }; + struct p { struct s { int a; } c; } y = { x0 }; +} + +struct q { struct { int a; }; }; +struct q { struct { int a; }; }; +struct q { int a; }; /* { dg-error "redefinition of struct or union" } */ + +struct r { int a; char b[]; }; +struct r { int a; char b[]; }; +struct r { int a; char b[0]; }; +struct r { int a; char b[1]; }; /* { dg-error "redefinition of struct or union" } */ + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-10.c b/gcc/testsuite/gcc.dg/c2x-tag-10.c new file mode 100644 index 00000000000..39abcb2db60 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-10.c @@ -0,0 +1,31 @@ +/* { dg-do compile } + * { dg-options "-std=c2x" } */ + +// structs with variably modified types + +void bar(int n, int m) +{ + struct f { int b; int a[n]; } *x; + { struct f { int b; int a[n]; } *x2 = x; } + { struct f { int b; int a[m]; } *x2 = x; } + { struct f { int b; int a[5]; } *x2 = x; } + { struct f { int b; int a[0]; } *x2 = x; } + { struct f { int b; int a[]; } *x2 = x; } + + struct g { int a[n]; int b; } *y; + { struct g { int a[n]; int b; } *y2 = y; } + { struct g { int a[m]; int b; } *y2 = y; } + { struct g { int a[4]; int b; } *y2 = y; } + + struct h { int b; int a[5]; } *w; + { struct h { int b; int a[5]; } *w2 = w; } + { struct h { int b; int a[n]; } *w2 = w; } + { struct h { int b; int a[m]; } *w2 = w; } + + struct i { int b; int (*a)(int c[n]); } *u; + { struct i { int b; int (*a)(int c[4]); } *u2 = u; } + { struct i { int b; int (*a)(int c[]); } *u2 = u; } + { struct i { int b; int (*a)(int c[*]); } *u2 = u; } +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-2.c b/gcc/testsuite/gcc.dg/c2x-tag-2.c new file mode 100644 index 00000000000..a68392e1fab --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-2.c @@ -0,0 +1,43 @@ +/* { dg-do { compile xfail { *-*-* } } } + * { dg-options "-std=c2x" } + */ + +// compatibility of structs in assignment + +typedef struct p { int a; } pd_t; + +void test1(void) +{ + pd_t y0; + struct p { int a; } x; + y0 = x; +} + +void test2(void) +{ + struct p { int a; } x; + struct p y0 = x; +} + +void test3(void) +{ + struct p { int a; } x; + pd_t y0 = x; +} + +typedef struct p { int a; } p2_t; + +void test4(void) +{ + p2_t x; + pd_t y0 = x; +} + +void test5(void) +{ + struct q { int a; } a; + struct q { int a; } b; + a = b; +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-3.c b/gcc/testsuite/gcc.dg/c2x-tag-3.c new file mode 100644 index 00000000000..bafb08ca11d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-3.c @@ -0,0 +1,16 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// conflicting types via linkage + +extern struct foo { int x; } x; +extern struct bar { float x; } y; + +void test(void) +{ + extern struct foo { int x; } x; + extern struct bar { int x; } y; /* { dg-error "conflicting types" } */ +} + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-4.c b/gcc/testsuite/gcc.dg/c2x-tag-4.c new file mode 100644 index 00000000000..b7c793c2dce --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-4.c @@ -0,0 +1,19 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// conflicting attributes + +extern struct __attribute__(( transaction_safe )) foo { int x; } x; +extern struct __attribute__(( unused )) foo2 { int x; } x2; +extern struct __attribute__(( may_alias )) foo3 { int x; } x3; + +void test(void) +{ + extern struct foo { int x; } x; /* { dg-error "conflicting types" } */ + extern struct foo2 { int x; } x2; + extern struct foo3 { int x; } x3; +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-5.c b/gcc/testsuite/gcc.dg/c2x-tag-5.c new file mode 100644 index 00000000000..b597d6403d2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-5.c @@ -0,0 +1,26 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// conflicting types for anonymous structs / unions + +extern struct { int x; } a; +extern struct { int x; } a; /* { dg-error "conflicting types" } */ + +extern union { int x; } b; +extern union { int x; } b; /* { dg-error "conflicting types" } */ + +typedef struct { int x; } u; +typedef struct { int x; } v; + +u c; +v c; /* { dg-error "conflicting types" } */ + +typedef union { int x; } q; +typedef union { int x; } r; + +q d; +r d; /* { dg-error "conflicting types" } */ + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-6.c b/gcc/testsuite/gcc.dg/c2x-tag-6.c new file mode 100644 index 00000000000..bf7cfb342d4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-6.c @@ -0,0 +1,34 @@ +/* + * { dg-do { run xfail { "*-*-*" } } } + * { dg-options "-std=c2x" } + */ + +// nesting and parameters + +#define product_type(T, A, B) \ +struct product_ ## T { A a ; B b ; } +#define sum_type(T, A, B) \ +struct sum_ ## T { _Bool flag ; union { A a ; B b ; }; } + +float foo1(product_type(iSfd_, int, sum_type(fd, float, double)) x) +{ + return x.b.a; +} + +static void test1(void) +{ + product_type(iSfd_, int, sum_type(fd, float, double)) y = { 3, { 1, { .a = 1. } } }; + product_type(iSfd_, int, sum_type(fd, float, double)) z = y; + product_type(iSfd_, int, sum_type(fd, float, double)) *zp = &y; + float a = foo1(y); + product_type(iSid_, int, sum_type(id, int, double)) *wp = &y; /* { dg-warning "incompatible pointer type" } */ + float b = foo1(y); + product_type(iSid_, int, sum_type(id, int, double)) w = *wp; + (void)a; (void)b; (void)z; (void)zp; (void)w; (void)wp; +} + +int main() +{ + test1(); +} + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-7.c b/gcc/testsuite/gcc.dg/c2x-tag-7.c new file mode 100644 index 00000000000..7ec121fe80e --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-7.c @@ -0,0 +1,28 @@ +/* + * { dg-do compile } + * { dg-options "-Wno-vla -std=gnu2x" } + */ + +// arrays in structs + +void foo(int n, int m) +{ + struct f { int b; int a[n]; }; + struct f { int b; int a[n]; }; /* { dg-error "redefinition of struct or union" } */ + struct f { int b; int a[m]; }; /* { dg-error "redefinition of struct or union" } */ + struct f { int b; int a[5]; }; /* { dg-error "redefinition of struct or union" } */ + struct f { int b; int a[]; }; /* { dg-error "redefinition of struct or union" } */ + + struct g { int a[n]; int b; }; + struct g { int a[n]; int b; }; /* { dg-error "redefinition of struct or union" } */ + struct g { int a[m]; int b; }; /* { dg-error "redefinition of struct or union" } */ + struct g { int a[4]; int b; }; /* { dg-error "redefinition of struct or union" } */ + + struct h { int (*a)[n]; int b; }; + struct h { int (*a)[n]; int b; }; /* { dg-error "redefinition of struct or union" } */ + struct h { int (*a)[m]; int b; }; /* { dg-error "redefinition of struct or union" } */ + struct h { int (*a)[4]; int b; }; /* { dg-error "redefinition of struct or union" } */ + struct h { int (*a)[]; int b; }; /* { dg-error "redefinition of struct or union" } */ +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-8.c b/gcc/testsuite/gcc.dg/c2x-tag-8.c new file mode 100644 index 00000000000..d1f503f23ba --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-8.c @@ -0,0 +1,25 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// (in-)completeness + +struct foo { + char x[10]; +} x; + +struct foo { + _Static_assert(_Generic(&x, struct foo*: 0, default: 1)); + char x[_Generic(&x, struct foo*: 1, default: 10)]; +}; + +void f(void) +{ + struct foo { char x[_Generic(&x, struct foo*: 1, default: 10)]; }; + + struct foo z; + _Static_assert(10 == sizeof(z.x), ""); +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-9.c b/gcc/testsuite/gcc.dg/c2x-tag-9.c new file mode 100644 index 00000000000..fdbae7baf46 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-9.c @@ -0,0 +1,12 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// recursive declarations + +extern struct bar { struct bar* p; int x; } b; +extern struct bar { struct bar* p; int x; } b; + +struct foo { struct foo { struct foo* p; int x; }* p; int x; } a; /* { dg-error "nested" } */ + From patchwork Sat Aug 26 16:24:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1826418 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=iKfK5hxB; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RY2G6661qz1yZ9 for ; Sun, 27 Aug 2023 02:24:30 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CFF2738582A4 for ; Sat, 26 Aug 2023 16:24:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CFF2738582A4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1693067068; bh=tMqxH+Js4m3v6LkE7Fllc0vkXvNGGlgUi0eehDgTiC8=; h=Subject:To:Cc:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=iKfK5hxB+BSARel3JXbS/l0jB3izPmf1mJbB9zxfkcVLPGe48UU1u9+uE97Qqs1Bq IFLoNgiUYQhoAUwJBiTO/T0FYjw7BjfejaA4DM9C6x/j8SCudrnZgpBdvjWbnYT+RR cFO0W4pmrECvyyx/hm2C+ok2B6ofGd3OkMrdhXJA= 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 1D5553858288 for ; Sat, 26 Aug 2023 16:24:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1D5553858288 Received: from vra-173-28.tugraz.at (vra-173-28.tugraz.at [129.27.173.28]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4RY2Fc5W5Gz3whg; Sat, 26 Aug 2023 18:24:04 +0200 (CEST) Message-ID: <525f0f422f6d907b415d42e16daf8acdbd92ebe6.camel@tugraz.at> Subject: [C PATCH 4/6] c23: tag compatibility rules for enums To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 26 Aug 2023 18:24:04 +0200 In-Reply-To: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.camel@tugraz.at> References: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.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=-11.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Martin Uecker via Gcc-patches From: Martin Uecker Reply-To: Martin Uecker Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Allow redefinition of enum types and enumerators. gcc/c: * c-decl.cc (start_num): Allow redefinition. (finish_enum): Diagnose conflicts. (build_enumerator): Set context. (diagnose_mismatched_decls): Diagnose conflicting enumerators. (push_decl): Preserve context for enumerators. gcc/testsuide/: * gcc.dg/c2x-tag-enum-1.c: New test. * gcc.dg/c2x-tag-enum-2.c: New test. * gcc.dg/c2x-tag-enum-3.c: New test. * gcc.dg/c2x-tag-enum-4.c: New test. --- gcc/c/c-decl.cc | 47 ++++++++++++++++++++-- gcc/c/c-typeck.cc | 5 ++- gcc/testsuite/gcc.dg/c2x-tag-enum-1.c | 56 +++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-enum-2.c | 23 +++++++++++ gcc/testsuite/gcc.dg/c2x-tag-enum-3.c | 7 ++++ gcc/testsuite/gcc.dg/c2x-tag-enum-4.c | 22 +++++++++++ 6 files changed, 155 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-1.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-2.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-3.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-4.c diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index c5c6a853fa9..b514e8a35ee 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -2064,9 +2064,24 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, given scope. */ if (TREE_CODE (olddecl) == CONST_DECL) { - auto_diagnostic_group d; - error ("redeclaration of enumerator %q+D", newdecl); - locate_old_decl (olddecl); + if (flag_isoc2x + && TYPE_NAME (DECL_CONTEXT (newdecl)) + && DECL_CONTEXT (newdecl) != DECL_CONTEXT (olddecl) + && TYPE_NAME (DECL_CONTEXT (newdecl)) == TYPE_NAME (DECL_CONTEXT (olddecl))) + { + if (!simple_cst_equal (DECL_INITIAL (olddecl), DECL_INITIAL (newdecl))) + { + auto_diagnostic_group d; + error ("conflicting redeclaration of enumerator %q+D", newdecl); + locate_old_decl (olddecl); + } + } + else + { + auto_diagnostic_group d; + error ("redeclaration of enumerator %q+D", newdecl); + locate_old_decl (olddecl); + } return false; } @@ -3227,8 +3242,11 @@ pushdecl (tree x) /* Must set DECL_CONTEXT for everything not at file scope or DECL_FILE_SCOPE_P won't work. Local externs don't count - unless they have initializers (which generate code). */ + unless they have initializers (which generate code). We + also exclude CONST_DECLs because enumerators will get the + type of the enum as context. */ if (current_function_decl + && TREE_CODE (x) != CONST_DECL && (!VAR_OR_FUNCTION_DECL_P (x) || DECL_INITIAL (x) || !TREE_PUBLIC (x))) DECL_CONTEXT (x) = current_function_decl; @@ -9606,9 +9624,15 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, if (name != NULL_TREE) enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc); + if (flag_isoc2x && enumtype != NULL_TREE + && TREE_CODE (enumtype) == ENUMERAL_TYPE + && TYPE_VALUES (enumtype) != NULL_TREE) + enumtype = NULL_TREE; + if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE) { enumtype = make_node (ENUMERAL_TYPE); + TYPE_SIZE (enumtype) = NULL_TREE; pushtag (loc, name, enumtype); if (fixed_underlying_type != NULL_TREE) { @@ -9868,6 +9892,20 @@ finish_enum (tree enumtype, tree values, tree attributes) && !in_sizeof && !in_typeof && !in_alignof) struct_parse_info->struct_types.safe_push (enumtype); + /* Check for consistency with previous definition */ + if (flag_isoc2x) + { + tree vistype = previous_tag (enumtype); + if (vistype + && TREE_CODE (vistype) == TREE_CODE (enumtype) + && !C_TYPE_BEING_DEFINED (vistype)) + { + TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (enumtype); + if (!comptypes_same_p (enumtype, vistype)) + error("conflicting redefinition of enum %qT", enumtype); + } + } + C_TYPE_BEING_DEFINED (enumtype) = 0; return enumtype; @@ -10047,6 +10085,7 @@ build_enumerator (location_t decl_loc, location_t loc, decl = build_decl (decl_loc, CONST_DECL, name, TREE_TYPE (value)); DECL_INITIAL (decl) = value; + DECL_CONTEXT (decl) = the_enum->enum_type; pushdecl (decl); return tree_cons (decl, value, NULL_TREE); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 802c727d9d3..2b79cbba950 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1396,6 +1396,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, { case ENUMERAL_TYPE: { + if (!comptypes (ENUM_UNDERLYING_TYPE (t1), ENUM_UNDERLYING_TYPE (t2))) + return false; + /* Speed up the case where the type values are in the same order. */ tree tv1 = TYPE_VALUES (t1); tree tv2 = TYPE_VALUES (t2); @@ -6895,7 +6898,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, if (checktype != error_mark_node && TREE_CODE (checktype) == ENUMERAL_TYPE && TREE_CODE (type) == ENUMERAL_TYPE - && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type)) + && !comptypes (TYPE_MAIN_VARIANT (checktype), TYPE_MAIN_VARIANT (type))) { gcc_rich_location loc (location); warning_at (&loc, OPT_Wenum_conversion, diff --git a/gcc/testsuite/gcc.dg/c2x-tag-enum-1.c b/gcc/testsuite/gcc.dg/c2x-tag-enum-1.c new file mode 100644 index 00000000000..d66d30d356f --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-enum-1.c @@ -0,0 +1,56 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// incompatible redeclarations, conflicing redefinitions + + +enum aa { A = 1 } *a; +enum bb { B = 1 } *b; + +void test(void) +{ + enum aa { A = 1 } *c = a; + enum bb { B = 2 } *d = b; /* { dg-warning "incompatible pointer type" } */ +} + +enum cc { C = 1 }; +enum cc { D = 1 }; /* { dg-error "conflicting redefinition" } */ + +enum dd { E = 1 }; +enum dd { E = 2 }; /* { dg-error "conflicting redefinition" } */ + /* { dg-error "redeclaration of enumerator" "" { target *-*-* } .-1 } */ + + + +void test2(void) +{ + enum ee *a; + enum ee { F = 2 } *b; + b = a; +} + + +enum ff { G = 2 }; +enum gg { G = 2 }; /* { dg-error "redeclaration of enumerator" } */ +enum g2 { G = 3 }; /* { dg-error "redeclaration of enumerator" } */ + +enum hh { H = 1, H = 1 }; /* { dg-error "redeclaration of enumerator" } */ + +enum ss { K = 2 }; +enum ss { K = 2 }; + +enum tt { R = 2 } TT; +enum tt { + R = _Generic(&TT, enum tt*: 0, default: 2) +}; + +enum { U = 1 }; +enum { U = 1 }; /* { dg-error "redeclaration of enumerator" } */ + +enum { V = 1 }; +enum { V = 2 }; /* { dg-error "redeclaration of enumerator" } */ + + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-enum-2.c b/gcc/testsuite/gcc.dg/c2x-tag-enum-2.c new file mode 100644 index 00000000000..bbe872c1480 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-enum-2.c @@ -0,0 +1,23 @@ +/* + * { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// incomplete during construction + +enum A { B = 7 } y; +enum A { B = 7 }; + +enum A { B = _Generic(&y, enum A*: 1, default: 7) }; + +void g(void) +{ + enum A { B = _Generic(&y, enum A*: 1, default: 7) }; + _Static_assert(7 == B, ""); +} + +enum X { E = 1, F = 1 + 1 }; +enum X { F = 2, E = 1 }; + + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-enum-3.c b/gcc/testsuite/gcc.dg/c2x-tag-enum-3.c new file mode 100644 index 00000000000..6f65bb73ef6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-enum-3.c @@ -0,0 +1,7 @@ +/* { dg-do compile } + * { dg-options "-std=c2x" } + */ + +enum A { N = 0 * sizeof(enum A { M = 1 }) }; /* { dg-error "nested" } */ + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-enum-4.c b/gcc/testsuite/gcc.dg/c2x-tag-enum-4.c new file mode 100644 index 00000000000..413b1fe8110 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-enum-4.c @@ -0,0 +1,22 @@ +/* { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// fixed underlying types + +enum A : int { N = 1 } x1 = { }; +enum B : int { M = 1 } x2 = { }; +enum C { U = 1 } x3 = { }; + +void f(void) +{ + enum A : int { N = 1 } y1 = x1; + enum B : short { M = 1 } y2; + y2 = x2; + enum B : short { M = 1 } y2b; + enum Bb : short { V = 1 } y2d = x2; + enum B : short { M = 1 } *y2e = &x2; /* { dg-warning "incompatible" } */ + enum B : short { M = 1 } y2c = x2; + enum C { U = 1 } y3 = x3; +} + From patchwork Sat Aug 26 16:25:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1826419 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=ytg1DN+V; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RY2Hf2203z1yg5 for ; Sun, 27 Aug 2023 02:25:50 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1AC5538582A1 for ; Sat, 26 Aug 2023 16:25:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1AC5538582A1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1693067148; bh=PbsQ8L6rtdc+KKaCZF/cjOg6jEU4Ff4/bq3wuYyBaJ0=; h=Subject:To:Cc:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=ytg1DN+VB6jy0aNe+HZFvyVCUQlrQ9y93KdBRrOjIZESKuAYvtWsegkAnoDDLUEIr EJZ50FoIFKoaS+hSqNRd9Aal1eX31L6gWRX0Pno4ldoE6MEeBuKOxJ48LlCOQU6l4r 5CmeDOHp/9z5Ltvp1vhddHxCb6dBKWjb+tLc6B64= 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 1DB863858C53 for ; Sat, 26 Aug 2023 16:25:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1DB863858C53 Received: from vra-173-28.tugraz.at (vra-173-28.tugraz.at [129.27.173.28]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4RY2H23K2tz3wkf; Sat, 26 Aug 2023 18:25:18 +0200 (CEST) Message-ID: <340e5e37051a32c9637ae221e17c75f9421840a8.camel@tugraz.at> Subject: [C PATCH 5/6] c23: aliasing of compatible tagged types To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 26 Aug 2023 18:25:18 +0200 In-Reply-To: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.camel@tugraz.at> References: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.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.116 X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Martin Uecker via Gcc-patches From: Martin Uecker Reply-To: Martin Uecker Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Tell the backend which types are equivalent by setting TYPE_CANONICAL to one struct in the set of equivalent structs. Structs are considered equivalent by ignoring all sizes of arrays nested in types below field level. gcc/c: * c-decl.cc (c_struct_hasher): Hash stable for struct types. (c_struct_hasher::hash, c_struct_hasher::equal): New functions. (finish_struct): Set TYPE_CANONICAL to first struct in equivalence class. * c-objc-common.cc (c_get_alias_set): Let structs or unions with variable size alias anything. * c-tree.h (comptypes_equiv): New prototype. * c-typeck.cc (comptypes_equiv): New function. (comptypes_internal): Implement equivalence mode. (tagged_types_tu_compatible): Implement equivalence mode. gcc/testsuite: * gcc.dg/c2x-tag-2.c: Remove xfail. * gcc.dg/c2x-tag-6.c: Remove xfail. * gcc.dg/c2x-tag-alias-1.c: New test. * gcc.dg/c2x-tag-alias-2.c: New test. * gcc.dg/c2x-tag-alias-3.c: New test. * gcc.dg/c2x-tag-alias-4.c: New test. * gcc.dg/c2x-tag-alias-5.c: New test. * gcc.dg/c2x-tag-alias-6.c: New test. * gcc.dg/c2x-tag-alias-7.c: New test. * gcc.dg/c2x-tag-alias-8.c: New test. --- gcc/c/c-decl.cc | 48 +++++++++++++ gcc/c/c-objc-common.cc | 5 ++ gcc/c/c-tree.h | 1 + gcc/c/c-typeck.cc | 31 ++++++++ gcc/testsuite/gcc.dg/c2x-tag-2.c | 2 +- gcc/testsuite/gcc.dg/c2x-tag-6.c | 2 +- gcc/testsuite/gcc.dg/c2x-tag-alias-1.c | 48 +++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-alias-2.c | 73 +++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-alias-3.c | 48 +++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-alias-4.c | 73 +++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-alias-5.c | 30 ++++++++ gcc/testsuite/gcc.dg/c2x-tag-alias-6.c | 77 ++++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-alias-7.c | 98 ++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-tag-alias-8.c | 90 +++++++++++++++++++++++ 14 files changed, 624 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-1.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-2.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-3.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-4.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-5.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-6.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-7.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-8.c diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index b514e8a35ee..2137ba8b845 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -603,6 +603,36 @@ public: auto_vec typedefs_seen; }; + +/* Hash table for structs and unions. */ +struct c_struct_hasher : ggc_ptr_hash +{ + static hashval_t hash (tree t); + static bool equal (tree, tree); +}; + +/* Hash an RECORD OR UNION. */ +hashval_t +c_struct_hasher::hash (tree type) +{ + inchash::hash hstate; + + hstate.add_int (TREE_CODE (type)); + hstate.add_object (TYPE_NAME (type)); + + return hstate.end (); +} + +/* Compare two RECORD or UNION types. */ +bool +c_struct_hasher::equal (tree t1, tree t2) +{ + return comptypes_equiv_p (t1, t2); +} + +/* All tagged typed so that TYPE_CANONICAL can be set correctly. */ +static GTY (()) hash_table *c_struct_htab; + /* Information for the struct or union currently being parsed, or NULL if not parsing a struct or union. */ static class c_struct_parse_info *struct_parse_info; @@ -9503,6 +9533,24 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, C_TYPE_BEING_DEFINED (t) = 0; + /* Set type canonical based on equivalence class. */ + if (flag_isoc2x) + { + if (NULL == c_struct_htab) + c_struct_htab = hash_table::create_ggc (61); + + hashval_t hash = c_struct_hasher::hash (t); + + tree *e = c_struct_htab->find_slot_with_hash (t, hash, INSERT); + if (*e) + TYPE_CANONICAL (t) = *e; + else + { + TYPE_CANONICAL (t) = t; + *e = t; + } + } + tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)); for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) { diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc index e4aed61ed00..992225bbb29 100644 --- a/gcc/c/c-objc-common.cc +++ b/gcc/c/c-objc-common.cc @@ -389,6 +389,11 @@ c_get_alias_set (tree t) if (TREE_CODE (t) == ENUMERAL_TYPE) return get_alias_set (ENUM_UNDERLYING_TYPE (t)); + /* Structs with variable size can alias different incompatible + structs. Let them alias anything. */ + if (RECORD_OR_UNION_TYPE_P (t) && C_TYPE_VARIABLE_SIZE (t)) + return 0; + return c_common_get_alias_set (t); } diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 511fd9ee0e5..1a8e8f072bd 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -748,6 +748,7 @@ extern tree require_complete_type (location_t, tree); extern bool same_translation_unit_p (const_tree, const_tree); extern int comptypes (tree, tree); extern bool comptypes_same_p (tree, tree); +extern int comptypes_equiv_p (tree, tree); extern int comptypes_check_different_types (tree, tree, bool *); extern int comptypes_check_enum_int (tree, tree, bool *); extern bool c_mark_addressable (tree, bool = false); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 2b79cbba950..2489fa1e3d1 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1041,6 +1041,7 @@ struct comptypes_data { bool different_types_p; bool warning_needed; bool anon_field; + bool equiv; const struct tagged_tu_seen_cache* cache; }; @@ -1101,6 +1102,21 @@ comptypes_check_different_types (tree type1, tree type2, return ret ? (data.warning_needed ? 2 : 1) : 0; } + + +/* Like comptypes, but if it returns nonzero for struct and union + types considered equivalent for aliasing purposes. */ + +int +comptypes_equiv_p (tree type1, tree type2) +{ + struct comptypes_data data = { }; + data.equiv = true; + bool ret = comptypes_internal (type1, type2, &data); + + return ret; +} + /* Return true if TYPE1 and TYPE2 are compatible types for assignment or various other operations. If they are compatible but a warning may @@ -1227,6 +1243,9 @@ comptypes_internal (const_tree type1, const_tree type2, if ((d1 == NULL_TREE) != (d2 == NULL_TREE)) data->different_types_p = true; + /* ignore size mismatches */ + if (data->equiv) + return 1; /* Sizes must match unless one is missing or variable. */ if (d1 == NULL_TREE || d2 == NULL_TREE || d1 == d2) return true; @@ -1443,6 +1462,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2))) return false; + if (data->equiv && (C_TYPE_VARIABLE_SIZE (t1) || C_TYPE_VARIABLE_SIZE (t2))) + return 0; + for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2; s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2)) @@ -1462,6 +1484,15 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1), DECL_FIELD_BIT_OFFSET (s2)) != 1) return false; + + tree st1 = TYPE_SIZE (TREE_TYPE (s1)); + tree st2 = TYPE_SIZE (TREE_TYPE (s2)); + + if (data->equiv + && st1 && TREE_CODE (st1) == INTEGER_CST + && st2 && TREE_CODE (st2) == INTEGER_CST + && !tree_int_cst_equal (st1, st2)) + return 0; } return true; diff --git a/gcc/testsuite/gcc.dg/c2x-tag-2.c b/gcc/testsuite/gcc.dg/c2x-tag-2.c index a68392e1fab..e28c2b5eea2 100644 --- a/gcc/testsuite/gcc.dg/c2x-tag-2.c +++ b/gcc/testsuite/gcc.dg/c2x-tag-2.c @@ -1,4 +1,4 @@ -/* { dg-do { compile xfail { *-*-* } } } +/* { dg-do compile } * { dg-options "-std=c2x" } */ diff --git a/gcc/testsuite/gcc.dg/c2x-tag-6.c b/gcc/testsuite/gcc.dg/c2x-tag-6.c index bf7cfb342d4..95a04bf9b0e 100644 --- a/gcc/testsuite/gcc.dg/c2x-tag-6.c +++ b/gcc/testsuite/gcc.dg/c2x-tag-6.c @@ -1,5 +1,5 @@ /* - * { dg-do { run xfail { "*-*-*" } } } + * { dg-do run } * { dg-options "-std=c2x" } */ diff --git a/gcc/testsuite/gcc.dg/c2x-tag-alias-1.c b/gcc/testsuite/gcc.dg/c2x-tag-alias-1.c new file mode 100644 index 00000000000..dfa1f084743 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-alias-1.c @@ -0,0 +1,48 @@ +/* + * { dg-do run } + * { dg-options "-std=c2x -O2" } + */ + + +struct foo { int x; }; + +int test_foo(struct foo* a, void* b) +{ + a->x = 1; + + struct foo { int x; }* p = b; + p->x = 2; + + return a->x; +} + + +enum bar { A = 1, B = 3 }; + +int test_bar(enum bar* a, void* b) +{ + *a = A; + + enum bar { A = 1, B = 3 }* p = b; + *p = B; + + return *a; +} + + +int main() +{ + struct foo y; + + if (2 != test_foo(&y, &y)) + __builtin_abort(); + + enum bar z; + + if (A == test_bar(&z, &z)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-alias-2.c b/gcc/testsuite/gcc.dg/c2x-tag-alias-2.c new file mode 100644 index 00000000000..1354adb3483 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-alias-2.c @@ -0,0 +1,73 @@ +/* + * { dg-do run } + * { dg-options "-std=c2x -O2" } + */ + + +struct foo { int x; }; + +int test_foo1(struct foo* a, void* b) +{ + a->x = 1; + + struct foo { int x; int y; }* p = b; + p->x = 2; + + return a->x; +} + +int test_foo2(struct foo* a, void* b) +{ + a->x = 1; + + struct fox { int x; }* p = b; + p->x = 2; + + return a->x; +} + +enum bar { A = 1, B = 3, C = 5, D = 9 }; + +int test_bar1(enum bar* a, void* b) +{ + *a = A; + + enum bar { A = 1, B = 3, C = 6, D = 9 }* p = b; + *p = B; + + return *a; +} + +int test_bar2(enum bar* a, void* b) +{ + *a = A; + + enum baX { A = 1, B = 3, C = 5, D = 9 }* p = b; + *p = B; + + return *a; +} + + +int main() +{ + struct foo y; + + if (1 != test_foo1(&y, &y)) + __builtin_abort(); + + if (1 != test_foo2(&y, &y)) + __builtin_abort(); + + enum bar z; + + if (A == test_bar1(&z, &z)) + __builtin_abort(); + + if (A == test_bar2(&z, &z)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-alias-3.c b/gcc/testsuite/gcc.dg/c2x-tag-alias-3.c new file mode 100644 index 00000000000..ec086dd52ab --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-alias-3.c @@ -0,0 +1,48 @@ +/* + * { dg-do run } + * { dg-options "-std=c2x -flto -O2" } + */ + + +struct foo { int x; }; + +int test_foo(struct foo* a, void* b) +{ + a->x = 1; + + struct foo { int x; }* p = b; + p->x = 2; + + return a->x; +} + + +enum bar { A = 1, B = 3 }; + +int test_bar(enum bar* a, void* b) +{ + *a = A; + + enum bar { A = 1, B = 3 }* p = b; + *p = B; + + return *a; +} + + +int main() +{ + struct foo y; + + if (2 != test_foo(&y, &y)) + __builtin_abort(); + + enum bar z; + + if (A == test_bar(&z, &z)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-alias-4.c b/gcc/testsuite/gcc.dg/c2x-tag-alias-4.c new file mode 100644 index 00000000000..537a1874454 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-alias-4.c @@ -0,0 +1,73 @@ +/* + * { dg-do run } + * { dg-options "-std=c2x -flto -O2" } + */ + + +struct foo { int x; }; + +int test_foo1(struct foo* a, void* b) +{ + a->x = 1; + + struct foo { int x; int y; }* p = b; + p->x = 2; + + return a->x; +} + +int test_foo2(struct foo* a, void* b) +{ + a->x = 1; + + struct fox { int x; }* p = b; + p->x = 2; + + return a->x; +} + +enum bar { A = 1, B = 3, C = 5, D = 9 }; + +int test_bar1(enum bar* a, void* b) +{ + *a = A; + + enum bar { A = 1, B = 3, C = 6, D = 9 }* p = b; + *p = B; + + return *a; +} + +int test_bar2(enum bar* a, void* b) +{ + *a = A; + + enum baX { A = 1, B = 3, C = 5, D = 9 }* p = b; + *p = B; + + return *a; +} + + +int main() +{ + struct foo y; + + if (1 != test_foo1(&y, &y)) + __builtin_abort(); + + if (1 != test_foo2(&y, &y)) + __builtin_abort(); + + enum bar z; + + if (A == test_bar1(&z, &z)) + __builtin_abort(); + + if (A == test_bar2(&z, &z)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-alias-5.c b/gcc/testsuite/gcc.dg/c2x-tag-alias-5.c new file mode 100644 index 00000000000..061676c2672 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-alias-5.c @@ -0,0 +1,30 @@ +/* { dg-do run } + * { dg-options "-std=c2x -O2" } + */ + +// not sure this is wise, but this was already like thi sbefore + +typedef struct { int x; } foo_t; + +int test_foo(foo_t* a, void* b) +{ + a->x = 1; + + struct { int x; }* p = b; + p->x = 2; + + return a->x; +} + + +int main() +{ + foo_t y; + + if (1 != test_foo(&y, &y)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-alias-6.c b/gcc/testsuite/gcc.dg/c2x-tag-alias-6.c new file mode 100644 index 00000000000..3617a159d7c --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-alias-6.c @@ -0,0 +1,77 @@ +/* + * { dg-do run } + * { dg-options "-std=c2x -O2" } + */ + + +/* We check that we tolerate differences for + * optimization. + */ + + +struct bar0 { int x; int f[3]; int y; }; + +int test_bar0(struct bar0* a, void* b) +{ + a->x = 1; + + struct bar0 { int x; int f[4]; int y; }* p = b; + p->x = 2; + + return a->x; +} + + + +struct bar1 { int x; int (*f)[3]; }; + +int test_bar1(struct bar1* a, void* b) +{ + a->x = 1; + + struct bar1 { int x; int (*f)[3]; }* p = b; + p->x = 2; + + return a->x; +} + + +struct bar2 { int x; int (*f)[3]; }; + +int test_bar2(struct bar2* a, void* b) +{ + a->x = 1; + + struct bar2 { int x; int (*f)[4]; }* p = b; + p->x = 2; + + return a->x; +} + + + +int main() +{ + // control + + struct bar0 z0; + + if (1 != test_bar0(&z0, &z0)) + __builtin_abort(); + + // this could be different + struct bar1 z1; + + if (2 != test_bar1(&z1, &z1)) + __builtin_abort(); + + struct bar2 z2; + + if (2 != test_bar2(&z2, &z2)) + __builtin_abort(); + + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-alias-7.c b/gcc/testsuite/gcc.dg/c2x-tag-alias-7.c new file mode 100644 index 00000000000..0c1114e2b70 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-alias-7.c @@ -0,0 +1,98 @@ +/* + * { dg-do run } + * { dg-options "-std=c2x -O2" } + */ + + + +struct bar { int x; int f[]; }; + +int test_bar1(struct bar* a, void* b) +{ + a->x = 1; + + struct bar { int x; int f[]; }* p = b; + struct bar* q = a; + p->x = 2; + + return a->x; +} + +int test_bar2(struct bar* a, void* b) +{ + a->x = 1; + + struct bar { int x; int f[0]; }* p = b; + struct bar* q = a; + p->x = 2; + + return a->x; +} + +int test_bar3(struct bar* a, void* b) +{ + a->x = 1; + + struct bar { int x; int f[1]; }* p = b; + struct bar* q = a; /* { dg-warning "incompatible" } */ + p->x = 2; + + return a->x; +} + + +int test_bar4(struct bar* a, void* b) +{ + a->x = 1; + + int n = 3; + struct bar { int x; int f[n]; }* p = b; + struct bar* q = a; + p->x = 2; + + return a->x; +} + + +struct foo { int x; int f[3]; }; + + +int test_foo1(struct foo* a, void* b) +{ + a->x = 1; + + int n = 3; + struct foo { int x; int f[n]; }* p = b; + struct foo* q = a; + p->x = 2; + + return a->x; +} + + + +int main() +{ + struct bar z; + + if (2 != test_bar1(&z, &z)) + __builtin_abort(); + + if (2 != test_bar2(&z, &z)) + __builtin_abort(); +#if 0 + if (1 != test_bar3(&z, &z)) + __builtin_abort(); +#endif + if (2 != test_bar4(&z, &z)) + __builtin_abort(); + + struct foo y; + + if (2 != test_foo1(&y, &y)) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-alias-8.c b/gcc/testsuite/gcc.dg/c2x-tag-alias-8.c new file mode 100644 index 00000000000..e3f6173005f --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-alias-8.c @@ -0,0 +1,90 @@ +/* + * { dg-do run } + * { dg-options "-std=c2x -O2" } + */ + + +/* We check that we tolerate differences for + * optimization. + */ + +struct bar1 { int x; enum A1 { X1 = 1 } f; }; + +int test_bar1(struct bar1* a, void* b) +{ + a->x = 1; + + struct bar1 { int x; enum A1 { X1 = 2 } f; }* p = b; + p->x = 2; + + return a->x; +} + + +struct bar2 { int x; enum A2 { X2 = 1 } f; }; + +int test_bar2(struct bar2* a, void* b) +{ + a->x = 1; + + struct bar2 { int x; enum B2 { X2 = 1 } f; }* p = b; + p->x = 2; + + return a->x; +} + + + +struct bar3 { int x; enum A3 { X3 = 1 } f; }; + +int test_bar3(struct bar3* a, void* b) +{ + a->x = 1; + + struct bar3 { int x; enum A3 { Y3 = 1 } f; }* p = b; + p->x = 2; + + return a->x; +} + + +struct bar4 { int x; enum { Z4 = 1 } f; }; + +int test_bar4(struct bar4* a, void* b) +{ + a->x = 1; + + struct bar4 { int x; enum { Z4 = 1 } f; }* p = b; + p->x = 2; + + return a->x; +} + + + +int main() +{ + struct bar1 z1; + + if (1 != test_bar1(&z1, &z1)) + __builtin_abort(); + + struct bar2 z2; + + if (1 != test_bar2(&z2, &z2)) + __builtin_abort(); + + struct bar3 z3; + + if (1 != test_bar3(&z3, &z3)) + __builtin_abort(); + + struct bar4 z4; + + if (1 != test_bar4(&z4, &z4)) + __builtin_abort(); + + return 0; +} + + From patchwork Sat Aug 26 16:26:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1826420 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=owVhigcf; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RY2JT4P43z1yg5 for ; Sun, 27 Aug 2023 02:26:33 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A47E63857714 for ; Sat, 26 Aug 2023 16:26:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A47E63857714 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1693067191; bh=n7v2ljxKwc3ZmPkQevWatbNet3EUAp+TmHrA2UjZW2A=; h=Subject:To:Cc:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=owVhigcfhn/eADTkzTbXA8IHNIs4dXmqYYfyD9tyyz6Q73Wz7+LEBGLvjXJLPhQNW c7Ln8rWFmeM1k54pv2zwhbHBbx4U0tuknrfWbDTD25M7XOxrKNtYfNK6+OSmBqrP2P dy4mkZgr4jvmCIVxBNhYStp0NT6xc0XmmZj5rlsI= 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 B21FC3858413 for ; Sat, 26 Aug 2023 16:26:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B21FC3858413 Received: from vra-173-28.tugraz.at (vra-173-28.tugraz.at [129.27.173.28]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4RY2Hz02Kyz3wkf; Sat, 26 Aug 2023 18:26:06 +0200 (CEST) Message-ID: <748ad71f62bb0e306d2fc050763b2e69ca81190f.camel@tugraz.at> Subject: [C PATCH 6/6] c23: construct composite type for tagged types To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 26 Aug 2023 18:26:06 +0200 In-Reply-To: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.camel@tugraz.at> References: <4b3866a8cc9b48f3be97c004dedbac8e9149da63.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.116 X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Martin Uecker via Gcc-patches From: Martin Uecker Reply-To: Martin Uecker Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Support for constructing composite type for structs and unions in C23. gcc/c: * c-typeck.cc (composite_type_internal): Adapted from composite_type to support structs and unions. (composite_type): New wrapper function. (build_conditional_operator): Return composite type. gcc/testsuite: * gcc.dg/c2x-tag-composite-1.c: New test. * gcc.dg/c2x-tag-composite-2.c: New test. * gcc.dg/c2x-tag-composite-3.c: New test. * gcc.dg/c2x-tag-composite-4.c: New test. --- gcc/c/c-typeck.cc | 114 +++++++++++++++++---- gcc/testsuite/gcc.dg/c2x-tag-composite-1.c | 26 +++++ gcc/testsuite/gcc.dg/c2x-tag-composite-2.c | 16 +++ gcc/testsuite/gcc.dg/c2x-tag-composite-3.c | 17 +++ gcc/testsuite/gcc.dg/c2x-tag-composite-4.c | 21 ++++ 5 files changed, 176 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-1.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-2.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-3.c create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-4.c diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 2489fa1e3d1..357367eab09 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -381,8 +381,15 @@ build_functype_attribute_variant (tree ntype, tree otype, tree attrs) nonzero; if that isn't so, this may crash. In particular, we assume that qualifiers match. */ +struct composite_cache { + tree t1; + tree t2; + tree composite; + struct composite_cache* next; +}; + tree -composite_type (tree t1, tree t2) +composite_type_internal (tree t1, tree t2, struct composite_cache* cache) { enum tree_code code1; enum tree_code code2; @@ -425,7 +432,8 @@ composite_type (tree t1, tree t2) { tree pointed_to_1 = TREE_TYPE (t1); tree pointed_to_2 = TREE_TYPE (t2); - tree target = composite_type (pointed_to_1, pointed_to_2); + tree target = composite_type_internal (pointed_to_1, + pointed_to_2, cache); t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false); t1 = build_type_attribute_variant (t1, attributes); return qualify_type (t1, t2); @@ -433,7 +441,8 @@ composite_type (tree t1, tree t2) case ARRAY_TYPE: { - tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2)); + tree elt = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2), + cache); int quals; tree unqual_elt; tree d1 = TYPE_DOMAIN (t1); @@ -501,9 +510,61 @@ composite_type (tree t1, tree t2) return build_type_attribute_variant (t1, attributes); } - case ENUMERAL_TYPE: case RECORD_TYPE: case UNION_TYPE: + if (flag_isoc2x && !comptypes_same_p (t1, t2)) + { + gcc_checking_assert (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2)); + gcc_checking_assert (comptypes (t1, t2)); + + /* If a composite type for these two types is already under + construction, return it. */ + + for (struct composite_cache *c = cache; c != NULL; c = c->next) + if (c->t1 == t1 && c->t2 == t2) + return c->composite; + + /* Otherwise, create a new type node and link it into the cache. */ + + tree n = make_node (code1); + struct composite_cache cache2 = { t1, t2, n, cache }; + cache = &cache2; + + tree f1 = TYPE_FIELDS (t1); + tree f2 = TYPE_FIELDS (t2); + tree fields = NULL_TREE; + + for (tree a = f1, b = f2; a && b; + a = DECL_CHAIN (a), b = DECL_CHAIN (b)) + { + tree ta = TREE_TYPE (a); + tree tb = TREE_TYPE (b); + + gcc_assert (DECL_NAME (a) == DECL_NAME (b)); + gcc_assert (comptypes (ta, tb)); + + tree f = build_decl (input_location, FIELD_DECL, DECL_NAME (a), + composite_type_internal (ta, tb, cache)); + + DECL_FIELD_CONTEXT (f) = n; + DECL_CHAIN (f) = fields; + fields = f; + } + + TYPE_NAME (n) = TYPE_NAME (t1); + TYPE_FIELDS (n) = nreverse (fields); + TYPE_ATTRIBUTES (n) = attributes; + layout_type (n); + n = build_type_attribute_variant (n, attributes); + n = qualify_type (n, t1); + + gcc_checking_assert (comptypes (n, t1)); + gcc_checking_assert (comptypes (n, t2)); + + return n; + } + /* FALLTHRU */ + case ENUMERAL_TYPE: if (attributes != NULL) { /* Try harder not to create a new aggregate type. */ @@ -518,7 +579,8 @@ composite_type (tree t1, tree t2) /* Function types: prefer the one that specified arg types. If both do, merge the arg types. Also merge the return types. */ { - tree valtype = composite_type (TREE_TYPE (t1), TREE_TYPE (t2)); + tree valtype = composite_type_internal (TREE_TYPE (t1), + TREE_TYPE (t2), cache); tree p1 = TYPE_ARG_TYPES (t1); tree p2 = TYPE_ARG_TYPES (t2); int len; @@ -563,6 +625,16 @@ composite_type (tree t1, tree t2) for (; p1 && p1 != void_list_node; p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n)) { + tree mv1 = TREE_VALUE (p1); + if (mv1 && mv1 != error_mark_node + && TREE_CODE (mv1) != ARRAY_TYPE) + mv1 = TYPE_MAIN_VARIANT (mv1); + + tree mv2 = TREE_VALUE (p2); + if (mv2 && mv2 != error_mark_node + && TREE_CODE (mv2) != ARRAY_TYPE) + mv2 = TYPE_MAIN_VARIANT (mv2); + /* A null type means arg type is not specified. Take whatever the other function type has. */ if (TREE_VALUE (p1) == NULL_TREE) @@ -583,10 +655,6 @@ composite_type (tree t1, tree t2) && TREE_VALUE (p1) != TREE_VALUE (p2)) { tree memb; - tree mv2 = TREE_VALUE (p2); - if (mv2 && mv2 != error_mark_node - && TREE_CODE (mv2) != ARRAY_TYPE) - mv2 = TYPE_MAIN_VARIANT (mv2); for (memb = TYPE_FIELDS (TREE_VALUE (p1)); memb; memb = DECL_CHAIN (memb)) { @@ -596,8 +664,9 @@ composite_type (tree t1, tree t2) mv3 = TYPE_MAIN_VARIANT (mv3); if (comptypes (mv3, mv2)) { - TREE_VALUE (n) = composite_type (TREE_TYPE (memb), - TREE_VALUE (p2)); + TREE_VALUE (n) = composite_type_internal (TREE_TYPE (memb), + TREE_VALUE (p2), + cache); pedwarn (input_location, OPT_Wpedantic, "function types not truly compatible in ISO C"); goto parm_done; @@ -608,10 +677,6 @@ composite_type (tree t1, tree t2) && TREE_VALUE (p2) != TREE_VALUE (p1)) { tree memb; - tree mv1 = TREE_VALUE (p1); - if (mv1 && mv1 != error_mark_node - && TREE_CODE (mv1) != ARRAY_TYPE) - mv1 = TYPE_MAIN_VARIANT (mv1); for (memb = TYPE_FIELDS (TREE_VALUE (p2)); memb; memb = DECL_CHAIN (memb)) { @@ -621,15 +686,17 @@ composite_type (tree t1, tree t2) mv3 = TYPE_MAIN_VARIANT (mv3); if (comptypes (mv3, mv1)) { - TREE_VALUE (n) = composite_type (TREE_TYPE (memb), - TREE_VALUE (p1)); + TREE_VALUE (n) + = composite_type_internal (TREE_TYPE (memb), + TREE_VALUE (p1), + cache); pedwarn (input_location, OPT_Wpedantic, "function types not truly compatible in ISO C"); goto parm_done; } } } - TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2)); + TREE_VALUE (n) = composite_type_internal (mv1, mv2, cache); parm_done: ; } @@ -641,7 +708,13 @@ composite_type (tree t1, tree t2) default: return build_type_attribute_variant (t1, attributes); } +} +tree +composite_type (tree t1, tree t2) +{ + struct composite_cache cache = { }; + return composite_type_internal (t1, t2, &cache); } /* Return the type of a conditional expression between pointers to @@ -5480,6 +5553,11 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, result_type = type2; else if (code1 == POINTER_TYPE && code2 == NULLPTR_TYPE) result_type = type1; + else if (RECORD_OR_UNION_TYPE_P (type1) && RECORD_OR_UNION_TYPE_P (type2) + && comptypes (TYPE_MAIN_VARIANT (type1), + TYPE_MAIN_VARIANT (type2))) + result_type = composite_type (TYPE_MAIN_VARIANT (type1), + TYPE_MAIN_VARIANT (type2)); if (!result_type) { diff --git a/gcc/testsuite/gcc.dg/c2x-tag-composite-1.c b/gcc/testsuite/gcc.dg/c2x-tag-composite-1.c new file mode 100644 index 00000000000..aae11f6cee2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-composite-1.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + +void b(void) +{ + int n = 3; + + extern struct f { char (*x)[3]; char (*y)[]; } q; + { extern struct f { char (*x)[]; char (*y)[4]; } q; + _Static_assert(3 == sizeof(*q.x), ""); + _Static_assert(4 == sizeof(*q.y), ""); + } + { extern struct f { char (*x)[2]; char (*y)[]; } q; (void)q; } /* { dg-error "conflicting" } */ + + { struct f { char (*x)[n]; char (*y)[3]; }* qp = &q; (void)*qp; } + (void)q; + + static struct g { int a; char buf[n]; } *p; (void)p; + { static struct g { int a; char buf[3]; } *p; (void)p; } + + static struct h { int a; void (*s)(char buf[n]); } *t; (void)t; + { static struct h { int a; void (*s)(char buf[3]); } *t; (void)t; } +} + + + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-composite-2.c b/gcc/testsuite/gcc.dg/c2x-tag-composite-2.c new file mode 100644 index 00000000000..dfc4336751a --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-composite-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + + +struct foo { int (*(*i)(void))[]; } x; + + +void f(void) +{ + const struct foo { int (*(*i)())[3]; } y; + _Static_assert(3 * sizeof(int) == sizeof(*((1 ? &x : &y)->i())), ""); +} + +void g(struct foo { int x; } a); +void g(const struct foo { int x; } a); + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-composite-3.c b/gcc/testsuite/gcc.dg/c2x-tag-composite-3.c new file mode 100644 index 00000000000..02159f3c44d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-composite-3.c @@ -0,0 +1,17 @@ +/* { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// bit-fields + +extern struct foo { int x:3; } x; +struct foo { int x:3; } y; + +void f(void) +{ + extern typeof(*(1 ? &x : &y)) x; + &x.x; /* { dg-error "bit-field" } */ +} + +struct foo { int x:2; }; /* { dg-error "redefinition" } */ + diff --git a/gcc/testsuite/gcc.dg/c2x-tag-composite-4.c b/gcc/testsuite/gcc.dg/c2x-tag-composite-4.c new file mode 100644 index 00000000000..1bd98cc1a44 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-tag-composite-4.c @@ -0,0 +1,21 @@ +/* { dg-do compile } + * { dg-options "-std=c2x" } + */ + +// conditional operator + +void f(void) +{ + struct foo { int x; } a; + struct foo { int x; } b; + 1 ? a : b; +} + +struct bar { int x; } a; + +void g(void) +{ + struct bar { int x; } b; + 1 ? a : b; +} +