PR preprocessor/79210 identifies a ICE due to a failing assertion within get_substring_ranges_for_loc when re-lexing strings, due to the wrong location being used for a string token.
The root cause of the bogus string location is due to (A) a bogus location being generated when pasting together two tokens during macro expansion. This bogus location gets inherited by subsequent temporary tokens during the expansion, including (B) that of a stringized macro argument - the assertion failure happens when attempting to re-lex the string token obtained from this stringized macro argument, used within a string concatenation. It doesn't appear possible to give (A) a full source_location/location_t since such a value can only cover one range (rather than the multiple ranges involved in pasted tokens). The location of (B) could perhaps be addressed by giving the stringized token the location of the macro argument. However, this would not address the issue with re-lexing the string, which expects C/C++ syntax (quotes, etc). So the simplest fix at stage 4 is to convert the assertion into an error-checking conditional, so that when this situation occurs, we don't provide a location_t within the string, and instead fail gracefully by providing the location for the start of the string. Successfully bootstrapped®rtested on x86_64-pc-linux-gnu. Committed to trunk as r245070. gcc/ChangeLog: PR preprocessor/79210 * input.c (get_substring_ranges_for_loc): Replace line_width assertion with error-handling. gcc/testsuite/ChangeLog: PR preprocessor/79210 * gcc.dg/format/pr79210.c: New test case. * gcc.dg/plugin/diagnostic-test-string-literals-2.c (test_pr79210): New function. --- gcc/input.c | 5 ++++- gcc/testsuite/gcc.dg/format/pr79210.c | 23 ++++++++++++++++++++++ .../plugin/diagnostic-test-string-literals-2.c | 23 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/format/pr79210.c diff --git a/gcc/input.c b/gcc/input.c index 3e67314..38deb62 100644 --- a/gcc/input.c +++ b/gcc/input.c @@ -1395,7 +1395,10 @@ get_substring_ranges_for_loc (cpp_reader *pfile, const char *literal = line + start.column - 1; int literal_length = finish.column - start.column + 1; - gcc_assert (line_width >= (start.column - 1 + literal_length)); + /* Ensure that we don't crash if we got the wrong location. */ + if (line_width < (start.column - 1 + literal_length)) + return "line is not wide enough"; + cpp_string from; from.len = literal_length; /* Make a copy of the literal, to avoid having to rely on diff --git a/gcc/testsuite/gcc.dg/format/pr79210.c b/gcc/testsuite/gcc.dg/format/pr79210.c new file mode 100644 index 0000000..71f5dd6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/format/pr79210.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-Wformat -Wformat-signedness" } */ + +__attribute__((format(printf, 3, 4))) +void dev_printk(const char *level, void *dev, const char *fmt, ...); + +#define lpfc_vport_param_init(attr) \ +void lpfc_##attr##_init(void *vport, unsigned int val) \ +{ \ + dev_printk("3", (void *)0, \ + "0423 lpfc_"#attr" attribute cannot be set to %d, "\ + "allowed range is [0, 1]\n", val); \ +} + +#define LPFC_VPORT_ATTR_R(name, desc) \ +unsigned int lpfc_##name;\ +lpfc_vport_param_init(name)\ + +LPFC_VPORT_ATTR_R(peer_port_login, + "Allow peer ports on the same physical port to login to each " + "other."); + +/* { dg-warning "6: format .%d. expects argument of type .int., but argument 4 has type .unsigned int. " "" { target *-*-* } .-12 } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-2.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-2.c index 25cb3f0..e916b93 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-2.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-2.c @@ -51,3 +51,26 @@ test_stringified_token_3 (int x) #undef FOO } +/* Test of a stringified macro argument within a concatenation. */ + +void +test_pr79210 (void) +{ +#define lpfc_vport_param_init(attr) \ + __emit_string_literal_range ( \ + "0423 lpfc_"#attr" attribute cannot be set to %d, "\ + "allowed range is [0, 1]\n", 54, 53, 54) \ + +#define LPFC_VPORT_ATTR_R(name, decc) \ + unsigned int lpfc_##name; \ + lpfc_vport_param_init(name) \ + + LPFC_VPORT_ATTR_R(peer_port_login, + "some multiline blurb with a short final line " + "here"); + + /* { dg-error "19: unable to read substring location: line is not wide enough" "" { target *-*-* } .-11 } */ + +#undef LPFC_VPORT_ATTR_R +#undef lpfc_vport_param_init +} -- 1.8.5.3