https://github.com/arrowten updated 
https://github.com/llvm/llvm-project/pull/156436

>From 52ce1d23cd085893bf41943576a89127475acfca Mon Sep 17 00:00:00 2001
From: arrowten <[email protected]>
Date: Tue, 2 Sep 2025 15:33:52 +0530
Subject: [PATCH] [Sema] Diagnose use of if/else-if condition variable inside
 else-if/else branch(s)

---
 .../clang/Basic/DiagnosticSemaKinds.td        |   3 +
 clang/lib/Parse/ParseStmt.cpp                 |  38 ++++++
 clang/test/Parser/warn-conditional-scope.cpp  | 111 ++++++++++++++++++
 3 files changed, 152 insertions(+)
 create mode 100644 clang/test/Parser/warn-conditional-scope.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c934fed2c7462..492dcf934323f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13594,6 +13594,9 @@ def warn_acc_var_referenced_lacks_op
               "reference has no effect">,
       InGroup<DiagGroup<"openacc-var-lacks-operation">>,
       DefaultError;
+def warn_out_of_scope_var_usage
+    : Warning<"variable %0 declared in 'if' block is either false or null">,
+      InGroup<DiagGroup<"conditional-scope">>, DefaultIgnore;
 
 // AMDGCN builtins diagnostics
 def err_amdgcn_load_lds_size_invalid_value : Error<"invalid size value">;
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index bf1978c22ee9f..58bed9f93d51a 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1526,6 +1526,44 @@ StmtResult Parser::ParseIfStatement(SourceLocation 
*TrailingElseLoc) {
   SourceLocation ElseStmtLoc;
   StmtResult ElseStmt;
 
+  static llvm::DenseMap<const IdentifierInfo*, SourceLocation> UsedCondVars;
+  const VarDecl *VD = dyn_cast_or_null<VarDecl>(Cond.get().first);
+
+  if (VD) {
+    SourceLocation Loc = VD->getLocation();
+
+    if (!UsedCondVars.count(VD->getIdentifier()))
+      UsedCondVars[VD->getIdentifier()] = Loc;
+  }
+
+  std::function<void(const Stmt *)> DiagnoseOutOfScopeUse = [&](const Stmt *S) 
{
+    if (!S) return;
+
+    for (const Stmt *Child : S->children()) {
+      if (!Child) continue;
+
+      if (const auto *DRE = dyn_cast<DeclRefExpr>(Child)) {
+        if (const auto *UsedVD = dyn_cast<VarDecl>(DRE->getDecl())) {
+          if (UsedCondVars.count(UsedVD->getIdentifier()) && UsedVD != VD) {
+            if (Diags.isIgnored(diag::warn_out_of_scope_var_usage, 
DRE->getExprLoc()))
+              continue; 
+
+            Diag(DRE->getExprLoc(), diag::warn_out_of_scope_var_usage)
+              << UsedVD->getName();
+          }
+        }
+      }
+
+      DiagnoseOutOfScopeUse(Child);
+    }
+  };
+
+  if (ThenStmt.get())
+    DiagnoseOutOfScopeUse(ThenStmt.get());
+ 
+  if (ElseStmt.get())
+    DiagnoseOutOfScopeUse(ElseStmt.get());
+
   if (Tok.is(tok::kw_else)) {
     if (TrailingElseLoc)
       *TrailingElseLoc = Tok.getLocation();
diff --git a/clang/test/Parser/warn-conditional-scope.cpp 
b/clang/test/Parser/warn-conditional-scope.cpp
new file mode 100644
index 0000000000000..a6e3dfb95021d
--- /dev/null
+++ b/clang/test/Parser/warn-conditional-scope.cpp
@@ -0,0 +1,111 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wconditional-scope -DTEST_1 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wconditional-scope -DTEST_2 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wconditional-scope -DTEST_3 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wconditional-scope -DTEST_4 %s
+
+int *get_something();
+int *get_something_else();
+int *get_something_else_again();
+int *get_something_else_again_now();
+
+#ifdef TEST_1
+
+int test() {
+  if (int *ptr = get_something()) {
+    return ptr[0] * ptr[0];
+  }
+  // expected-warning@+2{{variable ptr declared in 'if' block is either false 
or null}}
+  else if (int *ptr2 = get_something_else()) {
+    return ptr[0] * ptr2[0];
+  }
+  // expected-warning@+3{{variable ptr declared in 'if' block is either false 
or null}}
+  // expected-warning@+2{{variable ptr2 declared in 'if' block is either false 
or null}}
+  else if (int* ptr3 = get_something_else_again()) {
+    return ptr[0] * ptr2[0] * ptr3[0]; 
+  }
+  // expected-warning@+4{{variable ptr declared in 'if' block is either false 
or null}}
+  // expected-warning@+3{{variable ptr2 declared in 'if' block is either false 
or null}}
+  // expected-warning@+2{{variable ptr3 declared in 'if' block is either false 
or null}}
+  else if (int *ptr4 = get_something_else_again_now()) {
+    return ptr[0] * ptr2[0] * ptr3[0] * ptr4[0];
+  }
+  else {
+    return -1;
+  }
+}
+
+#endif
+
+#ifdef TEST_2
+
+int test() {
+  if (int *ptr = get_something()) {
+    return ptr[0] * ptr[0];
+  }
+  else if (int *ptr2 = get_something_else()) {
+    return ptr2[0] * ptr2[0];
+  }
+  // expected-warning@+3{{variable ptr declared in 'if' block is either false 
or null}}
+  // expected-warning@+2{{variable ptr2 declared in 'if' block is either false 
or null}}
+  else if (int* ptr3 = get_something_else_again()) {
+    return ptr[0] * ptr2[0] * ptr3[0];
+  }
+  else {
+    return -1;
+  }
+}
+
+#endif
+
+#ifdef TEST_3
+
+int test() {
+  if (int *ptr = get_something()) {
+    return ptr[0] * ptr[0];
+  }
+  else if (int *ptr2 = get_something_else()) {
+    return ptr2[0] * ptr2[0];
+  }
+  // expected-warning@+3{{variable ptr2 declared in 'if' block is either false 
or null}}
+  // expected-warning@+2{{variable ptr2 declared in 'if' block is either false 
or null}}
+  else if (int* ptr3 = get_something_else_again()) {
+    return ptr2[0] * ptr2[0] * ptr3[0];
+  }
+  else {
+    return -1;
+  }
+}
+
+#endif
+
+#ifdef TEST_4
+
+int test() {
+  int x = 10; 
+
+  if (x == 30) {
+    return x;
+  }
+  else if (int *ptr = get_something()) {
+    return ptr[0];
+  }
+  // expected-warning@+3{{variable ptr declared in 'if' block is either false 
or null}}
+  // expected-warning@+2{{variable ptr declared in 'if' block is either false 
or null}}
+  else if (x == 20) {
+    return ptr[0] * ptr[0];
+  }
+  // expected-warning@+2{{variable ptr declared in 'if' block is either false 
or null}}
+  else if (int* ptr2 = get_something_else()) {
+    return ptr[0] * ptr2[0];  
+  }
+  // expected-warning@+3{{variable ptr declared in 'if' block is either false 
or null}}
+  // expected-warning@+2{{variable ptr2 declared in 'if' block is either false 
or null}}
+  else if (int *ptr3 = get_something_else_again()) {
+    return ptr[0] * ptr2[0] * ptr3[0];
+  }
+  else {
+    return -1; 
+  }
+}
+
+#endif

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to