libcpp: Implement C++23 P2334R1 - #elifdef/#elifndef
authorJakub Jelinek <jakub@redhat.com>
Wed, 6 Oct 2021 08:13:51 +0000 (10:13 +0200)
committerJakub Jelinek <jakub@redhat.com>
Wed, 6 Oct 2021 08:13:51 +0000 (10:13 +0200)
commitf43eb7707c06e8824d07d5c87ed2019d796fa8a0
treede2393608bfe1d6a93145f93343c7222ac8fe704
parentece8b0fce6bbfb1e531de8164da47eeed80d3cf1
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.
13 files changed:
gcc/testsuite/g++.dg/cpp/elifdef-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp/elifdef-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp/elifdef-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp/elifdef-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp/elifdef-5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp/elifdef-6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp/elifdef-7.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cpp/gnu11-elifdef-4.c [new file with mode: 0644]
libcpp/directives.c
libcpp/init.c