[llvm-branch-commits] [clang] [clang] "modular_format" attribute for functions using format strings (PR #147431)
Daniel Thornburgh via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Jul 8 15:00:37 PDT 2025
https://github.com/mysterymath updated https://github.com/llvm/llvm-project/pull/147431
>From 619dfb750f9d262328f630a4735c1fcd62056d48 Mon Sep 17 00:00:00 2001
From: Daniel Thornburgh <dthorn at google.com>
Date: Tue, 10 Jun 2025 14:06:53 -0700
Subject: [PATCH] [clang] "modular_format" attribute for functions using format
strings
This provides a C language version of the new IR modular-format
attribute. This, in concert with the format attribute, allows a library
function to declare that a modular version of its implementation is
available.
See issue #146159 for context.
---
clang/include/clang/Basic/Attr.td | 11 +++++++++++
clang/include/clang/Basic/AttrDocs.td | 25 +++++++++++++++++++++++++
clang/lib/CodeGen/CGCall.cpp | 12 ++++++++++++
clang/lib/Sema/SemaDeclAttr.cpp | 27 +++++++++++++++++++++++++++
4 files changed, 75 insertions(+)
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 27fea7dea0a5e..bed878a10424c 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -5182,3 +5182,14 @@ def NonString : InheritableAttr {
let Subjects = SubjectList<[Var, Field]>;
let Documentation = [NonStringDocs];
}
+
+def ModularFormat : InheritableAttr {
+ let Spellings = [Clang<"modular_format">];
+ let Args = [
+ IdentifierArgument<"ModularImplFn">,
+ StringArgument<"ImplName">,
+ VariadicStringArgument<"Aspects">
+ ];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [ModularFormatDocs];
+}
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 43442f177ab7b..3c325ce2462cb 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -9427,3 +9427,28 @@ 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 to indicate that the implementation is modular on the
+format string argument. When the format argument 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.
+
+The following aspects are currently supported:
+
+- ``float``: The call has a floating point argument
+ }];
+}
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index a06455d25b1ef..9e8929b5a56ae 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -2569,6 +2569,18 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
if (TargetDecl->hasAttr<ArmLocallyStreamingAttr>())
FuncAttrs.addAttribute("aarch64_pstate_sm_body");
+
+ if (auto *ModularFormat = TargetDecl->getAttr<ModularFormatAttr>()) {
+ // TODO: Error checking
+ FormatAttr *Format = TargetDecl->getAttr<FormatAttr>();
+ std::string FormatIdx = std::to_string(Format->getFormatIdx());
+ std::string FirstArg = std::to_string(Format->getFirstArg());
+ SmallVector<StringRef> Args = {
+ FormatIdx, FirstArg, ModularFormat->getModularImplFn()->getName(),
+ ModularFormat->getImplName()};
+ llvm::append_range(Args, ModularFormat->aspects());
+ FuncAttrs.addAttribute("modular-format", llvm::join(Args, ","));
+ }
}
// Attach "no-builtins" attributes to:
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index eba29e609cb05..b70ffd7c35f7b 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -6897,6 +6897,29 @@ static void handleVTablePointerAuthentication(Sema &S, Decl *D,
CustomDiscriminationValue));
}
+static void handleModularFormat(Sema &S, Decl *D, const ParsedAttr &AL) {
+ StringRef ImplName;
+ if (!S.checkStringLiteralArgumentAttr(AL, 1, ImplName))
+ return;
+ SmallVector<StringRef> Aspects;
+ for (unsigned I = 2, E = AL.getNumArgs(); I != E; ++I) {
+ StringRef Aspect;
+ if (!S.checkStringLiteralArgumentAttr(AL, I, Aspect))
+ return;
+ Aspects.push_back(Aspect);
+ }
+
+ // Store aspects sorted and without duplicates.
+ llvm::sort(Aspects);
+ Aspects.erase(llvm::unique(Aspects), Aspects.end());
+
+ // TODO: Type checking on identifier
+ // TODO: Merge attributes
+ D->addAttr(::new (S.Context) ModularFormatAttr(
+ S.Context, AL, AL.getArgAsIdent(0)->getIdentifierInfo(), ImplName,
+ Aspects.data(), Aspects.size()));
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@@ -7821,6 +7844,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_VTablePointerAuthentication:
handleVTablePointerAuthentication(S, D, AL);
break;
+
+ case ParsedAttr::AT_ModularFormat:
+ handleModularFormat(S, D, AL);
+ break;
}
}
More information about the llvm-branch-commits
mailing list