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 ();