public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-4205] libcpp: Implement C++23 P2334R1 - #elifdef/#elifndef
@ 2021-10-06  8:22 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2021-10-06  8:22 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:f43eb7707c06e8824d07d5c87ed2019d796fa8a0

commit r12-4205-gf43eb7707c06e8824d07d5c87ed2019d796fa8a0
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Oct 6 10:13:51 2021 +0200

    libcpp: Implement C++23 P2334R1 - #elifdef/#elifndef
    
    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 ignoring that sentence and only implementing it
    for -std=c++23/-std=gnu++23 like it is only implemented for -std=c2x.
    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.
    After feedback, this option enables #elifdef/#elifndef for -std=c2x
    and -std=c++2{b,3} and enables it also for -std=gnu*, but for GNU modes
    older than C2X or C++23 if -pedantic it emits a pedwarn on the directives
    that either would be rejected in the corresponding -std=c* modes, e.g.
      #if 1
      #elifdef A // pedwarn if -pedantic
      #endif
    or when the directives would be silently accepted, but when they are
    recognized it changes behavior, so e.g.
      #define A
      #if 0
      #elifdef A // pedwarn if -pedantic
      #define M 1
      #endif
    It won't pedwarn if the directives would be silently ignored and wouldn't
    change anything, like:
      #define A
      #if 0
      #elifndef A
      #define M 1
      #endif
    or
      #undef B
      #if 0
      #elifdef B
      #define M 1
      #endif
    
    2021-10-06  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.

Diff:
---
 gcc/testsuite/g++.dg/cpp/elifdef-1.C       |  3 ++
 gcc/testsuite/g++.dg/cpp/elifdef-2.C       |  4 ++
 gcc/testsuite/g++.dg/cpp/elifdef-3.C       | 62 ++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp/elifdef-4.C       |  5 +++
 gcc/testsuite/g++.dg/cpp/elifdef-5.C       | 63 +++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp/elifdef-6.C       | 65 ++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp/elifdef-7.C       | 65 ++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-1.c |  5 +++
 gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-2.c | 63 +++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-3.c | 65 ++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-4.c | 65 ++++++++++++++++++++++++++++++
 libcpp/directives.c                        | 43 +++++++++++++++++++-
 libcpp/init.c                              |  4 +-
 13 files changed, 508 insertions(+), 4 deletions(-)

diff --git a/gcc/testsuite/g++.dg/cpp/elifdef-1.C b/gcc/testsuite/g++.dg/cpp/elifdef-1.C
new file mode 100644
index 00000000000..f7965e3c2e8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp/elifdef-1.C
@@ -0,0 +1,3 @@
+// { dg-do preprocess { target { ! c++23 } } }
+
+#include "../../gcc.dg/cpp/c11-elifdef-1.c"
diff --git a/gcc/testsuite/g++.dg/cpp/elifdef-2.C b/gcc/testsuite/g++.dg/cpp/elifdef-2.C
new file mode 100644
index 00000000000..64082710fde
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp/elifdef-2.C
@@ -0,0 +1,4 @@
+// P2334R1
+// { dg-do preprocess { target c++23 } }
+
+#include "../../gcc.dg/cpp/c2x-elifdef-1.c"
diff --git a/gcc/testsuite/g++.dg/cpp/elifdef-3.C b/gcc/testsuite/g++.dg/cpp/elifdef-3.C
new file mode 100644
index 00000000000..d9acce06e05
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp/elifdef-3.C
@@ -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
diff --git a/gcc/testsuite/g++.dg/cpp/elifdef-4.C b/gcc/testsuite/g++.dg/cpp/elifdef-4.C
new file mode 100644
index 00000000000..08edf583fa5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp/elifdef-4.C
@@ -0,0 +1,5 @@
+// P2334R1
+// { dg-do preprocess }
+// { dg-options "" }
+
+#include "../../gcc.dg/cpp/c2x-elifdef-1.c"
diff --git a/gcc/testsuite/g++.dg/cpp/elifdef-5.C b/gcc/testsuite/g++.dg/cpp/elifdef-5.C
new file mode 100644
index 00000000000..f7d4007d345
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp/elifdef-5.C
@@ -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
diff --git a/gcc/testsuite/g++.dg/cpp/elifdef-6.C b/gcc/testsuite/g++.dg/cpp/elifdef-6.C
new file mode 100644
index 00000000000..94d2118aae0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp/elifdef-6.C
@@ -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
diff --git a/gcc/testsuite/g++.dg/cpp/elifdef-7.C b/gcc/testsuite/g++.dg/cpp/elifdef-7.C
new file mode 100644
index 00000000000..bb9b8efab94
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp/elifdef-7.C
@@ -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
diff --git a/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-1.c b/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-1.c
new file mode 100644
index 00000000000..efcfbc93270
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-1.c
@@ -0,0 +1,5 @@
+/* Test #elifdef and #elifndef in GNU11.  */
+/* { dg-do preprocess } */
+/* { dg-options "-std=gnu11" } */
+
+#include "c2x-elifdef-1.c"
diff --git a/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-2.c b/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-2.c
new file mode 100644
index 00000000000..e5bd7056de3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-2.c
@@ -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
diff --git a/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-3.c b/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-3.c
new file mode 100644
index 00000000000..0b769a73a83
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-3.c
@@ -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
diff --git a/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-4.c b/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-4.c
new file mode 100644
index 00000000000..aba34673366
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-4.c
@@ -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
diff --git a/libcpp/directives.c b/libcpp/directives.c
index 261a584c550..b4bc8b4df30 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -447,7 +447,11 @@ _cpp_handle_directive (cpp_reader *pfile, bool indented)
       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;
 		}
 	    }
diff --git a/libcpp/init.c b/libcpp/init.c
index eda17a6a038..5a424e23553 100644
--- a/libcpp/init.c
+++ b/libcpp/init.c
@@ -122,8 +122,8 @@ static const struct lang_flags lang_defaults[] =
   /* 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 }
 };


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-10-06  8:22 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-06  8:22 [gcc r12-4205] libcpp: Implement C++23 P2334R1 - #elifdef/#elifndef Jakub Jelinek

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).