https://github.com/to268 updated https://github.com/llvm/llvm-project/pull/196088
>From dd07939ce8128b9d54cca3a4f68fc3f137d9f60b Mon Sep 17 00:00:00 2001 From: Tony Guillot <[email protected]> Date: Wed, 6 May 2026 16:48:40 +0200 Subject: [PATCH 1/3] Documented sentinel attribute --- clang/include/clang/Basic/Attr.td | 2 +- clang/include/clang/Basic/AttrDocs.td | 28 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 70b5773f95b08..81993146e6d0c 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3419,7 +3419,7 @@ def Sentinel : InheritableAttr { let Args = [DefaultIntArgument<"Sentinel", 0>, DefaultIntArgument<"NullPos", 0>]; // let Subjects = SubjectList<[Function, ObjCMethod, Block, Var]>; - let Documentation = [Undocumented]; + let Documentation = [SentinelDocs]; } def StdCall : DeclOrTypeAttr { diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 87b9053be7cb6..edafc335a1dd1 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -10055,3 +10055,31 @@ different languages to coexist on the same call stack while each interpreting exceptions according to their own rules. }]; } + +def SentinelDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``sentinel`` attribute can only be applied to variadic functions to +diagnose each function call that do not pass a sentinel value at the end of the +argument list. It checks if a null pointer constant exists at the end of the +argument list by default, or at the (N+1)th position starting from the end when +an argument is provided. + +.. code-block:: c + + #include <stddef.h> + + void foo(const char*, ...) __attribute__((sentinel)); + void bar(int, ...) __attribute__((sentinel(1))); + + void example() { + foo("Example", (void*)0); + foo("Another", "example", NULL); + foo("Missing", "sentinel"); // Not OK + + bar(1, 2, NULL, 3); // OK: sentinel value at the 2nd to last positon + bar(1, 2, 3, nullptr, 4); // OK: `nullptr` is valid in C23 + bar(1, 2, 3, 4, NULL); // Not OK + } + }]; +} >From bc01b2c64936708f7b2fba926bbf8744a2ff8ce2 Mon Sep 17 00:00:00 2001 From: Tony Guillot <[email protected]> Date: Sun, 24 May 2026 19:27:39 +0200 Subject: [PATCH 2/3] Added mention of pointers to variadic functions --- clang/include/clang/Basic/AttrDocs.td | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index edafc335a1dd1..074c8b3b03244 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -9314,8 +9314,8 @@ def HLSLMatrixLayoutDocs : Documentation { let Category = DocCatVariable; let Heading = "row_major, column_major"; let Content = [{ -The ``row_major`` and ``column_major`` keywords specify the memory layout -of an HLSL matrix type. +The ``row_major`` and ``column_major`` keywords specify the memory layout +of an HLSL matrix type. * ``row_major``: Matrices are stored in memory row-by-row. * ``column_major``: Matrices are stored in memory column-by-column (default). @@ -10059,11 +10059,11 @@ exceptions according to their own rules. def SentinelDocs : Documentation { let Category = DocCatFunction; let Content = [{ -The ``sentinel`` attribute can only be applied to variadic functions to -diagnose each function call that do not pass a sentinel value at the end of the -argument list. It checks if a null pointer constant exists at the end of the -argument list by default, or at the (N+1)th position starting from the end when -an argument is provided. +The ``sentinel`` attribute can be applied to variadic functions and pointers to +variadic functions, to diagnose each function call that do not pass a sentinel +value at the end of the argument list. It checks if a null pointer constant +exists at the end of the argument list by default, or at the (N+1)th position +starting from the end when an argument is provided. .. code-block:: c @@ -10080,6 +10080,9 @@ an argument is provided. bar(1, 2, NULL, 3); // OK: sentinel value at the 2nd to last positon bar(1, 2, 3, nullptr, 4); // OK: `nullptr` is valid in C23 bar(1, 2, 3, 4, NULL); // Not OK + + void (*ptr) (int arg, ...) __attribute__ ((__sentinel__)); + ptr(1, 2, 3, NULL); } }]; } >From a57b4d8123cbfea29ba72e1c3fca0cb36b8eeeb2 Mon Sep 17 00:00:00 2001 From: Tony Guillot <[email protected]> Date: Thu, 28 May 2026 13:04:16 +0200 Subject: [PATCH 3/3] Improved documentation --- clang/include/clang/Basic/AttrDocs.td | 37 ++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 074c8b3b03244..1d67b54044f40 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -10061,16 +10061,17 @@ def SentinelDocs : Documentation { let Content = [{ The ``sentinel`` attribute can be applied to variadic functions and pointers to variadic functions, to diagnose each function call that do not pass a sentinel -value at the end of the argument list. It checks if a null pointer constant -exists at the end of the argument list by default, or at the (N+1)th position -starting from the end when an argument is provided. +value (a null pointer constant) in the argument list, at the end by default. +The attribute accepts 2 optional parameters: the first parameter is the +position of the expected sentinel value, starting from the last parameter which +defaults to 0, and the second parameter describes whether the last fixed +parameter is treated as a valid sentinel value when set to 1 (defaults to 0). +The attribute is also supported with blocks and in Objective-C. .. code-block:: c - - #include <stddef.h> - void foo(const char*, ...) __attribute__((sentinel)); void bar(int, ...) __attribute__((sentinel(1))); + void baz(const char*, const char*, ...) __attribute__((sentinel(0, 1))); void example() { foo("Example", (void*)0); @@ -10081,8 +10082,32 @@ starting from the end when an argument is provided. bar(1, 2, 3, nullptr, 4); // OK: `nullptr` is valid in C23 bar(1, 2, 3, 4, NULL); // Not OK + baz("Test", "with", "multiple", "args", NULL); + baz("One", NULL); // OK: last fixed parameter is a valid sentinel + void (*ptr) (int arg, ...) __attribute__ ((__sentinel__)); ptr(1, 2, 3, NULL); } + +.. code-block:: c++ + struct Ty { + int value; + + template<typename T> + auto&& foo(T&& val, ...) __attribute__((sentinel(1))) { + return std::forward<T>(val); + } + + template<class Self> + auto&& bar(this Self&& self, ...) __attribute__((sentinel(1))) { + return std::forward<Self>(self).value; + } + }; + + void example2() { + auto sty = Ty{}; + sty.foo(1, nullptr, 3); + sty.bar(1, nullptr, 3); + } }]; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
