* [PATCH] cpp: new built-in __EXP_COUNTER__
@ 2022-04-21 11:31 Kaz Kylheku
2024-03-18 7:30 ` Jonathan Wakely
0 siblings, 1 reply; 10+ messages in thread
From: Kaz Kylheku @ 2022-04-21 11:31 UTC (permalink / raw)
To: gcc-patches
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__}.
+When @code{__EXP_COUNTER__} occurs in the replacement token sequence
+of a macro, it expands to positive decimal integer token which
+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.
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter1.c
b/gcc/testsuite/gcc.dg/cpp/expcounter1.c
new file mode 100644
index 00000000000..21bb89c7d13
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter1.c
@@ -0,0 +1,16 @@
+/* { dg-do preprocess } */
+/* { dg-options "-Wcpp" } */
+#if __EXP_COUNTER__ == 1
+#warning "yes" // { dg-warning "-:yes" }
+#endif
+#if __UEXP_COUNTER__ == 1
+#warning "yes" // { dg-warning "-:yes" }
+#endif
+#define __EXP_COUNTER__ 42 // { dg-warning "-:redefined" }
+#define __UEXP_COUNTER__ 73 // { dg-warning "-:redefined" }
+#if __EXP_COUNTER__ == 42
+#warning "yes" // { dg-warning "-:yes" }
+#endif
+#if __UEXP_COUNTER__ == 73
+#warning "yes" // { dg-warning "-:yes" }
+#endif
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter2.c
b/gcc/testsuite/gcc.dg/cpp/expcounter2.c
new file mode 100644
index 00000000000..de1cf6fca45
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter2.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#define M0(X) X, __EXP_COUNTER__
+#define M1(X) X, M0(__EXP_COUNTER__), __EXP_COUNTER__
+#define M2(X) X, M1(__EXP_COUNTER__), __EXP_COUNTER__
+
+int out[] = { M2(__EXP_COUNTER__), __EXP_COUNTER__ };
+int ref[] = { 1, 3, 4, 5, 4, 3, 1 };
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ if (sizeof(out) != sizeof(ref))
+ return EXIT_FAILURE;
+ if (memcmp(out, ref, sizeof out) != 0)
+ return EXIT_FAILURE;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter3.c
b/gcc/testsuite/gcc.dg/cpp/expcounter3.c
new file mode 100644
index 00000000000..b7f9bb03a7f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter3.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#define M0(X) X, __UEXP_COUNTER__
+#define M1(X) X, M0(__UEXP_COUNTER__), __UEXP_COUNTER__
+#define M2(X) X, M1(__UEXP_COUNTER__), __UEXP_COUNTER__
+#define M3(X) X, M2(__UEXP_COUNTER__), __UEXP_COUNTER__
+
+int out[] = { M3(__UEXP_COUNTER__), __UEXP_COUNTER__ };
+int ref[] = { 1, 1, 3, 4, 5, 4, 3, 1, 1 };
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ if (sizeof(out) != sizeof(ref))
+ return EXIT_FAILURE;
+ if (memcmp(out, ref, sizeof out) != 0)
+ return EXIT_FAILURE;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter4.c
b/gcc/testsuite/gcc.dg/cpp/expcounter4.c
new file mode 100644
index 00000000000..47f0732a655
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter4.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#define M0 __UEXP_COUNTER__
+#define M1 M0, __EXP_COUNTER__, __UEXP_COUNTER__
+#define M2 M1, __EXP_COUNTER__, __UEXP_COUNTER__
+#define M3 M2, __EXP_COUNTER__, __UEXP_COUNTER__
+
+int out[] = { M3, __EXP_COUNTER__, __UEXP_COUNTER__ };
+int ref[] = { 5, 5, 4, 4, 3, 3, 1, 1, 1 };
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ if (sizeof(out) != sizeof(ref))
+ return EXIT_FAILURE;
+ if (memcmp(out, ref, sizeof out) != 0)
+ return EXIT_FAILURE;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter5.c
b/gcc/testsuite/gcc.dg/cpp/expcounter5.c
new file mode 100644
index 00000000000..59b0e780768
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter5.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#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)++)
+
+#define str(x) #x
+#define xstr(x) str(x)
+
+const char *out = xstr(repeat(42) repeat(73) foo(););
+const char *ref = "for (int i_uniq_3 = 0, c_uniq_3 = (42); "
+ "i_uniq_3 < c_uniq_3; i_uniq_3++) "
+ "for (int i_uniq_29 = 0, c_uniq_29 = (73); "
+ "i_uniq_29 < c_uniq_29; i_uniq_29++) foo();";
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ return (strcmp(out, ref) == 0) ? 0 : EXIT_FAILURE;
+}
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index a0242895188..024924f9fe1 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,52 @@
+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 epand 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.
+
2022-02-11 Joseph Myers <joseph@codesourcery.com>
* Makefile.in (po/$(PACKAGE).pot): Also handle cpp_warning_at,
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 3eba6f74b57..f3c724a1a15 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -827,6 +827,12 @@ struct GTY(()) cpp_macro {
cpp_macro *GTY ((tag ("true"))) next;
} GTY ((desc ("%1.kind == cmk_assert"))) parm;
+ /* Global expansion number, derived from exp_counter. */
+ long long exp_number;
+
+ /* Parent expansion number; zero if unavailable. */
+ long long uexp_number;
+
/* Definition line number. */
location_t line;
@@ -920,6 +926,8 @@ enum cpp_builtin_type
BT_PRAGMA, /* `_Pragma' operator */
BT_TIMESTAMP, /* `__TIMESTAMP__' */
BT_COUNTER, /* `__COUNTER__' */
+ BT_EXP_COUNTER, /* `__EXP_COUNTER__' */
+ BT_UEXP_COUNTER, /* `__UEXP_COUNTER__' */
BT_HAS_ATTRIBUTE, /* `__has_attribute(x)' */
BT_HAS_STD_ATTRIBUTE, /* `__has_c_attribute(x)' */
BT_HAS_BUILTIN, /* `__has_builtin(x)' */
diff --git a/libcpp/init.cc b/libcpp/init.cc
index f4ab83d2145..60b0e482412 100644
--- a/libcpp/init.cc
+++ b/libcpp/init.cc
@@ -411,6 +411,8 @@ static const struct builtin_macro builtin_array[] =
B("__LINE__", BT_SPECLINE, true),
B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL, true),
B("__COUNTER__", BT_COUNTER, true),
+ B("__EXP_COUNTER__", BT_EXP_COUNTER, true),
+ B("__UEXP_COUNTER__", BT_UEXP_COUNTER, true),
/* Make sure to update the list of built-in
function-like macros in traditional.cc:
fun_like_macro() when adding more following */
diff --git a/libcpp/macro.cc b/libcpp/macro.cc
index 8ebf360c03c..5a14a655c0f 100644
--- a/libcpp/macro.cc
+++ b/libcpp/macro.cc
@@ -362,6 +362,10 @@ static const cpp_token* cpp_get_token_1 (cpp_reader *,
location_t *);
static cpp_hashnode* macro_of_context (cpp_context *context);
+/* Counter tracking the number of macros expanded, for purposes
+ of __EXP_COUNTER__. */
+static unsigned long exp_counter = 0;
+
/* Statistical counter tracking the number of macros that got
expanded. */
unsigned num_expanded_macros_counter = 0;
@@ -490,7 +494,7 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode
*node,
location_t loc)
{
const uchar *result = NULL;
- linenum_type number = 1;
+ unsigned long long number = 1;
switch (node->value.builtin)
{
@@ -660,6 +664,26 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode
*node,
number = pfile->counter++;
break;
+ case BT_EXP_COUNTER:
+ {
+ cpp_hashnode *macro = macro_of_context (pfile->context);
+ if (macro != NULL)
+ number = macro->value.macro->exp_number;
+ }
+ break;
+
+ case BT_UEXP_COUNTER:
+ {
+ cpp_hashnode *macro = macro_of_context (pfile->context);
+ if (macro != NULL)
+ {
+ unsigned long long ue = macro->value.macro->uexp_number;
+ if (ue > 0)
+ number = ue;
+ }
+ }
+ break;
+
case BT_HAS_ATTRIBUTE:
number = pfile->cb.has_attribute (pfile, false);
break;
@@ -683,7 +707,7 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode
*node,
{
/* 21 bytes holds all NUL-terminated unsigned 64-bit numbers. */
result = _cpp_unaligned_alloc (pfile, 21);
- sprintf ((char *) result, "%u", number);
+ sprintf ((char *) result, "%llu", number);
}
return result;
@@ -1492,6 +1516,22 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode
*node,
/* Disable the macro within its expansion. */
node->flags |= NODE_DISABLED;
+ /* Increment and capture __EXP_COUNTER__ counter. */
+ macro->exp_number = ++exp_counter;
+
+ /* If we are in the middle of an existing macro, get *its*
+ exp_number into uexp_number, for __UEXP_COUNTER__. */
+ {
+ cpp_hashnode *existing_macro = macro_of_context (pfile->context);
+ cpp_macro *pmac = existing_macro != NULL
+ ? existing_macro->value.macro
+ : NULL;
+ if (pmac != NULL && pmac->paramc > 0)
+ existing_macro = macro_of_context (pfile->context->prev);
+ if (existing_macro != NULL)
+ macro->uexp_number = existing_macro->value.macro->exp_number;
+ }
+
/* Laziness can only affect the expansion tokens of the macro,
not its fun-likeness or parameters. */
_cpp_maybe_notify_macro_use (pfile, node, location);
--
2.17.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] cpp: new built-in __EXP_COUNTER__
2022-04-21 11:31 [PATCH] cpp: new built-in __EXP_COUNTER__ Kaz Kylheku
@ 2024-03-18 7:30 ` Jonathan Wakely
2024-03-18 7:32 ` Jonathan Wakely
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Jonathan Wakely @ 2024-03-18 7:30 UTC (permalink / raw)
To: Kaz Kylheku; +Cc: gcc-patches
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.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] cpp: new built-in __EXP_COUNTER__
2024-03-18 7:30 ` Jonathan Wakely
@ 2024-03-18 7:32 ` Jonathan Wakely
2024-03-18 16:39 ` Kaz Kylheku
2024-03-19 17:27 ` Kaz Kylheku
2 siblings, 0 replies; 10+ messages in thread
From: Jonathan Wakely @ 2024-03-18 7:32 UTC (permalink / raw)
To: Kaz Kylheku; +Cc: gcc-patches
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.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] cpp: new built-in __EXP_COUNTER__
2024-03-18 7:30 ` Jonathan Wakely
2024-03-18 7:32 ` Jonathan Wakely
@ 2024-03-18 16:39 ` Kaz Kylheku
2024-03-18 19:28 ` Jonathan Wakely
2024-03-19 17:27 ` Kaz Kylheku
2 siblings, 1 reply; 10+ messages in thread
From: Kaz Kylheku @ 2024-03-18 16:39 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: gcc-patches
On 2024-03-18 00:30, Jonathan Wakely wrote:
>>+@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?
Thanks for looking at the patch.
The macro has to be defined, but it doesn't have to be 1.
Outside a macro body, it could just appear defined
with an empty value, as if by #define __EXP_COUNTER__.
When I dump the predefined macros of a nearby GCC installation, I
see very few empty ones:
$ echo | gcc -dM -E - | awk 'NF == 2'
#define __USER_LABEL_PREFIX__
#define __REGISTER_PREFIX__
The __EXP_COUNTER__ and __UEXP_COUNTER__ symbols are
intended for suffix and infix use, so they are roughly in
a kind of category with those those two.
I will make that change, and also fix the grammar error
and remove the conflict-promoting ChangeLog changes.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] cpp: new built-in __EXP_COUNTER__
2024-03-18 16:39 ` Kaz Kylheku
@ 2024-03-18 19:28 ` Jonathan Wakely
0 siblings, 0 replies; 10+ messages in thread
From: Jonathan Wakely @ 2024-03-18 19:28 UTC (permalink / raw)
To: Kaz Kylheku; +Cc: gcc-patches
On Mon, 18 Mar 2024 at 16:46, Kaz Kylheku <kaz@kylheku.com> wrote:
>
> On 2024-03-18 00:30, Jonathan Wakely wrote:
> >>+@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?
>
> Thanks for looking at the patch.
>
> The macro has to be defined, but it doesn't have to be 1.
>
> Outside a macro body, it could just appear defined
> with an empty value, as if by #define __EXP_COUNTER__.
>
> When I dump the predefined macros of a nearby GCC installation, I
> see very few empty ones:
>
> $ echo | gcc -dM -E - | awk 'NF == 2'
> #define __USER_LABEL_PREFIX__
> #define __REGISTER_PREFIX__
>
> The __EXP_COUNTER__ and __UEXP_COUNTER__ symbols are
> intended for suffix and infix use, so they are roughly in
> a kind of category with those those two.
I don't feel strongly about the value, it seems fine to define it as 1
too. I just thought it was a bit strange to explicitly mention testing
its value to detect support, when #ifdef seems simpler and more
"correct" (as in, it just checks if it's defined, and thevalue is
irrelevant).
>
> I will make that change, and also fix the grammar error
> and remove the conflict-promoting ChangeLog changes.
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] cpp: new built-in __EXP_COUNTER__
2024-03-18 7:30 ` Jonathan Wakely
2024-03-18 7:32 ` Jonathan Wakely
2024-03-18 16:39 ` Kaz Kylheku
@ 2024-03-19 17:27 ` Kaz Kylheku
2024-03-20 23:34 ` rep.dot.nop
2 siblings, 1 reply; 10+ messages in thread
From: Kaz Kylheku @ 2024-03-19 17:27 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: gcc-patches
[-- Attachment #1: Type: text/plain, Size: 665 bytes --]
On 2024-03-18 00:30, Jonathan Wakely wrote:
> I don't have an opinion on the implementation, or the proposal itself,
> except that the implementation seems susprisingly simple, which is
> nice.
Hi Jonathan,
Here is an updated patch.
It rebased cleanly over more than newer 16000 commits, suggesting
that the area in the cpp code is "still waters", which is good.
I made the documentation change not to recommend using #if, but
#ifdef.
I got rid of the ChangeLog changes, and also tried to pay more
attention to the log message format, where the ChangeLog pieces
are specified.
In the first test case, I had to adjust the expected warning text
for two lines.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-cpp-new-built-in-__EXP_COUNTER__.patch --]
[-- Type: text/x-diff; name=0001-cpp-new-built-in-__EXP_COUNTER__.patch, Size: 15866 bytes --]
From 65effbcac172e8bb1a89f0621b3de6cdcb8dbab2 Mon Sep 17 00:00:00 2001
From: Kaz Kylheku <kaz@kylheku.com>
Date: Wed, 20 Apr 2022 01:15:24 -0700
Subject: [PATCH] cpp: new built-in __EXP_COUNTER__
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 epand to 1,
so they are easy to test for in portable code that needs
to fall back on something, like __LINE__.
libcpp/ChangeLog:
* 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 th emacro's uexp_number: the parent context's
exp_cnumber. 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/ChangeLog:
* gcc/doc/cpp.texi (__EXP_COUNTER__, __UEXP_COUNTER__):
Special built-in macros documented.
gcc/testsuite/ChangeLog:
* 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/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/include/cpplib.h | 8 +++
libcpp/init.cc | 2 +
libcpp/macro.cc | 44 +++++++++++++-
9 files changed, 242 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 3de6e7aa737..a21e8b44be1 100644
--- a/gcc/doc/cpp.texi
+++ b/gcc/doc/cpp.texi
@@ -1942,6 +1942,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{#ifdef __EXP_COUNTER__}.
+When @code{__EXP_COUNTER__} occurs in the replacement token sequence
+of a macro, it expands to a positive decimal integer token which
+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/gcc.dg/cpp/expcounter1.c b/gcc/testsuite/gcc.dg/cpp/expcounter1.c
new file mode 100644
index 00000000000..0734fc07114
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter1.c
@@ -0,0 +1,16 @@
+/* { dg-do preprocess } */
+/* { dg-options "-Wcpp" } */
+#if __EXP_COUNTER__ == 1
+#warning "yes" // { dg-warning "-:yes" }
+#endif
+#if __UEXP_COUNTER__ == 1
+#warning "yes" // { dg-warning "-:yes" }
+#endif
+#define __EXP_COUNTER__ 42 // { dg-warning "-:\"__EXP_COUNTER__\" redefined" }
+#define __UEXP_COUNTER__ 73 // { dg-warning "-:\"__UEXP_COUNTER__\" redefined" }
+#if __EXP_COUNTER__ == 42
+#warning "yes" // { dg-warning "-:yes" }
+#endif
+#if __UEXP_COUNTER__ == 73
+#warning "yes" // { dg-warning "-:yes" }
+#endif
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter2.c b/gcc/testsuite/gcc.dg/cpp/expcounter2.c
new file mode 100644
index 00000000000..de1cf6fca45
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter2.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#define M0(X) X, __EXP_COUNTER__
+#define M1(X) X, M0(__EXP_COUNTER__), __EXP_COUNTER__
+#define M2(X) X, M1(__EXP_COUNTER__), __EXP_COUNTER__
+
+int out[] = { M2(__EXP_COUNTER__), __EXP_COUNTER__ };
+int ref[] = { 1, 3, 4, 5, 4, 3, 1 };
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ if (sizeof(out) != sizeof(ref))
+ return EXIT_FAILURE;
+ if (memcmp(out, ref, sizeof out) != 0)
+ return EXIT_FAILURE;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter3.c b/gcc/testsuite/gcc.dg/cpp/expcounter3.c
new file mode 100644
index 00000000000..b7f9bb03a7f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter3.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#define M0(X) X, __UEXP_COUNTER__
+#define M1(X) X, M0(__UEXP_COUNTER__), __UEXP_COUNTER__
+#define M2(X) X, M1(__UEXP_COUNTER__), __UEXP_COUNTER__
+#define M3(X) X, M2(__UEXP_COUNTER__), __UEXP_COUNTER__
+
+int out[] = { M3(__UEXP_COUNTER__), __UEXP_COUNTER__ };
+int ref[] = { 1, 1, 3, 4, 5, 4, 3, 1, 1 };
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ if (sizeof(out) != sizeof(ref))
+ return EXIT_FAILURE;
+ if (memcmp(out, ref, sizeof out) != 0)
+ return EXIT_FAILURE;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter4.c b/gcc/testsuite/gcc.dg/cpp/expcounter4.c
new file mode 100644
index 00000000000..47f0732a655
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter4.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#define M0 __UEXP_COUNTER__
+#define M1 M0, __EXP_COUNTER__, __UEXP_COUNTER__
+#define M2 M1, __EXP_COUNTER__, __UEXP_COUNTER__
+#define M3 M2, __EXP_COUNTER__, __UEXP_COUNTER__
+
+int out[] = { M3, __EXP_COUNTER__, __UEXP_COUNTER__ };
+int ref[] = { 5, 5, 4, 4, 3, 3, 1, 1, 1 };
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ if (sizeof(out) != sizeof(ref))
+ return EXIT_FAILURE;
+ if (memcmp(out, ref, sizeof out) != 0)
+ return EXIT_FAILURE;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter5.c b/gcc/testsuite/gcc.dg/cpp/expcounter5.c
new file mode 100644
index 00000000000..59b0e780768
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter5.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#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)++)
+
+#define str(x) #x
+#define xstr(x) str(x)
+
+const char *out = xstr(repeat(42) repeat(73) foo(););
+const char *ref = "for (int i_uniq_3 = 0, c_uniq_3 = (42); "
+ "i_uniq_3 < c_uniq_3; i_uniq_3++) "
+ "for (int i_uniq_29 = 0, c_uniq_29 = (73); "
+ "i_uniq_29 < c_uniq_29; i_uniq_29++) foo();";
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ return (strcmp(out, ref) == 0) ? 0 : EXIT_FAILURE;
+}
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index c62374d3192..25550b0281b 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -875,6 +875,12 @@ struct GTY(()) cpp_macro {
cpp_macro *GTY ((tag ("true"))) next;
} GTY ((desc ("%1.kind == cmk_assert"))) parm;
+ /* Global expansion number, derived from exp_counter. */
+ long long exp_number;
+
+ /* Parent expansion number; zero if unavailable. */
+ long long uexp_number;
+
/* Definition line number. */
location_t line;
@@ -968,6 +974,8 @@ enum cpp_builtin_type
BT_PRAGMA, /* `_Pragma' operator */
BT_TIMESTAMP, /* `__TIMESTAMP__' */
BT_COUNTER, /* `__COUNTER__' */
+ BT_EXP_COUNTER, /* `__EXP_COUNTER__' */
+ BT_UEXP_COUNTER, /* `__UEXP_COUNTER__' */
BT_HAS_ATTRIBUTE, /* `__has_attribute(x)' */
BT_HAS_STD_ATTRIBUTE, /* `__has_c_attribute(x)' */
BT_HAS_BUILTIN, /* `__has_builtin(x)' */
diff --git a/libcpp/init.cc b/libcpp/init.cc
index 54fc9236d38..0074634c2e7 100644
--- a/libcpp/init.cc
+++ b/libcpp/init.cc
@@ -426,6 +426,8 @@ static const struct builtin_macro builtin_array[] =
B("__LINE__", BT_SPECLINE, true),
B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL, true),
B("__COUNTER__", BT_COUNTER, true),
+ B("__EXP_COUNTER__", BT_EXP_COUNTER, true),
+ B("__UEXP_COUNTER__", BT_UEXP_COUNTER, true),
/* Make sure to update the list of built-in
function-like macros in traditional.cc:
fun_like_macro() when adding more following */
diff --git a/libcpp/macro.cc b/libcpp/macro.cc
index 352eb2e4fd9..2a7ca90d955 100644
--- a/libcpp/macro.cc
+++ b/libcpp/macro.cc
@@ -362,6 +362,10 @@ static const cpp_token* cpp_get_token_1 (cpp_reader *, location_t *);
static cpp_hashnode* macro_of_context (cpp_context *context);
+/* Counter tracking the number of macros expanded, for purposes
+ of __EXP_COUNTER__. */
+static unsigned long exp_counter = 0;
+
/* Statistical counter tracking the number of macros that got
expanded. */
unsigned num_expanded_macros_counter = 0;
@@ -493,7 +497,7 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
location_t loc)
{
const uchar *result = NULL;
- linenum_type number = 1;
+ unsigned long long number = 1;
switch (node->value.builtin)
{
@@ -663,6 +667,26 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
number = pfile->counter++;
break;
+ case BT_EXP_COUNTER:
+ {
+ cpp_hashnode *macro = macro_of_context (pfile->context);
+ if (macro != NULL)
+ number = macro->value.macro->exp_number;
+ }
+ break;
+
+ case BT_UEXP_COUNTER:
+ {
+ cpp_hashnode *macro = macro_of_context (pfile->context);
+ if (macro != NULL)
+ {
+ unsigned long long ue = macro->value.macro->uexp_number;
+ if (ue > 0)
+ number = ue;
+ }
+ }
+ break;
+
case BT_HAS_ATTRIBUTE:
number = pfile->cb.has_attribute (pfile, false);
break;
@@ -692,7 +716,7 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
{
/* 21 bytes holds all NUL-terminated unsigned 64-bit numbers. */
result = _cpp_unaligned_alloc (pfile, 21);
- sprintf ((char *) result, "%u", number);
+ sprintf ((char *) result, "%llu", number);
}
return result;
@@ -1501,6 +1525,22 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node,
/* Disable the macro within its expansion. */
node->flags |= NODE_DISABLED;
+ /* Increment and capture __EXP_COUNTER__ counter. */
+ macro->exp_number = ++exp_counter;
+
+ /* If we are in the middle of an existing macro, get *its*
+ exp_number into uexp_number, for __UEXP_COUNTER__. */
+ {
+ cpp_hashnode *existing_macro = macro_of_context (pfile->context);
+ cpp_macro *pmac = existing_macro != NULL
+ ? existing_macro->value.macro
+ : NULL;
+ if (pmac != NULL && pmac->paramc > 0)
+ existing_macro = macro_of_context (pfile->context->prev);
+ if (existing_macro != NULL)
+ macro->uexp_number = existing_macro->value.macro->exp_number;
+ }
+
/* Laziness can only affect the expansion tokens of the macro,
not its fun-likeness or parameters. */
_cpp_maybe_notify_macro_use (pfile, node, location);
--
2.17.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] cpp: new built-in __EXP_COUNTER__
2024-03-19 17:27 ` Kaz Kylheku
@ 2024-03-20 23:34 ` rep.dot.nop
2024-03-22 0:18 ` Kaz Kylheku
0 siblings, 1 reply; 10+ messages in thread
From: rep.dot.nop @ 2024-03-20 23:34 UTC (permalink / raw)
To: gcc-patches, Kaz Kylheku, Jonathan Wakely
On 19 March 2024 18:27:13 CET, Kaz Kylheku <kaz@kylheku.com> wrote:
>On 2024-03-18 00:30, Jonathan Wakely wrote:
>> I don't have an opinion on the implementation, or the proposal itself,
>> except that the implementation seems susprisingly simple, which is
>> nice.
>
>Hi Jonathan,
>
>Here is an updated patch.
>
>It rebased cleanly over more than newer 16000 commits, suggesting
>that the area in the cpp code is "still waters", which is good.
>
>I made the documentation change not to recommend using #if, but
>#ifdef.
>
>I got rid of the ChangeLog changes, and also tried to pay more
>attention to the log message format, where the ChangeLog pieces
>are specified.
>
>In the first test case, I had to adjust the expected warning text
>for two lines.
>
Please forgive the bike shedding, but __EXP_COUNTER__ would lead me into thinking about exponents or thereabouts.
__MACRO_EXPANSION_COUNTER__ is more what your patch is about, IMHO? Maybe you could come up with a more descriptive name, please?
And, while I can see what could possibly be done with that, I'm not really convinced that it would be a wise idea to (unilaterally) support that idea. Don't you think that this would encourage producing more spaghetti code?
Just curious about real world motivating examples I guess.
cheers
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] cpp: new built-in __EXP_COUNTER__
2024-03-20 23:34 ` rep.dot.nop
@ 2024-03-22 0:18 ` Kaz Kylheku
2024-03-22 1:40 ` Andrew Pinski
0 siblings, 1 reply; 10+ messages in thread
From: Kaz Kylheku @ 2024-03-22 0:18 UTC (permalink / raw)
To: rep.dot.nop; +Cc: gcc-patches, Jonathan Wakely
[-- Attachment #1: Type: text/plain, Size: 3636 bytes --]
On 2024-03-20 16:34, rep.dot.nop@gmail.com wrote:
> On 19 March 2024 18:27:13 CET, Kaz Kylheku <kaz@kylheku.com> wrote:
>>On 2024-03-18 00:30, Jonathan Wakely wrote:
>>> I don't have an opinion on the implementation, or the proposal itself,
>>> except that the implementation seems susprisingly simple, which is
>>> nice.
>>
>>Hi Jonathan,
>>
>>Here is an updated patch.
>>
>>It rebased cleanly over more than newer 16000 commits, suggesting
>>that the area in the cpp code is "still waters", which is good.
>>
>>I made the documentation change not to recommend using #if, but
>>#ifdef.
>>
>>I got rid of the ChangeLog changes, and also tried to pay more
>>attention to the log message format, where the ChangeLog pieces
>>are specified.
>>
>>In the first test case, I had to adjust the expected warning text
>>for two lines.
>>
>
> Please forgive the bike shedding, but __EXP_COUNTER__ would lead me into thinking about exponents or thereabouts.
> __MACRO_EXPANSION_COUNTER__ is more what your patch is about, IMHO? Maybe you could come up with a more descriptive name, please?
>
> And, while I can see what could possibly be done with that, I'm not really convinced that it would be a wise idea to (unilaterally) support that idea. Don't you think that this would encourage producing more spaghetti code?
>
> Just curious about real world motivating examples I guess.
> cheers
Hi, (Bernhard?)
Concerns about naming are very important; not bike shedding at all.
I changed the patch to use __EXPANSION_NUMBER__. I didn't include MACRO
because I hope it's clear that in preprocessing, we are expanding
macros. The parent symbol is now called __PARENT_EXPANSION_NUMBER__.
I dropped the COUNTER terminology because the existing __COUNTER__
is a symbol whose value changes each time it is mentioned,
These symbols are not like that; they capture a fixed value in
a scope and behave like ordinary macros.
In doing the renaming, I noticed that from the beginning I've already
been calling the internal value in the macro context macro->exp_number,
because it's not a counter.
The focus of this feature isn't to enable some new "earth-shattering"
techniques, but to improve certain situations in existing macros.
For instance, suppose we have a macro that expands to some block
of code in which there is an internal goto. If we have it
#define MAC(...) { ... goto _label; ... __label: ; }
then this cannot be used twice in the same function; labels have
function scope. If we make it
#define MAC(...) { ... goto CAT(__label, __LINE__); ... CAT(__label, __LINE__): ; }
we now can use MAC two or more times in the same function, but not in
the same line of code.
With __EXPANSION_NUMBER__ it is doable. Given this program:
#define xcat(A, B) A ## B
#define cat(A, B) xcat(A, B)
#define lab(PREFIX) cat(PREFIX, __PARENT_EXPANSION_NUMBER__)
#define MAC { goto lab(foo); /*...*/ lab(foo): ; }
MAC MAC MAC
We get the preprocessed output (with -E):
{ goto foo3; foo3: ; } { goto foo10; foo10: ; } { goto foo17; foo17: ; }
There are issues with relying on __LINE__ to produce different values
when it is referenced in code generated by a macro.
The following program prints the same value 12 three times; even though
PRINT seems to be referenced on different physical lines in the
PRINT3 macro replacement text. __LINE__ references the line where
the top-level expansion of PRINT3 occurs, not where PRINT occurs.
#include <stdio.h>
#define PRINT (printf("%d\n", __LINE__))
#define PRINT3 do { \
PRINT; \
PRINT; \
PRINT; \
} while (0)
int main()
{
PRINT3;
return 0;
}
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-cpp-new-built-in-__EXPANSION_NUMBER__.patch --]
[-- Type: text/x-diff; name=0001-cpp-new-built-in-__EXPANSION_NUMBER__.patch, Size: 16664 bytes --]
From 4aded10c4171f9a9a361bb8986d721357f1fc2c8 Mon Sep 17 00:00:00 2001
From: Kaz Kylheku <kaz@kylheku.com>
Date: Wed, 20 Apr 2022 01:15:24 -0700
Subject: [PATCH] cpp: new built-in __EXPANSION_NUMBER__
This change introduces a pair of related macros __EXPANSION_NUMBER__ and
__PARENT_EXPANSION_NUMBER__. 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 epand to 1, so they are easy
to test for in portable code that needs to fall back on another
approach, perhaps involving __LINE__.
libcpp/ChangeLog:
* libcpp/include/cpplib.h (struct cpp_macro): New members of
type long long: expansion_number and parent_expansion_number.
These members are used to attach the current expansion_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_EXPANSION_NUMBER and BT_PARENT_EXPANSION_NUMBER.
* libcpp/macro.cc (expansion_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_EXPANSION_NUMBER and
BT_PARENT_EXPANSION_NUMBER 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_PARENT_EXPANSION_NUMBER, 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 expansion_counter and attach its new value to
the macro's context structure in the expansion_number member.
We also calculate the emacro's parent_expansion_number: the
parent context's exp_cnumber. 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/ChangeLog:
* gcc/doc/cpp.texi (__EXPANSION_NUMBER__,
__PARENT_EXPANSION_NUMBER__): Special built-in macros
documented.
gcc/testsuite/ChangeLog:
* 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 | 84 ++++++++++++++++++++++++++
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/include/cpplib.h | 8 +++
libcpp/init.cc | 2 +
libcpp/macro.cc | 44 +++++++++++++-
9 files changed, 245 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 3de6e7aa737..40aa6c31375 100644
--- a/gcc/doc/cpp.texi
+++ b/gcc/doc/cpp.texi
@@ -1942,6 +1942,90 @@ 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 __EXPANSION_NUMBER__
+This macro's name means "(macro) expansion number". 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{#ifdef __EXPANSION_NUMBER__}.
+When @code{__EXPANSION_NUMBER__} occurs in the replacement token
+sequence of a macro, it expands to a positive decimal integer token
+which uniquely identifies the expansion, within a translation unit.
+Unlike @code{__COUNTER__}, @code{__EXPANSION_NUMBER__} 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{__EXPANSION_NUMBER__} 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{__EXPANSION_NUMBER__} is subsequently accessed, the behavior is
+unspecified.
+
+The main use for @code{__EXPANSION_NUMBER__} 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, __EXPANSION_NUMBER__) = 0, \
+ uni (c, __EXPANSION_NUMBER__) = (count); \
+ uni (i, __EXPANSION_NUMBER__) < uni (c, __EXPANSION_NUMBER__); \
+ uni (i, __EXPANSION_NUMBER__)++)
+
+repeat (get_repeat_count ())
+ puts ("Hello, world!")
+@end smallexample
+
+@item __PARENT_EXPANSION_NUMBER__
+This macro is closely related to @code{__EXPANSION_NUMBER__}. In the
+expansion of a macro which is being expanded in the middle of another
+macro expansion, @code{__PARENT_EXPANSION_NUMBER__} produces the
+@code{__EXPANSION_NUMBER__} value of the parent expansion. In any other
+situation, this macro expands to @code{1}.
+
+Consider the following example:
+
+@smallexample
+#define child __PARENT_EXPANSION_NUMBER__ __EXPANSION_NUMBER__
+#define parent @{ __EXPANSION_NUMBER__ child @}
+parent
+@end smallexample
+
+Here, @code{parent} will expand to a sequence similar to
+@code{@{ 42 42 43 @}}. The @code{__PARENT_EXPANSION_NUMBER__} value
+from @code{child} matches the @code{__EXPANSION_NUMBER__} in
+@code{parent}, but the @code{child}'s own @code{__EXPANSION_NUMBER__}
+is, of course, different.
+
+The main use for @code{__PARENT_EXPANSION_NUMBER__} is the
+simplification of macros that require @code{__EXPANSION_NUMBER__}. The
+example given for @code{__EXPANSION_NUMBER__} 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_, __PARENT_EXPANSION_NUMBER__))
+
+#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/gcc.dg/cpp/expcounter1.c b/gcc/testsuite/gcc.dg/cpp/expcounter1.c
new file mode 100644
index 00000000000..37c2e4626d3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter1.c
@@ -0,0 +1,16 @@
+/* { dg-do preprocess } */
+/* { dg-options "-Wcpp" } */
+#if __EXPANSION_NUMBER__ == 1
+#warning "yes" // { dg-warning "-:yes" }
+#endif
+#if __PARENT_EXPANSION_NUMBER__ == 1
+#warning "yes" // { dg-warning "-:yes" }
+#endif
+#define __EXPANSION_NUMBER__ 42 // { dg-warning "-:\"__EXPANSION_NUMBER__\" redefined" }
+#define __PARENT_EXPANSION_NUMBER__ 73 // { dg-warning "-:\"__PARENT_EXPANSION_NUMBER__\" redefined" }
+#if __EXPANSION_NUMBER__ == 42
+#warning "yes" // { dg-warning "-:yes" }
+#endif
+#if __PARENT_EXPANSION_NUMBER__ == 73
+#warning "yes" // { dg-warning "-:yes" }
+#endif
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter2.c b/gcc/testsuite/gcc.dg/cpp/expcounter2.c
new file mode 100644
index 00000000000..7b20631ca5d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter2.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#define M0(X) X, __EXPANSION_NUMBER__
+#define M1(X) X, M0(__EXPANSION_NUMBER__), __EXPANSION_NUMBER__
+#define M2(X) X, M1(__EXPANSION_NUMBER__), __EXPANSION_NUMBER__
+
+int out[] = { M2(__EXPANSION_NUMBER__), __EXPANSION_NUMBER__ };
+int ref[] = { 1, 3, 4, 5, 4, 3, 1 };
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ if (sizeof(out) != sizeof(ref))
+ return EXIT_FAILURE;
+ if (memcmp(out, ref, sizeof out) != 0)
+ return EXIT_FAILURE;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter3.c b/gcc/testsuite/gcc.dg/cpp/expcounter3.c
new file mode 100644
index 00000000000..8c27e0754c2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter3.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#define M0(X) X, __PARENT_EXPANSION_NUMBER__
+#define M1(X) X, M0(__PARENT_EXPANSION_NUMBER__), __PARENT_EXPANSION_NUMBER__
+#define M2(X) X, M1(__PARENT_EXPANSION_NUMBER__), __PARENT_EXPANSION_NUMBER__
+#define M3(X) X, M2(__PARENT_EXPANSION_NUMBER__), __PARENT_EXPANSION_NUMBER__
+
+int out[] = { M3(__PARENT_EXPANSION_NUMBER__), __PARENT_EXPANSION_NUMBER__ };
+int ref[] = { 1, 1, 3, 4, 5, 4, 3, 1, 1 };
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ if (sizeof(out) != sizeof(ref))
+ return EXIT_FAILURE;
+ if (memcmp(out, ref, sizeof out) != 0)
+ return EXIT_FAILURE;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter4.c b/gcc/testsuite/gcc.dg/cpp/expcounter4.c
new file mode 100644
index 00000000000..6538b701876
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter4.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#define M0 __PARENT_EXPANSION_NUMBER__
+#define M1 M0, __EXPANSION_NUMBER__, __PARENT_EXPANSION_NUMBER__
+#define M2 M1, __EXPANSION_NUMBER__, __PARENT_EXPANSION_NUMBER__
+#define M3 M2, __EXPANSION_NUMBER__, __PARENT_EXPANSION_NUMBER__
+
+int out[] = { M3, __EXPANSION_NUMBER__, __PARENT_EXPANSION_NUMBER__ };
+int ref[] = { 5, 5, 4, 4, 3, 3, 1, 1, 1 };
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ if (sizeof(out) != sizeof(ref))
+ return EXIT_FAILURE;
+ if (memcmp(out, ref, sizeof out) != 0)
+ return EXIT_FAILURE;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cpp/expcounter5.c b/gcc/testsuite/gcc.dg/cpp/expcounter5.c
new file mode 100644
index 00000000000..a09406ce91a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/expcounter5.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+
+#define cat(a, b) a ## b
+#define xcat(a, b) cat(a, b)
+#define uni(pfx) xcat(pfx, xcat(_uniq_, __PARENT_EXPANSION_NUMBER__))
+
+#define repeat(count) \
+ for (int uni(i) = 0, uni(c) = (count); \
+ uni(i) < uni(c); \
+ uni(i)++)
+
+#define str(x) #x
+#define xstr(x) str(x)
+
+const char *out = xstr(repeat(42) repeat(73) foo(););
+const char *ref = "for (int i_uniq_3 = 0, c_uniq_3 = (42); "
+ "i_uniq_3 < c_uniq_3; i_uniq_3++) "
+ "for (int i_uniq_29 = 0, c_uniq_29 = (73); "
+ "i_uniq_29 < c_uniq_29; i_uniq_29++) foo();";
+
+#include <string.h>
+#include <stdlib.h>
+
+int main()
+{
+ return (strcmp(out, ref) == 0) ? 0 : EXIT_FAILURE;
+}
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index c62374d3192..637b85f2d5a 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -875,6 +875,12 @@ struct GTY(()) cpp_macro {
cpp_macro *GTY ((tag ("true"))) next;
} GTY ((desc ("%1.kind == cmk_assert"))) parm;
+ /* Global expansion number, derived from exp_counter. */
+ long long expansion_number;
+
+ /* Parent expansion number; zero if unavailable. */
+ long long parent_expansion_number;
+
/* Definition line number. */
location_t line;
@@ -968,6 +974,8 @@ enum cpp_builtin_type
BT_PRAGMA, /* `_Pragma' operator */
BT_TIMESTAMP, /* `__TIMESTAMP__' */
BT_COUNTER, /* `__COUNTER__' */
+ BT_EXPANSION_NUMBER, /* `__EXPANSION_NUMBER__' */
+ BT_PARENT_EXPANSION_NUMBER, /* `__PARENT_EXPANSION_NUMBER__' */
BT_HAS_ATTRIBUTE, /* `__has_attribute(x)' */
BT_HAS_STD_ATTRIBUTE, /* `__has_c_attribute(x)' */
BT_HAS_BUILTIN, /* `__has_builtin(x)' */
diff --git a/libcpp/init.cc b/libcpp/init.cc
index 54fc9236d38..62c71b0518e 100644
--- a/libcpp/init.cc
+++ b/libcpp/init.cc
@@ -426,6 +426,8 @@ static const struct builtin_macro builtin_array[] =
B("__LINE__", BT_SPECLINE, true),
B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL, true),
B("__COUNTER__", BT_COUNTER, true),
+ B("__EXPANSION_NUMBER__", BT_EXPANSION_NUMBER, true),
+ B("__PARENT_EXPANSION_NUMBER__", BT_PARENT_EXPANSION_NUMBER, true),
/* Make sure to update the list of built-in
function-like macros in traditional.cc:
fun_like_macro() when adding more following */
diff --git a/libcpp/macro.cc b/libcpp/macro.cc
index 352eb2e4fd9..ef0b74e9434 100644
--- a/libcpp/macro.cc
+++ b/libcpp/macro.cc
@@ -362,6 +362,10 @@ static const cpp_token* cpp_get_token_1 (cpp_reader *, location_t *);
static cpp_hashnode* macro_of_context (cpp_context *context);
+/* Counter tracking the number of macros expanded, for purposes
+ of __EXPANSION_NUMBER__. */
+static unsigned long expansion_counter = 0;
+
/* Statistical counter tracking the number of macros that got
expanded. */
unsigned num_expanded_macros_counter = 0;
@@ -493,7 +497,7 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
location_t loc)
{
const uchar *result = NULL;
- linenum_type number = 1;
+ unsigned long long number = 1;
switch (node->value.builtin)
{
@@ -663,6 +667,26 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
number = pfile->counter++;
break;
+ case BT_EXPANSION_NUMBER:
+ {
+ cpp_hashnode *macro = macro_of_context (pfile->context);
+ if (macro != NULL)
+ number = macro->value.macro->expansion_number;
+ }
+ break;
+
+ case BT_PARENT_EXPANSION_NUMBER:
+ {
+ cpp_hashnode *macro = macro_of_context (pfile->context);
+ if (macro != NULL)
+ {
+ unsigned long long ue = macro->value.macro->parent_expansion_number;
+ if (ue > 0)
+ number = ue;
+ }
+ }
+ break;
+
case BT_HAS_ATTRIBUTE:
number = pfile->cb.has_attribute (pfile, false);
break;
@@ -692,7 +716,7 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node,
{
/* 21 bytes holds all NUL-terminated unsigned 64-bit numbers. */
result = _cpp_unaligned_alloc (pfile, 21);
- sprintf ((char *) result, "%u", number);
+ sprintf ((char *) result, "%llu", number);
}
return result;
@@ -1501,6 +1525,22 @@ enter_macro_context (cpp_reader *pfile, cpp_hashnode *node,
/* Disable the macro within its expansion. */
node->flags |= NODE_DISABLED;
+ /* Increment and capture __EXPANSION_NUMBER__ counter. */
+ macro->expansion_number = ++expansion_counter;
+
+ /* If we are in the middle of an existing macro, get *its*
+ expansion_number into parent_expansion_number, for __PARENT_EXPANSION_NUMBER__. */
+ {
+ cpp_hashnode *existing_macro = macro_of_context (pfile->context);
+ cpp_macro *pmac = existing_macro != NULL
+ ? existing_macro->value.macro
+ : NULL;
+ if (pmac != NULL && pmac->paramc > 0)
+ existing_macro = macro_of_context (pfile->context->prev);
+ if (existing_macro != NULL)
+ macro->parent_expansion_number = existing_macro->value.macro->expansion_number;
+ }
+
/* Laziness can only affect the expansion tokens of the macro,
not its fun-likeness or parameters. */
_cpp_maybe_notify_macro_use (pfile, node, location);
--
2.17.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] cpp: new built-in __EXP_COUNTER__
2024-03-22 0:18 ` Kaz Kylheku
@ 2024-03-22 1:40 ` Andrew Pinski
2024-03-22 6:03 ` Kaz Kylheku
0 siblings, 1 reply; 10+ messages in thread
From: Andrew Pinski @ 2024-03-22 1:40 UTC (permalink / raw)
To: Kaz Kylheku; +Cc: Bernhard Reutner-Fischer, GCC Patches, Jonathan Wakely
[-- Attachment #1: Type: text/plain, Size: 4145 bytes --]
On Thu, Mar 21, 2024, 17:20 Kaz Kylheku <kaz@kylheku.com> wrote:
> On 2024-03-20 16:34, rep.dot.nop@gmail.com wrote:
> > On 19 March 2024 18:27:13 CET, Kaz Kylheku <kaz@kylheku.com> wrote:
> >>On 2024-03-18 00:30, Jonathan Wakely wrote:
> >>> I don't have an opinion on the implementation, or the proposal itself,
> >>> except that the implementation seems susprisingly simple, which is
> >>> nice.
> >>
> >>Hi Jonathan,
> >>
> >>Here is an updated patch.
> >>
> >>It rebased cleanly over more than newer 16000 commits, suggesting
> >>that the area in the cpp code is "still waters", which is good.
> >>
> >>I made the documentation change not to recommend using #if, but
> >>#ifdef.
> >>
> >>I got rid of the ChangeLog changes, and also tried to pay more
> >>attention to the log message format, where the ChangeLog pieces
> >>are specified.
> >>
> >>In the first test case, I had to adjust the expected warning text
> >>for two lines.
> >>
> >
> > Please forgive the bike shedding, but __EXP_COUNTER__ would lead me into
> thinking about exponents or thereabouts.
> > __MACRO_EXPANSION_COUNTER__ is more what your patch is about, IMHO?
> Maybe you could come up with a more descriptive name, please?
> >
> > And, while I can see what could possibly be done with that, I'm not
> really convinced that it would be a wise idea to (unilaterally) support
> that idea. Don't you think that this would encourage producing more
> spaghetti code?
> >
> > Just curious about real world motivating examples I guess.
> > cheers
>
> Hi, (Bernhard?)
>
> Concerns about naming are very important; not bike shedding at all.
> I changed the patch to use __EXPANSION_NUMBER__. I didn't include MACRO
> because I hope it's clear that in preprocessing, we are expanding
> macros. The parent symbol is now called __PARENT_EXPANSION_NUMBER__.
>
> I dropped the COUNTER terminology because the existing __COUNTER__
> is a symbol whose value changes each time it is mentioned,
> These symbols are not like that; they capture a fixed value in
> a scope and behave like ordinary macros.
>
> In doing the renaming, I noticed that from the beginning I've already
> been calling the internal value in the macro context macro->exp_number,
> because it's not a counter.
>
> The focus of this feature isn't to enable some new "earth-shattering"
> techniques, but to improve certain situations in existing macros.
>
> For instance, suppose we have a macro that expands to some block
> of code in which there is an internal goto. If we have it
>
> #define MAC(...) { ... goto _label; ... __label: ; }
>
> then this cannot be used twice in the same function; labels have
> function scope.
In this case why can't you use gcc's already extension of defining a local
label?
https://gcc.gnu.org/onlinedocs/gcc-13.2.0/gcc/Local-Labels.html
This extension has been around for over 20 years specifically for that use
case.
Thanks,
Andrew
If we make it
>
> #define MAC(...) { ... goto CAT(__label, __LINE__); ... CAT(__label,
> __LINE__): ; }
>
> we now can use MAC two or more times in the same function, but not in
> the same line of code.
>
> With __EXPANSION_NUMBER__ it is doable. Given this program:
>
> #define xcat(A, B) A ## B
> #define cat(A, B) xcat(A, B)
> #define lab(PREFIX) cat(PREFIX, __PARENT_EXPANSION_NUMBER__)
>
> #define MAC { goto lab(foo); /*...*/ lab(foo): ; }
>
> MAC MAC MAC
>
> We get the preprocessed output (with -E):
>
> { goto foo3; foo3: ; } { goto foo10; foo10: ; } { goto foo17; foo17: ; }
>
> There are issues with relying on __LINE__ to produce different values
> when it is referenced in code generated by a macro.
>
> The following program prints the same value 12 three times; even though
> PRINT seems to be referenced on different physical lines in the
> PRINT3 macro replacement text. __LINE__ references the line where
> the top-level expansion of PRINT3 occurs, not where PRINT occurs.
>
> #include <stdio.h>
>
> #define PRINT (printf("%d\n", __LINE__))
>
> #define PRINT3 do { \
> PRINT; \
> PRINT; \
> PRINT; \
> } while (0)
>
> int main()
> {
> PRINT3;
> return 0;
> }
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] cpp: new built-in __EXP_COUNTER__
2024-03-22 1:40 ` Andrew Pinski
@ 2024-03-22 6:03 ` Kaz Kylheku
0 siblings, 0 replies; 10+ messages in thread
From: Kaz Kylheku @ 2024-03-22 6:03 UTC (permalink / raw)
To: Andrew Pinski; +Cc: Bernhard Reutner-Fischer, GCC Patches, Jonathan Wakely
[-- Attachment #1: Type: text/plain, Size: 1277 bytes --]
On 2024-03-21 18:40, Andrew Pinski wrote:
On Thu, Mar 21, 2024, 17:20 Kaz Kylheku <kaz@kylheku.com> wrote: For instance, suppose we have a macro that expands to some block
of code in which there is an internal goto. If we have it
#define MAC(...) { ... goto _label; ... __label: ; }
then this cannot be used twice in the same function; labels have
function scope.
In this case why can't you use gcc's already extension of defining a local label?
https://gcc.gnu.org/onlinedocs/gcc-13.2.0/gcc/Local-Labels.html
This extension has been around for over 20 years specifically for that use case.
Yes. For that case, local labels are a nice solution.
It's just an example of the sort of thing for which it may be useful
for a macro to be able to invent different identifiers in different invocations.
The GNU preprocessor is used for multiple languages, and is also exposed
as an independent utility that can be used to process anything that has
a sufficiently C-like token structure.
Since local labels are intended for macros, they are not subject to
diagnosis by -Wshadow. In the ordinary namespace for
variables/functions/typedefs, there is no such concession. Macros
that reuse identifiers in nested scopes will trigger nuisance warnings
from -Wshadow.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2024-03-22 6:03 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-21 11:31 [PATCH] cpp: new built-in __EXP_COUNTER__ Kaz Kylheku
2024-03-18 7:30 ` Jonathan Wakely
2024-03-18 7:32 ` Jonathan Wakely
2024-03-18 16:39 ` Kaz Kylheku
2024-03-18 19:28 ` Jonathan Wakely
2024-03-19 17:27 ` Kaz Kylheku
2024-03-20 23:34 ` rep.dot.nop
2024-03-22 0:18 ` Kaz Kylheku
2024-03-22 1:40 ` Andrew Pinski
2024-03-22 6:03 ` Kaz Kylheku
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).