Patch for C99 mixed declarations and code

Joseph S. Myers jsm28@cam.ac.uk
Mon Nov 6 02:31:00 GMT 2000


This patch adds support for mixed declarations and code in C.  The
complexity (in the parser - it's purely a parser patch since all the
non-parser code needed is already shared between C and C++) is largely
due to two GCC extensions:

* Labels at end of compound statements (which seems to be why
ends_in_label was there, and prevented stmts from expanding to a
series of lineno_labeled_stmt - with the optional trailing labels
extension at the end - because that would lead to a parser conflict).
(This extension seems gratuitous - using a null statement is trivial,
so it just serves to encourage nonportable (possibly unintentionally
so) code.  This extension also seems to be undocumented - perhaps the
pedwarn should become mandatory?)

* Attributes on labels - these mean that supporting labels on
declarations as well as statements (otherwise a natural extension)
would allow an attribute between a label and a declaration to be
parsed as being attached to either of them.  So, labels on
declarations will simply fail to parse with the patch; C99 only allows
labels to be attached to statements.

The patch does not cover "for (int i = 0; i < 10; i++)" - that depends
on my previous patch to implement C99 block scopes (and, when I do
implement it, will probably yield a hard error outside of C99 mode for
simplicity of implementation).  The mixed declarations and code
supported by this patch will, however, work fine outside C99 mode with
just a pedwarn under -pedantic for each declaration immediately
following a statement.

People hoping for stability before the GCC 3.0 feature freeze may be
glad to hear that _Bool, plus this, plus the C99 block scopes and a
future patch for declarations in for loops, will complete the
significant C99 features I want to get into GCC 3.0 in order to use
them and so have been implementing now (notwithstanding that they're
slightly out of my depth) since no-one else has appeared to be working
on them.

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

gcc/ChangeLog:
2000-11-06  Joseph S. Myers  <jsm28@cam.ac.uk>

	* c-parse.in (ends_in_label): Remove from %union and %type.
	(decls, stmts, lineno_stmt_or_labels, xstmts,
	lineno_stmt_or_label, stmt_or_label): Remove.
	(stmts_and_decls, lineno_stmt_decl_or_labels_ending_stmt,
	lineno_stmt_decl_or_labels_ending_decl,
	lineno_stmt_decl_or_labels_ending_label,
	lineno_stmt_decl_or_labels_ending_error,
	lineno_stmt_decl_or_labels, compstmt_contents_nonempty,
	lineno_stmt, lineno_label): New.
	(compstmt_nostart): Use compstmt_contents_nonempty.

gcc/testsuite/ChangeLog:
2000-11-06  Joseph S. Myers  <jsm28@cam.ac.uk>

	* gcc.dg/c99-mixdecl-1.c, gcc.dg/c90-mixdecl-1.c: New tests.

--- c-parse.in.orig	Mon Nov  6 07:24:40 2000
+++ c-parse.in	Mon Nov  6 07:37:38 2000
@@ -79,7 +79,7 @@
 %start program

 %union {long itype; tree ttype; enum tree_code code;
-	const char *filename; int lineno; int ends_in_label; }
+	const char *filename; int lineno; }

 /* All identifiers that are not reserved words
    and are not declared typedefs in the current block */
@@ -193,8 +193,6 @@

 %type <itype> setspecs

-%type <ends_in_label> lineno_stmt_or_label lineno_stmt_or_labels stmt_or_label
-
 %type <filename> save_filename
 %type <lineno> save_lineno

@@ -823,13 +821,6 @@
 		{ }
 	;

-decls:
-	lineno_decl
-	| errstmt
-	| decls lineno_decl
-	| lineno_decl errstmt
-	;
-
 /* records the type and storage class specs to use for processing
    the declarators that follow.
    Maintains a stack of outer-level values of current_declspecs,
@@ -1573,29 +1564,58 @@
 		{ $$ = $3; }
 	;

-/* at least one statement, the first of which parses without error.  */
-/* stmts is used only after decls, so an invalid first statement
-   is actually regarded as an invalid decl and part of the decls.  */
-
-stmts:
-	lineno_stmt_or_labels
+/* A nonempty series of declarations and statements (possibly followed by
+   some labels) that can form the body of a compound statement.
+   NOTE: we don't allow labels on declarations; this might seem like a
+   natural extension, but there would be a conflict between attributes
+   on the label and prefix attributes on the declaration.  */
+
+stmts_and_decls:
+	  lineno_stmt_decl_or_labels_ending_stmt
+	| lineno_stmt_decl_or_labels_ending_decl
+	| lineno_stmt_decl_or_labels_ending_label
 		{
-		  if (pedantic && $1)
+		  if (pedantic)
 		    pedwarn ("ISO C forbids label at end of compound statement");
 		}
+	| lineno_stmt_decl_or_labels_ending_error
 	;

-lineno_stmt_or_labels:
-	  lineno_stmt_or_label
-	| lineno_stmt_or_labels lineno_stmt_or_label
-		{ $$ = $2; }
-	| lineno_stmt_or_labels errstmt
-		{ $$ = 0; }
+lineno_stmt_decl_or_labels_ending_stmt:
+	  lineno_stmt
+	| lineno_stmt_decl_or_labels_ending_stmt lineno_stmt
+	| lineno_stmt_decl_or_labels_ending_decl lineno_stmt
+	| lineno_stmt_decl_or_labels_ending_label lineno_stmt
+	| lineno_stmt_decl_or_labels_ending_error lineno_stmt
 	;

-xstmts:
-	/* empty */
-	| stmts
+lineno_stmt_decl_or_labels_ending_decl:
+	  lineno_decl
+	| lineno_stmt_decl_or_labels_ending_stmt lineno_decl
+		{ if (pedantic && !flag_isoc99)
+		    pedwarn ("ISO C89 forbids mixed declarations and code"); }
+	| lineno_stmt_decl_or_labels_ending_decl lineno_decl
+	| lineno_stmt_decl_or_labels_ending_error lineno_decl
+	;
+
+lineno_stmt_decl_or_labels_ending_label:
+	  lineno_label
+	| lineno_stmt_decl_or_labels_ending_stmt lineno_label
+	| lineno_stmt_decl_or_labels_ending_decl lineno_label
+	| lineno_stmt_decl_or_labels_ending_label lineno_label
+	| lineno_stmt_decl_or_labels_ending_error lineno_label
+	;
+
+lineno_stmt_decl_or_labels_ending_error:
+	errstmt
+	| lineno_stmt_decl_or_labels errstmt
+	;
+
+lineno_stmt_decl_or_labels:
+	  lineno_stmt_decl_or_labels_ending_stmt
+	| lineno_stmt_decl_or_labels_ending_decl
+	| lineno_stmt_decl_or_labels_ending_label
+	| lineno_stmt_decl_or_labels_ending_error
 	;

 errstmt:  error ';'
@@ -1654,23 +1674,18 @@

 compstmt_nostart: '}'
 		{ $$ = convert (void_type_node, integer_zero_node); }
-	| pushlevel maybe_label_decls decls xstmts '}' poplevel
-		{ $$ = poplevel (1, 1, 0);
-		  SCOPE_STMT_BLOCK (TREE_PURPOSE ($6))
-		    = SCOPE_STMT_BLOCK (TREE_VALUE ($6))
-		    = $$; }
-	| pushlevel maybe_label_decls error '}' poplevel
-		{ $$ = poplevel (kept_level_p (), 0, 0);
-		  SCOPE_STMT_BLOCK (TREE_PURPOSE ($5))
-		    = SCOPE_STMT_BLOCK (TREE_VALUE ($5))
-		    = $$; }
-	| pushlevel maybe_label_decls stmts '}' poplevel
-		{ $$ = poplevel (kept_level_p (), 0, 0);
+	| pushlevel maybe_label_decls compstmt_contents_nonempty '}' poplevel
+		{ $$ = poplevel (kept_level_p (), 1, 0);
 		  SCOPE_STMT_BLOCK (TREE_PURPOSE ($5))
 		    = SCOPE_STMT_BLOCK (TREE_VALUE ($5))
 		    = $$; }
 	;

+compstmt_contents_nonempty:
+	  stmts_and_decls
+	| error
+	;
+
 compstmt_primary_start:
 	'(' '{'
 		{ if (current_function_decl == 0)
@@ -1757,16 +1772,14 @@
 		{ }
 	;

-lineno_stmt_or_label:
-	  save_filename save_lineno stmt_or_label
-		{ $$ = $3; }
+lineno_stmt:
+	  save_filename save_lineno stmt
+		{ }
 	;

-stmt_or_label:
-	  stmt
-		{ $$ = 0; }
-	| label
-		{ $$ = 1; }
+lineno_label:
+	  save_filename save_lineno label
+		{ }
 	;

 /* Parse a single real statement, not including any labels.  */
--- testsuite/gcc.dg/c90-mixdecl-1.c.orig	Fri Sep 11 11:31:59 1998
+++ testsuite/gcc.dg/c90-mixdecl-1.c	Sun Nov  5 23:57:00 2000
@@ -0,0 +1,13 @@
+/* Test for C99 mixed declarations and code: not in C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+void
+foo (void)
+{
+  int i;
+  i = 0;
+  int j; /* { dg-bogus "warning" "warning in place of error" } */
+  /* { dg-error "mix|parse" "mixed declarations and code not in C90" { target *-*-* } 11 } */
+}
--- testsuite/gcc.dg/c99-mixdecl-1.c.orig	Fri Sep 11 11:31:59 1998
+++ testsuite/gcc.dg/c99-mixdecl-1.c	Sun Nov  5 23:54:25 2000
@@ -0,0 +1,25 @@
+/* Test for C99 mixed declarations and code.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do run } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+extern void abort (void);
+extern void exit (int);
+
+int
+main (void)
+{
+  int i = 0;
+  if (i != 0)
+    abort ();
+  i++;
+  if (i != 1)
+    abort ();
+  int j = i;
+  if (j != 1)
+    abort ();
+  struct foo { int i0; } k = { 4 };
+  if (k.i0 != 4)
+    abort ();
+  exit (0);
+}

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



More information about the Gcc-patches mailing list