Patch for struct/union/enum tag handling

Joseph S. Myers jsm28@cam.ac.uk
Tue Jan 30 16:54:00 GMT 2001


This patch fixes the bug listed in Actual Bugs in the manual of
failing to detect certain misuses of struct/union/enum tags.  (As far
as I can tell, it makes the compiler follow the specification of how
tags are handled, as refined in C99 following DR#165 - if anyone knows
of other cases that were covered by the entry in gcc.texi, please let
me know.)

Cases that were mishandled (not diagnosed when they should have been)
are, for example,

	struct foo { int bar; };
	int z [ sizeof (union foo *)];
	struct bar;

and

	struct foo;
	union foo;

and (only when pedantic)

	enum foo { A = sizeof (enum foo *) };

Bootstrapped with no regressions on i686-pc-linux-gnu.  OK to commit?

2001-01-31  Joseph S. Myers  <jsm28@cam.ac.uk>

	* c-parse.in (structsp): Pedwarn when "enum foo" refers to an
	incomplete type.
	(typename): Call pending_xref_error after parsing typed_typespecs.
	* c-decl.c (lookup_tag): Give error immediately rather than
	leaving it pending if the tag of the wrong type is in the same
	binding level.
	(xref_tag): Don't pedwarn for forward declarations of enum types
	here.
	* gcc.texi (Actual Bugs): Remove entry for misuse of struct, union
	and enum tags.

2001-01-31  Joseph S. Myers  <jsm28@cam.ac.uk>

	* gcc.dg/c99-tag-1.c: New test.

--- c-decl.c.orig	Sun Jan 28 11:05:37 2001
+++ c-decl.c	Tue Jan 30 16:49:23 2001
@@ -2815,6 +2815,7 @@ lookup_tag (code, name, binding_level, t
      int thislevel_only;
 {
   register struct binding_level *level;
+  int thislevel = 1;
 
   for (level = binding_level; level; level = level->level_chain)
     {
@@ -2829,12 +2830,22 @@ lookup_tag (code, name, binding_level, t
 		  pending_invalid_xref = name;
 		  pending_invalid_xref_file = input_filename;
 		  pending_invalid_xref_line = lineno;
+		  /* If in the same binding level as a declaration as a tag
+		     of a different type, this must not be allowed to
+		     shadow that tag, so give the error immediately.
+		     (For example, "struct foo; union foo;" is invalid.)  */
+		  if (thislevel)
+		    pending_xref_error ();
 		}
 	      return TREE_VALUE (tail);
 	    }
 	}
-      if (thislevel_only && ! level->tag_transparent)
-	return NULL_TREE;
+      if (! level->tag_transparent)
+	{
+	  if (thislevel_only)
+	    return NULL_TREE;
+	  thislevel = 0;
+	}
     }
   return NULL_TREE;
 }
@@ -5112,9 +5123,6 @@ xref_tag (code, name)
   ref = make_node (code);
   if (code == ENUMERAL_TYPE)
     {
-      /* (In ANSI, Enums can be referred to only if already defined.)  */
-      if (pedantic)
-	pedwarn ("ISO C forbids forward references to `enum' types");
       /* Give the type a default layout like unsigned int
 	 to avoid crashing if it does not get defined.  */
       TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node);
--- c-parse.in.orig	Wed Jan 24 20:37:43 2001
+++ c-parse.in	Tue Jan 30 16:51:34 2001
@@ -1397,7 +1397,11 @@ structsp:
 		{ $$ = finish_enum ($<ttype>3, nreverse ($4),
 				    chainon ($1, $7)); }
 	| enum_head identifier
-		{ $$ = xref_tag (ENUMERAL_TYPE, $2); }
+		{ $$ = xref_tag (ENUMERAL_TYPE, $2);
+		  /* In ISO C, enumerated types can be referred to
+		     only if already defined.  */
+		  if (pedantic && !COMPLETE_TYPE_P ($$))
+		    pedwarn ("ISO C forbids forward references to `enum' types"); }
 	;
 
 maybecomma:
@@ -1534,8 +1538,10 @@ enumerator:
 	;
 
 typename:
-	typed_typespecs absdcl
-		{ $$ = build_tree_list ($1, $2); }
+	  typed_typespecs
+		{ pending_xref_error (); }
+	  absdcl
+		{ $$ = build_tree_list ($1, $3); }
 	| nonempty_type_quals absdcl
 		{ $$ = build_tree_list ($1, $2); }
 	;
--- gcc.texi.orig	Wed Jan 24 19:40:23 2001
+++ gcc.texi	Tue Jan 30 16:19:35 2001
@@ -537,10 +537,6 @@
 prototypes.
 
 @item
-There are several obscure case of mis-using struct, union, and
-enum tags that are not detected as errors by the compiler.
-
-@item
 When @samp{-pedantic-errors} is specified, GCC will incorrectly give
 an error message when a function name is specified in an expression
 involving the comma operator.
--- testsuite/gcc.dg/c99-tag-1.c.orig	Fri Sep 11 11:31:59 1998
+++ testsuite/gcc.dg/c99-tag-1.c	Tue Jan 30 22:48:45 2001
@@ -0,0 +1,136 @@
+/* Test for handling of tags (6.7.2.3).  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+void
+foo (void)
+{
+  /* Forward declarations of structs and unions are OK; those of enums are
+     not.  */
+  {
+    struct s0;
+    struct s1 *x0;
+    union u0;
+    union u1 *x1;
+    enum e0; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "forward" "enum forward 1" { target *-*-* } 16 } */
+    enum e1 *x2; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "forward" "enum forward 2" { target *-*-* } 18 } */
+    /* GCC used to fail to diagnose a use of an enum inside its definition.  */
+    enum e2 { E2A = sizeof (enum e2 *) }; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "forward" "enum forward 3" { target *-*-* } 21 } */
+  }
+  /* A specific type shall have its content defined at most once.  But we
+     may redeclare the tag in different scopes.  */
+  {
+    struct s0 { int i; };
+    {
+      struct s0 { long l; };
+    }
+    {
+      union s0 { long l; };
+    }
+    struct s0 { int i; }; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "rede" "struct redef" { target *-*-* } 34 } */
+    union u0 { int i; };
+    {
+      union u0 { long l; };
+    }
+    {
+      struct u0 { long l; };
+    }
+    union u0 { int i; }; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "rede" "union redef" { target *-*-* } 43 } */
+    enum e0 { E0A };
+    {
+      enum e0 { E0B };
+    }
+    {
+      struct e0 { long l; };
+    }
+    enum e0 { E0B }; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "rede" "enum redef" { target *-*-* } 52 } */
+  }
+  /* Structure, union and enumerated types have a single namespace of tags.  */
+  {
+    struct s0;
+    struct s1;
+    struct s2 { int i; };
+    struct s2;
+    struct s3 { int i; };
+    struct s2 sv;
+    union u0;
+    union u2 { int i; };
+    union u2;
+    union u2 uv;
+    enum e0 { E0A };
+    enum e1 { E1A };
+    /* None of the following are allowed; some were not detected by GCC.  */
+    union s0; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "wrong" "wrong tag type" { target *-*-* } 70 } */
+    union s1 { int i; }; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "wrong" "wrong tag type" { target *-*-* } 72 } */
+    union s2; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "wrong" "wrong tag type" { target *-*-* } 74 } */
+    union s3 { int i; }; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "wrong" "wrong tag type" { target *-*-* } 76 } */
+    enum u0 { U0A }; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "wrong" "wrong tag type" { target *-*-* } 78 } */
+    enum u2 { U2A }; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "wrong" "wrong tag type" { target *-*-* } 80 } */
+    struct e0; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "wrong" "wrong tag type" { target *-*-* } 82 } */
+    struct e1 { int i; }; /* { dg-bogus "warning" "warning in place of error" } */
+    /* { dg-error "wrong" "wrong tag type" { target *-*-* } 84 } */
+  }
+  /* Explicit shadowing in inner scopes is OK, but references to the tag
+     that don't explicitly shadow it must (whether in declarations or
+     expressions) use the correct one of struct/union/enum.  */
+  {
+    struct s0;
+    struct s1;
+    struct s2 { int i; };
+    struct s2;
+    struct s3 { int i; };
+    struct s2 sv;
+    union u0;
+    union u2 { int i; };
+    union u2;
+    union u2 uv;
+    enum e0 { E0A };
+    enum e1 { E1A };
+    {
+      union s0;
+      union s1;
+      union s2;
+      union s3;
+      struct u0;
+      struct u2;
+      struct e0;
+      union e1;
+    }
+    {
+      union s0 *x0; /* { dg-bogus "warning" "warning in place of error" } */
+      /* { dg-error "wrong" "wrong tag type" { target *-*-* } 114 } */
+      int x1[sizeof (union s1 *)]; /* { dg-bogus "warning" "warning in place of error" } */
+      /* { dg-error "wrong" "wrong tag type" { target *-*-* } 116 } */
+      struct t;
+      union s2 *x2;
+      /* { dg-error "wrong" "wrong tag type" { target *-*-* } 119 } */
+      int x3[sizeof (union s3 *)]; /* { dg-bogus "warning" "warning in place of error" } */
+      /* { dg-error "wrong" "wrong tag type" { target *-*-* } 121 } */
+      struct u;
+      enum u0 *y0; /* { dg-bogus "warning" "warning in place of error" } */
+      /* { dg-error "wrong|forward" "wrong tag type" { target *-*-* } 124 } */
+      int y1[sizeof (enum u2 *)]; /* { dg-bogus "warning" "warning in place of error" } */
+      /* { dg-error "wrong" "wrong tag type" { target *-*-* } 126 } */
+      struct v;
+      struct e0 *z0; /* { dg-bogus "warning" "warning in place of error" } */
+      /* { dg-error "wrong" "wrong tag type" { target *-*-* } 129 } */
+      int z1[sizeof (struct e1 *)]; /* { dg-bogus "warning" "warning in place of error" } */
+      /* { dg-error "wrong" "wrong tag type" { target *-*-* } 131 } */
+      struct w;
+    }
+  }
+}

-- 
Joseph S. Myers
jsm28@cam.ac.uk



More information about the Gcc-patches mailing list