aboutsummaryrefslogtreecommitdiff
path: root/libcpp
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2021-10-06 10:13:51 +0200
committerJakub Jelinek <jakub@redhat.com>2021-10-06 10:13:51 +0200
commitf43eb7707c06e8824d07d5c87ed2019d796fa8a0 (patch)
treede2393608bfe1d6a93145f93343c7222ac8fe704 /libcpp
parentece8b0fce6bbfb1e531de8164da47eeed80d3cf1 (diff)
downloadgcc-f43eb7707c06e8824d07d5c87ed2019d796fa8a0.zip
gcc-f43eb7707c06e8824d07d5c87ed2019d796fa8a0.tar.gz
gcc-f43eb7707c06e8824d07d5c87ed2019d796fa8a0.tar.bz2
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.
Diffstat (limited to 'libcpp')
-rw-r--r--libcpp/directives.c43
-rw-r--r--libcpp/init.c4
2 files changed, 43 insertions, 4 deletions
diff --git a/libcpp/directives.c b/libcpp/directives.c
index 261a584..b4bc8b4 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 eda17a6a..5a424e2 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 }
};