diff options
| author | Artem Dergachev <artem.dergachev@gmail.com> | 2019-08-29 20:37:28 +0000 |
|---|---|---|
| committer | Artem Dergachev <artem.dergachev@gmail.com> | 2019-08-29 20:37:28 +0000 |
| commit | e5c0994ddfcf64bbc7e65ebb68890e98141b84d9 (patch) | |
| tree | 24cc6e0a6cfe5c838f51e883c5e1b374acfa2e26 /clang/test | |
| parent | fe47ed67fcca1ab5bcb0feb65c6b608137d91140 (diff) | |
| download | bcm5719-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.cpp | 49 | ||||
| -rw-r--r-- | clang/test/Sema/return.c | 11 |
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") |

