diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index fab2dacc8a78..d08a01244d78 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -1276,6 +1276,11 @@ class TranslatedJumpStmt extends TranslatedStmt { override JumpStmt stmt; override Instruction getFirstInstruction(EdgeKind kind) { + // The first instruction is a destructor call, if any. + result = this.getChildInternal(0).getFirstInstruction(kind) + or + // Otherwise, the first (and only) instruction is a `NoOp` + not exists(this.getChildInternal(0)) and result = this.getInstruction(OnlyInstructionTag()) and kind instanceof GotoEdge } @@ -1284,7 +1289,20 @@ class TranslatedJumpStmt extends TranslatedStmt { result = this.getInstruction(OnlyInstructionTag()) } - override TranslatedElement getChildInternal(int id) { none() } + private TranslatedCall getTranslatedImplicitDestructorCall(int id) { + result.getExpr() = stmt.getImplicitDestructorCall(id) + } + + override TranslatedElement getLastChild() { + result = + this.getTranslatedImplicitDestructorCall(max(int id | + exists(stmt.getImplicitDestructorCall(id)) + )) + } + + override TranslatedElement getChildInternal(int id) { + result = this.getTranslatedImplicitDestructorCall(id) + } override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) { tag = OnlyInstructionTag() and @@ -1297,7 +1315,19 @@ class TranslatedJumpStmt extends TranslatedStmt { result = getTranslatedStmt(stmt.getTarget()).getFirstInstruction(kind) } - override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { none() } + final override predicate handlesDestructorsExplicitly() { any() } + + override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { + exists(int id | child = this.getChildInternal(id) | + // Transition to the next destructor call, if any. + result = this.getChildInternal(id + 1).getFirstInstruction(kind) + or + // And otherwise, exit this element by flowing to the target of the jump. + not exists(this.getChildInternal(id + 1)) and + kind instanceof GotoEdge and + result = this.getInstruction(OnlyInstructionTag()) + ) + } } private EdgeKind getCaseEdge(SwitchCase switchCase) { diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index 28c1398d90bc..0897b3f25c3e 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -22442,6 +22442,139 @@ ir.cpp: #-----| Type = [Class] ClassWithDestructor #-----| ValueCategory = lvalue # 2499| getStmt(4): [ReturnStmt] return ... +# 2501| [TopLevelFunction] void destruction_in_switch_1(int) +# 2501| : +# 2501| getParameter(0): [Parameter] c +# 2501| Type = [IntType] int +# 2501| getEntryPoint(): [BlockStmt] { ... } +# 2502| getStmt(0): [SwitchStmt] switch (...) ... +# 2502| getExpr(): [VariableAccess] c +# 2502| Type = [IntType] int +# 2502| ValueCategory = prvalue(load) +# 2502| getStmt(): [BlockStmt] { ... } +# 2503| getStmt(0): [SwitchCase] case ...: +# 2503| getExpr(): [Literal] 0 +# 2503| Type = [IntType] int +# 2503| Value = [Literal] 0 +# 2503| ValueCategory = prvalue +# 2503| getStmt(1): [BlockStmt] { ... } +# 2504| getStmt(0): [DeclStmt] declaration +# 2504| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x +# 2504| Type = [Class] ClassWithDestructor +# 2504| getVariable().getInitializer(): [Initializer] initializer for x +# 2504| getExpr(): [ConstructorCall] call to ClassWithDestructor +# 2504| Type = [VoidType] void +# 2504| ValueCategory = prvalue +# 2505| getStmt(1): [BreakStmt] break; +# 2506| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor +# 2506| Type = [VoidType] void +# 2506| ValueCategory = prvalue +# 2506| getQualifier(): [VariableAccess] x +# 2506| Type = [Class] ClassWithDestructor +# 2506| ValueCategory = lvalue +# 2506| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor +# 2506| Type = [VoidType] void +# 2506| ValueCategory = prvalue +# 2506| getQualifier(): [VariableAccess] x +# 2506| Type = [Class] ClassWithDestructor +# 2506| ValueCategory = lvalue +# 2507| getStmt(1): [LabelStmt] label ...: +# 2508| getStmt(2): [ReturnStmt] return ... +# 2510| [TopLevelFunction] void destruction_in_switch_2(int) +# 2510| : +# 2510| getParameter(0): [Parameter] c +# 2510| Type = [IntType] int +# 2510| getEntryPoint(): [BlockStmt] { ... } +# 2511| getStmt(0): [SwitchStmt] switch (...) ... +# 2511| getInitialization(): [DeclStmt] declaration +# 2511| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y +# 2511| Type = [Class] ClassWithDestructor +# 2511| getVariable().getInitializer(): [Initializer] initializer for y +# 2511| getExpr(): [ConstructorCall] call to ClassWithDestructor +# 2511| Type = [VoidType] void +# 2511| ValueCategory = prvalue +# 2511| getExpr(): [VariableAccess] c +# 2511| Type = [IntType] int +# 2511| ValueCategory = prvalue(load) +# 2511| getStmt(): [BlockStmt] { ... } +# 2512| getStmt(0): [SwitchCase] case ...: +# 2512| getExpr(): [Literal] 0 +# 2512| Type = [IntType] int +# 2512| Value = [Literal] 0 +# 2512| ValueCategory = prvalue +# 2512| getStmt(1): [BlockStmt] { ... } +# 2513| getStmt(0): [BreakStmt] break; +# 2515| getStmt(2): [SwitchCase] default: +# 2515| getStmt(3): [BlockStmt] { ... } +# 2516| getStmt(0): [BreakStmt] break; +# 2518| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor +# 2518| Type = [VoidType] void +# 2518| ValueCategory = prvalue +# 2518| getQualifier(): [VariableAccess] y +# 2518| Type = [Class] ClassWithDestructor +# 2518| ValueCategory = lvalue +# 2518| getStmt(1): [LabelStmt] label ...: +# 2519| getStmt(2): [ReturnStmt] return ... +# 2521| [TopLevelFunction] void destruction_in_switch_3(int) +# 2521| : +# 2521| getParameter(0): [Parameter] c +# 2521| Type = [IntType] int +# 2521| getEntryPoint(): [BlockStmt] { ... } +# 2522| getStmt(0): [SwitchStmt] switch (...) ... +# 2522| getInitialization(): [DeclStmt] declaration +# 2522| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y +# 2522| Type = [Class] ClassWithDestructor +# 2522| getVariable().getInitializer(): [Initializer] initializer for y +# 2522| getExpr(): [ConstructorCall] call to ClassWithDestructor +# 2522| Type = [VoidType] void +# 2522| ValueCategory = prvalue +# 2522| getExpr(): [VariableAccess] c +# 2522| Type = [IntType] int +# 2522| ValueCategory = prvalue(load) +# 2522| getStmt(): [BlockStmt] { ... } +# 2523| getStmt(0): [SwitchCase] case ...: +# 2523| getExpr(): [Literal] 0 +# 2523| Type = [IntType] int +# 2523| Value = [Literal] 0 +# 2523| ValueCategory = prvalue +# 2523| getStmt(1): [BlockStmt] { ... } +# 2524| getStmt(0): [DeclStmt] declaration +# 2524| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x +# 2524| Type = [Class] ClassWithDestructor +# 2524| getVariable().getInitializer(): [Initializer] initializer for x +# 2524| getExpr(): [ConstructorCall] call to ClassWithDestructor +# 2524| Type = [VoidType] void +# 2524| ValueCategory = prvalue +# 2525| getStmt(1): [BreakStmt] break; +# 2526| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor +# 2526| Type = [VoidType] void +# 2526| ValueCategory = prvalue +# 2526| getQualifier(): [VariableAccess] x +# 2526| Type = [Class] ClassWithDestructor +# 2526| ValueCategory = lvalue +# 2530| getImplicitDestructorCall(1): [DestructorCall] call to ~ClassWithDestructor +# 2530| Type = [VoidType] void +# 2530| ValueCategory = prvalue +# 2530| getQualifier(): [VariableAccess] y +# 2530| Type = [Class] ClassWithDestructor +# 2530| ValueCategory = lvalue +# 2526| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor +# 2526| Type = [VoidType] void +# 2526| ValueCategory = prvalue +# 2526| getQualifier(): [VariableAccess] x +# 2526| Type = [Class] ClassWithDestructor +# 2526| ValueCategory = lvalue +# 2527| getStmt(2): [SwitchCase] default: +# 2527| getStmt(3): [BlockStmt] { ... } +# 2528| getStmt(0): [BreakStmt] break; +# 2530| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor +# 2530| Type = [VoidType] void +# 2530| ValueCategory = prvalue +# 2530| getQualifier(): [VariableAccess] y +# 2530| Type = [Class] ClassWithDestructor +# 2530| ValueCategory = lvalue +# 2530| getStmt(1): [LabelStmt] label ...: +# 2531| getStmt(2): [ReturnStmt] return ... perf-regression.cpp: # 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&) # 4| : diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected index 68e5d36d2062..e1f8430d1607 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ir.expected @@ -17958,6 +17958,152 @@ ir.cpp: # 2484| v2484_8(void) = AliasedUse : ~m2497_4 # 2484| v2484_9(void) = ExitFunction : +# 2501| void destruction_in_switch_1(int) +# 2501| Block 0 +# 2501| v2501_1(void) = EnterFunction : +# 2501| m2501_2(unknown) = AliasedDefinition : +# 2501| m2501_3(unknown) = InitializeNonLocal : +# 2501| m2501_4(unknown) = Chi : total:m2501_2, partial:m2501_3 +# 2501| r2501_5(glval) = VariableAddress[c] : +# 2501| m2501_6(int) = InitializeParameter[c] : &:r2501_5 +# 2502| r2502_1(glval) = VariableAddress[c] : +# 2502| r2502_2(int) = Load[c] : &:r2502_1, m2501_6 +# 2502| v2502_3(void) = Switch : r2502_2 +#-----| Case[0] -> Block 1 +#-----| Default -> Block 2 + +# 2503| Block 1 +# 2503| v2503_1(void) = NoOp : +# 2504| r2504_1(glval) = VariableAddress[x] : +# 2504| m2504_2(ClassWithDestructor) = Uninitialized[x] : &:r2504_1 +# 2504| r2504_3(glval) = FunctionAddress[ClassWithDestructor] : +# 2504| v2504_4(void) = Call[ClassWithDestructor] : func:r2504_3, this:r2504_1 +# 2504| m2504_5(unknown) = ^CallSideEffect : ~m2501_4 +# 2504| m2504_6(unknown) = Chi : total:m2501_4, partial:m2504_5 +# 2504| m2504_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2504_1 +# 2504| m2504_8(ClassWithDestructor) = Chi : total:m2504_2, partial:m2504_7 +# 2506| r2506_1(glval) = VariableAddress[x] : +# 2506| r2506_2(glval) = FunctionAddress[~ClassWithDestructor] : +# 2506| v2506_3(void) = Call[~ClassWithDestructor] : func:r2506_2, this:r2506_1 +# 2506| m2506_4(unknown) = ^CallSideEffect : ~m2504_6 +# 2506| m2506_5(unknown) = Chi : total:m2504_6, partial:m2506_4 +# 2506| v2506_6(void) = ^IndirectReadSideEffect[-1] : &:r2506_1, m2504_8 +# 2506| m2506_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2506_1 +# 2506| m2506_8(ClassWithDestructor) = Chi : total:m2504_8, partial:m2506_7 +# 2505| v2505_1(void) = NoOp : +#-----| Goto -> Block 2 + +# 2507| Block 2 +# 2507| m2507_1(unknown) = Phi : from 0:~m2501_4, from 1:~m2506_5 +# 2507| v2507_2(void) = NoOp : +# 2508| v2508_1(void) = NoOp : +# 2501| v2501_7(void) = ReturnVoid : +# 2501| v2501_8(void) = AliasedUse : ~m2507_1 +# 2501| v2501_9(void) = ExitFunction : + +# 2510| void destruction_in_switch_2(int) +# 2510| Block 0 +# 2510| v2510_1(void) = EnterFunction : +# 2510| m2510_2(unknown) = AliasedDefinition : +# 2510| m2510_3(unknown) = InitializeNonLocal : +# 2510| m2510_4(unknown) = Chi : total:m2510_2, partial:m2510_3 +# 2510| r2510_5(glval) = VariableAddress[c] : +# 2510| m2510_6(int) = InitializeParameter[c] : &:r2510_5 +# 2511| r2511_1(glval) = VariableAddress[y] : +# 2511| m2511_2(ClassWithDestructor) = Uninitialized[y] : &:r2511_1 +# 2511| r2511_3(glval) = FunctionAddress[ClassWithDestructor] : +# 2511| v2511_4(void) = Call[ClassWithDestructor] : func:r2511_3, this:r2511_1 +# 2511| m2511_5(unknown) = ^CallSideEffect : ~m2510_4 +# 2511| m2511_6(unknown) = Chi : total:m2510_4, partial:m2511_5 +# 2511| m2511_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2511_1 +# 2511| m2511_8(ClassWithDestructor) = Chi : total:m2511_2, partial:m2511_7 +# 2511| r2511_9(glval) = VariableAddress[c] : +# 2511| r2511_10(int) = Load[c] : &:r2511_9, m2510_6 +# 2511| v2511_11(void) = Switch : r2511_10 +#-----| Case[0] -> Block 1 +#-----| Default -> Block 2 + +# 2512| Block 1 +# 2512| v2512_1(void) = NoOp : +# 2513| v2513_1(void) = NoOp : +#-----| Goto -> Block 3 + +# 2515| Block 2 +# 2515| v2515_1(void) = NoOp : +# 2516| v2516_1(void) = NoOp : +#-----| Goto -> Block 3 + +# 2518| Block 3 +# 2518| v2518_1(void) = NoOp : +# 2519| v2519_1(void) = NoOp : +# 2510| v2510_7(void) = ReturnVoid : +# 2510| v2510_8(void) = AliasedUse : ~m2511_6 +# 2510| v2510_9(void) = ExitFunction : + +# 2521| void destruction_in_switch_3(int) +# 2521| Block 0 +# 2521| v2521_1(void) = EnterFunction : +# 2521| m2521_2(unknown) = AliasedDefinition : +# 2521| m2521_3(unknown) = InitializeNonLocal : +# 2521| m2521_4(unknown) = Chi : total:m2521_2, partial:m2521_3 +# 2521| r2521_5(glval) = VariableAddress[c] : +# 2521| m2521_6(int) = InitializeParameter[c] : &:r2521_5 +# 2522| r2522_1(glval) = VariableAddress[y] : +# 2522| m2522_2(ClassWithDestructor) = Uninitialized[y] : &:r2522_1 +# 2522| r2522_3(glval) = FunctionAddress[ClassWithDestructor] : +# 2522| v2522_4(void) = Call[ClassWithDestructor] : func:r2522_3, this:r2522_1 +# 2522| m2522_5(unknown) = ^CallSideEffect : ~m2521_4 +# 2522| m2522_6(unknown) = Chi : total:m2521_4, partial:m2522_5 +# 2522| m2522_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2522_1 +# 2522| m2522_8(ClassWithDestructor) = Chi : total:m2522_2, partial:m2522_7 +# 2522| r2522_9(glval) = VariableAddress[c] : +# 2522| r2522_10(int) = Load[c] : &:r2522_9, m2521_6 +# 2522| v2522_11(void) = Switch : r2522_10 +#-----| Case[0] -> Block 1 +#-----| Default -> Block 2 + +# 2523| Block 1 +# 2523| v2523_1(void) = NoOp : +# 2524| r2524_1(glval) = VariableAddress[x] : +# 2524| m2524_2(ClassWithDestructor) = Uninitialized[x] : &:r2524_1 +# 2524| r2524_3(glval) = FunctionAddress[ClassWithDestructor] : +# 2524| v2524_4(void) = Call[ClassWithDestructor] : func:r2524_3, this:r2524_1 +# 2524| m2524_5(unknown) = ^CallSideEffect : ~m2522_6 +# 2524| m2524_6(unknown) = Chi : total:m2522_6, partial:m2524_5 +# 2524| m2524_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2524_1 +# 2524| m2524_8(ClassWithDestructor) = Chi : total:m2524_2, partial:m2524_7 +# 2526| r2526_1(glval) = VariableAddress[x] : +# 2526| r2526_2(glval) = FunctionAddress[~ClassWithDestructor] : +# 2526| v2526_3(void) = Call[~ClassWithDestructor] : func:r2526_2, this:r2526_1 +# 2526| m2526_4(unknown) = ^CallSideEffect : ~m2524_6 +# 2526| m2526_5(unknown) = Chi : total:m2524_6, partial:m2526_4 +# 2526| v2526_6(void) = ^IndirectReadSideEffect[-1] : &:r2526_1, m2524_8 +# 2526| m2526_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2526_1 +# 2526| m2526_8(ClassWithDestructor) = Chi : total:m2524_8, partial:m2526_7 +# 2530| r2530_1(glval) = VariableAddress[y] : +# 2530| r2530_2(glval) = FunctionAddress[~ClassWithDestructor] : +# 2530| v2530_3(void) = Call[~ClassWithDestructor] : func:r2530_2, this:r2530_1 +# 2530| m2530_4(unknown) = ^CallSideEffect : ~m2526_5 +# 2530| m2530_5(unknown) = Chi : total:m2526_5, partial:m2530_4 +# 2530| v2530_6(void) = ^IndirectReadSideEffect[-1] : &:r2530_1, m2522_8 +# 2530| m2530_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_1 +# 2530| m2530_8(ClassWithDestructor) = Chi : total:m2522_8, partial:m2530_7 +# 2525| v2525_1(void) = NoOp : +#-----| Goto -> Block 3 + +# 2527| Block 2 +# 2527| v2527_1(void) = NoOp : +# 2528| v2528_1(void) = NoOp : +#-----| Goto -> Block 3 + +# 2530| Block 3 +# 2530| m2530_9(unknown) = Phi : from 1:~m2530_5, from 2:~m2522_6 +# 2530| v2530_10(void) = NoOp : +# 2531| v2531_1(void) = NoOp : +# 2521| v2521_7(void) = ReturnVoid : +# 2521| v2521_8(void) = AliasedUse : ~m2530_9 +# 2521| v2521_9(void) = ExitFunction : + perf-regression.cpp: # 6| void Big::Big() # 6| Block 0 diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp index c8840fd0b56e..e6c8b90ea5c8 100644 --- a/cpp/ql/test/library-tests/ir/ir/ir.cpp +++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp @@ -2498,4 +2498,36 @@ void destructor_without_block(bool b) ClassWithDestructor g; } +void destruction_in_switch_1(int c) { + switch (c) { + case 0: { + ClassWithDestructor x; + break; + } + } +} + +void destruction_in_switch_2(int c) { + switch (ClassWithDestructor y; c) { + case 0: { + break; + } + default: { + break; + } + } +} + +void destruction_in_switch_3(int c) { + switch (ClassWithDestructor y; c) { + case 0: { + ClassWithDestructor x; + break; + } + default: { + break; + } + } +} + // semmle-extractor-options: -std=c++20 --clang diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index aadcd33f5104..d2ccd190ac29 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -16372,6 +16372,169 @@ ir.cpp: # 2484| v2484_7(void) = AliasedUse : ~m? # 2484| v2484_8(void) = ExitFunction : +# 2501| void destruction_in_switch_1(int) +# 2501| Block 0 +# 2501| v2501_1(void) = EnterFunction : +# 2501| mu2501_2(unknown) = AliasedDefinition : +# 2501| mu2501_3(unknown) = InitializeNonLocal : +# 2501| r2501_4(glval) = VariableAddress[c] : +# 2501| mu2501_5(int) = InitializeParameter[c] : &:r2501_4 +# 2502| r2502_1(glval) = VariableAddress[c] : +# 2502| r2502_2(int) = Load[c] : &:r2502_1, ~m? +# 2502| v2502_3(void) = Switch : r2502_2 +#-----| Case[0] -> Block 1 +#-----| Default -> Block 3 + +# 2503| Block 1 +# 2503| v2503_1(void) = NoOp : +# 2504| r2504_1(glval) = VariableAddress[x] : +# 2504| mu2504_2(ClassWithDestructor) = Uninitialized[x] : &:r2504_1 +# 2504| r2504_3(glval) = FunctionAddress[ClassWithDestructor] : +# 2504| v2504_4(void) = Call[ClassWithDestructor] : func:r2504_3, this:r2504_1 +# 2504| mu2504_5(unknown) = ^CallSideEffect : ~m? +# 2504| mu2504_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2504_1 +# 2506| r2506_1(glval) = VariableAddress[x] : +# 2506| r2506_2(glval) = FunctionAddress[~ClassWithDestructor] : +# 2506| v2506_3(void) = Call[~ClassWithDestructor] : func:r2506_2, this:r2506_1 +# 2506| mu2506_4(unknown) = ^CallSideEffect : ~m? +# 2506| v2506_5(void) = ^IndirectReadSideEffect[-1] : &:r2506_1, ~m? +# 2506| mu2506_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2506_1 +# 2505| v2505_1(void) = NoOp : +#-----| Goto -> Block 3 + +# 2506| Block 2 +# 2506| r2506_7(glval) = VariableAddress[x] : +# 2506| r2506_8(glval) = FunctionAddress[~ClassWithDestructor] : +# 2506| v2506_9(void) = Call[~ClassWithDestructor] : func:r2506_8, this:r2506_7 +# 2506| mu2506_10(unknown) = ^CallSideEffect : ~m? +# 2506| v2506_11(void) = ^IndirectReadSideEffect[-1] : &:r2506_7, ~m? +# 2506| mu2506_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2506_7 +#-----| Goto -> Block 3 + +# 2507| Block 3 +# 2507| v2507_1(void) = NoOp : +# 2508| v2508_1(void) = NoOp : +# 2501| v2501_6(void) = ReturnVoid : +# 2501| v2501_7(void) = AliasedUse : ~m? +# 2501| v2501_8(void) = ExitFunction : + +# 2510| void destruction_in_switch_2(int) +# 2510| Block 0 +# 2510| v2510_1(void) = EnterFunction : +# 2510| mu2510_2(unknown) = AliasedDefinition : +# 2510| mu2510_3(unknown) = InitializeNonLocal : +# 2510| r2510_4(glval) = VariableAddress[c] : +# 2510| mu2510_5(int) = InitializeParameter[c] : &:r2510_4 +# 2511| r2511_1(glval) = VariableAddress[y] : +# 2511| mu2511_2(ClassWithDestructor) = Uninitialized[y] : &:r2511_1 +# 2511| r2511_3(glval) = FunctionAddress[ClassWithDestructor] : +# 2511| v2511_4(void) = Call[ClassWithDestructor] : func:r2511_3, this:r2511_1 +# 2511| mu2511_5(unknown) = ^CallSideEffect : ~m? +# 2511| mu2511_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2511_1 +# 2511| r2511_7(glval) = VariableAddress[c] : +# 2511| r2511_8(int) = Load[c] : &:r2511_7, ~m? +# 2511| v2511_9(void) = Switch : r2511_8 +#-----| Case[0] -> Block 1 +#-----| Default -> Block 2 + +# 2512| Block 1 +# 2512| v2512_1(void) = NoOp : +# 2513| v2513_1(void) = NoOp : +#-----| Goto -> Block 4 + +# 2515| Block 2 +# 2515| v2515_1(void) = NoOp : +# 2516| v2516_1(void) = NoOp : +#-----| Goto -> Block 4 + +# 2518| Block 3 +# 2518| r2518_1(glval) = VariableAddress[y] : +# 2518| r2518_2(glval) = FunctionAddress[~ClassWithDestructor] : +# 2518| v2518_3(void) = Call[~ClassWithDestructor] : func:r2518_2, this:r2518_1 +# 2518| mu2518_4(unknown) = ^CallSideEffect : ~m? +# 2518| v2518_5(void) = ^IndirectReadSideEffect[-1] : &:r2518_1, ~m? +# 2518| mu2518_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2518_1 +#-----| Goto -> Block 4 + +# 2518| Block 4 +# 2518| v2518_7(void) = NoOp : +# 2519| v2519_1(void) = NoOp : +# 2510| v2510_6(void) = ReturnVoid : +# 2510| v2510_7(void) = AliasedUse : ~m? +# 2510| v2510_8(void) = ExitFunction : + +# 2521| void destruction_in_switch_3(int) +# 2521| Block 0 +# 2521| v2521_1(void) = EnterFunction : +# 2521| mu2521_2(unknown) = AliasedDefinition : +# 2521| mu2521_3(unknown) = InitializeNonLocal : +# 2521| r2521_4(glval) = VariableAddress[c] : +# 2521| mu2521_5(int) = InitializeParameter[c] : &:r2521_4 +# 2522| r2522_1(glval) = VariableAddress[y] : +# 2522| mu2522_2(ClassWithDestructor) = Uninitialized[y] : &:r2522_1 +# 2522| r2522_3(glval) = FunctionAddress[ClassWithDestructor] : +# 2522| v2522_4(void) = Call[ClassWithDestructor] : func:r2522_3, this:r2522_1 +# 2522| mu2522_5(unknown) = ^CallSideEffect : ~m? +# 2522| mu2522_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2522_1 +# 2522| r2522_7(glval) = VariableAddress[c] : +# 2522| r2522_8(int) = Load[c] : &:r2522_7, ~m? +# 2522| v2522_9(void) = Switch : r2522_8 +#-----| Case[0] -> Block 1 +#-----| Default -> Block 3 + +# 2523| Block 1 +# 2523| v2523_1(void) = NoOp : +# 2524| r2524_1(glval) = VariableAddress[x] : +# 2524| mu2524_2(ClassWithDestructor) = Uninitialized[x] : &:r2524_1 +# 2524| r2524_3(glval) = FunctionAddress[ClassWithDestructor] : +# 2524| v2524_4(void) = Call[ClassWithDestructor] : func:r2524_3, this:r2524_1 +# 2524| mu2524_5(unknown) = ^CallSideEffect : ~m? +# 2524| mu2524_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2524_1 +# 2526| r2526_1(glval) = VariableAddress[x] : +# 2526| r2526_2(glval) = FunctionAddress[~ClassWithDestructor] : +# 2526| v2526_3(void) = Call[~ClassWithDestructor] : func:r2526_2, this:r2526_1 +# 2526| mu2526_4(unknown) = ^CallSideEffect : ~m? +# 2526| v2526_5(void) = ^IndirectReadSideEffect[-1] : &:r2526_1, ~m? +# 2526| mu2526_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2526_1 +# 2530| r2530_1(glval) = VariableAddress[y] : +# 2530| r2530_2(glval) = FunctionAddress[~ClassWithDestructor] : +# 2530| v2530_3(void) = Call[~ClassWithDestructor] : func:r2530_2, this:r2530_1 +# 2530| mu2530_4(unknown) = ^CallSideEffect : ~m? +# 2530| v2530_5(void) = ^IndirectReadSideEffect[-1] : &:r2530_1, ~m? +# 2530| mu2530_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_1 +# 2525| v2525_1(void) = NoOp : +#-----| Goto -> Block 5 + +# 2526| Block 2 +# 2526| r2526_7(glval) = VariableAddress[x] : +# 2526| r2526_8(glval) = FunctionAddress[~ClassWithDestructor] : +# 2526| v2526_9(void) = Call[~ClassWithDestructor] : func:r2526_8, this:r2526_7 +# 2526| mu2526_10(unknown) = ^CallSideEffect : ~m? +# 2526| v2526_11(void) = ^IndirectReadSideEffect[-1] : &:r2526_7, ~m? +# 2526| mu2526_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2526_7 +#-----| Goto -> Block 3 + +# 2527| Block 3 +# 2527| v2527_1(void) = NoOp : +# 2528| v2528_1(void) = NoOp : +#-----| Goto -> Block 5 + +# 2530| Block 4 +# 2530| r2530_7(glval) = VariableAddress[y] : +# 2530| r2530_8(glval) = FunctionAddress[~ClassWithDestructor] : +# 2530| v2530_9(void) = Call[~ClassWithDestructor] : func:r2530_8, this:r2530_7 +# 2530| mu2530_10(unknown) = ^CallSideEffect : ~m? +# 2530| v2530_11(void) = ^IndirectReadSideEffect[-1] : &:r2530_7, ~m? +# 2530| mu2530_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_7 +#-----| Goto -> Block 5 + +# 2530| Block 5 +# 2530| v2530_13(void) = NoOp : +# 2531| v2531_1(void) = NoOp : +# 2521| v2521_6(void) = ReturnVoid : +# 2521| v2521_7(void) = AliasedUse : ~m? +# 2521| v2521_8(void) = ExitFunction : + perf-regression.cpp: # 6| void Big::Big() # 6| Block 0