tomasz-kaminski-sonarsource created this revision. Herald added a reviewer: NoQ. Herald added a project: All. tomasz-kaminski-sonarsource requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Per [stmt.for] p1 (https://eel.is/c++draft/stmt.for#1) the following 'for' and `while` statement are equivalent for (; A c = b; b.c) { A d; } while (A c = b) { A d; b.c; } As a consequence, the variable declared in for condition expression should be destroyed after the increment expression. Co-authored-by: Tomasz Kamiński <tomasz.kamińs...@sonarsource.com> Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D155547 Files: clang/lib/Analysis/CFG.cpp clang/test/Analysis/auto-obj-dtors-cfg-output.cpp clang/test/Analysis/lifetime-cfg-output.cpp clang/test/Analysis/scopes-cfg-output.cpp
Index: clang/test/Analysis/scopes-cfg-output.cpp =================================================================== --- clang/test/Analysis/scopes-cfg-output.cpp +++ clang/test/Analysis/scopes-cfg-output.cpp @@ -25,6 +25,7 @@ // CHECK: [B0 (EXIT)] // CHECK-NEXT: Preds (1): B1 operator int() const { return 1; } + int *p; }; int getX(); @@ -524,6 +525,10 @@ // CHECK-NEXT: Preds (1): B4 // CHECK-NEXT: Succs (1): B0 // CHECK: [B2] +// CHECK-NEXT: 1: b +// CHECK-NEXT: 2: [B2.1].p +// CHECK-NEXT: 3: [B4.5].~A() (Implicit destructor) +// CHECK-NEXT: 4: CFGScopeEnd(b) // CHECK-NEXT: Preds (1): B3 // CHECK-NEXT: Succs (1): B4 // CHECK: [B3] @@ -532,8 +537,6 @@ // CHECK-NEXT: 3: A c; // CHECK-NEXT: 4: [B3.3].~A() (Implicit destructor) // CHECK-NEXT: 5: CFGScopeEnd(c) -// CHECK-NEXT: 6: [B4.5].~A() (Implicit destructor) -// CHECK-NEXT: 7: CFGScopeEnd(b) // CHECK-NEXT: Preds (1): B4 // CHECK-NEXT: Succs (1): B2 // CHECK: [B4] @@ -548,7 +551,7 @@ // CHECK-NEXT: 9: [B4.7] // CHECK-NEXT: 10: [B4.9] (ImplicitCastExpr, UserDefinedConversion, int) // CHECK-NEXT: 11: [B4.10] (ImplicitCastExpr, IntegralToBoolean, _Bool) -// CHECK-NEXT: T: for (...; [B4.11]; ) +// CHECK-NEXT: T: for (...; [B4.11]; ...) // CHECK-NEXT: Preds (2): B2 B5 // CHECK-NEXT: Succs (2): B3 B1 // CHECK: [B5] @@ -560,7 +563,7 @@ // CHECK: [B0 (EXIT)] // CHECK-NEXT: Preds (1): B1 void test_for_implicit_scope() { - for (A a; A b = a; ) + for (A a; A b = a; b.p) A c; } @@ -579,6 +582,10 @@ // CHECK-NEXT: Preds (2): B8 B10 // CHECK-NEXT: Succs (1): B0 // CHECK: [B2] +// CHECK-NEXT: 1: c +// CHECK-NEXT: 2: [B2.1].p +// CHECK-NEXT: 3: [B10.5].~A() (Implicit destructor) +// CHECK-NEXT: 4: CFGScopeEnd(c) // CHECK-NEXT: Preds (2): B3 B6 // CHECK-NEXT: Succs (1): B10 // CHECK: [B3] @@ -587,8 +594,6 @@ // CHECK-NEXT: 3: [B3.2].~A() (Implicit destructor) // CHECK-NEXT: 4: [B9.3].~A() (Implicit destructor) // CHECK-NEXT: 5: CFGScopeEnd(d) -// CHECK-NEXT: 6: [B10.5].~A() (Implicit destructor) -// CHECK-NEXT: 7: CFGScopeEnd(c) // CHECK-NEXT: Preds (1): B5 // CHECK-NEXT: Succs (1): B2 // CHECK: [B4] @@ -648,7 +653,7 @@ // CHECK-NEXT: 9: [B10.7] // CHECK-NEXT: 10: [B10.9] (ImplicitCastExpr, UserDefinedConversion, int) // CHECK-NEXT: 11: [B10.10] (ImplicitCastExpr, IntegralToBoolean, _Bool) -// CHECK-NEXT: T: for (...; [B10.11]; ) +// CHECK-NEXT: T: for (...; [B10.11]; ...) // CHECK-NEXT: Preds (2): B2 B11 // CHECK-NEXT: Succs (2): B9 B1 // CHECK: [B11] @@ -664,7 +669,7 @@ // CHECK-NEXT: Preds (2): B1 B4 void test_for_jumps() { A a; - for (A b; A c = b; ) { + for (A b; A c = b; c.p) { A d; if (UV) break; if (UV) continue; Index: clang/test/Analysis/lifetime-cfg-output.cpp =================================================================== --- clang/test/Analysis/lifetime-cfg-output.cpp +++ clang/test/Analysis/lifetime-cfg-output.cpp @@ -529,13 +529,15 @@ // CHECK-NEXT: Preds (1): B4 // CHECK-NEXT: Succs (1): B0 // CHECK: [B2] +// CHECK-NEXT: 1: b +// CHECK-NEXT: 2: [B2.1].p +// CHECK-NEXT: 3: [B4.4] (Lifetime ends) // CHECK-NEXT: Preds (1): B3 // CHECK-NEXT: Succs (1): B4 // CHECK: [B3] // CHECK-NEXT: 1: (CXXConstructExpr, A) // CHECK-NEXT: 2: A c; // CHECK-NEXT: 3: [B3.2] (Lifetime ends) -// CHECK-NEXT: 4: [B4.4] (Lifetime ends) // CHECK-NEXT: Preds (1): B4 // CHECK-NEXT: Succs (1): B2 // CHECK: [B4] @@ -549,7 +551,7 @@ // CHECK-NEXT: 8: [B4.6] // CHECK-NEXT: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int) // CHECK-NEXT: 10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) -// CHECK-NEXT: T: for (...; [B4.10]; ) +// CHECK-NEXT: T: for (...; [B4.10]; ...) // CHECK-NEXT: Preds (2): B2 B5 // CHECK-NEXT: Succs (2): B3 B1 // CHECK: [B5] @@ -560,7 +562,7 @@ // CHECK: [B0 (EXIT)] // CHECK-NEXT: Preds (1): B1 void test_for_implicit_scope() { - for (A a; A b = a;) + for (A a; A b = a; b.p) A c; } @@ -576,6 +578,9 @@ // CHECK-NEXT: Preds (2): B8 B10 // CHECK-NEXT: Succs (1): B0 // CHECK: [B2] +// CHECK-NEXT: 1: c +// CHECK-NEXT: 2: [B2.1].p +// CHECK-NEXT: 3: [B10.4] (Lifetime ends) // CHECK-NEXT: Preds (2): B3 B6 // CHECK-NEXT: Succs (1): B10 // CHECK: [B3] @@ -583,7 +588,6 @@ // CHECK-NEXT: 2: A e; // CHECK-NEXT: 3: [B3.2] (Lifetime ends) // CHECK-NEXT: 4: [B9.2] (Lifetime ends) -// CHECK-NEXT: 5: [B10.4] (Lifetime ends) // CHECK-NEXT: Preds (1): B5 // CHECK-NEXT: Succs (1): B2 // CHECK: [B4] @@ -635,7 +639,7 @@ // CHECK-NEXT: 8: [B10.6] // CHECK-NEXT: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int) // CHECK-NEXT: 10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) -// CHECK-NEXT: T: for (...; [B10.10]; ) +// CHECK-NEXT: T: for (...; [B10.10]; ...) // CHECK-NEXT: Preds (2): B2 B11 // CHECK-NEXT: Succs (2): B9 B1 // CHECK: [B11] @@ -649,7 +653,7 @@ // CHECK-NEXT: Preds (2): B1 B4 void test_for_jumps() { A a; - for (A b; A c = b;) { + for (A b; A c = b; c.p) { A d; if (UV) break; Index: clang/test/Analysis/auto-obj-dtors-cfg-output.cpp =================================================================== --- clang/test/Analysis/auto-obj-dtors-cfg-output.cpp +++ clang/test/Analysis/auto-obj-dtors-cfg-output.cpp @@ -1040,6 +1040,10 @@ // CHECK-NEXT: Preds (1): B4 // CHECK-NEXT: Succs (1): B0 // CHECK: [B2] +// CHECK-NEXT: 1: b +// CHECK-NEXT: 2: [B2.1].x +// CHECK-NEXT: 3: ++[B2.2] +// CHECK-NEXT: 4: [B4.4].~A() (Implicit destructor) // CHECK-NEXT: Preds (1): B3 // CHECK-NEXT: Succs (1): B4 // CHECK: [B3] @@ -1047,7 +1051,6 @@ // ANALYZER-NEXT: 1: (CXXConstructExpr, [B3.2], A) // CHECK-NEXT: 2: A c; // CHECK-NEXT: 3: [B3.2].~A() (Implicit destructor) -// CHECK-NEXT: 4: [B4.4].~A() (Implicit destructor) // CHECK-NEXT: Preds (1): B4 // CHECK-NEXT: Succs (1): B2 // CHECK: [B4] @@ -1062,7 +1065,7 @@ // CHECK-NEXT: 8: [B4.6] // CHECK-NEXT: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int) // CHECK: 10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) -// CHECK-NEXT: T: for (...; [B4.10]; ) +// CHECK-NEXT: T: for (...; [B4.10]; ...) // CHECK-NEXT: Preds (2): B2 B5 // CHECK-NEXT: Succs (2): B3 B1 // CHECK: [B5] @@ -1074,7 +1077,7 @@ // CHECK: [B0 (EXIT)] // CHECK-NEXT: Preds (1): B1 void test_for_implicit_scope() { - for (A a; A b = a; ) + for (A a; A b = a; ++b.x) A c; } @@ -1144,6 +1147,10 @@ // CHECK-NEXT: Preds (2): B8 B10 // CHECK-NEXT: Succs (1): B0 // CHECK: [B2] +// CHECK-NEXT: 1: c +// CHECK-NEXT: 2: [B2.1].x +// CHECK-NEXT: 3: ++[B2.2] +// CHECK-NEXT: 4: [B10.4].~A() (Implicit destructor) // CHECK-NEXT: Preds (2): B3 B6 // CHECK-NEXT: Succs (1): B10 // CHECK: [B3] @@ -1152,7 +1159,6 @@ // CHECK-NEXT: 2: A e; // CHECK-NEXT: 3: [B3.2].~A() (Implicit destructor) // CHECK-NEXT: 4: [B9.2].~A() (Implicit destructor) -// CHECK-NEXT: 5: [B10.4].~A() (Implicit destructor) // CHECK-NEXT: Preds (1): B5 // CHECK-NEXT: Succs (1): B2 // CHECK: [B4] @@ -1206,7 +1212,7 @@ // CHECK-NEXT: 8: [B10.6] // CHECK-NEXT: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int) // CHECK: 10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) -// CHECK-NEXT: T: for (...; [B10.10]; ) +// CHECK-NEXT: T: for (...; [B10.10]; ...) // CHECK-NEXT: Preds (2): B2 B11 // CHECK-NEXT: Succs (2): B9 B1 // CHECK: [B11] @@ -1222,7 +1228,7 @@ // CHECK-NEXT: Preds (2): B1 B4 void test_for_jumps() { A a; - for (A b; A c = b; ) { + for (A b; A c = b; ++c.x) { A d; if (UV) break; if (UV) continue; Index: clang/lib/Analysis/CFG.cpp =================================================================== --- clang/lib/Analysis/CFG.cpp +++ clang/lib/Analysis/CFG.cpp @@ -3511,6 +3511,11 @@ Block = Succ = TransitionBlock = createBlock(false); TransitionBlock->setLoopTarget(F); + + // Loop iteration (after increment) should end with destructor of Condition + // variable (if any). + addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F); + if (Stmt *I = F->getInc()) { // Generate increment code in its own basic block. This is the target of // continue statements. @@ -3530,8 +3535,6 @@ ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos); ContinueJumpTarget.block->setLoopTarget(F); - // Loop body should end with destructor of Condition variable (if any). - addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F); // If body is not a compound statement create implicit scope // and add destructors.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits