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
