Fix expansion point loc for macro-like tokens
authorDodji Seketeli <dodji@redhat.com>
Mon, 30 Apr 2012 11:41:46 +0000 (11:41 +0000)
committerDodji Seketeli <dodji@gcc.gnu.org>
Mon, 30 Apr 2012 11:41:46 +0000 (13:41 +0200)
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

gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-5.c
gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-6.c
libcpp/ChangeLog
libcpp/macro.c

index c7f6419c652ace56228aa10728e8ba0e6a306504..ed2779e83ad780e452601bda7e73a78ee1f4e58a 100644 (file)
@@ -1,5 +1,9 @@
 2012-04-30  Dodji Seketeli  <dodji@redhat.com>
 
+       Fix expansion point loc for macro-like tokens
+       * gcc.dg/debug/dwarf2/pr41445-5.c: Adjust.
+       * gcc.dg/debug/dwarf2/pr41445-6.c: Likewise.
+
        Fix token pasting with -ftrack-macro-expansion
        * gcc.dg/cpp/paste17.c: New test case for
        -ftrack-macro-expansion=2 mode only.
index 03af604a7c0a374225ba1cda7ca2ac61f33e85fe..d21acd5aba98c704dfac35427ff58f9da5753f40 100644 (file)
@@ -9,6 +9,9 @@
 #define B , varj
 int A(B) ;
 
-/* { dg-final { scan-assembler "DW_TAG_variable\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\"vari\[^\\r\\n\]*DW_AT_name(\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*DW_AT_)*\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\[^0-9a-fA-FxX](0x)?7\[^0-9a-fA-FxX]\[^\\r\\n\]*DW_AT_decl_line" } } */
+/*  We want to check that both vari and varj have the same line
+    number.  */
+
+/* { dg-final { scan-assembler "DW_TAG_variable\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\"vari\[^\\r\\n\]*DW_AT_name(\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*DW_AT_)*\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\[^0-9a-fA-FxX](0xa|10)\[^0-9a-fA-FxX]\[^\\r\\n\]*DW_AT_decl_line" } } */
 /* { dg-final { scan-assembler "DW_TAG_variable\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\"varj\[^\\r\\n\]*DW_AT_name(\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*DW_AT_)*\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\[^0-9a-fA-FxX](0xa|10)\[^0-9a-fA-FxX]\[^\\r\\n\]*DW_AT_decl_line" } } */
 /* { dg-final { cleanup-saved-temps } } */
index 8aa37d1c1a67cb164277944254b2c83df7befcb3..d6d79ccc46969fbdf3d0f16ccc1699c5b4ad4078 100644 (file)
@@ -4,5 +4,8 @@
 
 #include "pr41445-5.c"
 
-/* { dg-final { scan-assembler "DW_TAG_variable\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\"vari\[^\\r\\n\]*DW_AT_name(\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*DW_AT_)*\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\[^0-9a-fA-FxX](0x)?7\[^0-9a-fA-FxX]\[^\\r\\n\]*DW_AT_decl_line" } } */
+/*  We want to check that both vari and varj have the same line
+    number.  */
+
+/* { dg-final { scan-assembler "DW_TAG_variable\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\"vari\[^\\r\\n\]*DW_AT_name(\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*DW_AT_)*\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\[^0-9a-fA-FxX](0xa|10)?\[^0-9a-fA-FxX]\[^\\r\\n\]*DW_AT_decl_line" } } */
 /* { dg-final { scan-assembler "DW_TAG_variable\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\"varj\[^\\r\\n\]*DW_AT_name(\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*DW_AT_)*\[^\\r\\n\]*\[\\r\\n\]+\[^\\r\\n\]*\[^0-9a-fA-FxX](0xa|10)\[^0-9a-fA-FxX]\[^\\r\\n\]*DW_AT_decl_line" } } */
index 189f394418e266d3d4caed523ce106017de52e5a..5e93396ac7536adb41a108bdfc4020949b73ca4f 100644 (file)
@@ -1,5 +1,13 @@
 2012-04-30  Dodji Seketeli  <dodji@redhat.com>
 
+       Fix expansion point loc for macro-like tokens
+       * 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.
+
        Fix token pasting with -ftrack-macro-expansion
        * macro.c (paste_all_tokens): Put the token resulting from pasting
        into an extended token context with -ftrack-macro-location is in
index f4638c49cd99f0e418ac8e3cad862ffaf5e98c69..ab3e8f641dca31093780b0941f9cca2664394d63 100644 (file)
@@ -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;
     }