Author: Lane0218 Date: 2026-08-25T10:59:49+08:00 New Revision: 01fec9890ad8a4980beb8ec1945320e126ddbdcd
URL: https://github.com/llvm/llvm-project/commit/01fec9890ad8a4980beb8ec1945320e126ddbdcd DIFF: https://github.com/llvm/llvm-project/commit/01fec9890ad8a4980beb8ec1945320e126ddbdcd.diff LOG: [Clang] Fix -Wunused-parameter for implicit coroutine uses (#217518) Clang's coroutine semantic analysis builds references to coroutine parameters while looking up a class-specific allocation function. When overload resolution falls back to a size-only `operator new`, these speculative references currently suppress `-Wunused-parameter`. Preserve each parameter's referenced state while collecting placement arguments, then mark the parameters referenced only when those arguments are included in the selected allocation call. Keep this distinction when placement arguments are replaced by `std::nothrow`. Apply the same rule to promise initialization: when initialization using the coroutine parameter copies succeeds, mark the original parameters referenced; when it falls back to default initialization, leave them unchanged. Add regression coverage for both the matching and fallback allocation-function and promise-initialization cases, and add a release note. Testing: - `clang/test/SemaCXX/warn-unused-parameters-coroutine.cpp`: 1/1 passed. - `clang/test/SemaCXX/coroutine*.cpp`: 24/24 passed. Fixes #217501. Assisted-by: OpenAI Codex Added: Modified: clang/docs/ReleaseNotes.md clang/lib/Sema/SemaCoroutine.cpp clang/test/SemaCXX/warn-unused-parameters-coroutine.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 54e3325a84e19..8cc8eb5f80066 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -238,6 +238,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 48ee5cc0b0836..627ed96522025 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,10 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) { VD->setInit(MaybeCreateExprWithCleanups(Result.get())); VD->setInitStyle(VarDecl::CallInit); CheckCompleteVariableDeclaration(VD); + // The constructor is selected with the coroutine parameter copies as + // arguments. Mark the original parameters as referenced for + // -Wunused-parameter. + markCoroutineParametersReferenced(*FD); } } else ActOnUninitializedDecl(VD); @@ -1386,9 +1396,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; @@ -1444,6 +1459,8 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { FunctionDecl *OperatorNew = nullptr; SmallVector<Expr *, 1> PlacementArgs; + // Track whether PlacementArgs still refer to the coroutine parameters. + bool PlacementArgsFromCoroutine = false; DeclarationName NewName = S.getASTContext().DeclarationNames.getCXXOperatorName(OO_New); @@ -1497,8 +1514,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; + PlacementArgsFromCoroutine = true; + } LookupAllocationFunction(); @@ -1564,6 +1584,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { if (!StdNoThrow) return false; PlacementArgs = {StdNoThrow}; + PlacementArgsFromCoroutine = false; OperatorNew = nullptr; LookupAllocationFunction(AllocationFunctionScope::Global); } @@ -1650,8 +1671,14 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { isAlignedAllocation(IAP.PassAlignment)) NewArgs.push_back(FrameAlignment); - if (OperatorNew->getNumParams() > NewArgs.size()) + // getNumParams() does not include an ellipsis, but a variadic allocation + // function still receives the coroutine parameters as placement arguments. + if (OperatorNew->isVariadic() || + OperatorNew->getNumParams() > NewArgs.size()) { llvm::append_range(NewArgs, PlacementArgs); + if (PlacementArgsFromCoroutine) + 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 fee379d869112..ef0c767dbc802 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,10 +22,50 @@ 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; + void unhandled_exception(); + void return_void(); + }; +}; + +struct task_with_variadic_new { + struct promise_type { + void *operator new(decltype(sizeof(0)), ...); + task_with_variadic_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 promise_constructor_uses_parameter(promise_arg a) { co_return; } + +task_with_new class_specific_new_fallback( + int a) { // expected-warning{{unused parameter 'a'}} + co_return; +} + +task_with_new placement_allocation_uses_parameter(allocation_arg a) { + co_return; +} + +task_with_variadic_new variadic_allocation_uses_parameter(int a) { + co_return; +} + task bar(int a, int b) { // expected-warning{{unused parameter 'b'}} a = a + 1; co_return; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
