[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