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

Reply via email to