diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -2839,11 +2839,30 @@ /// DeclStmts and initializers in them. CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { assert(DS->isSingleDecl() && "Can handle single declarations only."); + + if (const auto *TND = dyn_cast(DS->getSingleDecl())) { + // If we encounter a VLA, process its size expressions. + const Type *T = TND->getUnderlyingType().getTypePtr(); + if (!T->isVariablyModifiedType()) + return Block; + + autoCreateBlock(); + appendStmt(Block, DS); + + CFGBlock *LastBlock = Block; + for (const VariableArrayType *VA = FindVA(T); VA != nullptr; + VA = FindVA(VA->getElementType().getTypePtr())) { + if (CFGBlock *newBlock = addStmt(VA->getSizeExpr())) + LastBlock = newBlock; + } + return LastBlock; + } + VarDecl *VD = dyn_cast(DS->getSingleDecl()); if (!VD) { - // Of everything that can be declared in a DeclStmt, only VarDecls impact - // runtime semantics. + // Of everything that can be declared in a DeclStmt, only VarDecls and the + // exceptions above impact runtime semantics. return Block; } @@ -2905,6 +2924,8 @@ } // If the type of VD is a VLA, then we must process its size expressions. + // FIXME: This does not find the VLA if it is embedded in other types, + // like here: `void (*vla)(int[x]);` for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr()); VA != nullptr; VA = FindVA(VA->getElementType().getTypePtr())) { if (CFGBlock *newBlock = addStmt(VA->getSizeExpr())) diff --git a/clang/test/Analysis/cfg.cpp b/clang/test/Analysis/cfg.cpp --- a/clang/test/Analysis/cfg.cpp +++ b/clang/test/Analysis/cfg.cpp @@ -568,6 +568,71 @@ return 2; } +// CHECK-LABEL: void vla_simple(int x) +// CHECK: [B1] +// CHECK-NEXT: 1: x +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, int) +// CHECK-NEXT: 3: int vla[x]; +void vla_simple(int x) { + int vla[x]; +} + +// CHECK-LABEL: void vla_typedef(int x) +// CHECK: [B1] +// CHECK-NEXT: 1: x +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, int) +// CHECK-NEXT: 3: typedef int VLA[x]; +void vla_typedef(int x) { + typedef int VLA[x]; +} + +// CHECK-LABEL: void vla_typealias(int x) +// CHECK: [B1] +// CHECK-NEXT: 1: x +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, int) +// CHECK-NEXT: 3: using VLA = int [x]; +void vla_typealias(int x) { + using VLA = int[x]; +} + +// CHECK-LABEL: void vla_typedef_multi(int x, int y) +// CHECK: [B1] +// CHECK-NEXT: 1: y +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, int) +// CHECK-NEXT: 3: x +// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, LValueToRValue, int) +// CHECK-NEXT: 5: typedef int VLA[x][y]; +void vla_typedef_multi(int x, int y) { + typedef int VLA[x][y]; +} + +// CHECK-LABEL: void vla_typedefname_multi(int x, int y) +// CHECK: [B1] +// CHECK-NEXT: 1: x +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, int) +// CHECK-NEXT: 3: typedef int VLA[x]; +// CHECK-NEXT: 4: y +// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, LValueToRValue, int) +// CHECK-NEXT: 6: typedef VLA VLA1[y]; +// CHECK-NEXT: 7: 3 +// CHECK-NEXT: 8: using VLA2 = VLA1 [3]; +// CHECK-NEXT: 9: 4 +// CHECK-NEXT: 10: VLA2 vla[4]; +void vla_typedefname_multi(int x, int y) { + typedef int VLA[x]; + typedef VLA VLA1[y]; + using VLA2 = VLA1[3]; + VLA2 vla[4]; +} + +// CHECK-LABEL: void vla_embedded(int x) +// CHECK: [B1] +// CHECK-NEXT: 1: void (*vla)(int *); +void vla_embedded(int x) { + // FIXME: 'x' is not generated but should be. + void (*vla)(int[x]); +} + // CHECK-LABEL: template<> int *PR18472() // CHECK: [B2 (ENTRY)] // CHECK-NEXT: Succs (1): B1