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@-1 {{explicit object parameters are incompatible with C++ standards before C++2b}} +}; + +void test_baseline0() { + auto sty = Ty{}; + + sty.baseline0(1); + // expected-warning@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
