On 18/03/24 07:30 +0000, Jonathan Wakely wrote:
On 21/04/22 04:31 -0700, Kaz Kylheku wrote:
libcpp/ChangeLog
2022-04-21  Kaz Kylheku  <k...@kylheku.com>

        This change introduces a pair of related macros
        __EXP_COUNTER__ and __UEXP_COUNTER__.  These macros access
        integer values which enumerate macro expansions.
        They can be used for the purposes of obtaining, unique
        identifiers (within the scope of a translation unit), as a
        replacement for unreliable hacks based on __LINE__.

        Outside of macro expansions, these macros expand to 1,
        so they are easy to test for in portable code that needs
        to fall back on something, like __LINE__.

        * gcc/doc/cpp.texi (__EXP_COUNTER__, __UEXP_COUNTER__):
        Special built-in macros documented.

        * libcpp/include/cpplib.h (struct cpp_macro): New members of
        type long long: exp_number and uexp_number.  These members are
        used to attach the current exp_counter value, and the parent
        context's copy of it to a new macro expansion.  The special
        macros then just access these.
        (enum cpp_builtin_type): New enumeration members,
        BT_EXP_COUNTER and BT_UEXP_COUNTER.

        * libcpp/macro.cc (exp_counter): New static variable for
        counting expansions.  There is an existing one,
        num_expanded_macros_counter, but that has its own purpose and
        is incremented in a specific place.  Plus it uses a narrower
        integer type.
        (_cpp_builtin_number_text): Change the local variable "number"
        from linenum_type to unsigned long long, so it holds at least
        64 bit values.  Handle the BT_EXP_COUNTER and BT_UEXP_COUNTER
        cases.  These just have to see if there is a current macro, and
        retrieve the values from it, otherwise do nothing so that the
        default 1 is produced.  In the case of BT_UEXP_COUNTER, if the
        value is zero, we don't use it, so 1 emerges.  The sprintf of
        the number is adjusted to use the right conversion specifier
        for the wider type.  Space is already being reserved for
        a 64 bit decimal.
        (enter_macro_context): After processing the macro arguments,
        if any, we increment exp_counter and attach its new value to
        the macro's context structure in the exp_number member.  We
        also calculate the macro's uexp_number: the parent context's
        exp_number.  This is tricky: we have to chase the previous
        macro context.  This works if the macro is object-like, or has
        no parameters.  If it has parameters, there is a parameter
        context, and so we have to climb one more flight of stairs to
        get to the real context.

gcc/testsuite/ChangeLog
2022-04-21  Kaz Kylheku  <k...@kylheku.com>

        * gcc.dg/cpp/expcounter1.c: New test.
        * gcc.dg/cpp/expcounter2.c: New test.
        * gcc.dg/cpp/expcounter3.c: New test.
        * gcc.dg/cpp/expcounter4.c: New test.
        * gcc.dg/cpp/expcounter5.c: New test.

Signed-off-by: Kaz Kylheku <k...@kylheku.com>
---
gcc/doc/cpp.texi                       | 81 ++++++++++++++++++++++++++
gcc/testsuite/ChangeLog                |  8 +++
gcc/testsuite/gcc.dg/cpp/expcounter1.c | 16 +++++
gcc/testsuite/gcc.dg/cpp/expcounter2.c | 21 +++++++
gcc/testsuite/gcc.dg/cpp/expcounter3.c | 22 +++++++
gcc/testsuite/gcc.dg/cpp/expcounter4.c | 22 +++++++
gcc/testsuite/gcc.dg/cpp/expcounter5.c | 28 +++++++++
libcpp/ChangeLog                       | 49 ++++++++++++++++
libcpp/include/cpplib.h                |  8 +++
libcpp/init.cc                         |  2 +
libcpp/macro.cc                        | 44 +++++++++++++-
11 files changed, 299 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/cpp/expcounter1.c
create mode 100644 gcc/testsuite/gcc.dg/cpp/expcounter2.c
create mode 100644 gcc/testsuite/gcc.dg/cpp/expcounter3.c
create mode 100644 gcc/testsuite/gcc.dg/cpp/expcounter4.c
create mode 100644 gcc/testsuite/gcc.dg/cpp/expcounter5.c

diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi
index 90b2767e39a..d52450958d7 100644
--- a/gcc/doc/cpp.texi
+++ b/gcc/doc/cpp.texi
@@ -1941,6 +1941,87 @@ generate unique identifiers. Care must be taken to ensure that
@code{__COUNTER__} is not expanded prior to inclusion of precompiled headers
which use it.  Otherwise, the precompiled headers will not be used.

+@item __EXP_COUNTER__
+This macro's name means "(macro) expansion counter".
+Outside of macro replacement sequences, it expands to the integer
+token @code{1}.  This make it possible to easily test for the presence
+of this feature using conditional directives such as
+@code{#if __EXP_COUNTER__}.

It's a macro, so you can just use '#ifdef __EXP_COUNTER__' to test if
it's supported. Is this additional behaviour necessary?

+When @code{__EXP_COUNTER__} occurs in the replacement token sequence
+of a macro, it expands to positive decimal integer token which

expands to _a_ positive decimal integer token?

+uniquely identifies the expansion, within a translation unit.
+Unlike @code{__COUNTER__}, @code{__EXP_COUNTER__} does not increment
+on each access: all references to it which occur in the same token
+replacement sequence of the same instance of a macro being expanded
+produce the same integer token.
+
+The implementation of this feature works as follows: a counter is initialized +to zero prior to the processing of any tokens of the translation unit. Whenever +a macro is about to be expanded, the counter is incremented, and the counter's +value is associated with that macro expansion context. Subsequent increments of +the counter, such as during rescanning of a token sequence for more macros, do
+not affect the captured value.  Nested macro expansions are associated with
+their own @code{__EXP_COUNTER__} values.  The counter uses the
+@code{unsigned long long} type of the host implementation for which the
+preprocessor is compiled. If this counter overflows and @code{__EXP_COUNTER__}
+is subsequently accessed, the behavior is unspecified.
+
+The main use for @code{__EXP_COUNTER__} is the generation of unique symbols,
+as in the following example:
+
+@smallexample
+#define cat(a, b) a ## b
+#define xcat(a, b) cat (a, b)
+#define uni(pfx, count) xcat (pfx, xcat (_uniq_, count))
+
+#define repeat(count)                                       \
+  for (int uni (i, __EXP_COUNTER__) = 0,                    \
+       uni (c, __EXP_COUNTER__) = (count);                  \
+       uni (i, __EXP_COUNTER__) < uni (c, __EXP_COUNTER__); \
+       uni (i, __EXP_COUNTER__)++)
+
+repeat (get_repeat_count ())
+  puts ("Hello, world!")
+@end smallexample
+
+@item __UEXP_COUNTER__
+This macro is closely related to @code{__EXP_COUNTER__}.  In the
+expansion of a macro which is being expanded in the middle of another
+macro expansion, @code{__UEXP_COUNTER__} ("upper context expansion counter")
+produces the @code{__EXP_COUNTER__} value of the parent expansion.
+In any other situation, this macro expands to @code{1}.
+
+Consider the following example:
+
+@smallexample
+#define child __UEXP_COUNTER__ __EXP_COUNTER__
+#define parent @{ __EXP_COUNTER__ child @}
+parent
+@end smallexample
+
+Here, @code{parent} will expand to a sequence similar to @code{@{ 42 42 43 @}}.
+The @code{__UEXP_COUNTER__} value from @code{child} matches the
+@code{__EXP_COUNTER__} in @code{parent}, but the @code{child}'s own
+@code{__EXP_COUNTER__} is, of course, different.
+
+The main use for @code{__UEXP_COUNTER__} is the simplification of macros
+that require @code{__EXP_COUNTER__}.  The example given for
+@code{__EXP_COUNTER__} can be simplified like this:
+
+@smallexample
+#define cat(a, b) a ## b
+#define xcat(a, b) cat (a, b)
+#define uni(pfx) xcat (pfx, xcat (_uniq_, __UEXP_COUNTER__))
+
+#define repeat(count)                       \
+  for (int uni (i) = 0, uni (c) = (count);  \
+       uni (i) < uni (c);                   \
+       uni (i)++)
+
+repeat (get_repeat_count ())
+  puts ("Hello, world!")
+@end smallexample
+
@item __GFORTRAN__
The GNU Fortran compiler defines this.

diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e147f69c8eb..fee0ae0ad4b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2022-04-21  Kaz Kylheku  <k...@kylheku.com>
+
+       * gcc.dg/cpp/expcounter1.c: New test.
+       * gcc.dg/cpp/expcounter2.c: New test.
+       * gcc.dg/cpp/expcounter3.c: New test.
+       * gcc.dg/cpp/expcounter4.c: New test.
+       * gcc.dg/cpp/expcounter5.c: New test.
+
2022-04-15  Paul A. Clarke  <p...@us.ibm.com>

        * g++.dg/debug/dwarf2/const2.C: Move to g++.target/powerpc.

ChangeLog files are autogenerated every night, please don't include
modifications to them in patch submissions (it's not necessary, and it
means the patch won't apply cleanly because the ChangeLog will have
moved on since you created the patch).

I don't have an opinion on the implementation, or the proposal itself,
except that the implementation seems susprisingly simple, which is
nice.

Oh I see there's a [PATCH v2] at
https://gcc.gnu.org/pipermail/gcc-patches/2022-April/593473.html
although I think my brief comments apply to that one too.


Reply via email to