From fc6b2281bfd747b3e24d23e2ee8de189f741770f Mon Sep 17 00:00:00 2001 From: isuckatcs <65320245+isuckatcs@users.noreply.github.com> Date: Thu, 16 Jun 2022 19:57:25 +0200 Subject: [PATCH] [Static Analyzer][CFG] Introducing the source array in the CFG of DecompositionDecl For DecompositionDecl, the array, which is being decomposed was not present in the CFG, which lead to the liveness analysis falsely detecting it as a dead symbol. Differential Revision: https://reviews.llvm.org/D127993 --- clang/lib/Analysis/CFG.cpp | 25 +++++++++++++++++++++++++ clang/test/Analysis/cfg.cpp | 16 ++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 8379e10..b16898d 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -609,6 +609,7 @@ private: AddStmtChoice asc); CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc); CFGBlock *VisitWhileStmt(WhileStmt *W); + CFGBlock *VisitArrayInitLoopExpr(ArrayInitLoopExpr *A, AddStmtChoice asc); CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd, bool ExternallyDestructed = false); @@ -2330,6 +2331,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc, case Stmt::WhileStmtClass: return VisitWhileStmt(cast(S)); + + case Stmt::ArrayInitLoopExprClass: + return VisitArrayInitLoopExpr(cast(S), asc); } } @@ -3881,6 +3885,27 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { return EntryConditionBlock; } +CFGBlock *CFGBuilder::VisitArrayInitLoopExpr(ArrayInitLoopExpr *A, + AddStmtChoice asc) { + if (asc.alwaysAdd(*this, A)) { + autoCreateBlock(); + appendStmt(Block, A); + } + + CFGBlock *B = Block; + + if (CFGBlock *R = Visit(A->getSubExpr())) + B = R; + + auto *OVE = dyn_cast(A->getCommonExpr()); + assert(OVE && "ArrayInitLoopExpr->getCommonExpr() should be wrapped in an " + "OpaqueValueExpr!"); + if (CFGBlock *R = Visit(OVE->getSourceExpr())) + B = R; + + return B; +} + CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *CS) { // ObjCAtCatchStmt are treated like labels, so they are the first statement // in a block. diff --git a/clang/test/Analysis/cfg.cpp b/clang/test/Analysis/cfg.cpp index 333ea56..df4c7b3 100644 --- a/clang/test/Analysis/cfg.cpp +++ b/clang/test/Analysis/cfg.cpp @@ -650,6 +650,22 @@ bail: return 0; } +// CHECK-LABEL: void DecompositionDecl() +// CHECK: [B1] +// CHECK-NEXT: 1: int arr[2]; +// CHECK-NEXT: 2: arr +// CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, ArrayToPointerDecay, int *) +// CHECK-NEXT: 4: * +// CHECK-NEXT: 5: [B1.3]{{\[\[}}B1.4]] +// CHECK-NEXT: 6: [B1.5] (ImplicitCastExpr, LValueToRValue, int) +// CHECK-NEXT: 7: {{\{}}[B1.6]{{(\})}} +// CHECK-NEXT: 8: auto = {{\{}}arr[*]{{(\})}}; +void DecompositionDecl() { + int arr[2]; + + auto [a, b] = arr; +} + // CHECK-LABEL: template<> int *PR18472() // CHECK: [B2 (ENTRY)] // CHECK-NEXT: Succs (1): B1 -- 2.7.4