From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from hognose1.porkbun.com (hognose1.porkbun.com [35.82.102.206]) by sourceware.org (Postfix) with ESMTPS id F376E3857030 for ; Sun, 23 Oct 2022 16:53:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org F376E3857030 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=undefinedbehaviour.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=undefinedbehaviour.org Received: by hognose1.porkbun.com (Postfix, from userid 497) id DA7AA421D8; Sun, 23 Oct 2022 16:53:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=undefinedbehaviour.org; s=default; t=1666544013; bh=vbsKIohllBeXlLj3uuVu2WRG2smjh9w32+nJRBW5nP0=; h=From:To:Cc:Subject:Date; b=RGwB+pTW2jdRdr/lT9yXhTGAO4YD0k4DeH/m8lg4Rv9AKtKHZQ9DX1I6/LdE/fjku xo/rtxgdWLG40MqHs/rWCgFjUR8w2dvurAXlLiDKWl0rsmG1ZXoca7enBWwGBLoMdT qCmthQgNIazQPeHrv6Z2sA+uzHlLUzSVy7MZV9Iw= X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-Spam-Level: X-Spam-Status: No, score=-14.0 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,SPF_HELO_PASS,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 Received: from localhost.localdomain (unknown [67.69.69.100]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) (Authenticated sender: keegan@undefinedbehaviour.org) by hognose1.porkbun.com (Postfix) with ESMTPSA id 36A0041EE1; Sun, 23 Oct 2022 16:53:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=undefinedbehaviour.org; s=default; t=1666544011; bh=vbsKIohllBeXlLj3uuVu2WRG2smjh9w32+nJRBW5nP0=; h=From:To:Cc:Subject:Date; b=ELsSMUpTjBSgfB4sgwRyO13bVToxm/0AJ6aQBN4kTmn3XW6H1XU2sV8bIdemv2AGJ dtqGLU5+0fNSr3NlsX4JBrEohiCkatmrcEaKobq4LBlxEIDk1aA21HSr89IY4BZ/7f HmwVlX4jP6v0hlyid6qitscnlGMZNU6rM0BQ9we0= From: Keegan Saunders To: gcc-patches@gcc.gnu.org Cc: Keegan Saunders Subject: [PATCH] c: If -fplan9-extensions, allow duplicate field declarations Date: Sun, 23 Oct 2022 12:52:24 -0400 Message-Id: <20221023165224.97237-1-keegan@undefinedbehaviour.org> X-Mailer: git-send-email 2.37.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: The Plan 9 compilers defer duplicate declaration checks until field resolution time. Further, there is a priority order of resolution such that field lookups first match the name, then typedef'd names before recursing into substructures. This enables large portions of the Plan 9 userspace and kernel to be compiled with GCC without modification. gcc/c/ChangeLog: * c-decl.cc (is_duplicate_field): Remove unused Plan 9 logic. (detect_field_duplicates_hash): Likewise. (detect_field_duplicates): If -fplan9-extensions, disable duplicate field detection. * c-typeck.cc (lookup_field_plan9): Implement the Plan 9 look up scheme. (lookup_field): Likewise. gcc/testsuite/ChangeLog: * gcc.dg/anon-struct-13.c: Add duplicate fields. Signed-off-by: Keegan Saunders --- gcc/c/c-decl.cc | 63 ++-------------- gcc/c/c-typeck.cc | 101 ++++++++++++++++++++------ gcc/testsuite/gcc.dg/anon-struct-13.c | 9 +++ 3 files changed, 96 insertions(+), 77 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 193e268f04e..539ad407f49 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -8538,41 +8538,7 @@ grokfield (location_t loc, static bool is_duplicate_field (tree x, tree y) { - if (DECL_NAME (x) != NULL_TREE && DECL_NAME (x) == DECL_NAME (y)) - return true; - - /* When using -fplan9-extensions, an anonymous field whose name is a - typedef can duplicate a field name. */ - if (flag_plan9_extensions - && (DECL_NAME (x) == NULL_TREE || DECL_NAME (y) == NULL_TREE)) - { - tree xt, xn, yt, yn; - - xt = TREE_TYPE (x); - if (DECL_NAME (x) != NULL_TREE) - xn = DECL_NAME (x); - else if (RECORD_OR_UNION_TYPE_P (xt) - && TYPE_NAME (xt) != NULL_TREE - && TREE_CODE (TYPE_NAME (xt)) == TYPE_DECL) - xn = DECL_NAME (TYPE_NAME (xt)); - else - xn = NULL_TREE; - - yt = TREE_TYPE (y); - if (DECL_NAME (y) != NULL_TREE) - yn = DECL_NAME (y); - else if (RECORD_OR_UNION_TYPE_P (yt) - && TYPE_NAME (yt) != NULL_TREE - && TREE_CODE (TYPE_NAME (yt)) == TYPE_DECL) - yn = DECL_NAME (TYPE_NAME (yt)); - else - yn = NULL_TREE; - - if (xn != NULL_TREE && xn == yn) - return true; - } - - return false; + return DECL_NAME (x) != NULL_TREE && DECL_NAME (x) == DECL_NAME (y); } /* Subroutine of detect_field_duplicates: add the fields of FIELDLIST @@ -8599,19 +8565,6 @@ detect_field_duplicates_hash (tree fieldlist, else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) { detect_field_duplicates_hash (TYPE_FIELDS (TREE_TYPE (x)), htab); - - /* When using -fplan9-extensions, an anonymous field whose - name is a typedef can duplicate a field name. */ - if (flag_plan9_extensions - && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE - && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL) - { - tree xn = DECL_NAME (TYPE_NAME (TREE_TYPE (x))); - slot = htab->find_slot (xn, INSERT); - if (*slot) - error ("duplicate member %q+D", TYPE_NAME (TREE_TYPE (x))); - *slot = xn; - } } } @@ -8639,6 +8592,11 @@ detect_field_duplicates (tree fieldlist) if (objc_detect_field_duplicates (false)) return; + /* When using -fplan9-extensions, do not perform duplicate field + checks until a field look up is performed. */ + if (flag_plan9_extensions) + return; + /* First, see if there are more than "a few" fields. This is trivially true if there are zero or one fields. */ if (!fieldlist || !DECL_CHAIN (fieldlist)) @@ -8658,14 +8616,7 @@ detect_field_duplicates (tree fieldlist) if (timeout > 0) { for (x = DECL_CHAIN (fieldlist); x; x = DECL_CHAIN (x)) - /* When using -fplan9-extensions, we can have duplicates - between typedef names and fields. */ - if (DECL_NAME (x) - || (flag_plan9_extensions - && DECL_NAME (x) == NULL_TREE - && RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)) - && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE - && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL)) + if (DECL_NAME (x)) { for (y = fieldlist; y != x; y = TREE_CHAIN (y)) if (is_duplicate_field (y, x)) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index f9190680a3c..97ffa329ba7 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -95,6 +95,7 @@ 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 *); +static tree lookup_field_plan9 (tree, tree); static tree lookup_field (tree, tree); static int convert_arguments (location_t, vec, tree, vec *, vec *, tree, @@ -2280,6 +2281,81 @@ default_conversion (tree exp) return exp; } +/* Look up COMPONENT in a structure or union TYPE like a Plan 9 C compiler. + + Look up is performed in 3 passes: + 1. Look for field names that match the look up name. + 2. Look for anonymous records who's typedef name matches the look up name. + 3. Look for fields in embedded anonymous records. + + If the component name is not found, returns NULL_TREE. If the component + name references multiple fields, issue an error. */ + +static tree +lookup_field_plan9 (tree type, tree component) +{ + tree field; + tree found = NULL_TREE; + + /* Passes 1 & 2 are fused: conflicts are an error. */ + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + /* Pass 1. */ + if (DECL_NAME (field) == component) + { + if (found != NULL_TREE) + { + error ("duplicate member %q+D", found); + return NULL_TREE; + } + found = field; + } + + /* Pass 2. */ + if (DECL_NAME (field) == NULL_TREE + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) + { + if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE + && TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL + && (DECL_NAME (TYPE_NAME (TREE_TYPE (field))) + == component)) + { + if (found != NULL_TREE) + { + error ("duplicate member %q+D", found); + return NULL_TREE; + } + found = field; + } + } + } + + if (found != NULL_TREE) + return tree_cons (NULL_TREE, found, NULL_TREE); + + /* Pass 3. */ + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + if (DECL_NAME (field) == NULL_TREE + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) + { + tree anon = lookup_field_plan9 (TREE_TYPE (field), component); + + if (anon != NULL_TREE) + { + if (found != NULL_TREE) + { + error ("duplicate member %q+D", TREE_VALUE (nreverse (anon))); + return NULL_TREE; + } + found = tree_cons (NULL_TREE, field, anon); + } + } + } + + return found; +} + /* Look up COMPONENT in a structure or union TYPE. If the component name is not found, returns NULL_TREE. Otherwise, @@ -2294,6 +2370,10 @@ lookup_field (tree type, tree component) { tree field; + /* The Plan 9 compiler has a different field resolution scheme. */ + if (flag_plan9_extensions) + return lookup_field_plan9 (type, component); + /* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers to the field elements. Use a binary search on this array to quickly find the element. Otherwise, do a linear search. TYPE_LANG_SPECIFIC @@ -2329,17 +2409,6 @@ lookup_field (tree type, tree component) if (anon) return tree_cons (NULL_TREE, field, anon); - - /* The Plan 9 compiler permits referring - directly to an anonymous struct/union field - using a typedef name. */ - if (flag_plan9_extensions - && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE - && (TREE_CODE (TYPE_NAME (TREE_TYPE (field))) - == TYPE_DECL) - && (DECL_NAME (TYPE_NAME (TREE_TYPE (field))) - == component)) - break; } } @@ -2375,16 +2444,6 @@ lookup_field (tree type, tree component) if (anon) return tree_cons (NULL_TREE, field, anon); - - /* The Plan 9 compiler permits referring directly to an - anonymous struct/union field using a typedef - name. */ - if (flag_plan9_extensions - && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE - && TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL - && (DECL_NAME (TYPE_NAME (TREE_TYPE (field))) - == component)) - break; } if (DECL_NAME (field) == component) diff --git a/gcc/testsuite/gcc.dg/anon-struct-13.c b/gcc/testsuite/gcc.dg/anon-struct-13.c index 6a508141bac..c7b7d8cb101 100644 --- a/gcc/testsuite/gcc.dg/anon-struct-13.c +++ b/gcc/testsuite/gcc.dg/anon-struct-13.c @@ -5,6 +5,8 @@ struct A { char a; /* { dg-error "duplicate member" } */ + char b; + char b; }; struct B @@ -46,6 +48,13 @@ struct E struct D; }; +struct F +{ + char a; + char a; + char a; +}; + char f4 (struct E *p) { -- 2.37.1