https://github.com/Expertcoderz updated https://github.com/llvm/llvm-project/pull/225748
>From 730360dc5a0f855d996f12b7f8ab2f8bdf5ebff1 Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Wed, 23 Sep 2026 08:22:44 +0000 Subject: [PATCH 01/13] [Clang][Sema] Add -Wredundant-defer to diagnose redundant `_Defer`s This PR adds a new `-Wredundant-defer` diagnostic to have Clang emit warnings for superfluous uses of `_Defer`, where the substatement is always executed at the point of defer. With `-Wredundant-defer`, `_Defer` statements that occur in these positions will trigger the warning: - as the last statement of a compound statement or function - as the body of an `if`/`else` statement - as the body of a `for`/`while` loop - immediately preceding a `break` or `continue` statement - as the substatement of another `_Defer` This helps to detect mistakes and some potential misuses of `_Defer`. --- clang/docs/ReleaseNotes.md | 5 + clang/include/clang/Basic/DiagnosticGroups.td | 2 + .../clang/Basic/DiagnosticSemaKinds.td | 4 + clang/lib/Sema/SemaStmt.cpp | 41 ++++- clang/test/Parser/defer-ts.c | 4 +- clang/test/Sema/warn-redundant-defer.c | 151 ++++++++++++++++++ 6 files changed, 203 insertions(+), 4 deletions(-) create mode 100644 clang/test/Sema/warn-redundant-defer.c diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index e5da258b9950a3..a0126b0785d59d 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -518,6 +518,11 @@ features cannot lower the translation-unit ABI level; - Improve Clang diagnoses when unary `__imag` operator with non-complex type operand is used as lvalue. (GH222383) +- Added `-Wredundant-defer` to diagnose redundant uses of the `_Defer` + keyword, such as when deferring the last statement of a block; when + used as the body of a conditional; or when it immediately precedes + a `break`/`continue` statement. + ### Improvements to Clang's time-trace ### Improvements to Coverage Mapping diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 1da7698944b24b..4b35e4247e2c4c 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -345,6 +345,8 @@ def EmptyBody : DiagGroup<"empty-body">; def Exceptions : DiagGroup<"exceptions">; def DeclarationAfterStatement : DiagGroup<"declaration-after-statement">; +def RedundantDefer : DiagGroup<"redundant-defer">; + def GNUEmptyStruct : DiagGroup<"gnu-empty-struct">; def ExtraTokens : DiagGroup<"extra-tokens">; def CXX98CompatExtraSemi : DiagGroup<"c++98-compat-extra-semi">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 36a18473f4d4cc..17a15406d003aa 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11342,6 +11342,10 @@ def warn_empty_defer_body : Warning< def note_empty_body_on_separate_line : Note< "put the semicolon on a separate line to silence this warning">; +def warn_redundant_defer: Warning< + "redundant use of defer; the deferred statement is executed immediately">, + InGroup<RedundantDefer>, DefaultIgnore; + def err_va_start_captured_stmt : Error< "'va_start' cannot be used in a captured statement">; def err_va_start_outside_function : Error< diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 74fe253efa1374..8454f4f2bd8421 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -470,6 +470,23 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]); } + // Find defer statements that immediately precede a break/continue statement. + std::optional<SourceLocation> DeferLoc = std::nullopt; + for (unsigned i = 0; i != NumElts; ++i) { + if (DeferLoc && isa<BreakStmt, ContinueStmt>(Elts[i])) + Diag(DeferLoc.value(), diag::warn_redundant_defer) + << Elts[i]->getSourceRange(); + DeferLoc = isa<DeferStmt>(Elts[i]) + ? std::optional<SourceLocation>(Elts[i]->getBeginLoc()) + : std::nullopt; + } + + // Check for defer as last statement. + Stmt *Back = NumElts > 0 ? Elts[NumElts - 1] : nullptr; + if (Back && isa<DeferStmt>(Back)) + Diag(Back->getBeginLoc(), diag::warn_redundant_defer) + << Back->getSourceRange(); + // Calculate difference between FP options in this compound statement and in // the enclosing one. If this is a function body, take the difference against // default options. In this case the difference will indicate options that are @@ -997,6 +1014,14 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, if (!ConstevalOrNegatedConsteval && !elseStmt) DiagnoseEmptyStmtBody(RParenLoc, thenStmt, diag::warn_empty_if_body); + if (isa<DeferStmt>(thenStmt)) + Diag(thenStmt->getBeginLoc(), diag::warn_redundant_defer) + << thenStmt->getSourceRange(); + + if (elseStmt && isa<DeferStmt>(elseStmt)) + Diag(elseStmt->getBeginLoc(), diag::warn_redundant_defer) + << elseStmt->getSourceRange(); + if (ConstevalOrNegatedConsteval || StatementKind == IfStatementKind::Constexpr) { auto DiagnoseLikelihood = [&](const Stmt *S) { @@ -1837,6 +1862,9 @@ StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, if (isa<NullStmt>(Body)) getCurCompoundScope().setHasEmptyLoopBodies(); + else if (isa<DeferStmt>(Body)) + Diag(Body->getBeginLoc(), diag::warn_redundant_defer) + << Body->getSourceRange(); return WhileStmt::Create(Context, CondVal.first, CondVal.second, Body, WhileLoc, LParenLoc, RParenLoc); @@ -2328,6 +2356,9 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Expr *Third = third.release().getAs<Expr>(); if (isa<NullStmt>(Body)) getCurCompoundScope().setHasEmptyLoopBodies(); + else if (isa<DeferStmt>(Body)) + Diag(Body->getBeginLoc(), diag::warn_redundant_defer) + << Body->getSourceRange(); return new (Context) ForStmt(Context, First, Second.get().second, Second.get().first, Third, @@ -4033,11 +4064,17 @@ void Sema::ActOnDeferStmtError([[maybe_unused]] Scope *CurScope) { CurrentDefer.pop_back(); } -StmtResult Sema::ActOnEndOfDeferStmt(Stmt *Body, - [[maybe_unused]] Scope *CurScope) { +StmtResult Sema::ActOnEndOfDeferStmt(Stmt *Body, Scope *CurScope) { assert(!CurrentDefer.empty() && CurrentDefer.back().first == CurScope); + SourceLocation DeferLoc = CurrentDefer.pop_back_val().second; DiagnoseEmptyStmtBody(DeferLoc, Body, diag::warn_empty_defer_body); + + // Check for superfluous nested defer. + if (isa<DeferStmt>(Body)) + Diag(Body->getBeginLoc(), diag::warn_redundant_defer) + << Body->getSourceRange(); + setFunctionHasBranchProtectedScope(); return DeferStmt::Create(Context, DeferLoc, Body); } diff --git a/clang/test/Parser/defer-ts.c b/clang/test/Parser/defer-ts.c index 118fe9ee3cc8f5..1fe7eb2ec57163 100644 --- a/clang/test/Parser/defer-ts.c +++ b/clang/test/Parser/defer-ts.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -std=c11 -fsyntax-only -fdefer-ts -verify %s -// RUN: %clang_cc1 -std=c23 -fsyntax-only -fdefer-ts -verify %s +// RUN: %clang_cc1 -std=c11 -fsyntax-only -fdefer-ts -Wno-redundant-defer -verify %s +// RUN: %clang_cc1 -std=c23 -fsyntax-only -fdefer-ts -Wno-redundant-defer -verify %s #define defer _Defer diff --git a/clang/test/Sema/warn-redundant-defer.c b/clang/test/Sema/warn-redundant-defer.c new file mode 100644 index 00000000000000..2d9b92bbe9b63b --- /dev/null +++ b/clang/test/Sema/warn-redundant-defer.c @@ -0,0 +1,151 @@ +// RUN: %clang_cc1 -std=c23 -fdefer-ts -fsyntax-only -verify %s -Wredundant-defer + +#define defer _Defer + +void f1() { + defer {} // expected-warning {{redundant use of defer}} +} + +void f2() { + defer {} // OK + + defer defer {} // expected-warning {{redundant use of defer}} + + defer defer defer {} // expected-warning 2 {{redundant use of defer}} + + { + defer {} // OK + f1(); + } + + { defer {} } // expected-warning {{redundant use of defer}} + + { defer defer {} } // expected-warning 2 {{redundant use of defer}} + + { + defer { // OK + defer {} // OK + f1(); + } + f1(); + } + + { + defer { // expected-warning {{redundant use of defer}} + defer defer {} // expected-warning 2 {{redundant use of defer}} + } + } + + if (true) { + defer {} // OK + f1(); + } + + if (true) + defer {} // expected-warning {{redundant use of defer}} + + if (true) { + defer {} // expected-warning {{redundant use of defer}} + } + + for (;;) { + defer {} // OK + f1(); + } + + for (;;) + defer {} // expected-warning {{redundant use of defer}} + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + } + + for (;;) { + defer {} // OK + f1(); + break; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + break; + } + + for (;;) { + defer {} // OK + f1(); + continue; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + continue; + } + + while (true) { + defer {} // OK + f1(); + } + + while (true) + defer {} // expected-warning {{redundant use of defer}} + + while (true) { + defer {} // expected-warning {{redundant use of defer}} + } + + while (true) { + defer {} // OK + f1(); + break; + } + + while (true) { + defer {} // expected-warning {{redundant use of defer}} + break; + } + + while (true) { + defer {} // OK + f1(); + continue; + } + + while (true) { + defer {} // expected-warning {{redundant use of defer}} + continue; + } + + do { + defer {} // OK + f1(); + } while (true); + + do { + defer {} // expected-warning {{redundant use of defer}} + } while (true); + + do { + defer {} // OK + f1(); + break; + } while (true); + + do { + defer {} // expected-warning {{redundant use of defer}} + break; + } while (true); + + do { + defer {} // OK + f1(); + continue; + } while (true); + + do { + defer {} // expected-warning {{redundant use of defer}} + continue; + } while (true); + + defer {} // expected-warning {{redundant use of defer}} +} >From 43552bba54d55954537750ee28d0c88aaf7c5d8a Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Wed, 23 Sep 2026 12:49:22 +0000 Subject: [PATCH 02/13] Remove accidental change to clang/test/Parser/defer-ts.c --- clang/test/Parser/defer-ts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Parser/defer-ts.c b/clang/test/Parser/defer-ts.c index 1fe7eb2ec57163..118fe9ee3cc8f5 100644 --- a/clang/test/Parser/defer-ts.c +++ b/clang/test/Parser/defer-ts.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -std=c11 -fsyntax-only -fdefer-ts -Wno-redundant-defer -verify %s -// RUN: %clang_cc1 -std=c23 -fsyntax-only -fdefer-ts -Wno-redundant-defer -verify %s +// RUN: %clang_cc1 -std=c11 -fsyntax-only -fdefer-ts -verify %s +// RUN: %clang_cc1 -std=c23 -fsyntax-only -fdefer-ts -verify %s #define defer _Defer >From 995108a364b039bef658384a02cfe380e0bdf4a2 Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Wed, 23 Sep 2026 14:52:28 +0000 Subject: [PATCH 03/13] Remove DefaultIgnore on -Wredundant-defer --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +- clang/test/Sema/defer-ts-seh.c | 2 +- clang/test/Sema/defer-ts-sjlj.c | 2 +- clang/test/Sema/defer-ts.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 17a15406d003aa..ee93b6c4c33c17 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11344,7 +11344,7 @@ def note_empty_body_on_separate_line : Note< def warn_redundant_defer: Warning< "redundant use of defer; the deferred statement is executed immediately">, - InGroup<RedundantDefer>, DefaultIgnore; + InGroup<RedundantDefer>; def err_va_start_captured_stmt : Error< "'va_start' cannot be used in a captured statement">; diff --git a/clang/test/Sema/defer-ts-seh.c b/clang/test/Sema/defer-ts-seh.c index 4b773ed3f09a0c..de515f38aae876 100644 --- a/clang/test/Sema/defer-ts-seh.c +++ b/clang/test/Sema/defer-ts-seh.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c23 -fdefer-ts -fms-compatibility -triple x86_64-windows-msvc -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c23 -fdefer-ts -Wno-redundant-defer -fms-compatibility -triple x86_64-windows-msvc -fsyntax-only -verify %s void f() { __try { diff --git a/clang/test/Sema/defer-ts-sjlj.c b/clang/test/Sema/defer-ts-sjlj.c index 49230fa721e0f7..dc23f1f6969d41 100644 --- a/clang/test/Sema/defer-ts-sjlj.c +++ b/clang/test/Sema/defer-ts-sjlj.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=gnu23 -fdefer-ts -fsyntax-only -fblocks -verify %s +// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=gnu23 -fdefer-ts -Wno-redundant-defer -fsyntax-only -fblocks -verify %s typedef void** jmp_buf; typedef void** sigjmp_buf; diff --git a/clang/test/Sema/defer-ts.c b/clang/test/Sema/defer-ts.c index 95c68fa213eaae..d1fba4128b088c 100644 --- a/clang/test/Sema/defer-ts.c +++ b/clang/test/Sema/defer-ts.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c23 -fdefer-ts -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c23 -fdefer-ts -Wno-redundant-defer -fsyntax-only -verify %s #define defer _Defer >From b8bd97ebc20fe865d3a91bc12185843964b56640 Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Wed, 23 Sep 2026 15:01:29 +0000 Subject: [PATCH 04/13] Simplify check for _Defer before break/continue statements --- clang/lib/Sema/SemaStmt.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 8454f4f2bd8421..00eccea0f5a0e2 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -471,14 +471,10 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, } // Find defer statements that immediately precede a break/continue statement. - std::optional<SourceLocation> DeferLoc = std::nullopt; - for (unsigned i = 0; i != NumElts; ++i) { - if (DeferLoc && isa<BreakStmt, ContinueStmt>(Elts[i])) - Diag(DeferLoc.value(), diag::warn_redundant_defer) + for (unsigned i = 0; i != NumElts - 1; ++i) { + if (isa<DeferStmt>(Elts[i]) && isa<BreakStmt, ContinueStmt>(Elts[i+1])) + Diag(Elts[i]->getBeginLoc(), diag::warn_redundant_defer) << Elts[i]->getSourceRange(); - DeferLoc = isa<DeferStmt>(Elts[i]) - ? std::optional<SourceLocation>(Elts[i]->getBeginLoc()) - : std::nullopt; } // Check for defer as last statement. >From bca3b93e62a75a5969b576ce8c7b8fa5bd2c8dff Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Wed, 23 Sep 2026 15:14:50 +0000 Subject: [PATCH 05/13] Add redundant _Defer check for void return statements --- clang/lib/Sema/SemaStmt.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 00eccea0f5a0e2..204d8a3270b58a 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -470,11 +470,19 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]); } - // Find defer statements that immediately precede a break/continue statement. - for (unsigned i = 0; i != NumElts - 1; ++i) { - if (isa<DeferStmt>(Elts[i]) && isa<BreakStmt, ContinueStmt>(Elts[i+1])) - Diag(Elts[i]->getBeginLoc(), diag::warn_redundant_defer) - << Elts[i]->getSourceRange(); + // Find defer statements that immediately precede a `break`/`continue` + // or a plain `return` statement. + if (NumElts > 1) { + for (unsigned i = 0; i != NumElts - 1; ++i) { + if (!isa<DeferStmt>(Elts[i])) + continue; + + if (isa<BreakStmt, ContinueStmt>(Elts[i + 1]) || + (isa<ReturnStmt>(Elts[i + 1]) && + !cast<ReturnStmt>(Elts[i + 1])->getRetValue())) + Diag(Elts[i]->getBeginLoc(), diag::warn_redundant_defer) + << Elts[i]->getSourceRange(); + } } // Check for defer as last statement. >From 2058a8ed833e5dfc61a34dbe231b5d9dd12c16dd Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Wed, 23 Sep 2026 15:44:58 +0000 Subject: [PATCH 06/13] Add -Wredundant-defer tests for break/continue with labels/attributes --- clang/test/Sema/warn-redundant-defer.c | 64 ++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/clang/test/Sema/warn-redundant-defer.c b/clang/test/Sema/warn-redundant-defer.c index 2d9b92bbe9b63b..6e158d2c425667 100644 --- a/clang/test/Sema/warn-redundant-defer.c +++ b/clang/test/Sema/warn-redundant-defer.c @@ -71,6 +71,38 @@ void f2() { break; } + for (;;) { + defer {} // OK + f1(); + l1: break; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + l2: break; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + l3: l4: break; + } + + for (;;) { + defer {} // OK + f1(); + [[clang::likely]] break; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + [[clang::likely]] break; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + [[clang::likely]] [[clang::suppress]] break; + } + for (;;) { defer {} // OK f1(); @@ -82,6 +114,38 @@ void f2() { continue; } + for (;;) { + defer {} // OK + f1(); + l5: continue; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + l6: continue; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + l7: l8: continue; + } + + for (;;) { + defer {} // OK + f1(); + [[clang::likely]] continue; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + [[clang::likely]] continue; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + [[clang::likely]] [[clang::suppress]] continue; + } + while (true) { defer {} // OK f1(); >From 17819b914de3d1a8ffa7a923d5ef27989e305ada Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Wed, 23 Sep 2026 15:48:49 +0000 Subject: [PATCH 07/13] Add -Wredundant-defer tests for _Defer before return --- clang/test/Sema/warn-redundant-defer.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/clang/test/Sema/warn-redundant-defer.c b/clang/test/Sema/warn-redundant-defer.c index 6e158d2c425667..61a5a75f2ee5bc 100644 --- a/clang/test/Sema/warn-redundant-defer.c +++ b/clang/test/Sema/warn-redundant-defer.c @@ -213,3 +213,19 @@ void f2() { defer {} // expected-warning {{redundant use of defer}} } + +int f3() { + defer {} // OK + return 0; +} + +void f4() { + defer {} // OK + f1(); + return; +} + +void f5() { + defer {} // expected-warning {{redundant use of defer}} + return; +} >From 699f9d5af02a4db715bb5f2316f4f0497bf6004d Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Wed, 23 Sep 2026 16:18:29 +0000 Subject: [PATCH 08/13] Inline the DiagGroup of warn_redundant_defer --- clang/include/clang/Basic/DiagnosticGroups.td | 2 -- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 4b35e4247e2c4c..1da7698944b24b 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -345,8 +345,6 @@ def EmptyBody : DiagGroup<"empty-body">; def Exceptions : DiagGroup<"exceptions">; def DeclarationAfterStatement : DiagGroup<"declaration-after-statement">; -def RedundantDefer : DiagGroup<"redundant-defer">; - def GNUEmptyStruct : DiagGroup<"gnu-empty-struct">; def ExtraTokens : DiagGroup<"extra-tokens">; def CXX98CompatExtraSemi : DiagGroup<"c++98-compat-extra-semi">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ee93b6c4c33c17..72197af301c54a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11344,7 +11344,7 @@ def note_empty_body_on_separate_line : Note< def warn_redundant_defer: Warning< "redundant use of defer; the deferred statement is executed immediately">, - InGroup<RedundantDefer>; + InGroup<DiagGroup<"redundant-defer">>; def err_va_start_captured_stmt : Error< "'va_start' cannot be used in a captured statement">; >From 98013854a670123adaf4bb85ffa80c10f584bd0c Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Wed, 23 Sep 2026 16:27:53 +0000 Subject: [PATCH 09/13] Update ReleaseNotes.md entry on -Wredundant-defer features Co-authored-by: Ambrose Leeb <[email protected]> --- clang/docs/ReleaseNotes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index a0126b0785d59d..3e9a67201c60ef 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -521,7 +521,7 @@ features cannot lower the translation-unit ABI level; - Added `-Wredundant-defer` to diagnose redundant uses of the `_Defer` keyword, such as when deferring the last statement of a block; when used as the body of a conditional; or when it immediately precedes - a `break`/`continue` statement. + a `break`/`continue` statement or a `return` with no argument. ### Improvements to Clang's time-trace >From 9f5ff658fca2f0d4c7795de9a2f99acdb92a1116 Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Wed, 23 Sep 2026 16:33:35 +0000 Subject: [PATCH 10/13] Change wording in -Wredundant-defer from "defer" to "_Defer" Co-authored-by: Ambrose Leeb <[email protected]> --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 72197af301c54a..cbf7d95c1cc7ff 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11343,7 +11343,7 @@ def note_empty_body_on_separate_line : Note< "put the semicolon on a separate line to silence this warning">; def warn_redundant_defer: Warning< - "redundant use of defer; the deferred statement is executed immediately">, + "redundant use of '_Defer'; the deferred statement is executed immediately">, InGroup<DiagGroup<"redundant-defer">>; def err_va_start_captured_stmt : Error< >From 7e12e83b3a3a97978c14f53696944e930bce66d4 Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Fri, 25 Sep 2026 13:23:55 +0000 Subject: [PATCH 11/13] Ignore unexpected -Wredundant-defer warnings in defer-ts Parser test --- clang/test/Parser/defer-ts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Parser/defer-ts.c b/clang/test/Parser/defer-ts.c index 118fe9ee3cc8f5..1fe7eb2ec57163 100644 --- a/clang/test/Parser/defer-ts.c +++ b/clang/test/Parser/defer-ts.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -std=c11 -fsyntax-only -fdefer-ts -verify %s -// RUN: %clang_cc1 -std=c23 -fsyntax-only -fdefer-ts -verify %s +// RUN: %clang_cc1 -std=c11 -fsyntax-only -fdefer-ts -Wno-redundant-defer -verify %s +// RUN: %clang_cc1 -std=c23 -fsyntax-only -fdefer-ts -Wno-redundant-defer -verify %s #define defer _Defer >From 325c0193b6df1a72805c681662065c8e8e8bed11 Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Fri, 25 Sep 2026 13:45:41 +0000 Subject: [PATCH 12/13] Add stronger testcases with labels/attributes for redundant-defer --- clang/test/Sema/warn-redundant-defer.c | 80 ++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 6 deletions(-) diff --git a/clang/test/Sema/warn-redundant-defer.c b/clang/test/Sema/warn-redundant-defer.c index 61a5a75f2ee5bc..f2b9f4272fd48f 100644 --- a/clang/test/Sema/warn-redundant-defer.c +++ b/clang/test/Sema/warn-redundant-defer.c @@ -13,6 +13,32 @@ void f2() { defer defer defer {} // expected-warning 2 {{redundant use of defer}} + l1: defer defer {} // expected-warning {{redundant use of defer}} + + l2: defer defer defer {} // expected-warning 2 {{redundant use of defer}} + + defer [[clang::likely]] defer {} // expected-warning {{redundant use of defer}} + + defer + [[clang::likely]] [[clang::suppress]] + defer {}; // expected-warning {{redundant use of defer}} + + [[clang::likely]] defer defer {} // expected-warning {{redundant use of defer}} + + l3: + [[clang::likely]] defer + defer {} // expected-warning {{redundant use of defer}} + + defer __attribute__((suppress)) + defer {} // expected-warning {{redundant use of defer}} + + __attribute__((suppress)) defer + defer {} // expected-warning {{redundant use of defer}} + + l4: + __attribute__((unknown)) defer // expected-warning {{unknown attribute}} + defer {} // expected-warning {{redundant use of defer}} + { defer {} // OK f1(); @@ -36,6 +62,13 @@ void f2() { } } + { + [[clang::likely]] defer { // expected-warning {{redundant use of defer}} + [[clang::likely]] + defer defer {} // expected-warning 2 {{redundant use of defer}} + } + } + if (true) { defer {} // OK f1(); @@ -74,17 +107,17 @@ void f2() { for (;;) { defer {} // OK f1(); - l1: break; + l5: break; } for (;;) { defer {} // expected-warning {{redundant use of defer}} - l2: break; + l6: break; } for (;;) { defer {} // expected-warning {{redundant use of defer}} - l3: l4: break; + l7: l8: break; } for (;;) { @@ -103,6 +136,16 @@ void f2() { [[clang::likely]] [[clang::suppress]] break; } + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + __attribute__((suppress)) continue; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + l9: [[clang::likely]] break; + } + for (;;) { defer {} // OK f1(); @@ -117,17 +160,17 @@ void f2() { for (;;) { defer {} // OK f1(); - l5: continue; + l10: continue; } for (;;) { defer {} // expected-warning {{redundant use of defer}} - l6: continue; + l11: continue; } for (;;) { defer {} // expected-warning {{redundant use of defer}} - l7: l8: continue; + l12: l13: continue; } for (;;) { @@ -146,6 +189,16 @@ void f2() { [[clang::likely]] [[clang::suppress]] continue; } + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + __attribute__((suppress)) continue; + } + + for (;;) { + defer {} // expected-warning {{redundant use of defer}} + l14: [[clang::likely]] continue; + } + while (true) { defer {} // OK f1(); @@ -229,3 +282,18 @@ void f5() { defer {} // expected-warning {{redundant use of defer}} return; } + +void f6() { + defer {} // expected-warning {{redundant use of defer}} + l15: return; +} + +void f7() { + defer {} // expected-warning {{redundant use of defer}} + [[clang::likely]] return; +} + +void f8() { + defer {} // expected-warning {{redundant use of defer}} + l16: l17: [[clang::likely]] [[clang::suppress]] return; +} >From d0a7f75e71afd8462ef7a25535650a469ade53cf Mon Sep 17 00:00:00 2001 From: Expertcoderz <[email protected]> Date: Fri, 25 Sep 2026 13:47:16 +0000 Subject: [PATCH 13/13] Handle AttributedStmt and LabelStmt for redundant-defer checks --- clang/lib/Sema/SemaStmt.cpp | 63 ++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 204d8a3270b58a..08bdb2d3908f41 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -430,6 +430,27 @@ void Sema::ActOnFinishOfCompoundStmt() { PopCompoundScope(); } +// Returns the given statement as if its labels and attributes were +// stripped, if any. +static Stmt *GetInnermostStatement(Stmt *Outer) { + if (isa<LabelStmt>(Outer)) + Outer = cast<LabelStmt>(Outer)->getInnermostLabeledStmt(); + + if (isa<AttributedStmt>(Outer)) + Outer = cast<AttributedStmt>(Outer)->getSubStmt(); + + return Outer; +} + +// Diagnose if the given statement is a redundant _Defer statement. +static void CheckRedundantDeferStmt(Sema &S, Stmt *Body) { + Stmt *Inner = GetInnermostStatement(Body); + + if (isa<DeferStmt>(Inner)) + S.Diag(Inner->getBeginLoc(), diag::warn_redundant_defer) + << Inner->getSourceRange(); +} + sema::CompoundScopeInfo &Sema::getCurCompoundScope() const { return getCurFunction()->CompoundScopes.back(); } @@ -474,22 +495,16 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, // or a plain `return` statement. if (NumElts > 1) { for (unsigned i = 0; i != NumElts - 1; ++i) { - if (!isa<DeferStmt>(Elts[i])) - continue; - - if (isa<BreakStmt, ContinueStmt>(Elts[i + 1]) || - (isa<ReturnStmt>(Elts[i + 1]) && - !cast<ReturnStmt>(Elts[i + 1])->getRetValue())) - Diag(Elts[i]->getBeginLoc(), diag::warn_redundant_defer) - << Elts[i]->getSourceRange(); + Stmt *Inner = GetInnermostStatement(Elts[i + 1]); + if (isa<BreakStmt, ContinueStmt>(Inner) || + (isa<ReturnStmt>(Inner) && !cast<ReturnStmt>(Inner)->getRetValue())) + CheckRedundantDeferStmt(*this, Elts[i]); } } // Check for defer as last statement. - Stmt *Back = NumElts > 0 ? Elts[NumElts - 1] : nullptr; - if (Back && isa<DeferStmt>(Back)) - Diag(Back->getBeginLoc(), diag::warn_redundant_defer) - << Back->getSourceRange(); + if (NumElts > 0) + CheckRedundantDeferStmt(*this, Elts[NumElts - 1]); // Calculate difference between FP options in this compound statement and in // the enclosing one. If this is a function body, take the difference against @@ -1018,13 +1033,9 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, if (!ConstevalOrNegatedConsteval && !elseStmt) DiagnoseEmptyStmtBody(RParenLoc, thenStmt, diag::warn_empty_if_body); - if (isa<DeferStmt>(thenStmt)) - Diag(thenStmt->getBeginLoc(), diag::warn_redundant_defer) - << thenStmt->getSourceRange(); - - if (elseStmt && isa<DeferStmt>(elseStmt)) - Diag(elseStmt->getBeginLoc(), diag::warn_redundant_defer) - << elseStmt->getSourceRange(); + CheckRedundantDeferStmt(*this, thenStmt); + if (elseStmt) + CheckRedundantDeferStmt(*this, elseStmt); if (ConstevalOrNegatedConsteval || StatementKind == IfStatementKind::Constexpr) { @@ -1866,9 +1877,8 @@ StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, if (isa<NullStmt>(Body)) getCurCompoundScope().setHasEmptyLoopBodies(); - else if (isa<DeferStmt>(Body)) - Diag(Body->getBeginLoc(), diag::warn_redundant_defer) - << Body->getSourceRange(); + else + CheckRedundantDeferStmt(*this, Body); return WhileStmt::Create(Context, CondVal.first, CondVal.second, Body, WhileLoc, LParenLoc, RParenLoc); @@ -2360,9 +2370,8 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Expr *Third = third.release().getAs<Expr>(); if (isa<NullStmt>(Body)) getCurCompoundScope().setHasEmptyLoopBodies(); - else if (isa<DeferStmt>(Body)) - Diag(Body->getBeginLoc(), diag::warn_redundant_defer) - << Body->getSourceRange(); + else + CheckRedundantDeferStmt(*this, Body); return new (Context) ForStmt(Context, First, Second.get().second, Second.get().first, Third, @@ -4075,9 +4084,7 @@ StmtResult Sema::ActOnEndOfDeferStmt(Stmt *Body, Scope *CurScope) { DiagnoseEmptyStmtBody(DeferLoc, Body, diag::warn_empty_defer_body); // Check for superfluous nested defer. - if (isa<DeferStmt>(Body)) - Diag(Body->getBeginLoc(), diag::warn_redundant_defer) - << Body->getSourceRange(); + CheckRedundantDeferStmt(*this, Body); setFunctionHasBranchProtectedScope(); return DeferStmt::Create(Context, DeferLoc, Body); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
