Consider these examples: #include <stdio.h> #include <string.h> const char *foo (const char *fmt, ...) __attribute__((format(printf, 1, 2))); int f1(const char *s, int x) { const char *fmt = "s: %s, x: %d\n"; foo(fmt, s, x); return strlen(fmt); } int f2(const char *s, int x) { const char *fmt = "s: %d, x: %s\n"; foo(fmt, s, x); return strlen(fmt); } int g1(const char *s, int x) { const char *const fmt = "ss: %s, xx: %d\n"; foo(fmt, s, x); return strlen(fmt); } int g2(const char *s, int x) { const char *const fmt = "ss: %d, xx: %s\n"; foo(fmt, s, x); return strlen(fmt); } With -Wformat-nonliteral, gcc diagnoses f1 and f2, which is of course not strictly wrong. However, since fmt is never assigned to apart from its initialization (and its address is not taken and passed on etc.), gcc should be able to deduce the constness of fmt and act as for g1 and g2 (granted, that only works at -O1 and higher). What's worse, -Wformat-nonliteral is not part of -Wall -Wextra, so with "just" -Wall -Wextra, f2() isn't diagnosed at all. The strlen() calls are just there to show that gcc does fold those to constants in all cases (at -O1 and higher). So this is of course dependent on optimization passes, and the format checking presumably happens quite early. Neverthess, the f1() case is rather common. Is there some magic one could insert above if (TREE_CODE (format_tree) != ADDR_EXPR) { res->number_non_literal++; return; } to replace format_tree with its DECL_INITIAL in a case like that, to silence Wformat-nonliteral and allow diagnosing f2()?
You'd need dataflow information that's not available at that point in the front end to know that the initializer is indeed the value of fmt at that point in the code.
Confirmed. It could be done by integrating -Wformat with -Wformat-overflow. The latter runs without optimization as well as with it so the integration shouldn't result in too many false negatives.