diff mbox series

[WIP] PR71102: Make #pragma GCC error/warning concat strings

Message ID 621f37aa-1ac5-05aa-674b-0d387bece69a@redhat.com
State New
Headers show
Series [WIP] PR71102: Make #pragma GCC error/warning concat strings | expand

Commit Message

Stephan Bergmann Sept. 30, 2019, 3:16 p.m. UTC
(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 mbox series

Patch

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);