Merge pull request #16459 from jketema/handler-fix

C++: Fix destructor translation for handlers
This commit is contained in:
Jeroen Ketema
2024-05-09 10:23:07 +02:00
committed by GitHub
4 changed files with 134 additions and 54 deletions

View File

@@ -830,6 +830,12 @@ newtype TTranslatedElement =
not ignoreExpr(dc)
)
} or
// The set of destructors to invoke after a handler for a `try` statement. These
// need to be special cased because the destructors need to run following an
// `ExceptionEdge`, but not following a `GotoEdge` edge.
TTranslatedDestructorsAfterHandler(Handler handler) {
exists(handler.getAnImplicitDestructorCall())
} or
// A precise side effect of an argument to a `Call`
TTranslatedArgumentExprSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
not ignoreExpr(expr) and

View File

@@ -777,6 +777,72 @@ abstract class TranslatedHandler extends TranslatedStmt {
TranslatedStmt getBlock() { result = getTranslatedStmt(stmt.getBlock()) }
}
/**
* The IR translation of the destructor calls of the parent `TranslatedCatchByTypeHandler`.
*
* This object does not itself generate the destructor calls. Instead, its
* children provide the actual calls.
*/
class TranslatedDestructorsAfterHandler extends TranslatedElement,
TTranslatedDestructorsAfterHandler
{
Handler handler;
TranslatedDestructorsAfterHandler() { this = TTranslatedDestructorsAfterHandler(handler) }
override string toString() { result = "Destructor calls after handler: " + handler }
private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
result.getExpr() = handler.getImplicitDestructorCall(id)
}
override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getChild(0).getFirstInstruction(kind)
}
override Handler getAst() { result = handler }
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) { none() }
override TranslatedElement getChild(int id) {
result = this.getTranslatedImplicitDestructorCall(id)
}
override predicate handlesDestructorsExplicitly() { any() }
override Declaration getFunction() { result = handler.getEnclosingFunction() }
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
exists(int id | child = this.getChild(id) |
// Transition to the next child, if any.
result = this.getChild(id + 1).getFirstInstruction(kind)
or
// And otherwise go to the next handler, if any.
not exists(this.getChild(id + 1)) and
result =
getTranslatedStmt(handler)
.getParent()
.(TranslatedTryStmt)
.getNextHandler(getTranslatedStmt(handler), kind)
)
}
override TranslatedElement getLastChild() {
result =
this.getTranslatedImplicitDestructorCall(max(int id |
exists(handler.getImplicitDestructorCall(id))
))
}
override Instruction getALastInstructionInternal() {
result = this.getLastChild().getALastInstruction()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
none()
}
}
/**
* The IR translation of a C++ `catch` block that catches an exception with a
* specific type (e.g. `catch (const std::exception&)`).
@@ -790,10 +856,14 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
resultType = getVoidType()
}
override predicate handlesDestructorsExplicitly() { any() }
override TranslatedElement getChildInternal(int id) {
result = super.getChildInternal(id)
or
id = 0 and result = this.getParameter()
or
id = 1 and result = this.getDestructors()
}
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
@@ -810,7 +880,9 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
result = this.getParameter().getFirstInstruction(kind)
or
kind instanceof ExceptionEdge and
result = this.getParent().(TranslatedTryStmt).getNextHandler(this, any(GotoEdge edge))
if exists(this.getDestructors())
then result = this.getDestructors().getFirstInstruction(any(GotoEdge edge))
else result = this.getParent().(TranslatedTryStmt).getNextHandler(this, any(GotoEdge edge))
)
}
@@ -822,6 +894,8 @@ class TranslatedCatchByTypeHandler extends TranslatedHandler {
private TranslatedParameter getParameter() {
result = getTranslatedParameter(stmt.getParameter())
}
private TranslatedDestructorsAfterHandler getDestructors() { result.getAst() = stmt }
}
/**

View File

@@ -18220,44 +18220,44 @@ ir.cpp:
# 2537| r2537_2(int) = Constant[42] :
# 2537| m2537_3(int) = Store[#throw2537:5] : &:r2537_1, r2537_2
# 2537| v2537_4(void) = ThrowValue : &:r2537_1, m2537_3
#-----| Exception -> Block 3
#-----| Exception -> Block 2
# 2534| Block 1
# 2534| m2534_5(unknown) = Phi : from 2:~m2535_6, from 4:~m2541_14
# 2534| m2534_5(unknown) = Phi : from 3:~m2541_6, from 4:~m2541_14
# 2534| v2534_6(void) = AliasedUse : ~m2534_5
# 2534| v2534_7(void) = ExitFunction :
# 2534| Block 2
# 2534| v2534_8(void) = Unwind :
#-----| Goto -> Block 1
# 2539| Block 2
# 2539| v2539_1(void) = CatchByType[char] :
#-----| Exception -> Block 4
#-----| Goto -> Block 3
# 2539| Block 3
# 2539| v2539_1(void) = CatchByType[char] :
#-----| Exception -> Block 2
#-----| Goto -> Block 4
# 2539| r2539_2(glval<char>) = VariableAddress[(unnamed parameter 0)] :
# 2539| m2539_3(char) = InitializeParameter[(unnamed parameter 0)] : &:r2539_2
# 2539| v2539_4(void) = NoOp :
# 2541| v2541_1(void) = NoOp :
# 2541| r2541_2(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2541| r2541_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2541| v2541_4(void) = Call[~ClassWithDestructor] : func:r2541_3, this:r2541_2
# 2541| m2541_5(unknown) = ^CallSideEffect : ~m2535_6
# 2541| m2541_6(unknown) = Chi : total:m2535_6, partial:m2541_5
# 2541| v2541_7(void) = ^IndirectReadSideEffect[-1] : &:r2541_2, m2535_8
# 2541| m2541_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_2
# 2541| m2541_9(ClassWithDestructor) = Chi : total:m2535_8, partial:m2541_8
# 2534| v2534_8(void) = ReturnVoid :
#-----| Goto -> Block 1
# 2539| Block 4
# 2539| r2539_2(glval<char>) = VariableAddress[(unnamed parameter 0)] :
# 2539| m2539_3(char) = InitializeParameter[(unnamed parameter 0)] : &:r2539_2
# 2539| v2539_4(void) = NoOp :
# 2541| r2541_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2541| r2541_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2541| v2541_3(void) = Call[~ClassWithDestructor] : func:r2541_2, this:r2541_1
# 2541| m2541_4(unknown) = ^CallSideEffect : ~m2535_6
# 2541| m2541_5(unknown) = Chi : total:m2535_6, partial:m2541_4
# 2541| v2541_6(void) = ^IndirectReadSideEffect[-1] : &:r2541_1, m2535_8
# 2541| m2541_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_1
# 2541| m2541_8(ClassWithDestructor) = Chi : total:m2535_8, partial:m2541_7
# 2541| v2541_9(void) = NoOp :
# 2541| r2541_10(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2541| r2541_11(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2541| v2541_12(void) = Call[~ClassWithDestructor] : func:r2541_11, this:r2541_10
# 2541| m2541_13(unknown) = ^CallSideEffect : ~m2541_5
# 2541| m2541_14(unknown) = Chi : total:m2541_5, partial:m2541_13
# 2541| v2541_15(void) = ^IndirectReadSideEffect[-1] : &:r2541_10, m2541_8
# 2541| m2541_16(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_10
# 2541| m2541_17(ClassWithDestructor) = Chi : total:m2541_8, partial:m2541_16
# 2534| v2534_9(void) = ReturnVoid :
# 2541| Block 4
# 2541| r2541_10(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2541| r2541_11(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2541| v2541_12(void) = Call[~ClassWithDestructor] : func:r2541_11, this:r2541_10
# 2541| m2541_13(unknown) = ^CallSideEffect : ~m2535_6
# 2541| m2541_14(unknown) = Chi : total:m2535_6, partial:m2541_13
# 2541| v2541_15(void) = ^IndirectReadSideEffect[-1] : &:r2541_10, m2535_8
# 2541| m2541_16(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_10
# 2541| m2541_17(ClassWithDestructor) = Chi : total:m2535_8, partial:m2541_16
# 2534| v2534_9(void) = Unwind :
#-----| Goto -> Block 1
# 2545| void this_inconsistency(bool)

View File

@@ -16577,39 +16577,39 @@ ir.cpp:
# 2537| r2537_2(int) = Constant[42] :
# 2537| mu2537_3(int) = Store[#throw2537:5] : &:r2537_1, r2537_2
# 2537| v2537_4(void) = ThrowValue : &:r2537_1, ~m?
#-----| Exception -> Block 3
#-----| Exception -> Block 2
# 2534| Block 1
# 2534| v2534_4(void) = AliasedUse : ~m?
# 2534| v2534_5(void) = ExitFunction :
# 2534| Block 2
# 2534| v2534_6(void) = Unwind :
#-----| Goto -> Block 1
# 2539| Block 2
# 2539| v2539_1(void) = CatchByType[char] :
#-----| Exception -> Block 4
#-----| Goto -> Block 3
# 2539| Block 3
# 2539| v2539_1(void) = CatchByType[char] :
#-----| Exception -> Block 2
#-----| Goto -> Block 4
# 2539| Block 4
# 2539| r2539_2(glval<char>) = VariableAddress[(unnamed parameter 0)] :
# 2539| mu2539_3(char) = InitializeParameter[(unnamed parameter 0)] : &:r2539_2
# 2539| v2539_4(void) = NoOp :
# 2541| r2541_1(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2541| r2541_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2541| v2541_3(void) = Call[~ClassWithDestructor] : func:r2541_2, this:r2541_1
# 2541| mu2541_4(unknown) = ^CallSideEffect : ~m?
# 2541| v2541_5(void) = ^IndirectReadSideEffect[-1] : &:r2541_1, ~m?
# 2541| mu2541_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_1
# 2541| v2541_7(void) = NoOp :
# 2541| r2541_8(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2541| r2541_9(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2541| v2541_10(void) = Call[~ClassWithDestructor] : func:r2541_9, this:r2541_8
# 2541| mu2541_11(unknown) = ^CallSideEffect : ~m?
# 2541| v2541_12(void) = ^IndirectReadSideEffect[-1] : &:r2541_8, ~m?
# 2541| mu2541_13(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_8
# 2534| v2534_7(void) = ReturnVoid :
# 2541| v2541_1(void) = NoOp :
# 2541| r2541_2(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2541| r2541_3(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2541| v2541_4(void) = Call[~ClassWithDestructor] : func:r2541_3, this:r2541_2
# 2541| mu2541_5(unknown) = ^CallSideEffect : ~m?
# 2541| v2541_6(void) = ^IndirectReadSideEffect[-1] : &:r2541_2, ~m?
# 2541| mu2541_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_2
# 2534| v2534_6(void) = ReturnVoid :
#-----| Goto -> Block 1
# 2541| Block 4
# 2541| r2541_8(glval<ClassWithDestructor>) = VariableAddress[x] :
# 2541| r2541_9(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
# 2541| v2541_10(void) = Call[~ClassWithDestructor] : func:r2541_9, this:r2541_8
# 2541| mu2541_11(unknown) = ^CallSideEffect : ~m?
# 2541| v2541_12(void) = ^IndirectReadSideEffect[-1] : &:r2541_8, ~m?
# 2541| mu2541_13(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2541_8
# 2534| v2534_7(void) = Unwind :
#-----| Goto -> Block 1
# 2545| void this_inconsistency(bool)