https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78304
--- Comment #5 from David Malcolm <dmalcolm at gcc dot gnu.org> --- More notes to self: The locations within the string_concat_db for this concatenation are all spelling locations, rather than virtual locations. The reason is that c-lex.c's lex_string calls cpp_get_token internally rather than cpp_get_token_with_location. I experimented with calling the latter, so that it captures the virtual location for e.g. PRIu32: --- a/gcc/c-family/c-lex.c +++ b/gcc/c-family/c-lex.c @@ -1150,6 +1157,7 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate) for the common case of just one string. */ cpp_string str = tok->val.str; location_t init_loc = tok->src_loc; + location_t virtual_loc; cpp_string *strs = &str; location_t *locs = NULL; @@ -1160,7 +1168,7 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate) bool objc_at_sign_was_seen = false; retry: - tok = cpp_get_token (parse_in); + tok = cpp_get_token_with_location (parse_in, &virtual_loc); switch (tok->type) { case CPP_PADDING: @@ -1203,7 +1211,7 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate) concats++; obstack_grow (&str_ob, &tok->val.str, sizeof (cpp_string)); - obstack_grow (&loc_ob, &tok->src_loc, sizeof (location_t)); + obstack_grow (&loc_ob, &virtual_loc, sizeof (location_t)); if (objc_string) objc_at_sign_was_seen = false; ...with that patch, we get the virtual loc encoded within the concat database. But then this within format_warning_va: fmt_loc.get_location (&fmt_substring_loc) fails, because we don't know how to handle a macro expansion, and doing so isn't something that seems sane to touch at this point in the development cycle. So one (or both?) of the fixes suggested in comment #4 seem appropriate.