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