https://github.com/voltur01 updated 
https://github.com/llvm/llvm-project/pull/194003

>From e36c9d6b9c1f0df50a577442a1c7460327efd1e3 Mon Sep 17 00:00:00 2001
From: Volodymyr Turanskyy <[email protected]>
Date: Fri, 24 Apr 2026 17:04:26 +0100
Subject: [PATCH 1/3] Fix modular printf attributes

This fixes declarations of modular printf attributes by adding the format
attribute required by clang and documented here
https://github.com/llvm/llvm-project/blob/deb84db5b4056eed1457a6b03148a486bbadd8ea/libc/docs/dev/modular_format.rst?plain=1#L26
---
 libc/include/llvm-libc-macros/CMakeLists.txt     |  2 +-
 .../_LIBC_MODULAR_FORMAT_PRINTF-disable.h        |  3 ++-
 .../_LIBC_MODULAR_FORMAT_PRINTF.h                |  4 +++-
 libc/include/stdio.yaml                          | 16 ++++++++--------
 4 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt 
b/libc/include/llvm-libc-macros/CMakeLists.txt
index 1f34257c57e01..a923b979e71c9 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -400,7 +400,7 @@ add_macro_header(
     sysexits-macros.h
 )
 
-if (LIBC_CONF_MODULAR_FORMAT)
+if (LIBC_CONF_PRINTF_MODULAR)
   add_macro_header(
     _LIBC_MODULAR_FORMAT_PRINTF
     HDR
diff --git 
a/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h 
b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h
index e3238161b3808..ecec03c2142ce 100644
--- a/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h
+++ b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
 #define LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
 
-#define _LIBC_MODULAR_FORMAT_PRINTF(MODULAR_IMPL_FN)
+#define _LIBC_MODULAR_FORMAT_PRINTF(MODULAR_IMPL_FN, FORMAT_INDEX,             
\
+                                    FIRST_TO_CHECK)
 
 #endif // LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
diff --git a/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h 
b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h
index 918241ab8f2ec..e7349afe94371 100644
--- a/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h
+++ b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h
@@ -9,7 +9,9 @@
 #ifndef LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
 #define LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
 
-#define _LIBC_MODULAR_FORMAT_PRINTF(MODULAR_IMPL_FN)                           
\
+#define _LIBC_MODULAR_FORMAT_PRINTF(MODULAR_IMPL_FN, FORMAT_INDEX,             
\
+                                    FIRST_TO_CHECK)                            
\
+  __attribute__((format(printf, FORMAT_INDEX, FIRST_TO_CHECK)))                
\
   __attribute__((modular_format(MODULAR_IMPL_FN, "__printf", "float")))
 
 #endif // LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
diff --git a/libc/include/stdio.yaml b/libc/include/stdio.yaml
index 24890b4b25670..ce7738e8e0648 100644
--- a/libc/include/stdio.yaml
+++ b/libc/include/stdio.yaml
@@ -51,7 +51,7 @@ functions:
       - type: const char *__restrict
       - type: '...'
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__asprintf_modular)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__asprintf_modular, 2, 3)
   - name: clearerr
     standards:
       - stdc
@@ -304,7 +304,7 @@ functions:
       - type: const char *__restrict
       - type: '...'
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__printf_modular)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__printf_modular, 1, 2)
   - name: putc
     standards:
       - stdc
@@ -377,7 +377,7 @@ functions:
       - type: const char *__restrict
       - type: '...'
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__snprintf_modular)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__snprintf_modular, 3, 4)
   - name: sprintf
     standards:
       - stdc
@@ -387,7 +387,7 @@ functions:
       - type: const char *__restrict
       - type: '...'
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__sprintf_modular)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__sprintf_modular, 2, 3)
   - name: sscanf
     standards:
       - stdc
@@ -412,7 +412,7 @@ functions:
       - type: const char *__restrict
       - type: va_list
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__vasprintf_modular)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__vasprintf_modular, 2, 0)
   - name: vfprintf
     standards:
       - stdc
@@ -429,7 +429,7 @@ functions:
       - type: const char *__restrict
       - type: va_list
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__vprintf_modular)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__vprintf_modular, 1, 0)
   - name: vsnprintf
     standards:
       - stdc
@@ -440,7 +440,7 @@ functions:
       - type: const char *__restrict
       - type: va_list
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__vsnprintf_modular)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__vsnprintf_modular, 3, 0)
   - name: vsprintf
     standards:
       - stdc
@@ -450,7 +450,7 @@ functions:
       - type: const char *__restrict
       - type: va_list
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__vsprintf_modular)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__vsprintf_modular, 2, 0)
   - name: vsscanf
     standards:
       - stdc

>From 57d4eda3a867c060823c873b5b6d0e420dad06db Mon Sep 17 00:00:00 2001
From: Volodymyr Turanskyy <[email protected]>
Date: Thu, 7 May 2026 11:44:40 +0100
Subject: [PATCH 2/3] Remove hardcoded format attributes

---
 .../_LIBC_MODULAR_FORMAT_PRINTF-disable.h        |  3 +--
 .../_LIBC_MODULAR_FORMAT_PRINTF.h                |  4 +---
 libc/include/stdio.yaml                          | 16 ++++++++--------
 3 files changed, 10 insertions(+), 13 deletions(-)

diff --git 
a/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h 
b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h
index ecec03c2142ce..e3238161b3808 100644
--- a/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h
+++ b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h
@@ -9,7 +9,6 @@
 #ifndef LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
 #define LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
 
-#define _LIBC_MODULAR_FORMAT_PRINTF(MODULAR_IMPL_FN, FORMAT_INDEX,             
\
-                                    FIRST_TO_CHECK)
+#define _LIBC_MODULAR_FORMAT_PRINTF(MODULAR_IMPL_FN)
 
 #endif // LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
diff --git a/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h 
b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h
index e7349afe94371..918241ab8f2ec 100644
--- a/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h
+++ b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h
@@ -9,9 +9,7 @@
 #ifndef LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
 #define LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
 
-#define _LIBC_MODULAR_FORMAT_PRINTF(MODULAR_IMPL_FN, FORMAT_INDEX,             
\
-                                    FIRST_TO_CHECK)                            
\
-  __attribute__((format(printf, FORMAT_INDEX, FIRST_TO_CHECK)))                
\
+#define _LIBC_MODULAR_FORMAT_PRINTF(MODULAR_IMPL_FN)                           
\
   __attribute__((modular_format(MODULAR_IMPL_FN, "__printf", "float")))
 
 #endif // LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H
diff --git a/libc/include/stdio.yaml b/libc/include/stdio.yaml
index ce7738e8e0648..24890b4b25670 100644
--- a/libc/include/stdio.yaml
+++ b/libc/include/stdio.yaml
@@ -51,7 +51,7 @@ functions:
       - type: const char *__restrict
       - type: '...'
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__asprintf_modular, 2, 3)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__asprintf_modular)
   - name: clearerr
     standards:
       - stdc
@@ -304,7 +304,7 @@ functions:
       - type: const char *__restrict
       - type: '...'
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__printf_modular, 1, 2)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__printf_modular)
   - name: putc
     standards:
       - stdc
@@ -377,7 +377,7 @@ functions:
       - type: const char *__restrict
       - type: '...'
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__snprintf_modular, 3, 4)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__snprintf_modular)
   - name: sprintf
     standards:
       - stdc
@@ -387,7 +387,7 @@ functions:
       - type: const char *__restrict
       - type: '...'
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__sprintf_modular, 2, 3)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__sprintf_modular)
   - name: sscanf
     standards:
       - stdc
@@ -412,7 +412,7 @@ functions:
       - type: const char *__restrict
       - type: va_list
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__vasprintf_modular, 2, 0)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__vasprintf_modular)
   - name: vfprintf
     standards:
       - stdc
@@ -429,7 +429,7 @@ functions:
       - type: const char *__restrict
       - type: va_list
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__vprintf_modular, 1, 0)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__vprintf_modular)
   - name: vsnprintf
     standards:
       - stdc
@@ -440,7 +440,7 @@ functions:
       - type: const char *__restrict
       - type: va_list
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__vsnprintf_modular, 3, 0)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__vsnprintf_modular)
   - name: vsprintf
     standards:
       - stdc
@@ -450,7 +450,7 @@ functions:
       - type: const char *__restrict
       - type: va_list
     attributes:
-      - _LIBC_MODULAR_FORMAT_PRINTF(__vsprintf_modular, 2, 0)
+      - _LIBC_MODULAR_FORMAT_PRINTF(__vsprintf_modular)
   - name: vsscanf
     standards:
       - stdc

>From b07c293b86039f0afdc95034341ce6decf2d955d Mon Sep 17 00:00:00 2001
From: Volodymyr Turanskyy <[email protected]>
Date: Thu, 7 May 2026 11:47:11 +0100
Subject: [PATCH 3/3] Make checkModularFormatAttr() aware of format attribute
 for builtins

Make checkModularFormatAttr() check aware of the format attribute added 
automatically for printf family of functions.

Add a C++ test as the builtin handling behavior is different from C.
---
 clang/lib/Sema/SemaDecl.cpp                | 67 ++++++++++++++++++----
 clang/test/SemaCXX/attr-modular-format.cpp | 18 ++++++
 2 files changed, 74 insertions(+), 11 deletions(-)
 create mode 100644 clang/test/SemaCXX/attr-modular-format.cpp

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 36538e18f297c..3ddb2de611f33 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -7244,9 +7244,55 @@ static void checkLifetimeBoundAttr(Sema &S, NamedDecl 
&ND) {
   }
 }
 
+static bool isPrintfScanfLikeBuiltin(Sema &S, const FunctionDecl &FD) {
+  if (unsigned BuiltinID = FD.getBuiltinID()) {
+    unsigned FormatIdx;
+    bool HasVAListArg;
+
+    return S.Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx,
+                                              HasVAListArg) ||
+           S.Context.BuiltinInfo.isScanfLike(BuiltinID, FormatIdx,
+                                             HasVAListArg);
+  }
+
+  return false;
+}
+
+static bool isPrintfLikeFunction(Sema &S, const FunctionDecl &FD,
+                                 unsigned &FormatIdx, unsigned &FirstArg) {
+  IdentifierInfo *Name = FD.getIdentifier();
+  if (!Name)
+    return false;
+
+  if ((!S.getLangOpts().CPlusPlus &&
+       FD.getDeclContext()->isTranslationUnit()) ||
+      (isa<LinkageSpecDecl>(FD.getDeclContext()) &&
+       cast<LinkageSpecDecl>(FD.getDeclContext())->getLanguage() ==
+           LinkageSpecLanguageIDs::C)) {
+    if (Name->isStr("asprintf") || Name->isStr("vasprintf")) {
+      FormatIdx = 2;
+      FirstArg = Name->isStr("vasprintf") ? 0 : 3;
+      return true;
+    }
+  }
+
+  return false;
+}
+
 static void checkModularFormatAttr(Sema &S, NamedDecl &ND) {
-  if (ND.hasAttr<ModularFormatAttr>() && !ND.hasAttr<FormatAttr>())
-    S.Diag(ND.getLocation(), diag::err_modular_format_attribute_no_format);
+  if (!ND.hasAttr<ModularFormatAttr>())
+    return;
+
+  if (isa<FunctionDecl>(ND)) {
+    FunctionDecl *FD = cast<FunctionDecl>(&ND);
+    unsigned FormatIdx, FirstArg;
+
+    if (FD->hasAttr<FormatAttr>() || isPrintfScanfLikeBuiltin(S, *FD) ||
+        isPrintfLikeFunction(S, *FD, FormatIdx, FirstArg))
+      return;
+  }
+
+  S.Diag(ND.getLocation(), diag::err_modular_format_attribute_no_format);
 }
 
 static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
@@ -17556,15 +17602,14 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl 
*FD) {
   } else
     return;
 
-  if (Name->isStr("asprintf") || Name->isStr("vasprintf")) {
-    // FIXME: asprintf and vasprintf aren't C99 functions. Should they be
-    // target-specific builtins, perhaps?
-    if (!FD->hasAttr<FormatAttr>())
-      FD->addAttr(FormatAttr::CreateImplicit(Context,
-                                             &Context.Idents.get("printf"), 2,
-                                             Name->isStr("vasprintf") ? 0 : 3,
-                                             FD->getLocation()));
-  }
+  // FIXME: asprintf and vasprintf aren't C99 functions. Should they be
+  // target-specific builtins, perhaps?
+  unsigned FormatIdx, FirstArg;
+  if (!FD->hasAttr<FormatAttr>() &&
+      isPrintfLikeFunction(*this, *FD, FormatIdx, FirstArg))
+    FD->addAttr(
+        FormatAttr::CreateImplicit(Context, &Context.Idents.get("printf"),
+                                   FormatIdx, FirstArg, FD->getLocation()));
 
   if (Name->isStr("__CFStringMakeConstantString")) {
     // We already have a __builtin___CFStringMakeConstantString,
diff --git a/clang/test/SemaCXX/attr-modular-format.cpp 
b/clang/test/SemaCXX/attr-modular-format.cpp
new file mode 100644
index 0000000000000..9427d7ef79eb8
--- /dev/null
+++ b/clang/test/SemaCXX/attr-modular-format.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify %s
+
+extern "C" int printf(const char *fmt, ...)
+    __attribute__((modular_format(__modular_printf, "__printf", "float")));
+extern "C" int asprintf(char **buf, const char *fmt, ...)
+    __attribute__((modular_format(__asprintf_modular, "__printf", "float")));
+extern "C" int vasprintf(char **buf, const char *fmt, __builtin_va_list ap)
+    __attribute__((modular_format(__vasprintf_modular, "__printf", "float")));
+
+int myprintf(const char *fmt, ...) __attribute__((
+    modular_format(__modular_printf, "__printf", "float")));
+// expected-error@-2 {{'modular_format' attribute requires 'format' attribute}}
+
+namespace ns {
+int asprintf(char **buf, const char *fmt, ...)
+    __attribute__((modular_format(__asprintf_modular, "__printf", "float")));
+// expected-error@-2 {{'modular_format' attribute requires 'format' attribute}}
+} // namespace ns

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to