On Tue, Sep 29, 2026 at 04:58:39PM -0300, Léo Hardt wrote:
> I'm currently trying to look into libcpp more deeply
> before submitting a patch to fix it and break another
> behaviour again.

I have looked at it more closely today and I think we should
go for the following patch (thouch so far just lightly tested
with
GXX_TESTSUITE_STDS=98,11,14,17,20,23,26,29 make check-gcc check-g++ -j32 -k 
RUNTESTFLAGS="dg.exp='cpp/*' cpp.exp gomp.exp"
and will test it properly overnight).

I'm guilty of introducing _cpp_get_token_no_padding 6 years ago
instead of fixing up get_token_no_padding back then, I wasn't
sure if the eating of CPP_EOF wasn't intentional in some cases,
but clearly it is never intentional and always a bug.
After all, get__Pragma_string has been fighting with it already
by using
  paren = get_token_no_padding (pfile);
  if (paren->type == CPP_EOF)
    _cpp_backup_tokens (pfile, 1);
glue_header_name and parse_include weren't doing this, but in
the usual case when pfile->state.in_directive and not lexing a raw string,
get_fresh_line_impl returns false and _cpp_lex_direct will just keep
returning CPP_EOF at the end of the line many times until we clear
the pfile->state.in_directive flag.
So, I think we should just drop the dangerous get_token_no_padding
function and simply never eat a CPP_EOF.

2026-09-30  Jakub Jelinek  <[email protected]>

        PR preprocessor/121508
        PR preprocessor/123339
        * macro.cc (builtin_has_include_1): Revert 2026-09-21 changes.
        * directives.cc (get_token_no_padding): Remove.
        (glue_header_name): Use _cpp_get_token_no_padding instead of
        get_token_no_padding.
        (parse_include): Likewise.
        (get__Pragma_string): Likewise.  Don't _cpp_backup_tokens on
        CPP_EOF.

        * c-c++-common/cpp/pr121508-1.c: New test.
        * c-c++-common/cpp/pr121508-2.c: New test.
        * c-c++-common/cpp/pr121508-3.c: New test.
        * c-c++-common/cpp/pr121508-4.c: New test.
        * c-c++-common/cpp/pr121508-5.c: New test.
        * c-c++-common/cpp/pr123339.c: New test.
        * c-c++-common/gomp/has-include-1.c: Remove spurious extra
        dg-error.

--- a/libcpp/macro.cc   2026-09-22 14:57:44.997568673 +0200
+++ b/libcpp/macro.cc   2026-09-30 17:14:54.626852363 +0200
@@ -392,11 +392,8 @@ builtin_has_include_1 (cpp_reader *pfile
                       bool *bracket, location_t *loc)
 {
   if (!pfile->state.in_directive)
-    {
-      cpp_error (pfile, CPP_DL_ERROR,
-                "%qs used outside of preprocessing directive", name);
-      return NULL;
-    }
+    cpp_error (pfile, CPP_DL_ERROR,
+              "%qs used outside of preprocessing directive", name);
 
   pfile->state.angled_headers = true;
   const auto sav_padding = pfile->state.directive_wants_padding;
--- a/libcpp/directives.cc      2026-06-30 09:21:02.004032964 +0200
+++ b/libcpp/directives.cc      2026-09-30 17:16:59.272223581 +0200
@@ -131,7 +131,6 @@ static void do_pragma_warning_or_error (
 static void do_pragma_warning (cpp_reader *);
 static void do_pragma_error (cpp_reader *);
 static void do_linemarker (cpp_reader *);
-static const cpp_token *get_token_no_padding (cpp_reader *);
 static const cpp_token *get__Pragma_string (cpp_reader *);
 static void destringize_and_run (cpp_reader *, const cpp_string *,
                                 location_t);
@@ -825,7 +824,7 @@ glue_header_name (cpp_reader *pfile)
   buffer = XNEWVEC (char, capacity);
   for (;;)
     {
-      token = get_token_no_padding (pfile);
+      token = _cpp_get_token_no_padding (pfile);
 
       if (token->type == CPP_GREATER)
        break;
@@ -868,7 +867,7 @@ parse_include (cpp_reader *pfile, int *p
   const cpp_token *header;
 
   /* Allow macro expansion.  */
-  header = get_token_no_padding (pfile);
+  header = _cpp_get_token_no_padding (pfile);
   *location = header->src_loc;
   if ((header->type == CPP_STRING && header->val.str.text[0] != 'R')
       || header->type == CPP_HEADER_NAME)
@@ -2399,18 +2398,6 @@ do_pragma_error (cpp_reader *pfile)
   do_pragma_warning_or_error (pfile, true);
 }
 
-/* Get a token but skip padding.  */
-static const cpp_token *
-get_token_no_padding (cpp_reader *pfile)
-{
-  for (;;)
-    {
-      const cpp_token *result = cpp_get_token (pfile);
-      if (result->type != CPP_PADDING)
-       return result;
-    }
-}
-
 /* Check syntax is "(string-literal)".  Returns the string on success,
    or NULL on failure.  */
 static const cpp_token *
@@ -2419,23 +2406,17 @@ get__Pragma_string (cpp_reader *pfile)
   const cpp_token *string;
   const cpp_token *paren;
 
-  paren = get_token_no_padding (pfile);
-  if (paren->type == CPP_EOF)
-    _cpp_backup_tokens (pfile, 1);
+  paren = _cpp_get_token_no_padding (pfile);
   if (paren->type != CPP_OPEN_PAREN)
     return NULL;
 
-  string = get_token_no_padding (pfile);
-  if (string->type == CPP_EOF)
-    _cpp_backup_tokens (pfile, 1);
+  string = _cpp_get_token_no_padding (pfile);
   if (string->type != CPP_STRING && string->type != CPP_WSTRING
       && string->type != CPP_STRING32 && string->type != CPP_STRING16
       && string->type != CPP_UTF8STRING)
     return NULL;
 
-  paren = get_token_no_padding (pfile);
-  if (paren->type == CPP_EOF)
-    _cpp_backup_tokens (pfile, 1);
+  paren = _cpp_get_token_no_padding (pfile);
   if (paren->type != CPP_CLOSE_PAREN)
     return NULL;
 
--- a/gcc/testsuite/c-c++-common/cpp/pr121508-1.c       2026-09-30 
17:33:01.408134587 +0200
+++ b/gcc/testsuite/c-c++-common/cpp/pr121508-1.c       2026-09-30 
17:35:20.608302408 +0200
@@ -0,0 +1,8 @@
+/* PR preprocessor/121508 */
+/* { dg-do compile } */
+
+/* { dg-error "'__has_include' used outside of preprocessing directive" "" { 
target *-*-* } .+4 } */
+/* { dg-error "missing terminating '>' character" "" { target *-*-* } .+3 } */
+/* { dg-error "missing '\\\)' after '__has_include' operand" "" { target *-*-* 
} .+2 } */
+/* { dg-error "expected ',' or ';' at end of input" "" { target *-*-* } .+1 } 
*/
+int i = __has_include(<__int16_t
--- a/gcc/testsuite/c-c++-common/cpp/pr121508-2.c       2026-09-30 
17:35:44.069995285 +0200
+++ b/gcc/testsuite/c-c++-common/cpp/pr121508-2.c       2026-09-30 
17:35:50.710908351 +0200
@@ -0,0 +1,8 @@
+/* PR preprocessor/121508 */
+/* { dg-do compile } */
+
+/* { dg-error "'__has_include' used outside of preprocessing directive" "" { 
target *-*-* } .+4 } */
+/* { dg-error "missing terminating '>' character" "" { target *-*-* } .+3 } */
+/* { dg-error "missing '\\\)' after '__has_include' operand" "" { target *-*-* 
} .+2 } */
+/* { dg-error "expected ',' or ';' at end of input" "" { target *-*-* } .+1 } 
*/
+int i = __has_include(<__int16_t)
--- a/gcc/testsuite/c-c++-common/cpp/pr121508-3.c       2026-09-30 
17:36:24.451466665 +0200
+++ b/gcc/testsuite/c-c++-common/cpp/pr121508-3.c       2026-09-30 
17:37:44.423419790 +0200
@@ -0,0 +1,8 @@
+/* PR preprocessor/121508 */
+/* { dg-do compile } */
+
+/* { dg-error "'__has_embed' used outside of preprocessing directive" "" { 
target *-*-* } .+4 } */
+/* { dg-error "missing terminating '>' character" "" { target *-*-* } .+3 } */
+/* { dg-error "expected '\\\)'" "" { target *-*-* } .+2 } */
+/* { dg-error "expected ',' or ';' at end of input" "" { target *-*-* } .+1 } 
*/
+int i = __has_embed(<__int16_t
--- a/gcc/testsuite/c-c++-common/cpp/pr121508-4.c       2026-09-30 
17:36:28.291416400 +0200
+++ b/gcc/testsuite/c-c++-common/cpp/pr121508-4.c       2026-09-30 
17:38:09.061097270 +0200
@@ -0,0 +1,8 @@
+/* PR preprocessor/121508 */
+/* { dg-do compile } */
+
+/* { dg-error "'__has_embed' used outside of preprocessing directive" "" { 
target *-*-* } .+4 } */
+/* { dg-error "missing terminating '>' character" "" { target *-*-* } .+3 } */
+/* { dg-error "expected '\\\)'" "" { target *-*-* } .+2 } */
+/* { dg-error "expected ',' or ';' at end of input" "" { target *-*-* } .+1 } 
*/
+int i = __has_embed(<__int16_t)
--- a/gcc/testsuite/c-c++-common/cpp/pr121508-5.c       2026-09-30 
17:36:40.743253399 +0200
+++ b/gcc/testsuite/c-c++-common/cpp/pr121508-5.c       2026-09-30 
17:38:19.264963696 +0200
@@ -0,0 +1,8 @@
+/* PR preprocessor/121508 */
+/* { dg-do compile } */
+
+/* { dg-error "'__has_embed' used outside of preprocessing directive" "" { 
target *-*-* } .+4 } */
+/* { dg-error "missing terminating '>' character" "" { target *-*-* } .+3 } */
+/* { dg-error "expected '\\\)'" "" { target *-*-* } .+2 } */
+/* { dg-error "expected ',' or ';' at end of input" "" { target *-*-* } .+1 } 
*/
+int i = __has_embed(<__int16_t + 1 + 2 + 3
--- a/gcc/testsuite/c-c++-common/cpp/pr123339.c 2026-09-30 17:39:05.715355636 
+0200
+++ b/gcc/testsuite/c-c++-common/cpp/pr123339.c 2026-09-30 17:41:50.798194604 
+0200
@@ -0,0 +1,9 @@
+/* PR preprocessor/123339 */
+/* { dg-do compile } */
+
+/* { dg-error "'__has_include' used outside of preprocessing directive" "" { 
target *-*-* } .+5 } */
+/* { dg-error "missing terminating '>' character" "" { target *-*-* } .+4 } */
+/* { dg-error "missing '\\\(' before '__has_include' operand" "" { target 
*-*-* } .+3 } */
+/* { dg-error "expected identifier or '\\\(' before numeric constant" "" { 
target c } .+2 } */
+/* { dg-error "expected unqualified-id before numeric constant" "" { target 
c++ } .+1 } */
+__has_include <"foo"
--- a/gcc/testsuite/c-c++-common/gomp/has-include-1.c   2026-09-22 
14:57:44.990568766 +0200
+++ b/gcc/testsuite/c-c++-common/gomp/has-include-1.c   2026-09-30 
17:26:36.987118699 +0200
@@ -4,6 +4,5 @@ void
 foo (void)
 {
 #pragma omp parallel if (__has_include ("<stdlib.h>")) /* { dg-error "used 
outside of preprocessing directive" } */
-/* { dg-error "a function" "" { target *-*-* } .-1 } */
   ;
 }


        Jakub

Reply via email to