Skip to content

Commit e5c0994

Browse files
committed
[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
1 parent fe47ed6 commit e5c0994

File tree

3 files changed

+61
-4
lines changed

3 files changed

+61
-4
lines changed

clang/lib/Analysis/CFG.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2994,9 +2994,8 @@ CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) {
29942994

29952995
// Visit children
29962996
if (ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) {
2997-
Expr *O = RS->getRetValue();
2998-
if (O)
2999-
Visit(O, AddStmtChoice::AlwaysAdd, /*ExternallyDestructed=*/true);
2997+
if (Expr *O = RS->getRetValue())
2998+
return Visit(O, AddStmtChoice::AlwaysAdd, /*ExternallyDestructed=*/true);
30002999
return Block;
30013000
} else { // co_return
30023001
return VisitChildren(S);

clang/test/Analysis/cfg.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,54 @@ void foo() {
499499
} // end namespace pr37688_deleted_union_destructor
500500

501501

502+
namespace return_statement_expression {
503+
int unknown();
504+
505+
// CHECK-LABEL: int foo()
506+
// CHECK: [B6 (ENTRY)]
507+
// CHECK-NEXT: Succs (1): B5
508+
// CHECK: [B1]
509+
// CHECK-NEXT: 1: 0
510+
// CHECK-NEXT: 2: return [B1.1];
511+
// CHECK-NEXT: Preds (1): B5
512+
// CHECK-NEXT: Succs (1): B0
513+
// CHECK: [B2]
514+
// CHECK-NEXT: 1: 0
515+
// CHECK-NEXT: 2: ({ ... ; [B2.1] })
516+
// CHECK-NEXT: 3: return [B2.2];
517+
// CHECK-NEXT: Preds (1): B4
518+
// CHECK-NEXT: Succs (1): B0
519+
// FIXME: Why do we have [B3] at all?
520+
// CHECK: [B3]
521+
// CHECK-NEXT: Succs (1): B4
522+
// CHECK: [B4]
523+
// CHECK-NEXT: 1: 0
524+
// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, IntegralToBoolean, _Bool)
525+
// CHECK-NEXT: T: while [B4.2]
526+
// CHECK-NEXT: Preds (2): B3 B5
527+
// CHECK-NEXT: Succs (2): NULL B2
528+
// CHECK: [B5]
529+
// CHECK-NEXT: 1: unknown
530+
// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, FunctionToPointerDecay, int (*)(void))
531+
// CHECK-NEXT: 3: [B5.2]()
532+
// CHECK-NEXT: 4: [B5.3] (ImplicitCastExpr, IntegralToBoolean, _Bool)
533+
// CHECK-NEXT: T: if [B5.4]
534+
// CHECK-NEXT: Preds (1): B6
535+
// CHECK-NEXT: Succs (2): B4 B1
536+
// CHECK: [B0 (EXIT)]
537+
// CHECK-NEXT: Preds (2): B1 B2
538+
int foo() {
539+
if (unknown())
540+
return ({
541+
while (0)
542+
;
543+
0;
544+
});
545+
else
546+
return 0;
547+
}
548+
} // namespace statement_expression_in_return
549+
502550
// CHECK-LABEL: template<> int *PR18472<int>()
503551
// CHECK: [B2 (ENTRY)]
504552
// CHECK-NEXT: Succs (1): B1
@@ -522,4 +570,3 @@ template <class T> T *PR18472() {
522570
void PR18472_helper() {
523571
PR18472<int>();
524572
}
525-

clang/test/Sema/return.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,3 +328,14 @@ int sizeof_long() {
328328
if (sizeof(long) == 8)
329329
return 2;
330330
} // no-warning
331+
332+
int return_statement_expression() {
333+
if (unknown())
334+
return ({
335+
while (0)
336+
;
337+
0;
338+
});
339+
else
340+
return 0;
341+
} // no-warning (used to be "control may reach end of non-void function")

0 commit comments

Comments
 (0)