public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: Implement C++23 P2334R1 - #elifdef/#elifndef
@ 2021-10-05  8:35 Jakub Jelinek
  2021-10-05 15:24 ` Marek Polacek
  2021-10-05 17:23 ` Joseph Myers
  0 siblings, 2 replies; 5+ messages in thread
From: Jakub Jelinek @ 2021-10-05  8:35 UTC (permalink / raw)
  To: Jason Merrill, Joseph S. Myers, Marek Polacek; +Cc: gcc-patches

Hi!

This patch implements C++23 P2334R1, which is easy because Joseph has done
all the hard work for C2X already.
Unlike the C N2645 paper, the C++ P2334R1 contains one important addition
(but not in the normative text):
"While this is a new preprocessor feature and cannot be treated as a defect
report, implementations that support older versions of the standard are
encouraged to implement this feature in the older language modes as well
as C++23."
so there are different variants how to implement it.
One is in the patch below, ignores that sentence and only implements it
for -std=c++23/-std=gnu++23 like it is only implemented for -std=c23.
Another option would be to implement it also in the older GNU modes but
not in the C/CXX modes (but it would be strange if we did that just for
C++ and not for C).
Yet another option is to enable it unconditionally.
And yet another option would be to enable it unconditionally but emit
a warning (or pedwarn) when it is seen.
Note, when it is enabled for the older language modes, as Joseph wrote
in the c11-elifdef-1.c testcase, it can result e.g. in rejecting previously
valid code:
#define A
#undef B
#if 0
#elifdef A
#error "#elifdef A applied"
#endif
#if 0
#elifndef B
#error "#elifndef B applied"
#endif
Note, seems clang went the enable it unconditionally in all standard
versions of both C and C++, no warnings or anything whatsoever, so
essentially treated it as a DR that changed behavior of e.g. the above code.

2021-10-05  Jakub Jelinek  <jakub@redhat.com>

libcpp/
	* init.c (lang_defaults): Implement P2334R1, enable elifdef for
	-std=c++23 and -std=gnu++23.
gcc/testsuite/
	* g++.dg/cpp/elifdef-1.C: New test.
	* g++.dg/cpp/elifdef-2.C: New test.
	* g++.dg/cpp/elifdef-3.C: New test.

--- libcpp/init.c.jj	2021-09-02 10:01:15.954715595 +0200
+++ libcpp/init.c	2021-10-05 09:55:15.010620700 +0200
@@ -122,8 +122,8 @@ static const struct lang_flags lang_defa
   /* CXX17    */  { 1,  1,  1,  1,  1,  0,    1,  1,   1,   1,   1,    1,     1,     0,   1,      0,   1,     0,   0,   0 },
   /* GNUCXX20 */  { 1,  1,  1,  1,  1,  0,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   0,   0 },
   /* CXX20    */  { 1,  1,  1,  1,  1,  0,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   0,   0 },
-  /* GNUCXX23 */  { 1,  1,  1,  1,  1,  1,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   0 },
-  /* CXX23    */  { 1,  1,  1,  1,  1,  1,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   0 },
+  /* GNUCXX23 */  { 1,  1,  1,  1,  1,  1,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   1 },
+  /* CXX23    */  { 1,  1,  1,  1,  1,  1,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   1 },
   /* ASM      */  { 0,  0,  1,  0,  0,  0,    0,  0,   0,   0,   0,    0,     0,     0,   0,      0,   0,     0,   0,   0 }
 };
 
--- gcc/testsuite/g++.dg/cpp/elifdef-1.C.jj	2021-10-05 10:00:41.410057024 +0200
+++ gcc/testsuite/g++.dg/cpp/elifdef-1.C	2021-10-05 10:00:33.110173069 +0200
@@ -0,0 +1,3 @@
+// { dg-do preprocess { target { ! c++23 } } }
+
+#include "../../gcc.dg/cpp/c11-elifdef-1.c"
--- gcc/testsuite/g++.dg/cpp/elifdef-2.C.jj	2021-10-05 10:01:30.345372808 +0200
+++ gcc/testsuite/g++.dg/cpp/elifdef-2.C	2021-10-05 10:03:36.560608083 +0200
@@ -0,0 +1,4 @@
+// P2334R1
+// { dg-do preprocess { target c++23 } }
+
+#include "../../gcc.dg/cpp/c2x-elifdef-1.c"
--- gcc/testsuite/g++.dg/cpp/elifdef-3.C.jj	2021-10-05 10:01:36.029293338 +0200
+++ gcc/testsuite/g++.dg/cpp/elifdef-3.C	2021-10-05 10:03:48.896435601 +0200
@@ -0,0 +1,4 @@
+// P2334R1
+// { dg-do preprocess { target c++23 } }
+
+#include "../../gcc.dg/cpp/c2x-elifdef-1.c"

	Jakub


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] c++: Implement C++23 P2334R1 - #elifdef/#elifndef
  2021-10-05  8:35 [PATCH] c++: Implement C++23 P2334R1 - #elifdef/#elifndef Jakub Jelinek
@ 2021-10-05 15:24 ` Marek Polacek
  2021-10-05 17:23 ` Joseph Myers
  1 sibling, 0 replies; 5+ messages in thread
From: Marek Polacek @ 2021-10-05 15:24 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Joseph S. Myers, gcc-patches

On Tue, Oct 05, 2021 at 10:35:12AM +0200, Jakub Jelinek wrote:
> Hi!
> 
> This patch implements C++23 P2334R1, which is easy because Joseph has done
> all the hard work for C2X already.
> Unlike the C N2645 paper, the C++ P2334R1 contains one important addition
> (but not in the normative text):
> "While this is a new preprocessor feature and cannot be treated as a defect
> report, implementations that support older versions of the standard are
> encouraged to implement this feature in the older language modes as well
> as C++23."
> so there are different variants how to implement it.
> One is in the patch below, ignores that sentence and only implements it
> for -std=c++23/-std=gnu++23 like it is only implemented for -std=c23.
> Another option would be to implement it also in the older GNU modes but
> not in the C/CXX modes (but it would be strange if we did that just for
> C++ and not for C).
> Yet another option is to enable it unconditionally.

This would work for me, but...

> And yet another option would be to enable it unconditionally but emit
> a warning (or pedwarn) when it is seen.

...frankly, I'd prefer this last option: enable it unconditionally but emit
a pedwarn when -Wpedantic.  I think let's see what Joseph and Jason think
before you change your patch though; don't want to add more work for you.

> Note, when it is enabled for the older language modes, as Joseph wrote
> in the c11-elifdef-1.c testcase, it can result e.g. in rejecting previously
> valid code:
> #define A
> #undef B
> #if 0
> #elifdef A
> #error "#elifdef A applied"
> #endif
> #if 0
> #elifndef B
> #error "#elifndef B applied"
> #endif
> Note, seems clang went the enable it unconditionally in all standard
> versions of both C and C++, no warnings or anything whatsoever, so
> essentially treated it as a DR that changed behavior of e.g. the above code.
> 
> 2021-10-05  Jakub Jelinek  <jakub@redhat.com>
> 
> libcpp/
> 	* init.c (lang_defaults): Implement P2334R1, enable elifdef for
> 	-std=c++23 and -std=gnu++23.
> gcc/testsuite/
> 	* g++.dg/cpp/elifdef-1.C: New test.
> 	* g++.dg/cpp/elifdef-2.C: New test.
> 	* g++.dg/cpp/elifdef-3.C: New test.
> 
> --- libcpp/init.c.jj	2021-09-02 10:01:15.954715595 +0200
> +++ libcpp/init.c	2021-10-05 09:55:15.010620700 +0200
> @@ -122,8 +122,8 @@ static const struct lang_flags lang_defa
>    /* CXX17    */  { 1,  1,  1,  1,  1,  0,    1,  1,   1,   1,   1,    1,     1,     0,   1,      0,   1,     0,   0,   0 },
>    /* GNUCXX20 */  { 1,  1,  1,  1,  1,  0,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   0,   0 },
>    /* CXX20    */  { 1,  1,  1,  1,  1,  0,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   0,   0 },
> -  /* GNUCXX23 */  { 1,  1,  1,  1,  1,  1,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   0 },
> -  /* CXX23    */  { 1,  1,  1,  1,  1,  1,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   0 },
> +  /* GNUCXX23 */  { 1,  1,  1,  1,  1,  1,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   1 },
> +  /* CXX23    */  { 1,  1,  1,  1,  1,  1,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   1 },
>    /* ASM      */  { 0,  0,  1,  0,  0,  0,    0,  0,   0,   0,   0,    0,     0,     0,   0,      0,   0,     0,   0,   0 }
>  };
>  
> --- gcc/testsuite/g++.dg/cpp/elifdef-1.C.jj	2021-10-05 10:00:41.410057024 +0200
> +++ gcc/testsuite/g++.dg/cpp/elifdef-1.C	2021-10-05 10:00:33.110173069 +0200
> @@ -0,0 +1,3 @@
> +// { dg-do preprocess { target { ! c++23 } } }
> +
> +#include "../../gcc.dg/cpp/c11-elifdef-1.c"
> --- gcc/testsuite/g++.dg/cpp/elifdef-2.C.jj	2021-10-05 10:01:30.345372808 +0200
> +++ gcc/testsuite/g++.dg/cpp/elifdef-2.C	2021-10-05 10:03:36.560608083 +0200
> @@ -0,0 +1,4 @@
> +// P2334R1
> +// { dg-do preprocess { target c++23 } }
> +
> +#include "../../gcc.dg/cpp/c2x-elifdef-1.c"
> --- gcc/testsuite/g++.dg/cpp/elifdef-3.C.jj	2021-10-05 10:01:36.029293338 +0200
> +++ gcc/testsuite/g++.dg/cpp/elifdef-3.C	2021-10-05 10:03:48.896435601 +0200
> @@ -0,0 +1,4 @@
> +// P2334R1
> +// { dg-do preprocess { target c++23 } }
> +
> +#include "../../gcc.dg/cpp/c2x-elifdef-1.c"
> 
> 	Jakub
> 

Marek


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] c++: Implement C++23 P2334R1 - #elifdef/#elifndef
  2021-10-05  8:35 [PATCH] c++: Implement C++23 P2334R1 - #elifdef/#elifndef Jakub Jelinek
  2021-10-05 15:24 ` Marek Polacek
@ 2021-10-05 17:23 ` Joseph Myers
  2021-10-05 20:24   ` [PATCH, v2] " Jakub Jelinek
  1 sibling, 1 reply; 5+ messages in thread
From: Joseph Myers @ 2021-10-05 17:23 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Marek Polacek, gcc-patches

On Tue, 5 Oct 2021, Jakub Jelinek via Gcc-patches wrote:

> One is in the patch below, ignores that sentence and only implements it
> for -std=c++23/-std=gnu++23 like it is only implemented for -std=c23.
> Another option would be to implement it also in the older GNU modes but
> not in the C/CXX modes (but it would be strange if we did that just for
> C++ and not for C).
> Yet another option is to enable it unconditionally.
> And yet another option would be to enable it unconditionally but emit
> a warning (or pedwarn) when it is seen.
> Note, when it is enabled for the older language modes, as Joseph wrote
> in the c11-elifdef-1.c testcase, it can result e.g. in rejecting previously
> valid code:

It would probably be reasonable to enable it in older GNU modes for C as 
well as C++ if desired (and, in that case, emit a pedwarn-if-pedantic when 
it's acted on) - cases where it affects compatibility should be rare.  
Enabling with a pedwarn in strict modes is problematic because it changes 
semantics of valid code where it was inside #if 0, however.  It doesn't 
make sense at all to me to think of a new feature like this (one with no 
prior art in C mentioned in the WG14 proposal) as a defect fix.

Any normal directive - i.e. one that has no effect on the preprocessor #if 
structure and so is ignored inside #if 0 for all language versions - can 
more reasonably be enabled for all language versions with a pedwarn when 
used for old versions.  (In particular, that will be appropriate for 
#warning, where the "don't pedwarn in C2X modes" part needs implementing 
after N2686 was accepted at the August / September WG14 meeting - I don't 
know if C++ is doing anything with #warning.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH, v2] c++: Implement C++23 P2334R1 - #elifdef/#elifndef
  2021-10-05 17:23 ` Joseph Myers
@ 2021-10-05 20:24   ` Jakub Jelinek
  2021-10-06  3:02     ` Jason Merrill
  0 siblings, 1 reply; 5+ messages in thread
From: Jakub Jelinek @ 2021-10-05 20:24 UTC (permalink / raw)
  To: Jason Merrill, Joseph Myers; +Cc: Marek Polacek, gcc-patches

On Tue, Oct 05, 2021 at 05:23:26PM +0000, Joseph Myers wrote:
> > One is in the patch below, ignores that sentence and only implements it
> > for -std=c++23/-std=gnu++23 like it is only implemented for -std=c23.
> > Another option would be to implement it also in the older GNU modes but
> > not in the C/CXX modes (but it would be strange if we did that just for
> > C++ and not for C).
> > Yet another option is to enable it unconditionally.
> > And yet another option would be to enable it unconditionally but emit
> > a warning (or pedwarn) when it is seen.
> > Note, when it is enabled for the older language modes, as Joseph wrote
> > in the c11-elifdef-1.c testcase, it can result e.g. in rejecting previously
> > valid code:
> 
> It would probably be reasonable to enable it in older GNU modes for C as 
> well as C++ if desired (and, in that case, emit a pedwarn-if-pedantic when 
> it's acted on) - cases where it affects compatibility should be rare.  
> Enabling with a pedwarn in strict modes is problematic because it changes 
> semantics of valid code where it was inside #if 0, however.  It doesn't 
> make sense at all to me to think of a new feature like this (one with no 
> prior art in C mentioned in the WG14 proposal) as a defect fix.
> 
> Any normal directive - i.e. one that has no effect on the preprocessor #if 
> structure and so is ignored inside #if 0 for all language versions - can 
> more reasonably be enabled for all language versions with a pedwarn when 
> used for old versions.  (In particular, that will be appropriate for 
> #warning, where the "don't pedwarn in C2X modes" part needs implementing 
> after N2686 was accepted at the August / September WG14 meeting - I don't 
> know if C++ is doing anything with #warning.)

Ok, here is an updated version which accepts them in both
CPP_OPTION (pfile, elifdef) (aka -std={gnu,c}{2x,++2b,++23} modes) or
!CPP_OPTION (pfile, std) (aka -std=gnu* modes), but for the latter
pedwarns if pedantic (but only if the directive actually changes the
preprocessing behavior or if it would be rejected with corresponding
-std=c*).
The second hunk in directives.c is for the cases where it would otherwise
error about unknown directive, the third hunk is for the case where it
changes the skipping state.  If pfile->state.skipping is true before
encountering the directive and after it as well, then whether the directive
is there or not makes no difference.

2021-10-05  Jakub Jelinek  <jakub@redhat.com>

libcpp/
	* init.c (lang_defaults): Implement P2334R1, enable elifdef for
	-std=c++23 and -std=gnu++23.
	* directives.c (_cpp_handle_directive): Support elifdef/elifndef if
	either CPP_OPTION (pfile, elifdef) or !CPP_OPTION (pfile, std).
	(do_elif): For older non-std modes if pedantic pedwarn about
	#elifdef/#elifndef directives that change behavior.
gcc/testsuite/
	* gcc.dg/cpp/gnu11-elifdef-1.c: New test.
	* gcc.dg/cpp/gnu11-elifdef-2.c: New test.
	* gcc.dg/cpp/gnu11-elifdef-3.c: New test.
	* gcc.dg/cpp/gnu11-elifdef-4.c: New test.
	* g++.dg/cpp/elifdef-1.C: New test.
	* g++.dg/cpp/elifdef-2.C: New test.
	* g++.dg/cpp/elifdef-3.C: New test.
	* g++.dg/cpp/elifdef-4.C: New test.
	* g++.dg/cpp/elifdef-5.C: New test.
	* g++.dg/cpp/elifdef-6.C: New test.
	* g++.dg/cpp/elifdef-7.C: New test.

--- libcpp/init.c.jj	2021-09-02 10:01:15.954715595 +0200
+++ libcpp/init.c	2021-10-05 09:55:15.010620700 +0200
@@ -122,8 +122,8 @@ static const struct lang_flags lang_defa
   /* CXX17    */  { 1,  1,  1,  1,  1,  0,    1,  1,   1,   1,   1,    1,     1,     0,   1,      0,   1,     0,   0,   0 },
   /* GNUCXX20 */  { 1,  1,  1,  1,  1,  0,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   0,   0 },
   /* CXX20    */  { 1,  1,  1,  1,  1,  0,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   0,   0 },
-  /* GNUCXX23 */  { 1,  1,  1,  1,  1,  1,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   0 },
-  /* CXX23    */  { 1,  1,  1,  1,  1,  1,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   0 },
+  /* GNUCXX23 */  { 1,  1,  1,  1,  1,  1,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   1 },
+  /* CXX23    */  { 1,  1,  1,  1,  1,  1,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   1 },
   /* ASM      */  { 0,  0,  1,  0,  0,  0,    0,  0,   0,   0,   0,    0,     0,     0,   0,      0,   0,     0,   0,   0 }
 };
 
--- libcpp/directives.c.jj	2021-05-12 09:44:55.080621650 +0200
+++ libcpp/directives.c	2021-10-05 22:05:52.303984796 +0200
@@ -447,7 +447,11 @@ _cpp_handle_directive (cpp_reader *pfile
       if (dname->val.node.node->is_directive)
 	{
 	  dir = &dtable[dname->val.node.node->directive_index];
-	  if ((dir->flags & ELIFDEF) && !CPP_OPTION (pfile, elifdef))
+	  if ((dir->flags & ELIFDEF)
+	      && !CPP_OPTION (pfile, elifdef)
+	      /* For -std=gnu* modes elifdef is supported with
+		 a pedwarn if pedantic.  */
+	      && CPP_OPTION (pfile, std))
 	    dir = 0;
 	}
     }
@@ -2117,7 +2121,26 @@ do_elif (cpp_reader *pfile)
 	 are skipped and their controlling directives are processed as
 	 if they were in a group that is skipped."  */
       if (ifs->skip_elses)
-	pfile->state.skipping = 1;
+	{
+	  /* In older GNU standards, #elifdef/#elifndef is supported
+	     as an extension, but pedwarn if -pedantic if the presence
+	     of the directive would be rejected.  */
+	  if (pfile->directive != &dtable[T_ELIF]
+	      && ! CPP_OPTION (pfile, elifdef)
+	      && CPP_PEDANTIC (pfile)
+	      && !pfile->state.skipping)
+	    {
+	      if (CPP_OPTION (pfile, cplusplus))
+		cpp_error (pfile, CPP_DL_PEDWARN,
+			   "#%s before C++23 is a GCC extension",
+			   pfile->directive->name);
+	      else
+		cpp_error (pfile, CPP_DL_PEDWARN,
+			   "#%s before C2X is a GCC extension",
+			   pfile->directive->name);
+	    }
+	  pfile->state.skipping = 1;
+	}
       else
 	{
 	  if (pfile->directive == &dtable[T_ELIF])
@@ -2139,6 +2162,22 @@ do_elif (cpp_reader *pfile)
 		  if (pfile->cb.used)
 		    pfile->cb.used (pfile, pfile->directive_line, node);
 		  check_eol (pfile, false);
+		  /* In older GNU standards, #elifdef/#elifndef is supported
+		     as an extension, but pedwarn if -pedantic if the presence
+		     of the directive would change behavior.  */
+		  if (! CPP_OPTION (pfile, elifdef)
+		      && CPP_PEDANTIC (pfile)
+		      && pfile->state.skipping != skip)
+		    {
+		      if (CPP_OPTION (pfile, cplusplus))
+			cpp_error (pfile, CPP_DL_PEDWARN,
+				   "#%s before C++23 is a GCC extension",
+				   pfile->directive->name);
+		      else
+			cpp_error (pfile, CPP_DL_PEDWARN,
+				   "#%s before C2X is a GCC extension",
+				   pfile->directive->name);
+		    }
 		  pfile->state.skipping = skip;
 		}
 	    }
--- gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-1.c.jj	2021-10-05 21:18:52.451803413 +0200
+++ gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-1.c	2021-10-05 21:20:26.883511595 +0200
@@ -0,0 +1,5 @@
+/* Test #elifdef and #elifndef in GNU11.  */
+/* { dg-do preprocess } */
+/* { dg-options "-std=gnu11" } */
+
+#include "c2x-elifdef-1.c"
--- gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-2.c.jj	2021-10-05 21:19:49.714020075 +0200
+++ gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-2.c	2021-10-05 21:21:14.554859458 +0200
@@ -0,0 +1,63 @@
+/* Test #elifdef and #elifndef in GNU11: erroneous usages.  */
+/* { dg-do preprocess } */
+/* { dg-options "-std=gnu11" } */
+
+#define A
+#undef B
+
+#elifdef A /* { dg-error "#elifdef without #if" } */
+#elifdef B /* { dg-error "#elifdef without #if" } */
+#elifndef A /* { dg-error "#elifndef without #if" } */
+#elifndef B /* { dg-error "#elifndef without #if" } */
+
+#if 1 /* { dg-error "-:began here" } */
+#else
+#elifdef A /* { dg-error "#elifdef after #else" } */
+#endif
+
+#if 1 /* { dg-error "-:began here" } */
+#else
+#elifdef B /* { dg-error "#elifdef after #else" } */
+#endif
+
+#if 1 /* { dg-error "-:began here" } */
+#else
+#elifndef A /* { dg-error "#elifndef after #else" } */
+#endif
+
+#if 1 /* { dg-error "-:began here" } */
+#else
+#elifndef B /* { dg-error "#elifndef after #else" } */
+#endif
+
+#if 0
+#elifdef A = /* { dg-warning "extra tokens at end of #elifdef directive" } */
+#endif
+
+#if 0
+#elifdef B = /* { dg-warning "extra tokens at end of #elifdef directive" } */
+#endif
+
+#if 0
+#elifndef A = /* { dg-warning "extra tokens at end of #elifndef directive" } */
+#endif
+
+#if 0
+#elifndef B = /* { dg-warning "extra tokens at end of #elifndef directive" } */
+#endif
+
+#if 0
+#elifdef /* { dg-error "no macro name given in #elifdef directive" } */
+#endif
+
+#if 0
+#elifndef /* { dg-error "no macro name given in #elifndef directive" } */
+#endif
+
+#if 0
+#elifdef , /* { dg-error "macro names must be identifiers" } */
+#endif
+
+#if 0
+#elifndef , /* { dg-error "macro names must be identifiers" } */
+#endif
--- gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-3.c.jj	2021-10-05 21:22:42.682650532 +0200
+++ gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-3.c	2021-10-05 22:15:51.698718704 +0200
@@ -0,0 +1,65 @@
+/* Test #elifdef and #elifndef in GNU11.  */
+/* { dg-do preprocess } */
+/* { dg-options "-std=gnu11 -pedantic" } */
+
+#define A
+#undef B
+
+#if 0
+#elifdef A	/* { dg-warning "#elifdef before C2X is a GCC extension" } */
+#define M1 1
+#endif
+
+#if M1 != 1
+#error "#elifdef A did not apply"
+#endif
+
+#if 0
+#elifdef B
+#error "#elifdef B applied"
+#endif
+
+#if 0
+#elifndef A
+#error "#elifndef A applied"
+#endif
+
+#if 0
+#elifndef B	/* { dg-warning "#elifndef before C2X is a GCC extension" } */
+#define M2 2
+#endif
+
+#if M2 != 2
+#error "#elifndef B did not apply"
+#endif
+
+#if 0
+#elifdef A	/* { dg-warning "#elifdef before C2X is a GCC extension" } */
+#else
+#error "#elifdef A did not apply"
+#endif
+
+#if 0
+#elifndef B	/* { dg-warning "#elifndef before C2X is a GCC extension" } */
+#else
+#error "#elifndef B did not apply"
+#endif
+
+#if 1
+#elifdef A	/* { dg-warning "#elifdef before C2X is a GCC extension" } */
+#endif
+
+#if 1
+#elifndef B	/* { dg-warning "#elifndef before C2X is a GCC extension" } */
+#endif
+
+/* As with #elif, the syntax of the new directives is relaxed after a
+   non-skipped group.  */
+
+#if 1
+#elifdef x * y	/* { dg-warning "#elifdef before C2X is a GCC extension" } */
+#endif
+
+#if 1
+#elifndef !	/* { dg-warning "#elifndef before C2X is a GCC extension" } */
+#endif
--- gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-4.c.jj	2021-10-05 21:26:35.671449109 +0200
+++ gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-4.c	2021-10-05 22:16:23.762276538 +0200
@@ -0,0 +1,65 @@
+/* Test #elifdef and #elifndef in GNU11.  */
+/* { dg-do preprocess } */
+/* { dg-options "-std=gnu11 -pedantic-errors" } */
+
+#define A
+#undef B
+
+#if 0
+#elifdef A	/* { dg-error "#elifdef before C2X is a GCC extension" } */
+#define M1 1
+#endif
+
+#if M1 != 1
+#error "#elifdef A did not apply"
+#endif
+
+#if 0
+#elifdef B
+#error "#elifdef B applied"
+#endif
+
+#if 0
+#elifndef A
+#error "#elifndef A applied"
+#endif
+
+#if 0
+#elifndef B	/* { dg-error "#elifndef before C2X is a GCC extension" } */
+#define M2 2
+#endif
+
+#if M2 != 2
+#error "#elifndef B did not apply"
+#endif
+
+#if 0
+#elifdef A	/* { dg-error "#elifdef before C2X is a GCC extension" } */
+#else
+#error "#elifdef A did not apply"
+#endif
+
+#if 0
+#elifndef B	/* { dg-error "#elifndef before C2X is a GCC extension" } */
+#else
+#error "#elifndef B did not apply"
+#endif
+
+#if 1
+#elifdef A	/* { dg-error "#elifdef before C2X is a GCC extension" } */
+#endif
+
+#if 1
+#elifndef B	/* { dg-error "#elifndef before C2X is a GCC extension" } */
+#endif
+
+/* As with #elif, the syntax of the new directives is relaxed after a
+   non-skipped group.  */
+
+#if 1
+#elifdef x * y	/* { dg-error "#elifdef before C2X is a GCC extension" } */
+#endif
+
+#if 1
+#elifndef !	/* { dg-error "#elifndef before C2X is a GCC extension" } */
+#endif
--- gcc/testsuite/g++.dg/cpp/elifdef-1.C.jj	2021-10-05 10:00:41.410057024 +0200
+++ gcc/testsuite/g++.dg/cpp/elifdef-1.C	2021-10-05 10:00:33.110173069 +0200
@@ -0,0 +1,3 @@
+// { dg-do preprocess { target { ! c++23 } } }
+
+#include "../../gcc.dg/cpp/c11-elifdef-1.c"
--- gcc/testsuite/g++.dg/cpp/elifdef-2.C.jj	2021-10-05 10:01:30.345372808 +0200
+++ gcc/testsuite/g++.dg/cpp/elifdef-2.C	2021-10-05 10:03:36.560608083 +0200
@@ -0,0 +1,4 @@
+// P2334R1
+// { dg-do preprocess { target c++23 } }
+
+#include "../../gcc.dg/cpp/c2x-elifdef-1.c"
--- gcc/testsuite/g++.dg/cpp/elifdef-3.C.jj	2021-10-05 10:01:36.029293338 +0200
+++ gcc/testsuite/g++.dg/cpp/elifdef-3.C	2021-10-05 21:27:52.627391684 +0200
@@ -0,0 +1,62 @@
+// P2334R1
+// { dg-do preprocess { target c++23 } }
+
+#define A
+#undef B
+
+#elifdef A // { dg-error "#elifdef without #if" }
+#elifdef B // { dg-error "#elifdef without #if" }
+#elifndef A // { dg-error "#elifndef without #if" }
+#elifndef B // { dg-error "#elifndef without #if" }
+
+#if 1 // { dg-error "-:began here" }
+#else
+#elifdef A // { dg-error "#elifdef after #else" }
+#endif
+
+#if 1 // { dg-error "-:began here" }
+#else
+#elifdef B // { dg-error "#elifdef after #else" }
+#endif
+
+#if 1 // { dg-error "-:began here" }
+#else
+#elifndef A // { dg-error "#elifndef after #else" }
+#endif
+
+#if 1 // { dg-error "-:began here" }
+#else
+#elifndef B // { dg-error "#elifndef after #else" }
+#endif
+
+#if 0
+#elifdef A = // { dg-error "extra tokens at end of #elifdef directive" }
+#endif
+
+#if 0
+#elifdef B = // { dg-error "extra tokens at end of #elifdef directive" }
+#endif
+
+#if 0
+#elifndef A = // { dg-error "extra tokens at end of #elifndef directive" }
+#endif
+
+#if 0
+#elifndef B = // { dg-error "extra tokens at end of #elifndef directive" }
+#endif
+
+#if 0
+#elifdef // { dg-error "no macro name given in #elifdef directive" }
+#endif
+
+#if 0
+#elifndef // { dg-error "no macro name given in #elifndef directive" }
+#endif
+
+#if 0
+#elifdef , // { dg-error "macro names must be identifiers" }
+#endif
+
+#if 0
+#elifndef , // { dg-error "macro names must be identifiers" }
+#endif
--- gcc/testsuite/g++.dg/cpp/elifdef-4.C.jj	2021-10-05 21:11:19.112005054 +0200
+++ gcc/testsuite/g++.dg/cpp/elifdef-4.C	2021-10-05 21:11:39.873721037 +0200
@@ -0,0 +1,5 @@
+// P2334R1
+// { dg-do preprocess }
+// { dg-options "" }
+
+#include "../../gcc.dg/cpp/c2x-elifdef-1.c"
--- gcc/testsuite/g++.dg/cpp/elifdef-5.C.jj	2021-10-05 21:11:54.602519548 +0200
+++ gcc/testsuite/g++.dg/cpp/elifdef-5.C	2021-10-05 21:28:13.093110471 +0200
@@ -0,0 +1,63 @@
+// P2334R1
+// { dg-do preprocess }
+// { dg-options "" }
+
+#define A
+#undef B
+
+#elifdef A // { dg-error "#elifdef without #if" }
+#elifdef B // { dg-error "#elifdef without #if" }
+#elifndef A // { dg-error "#elifndef without #if" }
+#elifndef B // { dg-error "#elifndef without #if" }
+
+#if 1 // { dg-error "-:began here" }
+#else
+#elifdef A // { dg-error "#elifdef after #else" }
+#endif
+
+#if 1 // { dg-error "-:began here" }
+#else
+#elifdef B // { dg-error "#elifdef after #else" }
+#endif
+
+#if 1 // { dg-error "-:began here" }
+#else
+#elifndef A // { dg-error "#elifndef after #else" }
+#endif
+
+#if 1 // { dg-error "-:began here" }
+#else
+#elifndef B // { dg-error "#elifndef after #else" }
+#endif
+
+#if 0
+#elifdef A = // { dg-warning "extra tokens at end of #elifdef directive" }
+#endif
+
+#if 0
+#elifdef B = // { dg-warning "extra tokens at end of #elifdef directive" }
+#endif
+
+#if 0
+#elifndef A = // { dg-warning "extra tokens at end of #elifndef directive" }
+#endif
+
+#if 0
+#elifndef B = // { dg-warning "extra tokens at end of #elifndef directive" }
+#endif
+
+#if 0
+#elifdef // { dg-error "no macro name given in #elifdef directive" }
+#endif
+
+#if 0
+#elifndef // { dg-error "no macro name given in #elifndef directive" }
+#endif
+
+#if 0
+#elifdef , // { dg-error "macro names must be identifiers" }
+#endif
+
+#if 0
+#elifndef , // { dg-error "macro names must be identifiers" }
+#endif
--- gcc/testsuite/g++.dg/cpp/elifdef-6.C.jj	2021-10-05 21:27:05.784035343 +0200
+++ gcc/testsuite/g++.dg/cpp/elifdef-6.C	2021-10-05 22:17:09.120651040 +0200
@@ -0,0 +1,65 @@
+// P2334R1
+// { dg-do preprocess }
+// { dg-options "-pedantic" }
+
+#define A
+#undef B
+
+#if 0
+#elifdef A	// { dg-warning "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#define M1 1
+#endif
+
+#if M1 != 1
+#error "#elifdef A did not apply"
+#endif
+
+#if 0
+#elifdef B
+#error "#elifdef B applied"
+#endif
+
+#if 0
+#elifndef A
+#error "#elifndef A applied"
+#endif
+
+#if 0
+#elifndef B	// { dg-warning "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#define M2 2
+#endif
+
+#if M2 != 2
+#error "#elifndef B did not apply"
+#endif
+
+#if 0
+#elifdef A	// { dg-warning "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#else
+#error "#elifdef A did not apply"
+#endif
+
+#if 0
+#elifndef B	// { dg-warning "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#else
+#error "#elifndef B did not apply"
+#endif
+
+#if 1
+#elifdef A	// { dg-warning "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#endif
+
+#if 1
+#elifndef B	// { dg-warning "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#endif
+
+// As with #elif, the syntax of the new directives is relaxed after a
+   non-skipped group. 
+
+#if 1
+#elifdef x * y	// { dg-warning "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#endif
+
+#if 1
+#elifndef !	// { dg-warning "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#endif
--- gcc/testsuite/g++.dg/cpp/elifdef-7.C.jj	2021-10-05 21:29:18.132216791 +0200
+++ gcc/testsuite/g++.dg/cpp/elifdef-7.C	2021-10-05 22:17:45.439150203 +0200
@@ -0,0 +1,65 @@
+// P2334R1
+// { dg-do preprocess }
+// { dg-options "-pedantic-errors" }
+
+#define A
+#undef B
+
+#if 0
+#elifdef A	// { dg-error "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#define M1 1
+#endif
+
+#if M1 != 1
+#error "#elifdef A did not apply"
+#endif
+
+#if 0
+#elifdef B
+#error "#elifdef B applied"
+#endif
+
+#if 0
+#elifndef A
+#error "#elifndef A applied"
+#endif
+
+#if 0
+#elifndef B	// { dg-error "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#define M2 2
+#endif
+
+#if M2 != 2
+#error "#elifndef B did not apply"
+#endif
+
+#if 0
+#elifdef A	// { dg-error "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#else
+#error "#elifdef A did not apply"
+#endif
+
+#if 0
+#elifndef B	// { dg-error "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#else
+#error "#elifndef B did not apply"
+#endif
+
+#if 1
+#elifdef A	// { dg-error "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#endif
+
+#if 1
+#elifndef B	// { dg-error "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#endif
+
+// As with #elif, the syntax of the new directives is relaxed after a
+   non-skipped group. 
+
+#if 1
+#elifdef x * y	// { dg-error "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#endif
+
+#if 1
+#elifndef !	// { dg-error "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
+#endif


	Jakub


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH, v2] c++: Implement C++23 P2334R1 - #elifdef/#elifndef
  2021-10-05 20:24   ` [PATCH, v2] " Jakub Jelinek
@ 2021-10-06  3:02     ` Jason Merrill
  0 siblings, 0 replies; 5+ messages in thread
From: Jason Merrill @ 2021-10-06  3:02 UTC (permalink / raw)
  To: Jakub Jelinek, Joseph Myers; +Cc: Marek Polacek, gcc-patches

On 10/5/21 16:24, Jakub Jelinek wrote:
> On Tue, Oct 05, 2021 at 05:23:26PM +0000, Joseph Myers wrote:
>>> One is in the patch below, ignores that sentence and only implements it
>>> for -std=c++23/-std=gnu++23 like it is only implemented for -std=c23.
>>> Another option would be to implement it also in the older GNU modes but
>>> not in the C/CXX modes (but it would be strange if we did that just for
>>> C++ and not for C).
>>> Yet another option is to enable it unconditionally.
>>> And yet another option would be to enable it unconditionally but emit
>>> a warning (or pedwarn) when it is seen.
>>> Note, when it is enabled for the older language modes, as Joseph wrote
>>> in the c11-elifdef-1.c testcase, it can result e.g. in rejecting previously
>>> valid code:
>>
>> It would probably be reasonable to enable it in older GNU modes for C as
>> well as C++ if desired (and, in that case, emit a pedwarn-if-pedantic when
>> it's acted on) - cases where it affects compatibility should be rare.
>> Enabling with a pedwarn in strict modes is problematic because it changes
>> semantics of valid code where it was inside #if 0, however.  It doesn't
>> make sense at all to me to think of a new feature like this (one with no
>> prior art in C mentioned in the WG14 proposal) as a defect fix.
>>
>> Any normal directive - i.e. one that has no effect on the preprocessor #if
>> structure and so is ignored inside #if 0 for all language versions - can
>> more reasonably be enabled for all language versions with a pedwarn when
>> used for old versions.  (In particular, that will be appropriate for
>> #warning, where the "don't pedwarn in C2X modes" part needs implementing
>> after N2686 was accepted at the August / September WG14 meeting - I don't
>> know if C++ is doing anything with #warning.)
> 
> Ok, here is an updated version which accepts them in both
> CPP_OPTION (pfile, elifdef) (aka -std={gnu,c}{2x,++2b,++23} modes) or
> !CPP_OPTION (pfile, std) (aka -std=gnu* modes), but for the latter
> pedwarns if pedantic (but only if the directive actually changes the
> preprocessing behavior or if it would be rejected with corresponding
> -std=c*).
> The second hunk in directives.c is for the cases where it would otherwise
> error about unknown directive, the third hunk is for the case where it
> changes the skipping state.  If pfile->state.skipping is true before
> encountering the directive and after it as well, then whether the directive
> is there or not makes no difference.

LGTM.

> 2021-10-05  Jakub Jelinek  <jakub@redhat.com>
> 
> libcpp/
> 	* init.c (lang_defaults): Implement P2334R1, enable elifdef for
> 	-std=c++23 and -std=gnu++23.
> 	* directives.c (_cpp_handle_directive): Support elifdef/elifndef if
> 	either CPP_OPTION (pfile, elifdef) or !CPP_OPTION (pfile, std).
> 	(do_elif): For older non-std modes if pedantic pedwarn about
> 	#elifdef/#elifndef directives that change behavior.
> gcc/testsuite/
> 	* gcc.dg/cpp/gnu11-elifdef-1.c: New test.
> 	* gcc.dg/cpp/gnu11-elifdef-2.c: New test.
> 	* gcc.dg/cpp/gnu11-elifdef-3.c: New test.
> 	* gcc.dg/cpp/gnu11-elifdef-4.c: New test.
> 	* g++.dg/cpp/elifdef-1.C: New test.
> 	* g++.dg/cpp/elifdef-2.C: New test.
> 	* g++.dg/cpp/elifdef-3.C: New test.
> 	* g++.dg/cpp/elifdef-4.C: New test.
> 	* g++.dg/cpp/elifdef-5.C: New test.
> 	* g++.dg/cpp/elifdef-6.C: New test.
> 	* g++.dg/cpp/elifdef-7.C: New test.
> 
> --- libcpp/init.c.jj	2021-09-02 10:01:15.954715595 +0200
> +++ libcpp/init.c	2021-10-05 09:55:15.010620700 +0200
> @@ -122,8 +122,8 @@ static const struct lang_flags lang_defa
>     /* CXX17    */  { 1,  1,  1,  1,  1,  0,    1,  1,   1,   1,   1,    1,     1,     0,   1,      0,   1,     0,   0,   0 },
>     /* GNUCXX20 */  { 1,  1,  1,  1,  1,  0,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   0,   0 },
>     /* CXX20    */  { 1,  1,  1,  1,  1,  0,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   0,   0 },
> -  /* GNUCXX23 */  { 1,  1,  1,  1,  1,  1,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   0 },
> -  /* CXX23    */  { 1,  1,  1,  1,  1,  1,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   0 },
> +  /* GNUCXX23 */  { 1,  1,  1,  1,  1,  1,    0,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   1 },
> +  /* CXX23    */  { 1,  1,  1,  1,  1,  1,    1,  1,   1,   1,   1,    1,     1,     0,   1,      1,   1,     0,   1,   1 },
>     /* ASM      */  { 0,  0,  1,  0,  0,  0,    0,  0,   0,   0,   0,    0,     0,     0,   0,      0,   0,     0,   0,   0 }
>   };
>   
> --- libcpp/directives.c.jj	2021-05-12 09:44:55.080621650 +0200
> +++ libcpp/directives.c	2021-10-05 22:05:52.303984796 +0200
> @@ -447,7 +447,11 @@ _cpp_handle_directive (cpp_reader *pfile
>         if (dname->val.node.node->is_directive)
>   	{
>   	  dir = &dtable[dname->val.node.node->directive_index];
> -	  if ((dir->flags & ELIFDEF) && !CPP_OPTION (pfile, elifdef))
> +	  if ((dir->flags & ELIFDEF)
> +	      && !CPP_OPTION (pfile, elifdef)
> +	      /* For -std=gnu* modes elifdef is supported with
> +		 a pedwarn if pedantic.  */
> +	      && CPP_OPTION (pfile, std))
>   	    dir = 0;
>   	}
>       }
> @@ -2117,7 +2121,26 @@ do_elif (cpp_reader *pfile)
>   	 are skipped and their controlling directives are processed as
>   	 if they were in a group that is skipped."  */
>         if (ifs->skip_elses)
> -	pfile->state.skipping = 1;
> +	{
> +	  /* In older GNU standards, #elifdef/#elifndef is supported
> +	     as an extension, but pedwarn if -pedantic if the presence
> +	     of the directive would be rejected.  */
> +	  if (pfile->directive != &dtable[T_ELIF]
> +	      && ! CPP_OPTION (pfile, elifdef)
> +	      && CPP_PEDANTIC (pfile)
> +	      && !pfile->state.skipping)
> +	    {
> +	      if (CPP_OPTION (pfile, cplusplus))
> +		cpp_error (pfile, CPP_DL_PEDWARN,
> +			   "#%s before C++23 is a GCC extension",
> +			   pfile->directive->name);
> +	      else
> +		cpp_error (pfile, CPP_DL_PEDWARN,
> +			   "#%s before C2X is a GCC extension",
> +			   pfile->directive->name);
> +	    }
> +	  pfile->state.skipping = 1;
> +	}
>         else
>   	{
>   	  if (pfile->directive == &dtable[T_ELIF])
> @@ -2139,6 +2162,22 @@ do_elif (cpp_reader *pfile)
>   		  if (pfile->cb.used)
>   		    pfile->cb.used (pfile, pfile->directive_line, node);
>   		  check_eol (pfile, false);
> +		  /* In older GNU standards, #elifdef/#elifndef is supported
> +		     as an extension, but pedwarn if -pedantic if the presence
> +		     of the directive would change behavior.  */
> +		  if (! CPP_OPTION (pfile, elifdef)
> +		      && CPP_PEDANTIC (pfile)
> +		      && pfile->state.skipping != skip)
> +		    {
> +		      if (CPP_OPTION (pfile, cplusplus))
> +			cpp_error (pfile, CPP_DL_PEDWARN,
> +				   "#%s before C++23 is a GCC extension",
> +				   pfile->directive->name);
> +		      else
> +			cpp_error (pfile, CPP_DL_PEDWARN,
> +				   "#%s before C2X is a GCC extension",
> +				   pfile->directive->name);
> +		    }
>   		  pfile->state.skipping = skip;
>   		}
>   	    }
> --- gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-1.c.jj	2021-10-05 21:18:52.451803413 +0200
> +++ gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-1.c	2021-10-05 21:20:26.883511595 +0200
> @@ -0,0 +1,5 @@
> +/* Test #elifdef and #elifndef in GNU11.  */
> +/* { dg-do preprocess } */
> +/* { dg-options "-std=gnu11" } */
> +
> +#include "c2x-elifdef-1.c"
> --- gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-2.c.jj	2021-10-05 21:19:49.714020075 +0200
> +++ gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-2.c	2021-10-05 21:21:14.554859458 +0200
> @@ -0,0 +1,63 @@
> +/* Test #elifdef and #elifndef in GNU11: erroneous usages.  */
> +/* { dg-do preprocess } */
> +/* { dg-options "-std=gnu11" } */
> +
> +#define A
> +#undef B
> +
> +#elifdef A /* { dg-error "#elifdef without #if" } */
> +#elifdef B /* { dg-error "#elifdef without #if" } */
> +#elifndef A /* { dg-error "#elifndef without #if" } */
> +#elifndef B /* { dg-error "#elifndef without #if" } */
> +
> +#if 1 /* { dg-error "-:began here" } */
> +#else
> +#elifdef A /* { dg-error "#elifdef after #else" } */
> +#endif
> +
> +#if 1 /* { dg-error "-:began here" } */
> +#else
> +#elifdef B /* { dg-error "#elifdef after #else" } */
> +#endif
> +
> +#if 1 /* { dg-error "-:began here" } */
> +#else
> +#elifndef A /* { dg-error "#elifndef after #else" } */
> +#endif
> +
> +#if 1 /* { dg-error "-:began here" } */
> +#else
> +#elifndef B /* { dg-error "#elifndef after #else" } */
> +#endif
> +
> +#if 0
> +#elifdef A = /* { dg-warning "extra tokens at end of #elifdef directive" } */
> +#endif
> +
> +#if 0
> +#elifdef B = /* { dg-warning "extra tokens at end of #elifdef directive" } */
> +#endif
> +
> +#if 0
> +#elifndef A = /* { dg-warning "extra tokens at end of #elifndef directive" } */
> +#endif
> +
> +#if 0
> +#elifndef B = /* { dg-warning "extra tokens at end of #elifndef directive" } */
> +#endif
> +
> +#if 0
> +#elifdef /* { dg-error "no macro name given in #elifdef directive" } */
> +#endif
> +
> +#if 0
> +#elifndef /* { dg-error "no macro name given in #elifndef directive" } */
> +#endif
> +
> +#if 0
> +#elifdef , /* { dg-error "macro names must be identifiers" } */
> +#endif
> +
> +#if 0
> +#elifndef , /* { dg-error "macro names must be identifiers" } */
> +#endif
> --- gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-3.c.jj	2021-10-05 21:22:42.682650532 +0200
> +++ gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-3.c	2021-10-05 22:15:51.698718704 +0200
> @@ -0,0 +1,65 @@
> +/* Test #elifdef and #elifndef in GNU11.  */
> +/* { dg-do preprocess } */
> +/* { dg-options "-std=gnu11 -pedantic" } */
> +
> +#define A
> +#undef B
> +
> +#if 0
> +#elifdef A	/* { dg-warning "#elifdef before C2X is a GCC extension" } */
> +#define M1 1
> +#endif
> +
> +#if M1 != 1
> +#error "#elifdef A did not apply"
> +#endif
> +
> +#if 0
> +#elifdef B
> +#error "#elifdef B applied"
> +#endif
> +
> +#if 0
> +#elifndef A
> +#error "#elifndef A applied"
> +#endif
> +
> +#if 0
> +#elifndef B	/* { dg-warning "#elifndef before C2X is a GCC extension" } */
> +#define M2 2
> +#endif
> +
> +#if M2 != 2
> +#error "#elifndef B did not apply"
> +#endif
> +
> +#if 0
> +#elifdef A	/* { dg-warning "#elifdef before C2X is a GCC extension" } */
> +#else
> +#error "#elifdef A did not apply"
> +#endif
> +
> +#if 0
> +#elifndef B	/* { dg-warning "#elifndef before C2X is a GCC extension" } */
> +#else
> +#error "#elifndef B did not apply"
> +#endif
> +
> +#if 1
> +#elifdef A	/* { dg-warning "#elifdef before C2X is a GCC extension" } */
> +#endif
> +
> +#if 1
> +#elifndef B	/* { dg-warning "#elifndef before C2X is a GCC extension" } */
> +#endif
> +
> +/* As with #elif, the syntax of the new directives is relaxed after a
> +   non-skipped group.  */
> +
> +#if 1
> +#elifdef x * y	/* { dg-warning "#elifdef before C2X is a GCC extension" } */
> +#endif
> +
> +#if 1
> +#elifndef !	/* { dg-warning "#elifndef before C2X is a GCC extension" } */
> +#endif
> --- gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-4.c.jj	2021-10-05 21:26:35.671449109 +0200
> +++ gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-4.c	2021-10-05 22:16:23.762276538 +0200
> @@ -0,0 +1,65 @@
> +/* Test #elifdef and #elifndef in GNU11.  */
> +/* { dg-do preprocess } */
> +/* { dg-options "-std=gnu11 -pedantic-errors" } */
> +
> +#define A
> +#undef B
> +
> +#if 0
> +#elifdef A	/* { dg-error "#elifdef before C2X is a GCC extension" } */
> +#define M1 1
> +#endif
> +
> +#if M1 != 1
> +#error "#elifdef A did not apply"
> +#endif
> +
> +#if 0
> +#elifdef B
> +#error "#elifdef B applied"
> +#endif
> +
> +#if 0
> +#elifndef A
> +#error "#elifndef A applied"
> +#endif
> +
> +#if 0
> +#elifndef B	/* { dg-error "#elifndef before C2X is a GCC extension" } */
> +#define M2 2
> +#endif
> +
> +#if M2 != 2
> +#error "#elifndef B did not apply"
> +#endif
> +
> +#if 0
> +#elifdef A	/* { dg-error "#elifdef before C2X is a GCC extension" } */
> +#else
> +#error "#elifdef A did not apply"
> +#endif
> +
> +#if 0
> +#elifndef B	/* { dg-error "#elifndef before C2X is a GCC extension" } */
> +#else
> +#error "#elifndef B did not apply"
> +#endif
> +
> +#if 1
> +#elifdef A	/* { dg-error "#elifdef before C2X is a GCC extension" } */
> +#endif
> +
> +#if 1
> +#elifndef B	/* { dg-error "#elifndef before C2X is a GCC extension" } */
> +#endif
> +
> +/* As with #elif, the syntax of the new directives is relaxed after a
> +   non-skipped group.  */
> +
> +#if 1
> +#elifdef x * y	/* { dg-error "#elifdef before C2X is a GCC extension" } */
> +#endif
> +
> +#if 1
> +#elifndef !	/* { dg-error "#elifndef before C2X is a GCC extension" } */
> +#endif
> --- gcc/testsuite/g++.dg/cpp/elifdef-1.C.jj	2021-10-05 10:00:41.410057024 +0200
> +++ gcc/testsuite/g++.dg/cpp/elifdef-1.C	2021-10-05 10:00:33.110173069 +0200
> @@ -0,0 +1,3 @@
> +// { dg-do preprocess { target { ! c++23 } } }
> +
> +#include "../../gcc.dg/cpp/c11-elifdef-1.c"
> --- gcc/testsuite/g++.dg/cpp/elifdef-2.C.jj	2021-10-05 10:01:30.345372808 +0200
> +++ gcc/testsuite/g++.dg/cpp/elifdef-2.C	2021-10-05 10:03:36.560608083 +0200
> @@ -0,0 +1,4 @@
> +// P2334R1
> +// { dg-do preprocess { target c++23 } }
> +
> +#include "../../gcc.dg/cpp/c2x-elifdef-1.c"
> --- gcc/testsuite/g++.dg/cpp/elifdef-3.C.jj	2021-10-05 10:01:36.029293338 +0200
> +++ gcc/testsuite/g++.dg/cpp/elifdef-3.C	2021-10-05 21:27:52.627391684 +0200
> @@ -0,0 +1,62 @@
> +// P2334R1
> +// { dg-do preprocess { target c++23 } }
> +
> +#define A
> +#undef B
> +
> +#elifdef A // { dg-error "#elifdef without #if" }
> +#elifdef B // { dg-error "#elifdef without #if" }
> +#elifndef A // { dg-error "#elifndef without #if" }
> +#elifndef B // { dg-error "#elifndef without #if" }
> +
> +#if 1 // { dg-error "-:began here" }
> +#else
> +#elifdef A // { dg-error "#elifdef after #else" }
> +#endif
> +
> +#if 1 // { dg-error "-:began here" }
> +#else
> +#elifdef B // { dg-error "#elifdef after #else" }
> +#endif
> +
> +#if 1 // { dg-error "-:began here" }
> +#else
> +#elifndef A // { dg-error "#elifndef after #else" }
> +#endif
> +
> +#if 1 // { dg-error "-:began here" }
> +#else
> +#elifndef B // { dg-error "#elifndef after #else" }
> +#endif
> +
> +#if 0
> +#elifdef A = // { dg-error "extra tokens at end of #elifdef directive" }
> +#endif
> +
> +#if 0
> +#elifdef B = // { dg-error "extra tokens at end of #elifdef directive" }
> +#endif
> +
> +#if 0
> +#elifndef A = // { dg-error "extra tokens at end of #elifndef directive" }
> +#endif
> +
> +#if 0
> +#elifndef B = // { dg-error "extra tokens at end of #elifndef directive" }
> +#endif
> +
> +#if 0
> +#elifdef // { dg-error "no macro name given in #elifdef directive" }
> +#endif
> +
> +#if 0
> +#elifndef // { dg-error "no macro name given in #elifndef directive" }
> +#endif
> +
> +#if 0
> +#elifdef , // { dg-error "macro names must be identifiers" }
> +#endif
> +
> +#if 0
> +#elifndef , // { dg-error "macro names must be identifiers" }
> +#endif
> --- gcc/testsuite/g++.dg/cpp/elifdef-4.C.jj	2021-10-05 21:11:19.112005054 +0200
> +++ gcc/testsuite/g++.dg/cpp/elifdef-4.C	2021-10-05 21:11:39.873721037 +0200
> @@ -0,0 +1,5 @@
> +// P2334R1
> +// { dg-do preprocess }
> +// { dg-options "" }
> +
> +#include "../../gcc.dg/cpp/c2x-elifdef-1.c"
> --- gcc/testsuite/g++.dg/cpp/elifdef-5.C.jj	2021-10-05 21:11:54.602519548 +0200
> +++ gcc/testsuite/g++.dg/cpp/elifdef-5.C	2021-10-05 21:28:13.093110471 +0200
> @@ -0,0 +1,63 @@
> +// P2334R1
> +// { dg-do preprocess }
> +// { dg-options "" }
> +
> +#define A
> +#undef B
> +
> +#elifdef A // { dg-error "#elifdef without #if" }
> +#elifdef B // { dg-error "#elifdef without #if" }
> +#elifndef A // { dg-error "#elifndef without #if" }
> +#elifndef B // { dg-error "#elifndef without #if" }
> +
> +#if 1 // { dg-error "-:began here" }
> +#else
> +#elifdef A // { dg-error "#elifdef after #else" }
> +#endif
> +
> +#if 1 // { dg-error "-:began here" }
> +#else
> +#elifdef B // { dg-error "#elifdef after #else" }
> +#endif
> +
> +#if 1 // { dg-error "-:began here" }
> +#else
> +#elifndef A // { dg-error "#elifndef after #else" }
> +#endif
> +
> +#if 1 // { dg-error "-:began here" }
> +#else
> +#elifndef B // { dg-error "#elifndef after #else" }
> +#endif
> +
> +#if 0
> +#elifdef A = // { dg-warning "extra tokens at end of #elifdef directive" }
> +#endif
> +
> +#if 0
> +#elifdef B = // { dg-warning "extra tokens at end of #elifdef directive" }
> +#endif
> +
> +#if 0
> +#elifndef A = // { dg-warning "extra tokens at end of #elifndef directive" }
> +#endif
> +
> +#if 0
> +#elifndef B = // { dg-warning "extra tokens at end of #elifndef directive" }
> +#endif
> +
> +#if 0
> +#elifdef // { dg-error "no macro name given in #elifdef directive" }
> +#endif
> +
> +#if 0
> +#elifndef // { dg-error "no macro name given in #elifndef directive" }
> +#endif
> +
> +#if 0
> +#elifdef , // { dg-error "macro names must be identifiers" }
> +#endif
> +
> +#if 0
> +#elifndef , // { dg-error "macro names must be identifiers" }
> +#endif
> --- gcc/testsuite/g++.dg/cpp/elifdef-6.C.jj	2021-10-05 21:27:05.784035343 +0200
> +++ gcc/testsuite/g++.dg/cpp/elifdef-6.C	2021-10-05 22:17:09.120651040 +0200
> @@ -0,0 +1,65 @@
> +// P2334R1
> +// { dg-do preprocess }
> +// { dg-options "-pedantic" }
> +
> +#define A
> +#undef B
> +
> +#if 0
> +#elifdef A	// { dg-warning "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#define M1 1
> +#endif
> +
> +#if M1 != 1
> +#error "#elifdef A did not apply"
> +#endif
> +
> +#if 0
> +#elifdef B
> +#error "#elifdef B applied"
> +#endif
> +
> +#if 0
> +#elifndef A
> +#error "#elifndef A applied"
> +#endif
> +
> +#if 0
> +#elifndef B	// { dg-warning "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#define M2 2
> +#endif
> +
> +#if M2 != 2
> +#error "#elifndef B did not apply"
> +#endif
> +
> +#if 0
> +#elifdef A	// { dg-warning "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#else
> +#error "#elifdef A did not apply"
> +#endif
> +
> +#if 0
> +#elifndef B	// { dg-warning "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#else
> +#error "#elifndef B did not apply"
> +#endif
> +
> +#if 1
> +#elifdef A	// { dg-warning "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#endif
> +
> +#if 1
> +#elifndef B	// { dg-warning "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#endif
> +
> +// As with #elif, the syntax of the new directives is relaxed after a
> +   non-skipped group.
> +
> +#if 1
> +#elifdef x * y	// { dg-warning "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#endif
> +
> +#if 1
> +#elifndef !	// { dg-warning "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#endif
> --- gcc/testsuite/g++.dg/cpp/elifdef-7.C.jj	2021-10-05 21:29:18.132216791 +0200
> +++ gcc/testsuite/g++.dg/cpp/elifdef-7.C	2021-10-05 22:17:45.439150203 +0200
> @@ -0,0 +1,65 @@
> +// P2334R1
> +// { dg-do preprocess }
> +// { dg-options "-pedantic-errors" }
> +
> +#define A
> +#undef B
> +
> +#if 0
> +#elifdef A	// { dg-error "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#define M1 1
> +#endif
> +
> +#if M1 != 1
> +#error "#elifdef A did not apply"
> +#endif
> +
> +#if 0
> +#elifdef B
> +#error "#elifdef B applied"
> +#endif
> +
> +#if 0
> +#elifndef A
> +#error "#elifndef A applied"
> +#endif
> +
> +#if 0
> +#elifndef B	// { dg-error "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#define M2 2
> +#endif
> +
> +#if M2 != 2
> +#error "#elifndef B did not apply"
> +#endif
> +
> +#if 0
> +#elifdef A	// { dg-error "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#else
> +#error "#elifdef A did not apply"
> +#endif
> +
> +#if 0
> +#elifndef B	// { dg-error "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#else
> +#error "#elifndef B did not apply"
> +#endif
> +
> +#if 1
> +#elifdef A	// { dg-error "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#endif
> +
> +#if 1
> +#elifndef B	// { dg-error "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#endif
> +
> +// As with #elif, the syntax of the new directives is relaxed after a
> +   non-skipped group.
> +
> +#if 1
> +#elifdef x * y	// { dg-error "#elifdef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#endif
> +
> +#if 1
> +#elifndef !	// { dg-error "#elifndef before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } }
> +#endif
> 
> 
> 	Jakub
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-10-06  3:02 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-05  8:35 [PATCH] c++: Implement C++23 P2334R1 - #elifdef/#elifndef Jakub Jelinek
2021-10-05 15:24 ` Marek Polacek
2021-10-05 17:23 ` Joseph Myers
2021-10-05 20:24   ` [PATCH, v2] " Jakub Jelinek
2021-10-06  3:02     ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).