Skip to content

Commit

Permalink
c: Implement C2y N3356, if declarations [PR117019]
Browse files Browse the repository at this point in the history
This patch implements C2y N3356, if declarations as described at
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3356.htm>.

This feature is cognate with C++17 Selection statements with initializer
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r1.html>,
but they are not the same yet.  For example, C++17 allows

  if (lock (); int i = getval ())

whereas C2y does not.

The proposal adds new grammar productions.  selection-header is handled
in c_parser_selection_header which is the gist of the patch.
simple-declaration is handled by c_parser_declaration_or_fndef, which
gets a new parameter.

	PR c/117019

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_declaration_or_fndef): Adjust declaration.
	(c_parser_external_declaration): Adjust a call to
	c_parser_declaration_or_fndef.
	(c_parser_declaration_or_fndef): New bool parameter.  Return a tree
	instead of void.  Adjust for N3356.  Adjust a call to
	c_parser_declaration_or_fndef.
	(c_parser_compound_statement_nostart): Adjust calls to
	c_parser_declaration_or_fndef.
	(c_parser_selection_header): New.
	(c_parser_paren_selection_header): New.
	(c_parser_if_statement): Call c_parser_paren_selection_header
	instead of c_parser_paren_condition.
	(c_parser_switch_statement): Call c_parser_selection_header instead of
	c_parser_expression.
	(c_parser_for_statement): Adjust calls to c_parser_declaration_or_fndef.
	(c_parser_objc_methodprotolist): Likewise.
	(c_parser_oacc_routine): Likewise.
	(c_parser_omp_loop_nest): Likewise.
	(c_parser_omp_declare_simd): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.dg/c23-if-decls-1.c: New test.
	* gcc.dg/c23-if-decls-2.c: New test.
	* gcc.dg/c2y-if-decls-1.c: New test.
	* gcc.dg/c2y-if-decls-2.c: New test.
	* gcc.dg/c2y-if-decls-3.c: New test.
	* gcc.dg/c2y-if-decls-4.c: New test.
	* gcc.dg/c2y-if-decls-5.c: New test.
	* gcc.dg/c2y-if-decls-6.c: New test.
	* gcc.dg/c2y-if-decls-7.c: New test.
	* gcc.dg/c2y-if-decls-8.c: New test.
	* gcc.dg/c2y-if-decls-9.c: New test.
	* gcc.dg/c2y-if-decls-10.c: New test.
	* gcc.dg/c2y-if-decls-11.c: New test.
	* gcc.dg/gnu2y-if-decls-1.c: New test.
	* gcc.dg/gnu99-if-decls-1.c: New test.
	* gcc.dg/gnu99-if-decls-2.c: New test.
  • Loading branch information
mpolacek committed Nov 8, 2024
1 parent 7175fec commit 440be01
Show file tree
Hide file tree
Showing 17 changed files with 1,302 additions and 56 deletions.
253 changes: 197 additions & 56 deletions gcc/c/c-parser.cc

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions gcc/testsuite/gcc.dg/c23-if-decls-1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* N3356 - if declarations. */
/* PR c/117019 */
/* { dg-do compile } */
/* { dg-options "-std=c23 -pedantic-errors" } */

void
g ()
{
if (int i = 42); /* { dg-error "ISO C does not support if declarations before C2Y" } */
if (int i = 42; i > 10); /* { dg-error "ISO C does not support if declarations before C2Y" } */
if (int i, j; i = 42); /* { dg-error "ISO C does not support if declarations before C2Y" } */
switch (int i = 42); /* { dg-error "ISO C does not support if declarations before C2Y" } */
switch (int i = 42; i); /* { dg-error "ISO C does not support if declarations before C2Y" } */
switch (int i, j; i = 42); /* { dg-error "ISO C does not support if declarations before C2Y" } */
}
6 changes: 6 additions & 0 deletions gcc/testsuite/gcc.dg/c23-if-decls-2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* N3356 - if declarations. */
/* PR c/117019 */
/* { dg-do compile } */
/* { dg-options "-std=c23 -pedantic-errors -Wno-c23-c2y-compat" } */

#include "c23-if-decls-1.c"
168 changes: 168 additions & 0 deletions gcc/testsuite/gcc.dg/c2y-if-decls-1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/* N3356 - if declarations. */
/* PR c/117019 */
/* { dg-do run } */
/* { dg-options "-std=c2y -Wc23-c2y-compat" } */
/* Test C2Y if declarations. Valid usages. */

int get () { return 42; }
int foo (int i) { return i; }

enum E { X = 1, Y };

void
simple ()
{
if (int i = get ()) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (int i = 0) /* { dg-warning "if declarations before C2Y" } */
__builtin_abort ();
else
foo (i);

if (auto i = get ()) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (__typeof__(get ()) i = get ()) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (auto i = 0) /* { dg-warning "if declarations before C2Y" } */
__builtin_abort ();
else
foo (i);

if (int (*f)(int) = foo) /* { dg-warning "if declarations before C2Y" } */
f (1);
else
__builtin_abort ();

if ([[maybe_unused]] int i = get ()) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (__attribute__((unused)) int i = get ()) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (enum E e = X) /* { dg-warning "if declarations before C2Y" } */
foo (e);
else
__builtin_abort ();

if (constexpr int i = 42) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (int i = 1) /* { dg-warning "if declarations before C2Y" } */
if (int j = 2) /* { dg-warning "if declarations before C2Y" } */
if (int k = 3) /* { dg-warning "if declarations before C2Y" } */
foo (i + j + k);

if (register int i = 0); /* { dg-warning "if declarations before C2Y" } */
if (static int i = 0); /* { dg-warning "if declarations before C2Y" } */
if (static int arr[3] = {}); /* { dg-warning "if declarations before C2Y" } */
if (_Atomic int i = 0); /* { dg-warning "if declarations before C2Y" } */

if (int arr[] = { 1 }) /* { dg-warning "if declarations before C2Y" } */
foo (arr[0]);
else
__builtin_abort ();

double i;
}

void
expr ()
{
if (int i = get (); i == 42) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (int i = get (); i != 42) /* { dg-warning "if declarations before C2Y" } */
__builtin_abort ();
else
foo (i);

if (auto i = get (); i == 42) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (__typeof__(get ()) i = get (); i == 42) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (auto i = get (); i != 42) /* { dg-warning "if declarations before C2Y" } */
__builtin_abort ();
else
foo (i);

if (int (*f)(int) = foo; f (42)) /* { dg-warning "if declarations before C2Y" } */
f (1);
else
__builtin_abort ();

if ([[maybe_unused]] int i = get (); i == 42) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (__attribute__((unused)) int i = get (); i == 42) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (enum E e = X; e == X) /* { dg-warning "if declarations before C2Y" } */
foo (e);
else
__builtin_abort ();

if (constexpr int i = 42; i == 42) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (int i = 1; i) /* { dg-warning "if declarations before C2Y" } */
if (int j = 2; j) /* { dg-warning "if declarations before C2Y" } */
if (int k = 3; k) /* { dg-warning "if declarations before C2Y" } */
foo (i + j + k);

if (int i = 2, j = get (); i + j > 0) /* { dg-warning "if declarations before C2Y" } */
foo (i + j);
else
__builtin_abort ();

if (int i; i = 1) /* { dg-warning "if declarations before C2Y" } */
foo (i);
else
__builtin_abort ();

if (int arr[] = { 1, 2, 3}; arr[0]) /* { dg-warning "if declarations before C2Y" } */
foo (arr[0]);
else
__builtin_abort ();

if (register int i = 0; i); /* { dg-warning "if declarations before C2Y" } */
if (static int i = 0; i); /* { dg-warning "if declarations before C2Y" } */
if (_Atomic int i = 0; i); /* { dg-warning "if declarations before C2Y" } */

double i;
}

int
main ()
{
simple ();
expr ();
}
38 changes: 38 additions & 0 deletions gcc/testsuite/gcc.dg/c2y-if-decls-10.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* N3356 - if declarations. */
/* PR c/117019 */
/* { dg-do compile } */
/* { dg-options "-std=c2y -pedantic-errors" } */
/* Test C2Y if declarations. Invalid usages. */

void
g (int g)
{
switch (;); /* { dg-error "expected" } */
switch (int); /* { dg-error "expected identifier" } */
/* { dg-error "declaration" "" { target *-*-* } .-1 } */
switch (auto); /* { dg-error "expected identifier" } */
/* { dg-error "declaration" "" { target *-*-* } .-1 } */
switch (int;); /* { dg-error "declaration" } */
switch (auto;); /* { dg-error "empty|initializer" } */
switch (int i); /* { dg-error "initializer" } */
switch (int i;); /* { dg-error "expected" } */
switch (int i = 0;); /* { dg-error "expected" } */

switch (extern int i = 0); /* { dg-error "both .extern. and initializer" } */
switch (extern int i); /* { dg-error "initializer" } */
switch (thread_local int i = 0); /* { dg-error "function-scope" } */
switch (typedef int i); /* { dg-error "initializer" } */
switch (typedef int i = 0); /* { dg-error "initialized" } */

switch (int i = 2, j = 3); /* { dg-error "only declare a single object" } */

switch (void (*fp)(int)); /* { dg-error "initializer" } */
switch ([[maybe_unused]] g); /* { dg-error "expected" } */
switch ([[maybe_unused]] 42); /* { dg-error "expected" } */
switch ([[maybe_unused]] int); /* { dg-error "expected|initializer" } */
switch (__attribute__((unused)) g); /* { dg-error "initializer" } */
switch (__attribute__((unused)) 42); /* { dg-error "expected|initializer" } */
switch (__attribute__((unused)) int); /* { dg-error "expected|initializer" } */

switch (int arr[] = { 1 }); /* { dg-error "switch quantity not an integer" } */
}
Loading

0 comments on commit 440be01

Please sign in to comment.