If a function is just a wrapper around vsprintf or friends, in some cases it neither captures nor writes its arguments.
Because such a function is variadic, we are very conservative about any operand it is called with elsewhere in the compiler, so here if we can we should propagate readonly + nocapture to any operand to the function at all callsites.
A variadic pointer argument to a printf-like function is only sometimes nocapture+readonly. For example in this case foo is captured into bar:
sprintf(buf, "%p", &foo); sscanf(buf, "%p", &bar);
For this reason we have to be careful which pointer arguments we mark as nocapture, and we have to parse the format string to be able to understand how the pointer is being used. In this implementation, the only "safe" use of a pointer is "%s", as it is not possible to encode the pointer address textually via %s (unlike with almost any numeric operator: %d/%u/%f etc).
Even though this code only detects %s, it is still useful as %s is so widely used. Consider a "plugin structure":
struct a { const char identifier[32], void (*f)(); } A; myprintf("ident: %s\n", &A.identifier);
Even if A were determined to be constant, no calls to A.f() could be speculated because a pointer into A is potentially captured. With this analysis we can determine that A is not captured so GlobalOpt can SROA the struct and make indirect calls to A.f() direct.
In the future this can be extended to other v* functions in the standard library that have defined behavior on their operands, such as vscanf and friends (these do not capture, but do write).
Wouldn't it be enough to have readonly/nocapture? Why do we need to test for library functions?