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
