summaryrefslogtreecommitdiffstats
path: root/clang/test
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2019-08-29 20:37:28 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2019-08-29 20:37:28 +0000
commite5c0994ddfcf64bbc7e65ebb68890e98141b84d9 (patch)
tree24cc6e0a6cfe5c838f51e883c5e1b374acfa2e26 /clang/test
parentfe47ed67fcca1ab5bcb0feb65c6b608137d91140 (diff)
downloadbcm5719-llvm-e5c0994ddfcf64bbc7e65ebb68890e98141b84d9.tar.gz
bcm5719-llvm-e5c0994ddfcf64bbc7e65ebb68890e98141b84d9.zip
[CFG] Fix CFG for statement-expressions in return values.
We're building the CFG from bottom to top, so when the return-value expression has a non-trivial CFG on its own, we need to continue building from the entry to the return-value expression CFG rather than from the block to which we've just appended the return statement. Fixes a false positive warning "control may reach end of non-void function". llvm-svn: 370406
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/Analysis/cfg.cpp49
-rw-r--r--clang/test/Sema/return.c11
2 files changed, 59 insertions, 1 deletions
diff --git a/clang/test/Analysis/cfg.cpp b/clang/test/Analysis/cfg.cpp
index 74f4d50f25d..9b0203e99ef 100644
--- a/clang/test/Analysis/cfg.cpp
+++ b/clang/test/Analysis/cfg.cpp
@@ -499,6 +499,54 @@ void foo() {
} // end namespace pr37688_deleted_union_destructor
+namespace return_statement_expression {
+int unknown();
+
+// CHECK-LABEL: int foo()
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+// CHECK: [B1]
+// CHECK-NEXT: 1: 0
+// CHECK-NEXT: 2: return [B1.1];
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: 0
+// CHECK-NEXT: 2: ({ ... ; [B2.1] })
+// CHECK-NEXT: 3: return [B2.2];
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B0
+// FIXME: Why do we have [B3] at all?
+// CHECK: [B3]
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B4]
+// CHECK-NEXT: 1: 0
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: while [B4.2]
+// CHECK-NEXT: Preds (2): B3 B5
+// CHECK-NEXT: Succs (2): NULL B2
+// CHECK: [B5]
+// CHECK-NEXT: 1: unknown
+// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, FunctionToPointerDecay, int (*)(void))
+// CHECK-NEXT: 3: [B5.2]()
+// CHECK-NEXT: 4: [B5.3] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: if [B5.4]
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (2): B4 B1
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (2): B1 B2
+int foo() {
+ if (unknown())
+ return ({
+ while (0)
+ ;
+ 0;
+ });
+ else
+ return 0;
+}
+} // namespace statement_expression_in_return
+
// CHECK-LABEL: template<> int *PR18472<int>()
// CHECK: [B2 (ENTRY)]
// CHECK-NEXT: Succs (1): B1
@@ -522,4 +570,3 @@ template <class T> T *PR18472() {
void PR18472_helper() {
PR18472<int>();
}
-
diff --git a/clang/test/Sema/return.c b/clang/test/Sema/return.c
index debf5ab55f5..68c2251c463 100644
--- a/clang/test/Sema/return.c
+++ b/clang/test/Sema/return.c
@@ -328,3 +328,14 @@ int sizeof_long() {
if (sizeof(long) == 8)
return 2;
} // no-warning
+
+int return_statement_expression() {
+ if (unknown())
+ return ({
+ while (0)
+ ;
+ 0;
+ });
+ else
+ return 0;
+} // no-warning (used to be "control may reach end of non-void function")
OpenPOWER on IntegriCloud