[llvm-branch-commits] [clang] [clang] "modular_format" attribute for functions using format strings (PR #147431)

Aaron Ballman via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jul 22 07:49:46 PDT 2025


================
@@ -9427,3 +9427,37 @@ diagnostics with code like:
   __attribute__((nonstring)) char NotAStr[3] = "foo"; // Not diagnosed
   }];
 }
+
+def ModularFormatDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``modular_format`` attribute can be applied to a function that bears the
+``format`` attribute (or standard library functions) to indicate that the
+implementation is modular on the format string argument. When the format string
+for a given call is constant, the compiler may redirect the call to the symbol
+given as the first argument to the attribute (the modular implementation
+function).
+
+The second argument is a implementation name, and the remaining arguments are
+aspects of the format string for the compiler to report. If the compiler does
+not understand a aspect, it must summarily report that the format string has
+that aspect.
+
+The compiler reports an aspect by issing a relocation for the symbol
+``<impl_name>_<aspect>``. This arranges for code and data needed to support the
+aspect of the implementation to be brought into the link to satisfy weak
+references in the modular implemenation function.
+
+For example, say ``printf`` is annotated with
+``modular_format(__modular_printf, __printf, float)``. Then, a call to
+``printf(var, 42)`` would be untouched. A call to ``printf("%d", 42)`` would
+become a call to ``__modular_printf`` with the same arguments, as would
----------------
AaronBallman wrote:

> > So will any call to `printf` with a constant format specifier string be rewritten to call `__modular_printf`?
> 
> That's correct.

Good to know, thanks!

> > Also, who is responsible for writing these attributes? Are they only in the libc implementation, or can a user write one of these themselves on their own declarations? I'm asking because I wonder about compatibility; e.g., the call dispatches to `__modular_printf` but that doesn't know about some particular extension being used in the format specifier and so the code appears to misbehave.
> 
> Users could use these for their own implementations, in particular to allow functions that e.g. wrap `vsnprintf` to do logging etc. As for compatibility, if the compiler understands aspect names that the implementation doesn't, there's no issue, as the compiler will not spontaneously emit them if not requested. If an implementation requests a verdict on an implementation aspect unknown to the compiler, the compiler will conservatively report that the aspect is required. The `modular_format` attribute provided by the code and the aspect references emitted by the compiler thus form a sort of two-phase handshake between the code and compiler.

My concern is more about dispatching in ways the user may not anticipate and getting observably different behavior. e.g., the user calls `printf("%I64d", 0LL)` and they were getting the MSVC CRT `printf` call which supported that modifier but now calls `__modular_printf` which doesn't know about the modifier. What happens in that kind of situation?

https://github.com/llvm/llvm-project/pull/147431


More information about the llvm-branch-commits mailing list