[clang] [Clang] Fix nonblocking warning for dependent default arguments (PR #235457)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 25 07:40:07 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: MitraGulla
<details>
<summary>Changes</summary>
This fixes an unexpected `-Wfunction-effects` warning that occurs when Clang analyzes a template's dependent default argument, even though the caller provides the argument explicitly.
Added a regression test for the reported issue and tests covering explicit and implicit arguments and other template default-argument cases.
## LLM usage
LLM was used to help understand the issue, and finding relevant code part. The implementation and test changes were reviewed and tested locally.
---
Full diff: https://github.com/llvm/llvm-project/pull/235457.diff
2 Files Affected:
- (modified) clang/lib/Sema/SemaFunctionEffects.cpp (+8)
- (modified) clang/test/Sema/attr-nonblocking-constraints.cpp (+52)
``````````diff
diff --git a/clang/lib/Sema/SemaFunctionEffects.cpp b/clang/lib/Sema/SemaFunctionEffects.cpp
index 975281175aebb4..ef92e0c8b3ec47 100644
--- a/clang/lib/Sema/SemaFunctionEffects.cpp
+++ b/clang/lib/Sema/SemaFunctionEffects.cpp
@@ -1342,6 +1342,14 @@ class Analyzer {
return Result;
}
+ bool TraverseParmVarDecl(ParmVarDecl *D) override {
+ // Uninstantiated default arguments are dependent expressions that cannot
+ // be analyzed for function effects without producing incorrect warnings.
+ if (D->hasUninstantiatedDefaultArg())
+ return true;
+ return DynamicRecursiveASTVisitor::TraverseParmVarDecl(D);
+ }
+
bool TraverseLambdaExpr(LambdaExpr *Lambda) override {
// We override this so as to be able to skip traversal of the lambda's
// body. We have to explicitly traverse the captures. Why not return
diff --git a/clang/test/Sema/attr-nonblocking-constraints.cpp b/clang/test/Sema/attr-nonblocking-constraints.cpp
index 400057768523c5..55aa3cfde11bc3 100644
--- a/clang/test/Sema/attr-nonblocking-constraints.cpp
+++ b/clang/test/Sema/attr-nonblocking-constraints.cpp
@@ -380,6 +380,58 @@ void nb21() [[clang::nonblocking]] {
void nb22(int param = badForDefaultArg()) [[clang::nonblocking]] { // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function 'badForDefaultArg'}}
}
+ // Template default arguments
+ template <typename T>
+ int tmplDefaultSafe() noexcept [[clang::nonblocking]] {
+ return 0;
+ }
+
+ template <typename T>
+ auto tmplDefault(T a = tmplDefaultSafe<T>()) noexcept [[clang::nonblocking]] {
+ return a;
+ }
+
+ void testTmplDefaultExplicit(int x) [[clang::nonblocking]] {
+ tmplDefault(x);
+ }
+
+ void testTmplDefaultImplicit() [[clang::nonblocking]] {
+ tmplDefault<int>();
+ }
+
+ int badForTmplDefaultArg(); // expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} \
+ // expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}}
+
+ template <typename T>
+ auto tmplDefaultBad(T a = badForTmplDefaultArg()) noexcept [[clang::nonblocking]] { // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function 'badForTmplDefaultArg'}} \
+ // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function 'badForTmplDefaultArg'}}
+ return a;
+ }
+
+ void testTmplDefaultBadExplicit(int x) [[clang::nonblocking]] {
+ tmplDefaultBad(x);
+ }
+
+ void testTmplDefaultBadImplicit() [[clang::nonblocking]] {
+ tmplDefaultBad<int>(); // expected-note {{in evaluating default argument here}}
+ }
+
+ // An explicit argument must not trigger analysis of an unused dependent
+ // default argument.
+ template <typename T>
+ int f1() noexcept [[clang::nonblocking]] {
+ return 0;
+ }
+
+ template <typename T>
+ auto f2(T a = f1<T>()) noexcept [[clang::nonblocking]] {
+ return a;
+ }
+
+ void testDependentDefaultExplicit(int argc) [[clang::nonblocking]] {
+ f2(argc);
+ }
+
// Verify traversal of implicit code paths - constructors and destructors.
struct Unsafe {
static void problem1(); // expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}}
``````````
</details>
https://github.com/llvm/llvm-project/pull/235457
More information about the cfe-commits
mailing list