From patchwork Thu Sep 30 03:50:56 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 66109 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id DE5E4B6F10 for ; Thu, 30 Sep 2010 13:51:23 +1000 (EST) Received: (qmail 1539 invoked by alias); 30 Sep 2010 03:51:20 -0000 Received: (qmail 1520 invoked by uid 22791); 30 Sep 2010 03:51:16 -0000 X-SWARE-Spam-Status: No, hits=-2.2 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, SPF_HELO_PASS, TW_MV, T_RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (74.125.121.35) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 30 Sep 2010 03:51:08 +0000 Received: from hpaq12.eem.corp.google.com (hpaq12.eem.corp.google.com [172.25.149.12]) by smtp-out.google.com with ESMTP id o8U3p5vE019851 for ; Wed, 29 Sep 2010 20:51:05 -0700 Received: from pwi6 (pwi6.prod.google.com [10.241.219.6]) by hpaq12.eem.corp.google.com with ESMTP id o8U3p3QU023804 for ; Wed, 29 Sep 2010 20:51:04 -0700 Received: by pwi6 with SMTP id 6so1217742pwi.25 for ; Wed, 29 Sep 2010 20:51:02 -0700 (PDT) Received: by 10.142.240.3 with SMTP id n3mr2481717wfh.26.1285818662783; Wed, 29 Sep 2010 20:51:02 -0700 (PDT) Received: from coign.google.com ([216.239.45.130]) by mx.google.com with ESMTPS id d10sm11056745wfe.10.2010.09.29.20.50.58 (version=TLSv1/SSLv3 cipher=RC4-MD5); Wed, 29 Sep 2010 20:51:00 -0700 (PDT) From: Ian Lance Taylor To: "Joseph S. Myers" Cc: gcc-patches@gcc.gnu.org Subject: Re: PATCH RFA: Support Plan 9 extensions in gcc References: Date: Wed, 29 Sep 2010 20:50:56 -0700 In-Reply-To: (Joseph S. Myers's message of "Tue, 28 Sep 2010 21:14:49 +0000 (UTC)") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org "Joseph S. Myers" writes: > On Sun, 26 Sep 2010, Ian Lance Taylor wrote: > >> Joseph Myers asked specifically about standardization; I very much doubt >> the Plan 9 folks care one way or another about whether this >> functionality is added to the standard. However, it seems to me >> unlikely that any contradictory functionality would be added. > > It is also the case that we now know what form of anonymous structures and > unions is in C1X and I implemented support for that in GCC. Thanks for the review. You are correct that I didn't fully grasp the fact that anonymous structures and unions are now implemented. > However, one case of ambiguity that this patch does not detect appears to > conflict with the standard semantics. > > typedef struct { int a; } s1; > struct s2 { s1; int s1; }; > int f(struct s2 *p) { return p->s1; } > > In C1X, p->s1 is an unambiguous reference to the int field. With > -fplan9-extensions, there is ambiguity; this is not detected as such, but > instead you get an error: > > t1.c:3:23: error: incompatible types when returning type 's1' but 'int' was expected > > Logically this option should perhaps cause such a case to be detected with > an error for duplicate fields (and so be documented as causing some code > to be rejected that is otherwise accepted). I have implemented this, and added a test case. > The duplicate field errors for anonymous structures and unions post-date > your previous patch. I don't actually see how the other cases of > ambiguity that your patch tries to detect can arise without an error being > given earlier for duplicate field names - they all involve multiple fields > with the same anonymous structure or union type, which would mean all the > fields within that type are duplicated. I agree. I have removed the ambiguity detection, and the code now relies on the duplicate field test. Here is the updated patch. Bootstrapped and tested on x86_64-unknown-linux-gnu. OK for mainline? Ian gcc/ChangeLog: 2010-09-29 Ian Lance Taylor * c-typeck.c (lookup_field): If -fplan9-extensions, permit referring to a field using a typedef name. (find_anonymous_field_with_type): New static function. (convert_to_anonymous_field): New static function. (convert_for_assignment): If -fplan9-extensions, permit converting pointer to struct to pointer to anonymous field. * c-decl.c (grokfield): If -fplan9-extensions, permit anonymous fields. (is_duplicate_field): New static function. (detect_field_duplicates_hash): If -fplan9-extensions, check for typedef names duplicating field names. (detect_field_duplicates): Likewise. * doc/invoke.texi (Option Summary): Mention -fplan9-extensions. (C Dialect Options): Document -fplan9-extensions. * doc/extend.texi (Unnamed Fields): Document -fplan9-extensions. gcc/c-family/ChangeLog: 2010-09-29 Ian Lance Taylor * c.opt (-fplan9-extensions): New option. gcc/testsuite/ChangeLog: 2010-09-29 Ian Lance Taylor * c-typeck.c (lookup_field): If -fplan9-extensions, permit referring to a field using a typedef name. (find_anonymous_field_with_type): New static function. (convert_to_anonymous_field): New static function. (convert_for_assignment): If -fplan9-extensions, permit converting pointer to struct to pointer to anonymous field. * c-decl.c (grokfield): If -fplan9-extensions, permit anonymous fields. (is_duplicate_field): New static function. (detect_field_duplicates_hash): If -fplan9-extensions, check for typedef names duplicating field names. (detect_field_duplicates): Likewise. * doc/invoke.texi (Option Summary): Mention -fplan9-extensions. (C Dialect Options): Document -fplan9-extensions. * doc/extend.texi (Unnamed Fields): Document -fplan9-extensions. Index: doc/extend.texi =================================================================== --- doc/extend.texi (revision 164724) +++ doc/extend.texi (working copy) @@ -13019,6 +13019,34 @@ also be a definition with a tag such as @samp{struct foo;}, or a reference to a @code{typedef} name for a previously defined structure or union type with a tag. +@opindex fplan9-extensions +The option @option{-fplan9-extensions} enables +@option{-fms-extensions} as well as two other extensions. First, a +pointer to a structure is automatically converted to a pointer to an +anonymous field for assignments and function calls. For example: + +@smallexample +struct s1 @{ int a; @}; +struct s2 @{ struct s1; @}; +extern void f1 (struct s1 *); +void f2 (struct s2 *p) @{ f1 (p); @} +@end smallexample + +In the call to @code{f1} inside @code{f2}, the pointer @code{p} is +converted into a pointer to the anonymous field. + +Second, when the type of an anonymous field is a @code{typedef} for a +@code{struct} or @code{union}, code may refer to the field using the +name of the @code{typedef}. + +@smallexample +typedef struct @{ int a; @} s1; +struct s2 @{ s1; @}; +s1 f1 (struct s2 *p) @{ return p->s1; @} +@end smallexample + +These usages are only permitted when they are not ambiguous. + @node Thread-Local @section Thread-Local Storage @cindex Thread-Local Storage Index: doc/invoke.texi =================================================================== --- doc/invoke.texi (revision 164724) +++ doc/invoke.texi (working copy) @@ -172,7 +172,7 @@ in the following sections. @gccoptlist{-ansi -std=@var{standard} -fgnu89-inline @gol -aux-info @var{filename} @gol -fno-asm -fno-builtin -fno-builtin-@var{function} @gol --fhosted -ffreestanding -fopenmp -fms-extensions @gol +-fhosted -ffreestanding -fopenmp -fms-extensions -fplan9-extensions @gol -trigraphs -no-integrated-cpp -traditional -traditional-cpp @gol -fallow-single-precision -fcond-mismatch -flax-vector-conversions @gol -fsigned-bitfields -fsigned-char @gol @@ -1689,6 +1689,16 @@ Some cases of unnamed fields in structur accepted with this option. @xref{Unnamed Fields,,Unnamed struct/union fields within structs/unions}, for details. +@item -fplan9-extensions +Accept some non-standard constructs used in Plan 9 code. + +This enables @option{-fms-extensions}, permits passing pointers to +structures with anonymous fields to functions which expect pointers to +elements of the type of the field, and permits referring to anonymous +fields declared using a typedef. @xref{Unnamed Fields,,Unnamed +struct/union fields within structs/unions}, for details. This is only +supported for C, not C++. + @item -trigraphs @opindex trigraphs Support ISO C trigraphs. The @option{-ansi} option (and @option{-std} Index: c-family/c.opt =================================================================== --- c-family/c.opt (revision 164724) +++ c-family/c.opt (working copy) @@ -893,6 +893,10 @@ fpermissive C++ ObjC++ Downgrade conformance errors to warnings +fplan9-extensions +C ObjC Var(flag_plan9_extensions) +Enable Plan 9 language extensions + fpreprocessed C ObjC C++ ObjC++ Treat the input file as already preprocessed Index: c-decl.c =================================================================== --- c-decl.c (revision 164724) +++ c-decl.c (working copy) @@ -6609,15 +6609,15 @@ grokfield (location_t loc, is the anonymous union extension. Similarly for struct. If this is something of the form "struct foo;", then - If MS extensions are enabled, this is handled as an - anonymous struct. + If MS or Plan 9 extensions are enabled, this is handled as + an anonymous struct. Otherwise this is a forward declaration of a structure tag. If this is something of the form "foo;" and foo is a TYPE_DECL, then If foo names a structure or union without a tag, then this is an anonymous struct (this is permitted by C1X). - If MS extensions are enabled and foo names a structure, then - again this is an anonymous struct. + If MS or Plan 9 extensions are enabled and foo names a + structure, then again this is an anonymous struct. Otherwise this is an error. Oh what a horrid tangled web we weave. I wonder if MS consciously @@ -6631,7 +6631,7 @@ grokfield (location_t loc, if (type_ok) { - if (flag_ms_extensions) + if (flag_ms_extensions || flag_plan9_extensions) ok = true; else if (TYPE_NAME (TYPE_MAIN_VARIANT (type)) == NULL) ok = true; @@ -6683,6 +6683,50 @@ grokfield (location_t loc, return value; } +/* Subroutine of detect_field_duplicates: return whether X and Y, + which are both fields in the same struct, have duplicate field + names. */ + +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 ((TREE_CODE (xt) == RECORD_TYPE || TREE_CODE (xt) == UNION_TYPE) + && 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 ((TREE_CODE (yt) == RECORD_TYPE || TREE_CODE (yt) == UNION_TYPE) + && 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; +} + /* Subroutine of detect_field_duplicates: add the fields of FIELDLIST to HTAB, giving errors for any duplicates. */ @@ -6705,7 +6749,22 @@ detect_field_duplicates_hash (tree field } else if (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE) - detect_field_duplicates_hash (TYPE_FIELDS (TREE_TYPE (x)), htab); + { + 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 (htab, xn, INSERT); + if (*slot) + error ("duplicate member %q+D", TYPE_NAME (TREE_TYPE (x))); + *slot = xn; + } + } } /* Generate an error for any duplicate field names in FIELDLIST. Munge @@ -6750,10 +6809,18 @@ detect_field_duplicates (tree fieldlist) if (timeout > 0) { for (x = DECL_CHAIN (fieldlist); x; x = DECL_CHAIN (x)) - if (DECL_NAME (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 + && (TREE_CODE (TREE_TYPE (x)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (x)) == UNION_TYPE) + && TYPE_NAME (TREE_TYPE (x)) != NULL_TREE + && TREE_CODE (TYPE_NAME (TREE_TYPE (x))) == TYPE_DECL)) { for (y = fieldlist; y != x; y = TREE_CHAIN (y)) - if (DECL_NAME (y) == DECL_NAME (x)) + if (is_duplicate_field (y, x)) { error ("duplicate member %q+D", x); DECL_NAME (x) = NULL_TREE; Index: c-typeck.c =================================================================== --- c-typeck.c (revision 164724) +++ c-typeck.c (working copy) @@ -2044,6 +2044,17 @@ 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; } } @@ -2080,6 +2091,16 @@ 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) @@ -4952,6 +4973,106 @@ build_modify_expr (location_t location, return result; } +/* Return whether STRUCT_TYPE has an anonymous field with type TYPE. + This is used to implement -fplan9-extensions. */ + +static bool +find_anonymous_field_with_type (tree struct_type, tree type) +{ + tree field; + bool found; + + gcc_assert (TREE_CODE (struct_type) == RECORD_TYPE + || TREE_CODE (struct_type) == UNION_TYPE); + found = false; + for (field = TYPE_FIELDS (struct_type); + field != NULL_TREE; + field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) == NULL + && comptypes (type, TYPE_MAIN_VARIANT (TREE_TYPE (field)))) + { + if (found) + return false; + found = true; + } + else if (DECL_NAME (field) == NULL + && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) + && find_anonymous_field_with_type (TREE_TYPE (field), type)) + { + if (found) + return false; + found = true; + } + } + return found; +} + +/* RHS is an expression whose type is pointer to struct. If there is + an anonymous field in RHS with type TYPE, then return a pointer to + that field in RHS. This is used with -fplan9-extensions. This + returns NULL if no conversion could be found. */ + +static tree +convert_to_anonymous_field (location_t location, tree type, tree rhs) +{ + tree rhs_struct_type, lhs_main_type; + tree field, found_field; + bool found_sub_field; + tree ret; + + gcc_assert (POINTER_TYPE_P (TREE_TYPE (rhs))); + rhs_struct_type = TREE_TYPE (TREE_TYPE (rhs)); + gcc_assert (TREE_CODE (rhs_struct_type) == RECORD_TYPE + || TREE_CODE (rhs_struct_type) == UNION_TYPE); + + gcc_assert (POINTER_TYPE_P (type)); + lhs_main_type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + + found_field = NULL_TREE; + found_sub_field = false; + for (field = TYPE_FIELDS (rhs_struct_type); + field != NULL_TREE; + field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) != NULL_TREE + || (TREE_CODE (TREE_TYPE (field)) != RECORD_TYPE + && TREE_CODE (TREE_TYPE (field)) != UNION_TYPE)) + continue; + if (comptypes (lhs_main_type, TYPE_MAIN_VARIANT (TREE_TYPE (field)))) + { + if (found_field != NULL_TREE) + return NULL_TREE; + found_field = field; + } + else if (find_anonymous_field_with_type (TREE_TYPE (field), + lhs_main_type)) + { + if (found_field != NULL_TREE) + return NULL_TREE; + found_field = field; + found_sub_field = true; + } + } + + if (found_field == NULL_TREE) + return NULL_TREE; + + ret = fold_build3_loc (location, COMPONENT_REF, TREE_TYPE (found_field), + build_fold_indirect_ref (rhs), found_field, + NULL_TREE); + ret = build_fold_addr_expr_loc (location, ret); + + if (found_sub_field) + { + ret = convert_to_anonymous_field (location, type, ret); + gcc_assert (ret != NULL_TREE); + } + + return ret; +} + /* Convert value RHS to type TYPE as preparation for an assignment to an lvalue of type TYPE. If ORIGTYPE is not NULL_TREE, it is the original type of RHS; this differs from TREE_TYPE (RHS) for enum @@ -5323,6 +5444,25 @@ convert_for_assignment (location_t locat /* Opaque pointers are treated like void pointers. */ is_opaque_pointer = vector_targets_convertible_p (ttl, ttr); + /* The Plan 9 compiler permits a pointer to a struct to be + automatically converted into a pointer to an anonymous field + within the struct. */ + if (flag_plan9_extensions + && (TREE_CODE (mvl) == RECORD_TYPE || TREE_CODE(mvl) == UNION_TYPE) + && (TREE_CODE (mvr) == RECORD_TYPE || TREE_CODE(mvr) == UNION_TYPE) + && mvl != mvr) + { + tree new_rhs = convert_to_anonymous_field (location, type, rhs); + if (new_rhs != NULL_TREE) + { + rhs = new_rhs; + rhstype = TREE_TYPE (rhs); + coder = TREE_CODE (rhstype); + ttr = TREE_TYPE (rhstype); + mvr = TYPE_MAIN_VARIANT (ttr); + } + } + /* C++ does not allow the implicit conversion void* -> T*. However, for the purpose of reducing the number of false positives, we tolerate the special case of Index: testsuite/gcc.dg/anon-struct-11.c =================================================================== --- testsuite/gcc.dg/anon-struct-11.c (revision 0) +++ testsuite/gcc.dg/anon-struct-11.c (revision 0) @@ -0,0 +1,111 @@ +/* { dg-do compile } */ + +/* No special options--in particular, turn off the default + -pedantic-errors option. */ +/* { dg-options "" } */ + +/* When not using -fplan9-extensions, we don't support automatic + conversion of pointer types, and we don't support referring to a + typedef name directly. */ + +extern void exit (int); +extern void abort (void); + +struct A { char a; }; + +struct B { + char b; + struct A; /* { dg-warning "does not declare anything" } */ + char c; +}; + +void +f1 (struct A *p) /* { dg-message "expected" } */ +{ + p->a = 1; +} + +void +test1 (void) +{ + struct B b; + struct A *p; + + b.b = 2; + b.c = 3; + f1 (&b); /* { dg-warning "incompatible pointer type" } */ + if (b.a != 1) /* { dg-error "no member" } */ + abort (); + if (b.b != 2 || b.c != 3) + abort (); + p = &b; /* { dg-warning "incompatible pointer type" } */ + if (p->a != 1) + abort (); +} + +typedef struct { char d; } D; + +struct E { + char b; + struct F { char f; }; /* { dg-warning "does not declare anything" } */ + char c; + union { + D; + }; + char e; +}; + +void +f2 (struct F *p) /* { dg-message "expected" } */ +{ + p->f = 6; +} + +void +f3 (D *p) /* { dg-message "expected" } */ +{ + p->d = 4; +} + +void +f4 (D d) +{ +} + +void +test2 (void) +{ + struct E e; + struct F *pf; + D *pd; + D d; + + e.b = 2; + e.c = 3; + e.e = 5; + f2 (&e); /* { dg-warning "incompatible pointer type" } */ + f3 (&e); /* { dg-warning "incompatible pointer type" } */ + if (e.d != 4) + abort (); + if (e.f != 6) /* { dg-error "no member" } */ + abort (); + if (e.b != 2 || e.c != 3 || e.e != 5) + abort (); + pf = &e; /* { dg-warning "incompatible pointer type" } */ + if (pf->f != 6) + abort (); + pd = &e; /* { dg-warning "incompatible pointer type" } */ + if (pd->d != 4) + abort (); + d = e.D; /* { dg-error "no member" } */ + f3 (&e.D); /* { dg-error "no member" } */ + f4 (e.D); /* { dg-error "no member" } */ +} + +int +main () +{ + test1 (); + test2 (); + exit (0); +} Index: testsuite/gcc.dg/anon-struct-12.c =================================================================== --- testsuite/gcc.dg/anon-struct-12.c (revision 0) +++ testsuite/gcc.dg/anon-struct-12.c (revision 0) @@ -0,0 +1,108 @@ +/* { dg-do run } */ +/* { dg-options "-fplan9-extensions" } */ + +/* When using -fplan9-extensions, we support automatic conversion of + pointer types, and we support referring to a typedef name + directly. */ + +extern void exit (int); +extern void abort (void); + +struct A { char a; }; + +struct B { + char b; + struct A; + char c; +}; + +void +f1 (struct A *p) +{ + p->a = 1; +} + +void +test1 (void) +{ + struct B b; + struct A *p; + + b.b = 2; + b.c = 3; + f1 (&b); + if (b.a != 1) + abort (); + if (b.b != 2 || b.c != 3) + abort (); + p = &b; + if (p->a != 1) + abort (); +} + +typedef struct { char d; } D; + +struct E { + char b; + struct F { char f; }; + char c; + union { + D; + }; + char e; +}; + +void +f2 (struct F *p) +{ + p->f = 6; +} + +void +f3 (D *p) +{ + p->d = 4; +} + +void +f4 (D d) +{ +} + +void +test2 (void) +{ + struct E e; + struct F *pf; + D *pd; + D d; + + e.b = 2; + e.c = 3; + e.e = 5; + f2 (&e); + f3 (&e); + if (e.d != 4) + abort (); + if (e.f != 6) + abort (); + if (e.b != 2 || e.c != 3 || e.e != 5) + abort (); + pf = &e; + if (pf->f != 6) + abort (); + pd = &e; + if (pd->d != 4) + abort (); + d = e.D; + f3 (&e.D); + f4 (e.D); +} + +int +main () +{ + test1 (); + test2 (); + exit (0); +} Index: testsuite/gcc.dg/anon-struct-13.c =================================================================== --- testsuite/gcc.dg/anon-struct-13.c (revision 0) +++ testsuite/gcc.dg/anon-struct-13.c (revision 0) @@ -0,0 +1,76 @@ +/* { dg-do compile } */ +/* { dg-options "-fplan9-extensions" } */ + +/* Test for ambiguity when using the Plan 9 extensions. */ + +struct A { + char a; /* { dg-error "duplicate member" } */ +}; + +struct B +{ + struct A; + struct A; +}; + +char +f1 (struct B *p) +{ + return p->a; /* { dg-error "no member" } */ +} + +void +f2 (struct A *p) /* { dg-message "expected" } */ +{ +} + +void +f3 (struct B *p) +{ + f2 (p); /* { dg-warning "incompatible pointer type" } */ +} + +struct C +{ + char c; /* { dg-error "duplicate member" } */ +}; + +struct D +{ + struct C; +}; + +struct E +{ + struct C; + struct D; +}; + +char +f4 (struct E *p) +{ + return p->c; /* { dg-error "no member" } */ +} + +void +f6 (struct C *p) /* { dg-message "expected" } */ +{ +} + +void +f7 (struct E *p) +{ + f6 (p); /* { dg-warning "incompatible pointer type" } */ +} + +struct A +f8 (struct B *p) +{ + return p->A; /* { dg-error "no member" } */ +} + +struct C +f9 (struct E *p) +{ + return p->C; /* { dg-error "no member" } */ +} Index: testsuite/gcc.dg/anon-struct-14.c =================================================================== --- testsuite/gcc.dg/anon-struct-14.c (revision 0) +++ testsuite/gcc.dg/anon-struct-14.c (revision 0) @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-fplan9-extensions" } */ + +/* When using Plan 9 extensions, a typedef can conflict with an + anonymous field. */ + +typedef struct { int a; } s1; +struct s2 { s1; int s1; }; /* { dg-error "duplicate" } */ +int f(struct s2 *p) { return p->s1; } /* { dg-error "incompatible" } */