[PATCH] cpp: new built-in __EXP_COUNTER__
Jonathan Wakely
jwakely@redhat.com
Mon Mar 18 07:32:33 GMT 2024
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 <kaz@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 <kaz@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 <kaz@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 <kaz@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 <pc@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.
More information about the Gcc-patches
mailing list