[clang] 9e014de - [Clang] Fixed missing sentinel attribute diagnostic discrepancy with explicit object parameters (#208842)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 13 06:15:10 PDT 2026
Author: Tony Guillot
Date: 2026-07-13T15:15:05+02:00
New Revision: 9e014de2d3cc674b548e321013bfe42e6f5485ab
URL: https://github.com/llvm/llvm-project/commit/9e014de2d3cc674b548e321013bfe42e6f5485ab
DIFF: https://github.com/llvm/llvm-project/commit/9e014de2d3cc674b548e321013bfe42e6f5485ab.diff
LOG: [Clang] Fixed missing sentinel attribute diagnostic discrepancy with explicit object parameters (#208842)
When using the sentinel attribute on a variadic function with an
explicit object parameter, the missing sentinel attribute diagnostic
takes into account the explicit object parameter as an argument. It was
diagnosing `missing sentinel in function call` instead of `not enough
variable arguments in '%0' declaration to fit a sentinel`, compared to
other similar variadic functions.
Fixes #200007
Added:
Modified:
clang/docs/ReleaseNotes.md
clang/lib/Sema/SemaExpr.cpp
clang/test/SemaCXX/attr-sentinel.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index bbd42848a98c2..69f86294d4377 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -741,6 +741,9 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
- Added a clearer diagnostic for uninitialized decomposition declarations. (#GH90107)
+- Fixed missing sentinel attribute diagnostic discrepancy with explicit object
+ parameters in variadic functions. (#GH200007)
+
### Improvements to Clang's time-trace
### Improvements to Coverage Mapping
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 3afca1a202062..6d7cdf9f60dea 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -433,6 +433,8 @@ void Sema::DiagnoseSentinelCalls(const NamedDecl *D, SourceLocation Loc,
} else if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
NumFormalParams = FD->param_size();
CalleeKind = CK_Function;
+ if (FD->hasCXXExplicitFunctionObjectParameter())
+ NumFormalParams++;
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
QualType Ty = VD->getType();
const FunctionType *Fn = nullptr;
diff --git a/clang/test/SemaCXX/attr-sentinel.cpp b/clang/test/SemaCXX/attr-sentinel.cpp
index 92c6e21444fa3..e11ac16fe6bcf 100644
--- a/clang/test/SemaCXX/attr-sentinel.cpp
+++ b/clang/test/SemaCXX/attr-sentinel.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17 -std=c++17 %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx23 -std=c++23 %s
void f(int, ...) __attribute__((sentinel));
@@ -21,3 +22,88 @@ void class_test() {
s2->a(1,2,3); // expected-warning {{missing sentinel in function call}}
s(1,2,3); // expected-warning {{missing sentinel in function call}}
}
+
+namespace consistent_diganostic_test {
+struct Ty {
+ void baseline0(int, ...) __attribute__((sentinel)); // #BASELINE0_NOTE
+ void baseline1(int, ...) __attribute__((sentinel(1))); // #BASELINE1_NOTE
+ void baseline2(int, ...) __attribute__((sentinel(2))); // #BASELINE2_NOTE
+
+ template<typename T>
+ int&& foo(T&& val, ...) __attribute__((sentinel(1))); // #FOO_NOTE
+
+ template<class Self>
+ int&& bar(this Self&& self, ...) __attribute__((sentinel(1))); // #BAR_NOTE
+ // cxx17-error at -1 {{explicit object parameters are incompatible with C++ standards before C++2b}}
+};
+
+void test_baseline0() {
+ auto sty = Ty{};
+
+ sty.baseline0(1);
+ // expected-warning at -1 {{not enough variable arguments in 'baseline0' declaration to fit a sentinel}}
+ // expected-note@#BASELINE0_NOTE {{function has been explicitly marked sentinel here}}
+
+ sty.baseline0(1, 2);
+ // expected-warning at -1 {{missing sentinel in function call}}
+ // expected-note@#BASELINE0_NOTE {{function has been explicitly marked sentinel here}}
+
+ sty.baseline0(1, 2, nullptr);
+}
+
+void test_baseline1() {
+ auto sty = Ty{};
+
+ sty.baseline1(1, 3);
+ // expected-warning at -1 {{not enough variable arguments in 'baseline1' declaration to fit a sentinel}}
+ // expected-note@#BASELINE1_NOTE {{function has been explicitly marked sentinel here}}
+
+ sty.baseline1(1, 2, 3);
+ // expected-warning at -1 {{missing sentinel in function call}}
+ // expected-note@#BASELINE1_NOTE {{function has been explicitly marked sentinel here}}
+
+ sty.baseline1(1, 2, nullptr, 3);
+}
+
+void test_baseline2() {
+ auto sty = Ty{};
+
+ sty.baseline2(1, 2, 3);
+ // expected-warning at -1 {{not enough variable arguments in 'baseline2' declaration to fit a sentinel}}
+ // expected-note@#BASELINE2_NOTE {{function has been explicitly marked sentinel here}}
+
+ sty.baseline2(1, 2, 3, 4);
+ // expected-warning at -1 {{missing sentinel in function call}}
+ // expected-note@#BASELINE2_NOTE {{function has been explicitly marked sentinel here}}
+
+ sty.baseline2(1, 2, nullptr, 3, 4);
+}
+
+void test_foo() {
+ auto sty = Ty{};
+
+ sty.foo(1, 2);
+ // expected-warning at -1 {{not enough variable arguments in 'foo' declaration to fit a sentinel}}
+ // expected-note@#FOO_NOTE {{function has been explicitly marked sentinel here}}
+
+ sty.foo(1, 2, 3);
+ // expected-warning at -1 {{missing sentinel in function call}}
+ // expected-note@#FOO_NOTE {{function has been explicitly marked sentinel here}}
+
+ sty.foo(1, nullptr, 3);
+}
+
+void test_bar() {
+ auto sty = Ty{};
+
+ sty.bar(1, 2);
+ // expected-warning at -1 {{not enough variable arguments in 'bar' declaration to fit a sentinel}}
+ // expected-note@#BAR_NOTE {{function has been explicitly marked sentinel here}}
+
+ sty.bar(1, 2, 3);
+ // expected-warning at -1 {{missing sentinel in function call}}
+ // expected-note@#BAR_NOTE {{function has been explicitly marked sentinel here}}
+
+ sty.bar(1, nullptr, 3);
+}
+} // namespace consistent_diganostic_test
More information about the cfe-commits
mailing list