[clang] 3b9b3d5 - [Analyzer] Include typedef statements in CFG build.
Balázs Kéri via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 27 03:36:50 PDT 2020
Author: Balázs Kéri
Date: 2020-04-27T12:36:26+02:00
New Revision: 3b9b3d56efaa6f611458899d5a1cdc74f36d72a4
URL: https://github.com/llvm/llvm-project/commit/3b9b3d56efaa6f611458899d5a1cdc74f36d72a4
DIFF: https://github.com/llvm/llvm-project/commit/3b9b3d56efaa6f611458899d5a1cdc74f36d72a4.diff
LOG: [Analyzer] Include typedef statements in CFG build.
Summary:
Array size expressions in typedef statements with a VLA
(variable-length array) are handled from now as in plain
(non-typedef) VLA declarations.
Type-aliases with VLA are handled too
(but main focus is on C code).
Reviewers: Szelethus, aaron.ballman, NoQ, xazax.hun
Reviewed By: aaron.ballman, xazax.hun
Subscribers: rnkovacs, NoQ, efriedma, xazax.hun, baloghadamsoftware, szepet, a.sidorin, mikhail.ramalho, Szelethus, donat.nagy, dkrupp, gamesh411, Charusso, martong, ASDenysPetrov, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D77809
Added:
clang/test/Analysis/cfg.c
Modified:
clang/lib/Analysis/CFG.cpp
clang/test/Analysis/cfg.cpp
Removed:
################################################################################
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 8091625703bc..bedc8455366f 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -2839,11 +2839,30 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
/// DeclStmts and initializers in them.
CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
assert(DS->isSingleDecl() && "Can handle single declarations only.");
+
+ if (const auto *TND = dyn_cast<TypedefNameDecl>(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<VarDecl>(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 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
}
// 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: `int (*p_vla)[x];`
for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr());
VA != nullptr; VA = FindVA(VA->getElementType().getTypePtr())) {
if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
@@ -3997,6 +4018,11 @@ CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
}
// VLA types have expressions that must be evaluated.
+ // Evaluation is done only for `sizeof`.
+
+ if (E->getKind() != UETT_SizeOf)
+ return Block;
+
CFGBlock *lastBlock = Block;
if (E->isArgumentType()) {
diff --git a/clang/test/Analysis/cfg.c b/clang/test/Analysis/cfg.c
new file mode 100644
index 000000000000..3494dd6ac2a3
--- /dev/null
+++ b/clang/test/Analysis/cfg.c
@@ -0,0 +1,120 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -fheinous-gnu-extensions %s > %t 2>&1
+// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,WARNINGS %s
+
+// This file is the C version of cfg.cpp.
+// Tests that are C-specific should go into this file.
+
+// CHECK-LABEL: void checkWrap(int i)
+// CHECK: ENTRY
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK: Succs (21): B2 B3 B4 B5 B6 B7 B8 B9
+// CHECK: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19
+// CHECK: B20 B21 B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (21): B2 B3 B4 B5 B6 B7 B8 B9
+// CHECK-NEXT: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19
+// CHECK-NEXT: B20 B21 B1
+void checkWrap(int i) {
+ switch(i) {
+ case 0: break;
+ case 1: break;
+ case 2: break;
+ case 3: break;
+ case 4: break;
+ case 5: break;
+ case 6: break;
+ case 7: break;
+ case 8: break;
+ case 9: break;
+ case 10: break;
+ case 11: break;
+ case 12: break;
+ case 13: break;
+ case 14: break;
+ case 15: break;
+ case 16: break;
+ case 17: break;
+ case 18: break;
+ case 19: break;
+ }
+}
+
+// CHECK-LABEL: void checkGCCAsmRValueOutput()
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: int arg
+// CHECK-NEXT: 2: arg
+// CHECK-NEXT: 3: (int)[B1.2] (CStyleCastExpr, NoOp, int)
+// CHECK-NEXT: 4: asm ("" : "=r" ([B1.3]));
+// CHECK-NEXT: 5: arg
+// CHECK-NEXT: 6: asm ("" : "=r" ([B1.5]));
+void checkGCCAsmRValueOutput() {
+ int arg;
+ __asm__("" : "=r"((int)arg)); // rvalue output operand
+ __asm__("" : "=r"(arg)); // lvalue output operand
+}
+
+// CHECK-LABEL: int overlap_compare(int x)
+// CHECK: [B2]
+// CHECK-NEXT: 1: 1
+// CHECK-NEXT: 2: return [B2.1];
+// CHECK-NEXT: Preds (1): B3(Unreachable)
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B3]
+// CHECK-NEXT: 1: x
+// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 5
+// CHECK-NEXT: 4: [B3.2] > [B3.3]
+// CHECK-NEXT: T: if [B4.5] && [B3.4]
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (2): B2(Unreachable) B1
+int overlap_compare(int x) {
+ if (x == -1 && x > 5)
+ return 1;
+
+ 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_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_type_indirect(int x)
+// CHECK: [B1]
+// CHECK-NEXT: 1: int (*p_vla)[x];
+// CHECK-NEXT: 2: void (*fp_vla)(int *);
+void vla_type_indirect(int x) {
+ // Should evaluate x
+ // FIXME: does not work
+ int (*p_vla)[x];
+
+ // Do not evaluate x
+ void (*fp_vla)(int[x]);
+}
diff --git a/clang/test/Analysis/cfg.cpp b/clang/test/Analysis/cfg.cpp
index a7d707ee20d1..0159a3c0488c 100644
--- a/clang/test/Analysis/cfg.cpp
+++ b/clang/test/Analysis/cfg.cpp
@@ -12,42 +12,6 @@
// off. Feel free to add tests that test only one of the CFG flavors if you're
// not sure how the other flavor is supposed to work in your case.
-// CHECK-LABEL: void checkWrap(int i)
-// CHECK: ENTRY
-// CHECK-NEXT: Succs (1): B1
-// CHECK: [B1]
-// CHECK: Succs (21): B2 B3 B4 B5 B6 B7 B8 B9
-// CHECK: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19
-// CHECK: B20 B21 B0
-// CHECK: [B0 (EXIT)]
-// CHECK-NEXT: Preds (21): B2 B3 B4 B5 B6 B7 B8 B9
-// CHECK-NEXT: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19
-// CHECK-NEXT: B20 B21 B1
-void checkWrap(int i) {
- switch(i) {
- case 0: break;
- case 1: break;
- case 2: break;
- case 3: break;
- case 4: break;
- case 5: break;
- case 6: break;
- case 7: break;
- case 8: break;
- case 9: break;
- case 10: break;
- case 11: break;
- case 12: break;
- case 13: break;
- case 14: break;
- case 15: break;
- case 16: break;
- case 17: break;
- case 18: break;
- case 19: break;
- }
-}
-
// CHECK-LABEL: void checkDeclStmts()
// CHECK: ENTRY
// CHECK-NEXT: Succs (1): B1
@@ -84,24 +48,6 @@ void checkDeclStmts() {
static_assert(1, "abc");
}
-
-// CHECK-LABEL: void checkGCCAsmRValueOutput()
-// CHECK: [B2 (ENTRY)]
-// CHECK-NEXT: Succs (1): B1
-// CHECK: [B1]
-// CHECK-NEXT: 1: int arg
-// CHECK-NEXT: 2: arg
-// CHECK-NEXT: 3: (int)[B1.2] (CStyleCastExpr, NoOp, int)
-// CHECK-NEXT: 4: asm ("" : "=r" ([B1.3]));
-// CHECK-NEXT: 5: arg
-// CHECK-NEXT: 6: asm ("" : "=r" ([B1.5]));
-void checkGCCAsmRValueOutput() {
- int arg;
- __asm__("" : "=r"((int)arg)); // rvalue output operand
- __asm__("" : "=r"(arg)); // lvalue output operand
-}
-
-
// CHECK-LABEL: void F(EmptyE e)
// CHECK: ENTRY
// CHECK-NEXT: Succs (1): B1
@@ -136,7 +82,6 @@ void testBuiltinSize() {
(void)__builtin_object_size(dummy(), 0);
}
-
class A {
public:
A() {}
@@ -355,7 +300,6 @@ int test_enum_with_extension_default(enum MyEnum value) {
return x;
}
-
// CHECK-LABEL: void test_placement_new()
// CHECK: [B2 (ENTRY)]
// CHECK-NEXT: Succs (1): B1
@@ -547,25 +491,88 @@ int foo() {
}
} // namespace statement_expression_in_return
-// CHECK-LABEL: int overlap_compare(int x)
-// CHECK: [B2]
-// CHECK-NEXT: 1: 1
-// CHECK-NEXT: 2: return [B2.1];
-// CHECK-NEXT: Preds (1): B3(Unreachable)
-// CHECK-NEXT: Succs (1): B0
-// CHECK: [B3]
+// CHECK-LABEL: void vla_simple(int x)
+// CHECK: [B1]
// CHECK-NEXT: 1: x
-// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, LValueToRValue, int)
-// CHECK-NEXT: 3: 5
-// CHECK-NEXT: 4: [B3.2] > [B3.3]
-// CHECK-NEXT: T: if [B4.5] && [B3.4]
-// CHECK-NEXT: Preds (1): B4
-// CHECK-NEXT: Succs (2): B2(Unreachable) B1
-int overlap_compare(int x) {
- if (x == -1 && x > 5)
- return 1;
-
- return 2;
+// 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: int vla_evaluate(int x)
+// CHECK: [B1]
+// CHECK-NEXT: 1: x
+// CHECK-NEXT: 2: ++[B1.1]
+// CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 4: typedef int VLA[++x];
+// CHECK-NEXT: 5: x
+// CHECK-NEXT: 6: ++[B1.5]
+// CHECK-NEXT: 7: [B1.6] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 8: sizeof(int [++x])
+// CHECK-NEXT: 9: alignof(int [++x])
+// CHECK-NEXT: 10: 0
+// CHECK-NEXT: 11: x
+// CHECK-NEXT: 12: [B1.11] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 13: return [B1.12];
+int vla_evaluate(int x) {
+ // Evaluates the ++x
+ typedef int VLA[++x];
+ sizeof(int[++x]);
+
+ // Do not evaluate the ++x
+ _Alignof(int[++x]);
+ _Generic((int(*)[++x])0, default : 0);
+
+ return x;
}
// CHECK-LABEL: template<> int *PR18472<int>()
More information about the cfe-commits
mailing list