diff mbox series

mixing of labels and code in C2X

Message ID 1599996046.28509.3.camel@med.uni-goettingen.de
State New
Headers show
Series mixing of labels and code in C2X | expand

Commit Message

Uecker, Martin Sept. 13, 2020, 11:20 a.m. UTC
Hi Joseph,

here is the (unfinished) patch to support
mixing of labels in C2X.

I preserved existing tests by adding
"-std=c17 -pedantic-error"

So far, I haven't figured out how
to fix the OpenMP related warning
in 'gcc.dg/gomp/barrier-2.c'.

Best,
Martin

Comments

Joseph Myers Sept. 14, 2020, 8:30 p.m. UTC | #1
On Sun, 13 Sep 2020, Uecker, Martin wrote:

> Hi Joseph,
> 
> here is the (unfinished) patch to support
> mixing of labels in C2X.

I think there should be explicit tests for old standard versions 
(c11-labels-1.c etc.) that these usages are errors with -pedantic-errors 
with the old -std option, are warnings with -pedantic, and are quietly 
accepted with neither.  In addition to using -pedantic-errors with the new 
standard version test to confirm it's not diagnosed, and a test with the 
new version and -Wc11-c2x-compat.

By way of example of further places that I think need changing in the 
patch: at present, c_parser_label gives an error (that you correctly 
change to a pedwarn_c11) if the label is followed by a declaration - and 
then parses the declaration itself rather than leaving it to be parsed in 
the caller.  So c_parser_compound_statement_nostart would parse a label 
followed by a declaration, and at that point last_label would be set to 
true, meaning that a second declaration would be rejected, when in C2x it 
should be accepted.  You can see this even without the patch with a test 
such as:

void
f (void)
{
 label : int a; int b; 
}

I think that instead c_parser_label should never try to parse a 
declaration following the label; that should be left for the caller to 
handle.  To avoid c_parser_label needing to return information about 
standard attributes on a following declaration, maybe it shouldn't parse 
standard attributes either (note that means that c_parser_all_labels would 
need to handle parsing and warning about and discarding standard 
attributes after each label instead - such attributes might be ones on a 
statement, or ones on the next label in a sequence of labels).

Then of course the checks of last_label in 
c_parser_compound_statement_nostart would need to become checks for 
whether to pedwarn_c11 about the use of a label in a given context, once 
the code knows whether there is a declaration, rather than preventing 
parsing a declaration there at all.  So probably c_parser_label would no 
longer have the pedwarn_c11 either; that would all be left to its callers.
Uecker, Martin Nov. 1, 2020, 10:34 p.m. UTC | #2
Am Montag, den 14.09.2020, 20:30 +0000 schrieb Joseph Myers:
> On Sun, 13 Sep 2020, Uecker, Martin wrote:
> 
> > Hi Joseph,
> > 
> > here is the (unfinished) patch to support
> > mixing of labels in C2X.
> 
> I think there should be explicit tests for old standard versions 
> (c11-labels-1.c etc.) that these usages are errors with -pedantic-errors 
> with the old -std option, are warnings with -pedantic, and are quietly 
> accepted with neither.  In addition to using -pedantic-errors with the new 
> standard version test to confirm it's not diagnosed, and a test with the 
> new version and -Wc11-c2x-compat.
> 
> By way of example of further places that I think need changing in the 
> patch: at present, c_parser_label gives an error (that you correctly 
> change to a pedwarn_c11) if the label is followed by a declaration - and 
> then parses the declaration itself rather than leaving it to be parsed in 
> the caller.  So c_parser_compound_statement_nostart would parse a label 
> followed by a declaration, and at that point last_label would be set to 
> true, meaning that a second declaration would be rejected, when in C2x it 
> should be accepted.  You can see this even without the patch with a test 
> such as:
> 
> void
> f (void)
> {
>  label : int a; int b; 
> }
> 
> I think that instead c_parser_label should never try to parse a 
> declaration following the label; that should be left for the caller to 
> handle.  To avoid c_parser_label needing to return information about 
> standard attributes on a following declaration, maybe it shouldn't parse 
> standard attributes either (note that means that c_parser_all_labels would 
> need to handle parsing and warning about and discarding standard 
> attributes after each label instead - such attributes might be ones on a 
> statement, or ones on the next label in a sequence of labels).
> 
> Then of course the checks of last_label in 
> c_parser_compound_statement_nostart would need to become checks for 
> whether to pedwarn_c11 about the use of a label in a given context, once 
> the code knows whether there is a declaration, rather than preventing 
> parsing a declaration there at all.  So probably c_parser_label would no 
> longer have the pedwarn_c11 either; that would all be left to its callers.


ok, here is a new revision of the patch. Still needs some
polish...

I also made the attributes not be ignored for labels.
Or should I separate this out?

There is a new warning for the case of GNU-style
attributes between a label and a declaration. It
now applies to the label. 

Best,
Martin


diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index b921c4e3852..aa039db087b 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1521,7 +1521,7 @@ static void c_parser_initval (c_parser *, struct c_expr *,
 			      struct obstack *);
 static tree c_parser_compound_statement (c_parser *, location_t * = NULL);
 static location_t c_parser_compound_statement_nostart (c_parser *);
-static void c_parser_label (c_parser *);
+static void c_parser_label (c_parser *, tree);
 static void c_parser_statement (c_parser *, bool *, location_t * = NULL);
 static void c_parser_statement_after_labels (c_parser *, bool *,
 					     vec<tree> * = NULL);
@@ -5523,7 +5523,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after,
 }
 
 /* Parse a compound statement (possibly a function body) (C90 6.6.2,
-   C99 6.8.2, C11 6.8.2).
+   C99 6.8.2, C11 6.8.2, C2X 6.X.Y).
 
    compound-statement:
      { block-item-list[opt] }
@@ -5674,7 +5674,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
     {
       location_t loc = c_parser_peek_token (parser)->location;
       loc = expansion_point_location_if_in_system_header (loc);
-      /* Standard attributes may start a statement or a declaration.  */
+      /* Standard attributes may start a label, statement or declaration.  */
       bool have_std_attrs
 	= c_parser_nth_token_starts_std_attributes (parser, 1);
       tree std_attrs = NULL_TREE;
@@ -5685,7 +5685,6 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  || (c_parser_next_token_is (parser, CPP_NAME)
 	      && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
 	{
-	  c_warn_unused_attributes (std_attrs);
 	  if (c_parser_next_token_is_keyword (parser, RID_CASE))
 	    label_loc = c_parser_peek_2nd_token (parser)->location;
 	  else
@@ -5693,27 +5692,54 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  last_label = true;
 	  last_stmt = false;
 	  mark_valid_location_for_stdc_pragma (false);
-	  c_parser_label (parser);
+	  c_parser_label (parser, std_attrs);
+
+	  /* Allow '__attribute__((fallthrough));'.  */
+	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+	    {
+	      location_t loc = c_parser_peek_token (parser)->location;
+	      tree attrs = c_parser_gnu_attributes (parser);
+	      if (attribute_fallthrough_p (attrs))
+		{
+		  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+		    {
+		      tree fn = build_call_expr_internal_loc (loc,
+							      IFN_FALLTHROUGH,
+							      void_type_node, 0);
+		      add_stmt (fn);
+		    }
+		  else
+		     warning_at (loc, OPT_Wattributes, "%<fallthrough%> attribute "
+			  "not followed by %<;%>");
+		}
+	      else if (attrs != NULL_TREE)
+		warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
+			    " can be applied to a null statement");
+	    }
 	}
-      else if (!last_label
-	       && (c_parser_next_tokens_start_declaration (parser)
-		   || (have_std_attrs
-		       && c_parser_next_token_is (parser, CPP_SEMICOLON))))
+      else if (c_parser_next_tokens_start_declaration (parser)
+	       || (have_std_attrs
+		   && c_parser_next_token_is (parser, CPP_SEMICOLON)))
 	{
-	  last_label = false;
+	  if (last_label)
+	    pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic,
+			 "a label can only be part of a statement and "
+			 "a declaration is not a statement");
+
 	  mark_valid_location_for_stdc_pragma (false);
 	  bool fallthru_attr_p = false;
 	  c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
 					 true, true, true, NULL,
 					 vNULL, have_std_attrs, std_attrs,
 					 NULL, &fallthru_attr_p);
+
 	  if (last_stmt && !fallthru_attr_p)
 	    pedwarn_c90 (loc, OPT_Wdeclaration_after_statement,
 			 "ISO C90 forbids mixed declarations and code");
 	  last_stmt = fallthru_attr_p;
+	  last_label = false;
 	}
-      else if (!last_label
-	       && c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+      else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
 	{
 	  /* __extension__ can start a declaration, but is also an
 	     unary operator that can start an expression.  Consume all
@@ -5796,7 +5822,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
       parser->error = false;
     }
   if (last_label)
-    error_at (label_loc, "label at end of compound statement");
+    pedwarn_c11 (label_loc, OPT_Wpedantic, "label at end of compound statement");
   location_t endloc = c_parser_peek_token (parser)->location;
   c_parser_consume_token (parser);
   /* Restore the value we started with.  */
@@ -5812,19 +5838,29 @@ c_parser_compound_statement_nostart (c_parser *parser)
 static void
 c_parser_all_labels (c_parser *parser)
 {
+  tree std_attrs = NULL;
   if (c_parser_nth_token_starts_std_attributes (parser, 1))
     {
-      tree std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+      std_attrs = c_parser_std_attribute_specifier_sequence (parser);
       if (c_parser_next_token_is (parser, CPP_SEMICOLON))
 	c_parser_error (parser, "expected statement");
-      else
-	c_warn_unused_attributes (std_attrs);
     }
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	 || (c_parser_next_token_is (parser, CPP_NAME)
 	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
-    c_parser_label (parser);
+    {
+      c_parser_label (parser, std_attrs);
+      std_attrs = NULL;
+      if (c_parser_nth_token_starts_std_attributes (parser, 1))
+	{
+	  std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+	  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	    c_parser_error (parser, "expected statement");
+	}
+    }
+   if (std_attrs)
+     c_warn_unused_attributes (std_attrs);
 }
 
 /* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1).
@@ -5843,12 +5879,10 @@ c_parser_all_labels (c_parser *parser)
    GNU C accepts any expressions without commas, non-constant
    expressions being rejected later.  Any standard
    attribute-specifier-sequence before the first label has been parsed
-   in the caller, to distinguish statements from declarations.  Any
-   attribute-specifier-sequence after the label is parsed in this
-   function.  */
+   in the caller, to distinguish statements from declarations.  */
 
 static void
-c_parser_label (c_parser *parser)
+c_parser_label (c_parser *parser, tree std_attrs)
 {
   location_t loc1 = c_parser_peek_token (parser)->location;
   tree label = NULL_TREE;
@@ -5898,8 +5932,13 @@ c_parser_label (c_parser *parser)
       if (tlab)
 	{
 	  decl_attributes (&tlab, attrs, 0);
+	  decl_attributes (&tlab, std_attrs, 0);
 	  label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab));
 	}
+      if (attrs
+	  && c_parser_next_tokens_start_declaration (parser))
+	  warning_at (loc2, OPT_Wattributes, "GNU-style attribute between"
+		      " label and declaration appertains to the label.");
     }
   if (label)
     {
@@ -5907,55 +5946,6 @@ c_parser_label (c_parser *parser)
 	FALLTHROUGH_LABEL_P (LABEL_EXPR_LABEL (label)) = fallthrough_p;
       else
 	FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p;
-
-      /* Standard attributes are only allowed here if they start a
-	 statement, not a declaration (including the case of an
-	 attribute-declaration with only attributes).  */
-      bool have_std_attrs
-	= c_parser_nth_token_starts_std_attributes (parser, 1);
-      tree std_attrs = NULL_TREE;
-      if (have_std_attrs)
-	std_attrs = c_parser_std_attribute_specifier_sequence (parser);
-
-      /* Allow '__attribute__((fallthrough));'.  */
-      if (!have_std_attrs
-	  && c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
-	{
-	  location_t loc = c_parser_peek_token (parser)->location;
-	  tree attrs = c_parser_gnu_attributes (parser);
-	  if (attribute_fallthrough_p (attrs))
-	    {
-	      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
-		{
-		  tree fn = build_call_expr_internal_loc (loc,
-							  IFN_FALLTHROUGH,
-							  void_type_node, 0);
-		  add_stmt (fn);
-		}
-	      else
-		warning_at (loc, OPT_Wattributes, "%<fallthrough%> attribute "
-			    "not followed by %<;%>");
-	    }
-	  else if (attrs != NULL_TREE)
-	    warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
-			" can be applied to a null statement");
-	}
-      if (c_parser_next_tokens_start_declaration (parser)
-	  || (have_std_attrs
-	      && c_parser_next_token_is (parser, CPP_SEMICOLON)))
-	{
-	  error_at (c_parser_peek_token (parser)->location,
-		    "a label can only be part of a statement and "
-		    "a declaration is not a statement");
-	  c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
-					 /*static_assert_ok*/ true,
-					 /*empty_ok*/ true, /*nested*/ true,
-					 /*start_attr_ok*/ true, NULL,
-					 vNULL, have_std_attrs, std_attrs);
-	}
-      else if (std_attrs)
-	/* Nonempty attributes on the following statement are ignored.  */
-	c_warn_unused_attributes (std_attrs);
     }
 }
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index f14772f7d38..d0e134b859c 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -55,7 +55,7 @@ extensions, accepted by GCC in C90 mode and in C++.
 * Designated Inits::    Labeling elements of initializers.
 * Case Ranges::         `case 1 ... 9' and such.
 * Cast to Union::       Casting to union type from any member of the union.
-* Mixed Declarations::  Mixing declarations and code.
+* Mixed Labels and Declarations::  Mixing declarations, labels and code.
 * Function Attributes:: Declaring that functions have no side effects,
                         or that they can never return.
 * Variable Attributes:: Specifying attributes of variables.
@@ -2353,15 +2353,17 @@ void hack (union foo);
 hack ((union foo) x);
 @end smallexample
 
-@node Mixed Declarations
-@section Mixed Declarations and Code
+@node Mixed Labels and Declarations
+@section Mixed Declarations, Labels and Code
 @cindex mixed declarations and code
 @cindex declarations, mixed with code
 @cindex code, mixed with declarations
 
 ISO C99 and ISO C++ allow declarations and code to be freely mixed
-within compound statements.  As an extension, GNU C also allows this in
-C90 mode.  For example, you could do:
+within compound statements.  ISO C2X allows labels to be
+placed before declarations and at the end of a compound statement.
+As an extension, GNU C also allows all this in C90 mode.  For example,
+you could do:
 
 @smallexample
 int i;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 492b7dcdf10..13b79da2c46 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -7592,7 +7592,7 @@ except when the same as the default promotion.
 @opindex Wno-declaration-after-statement
 Warn when a declaration is found after a statement in a block.  This
 construct, known from C++, was introduced with ISO C99 and is by default
-allowed in GCC@.  It is not supported by ISO C90.  @xref{Mixed Declarations}.
+allowed in GCC@.  It is not supported by ISO C90.  @xref{Mixed Labels and Declarations}.
 
 @item -Wshadow
 @opindex Wshadow
diff --git a/gcc/testsuite/gcc.dg/20031223-1.c b/gcc/testsuite/gcc.dg/20031223-1.c
index 68aa74ffe50..c529739e7ec 100644
--- a/gcc/testsuite/gcc.dg/20031223-1.c
+++ b/gcc/testsuite/gcc.dg/20031223-1.c
@@ -3,11 +3,10 @@
    because GCC was trying to expand the trees to rtl.  */
 
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-std=c17 -pedantic-errors" } */
 
 void f ()
 {
  l: int; /* { dg-error "a label can only be part of a statement and a declaration is not a
statement" "not stmt" } */
- /* { dg-warning "useless type name in empty declaration" "type name" { target *-*-* } .-1 } */
- /* { dg-error "label at end of compound statement" "label" { target *-*-* } .-2 } */
+ /* { dg-error "useless type name in empty declaration" "type name" { target *-*-* } .-1 } */
 }
diff --git a/gcc/testsuite/gcc.dg/c11-labels-1.c b/gcc/testsuite/gcc.dg/c11-labels-1.c
new file mode 100644
index 00000000000..6350403bf38
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-labels-1.c
@@ -0,0 +1,15 @@
+/* Tests for labels before declarations and at ends of compound statements.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11" } */
+
+int f(int x) 
+{ 
+	goto b;
+	a: int i = 2 * x;
+           goto c;
+	b: goto a;
+	{ i *= 3; c: }
+	return i;
+        d:
+}
+
diff --git a/gcc/testsuite/gcc.dg/c11-labels-2.c b/gcc/testsuite/gcc.dg/c11-labels-2.c
new file mode 100644
index 00000000000..e9b492446b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-labels-2.c
@@ -0,0 +1,15 @@
+/* Tests for labels before declarations and at ends of compound statements.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic" } */
+
+int f(int x) 
+{ 
+	goto b;
+	a: int i = 2 * x; 	/* { dg-warning "a label can only be part of a statement and a
declaration is not a statement" } */
+           goto c;
+	b: goto a;
+	{ i *= 3; c: }		/* { dg-warning "label at end of compound statement" } */
+	return i;
+        d:			/* { dg-warning "label at end of compound statement" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/c11-labels-3.c b/gcc/testsuite/gcc.dg/c11-labels-3.c
new file mode 100644
index 00000000000..1e4be63af69
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-labels-3.c
@@ -0,0 +1,15 @@
+/* Tests for labels before declarations and at ends of compound statements.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+int f(int x) 
+{ 
+	goto b;
+	a: int i = 2 * x;	/* { dg-error "a label can only be part of a statement and a
declaration is not a statement" } */
+           goto c;
+	b: goto a;
+	{ i *= 3; c: }		/* { dg-error "label at end of compound statement" } */
+	return i;
+        d:			/* { dg-error "label at end of compound statement" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c b/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
index 1f883d825e0..2f0d9f60cc0 100644
--- a/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
+++ b/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
@@ -25,13 +25,14 @@ f2 (void)
 }
 
 /* Declarations, including attribute declarations, cannot appear after
-   labels.  */
+   labels when a statement is expected.  */
 
 void
 f3 (void)
 {
- x: [[]];; /* { dg-error "can only be part of a statement" } */
-}
+  if (1)
+    x: [[]]; /* { dg-error "expected" } */
+} 
 
 /* Prefix attributes cannot appear on type names.  */
 
diff --git a/gcc/testsuite/gcc.dg/c2x-labels-1.c b/gcc/testsuite/gcc.dg/c2x-labels-1.c
new file mode 100644
index 00000000000..439cf7834ee
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-labels-1.c
@@ -0,0 +1,23 @@
+/* Tests for labels before declarations and at ends of compound statements.  */
+/* { dg-do run } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+int f(int x) 
+{ 
+	goto b;
+	a: int i = 2 * x;
+	aa: int u = 0; int v = 0;
+           goto c;
+	b: goto a;
+	{ i *= 3; c: }
+	return i + u + v;
+        d:
+}
+
+int main(void)
+{
+	if (2 != f(1))
+		__builtin_abort();
+
+	return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-labels-2.c b/gcc/testsuite/gcc.dg/c2x-labels-2.c
new file mode 100644
index 00000000000..bd010e9ecfb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-labels-2.c
@@ -0,0 +1,15 @@
+/* Tests for labels before declarations and at ends of compound statements.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat" } */
+
+int f(int x) 
+{ 
+	goto b;
+	a: int i = 2 * x;	/* { dg-warning "a label can only be part of a statement and a
declaration is not a statement" } */
+           goto c;
+	b: goto a;
+	{ i *= 3; c: }		/* { dg-warning "label at end of compound statement" } */
+	return i;
+        d:			/* { dg-warning "label at end of compound statement" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/c2x-labels-3.c b/gcc/testsuite/gcc.dg/c2x-labels-3.c
new file mode 100644
index 00000000000..159116db186
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-labels-3.c
@@ -0,0 +1,38 @@
+/* Tests for labels before declarations and at ends of compound statements
+ * in combination with attributes. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wall" } */
+
+int f(void) 
+{ 
+	goto b;
+	a: int i = 0;
+	aa: __attribute__((unused)) int u = 0; int v = 0;	/* { dg-warning "GNU-style
attribute between label and declaration appertains to the label" } */
+           goto c;
+	{ c: }
+	b: goto a;
+	return i + u + v;
+        d: __attribute__((unused)) (void)0;
+        e: __attribute__((unused))
+}
+
+int g(void) 
+{ 
+	goto b;
+	a: int i = 0;
+	[[maybe_unused]] aa: int u = 0; int v = 0;
+           goto c;
+	{ c: }
+	b: goto a;
+	return i + u + v;
+        [[maybe_unused]] d: (void)0;
+        [[maybe_unused]] e:
+}
+
+void h(void)
+{
+	[[maybe_unused]] a: [[maybe_unused]] b: [[maybe_unused]] int x;
+
+	if (1)
+		[[maybe_unused]] c: [[maybe_unused]] d: (void)0;
+}
diff --git a/gcc/testsuite/gcc.dg/decl-9.c b/gcc/testsuite/gcc.dg/decl-9.c
index eeca8e05e14..9bb15609d83 100644
--- a/gcc/testsuite/gcc.dg/decl-9.c
+++ b/gcc/testsuite/gcc.dg/decl-9.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-std=gnu89" } */
+/* { dg-options "-std=gnu89 -pedantic-errors" } */
 
 w *x; /* { dg-error "unknown type name 'w'" } */
 
@@ -12,6 +12,7 @@ int f1()
   int d, e;
   d * e; /* { dg-bogus "unknown type name 'd'" } */
   g * h; /* { dg-error "unknown type name 'g'" } */
+  /* { dg-error "mixed declarations" "" { target *-*-* } .-1 } */
   g i;   /* { dg-error "unknown type name 'g'" } */
 }
 
diff --git a/gcc/testsuite/gcc.dg/gomp/barrier-2.c b/gcc/testsuite/gcc.dg/gomp/barrier-2.c
index 5a7091946c4..98e16b2e051 100644
--- a/gcc/testsuite/gcc.dg/gomp/barrier-2.c
+++ b/gcc/testsuite/gcc.dg/gomp/barrier-2.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-options "-Wall -std=c17 -fopenmp -pedantic-errors" } */
 
 void f1(void)
 {
@@ -16,6 +17,7 @@ void f1(void)
 void f2(void)
 {
   label:       /* { dg-error "label at end of compound statement" } */
+    /* { dg-error "defined but not used" "" { target *-*-* } .-1 } */
     #pragma omp barrier		/* { dg-error "may only be used in compound statements" } */
 }
 
diff --git a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
index fe236525d62..51bd5f25bb0 100644
--- a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
+++ b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
@@ -1,5 +1,6 @@
 /* Test parsing of #pragma omp declare simd */
 /* { dg-do compile } */
+/* { dg-options "-std=c17 -fopenmp -pedantic-errors" } */
 
 int
 f1 (int x)
diff --git a/gcc/testsuite/gcc.dg/label-compound-stmt-1.c b/gcc/testsuite/gcc.dg/label-compound-
stmt-1.c
index 2f8fa4e65c2..2ae2b82ef1c 100644
--- a/gcc/testsuite/gcc.dg/label-compound-stmt-1.c
+++ b/gcc/testsuite/gcc.dg/label-compound-stmt-1.c
@@ -1,7 +1,7 @@
 /* Test that labels at ends of compound statements are hard errors.  */
 /* Origin: Joseph Myers <jsm@polyomino.org.uk> */
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-std=c17 -pedantic-errors" } */
 
 void f(void) { g: } /* { dg-bogus "warning" "warning in place of error" } */
 /* { dg-error "label|parse|syntax" "label at end of compound statement" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/parse-decl-after-label.c b/gcc/testsuite/gcc.dg/parse-decl-after-
label.c
index 9c9886a108f..6e2a047eb2e 100644
--- a/gcc/testsuite/gcc.dg/parse-decl-after-label.c
+++ b/gcc/testsuite/gcc.dg/parse-decl-after-label.c
@@ -1,6 +1,6 @@
 /* PR 29062 
 { dg-do compile }
-{ dg-options "-fsyntax-only" }
+{ dg-options "-std=c17 -pedantic-errors -fsyntax-only" }
 */
 
 int f(int x)
Joseph Myers Nov. 2, 2020, 9:16 p.m. UTC | #3
On Sun, 1 Nov 2020, Uecker, Martin wrote:

> @@ -5693,27 +5692,54 @@ c_parser_compound_statement_nostart (c_parser *parser)
>  	  last_label = true;
>  	  last_stmt = false;
>  	  mark_valid_location_for_stdc_pragma (false);
> -	  c_parser_label (parser);
> +	  c_parser_label (parser, std_attrs);
> +
> +	  /* Allow '__attribute__((fallthrough));'.  */
> +	  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
> +	    {
> +	      location_t loc = c_parser_peek_token (parser)->location;
> +	      tree attrs = c_parser_gnu_attributes (parser);
> +	      if (attribute_fallthrough_p (attrs))
> +		{
> +		  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
> +		    {
> +		      tree fn = build_call_expr_internal_loc (loc,
> +							      IFN_FALLTHROUGH,
> +							      void_type_node, 0);
> +		      add_stmt (fn);
> +		    }
> +		  else
> +		     warning_at (loc, OPT_Wattributes, "%<fallthrough%> attribute "
> +			  "not followed by %<;%>");
> +		}
> +	      else if (attrs != NULL_TREE)
> +		warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
> +			    " can be applied to a null statement");
> +	    }

I don't think this is necessary or correct here.

This code is being moved from c_parser_label.  The syntax that 
c_parser_label was supposed to handle, as shown in the comment above the 
function, is:

   label:
     identifier : gnu-attributes[opt]
     case constant-expression :
     default :

   GNU extensions:

   label:
     case constant-expression ... constant-expression :

That is: attributes on a label that is an identifier were parsed, and 
applied to the identifier, by code that's unchanged (beyond applying 
standard attributes rather than just warning in the caller that they are 
unused) by this patch.  So this code could only fire in c_parser_label for 
a case or default label, a case in which GNU attributes on the label are 
not part of the syntax.

Previously, a case or default label could not be followed by a 
declaration, so there was no particular concern about consuming prefix GNU 
attributes on such a following declaration; the declaration would still 
result in a syntax error (and fallthrough attributes were the only valid 
case needing to be handled).  Now that such a declaration is valid, I 
think the attributes should be be parsed specially here, but left to apply 
to that declaration.  The code in c_parser_declaration_or_fndef that 
handles GNU fallthrough attributes should suffice to handle one in this 
case; other warnings for empty declarations should suffice in the case 
where there are other attributes but no declaration following.

> @@ -5843,12 +5879,10 @@ c_parser_all_labels (c_parser *parser)
>     GNU C accepts any expressions without commas, non-constant
>     expressions being rejected later.  Any standard
>     attribute-specifier-sequence before the first label has been parsed
> -   in the caller, to distinguish statements from declarations.  Any
> -   attribute-specifier-sequence after the label is parsed in this
> -   function.  */
> +   in the caller, to distinguish statements from declarations.  */

I don't think this change to the comment is accurate.  As shown in the 
(unmodified) syntax comment, GNU attributes on a label that is an 
identifier (the only kind that has them) are still parsed in this 
function.  It's only fallthrough attributes after case and default labels 
(which weren't part of that syntax comment anyway) that are no longer 
parsed here.

> @@ -5898,8 +5932,13 @@ c_parser_label (c_parser *parser)
>        if (tlab)
>  	{
>  	  decl_attributes (&tlab, attrs, 0);
> +	  decl_attributes (&tlab, std_attrs, 0);
>  	  label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab));
>  	}
> +      if (attrs
> +	  && c_parser_next_tokens_start_declaration (parser))
> +	  warning_at (loc2, OPT_Wattributes, "GNU-style attribute between"
> +		      " label and declaration appertains to the label.");

No trailing '.' on diagnostics.
Uecker, Martin Nov. 6, 2020, 6:56 a.m. UTC | #4
Hi Joseph,

here is the revised patch. I remove the 'fallthrough'
code as suggested, so everything becomes even simpler.
Some tests had to be changed then, but it seems Ok to
me.

Best,
Martin


diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index ca844ca775a..c656b5f4cc5 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,8 @@
+2020-11-06  Martin Uecker  <muecker@gwdg.de>
+
+	* c-parser.c (c_parser_label): Implement mixing of labels and code.
+	(c_parser_all_labels): Likewise.
+
 2020-10-29  Asher Gordon  <AsDaGo@posteo.net>
 
 	* c-typeck.c (free_all_tagged_tu_seen_up_to): Replace free
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index fc97aa3f95f..53179f10985 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1521,7 +1521,7 @@ static void c_parser_initval (c_parser *, struct c_expr *,
 			      struct obstack *);
 static tree c_parser_compound_statement (c_parser *, location_t * = NULL);
 static location_t c_parser_compound_statement_nostart (c_parser *);
-static void c_parser_label (c_parser *);
+static void c_parser_label (c_parser *, tree);
 static void c_parser_statement (c_parser *, bool *, location_t * = NULL);
 static void c_parser_statement_after_labels (c_parser *, bool *,
 					     vec<tree> * = NULL);
@@ -5523,7 +5523,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after,
 }
 
 /* Parse a compound statement (possibly a function body) (C90 6.6.2,
-   C99 6.8.2, C11 6.8.2).
+   C99 6.8.2, C11 6.8.2, C2X 6.8.2).
 
    compound-statement:
      { block-item-list[opt] }
@@ -5534,6 +5534,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after,
      block-item-list block-item
 
    block-item:
+     label
      nested-declaration
      statement
 
@@ -5674,7 +5675,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
     {
       location_t loc = c_parser_peek_token (parser)->location;
       loc = expansion_point_location_if_in_system_header (loc);
-      /* Standard attributes may start a statement or a declaration.  */
+      /* Standard attributes may start a label, statement or declaration.  */
       bool have_std_attrs
 	= c_parser_nth_token_starts_std_attributes (parser, 1);
       tree std_attrs = NULL_TREE;
@@ -5685,7 +5686,6 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  || (c_parser_next_token_is (parser, CPP_NAME)
 	      && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
 	{
-	  c_warn_unused_attributes (std_attrs);
 	  if (c_parser_next_token_is_keyword (parser, RID_CASE))
 	    label_loc = c_parser_peek_2nd_token (parser)->location;
 	  else
@@ -5693,27 +5693,31 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  last_label = true;
 	  last_stmt = false;
 	  mark_valid_location_for_stdc_pragma (false);
-	  c_parser_label (parser);
+	  c_parser_label (parser, std_attrs);
 	}
-      else if (!last_label
-	       && (c_parser_next_tokens_start_declaration (parser)
-		   || (have_std_attrs
-		       && c_parser_next_token_is (parser, CPP_SEMICOLON))))
+      else if (c_parser_next_tokens_start_declaration (parser)
+	       || (have_std_attrs
+		   && c_parser_next_token_is (parser, CPP_SEMICOLON)))
 	{
-	  last_label = false;
+	  if (last_label)
+	    pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic,
+			 "a label can only be part of a statement and "
+			 "a declaration is not a statement");
+
 	  mark_valid_location_for_stdc_pragma (false);
 	  bool fallthru_attr_p = false;
 	  c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
 					 true, true, true, NULL,
 					 vNULL, have_std_attrs, std_attrs,
 					 NULL, &fallthru_attr_p);
+
 	  if (last_stmt && !fallthru_attr_p)
 	    pedwarn_c90 (loc, OPT_Wdeclaration_after_statement,
 			 "ISO C90 forbids mixed declarations and code");
 	  last_stmt = fallthru_attr_p;
+	  last_label = false;
 	}
-      else if (!last_label
-	       && c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+      else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
 	{
 	  /* __extension__ can start a declaration, but is also an
 	     unary operator that can start an expression.  Consume all
@@ -5796,7 +5800,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
       parser->error = false;
     }
   if (last_label)
-    error_at (label_loc, "label at end of compound statement");
+    pedwarn_c11 (label_loc, OPT_Wpedantic, "label at end of compound statement");
   location_t endloc = c_parser_peek_token (parser)->location;
   c_parser_consume_token (parser);
   /* Restore the value we started with.  */
@@ -5812,19 +5816,29 @@ c_parser_compound_statement_nostart (c_parser *parser)
 static void
 c_parser_all_labels (c_parser *parser)
 {
+  tree std_attrs = NULL;
   if (c_parser_nth_token_starts_std_attributes (parser, 1))
     {
-      tree std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+      std_attrs = c_parser_std_attribute_specifier_sequence (parser);
       if (c_parser_next_token_is (parser, CPP_SEMICOLON))
 	c_parser_error (parser, "expected statement");
-      else
-	c_warn_unused_attributes (std_attrs);
     }
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	 || (c_parser_next_token_is (parser, CPP_NAME)
 	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
-    c_parser_label (parser);
+    {
+      c_parser_label (parser, std_attrs);
+      std_attrs = NULL;
+      if (c_parser_nth_token_starts_std_attributes (parser, 1))
+	{
+	  std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+	  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	    c_parser_error (parser, "expected statement");
+	}
+    }
+   if (std_attrs)
+     c_warn_unused_attributes (std_attrs);
 }
 
 /* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1).
@@ -5846,9 +5860,8 @@ c_parser_all_labels (c_parser *parser)
    in the caller, to distinguish statements from declarations.  Any
    attribute-specifier-sequence after the label is parsed in this
    function.  */
-
 static void
-c_parser_label (c_parser *parser)
+c_parser_label (c_parser *parser, tree std_attrs)
 {
   location_t loc1 = c_parser_peek_token (parser)->location;
   tree label = NULL_TREE;
@@ -5898,8 +5911,13 @@ c_parser_label (c_parser *parser)
       if (tlab)
 	{
 	  decl_attributes (&tlab, attrs, 0);
+	  decl_attributes (&tlab, std_attrs, 0);
 	  label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab));
 	}
+      if (attrs
+	  && c_parser_next_tokens_start_declaration (parser))
+	  warning_at (loc2, OPT_Wattributes, "GNU-style attribute between"
+		      " label and declaration appertains to the label");
     }
   if (label)
     {
@@ -5907,55 +5925,6 @@ c_parser_label (c_parser *parser)
 	FALLTHROUGH_LABEL_P (LABEL_EXPR_LABEL (label)) = fallthrough_p;
       else
 	FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p;
-
-      /* Standard attributes are only allowed here if they start a
-	 statement, not a declaration (including the case of an
-	 attribute-declaration with only attributes).  */
-      bool have_std_attrs
-	= c_parser_nth_token_starts_std_attributes (parser, 1);
-      tree std_attrs = NULL_TREE;
-      if (have_std_attrs)
-	std_attrs = c_parser_std_attribute_specifier_sequence (parser);
-
-      /* Allow '__attribute__((fallthrough));'.  */
-      if (!have_std_attrs
-	  && c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
-	{
-	  location_t loc = c_parser_peek_token (parser)->location;
-	  tree attrs = c_parser_gnu_attributes (parser);
-	  if (attribute_fallthrough_p (attrs))
-	    {
-	      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
-		{
-		  tree fn = build_call_expr_internal_loc (loc,
-							  IFN_FALLTHROUGH,
-							  void_type_node, 0);
-		  add_stmt (fn);
-		}
-	      else
-		warning_at (loc, OPT_Wattributes, "%<fallthrough%> attribute "
-			    "not followed by %<;%>");
-	    }
-	  else if (attrs != NULL_TREE)
-	    warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
-			" can be applied to a null statement");
-	}
-      if (c_parser_next_tokens_start_declaration (parser)
-	  || (have_std_attrs
-	      && c_parser_next_token_is (parser, CPP_SEMICOLON)))
-	{
-	  error_at (c_parser_peek_token (parser)->location,
-		    "a label can only be part of a statement and "
-		    "a declaration is not a statement");
-	  c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
-					 /*static_assert_ok*/ true,
-					 /*empty_ok*/ true, /*nested*/ true,
-					 /*start_attr_ok*/ true, NULL,
-					 vNULL, have_std_attrs, std_attrs);
-	}
-      else if (std_attrs)
-	/* Nonempty attributes on the following statement are ignored.  */
-	c_warn_unused_attributes (std_attrs);
     }
 }
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 7a6ecce6a84..89179e243c6 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -55,7 +55,7 @@ extensions, accepted by GCC in C90 mode and in C++.
 * Designated Inits::    Labeling elements of initializers.
 * Case Ranges::         `case 1 ... 9' and such.
 * Cast to Union::       Casting to union type from any member of the union.
-* Mixed Declarations::  Mixing declarations and code.
+* Mixed Labels and Declarations::  Mixing declarations, labels and code.
 * Function Attributes:: Declaring that functions have no side effects,
                         or that they can never return.
 * Variable Attributes:: Specifying attributes of variables.
@@ -2353,15 +2353,17 @@ void hack (union foo);
 hack ((union foo) x);
 @end smallexample
 
-@node Mixed Declarations
-@section Mixed Declarations and Code
+@node Mixed Labels and Declarations
+@section Mixed Declarations, Labels and Code
 @cindex mixed declarations and code
 @cindex declarations, mixed with code
 @cindex code, mixed with declarations
 
 ISO C99 and ISO C++ allow declarations and code to be freely mixed
-within compound statements.  As an extension, GNU C also allows this in
-C90 mode.  For example, you could do:
+within compound statements.  ISO C2X allows labels to be
+placed before declarations and at the end of a compound statement.
+As an extension, GNU C also allows all this in C90 mode.  For example,
+you could do:
 
 @smallexample
 int i;
@@ -8630,7 +8632,8 @@ details of the exact syntax for using attributes.  Other attributes are
 available for functions (@pxref{Function Attributes}), variables 
 (@pxref{Variable Attributes}), enumerators (@pxref{Enumerator Attributes}),
 statements (@pxref{Statement Attributes}), and for types
-(@pxref{Type Attributes}).
+(@pxref{Type Attributes}). A label attribute followed
+by a declaration appertains to the label and not the declaration.
 
 This example uses the @code{cold} label attribute to indicate the 
 @code{ErrorHandling} branch is unlikely to be taken and that the
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5320e6c1e1e..eeb54fb46d9 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -7592,7 +7592,7 @@ except when the same as the default promotion.
 @opindex Wno-declaration-after-statement
 Warn when a declaration is found after a statement in a block.  This
 construct, known from C++, was introduced with ISO C99 and is by default
-allowed in GCC@.  It is not supported by ISO C90.  @xref{Mixed Declarations}.
+allowed in GCC@.  It is not supported by ISO C90.  @xref{Mixed Labels and Declarations}.
 
 @item -Wshadow
 @opindex Wshadow
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 40200222446..2a8233c04e4 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,22 @@
+2020-11-06  Martin Uecker  <muecker@gwdg.de>
+
+	* gcc.dg/20031223-1.c: Update compiler flags and adapt test.
+	* gcc.dg/c11-labels-1.c: New test.
+	* gcc.dg/c11-labels-2.c: New test.
+	* gcc.dg/c11-labels-3.c: New test.
+	* gcc.dg/c2x-attr-syntax-3.c: Adapt test.
+	* gcc.dg/c2x-labels-1.c: New test.
+	* gcc.dg/c2x-labels-2.c: New test.
+	* gcc.dg/c2x-labels-3.c: New test.
+	* gcc.dg/decl-9.c: Update compiler flags and add error.
+	* gcc.dg/c-c++-common/attr-fallthrough-2.c: Update compiler flags.
+	* gcc.dg/c-c++-common/Wimplicit-fallthrough-20.c: Adapt test.
+	* gcc.dg/gomp/barrier-2.c: Update compiler flags and add warning.
+	* gcc.dg/gomp/declare-simd-5.c: Update compiler flags and adapt test.
+	* gcc.dg/gomp/declare-variant-2.c: Update compiler flags and add error.
+	* gcc.dg/label-compound-stmt-1.c: Update compiler flags.
+	* gcc.dg/parse-decl-after-label.c: Update compiler flags.
+
 2020-11-03  Jan Hubicka  <jh@suse.cz>
 
 	* gcc.c-torture/execute/pr97695.c: New test.
diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
index d37a840a0d9..810c331b19a 100644
--- a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
+++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
@@ -27,13 +27,13 @@ g (int i)
   switch (i)
     {
     case -1:
-      __attribute__((used)); /* { dg-warning "ignored|only attribute" } */
+      __attribute__((used)); /* { dg-warning "empty declaration" } */
     default:
-      __attribute__((used)); /* { dg-warning "ignored|only attribute" } */
+      __attribute__((used)); /* { dg-warning "empty declaration" } */
     case 1:
       return 6;
     case 2 ... 4:
-      __attribute__((used)); /* { dg-warning "ignored|only attribute" } */
+      __attribute__((used)); /* { dg-warning "empty declaration" } */
     case 5:
       return 7;
     }
diff --git a/gcc/testsuite/c-c++-common/attr-fallthrough-2.c b/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
index e8659e572ca..be61d5e6666 100644
--- a/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
+++ b/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
@@ -1,6 +1,6 @@
 /* PR c/7652 */
 /* { dg-do compile } */
-/* { dg-options "-Wall -Wextra -Wpedantic -Wno-unused -Wno-implicit-fallthrough" } */
+/* { dg-options "-Wall -Wextra -Wno-unused -Wno-implicit-fallthrough" } */
 
 extern void bar (int);
 void
diff --git a/gcc/testsuite/gcc.dg/20031223-1.c b/gcc/testsuite/gcc.dg/20031223-1.c
index 68aa74ffe50..c529739e7ec 100644
--- a/gcc/testsuite/gcc.dg/20031223-1.c
+++ b/gcc/testsuite/gcc.dg/20031223-1.c
@@ -3,11 +3,10 @@
    because GCC was trying to expand the trees to rtl.  */
 
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-std=c17 -pedantic-errors" } */
 
 void f ()
 {
  l: int; /* { dg-error "a label can only be part of a statement and a declaration is not a statement" "not stmt" } */
- /* { dg-warning "useless type name in empty declaration" "type name" { target *-*-* } .-1 } */
- /* { dg-error "label at end of compound statement" "label" { target *-*-* } .-2 } */
+ /* { dg-error "useless type name in empty declaration" "type name" { target *-*-* } .-1 } */
 }
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c b/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
index 1f883d825e0..2f0d9f60cc0 100644
--- a/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
+++ b/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
@@ -25,13 +25,14 @@ f2 (void)
 }
 
 /* Declarations, including attribute declarations, cannot appear after
-   labels.  */
+   labels when a statement is expected.  */
 
 void
 f3 (void)
 {
- x: [[]];; /* { dg-error "can only be part of a statement" } */
-}
+  if (1)
+    x: [[]]; /* { dg-error "expected" } */
+} 
 
 /* Prefix attributes cannot appear on type names.  */
 
diff --git a/gcc/testsuite/gcc.dg/decl-9.c b/gcc/testsuite/gcc.dg/decl-9.c
index eeca8e05e14..9bb15609d83 100644
--- a/gcc/testsuite/gcc.dg/decl-9.c
+++ b/gcc/testsuite/gcc.dg/decl-9.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-std=gnu89" } */
+/* { dg-options "-std=gnu89 -pedantic-errors" } */
 
 w *x; /* { dg-error "unknown type name 'w'" } */
 
@@ -12,6 +12,7 @@ int f1()
   int d, e;
   d * e; /* { dg-bogus "unknown type name 'd'" } */
   g * h; /* { dg-error "unknown type name 'g'" } */
+  /* { dg-error "mixed declarations" "" { target *-*-* } .-1 } */
   g i;   /* { dg-error "unknown type name 'g'" } */
 }
 
diff --git a/gcc/testsuite/gcc.dg/gomp/barrier-2.c b/gcc/testsuite/gcc.dg/gomp/barrier-2.c
index 5a7091946c4..c0d62f572bb 100644
--- a/gcc/testsuite/gcc.dg/gomp/barrier-2.c
+++ b/gcc/testsuite/gcc.dg/gomp/barrier-2.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-options "-Wall -std=c17 -fopenmp -pedantic-errors" } */
 
 void f1(void)
 {
@@ -16,6 +17,7 @@ void f1(void)
 void f2(void)
 {
   label:       /* { dg-error "label at end of compound statement" } */
+    /* { dg-warning "defined but not used" "" { target *-*-* } .-1 } */
     #pragma omp barrier		/* { dg-error "may only be used in compound statements" } */
 }
 
diff --git a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
index fe236525d62..b9a4161c0c9 100644
--- a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
+++ b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
@@ -1,5 +1,6 @@
 /* Test parsing of #pragma omp declare simd */
 /* { dg-do compile } */
+/* { dg-options "-std=c17 -fopenmp -pedantic-errors" } */
 
 int
 f1 (int x)
@@ -14,7 +15,7 @@ f1 (int x)
 lab:
     #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int))
     extern int f5 (int a, int *b, int c);	/* { dg-error "must be followed by function declaration or definition" } */
-    x++;					/* { dg-error "expected expression before" "" { target *-*-* } .-1 } */
+    x++;					/* { dg-error "a label can only be part of a statement and a declaration is not a statement" "" { target *-*-* } .-1 } */
   }
   return x;
 }
diff --git a/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c b/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c
index 701d83b0ec3..39c2c1d40ee 100644
--- a/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c
+++ b/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c
@@ -1,5 +1,6 @@
 /* Test parsing of #pragma omp declare variant */
 /* { dg-do compile } */
+/* { dg-options "-std=c17 -fopenmp -pedantic-errors" } */
 
 int f0 (int, int *, int);
 
@@ -16,7 +17,7 @@ f1 (int x)
 lab:
     #pragma omp declare variant (fn0) match (user={condition(0)})
     extern int f5 (int a, int *b, int c);	/* { dg-error "must be followed by function declaration or definition" } */
-    x++;					/* { dg-error "expected expression before" "" { target *-*-* } .-1 } */
+    x++;					/* { dg-error "a label can only be part of a statement and a declaration is not a statement" "" { target *-*-* } .-1 } */
   }
   return x;
 }
diff --git a/gcc/testsuite/gcc.dg/label-compound-stmt-1.c b/gcc/testsuite/gcc.dg/label-compound-stmt-1.c
index 2f8fa4e65c2..2ae2b82ef1c 100644
--- a/gcc/testsuite/gcc.dg/label-compound-stmt-1.c
+++ b/gcc/testsuite/gcc.dg/label-compound-stmt-1.c
@@ -1,7 +1,7 @@
 /* Test that labels at ends of compound statements are hard errors.  */
 /* Origin: Joseph Myers <jsm@polyomino.org.uk> */
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-std=c17 -pedantic-errors" } */
 
 void f(void) { g: } /* { dg-bogus "warning" "warning in place of error" } */
 /* { dg-error "label|parse|syntax" "label at end of compound statement" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/parse-decl-after-label.c b/gcc/testsuite/gcc.dg/parse-decl-after-label.c
index 9c9886a108f..6e2a047eb2e 100644
--- a/gcc/testsuite/gcc.dg/parse-decl-after-label.c
+++ b/gcc/testsuite/gcc.dg/parse-decl-after-label.c
@@ -1,6 +1,6 @@
 /* PR 29062 
 { dg-do compile }
-{ dg-options "-fsyntax-only" }
+{ dg-options "-std=c17 -pedantic-errors -fsyntax-only" }
 */
 
 int f(int x)
Joseph Myers Nov. 6, 2020, 10:07 p.m. UTC | #5
On Fri, 6 Nov 2020, Uecker, Martin wrote:

> Hi Joseph,
> 
> here is the revised patch. I remove the 'fallthrough'
> code as suggested, so everything becomes even simpler.
> Some tests had to be changed then, but it seems Ok to
> me.

This patch is missing the new tests.

> +	* gcc.dg/c11-labels-1.c: New test.
> +	* gcc.dg/c11-labels-2.c: New test.
> +	* gcc.dg/c11-labels-3.c: New test.
> +	* gcc.dg/c2x-labels-1.c: New test.
> +	* gcc.dg/c2x-labels-2.c: New test.
> +	* gcc.dg/c2x-labels-3.c: New test.
Uecker, Martin Nov. 6, 2020, 10:25 p.m. UTC | #6
Am Freitag, den 06.11.2020, 22:07 +0000 schrieb Joseph Myers:
> On Fri, 6 Nov 2020, Uecker, Martin wrote:
> 
> > Hi Joseph,
> > 
> > here is the revised patch. I remove the 'fallthrough'
> > code as suggested, so everything becomes even simpler.
> > Some tests had to be changed then, but it seems Ok to
> > me.
> 
> This patch is missing the new tests.
> 
> > +	* gcc.dg/c11-labels-1.c: New test.
> > +	* gcc.dg/c11-labels-2.c: New test.
> > +	* gcc.dg/c11-labels-3.c: New test.
> > +	* gcc.dg/c2x-labels-1.c: New test.
> > +	* gcc.dg/c2x-labels-2.c: New test.
> > +	* gcc.dg/c2x-labels-3.c: New test.
> 
> 

My bad. Here there are.

diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index ca844ca775a..c656b5f4cc5 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,8 @@
+2020-11-06  Martin Uecker  <muecker@gwdg.de>
+
+	* c-parser.c (c_parser_label): Implement mixing of labels and code.
+	(c_parser_all_labels): Likewise.
+
 2020-10-29  Asher Gordon  <AsDaGo@posteo.net>
 
 	* c-typeck.c (free_all_tagged_tu_seen_up_to): Replace free
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index fc97aa3f95f..53179f10985 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1521,7 +1521,7 @@ static void c_parser_initval (c_parser *, struct c_expr *,
 			      struct obstack *);
 static tree c_parser_compound_statement (c_parser *, location_t * = NULL);
 static location_t c_parser_compound_statement_nostart (c_parser *);
-static void c_parser_label (c_parser *);
+static void c_parser_label (c_parser *, tree);
 static void c_parser_statement (c_parser *, bool *, location_t * = NULL);
 static void c_parser_statement_after_labels (c_parser *, bool *,
 					     vec<tree> * = NULL);
@@ -5523,7 +5523,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after,
 }
 
 /* Parse a compound statement (possibly a function body) (C90 6.6.2,
-   C99 6.8.2, C11 6.8.2).
+   C99 6.8.2, C11 6.8.2, C2X 6.8.2).
 
    compound-statement:
      { block-item-list[opt] }
@@ -5534,6 +5534,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after,
      block-item-list block-item
 
    block-item:
+     label
      nested-declaration
      statement
 
@@ -5674,7 +5675,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
     {
       location_t loc = c_parser_peek_token (parser)->location;
       loc = expansion_point_location_if_in_system_header (loc);
-      /* Standard attributes may start a statement or a declaration.  */
+      /* Standard attributes may start a label, statement or declaration.  */
       bool have_std_attrs
 	= c_parser_nth_token_starts_std_attributes (parser, 1);
       tree std_attrs = NULL_TREE;
@@ -5685,7 +5686,6 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  || (c_parser_next_token_is (parser, CPP_NAME)
 	      && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
 	{
-	  c_warn_unused_attributes (std_attrs);
 	  if (c_parser_next_token_is_keyword (parser, RID_CASE))
 	    label_loc = c_parser_peek_2nd_token (parser)->location;
 	  else
@@ -5693,27 +5693,31 @@ c_parser_compound_statement_nostart (c_parser *parser)
 	  last_label = true;
 	  last_stmt = false;
 	  mark_valid_location_for_stdc_pragma (false);
-	  c_parser_label (parser);
+	  c_parser_label (parser, std_attrs);
 	}
-      else if (!last_label
-	       && (c_parser_next_tokens_start_declaration (parser)
-		   || (have_std_attrs
-		       && c_parser_next_token_is (parser, CPP_SEMICOLON))))
+      else if (c_parser_next_tokens_start_declaration (parser)
+	       || (have_std_attrs
+		   && c_parser_next_token_is (parser, CPP_SEMICOLON)))
 	{
-	  last_label = false;
+	  if (last_label)
+	    pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic,
+			 "a label can only be part of a statement and "
+			 "a declaration is not a statement");
+
 	  mark_valid_location_for_stdc_pragma (false);
 	  bool fallthru_attr_p = false;
 	  c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
 					 true, true, true, NULL,
 					 vNULL, have_std_attrs, std_attrs,
 					 NULL, &fallthru_attr_p);
+
 	  if (last_stmt && !fallthru_attr_p)
 	    pedwarn_c90 (loc, OPT_Wdeclaration_after_statement,
 			 "ISO C90 forbids mixed declarations and code");
 	  last_stmt = fallthru_attr_p;
+	  last_label = false;
 	}
-      else if (!last_label
-	       && c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+      else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
 	{
 	  /* __extension__ can start a declaration, but is also an
 	     unary operator that can start an expression.  Consume all
@@ -5796,7 +5800,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
       parser->error = false;
     }
   if (last_label)
-    error_at (label_loc, "label at end of compound statement");
+    pedwarn_c11 (label_loc, OPT_Wpedantic, "label at end of compound statement");
   location_t endloc = c_parser_peek_token (parser)->location;
   c_parser_consume_token (parser);
   /* Restore the value we started with.  */
@@ -5812,19 +5816,29 @@ c_parser_compound_statement_nostart (c_parser *parser)
 static void
 c_parser_all_labels (c_parser *parser)
 {
+  tree std_attrs = NULL;
   if (c_parser_nth_token_starts_std_attributes (parser, 1))
     {
-      tree std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+      std_attrs = c_parser_std_attribute_specifier_sequence (parser);
       if (c_parser_next_token_is (parser, CPP_SEMICOLON))
 	c_parser_error (parser, "expected statement");
-      else
-	c_warn_unused_attributes (std_attrs);
     }
   while (c_parser_next_token_is_keyword (parser, RID_CASE)
 	 || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
 	 || (c_parser_next_token_is (parser, CPP_NAME)
 	     && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
-    c_parser_label (parser);
+    {
+      c_parser_label (parser, std_attrs);
+      std_attrs = NULL;
+      if (c_parser_nth_token_starts_std_attributes (parser, 1))
+	{
+	  std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+	  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	    c_parser_error (parser, "expected statement");
+	}
+    }
+   if (std_attrs)
+     c_warn_unused_attributes (std_attrs);
 }
 
 /* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1).
@@ -5846,9 +5860,8 @@ c_parser_all_labels (c_parser *parser)
    in the caller, to distinguish statements from declarations.  Any
    attribute-specifier-sequence after the label is parsed in this
    function.  */
-
 static void
-c_parser_label (c_parser *parser)
+c_parser_label (c_parser *parser, tree std_attrs)
 {
   location_t loc1 = c_parser_peek_token (parser)->location;
   tree label = NULL_TREE;
@@ -5898,8 +5911,13 @@ c_parser_label (c_parser *parser)
       if (tlab)
 	{
 	  decl_attributes (&tlab, attrs, 0);
+	  decl_attributes (&tlab, std_attrs, 0);
 	  label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab));
 	}
+      if (attrs
+	  && c_parser_next_tokens_start_declaration (parser))
+	  warning_at (loc2, OPT_Wattributes, "GNU-style attribute between"
+		      " label and declaration appertains to the label");
     }
   if (label)
     {
@@ -5907,55 +5925,6 @@ c_parser_label (c_parser *parser)
 	FALLTHROUGH_LABEL_P (LABEL_EXPR_LABEL (label)) = fallthrough_p;
       else
 	FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p;
-
-      /* Standard attributes are only allowed here if they start a
-	 statement, not a declaration (including the case of an
-	 attribute-declaration with only attributes).  */
-      bool have_std_attrs
-	= c_parser_nth_token_starts_std_attributes (parser, 1);
-      tree std_attrs = NULL_TREE;
-      if (have_std_attrs)
-	std_attrs = c_parser_std_attribute_specifier_sequence (parser);
-
-      /* Allow '__attribute__((fallthrough));'.  */
-      if (!have_std_attrs
-	  && c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
-	{
-	  location_t loc = c_parser_peek_token (parser)->location;
-	  tree attrs = c_parser_gnu_attributes (parser);
-	  if (attribute_fallthrough_p (attrs))
-	    {
-	      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
-		{
-		  tree fn = build_call_expr_internal_loc (loc,
-							  IFN_FALLTHROUGH,
-							  void_type_node, 0);
-		  add_stmt (fn);
-		}
-	      else
-		warning_at (loc, OPT_Wattributes, "%<fallthrough%> attribute "
-			    "not followed by %<;%>");
-	    }
-	  else if (attrs != NULL_TREE)
-	    warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
-			" can be applied to a null statement");
-	}
-      if (c_parser_next_tokens_start_declaration (parser)
-	  || (have_std_attrs
-	      && c_parser_next_token_is (parser, CPP_SEMICOLON)))
-	{
-	  error_at (c_parser_peek_token (parser)->location,
-		    "a label can only be part of a statement and "
-		    "a declaration is not a statement");
-	  c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
-					 /*static_assert_ok*/ true,
-					 /*empty_ok*/ true, /*nested*/ true,
-					 /*start_attr_ok*/ true, NULL,
-					 vNULL, have_std_attrs, std_attrs);
-	}
-      else if (std_attrs)
-	/* Nonempty attributes on the following statement are ignored.  */
-	c_warn_unused_attributes (std_attrs);
     }
 }
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 7a6ecce6a84..89179e243c6 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -55,7 +55,7 @@ extensions, accepted by GCC in C90 mode and in C++.
 * Designated Inits::    Labeling elements of initializers.
 * Case Ranges::         `case 1 ... 9' and such.
 * Cast to Union::       Casting to union type from any member of the union.
-* Mixed Declarations::  Mixing declarations and code.
+* Mixed Labels and Declarations::  Mixing declarations, labels and code.
 * Function Attributes:: Declaring that functions have no side effects,
                         or that they can never return.
 * Variable Attributes:: Specifying attributes of variables.
@@ -2353,15 +2353,17 @@ void hack (union foo);
 hack ((union foo) x);
 @end smallexample
 
-@node Mixed Declarations
-@section Mixed Declarations and Code
+@node Mixed Labels and Declarations
+@section Mixed Declarations, Labels and Code
 @cindex mixed declarations and code
 @cindex declarations, mixed with code
 @cindex code, mixed with declarations
 
 ISO C99 and ISO C++ allow declarations and code to be freely mixed
-within compound statements.  As an extension, GNU C also allows this in
-C90 mode.  For example, you could do:
+within compound statements.  ISO C2X allows labels to be
+placed before declarations and at the end of a compound statement.
+As an extension, GNU C also allows all this in C90 mode.  For example,
+you could do:
 
 @smallexample
 int i;
@@ -8630,7 +8632,8 @@ details of the exact syntax for using attributes.  Other attributes are
 available for functions (@pxref{Function Attributes}), variables 
 (@pxref{Variable Attributes}), enumerators (@pxref{Enumerator Attributes}),
 statements (@pxref{Statement Attributes}), and for types
-(@pxref{Type Attributes}).
+(@pxref{Type Attributes}). A label attribute followed
+by a declaration appertains to the label and not the declaration.
 
 This example uses the @code{cold} label attribute to indicate the 
 @code{ErrorHandling} branch is unlikely to be taken and that the
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5320e6c1e1e..eeb54fb46d9 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -7592,7 +7592,7 @@ except when the same as the default promotion.
 @opindex Wno-declaration-after-statement
 Warn when a declaration is found after a statement in a block.  This
 construct, known from C++, was introduced with ISO C99 and is by default
-allowed in GCC@.  It is not supported by ISO C90.  @xref{Mixed Declarations}.
+allowed in GCC@.  It is not supported by ISO C90.  @xref{Mixed Labels and Declarations}.
 
 @item -Wshadow
 @opindex Wshadow
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 40200222446..2a8233c04e4 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,22 @@
+2020-11-06  Martin Uecker  <muecker@gwdg.de>
+
+	* gcc.dg/20031223-1.c: Update compiler flags and adapt test.
+	* gcc.dg/c11-labels-1.c: New test.
+	* gcc.dg/c11-labels-2.c: New test.
+	* gcc.dg/c11-labels-3.c: New test.
+	* gcc.dg/c2x-attr-syntax-3.c: Adapt test.
+	* gcc.dg/c2x-labels-1.c: New test.
+	* gcc.dg/c2x-labels-2.c: New test.
+	* gcc.dg/c2x-labels-3.c: New test.
+	* gcc.dg/decl-9.c: Update compiler flags and add error.
+	* gcc.dg/c-c++-common/attr-fallthrough-2.c: Update compiler flags.
+	* gcc.dg/c-c++-common/Wimplicit-fallthrough-20.c: Adapt test.
+	* gcc.dg/gomp/barrier-2.c: Update compiler flags and add warning.
+	* gcc.dg/gomp/declare-simd-5.c: Update compiler flags and adapt test.
+	* gcc.dg/gomp/declare-variant-2.c: Update compiler flags and add error.
+	* gcc.dg/label-compound-stmt-1.c: Update compiler flags.
+	* gcc.dg/parse-decl-after-label.c: Update compiler flags.
+
 2020-11-03  Jan Hubicka  <jh@suse.cz>
 
 	* gcc.c-torture/execute/pr97695.c: New test.
diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
index d37a840a0d9..810c331b19a 100644
--- a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
+++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
@@ -27,13 +27,13 @@ g (int i)
   switch (i)
     {
     case -1:
-      __attribute__((used)); /* { dg-warning "ignored|only attribute" } */
+      __attribute__((used)); /* { dg-warning "empty declaration" } */
     default:
-      __attribute__((used)); /* { dg-warning "ignored|only attribute" } */
+      __attribute__((used)); /* { dg-warning "empty declaration" } */
     case 1:
       return 6;
     case 2 ... 4:
-      __attribute__((used)); /* { dg-warning "ignored|only attribute" } */
+      __attribute__((used)); /* { dg-warning "empty declaration" } */
     case 5:
       return 7;
     }
diff --git a/gcc/testsuite/c-c++-common/attr-fallthrough-2.c b/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
index e8659e572ca..be61d5e6666 100644
--- a/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
+++ b/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
@@ -1,6 +1,6 @@
 /* PR c/7652 */
 /* { dg-do compile } */
-/* { dg-options "-Wall -Wextra -Wpedantic -Wno-unused -Wno-implicit-fallthrough" } */
+/* { dg-options "-Wall -Wextra -Wno-unused -Wno-implicit-fallthrough" } */
 
 extern void bar (int);
 void
diff --git a/gcc/testsuite/gcc.dg/20031223-1.c b/gcc/testsuite/gcc.dg/20031223-1.c
index 68aa74ffe50..c529739e7ec 100644
--- a/gcc/testsuite/gcc.dg/20031223-1.c
+++ b/gcc/testsuite/gcc.dg/20031223-1.c
@@ -3,11 +3,10 @@
    because GCC was trying to expand the trees to rtl.  */
 
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-std=c17 -pedantic-errors" } */
 
 void f ()
 {
  l: int; /* { dg-error "a label can only be part of a statement and a declaration is not a statement" "not stmt" } */
- /* { dg-warning "useless type name in empty declaration" "type name" { target *-*-* } .-1 } */
- /* { dg-error "label at end of compound statement" "label" { target *-*-* } .-2 } */
+ /* { dg-error "useless type name in empty declaration" "type name" { target *-*-* } .-1 } */
 }
diff --git a/gcc/testsuite/gcc.dg/c11-labels-1.c b/gcc/testsuite/gcc.dg/c11-labels-1.c
new file mode 100644
index 00000000000..6350403bf38
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-labels-1.c
@@ -0,0 +1,15 @@
+/* Tests for labels before declarations and at ends of compound statements.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11" } */
+
+int f(int x) 
+{ 
+	goto b;
+	a: int i = 2 * x;
+           goto c;
+	b: goto a;
+	{ i *= 3; c: }
+	return i;
+        d:
+}
+
diff --git a/gcc/testsuite/gcc.dg/c11-labels-2.c b/gcc/testsuite/gcc.dg/c11-labels-2.c
new file mode 100644
index 00000000000..e9b492446b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-labels-2.c
@@ -0,0 +1,15 @@
+/* Tests for labels before declarations and at ends of compound statements.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic" } */
+
+int f(int x) 
+{ 
+	goto b;
+	a: int i = 2 * x; 	/* { dg-warning "a label can only be part of a statement and a declaration is not a statement" } */
+           goto c;
+	b: goto a;
+	{ i *= 3; c: }		/* { dg-warning "label at end of compound statement" } */
+	return i;
+        d:			/* { dg-warning "label at end of compound statement" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/c11-labels-3.c b/gcc/testsuite/gcc.dg/c11-labels-3.c
new file mode 100644
index 00000000000..1e4be63af69
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-labels-3.c
@@ -0,0 +1,15 @@
+/* Tests for labels before declarations and at ends of compound statements.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+int f(int x) 
+{ 
+	goto b;
+	a: int i = 2 * x;	/* { dg-error "a label can only be part of a statement and a declaration is not a statement" } */
+           goto c;
+	b: goto a;
+	{ i *= 3; c: }		/* { dg-error "label at end of compound statement" } */
+	return i;
+        d:			/* { dg-error "label at end of compound statement" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c b/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
index 1f883d825e0..2f0d9f60cc0 100644
--- a/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
+++ b/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
@@ -25,13 +25,14 @@ f2 (void)
 }
 
 /* Declarations, including attribute declarations, cannot appear after
-   labels.  */
+   labels when a statement is expected.  */
 
 void
 f3 (void)
 {
- x: [[]];; /* { dg-error "can only be part of a statement" } */
-}
+  if (1)
+    x: [[]]; /* { dg-error "expected" } */
+} 
 
 /* Prefix attributes cannot appear on type names.  */
 
diff --git a/gcc/testsuite/gcc.dg/c2x-labels-1.c b/gcc/testsuite/gcc.dg/c2x-labels-1.c
new file mode 100644
index 00000000000..439cf7834ee
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-labels-1.c
@@ -0,0 +1,23 @@
+/* Tests for labels before declarations and at ends of compound statements.  */
+/* { dg-do run } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+int f(int x) 
+{ 
+	goto b;
+	a: int i = 2 * x;
+	aa: int u = 0; int v = 0;
+           goto c;
+	b: goto a;
+	{ i *= 3; c: }
+	return i + u + v;
+        d:
+}
+
+int main(void)
+{
+	if (2 != f(1))
+		__builtin_abort();
+
+	return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-labels-2.c b/gcc/testsuite/gcc.dg/c2x-labels-2.c
new file mode 100644
index 00000000000..bd010e9ecfb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-labels-2.c
@@ -0,0 +1,15 @@
+/* Tests for labels before declarations and at ends of compound statements.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wc11-c2x-compat" } */
+
+int f(int x) 
+{ 
+	goto b;
+	a: int i = 2 * x;	/* { dg-warning "a label can only be part of a statement and a declaration is not a statement" } */
+           goto c;
+	b: goto a;
+	{ i *= 3; c: }		/* { dg-warning "label at end of compound statement" } */
+	return i;
+        d:			/* { dg-warning "label at end of compound statement" } */
+}
+
diff --git a/gcc/testsuite/gcc.dg/c2x-labels-3.c b/gcc/testsuite/gcc.dg/c2x-labels-3.c
new file mode 100644
index 00000000000..159116db186
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-labels-3.c
@@ -0,0 +1,38 @@
+/* Tests for labels before declarations and at ends of compound statements
+ * in combination with attributes. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -Wall" } */
+
+int f(void) 
+{ 
+	goto b;
+	a: int i = 0;
+	aa: __attribute__((unused)) int u = 0; int v = 0;	/* { dg-warning "GNU-style attribute between label and declaration appertains to the label" } */
+           goto c;
+	{ c: }
+	b: goto a;
+	return i + u + v;
+        d: __attribute__((unused)) (void)0;
+        e: __attribute__((unused))
+}
+
+int g(void) 
+{ 
+	goto b;
+	a: int i = 0;
+	[[maybe_unused]] aa: int u = 0; int v = 0;
+           goto c;
+	{ c: }
+	b: goto a;
+	return i + u + v;
+        [[maybe_unused]] d: (void)0;
+        [[maybe_unused]] e:
+}
+
+void h(void)
+{
+	[[maybe_unused]] a: [[maybe_unused]] b: [[maybe_unused]] int x;
+
+	if (1)
+		[[maybe_unused]] c: [[maybe_unused]] d: (void)0;
+}
diff --git a/gcc/testsuite/gcc.dg/decl-9.c b/gcc/testsuite/gcc.dg/decl-9.c
index eeca8e05e14..9bb15609d83 100644
--- a/gcc/testsuite/gcc.dg/decl-9.c
+++ b/gcc/testsuite/gcc.dg/decl-9.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-std=gnu89" } */
+/* { dg-options "-std=gnu89 -pedantic-errors" } */
 
 w *x; /* { dg-error "unknown type name 'w'" } */
 
@@ -12,6 +12,7 @@ int f1()
   int d, e;
   d * e; /* { dg-bogus "unknown type name 'd'" } */
   g * h; /* { dg-error "unknown type name 'g'" } */
+  /* { dg-error "mixed declarations" "" { target *-*-* } .-1 } */
   g i;   /* { dg-error "unknown type name 'g'" } */
 }
 
diff --git a/gcc/testsuite/gcc.dg/gomp/barrier-2.c b/gcc/testsuite/gcc.dg/gomp/barrier-2.c
index 5a7091946c4..c0d62f572bb 100644
--- a/gcc/testsuite/gcc.dg/gomp/barrier-2.c
+++ b/gcc/testsuite/gcc.dg/gomp/barrier-2.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-options "-Wall -std=c17 -fopenmp -pedantic-errors" } */
 
 void f1(void)
 {
@@ -16,6 +17,7 @@ void f1(void)
 void f2(void)
 {
   label:       /* { dg-error "label at end of compound statement" } */
+    /* { dg-warning "defined but not used" "" { target *-*-* } .-1 } */
     #pragma omp barrier		/* { dg-error "may only be used in compound statements" } */
 }
 
diff --git a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
index fe236525d62..b9a4161c0c9 100644
--- a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
+++ b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
@@ -1,5 +1,6 @@
 /* Test parsing of #pragma omp declare simd */
 /* { dg-do compile } */
+/* { dg-options "-std=c17 -fopenmp -pedantic-errors" } */
 
 int
 f1 (int x)
@@ -14,7 +15,7 @@ f1 (int x)
 lab:
     #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int))
     extern int f5 (int a, int *b, int c);	/* { dg-error "must be followed by function declaration or definition" } */
-    x++;					/* { dg-error "expected expression before" "" { target *-*-* } .-1 } */
+    x++;					/* { dg-error "a label can only be part of a statement and a declaration is not a statement" "" { target *-*-* } .-1 } */
   }
   return x;
 }
diff --git a/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c b/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c
index 701d83b0ec3..39c2c1d40ee 100644
--- a/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c
+++ b/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c
@@ -1,5 +1,6 @@
 /* Test parsing of #pragma omp declare variant */
 /* { dg-do compile } */
+/* { dg-options "-std=c17 -fopenmp -pedantic-errors" } */
 
 int f0 (int, int *, int);
 
@@ -16,7 +17,7 @@ f1 (int x)
 lab:
     #pragma omp declare variant (fn0) match (user={condition(0)})
     extern int f5 (int a, int *b, int c);	/* { dg-error "must be followed by function declaration or definition" } */
-    x++;					/* { dg-error "expected expression before" "" { target *-*-* } .-1 } */
+    x++;					/* { dg-error "a label can only be part of a statement and a declaration is not a statement" "" { target *-*-* } .-1 } */
   }
   return x;
 }
diff --git a/gcc/testsuite/gcc.dg/label-compound-stmt-1.c b/gcc/testsuite/gcc.dg/label-compound-stmt-1.c
index 2f8fa4e65c2..2ae2b82ef1c 100644
--- a/gcc/testsuite/gcc.dg/label-compound-stmt-1.c
+++ b/gcc/testsuite/gcc.dg/label-compound-stmt-1.c
@@ -1,7 +1,7 @@
 /* Test that labels at ends of compound statements are hard errors.  */
 /* Origin: Joseph Myers <jsm@polyomino.org.uk> */
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-std=c17 -pedantic-errors" } */
 
 void f(void) { g: } /* { dg-bogus "warning" "warning in place of error" } */
 /* { dg-error "label|parse|syntax" "label at end of compound statement" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/parse-decl-after-label.c b/gcc/testsuite/gcc.dg/parse-decl-after-label.c
index 9c9886a108f..6e2a047eb2e 100644
--- a/gcc/testsuite/gcc.dg/parse-decl-after-label.c
+++ b/gcc/testsuite/gcc.dg/parse-decl-after-label.c
@@ -1,6 +1,6 @@
 /* PR 29062 
 { dg-do compile }
-{ dg-options "-fsyntax-only" }
+{ dg-options "-std=c17 -pedantic-errors -fsyntax-only" }
 */
 
 int f(int x)
Joseph Myers Nov. 6, 2020, 10:44 p.m. UTC | #7
On Fri, 6 Nov 2020, Uecker, Martin wrote:

> Am Freitag, den 06.11.2020, 22:07 +0000 schrieb Joseph Myers:
> > On Fri, 6 Nov 2020, Uecker, Martin wrote:
> > 
> > > Hi Joseph,
> > > 
> > > here is the revised patch. I remove the 'fallthrough'
> > > code as suggested, so everything becomes even simpler.
> > > Some tests had to be changed then, but it seems Ok to
> > > me.
> > 
> > This patch is missing the new tests.
> > 
> > > +	* gcc.dg/c11-labels-1.c: New test.
> > > +	* gcc.dg/c11-labels-2.c: New test.
> > > +	* gcc.dg/c11-labels-3.c: New test.
> > > +	* gcc.dg/c2x-labels-1.c: New test.
> > > +	* gcc.dg/c2x-labels-2.c: New test.
> > > +	* gcc.dg/c2x-labels-3.c: New test.
> 
> My bad. Here there are.

Thanks.  This version is OK (note that ChangeLog entries now need to be 
included in the commit message, not as changes to the ChangeLog files, and 
the nightly cron job will update the ChangeLog files).
diff mbox series

Patch

diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index a8bc301ffad..dc7b2e6b555 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -5836,7 +5836,7 @@  c_parser_compound_statement_nostart (c_parser *parser)
       parser->error = false;
     }
   if (last_label)
-    error_at (label_loc, "label at end of compound statement");
+    pedwarn_c11 (label_loc, OPT_Wpedantic, "label at end of compound statement");
   location_t endloc = c_parser_peek_token (parser)->location;
   c_parser_consume_token (parser);
   /* Restore the value we started with.  */
@@ -5984,7 +5984,7 @@  c_parser_label (c_parser *parser)
 	  || (have_std_attrs
 	      && c_parser_next_token_is (parser, CPP_SEMICOLON)))
 	{
-	  error_at (c_parser_peek_token (parser)->location,
+	  pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic,
 		    "a label can only be part of a statement and "
 		    "a declaration is not a statement");
 	  c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 3b37aba5795..b0c54b6042d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -55,7 +55,7 @@  extensions, accepted by GCC in C90 mode and in C++.
 * Designated Inits::    Labeling elements of initializers.
 * Case Ranges::         `case 1 ... 9' and such.
 * Cast to Union::       Casting to union type from any member of the union.
-* Mixed Declarations::  Mixing declarations and code.
+* Mixed Labels and Declarations::  Mixing declarations, labels and code.
 * Function Attributes:: Declaring that functions have no side effects,
                         or that they can never return.
 * Variable Attributes:: Specifying attributes of variables.
@@ -2353,15 +2353,17 @@  void hack (union foo);
 hack ((union foo) x);
 @end smallexample
 
-@node Mixed Declarations
-@section Mixed Declarations and Code
+@node Mixed Labels and Declarations
+@section Mixed Declarations, Labels and Code
 @cindex mixed declarations and code
 @cindex declarations, mixed with code
 @cindex code, mixed with declarations
 
 ISO C99 and ISO C++ allow declarations and code to be freely mixed
-within compound statements.  As an extension, GNU C also allows this in
-C90 mode.  For example, you could do:
+within compound statements.  ISO C2X allows labels to be
+placed before declarations and at the end of a compound statement.
+As an extension, GNU C also allows all this in C90 mode.  For example,
+you could do:
 
 @smallexample
 int i;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5d29a7fa23c..97c594eacce 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -7442,7 +7442,7 @@  except when the same as the default promotion.
 @opindex Wno-declaration-after-statement
 Warn when a declaration is found after a statement in a block.  This
 construct, known from C++, was introduced with ISO C99 and is by default
-allowed in GCC@.  It is not supported by ISO C90.  @xref{Mixed Declarations}.
+allowed in GCC@.  It is not supported by ISO C90.  @xref{Mixed Labels and Declarations}.
 
 @item -Wshadow
 @opindex Wshadow
diff --git a/gcc/testsuite/gcc.dg/20031223-1.c b/gcc/testsuite/gcc.dg/20031223-1.c
index 68aa74ffe50..2744dc69454 100644
--- a/gcc/testsuite/gcc.dg/20031223-1.c
+++ b/gcc/testsuite/gcc.dg/20031223-1.c
@@ -3,11 +3,11 @@ 
    because GCC was trying to expand the trees to rtl.  */
 
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-std=c17 -pedantic-errors" } */
 
 void f ()
 {
  l: int; /* { dg-error "a label can only be part of a statement and a declaration is not a
statement" "not stmt" } */
- /* { dg-warning "useless type name in empty declaration" "type name" { target *-*-* } .-1 } */
+ /* { dg-error "useless type name in empty declaration" "type name" { target *-*-* } .-1 } */
  /* { dg-error "label at end of compound statement" "label" { target *-*-* } .-2 } */
 }
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c b/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
index 1f883d825e0..8ae33d9d01a 100644
--- a/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
+++ b/gcc/testsuite/gcc.dg/c2x-attr-syntax-3.c
@@ -30,8 +30,9 @@  f2 (void)
 void
 f3 (void)
 {
- x: [[]];; /* { dg-error "can only be part of a statement" } */
-}
+  if (1)
+    x: [[]];
+} /* { dg-error "expected" } */
 
 /* Prefix attributes cannot appear on type names.  */
 
diff --git a/gcc/testsuite/gcc.dg/c2x-labels-1.c b/gcc/testsuite/gcc.dg/c2x-labels-1.c
new file mode 100644
index 00000000000..5a7b7b97a01
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-labels-1.c
@@ -0,0 +1,22 @@ 
+/* Tests for labels before declarations and at ends of compound statements.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x" } */
+
+int f(int x) 
+{ 
+	goto b;
+	a: int i = 2 * x;
+           goto c;
+	b: goto a;
+	{ i *= 3; c: }
+	return i;
+        d:
+}
+
+int main(void)
+{
+	if (2 != f(1))
+		__builtin_abort();
+
+	return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/decl-9.c b/gcc/testsuite/gcc.dg/decl-9.c
index eeca8e05e14..9bb15609d83 100644
--- a/gcc/testsuite/gcc.dg/decl-9.c
+++ b/gcc/testsuite/gcc.dg/decl-9.c
@@ -1,5 +1,5 @@ 
 /* { dg-do compile } */
-/* { dg-options "-std=gnu89" } */
+/* { dg-options "-std=gnu89 -pedantic-errors" } */
 
 w *x; /* { dg-error "unknown type name 'w'" } */
 
@@ -12,6 +12,7 @@  int f1()
   int d, e;
   d * e; /* { dg-bogus "unknown type name 'd'" } */
   g * h; /* { dg-error "unknown type name 'g'" } */
+  /* { dg-error "mixed declarations" "" { target *-*-* } .-1 } */
   g i;   /* { dg-error "unknown type name 'g'" } */
 }
 
diff --git a/gcc/testsuite/gcc.dg/gomp/barrier-2.c b/gcc/testsuite/gcc.dg/gomp/barrier-2.c
index 5a7091946c4..98e16b2e051 100644
--- a/gcc/testsuite/gcc.dg/gomp/barrier-2.c
+++ b/gcc/testsuite/gcc.dg/gomp/barrier-2.c
@@ -1,4 +1,5 @@ 
 /* { dg-do compile } */
+/* { dg-options "-Wall -std=c17 -fopenmp -pedantic-errors" } */
 
 void f1(void)
 {
@@ -16,6 +17,7 @@  void f1(void)
 void f2(void)
 {
   label:       /* { dg-error "label at end of compound statement" } */
+    /* { dg-error "defined but not used" "" { target *-*-* } .-1 } */
     #pragma omp barrier		/* { dg-error "may only be used in compound statements" } */
 }
 
diff --git a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
index fe236525d62..51bd5f25bb0 100644
--- a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
+++ b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c
@@ -1,5 +1,6 @@ 
 /* Test parsing of #pragma omp declare simd */
 /* { dg-do compile } */
+/* { dg-options "-std=c17 -fopenmp -pedantic-errors" } */
 
 int
 f1 (int x)
diff --git a/gcc/testsuite/gcc.dg/label-compound-stmt-1.c b/gcc/testsuite/gcc.dg/label-compound-
stmt-1.c
index 2f8fa4e65c2..2ae2b82ef1c 100644
--- a/gcc/testsuite/gcc.dg/label-compound-stmt-1.c
+++ b/gcc/testsuite/gcc.dg/label-compound-stmt-1.c
@@ -1,7 +1,7 @@ 
 /* Test that labels at ends of compound statements are hard errors.  */
 /* Origin: Joseph Myers <jsm@polyomino.org.uk> */
 /* { dg-do compile } */
-/* { dg-options "" } */
+/* { dg-options "-std=c17 -pedantic-errors" } */
 
 void f(void) { g: } /* { dg-bogus "warning" "warning in place of error" } */
 /* { dg-error "label|parse|syntax" "label at end of compound statement" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/parse-decl-after-label.c b/gcc/testsuite/gcc.dg/parse-decl-after-
label.c
index 9c9886a108f..6e2a047eb2e 100644
--- a/gcc/testsuite/gcc.dg/parse-decl-after-label.c
+++ b/gcc/testsuite/gcc.dg/parse-decl-after-label.c
@@ -1,6 +1,6 @@ 
 /* PR 29062 
 { dg-do compile }
-{ dg-options "-fsyntax-only" }
+{ dg-options "-std=c17 -pedantic-errors -fsyntax-only" }
 */
 
 int f(int x)