(I think this is my first patch submission here, so please bear with me.)

As discussed at <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71102> "_Pragma("GCC warning ...") should concatenate string literals", it would be useful if #pragma GCC error/warning behaved like #pragma message and consumed multiple (macro-expanded) string literal tokens.

The below patch gets close, but:

* I don't know how to get a location_t that spans all the tokens, see the TODO in the patch. (If that's hard to get right, an alternative might be to instead highlight the "error" resp. "warning" token, in the same way as #pragma message highlights the "message" token.)

* Additional tokens that are not (ordinary) string literals keep being ignored (to be exact, the first such non--string-literal and all remaining tokens are ignored). That's in line with existing behavior for those pragmas, where they ignored everything following the first (necessarily string-literal) token (but unlike #pragma message, which emits "warning: junk at end of '#pragma message' [-Wpragmas]"). Something of a corner case happens when such a non--string-literal token is the result of macro expansion as in

  #define FOO "2" 3
  #pragma GCC error "1" FOO

emitting a message of "12". (My naive understanding of how cpp_get_token works in do_pragma_warnign_or_error is that the end of the #pragma line is represented by a CPP_EOF token.)

* I have left the documentation in gcc/doc/extend.texi alone, as it didn't specify any details of how the #pragma message string is parsed, either.


diff --git a/gcc/testsuite/c-c++-common/cpp/diagnostic-pragma-1.c b/gcc/testsuite/c-c++-common/cpp/diagnostic-pragma-1.c
index 9867c94a8dd..53bae44e210 100644
--- a/gcc/testsuite/c-c++-common/cpp/diagnostic-pragma-1.c
+++ b/gcc/testsuite/c-c++-common/cpp/diagnostic-pragma-1.c
@@ -9,3 +9,6 @@
 char a[CONST1]; // { dg-warning warn-c }
 char b[CONST2]; // { dg-error err-d }

+#define EXPAND "exp-"
+#pragma GCC warning "warn-" EXPAND "e" // { dg-warning warn-exp-e }
+#pragma GCC error "err-" EXPAND "f" // { dg-error err-exp-f }
diff --git a/libcpp/directives.c b/libcpp/directives.c
index 61f1fef9489..4d06a2d2934 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -1740,19 +1740,49 @@ do_pragma_dependency (cpp_reader *pfile)
 static void
 do_pragma_warning_or_error (cpp_reader *pfile, bool error)
 {
-  const cpp_token *tok = _cpp_lex_token (pfile);
+  size_t count = 0;
+  obstack str_ob;
+  obstack_specify_allocation (&str_ob, 0, 0, xmalloc, free);
+  location_t loc;
+  location_t loc_end;
+  gcc_assert (pfile->state.prevent_expansion > 0);
+  pfile->state.prevent_expansion--;
+  for (;; ++count)
+    {
+      const cpp_token *tok = cpp_get_token (pfile);
+      if (tok->type != CPP_STRING)
+       break;
+      if (count == 0)
+       loc = tok->src_loc;
+      obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string));
+      loc_end = tok->src_loc;
+    }
+  pfile->state.prevent_expansion++;
+  if (count == 0)
+    {
+ cpp_error (pfile, CPP_DL_ERROR, "invalid \"#pragma GCC %s\" directive",
+                error ? "error" : "warning");
+      return;
+    }
+  cpp_string * strs = (cpp_string *) obstack_finish (&str_ob);
   cpp_string str;
-  if (tok->type != CPP_STRING
-      || !cpp_interpret_string_notranslate (pfile, &tok->val.str, 1, &str,
-                                           CPP_STRING)
-      || str.len == 0)
+  bool combine = cpp_interpret_string_notranslate (pfile, strs, count,
+                                                  &str, CPP_STRING);
+  obstack_free (&str_ob, 0);
+  if (!combine || str.len == 0)
     {
cpp_error (pfile, CPP_DL_ERROR, "invalid \"#pragma GCC %s\" directive",
                 error ? "error" : "warning");
       return;
     }
-  cpp_error (pfile, error ? CPP_DL_ERROR : CPP_DL_WARNING,
-            "%s", str.text);
+  if (count != 1)
+    {
+      //TODO: combine loc, loc_end into
+      // loc = COMBINE_LOCATION_DATA (pfile->line_table, ..., ..., NULL);
+      (void)loc_end;
+    }
+  cpp_error_at (pfile, error ? CPP_DL_ERROR : CPP_DL_WARNING, loc,
+               "%s", str.text);
   free ((void *)str.text);
 }

Reply via email to