summaryrefslogtreecommitdiff
path: root/libcpp/macro.c
diff options
context:
space:
mode:
authorDodji Seketeli <dodji@redhat.com>2012-04-30 11:41:46 +0000
committerDodji Seketeli <dodji@gcc.gnu.org>2012-04-30 13:41:46 +0200
commit3600218c8ba558bf5ac3a5f7697dbc8f512099e7 (patch)
tree893dd585aa96874cc48af67d835d42819344b45b /libcpp/macro.c
parent163fa1ebbaa850de13fae527fdc921fd59535eec (diff)
Fix expansion point loc for macro-like tokens
Consider the test case gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-5.c. Its interesting part is: #define A(x) vari x /* line 7. */ #define vari(x) #define B , varj int A(B) ; /* line 10. */ In its initial version, this test was being pre-processed as: # 1 "gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-5.c" # 1 "build/gcc//" # 1 "<command-line>" # 1 "gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-5.c" # 10 "gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-5.c" int # 7 "gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-5.c" vari , varj ; Note how "int" and "vari" are on separate lines, whereas "int" and ", varj" are on the same line. This looks like a bug to me, even independantly from the macro location tracking work. With macro location tracking turned on, the preprocessed output becomes: # 1 "gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-5.c" # 1 "<command-line>" # 1 "gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-5.c" # 10 "gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-5.c" int vari , varj ; Which, IMO, is what we'd expect. This is due to an unexpected side effect of enter_macro_context when passed a token that might look like a function-like macro at first sight, but that it eventually considers to not be a macro after all. This is the case for the "vari" token which looks like a macro when it is first lexed, but is eventually considered to be a normal token by enter_macro_context because it's not used as a function-like macro invocation. In that case, besides returning NULL, enter_macro_context sets pfile->context->c.macro to NULL, making cpp_get_token_1 forget to set the location of the "vari" to the expansion point of A. enter_macro_context sets pfile->context->c.macro to NULL in that case because funlike_invocation_p reads one token pass "foo", sees that there is no '(' token, so we are not invoking the function-like parameter. It then puts the tokens (which it has read after "foo") back into the tokens stream by calling _cpp_push_token_context on it, which sets pfile->context->c.macro to NULL, saying in essence that the current macro expansion context is "stopped". The fix here is to teach _cpp_push_token and push_extended_tokens_context to continue the current macro context when passed a NULL macro. But then, now that there can be several continguous contexts associated with the same macro, we need to teach _cpp_pop_context to re-enable the expansion of the current macro only when we are really out of expanding the current macro. Otherwise we can run in cases where we have recursive expansions of the same macro. Tested on x86_64-unknown-linux-gnu against trunk. Now this test has the same output with and without tracking locations accross macro expansions. Note that the bootstrap with -ftrack-macro-expansion exhibits other separate issues that are addressed in subsequent patches. This patch just fixes one class of problems. The patch does pass bootstrap with -ftrack-macro-expansion turned off, though. libcpp/ * macro.c (macro_of_context): New static function. (_cpp_push_token_context, push_extended_tokens_context): If the macro argument is NULL, it means we are continuing the expansion of the current macro, if any. Update comments. (_cpp_pop_context): Re-enable expansion of the macro only when we are really out of the context of the current expansion. gcc/testsuite/ * gcc.dg/debug/dwarf2/pr41445-5.c: Adjust. * gcc.dg/debug/dwarf2/pr41445-6.c: Likewise. From-SVN: r186968
Diffstat (limited to 'libcpp/macro.c')
-rw-r--r--libcpp/macro.c56
1 files changed, 48 insertions, 8 deletions
diff --git a/libcpp/macro.c b/libcpp/macro.c
index f4638c49cd9..ab3e8f641dc 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -165,6 +165,8 @@ static void consume_next_token_from_context (cpp_reader *pfile,
source_location *);
static const cpp_token* cpp_get_token_1 (cpp_reader *, source_location *);
+static cpp_hashnode* macro_of_context (cpp_context *context);
+
/* Statistical counter tracking the number of macros that got
expanded. */
unsigned num_expanded_macros_counter = 0;
@@ -1808,18 +1810,27 @@ push_ptoken_context (cpp_reader *pfile, cpp_hashnode *macro, _cpp_buff *buff,
LAST (context).ptoken = first + count;
}
-/* Push a list of tokens. */
+/* Push a list of tokens.
+
+ A NULL macro means that we should continue the current macro
+ expansion, in essence. That means that if we are currently in a
+ macro expansion context, we'll make the new pfile->context refer to
+ the current macro. */
void
_cpp_push_token_context (cpp_reader *pfile, cpp_hashnode *macro,
const cpp_token *first, unsigned int count)
{
- cpp_context *context = next_context (pfile);
-
+ cpp_context *context;
+
+ if (macro == NULL)
+ macro = macro_of_context (pfile->context);
+
+ context = next_context (pfile);
context->tokens_kind = TOKENS_KIND_DIRECT;
context->c.macro = macro;
context->buff = NULL;
- FIRST (context).token = first;
- LAST (context).token = first + count;
+ FIRST (context).token = first;
+ LAST (context).token = first + count;
}
/* Build a context containing a list of tokens as well as their
@@ -1827,7 +1838,12 @@ _cpp_push_token_context (cpp_reader *pfile, cpp_hashnode *macro,
contains the tokens pointed to by FIRST. If TOKENS_BUFF is
non-NULL, it means that the context owns it, meaning that
_cpp_pop_context will free it as well as VIRT_LOCS_BUFF that
- contains the virtual locations. */
+ contains the virtual locations.
+
+ A NULL macro means that we should continue the current macro
+ expansion, in essence. That means that if we are currently in a
+ macro expansion context, we'll make the new pfile->context refer to
+ the current macro. */
static void
push_extended_tokens_context (cpp_reader *pfile,
cpp_hashnode *macro,
@@ -1836,9 +1852,13 @@ push_extended_tokens_context (cpp_reader *pfile,
const cpp_token **first,
unsigned int count)
{
- cpp_context *context = next_context (pfile);
+ cpp_context *context;
macro_context *m;
+ if (macro == NULL)
+ macro = macro_of_context (pfile->context);
+
+ context = next_context (pfile);
context->tokens_kind = TOKENS_KIND_EXTENDED;
context->buff = token_buff;
@@ -2110,6 +2130,19 @@ expand_arg (cpp_reader *pfile, macro_arg *arg)
CPP_WTRADITIONAL (pfile) = saved_warn_trad;
}
+/* Returns the macro associated to the current context if we are in
+ the context a macro expansion, NULL otherwise. */
+static cpp_hashnode*
+macro_of_context (cpp_context *context)
+{
+ if (context == NULL)
+ return NULL;
+
+ return (context->tokens_kind == TOKENS_KIND_EXTENDED)
+ ? context->c.mc->macro_node
+ : context->c.macro;
+}
+
/* Pop the current context off the stack, re-enabling the macro if the
context represented a macro's replacement list. Initially the
context structure was not freed so that we can re-use it later, but
@@ -2146,7 +2179,14 @@ _cpp_pop_context (cpp_reader *pfile)
tokens is pushed just for the purpose of walking them using
cpp_get_token_1. In that case, no 'macro' field is set into
the dummy context. */
- if (macro != NULL)
+ if (macro != NULL
+ /* Several contiguous macro expansion contexts can be
+ associated to the same macro; that means it's the same
+ macro expansion that spans accross all these (sub)
+ contexts. So we should re-enable an expansion-disabled
+ macro only when we are sure we are really out of that
+ macro expansion. */
+ && macro_of_context (context->prev) != macro)
macro->flags &= ~NODE_DISABLED;
}