Message ID | a790cf091d7fa1c57d4a823651888cda@kylheku.com |
---|---|
State | New |
Headers | show |
Series | cpp: new built-in __EXP_COUNTER__ | expand |
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.
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.
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.
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. >
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.
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
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; }
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; > } >
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.
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. */
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 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);