[clang] [Sema] Diagnose use of if/else-if condition variable inside else-if/else branch(s) (PR #156436)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 4 03:23:05 PDT 2025
https://github.com/arrowten updated https://github.com/llvm/llvm-project/pull/156436
>From e5ded955c4005ab52dd75c87550034fe34f6f479 Mon Sep 17 00:00:00 2001
From: arrowten <ajaywakodikarsocial at gmail.com>
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/Sema/SemaStmt.cpp | 29 ++++++++
clang/test/Sema/warn-conditional-scope.cpp | 74 +++++++++++++++++++
3 files changed, 106 insertions(+)
create mode 100644 clang/test/Sema/warn-conditional-scope.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c934fed2c7462..daabb3cd188d8 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">>;
// AMDGCN builtins diagnostics
def err_amdgcn_load_lds_size_invalid_value : Error<"invalid size value">;
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 5625fb359807a..93795db87427e 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -971,6 +971,35 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc,
if (!ConstevalOrNegatedConsteval && !elseStmt)
DiagnoseEmptyStmtBody(RParenLoc, thenStmt, diag::warn_empty_if_body);
+ // Checks for if condition variable usage in else scope
+ if (elseStmt) {
+ if (auto* CondVar = dyn_cast_or_null<VarDecl>(Cond.get().first)) {
+ bool usedInElse = false;
+ std::function<bool(Stmt*)> checkForUsage = [&](Stmt *S) -> bool {
+ if (!S) return false;
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
+ if (DRE->getDecl() == CondVar) {
+ return true;
+ }
+ }
+
+ for (Stmt *Child: S->children()) {
+ if (checkForUsage(Child)) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+ usedInElse = checkForUsage(elseStmt);
+
+ if (usedInElse) {
+ Diag(elseStmt->getBeginLoc(), diag::warn_out_of_scope_var_usage)
+ << CondVar->getName();
+ }
+ }
+ }
+
if (ConstevalOrNegatedConsteval ||
StatementKind == IfStatementKind::Constexpr) {
auto DiagnoseLikelihood = [&](const Stmt *S) {
diff --git a/clang/test/Sema/warn-conditional-scope.cpp b/clang/test/Sema/warn-conditional-scope.cpp
new file mode 100644
index 0000000000000..b4b4e2e163c2f
--- /dev/null
+++ b/clang/test/Sema/warn-conditional-scope.cpp
@@ -0,0 +1,74 @@
+// 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
+
+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 at +1{{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 at +1{{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 at +1{{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];
+ }
+ // expected-warning at +1{{variable ptr declared in 'if' block is either false or null}}
+ else if (int *ptr2 = get_something_else()) {
+ return ptr2[0] * ptr2[0];
+ }
+ // expected-warning at +1{{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 at +1{{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
More information about the cfe-commits
mailing list