[clang] [Clang] Preserve coroutine parameter referenced state during allocation function lookup (PR #217518)

via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 20 01:53:13 PDT 2026


https://github.com/Lane0218 updated https://github.com/llvm/llvm-project/pull/217518

>From 24aaf5e20013ea98bf907938f1d93f3d03c9f42e Mon Sep 17 00:00:00 2001
From: Lane0218 <laneljc at qq.com>
Date: Thu, 20 Aug 2026 10:55:51 +0800
Subject: [PATCH 1/2] [Clang] Preserve parameter referenced state during
 coroutine allocation

---
 clang/lib/Sema/SemaCoroutine.cpp                  |  5 +++++
 .../SemaCXX/warn-unused-parameters-coroutine.cpp  | 15 +++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 48ee5cc0b0836..275257bf9f198 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -1386,9 +1386,14 @@ static bool collectPlacementArgs(Sema &S, FunctionDecl &FD, SourceLocation Loc,
 
     // Build a reference to the parameter.
     auto PDLoc = PD->getLocation();
+    // Preserve the referenced state for unused parameter diagnostics.
+    bool DeclReferenced = PD->isReferenced();
     ExprResult PDRefExpr =
         S.BuildDeclRefExpr(PD, PD->getOriginalType().getNonReferenceType(),
                            ExprValueKind::VK_LValue, PDLoc);
+
+    PD->setReferenced(DeclReferenced);
+
     if (PDRefExpr.isInvalid())
       return false;
 
diff --git a/clang/test/SemaCXX/warn-unused-parameters-coroutine.cpp b/clang/test/SemaCXX/warn-unused-parameters-coroutine.cpp
index fee379d869112..42dd7bf586612 100644
--- a/clang/test/SemaCXX/warn-unused-parameters-coroutine.cpp
+++ b/clang/test/SemaCXX/warn-unused-parameters-coroutine.cpp
@@ -18,10 +18,25 @@ struct task : awaitable {
   };
 };
 
+struct task_with_new {
+  struct promise_type {
+    void *operator new(decltype(sizeof(0)));
+    task_with_new get_return_object();
+    awaitable initial_suspend();
+    awaitable final_suspend() noexcept;
+    void unhandled_exception();
+    void return_void();
+  };
+};
+
 task foo(int a) { // expected-warning{{unused parameter 'a'}}
   co_return;
 }
 
+task_with_new class_specific_new(int a) { // expected-warning{{unused parameter 'a'}}
+  co_return;
+}
+
 task bar(int a, int b) { // expected-warning{{unused parameter 'b'}}
   a = a + 1;
   co_return;

>From eac7dc1d5d3505cf3eaa86954eb19d4e02907a2e Mon Sep 17 00:00:00 2001
From: Lane0218 <laneljc at qq.com>
Date: Thu, 20 Aug 2026 16:52:41 +0800
Subject: [PATCH 2/2] fixup! [Clang] Preserve parameter referenced state during
 coroutine allocation

Distinguish speculative coroutine argument construction from parameters passed to the selected allocation function or promise constructor. Add regression coverage for both outcomes and a release note.

Assisted-by: OpenAI Codex
---
 clang/docs/ReleaseNotes.md                    |  5 +++++
 clang/lib/Sema/SemaCoroutine.cpp              | 21 ++++++++++++++++---
 .../warn-unused-parameters-coroutine.cpp      | 13 ++++++++++++
 3 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index b585161ba3ff4..b3b0f8caeb885 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -225,6 +225,11 @@ features cannot lower the translation-unit ABI level;
 
 - More consistent rendering of Unicode characters in diagnostic messages.
 
+- Fixed `-Wunused-parameter` to diagnose coroutine parameters that are only
+  considered during allocation function lookup or promise object
+  initialization, while not diagnosing parameters passed to the selected
+  allocation function or promise constructor. (#GH217501)
+
 - Fixed bug in `-Wdocumentation` so that it correctly handles explicit
   function template instantiations (#64087).
 
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 275257bf9f198..b5872bcc43868 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -463,6 +463,12 @@ static ExprResult buildPromiseCall(Sema &S, VarDecl *Promise,
   return buildMemberCall(S, PromiseRef.get(), Loc, Name, Args);
 }
 
+static void markCoroutineParametersReferenced(FunctionDecl &FD) {
+  for (auto *PD : FD.parameters())
+    if (!PD->getType()->isDependentType())
+      PD->setReferenced();
+}
+
 VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
   assert(isa<FunctionDecl>(CurContext) && "not in a function scope");
   auto *FD = cast<FunctionDecl>(CurContext);
@@ -556,6 +562,7 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
         VD->setInit(MaybeCreateExprWithCleanups(Result.get()));
         VD->setInitStyle(VarDecl::CallInit);
         CheckCompleteVariableDeclaration(VD);
+        markCoroutineParametersReferenced(*FD);
       }
     } else
       ActOnUninitializedDecl(VD);
@@ -1449,6 +1456,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
 
   FunctionDecl *OperatorNew = nullptr;
   SmallVector<Expr *, 1> PlacementArgs;
+  bool PlacementArgsAreCoroutineParameters = false;
   DeclarationName NewName =
       S.getASTContext().DeclarationNames.getCXXOperatorName(OO_New);
 
@@ -1502,8 +1510,11 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
   // We don't expect to call to global operator new with (size, p0, …, pn).
   // So if we choose to lookup the allocation function in global scope, we
   // shouldn't lookup placement arguments.
-  if (PromiseContainsNew && !collectPlacementArgs(S, FD, Loc, PlacementArgs))
-    return false;
+  if (PromiseContainsNew) {
+    if (!collectPlacementArgs(S, FD, Loc, PlacementArgs))
+      return false;
+    PlacementArgsAreCoroutineParameters = true;
+  }
 
   LookupAllocationFunction();
 
@@ -1569,6 +1580,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
     if (!StdNoThrow)
       return false;
     PlacementArgs = {StdNoThrow};
+    PlacementArgsAreCoroutineParameters = false;
     OperatorNew = nullptr;
     LookupAllocationFunction(AllocationFunctionScope::Global);
   }
@@ -1655,8 +1667,11 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
       isAlignedAllocation(IAP.PassAlignment))
     NewArgs.push_back(FrameAlignment);
 
-  if (OperatorNew->getNumParams() > NewArgs.size())
+  if (OperatorNew->getNumParams() > NewArgs.size()) {
     llvm::append_range(NewArgs, PlacementArgs);
+    if (PlacementArgsAreCoroutineParameters)
+      markCoroutineParametersReferenced(FD);
+  }
 
   ExprResult NewExpr =
       S.BuildCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc);
diff --git a/clang/test/SemaCXX/warn-unused-parameters-coroutine.cpp b/clang/test/SemaCXX/warn-unused-parameters-coroutine.cpp
index 42dd7bf586612..f065838e1000a 100644
--- a/clang/test/SemaCXX/warn-unused-parameters-coroutine.cpp
+++ b/clang/test/SemaCXX/warn-unused-parameters-coroutine.cpp
@@ -8,8 +8,12 @@ struct awaitable {
   void await_suspend(std::coroutine_handle<>) noexcept;
 };
 
+struct promise_arg {};
+
 struct task : awaitable {
   struct promise_type {
+    promise_type();
+    promise_type(promise_arg);
     task get_return_object() noexcept;
     awaitable initial_suspend() noexcept;
     awaitable final_suspend() noexcept;
@@ -18,9 +22,12 @@ struct task : awaitable {
   };
 };
 
+struct allocation_arg {};
+
 struct task_with_new {
   struct promise_type {
     void *operator new(decltype(sizeof(0)));
+    void *operator new(decltype(sizeof(0)), allocation_arg);
     task_with_new get_return_object();
     awaitable initial_suspend();
     awaitable final_suspend() noexcept;
@@ -33,10 +40,16 @@ task foo(int a) { // expected-warning{{unused parameter 'a'}}
   co_return;
 }
 
+task promise_constructor_uses_parameter(promise_arg a) { co_return; }
+
 task_with_new class_specific_new(int a) { // expected-warning{{unused parameter 'a'}}
   co_return;
 }
 
+task_with_new allocation_function_uses_parameter(allocation_arg a) {
+  co_return;
+}
+
 task bar(int a, int b) { // expected-warning{{unused parameter 'b'}}
   a = a + 1;
   co_return;



More information about the cfe-commits mailing list