>From 62ab7123e73563b43f1833842a419aa66eca7ce2 Mon Sep 17 00:00:00 2001
From: Max T Woodbury <mtewoodb...@gmail.com>
Date: Mon, 23 Oct 2017 16:58:49 -0400

Copyright 2017 Max TenEyck Woodbury, Durham North Carolina
all rights assigned to the Free Software Foundation, Inc., 23 Oct 2017

The Problem:

    There is a problem associated with writing portable code; it is sometimes
desirable to change the string returned by the __FILE__ and related macros or
diagnostic messages.  The #line directive lets you do this.  The problem is that
the #line directive also changes the sequence numbers of subsequent lines and
that may be an unwanted side effect.  The obvious solution is to put a number
into the new line number slot of the directive that will leave the line number
sequencing unchanged.  This creates a maintenance issue: any changes to the
module that changes the number of lines before the #line directive ends will
require changing the line number value in the directive.
    You would think that this issue could be avoided by using the __LINE__ macro
to insert the proper number.  There are examples in the programming literature
that suggest exactly that.  Unfortunately an ambiguity in the interpreting the
standard makes the exact value generated by __LINE__ in the #line directive
implementation dependent.  One fairly obvious implementation has the pre-
processor collect the entire text of any directive together, including the '\n'
that ends the directive, before processing a directive.  Since some directives
suppress macro expansion, the expansion of the __LINE__ macro in a #line dir-
ective is postponed until the #line directive has been identified.  In that case
the __LINE__ macro expands to the number of the next input line, which is
exactly the value wanted.
    Unfortunately there is another way to proceed; in this alternative, the type
of directive is identified "on the fly" and directives that allow macro
expansion also do the macro expansions "on-the-fly".  This results in __LINE__
values for the #line directive itself instead of the number for the next line,
which changes the subsequent line sequence.

The solution:

    In the interest of portability, a special check has been added to the #line
directive implementation to see if the __LINE__ macro is being used to specify
the new line number.  If it is, a flag is set that suppresses the line number
change.
    Note that this solution is not robust; hiding the __LINE__ reference inside
another macro will bypass this special case test.

    Test cases have been added to the test suite to check this behavior.
---
 gcc/testsuite/ChangeLog          |  4 ++++
 gcc/testsuite/gcc.dg/cpp/line4.c |  7 +++++++
 libcpp/ChangeLog                 |  4 ++++
 libcpp/directives.c              | 12 ++++++++++++
 4 files changed, 27 insertions(+)

diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f14930b..a65328f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2017-10-22  Max T. Woodbury <mtewoodb...@gmail.com>
+
+    * gcc.dg/cpp/line4.c: New #line __LINE__ tests.
+
 2017-10-22  Uros Bizjak  <ubiz...@gmail.com>

    PR target/52451
diff --git a/gcc/testsuite/gcc.dg/cpp/line4.c b/gcc/testsuite/gcc.dg/cpp/line4.c
index 84dbf96..5902046 100644
--- a/gcc/testsuite/gcc.dg/cpp/line4.c
+++ b/gcc/testsuite/gcc.dg/cpp/line4.c
@@ -17,3 +17,10 @@ enum { j = __LINE__ };
 char array1[i        == 44 ? 1 : -1];
 char array2[j        == 90 ? 1 : -1];
 char array3[__LINE__ == 19 ? 1 : -1];
+
+#line __LINE__ /* N.B. this should not change the line sequence numbering.  */
+char array4[__LINE__ == 22 ? 1 : -1];
+#line __LINE__ /* N.B. extra lines in block comment should
+                  not change the line sequence numbering.  */
+char array5[__LINE__ == 25 ? 1 : -1];
+
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index f2c0d4d..31e1991 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,7 @@
+2017-10-23  Max T. Woodbury <mtewoodb...@gmail.com>
+
+    * directives.c: Added #line __LINE__ special case handling.
+
 2017-10-10  Nathan Sidwell  <nat...@acm.org>

    PR preprocessor/82506
diff --git a/libcpp/directives.c b/libcpp/directives.c
index 7cac653..a6243ac 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -964,6 +964,13 @@ do_line (cpp_reader *pfile)
   linenum_type cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767;
   bool wrapped;

+  /* #line __LINE__ should not change the line numbers. */
+  token = cpp_peek_token (pfile, 0);
+  bool no_change = (token->type == CPP_NAME &&
+                    token->val.node.node->type == NT_MACRO &&
+                    token->val.node.node->flags & NODE_BUILTIN &&
 char array1[i        == 44 ? 1 : -1];
 char array2[j        == 90 ? 1 : -1];
 char array3[__LINE__ == 19 ? 1 : -1];
+
+#line __LINE__ /* N.B. this should not change the line sequence numbering.  */
+char array4[__LINE__ == 22 ? 1 : -1];
+#line __LINE__ /* N.B. extra lines in block comment should
+                  not change the line sequence numbering.  */
+char array5[__LINE__ == 25 ? 1 : -1];
+
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index f2c0d4d..31e1991 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,7 @@
+2017-10-23  Max T. Woodbury <mtewoodb...@gmail.com>
+
+    * directives.c: Added #line __LINE__ special case handling.
+
 2017-10-10  Nathan Sidwell  <nat...@acm.org>

    PR preprocessor/82506
diff --git a/libcpp/directives.c b/libcpp/directives.c
index 7cac653..a6243ac 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -964,6 +964,13 @@ do_line (cpp_reader *pfile)
   linenum_type cap = CPP_OPTION (pfile, c99) ? 2147483647 : 32767;
   bool wrapped;

+  /* #line __LINE__ should not change the line numbers. */
+  token = cpp_peek_token (pfile, 0);
+  bool no_change = (token->type == CPP_NAME &&
+                    token->val.node.node->type == NT_MACRO &&
+                    token->val.node.node->flags & NODE_BUILTIN &&
+                    token->val.node.node->value.builtin == BT_SPECLINE);
+
   /* #line commands expand macros.  */
   token = cpp_get_token (pfile);
   if (token->type != CPP_NUMBER
@@ -1001,6 +1008,11 @@ do_line (cpp_reader *pfile)
     }

   skip_rest_of_line (pfile);
+  if (no_change)
+    {
+      const line_map_ordinary *map = LINEMAPS_LAST_ORDINARY_MAP
(pfile->line_table);
+      new_lineno = SOURCE_LINE (map, pfile->line_table->highest_line);
+    }
   _cpp_do_file_change (pfile, LC_RENAME_VERBATIM, new_file, new_lineno,
               map_sysp);
   line_table->seen_line_directive = true;
-- 
1.8.0.rc0.18.gf84667d

Reply via email to