[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