From patchwork Thu Apr 21 11:31:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kaz Kylheku X-Patchwork-Id: 1620086 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=FIQPIbK7; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4Kkb4W3YX0z9sDX for ; Thu, 21 Apr 2022 21:32:42 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 660643834685 for ; Thu, 21 Apr 2022 11:32:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 660643834685 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1650540759; bh=Befcl8pLP/oa/6UUagD+5BNzrWVR2lf99gcGTvg1kOg=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=FIQPIbK7hb/kFx6iYROg8Udpn6TQeVwkT4/i0F0zWhQQpD5GGrZluAUqvc8hb4f87 cLPeCLBOOf7EO7gM1FPWrOwcwApkN2iGHzmXwenaTKkK4oV7VbfMEU1oKCAWqI9Vww ggOt5Y2OzdEYuYORN5HMGfLQ60MKORCDQOAn3Cco= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from omta002.cacentral1.a.cloudfilter.net (omta002.cacentral1.a.cloudfilter.net [3.97.99.33]) by sourceware.org (Postfix) with ESMTPS id F0B363839428 for ; Thu, 21 Apr 2022 11:31:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org F0B363839428 Received: from shw-obgw-4004a.ext.cloudfilter.net ([10.228.9.227]) by cmsmtp with ESMTP id hJlanSp5jgTZYhV2Nn0Doh; Thu, 21 Apr 2022 11:31:51 +0000 Received: from kylheku.com ([70.79.182.7]) by cmsmtp with ESMTPA id hV2MnAdnEd7RfhV2MnZ0aj; Thu, 21 Apr 2022 11:31:51 +0000 X-Authority-Analysis: v=2.4 cv=XrLphHJ9 c=1 sm=1 tr=0 ts=626140a7 a=pMSlDXUwMa7SJ1EIez8PdQ==:117 a=pMSlDXUwMa7SJ1EIez8PdQ==:17 a=xqWC_Br6kY4A:10 a=kj9zAlcOel0A:10 a=z0gMJWrwH1QA:10 a=2KUf1mbJAAAA:8 a=VnNF1IyMAAAA:8 a=lzDhS8hmAAAA:8 a=kD1XsaznVpbMYTJ4ggYA:9 a=CjuIK1q_8ugA:10 a=LME9DoRMzU6P72L8X6EC:22 a=rigQk1bY_8VmChEzA3fK:22 Received: from localhost ([::1] helo=mail.kylheku.com) by kylheku.com with esmtp (Exim 4.94.2) (envelope-from ) id 1nhV2K-0054pi-DI for gcc-patches@gcc.gnu.org; Thu, 21 Apr 2022 04:31:48 -0700 MIME-Version: 1.0 Date: Thu, 21 Apr 2022 04:31:48 -0700 To: gcc-patches@gcc.gnu.org Subject: [PATCH] cpp: new built-in __EXP_COUNTER__ User-Agent: Roundcube Webmail/1.4.13 Message-ID: X-Sender: kaz@kylheku.com X-CMAE-Envelope: MS4xfP5+rIY775TYV0srAGKZBdwmA4zwsVsyRBEHuGlnnG6/ZSNqSCQj7SySsGr0nmYPIKJPqqYfwXD0MNKDreeJrLBnKHqf5HnYrKuZma3gN+igx4DliXa1 OmelKOlfii5LTP7xg9jKang4PPoxg15PNKVsTleZVFX7EAcZrfj4B6QgpP/27yVDl38ET/WpQmH/iA== X-Spam-Status: No, score=-8.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Kaz Kylheku via Gcc-patches From: Kaz Kylheku Reply-To: Kaz Kylheku Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" libcpp/ChangeLog 2022-04-21 Kaz Kylheku 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 * 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 --- 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); 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 + + * 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 * 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 +#include + +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 +#include + +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 +#include + +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 +#include + +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 + + 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 * 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. */