From e5ded955c4005ab52dd75c87550034fe34f6f479 Mon Sep 17 00:00:00 2001 From: arrowten 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>, DefaultError; +def warn_out_of_scope_var_usage + : Warning<"variable %0 declared in 'if' block is either false or null">, + InGroup>; // 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(Cond.get().first)) { + bool usedInElse = false; + std::function checkForUsage = [&](Stmt *S) -> bool { + if (!S) return false; + if (DeclRefExpr *DRE = dyn_cast(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@+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@+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@+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@+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@+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@+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