Merge pull request #1551 from jbj/ir-DeleteExpr-placeholder

C++: Placeholder translation of delete expressions
This commit is contained in:
Dave Bartolomeo
2019-07-08 17:07:16 -07:00
committed by GitHub
5 changed files with 309 additions and 2 deletions

View File

@@ -67,6 +67,12 @@ private predicate ignoreExprAndDescendants(Expr expr) {
// Do not translate input/output variables in GNU asm statements
getRealParent(expr) instanceof AsmStmt or
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
// We do not yet translate destructors properly, so for now we ignore any
// custom deallocator call, if present.
or
exists(DeleteExpr deleteExpr | deleteExpr.getAllocatorCall() = expr)
or
exists(DeleteArrayExpr deleteArrayExpr | deleteArrayExpr.getAllocatorCall() = expr)
}
/**
@@ -80,6 +86,13 @@ private predicate ignoreExprOnly(Expr expr) {
newExpr.getAllocatorCall() = expr
) or
not translateFunction(expr.getEnclosingFunction())
or
// We do not yet translate destructors properly, so for now we ignore the
// destructor call. We do, however, translate the expression being
// destructed, and that expression can be a child of the destructor call.
exists(DeleteExpr deleteExpr | deleteExpr.getDestructorCall() = expr)
or
exists(DeleteArrayExpr deleteArrayExpr | deleteArrayExpr.getDestructorCall() = expr)
}
/**

View File

@@ -2561,6 +2561,88 @@ class TranslatedNewArrayExpr extends TranslatedNewOrNewArrayExpr {
}
}
/**
* A placeholder for the translation of a `delete[]` expression.
*
* Proper translation is not yet implemented, but this stub implementation
* ensures that code following a `delete[]` is not unreachable.
*/
class TranslatedDeleteArrayExprPlaceHolder extends TranslatedSingleInstructionExpr {
override DeleteArrayExpr expr;
override final Instruction getFirstInstruction() {
result = getOperand().getFirstInstruction()
}
override final TranslatedElement getChild(int id) {
id = 0 and result = getOperand()
}
override final Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
tag = OnlyInstructionTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
}
override final Instruction getChildSuccessor(TranslatedElement child) {
child = getOperand() and result = getInstruction(OnlyInstructionTag())
}
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
none()
}
override final Opcode getOpcode() {
result instanceof Opcode::NoOp
}
private TranslatedExpr getOperand() {
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
}
}
/**
* A placeholder for the translation of a `delete` expression.
*
* Proper translation is not yet implemented, but this stub implementation
* ensures that code following a `delete` is not unreachable.
*/
class TranslatedDeleteExprPlaceHolder extends TranslatedSingleInstructionExpr {
override DeleteExpr expr;
override final Instruction getFirstInstruction() {
result = getOperand().getFirstInstruction()
}
override final TranslatedElement getChild(int id) {
id = 0 and result = getOperand()
}
override final Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
tag = OnlyInstructionTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
}
override final Instruction getChildSuccessor(TranslatedElement child) {
child = getOperand() and result = getInstruction(OnlyInstructionTag())
}
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
none()
}
override final Opcode getOpcode() {
result instanceof Opcode::NoOp
}
private TranslatedExpr getOperand() {
result = getTranslatedExpr(expr.getExpr().getFullyConverted())
}
}
/**
* The IR translation of a `ConditionDeclExpr`, which represents the value of the declared variable
* after conversion to `bool` in code such as:

View File

@@ -12,12 +12,28 @@
#-----| Type = void *
#-----| 1: p#1
#-----| Type = unsigned long
#-----| void operator delete(void*, unsigned long, std::align_val_t)
#-----| params:
#-----| 0: p#0
#-----| Type = void *
#-----| 1: p#1
#-----| Type = unsigned long
#-----| 2: p#2
#-----| Type = align_val_t
#-----| void operator delete[](void*, unsigned long)
#-----| params:
#-----| 0: p#0
#-----| Type = void *
#-----| 1: p#1
#-----| Type = unsigned long
#-----| void operator delete[](void*, unsigned long, std::align_val_t)
#-----| params:
#-----| 0: p#0
#-----| Type = void *
#-----| 1: p#1
#-----| Type = unsigned long
#-----| 2: p#2
#-----| Type = align_val_t
#-----| void* operator new(unsigned long)
#-----| params:
#-----| 0: p#0
@@ -6647,6 +6663,162 @@ ir.cpp:
# 1002| 0: (statement expression)
# 1002| Type = int
# 1002| ValueCategory = prvalue
# 1006| void OperatorDelete()
# 1006| params:
# 1006| body: { ... }
# 1007| 0: ExprStmt
# 1007| 0: delete
# 1007| Type = void
# 1007| ValueCategory = prvalue
# 1007| 3: static_cast<int *>...
# 1007| Conversion = pointer conversion
# 1007| Type = int *
# 1007| Value = 0
# 1007| ValueCategory = prvalue
# 1007| expr: 0
# 1007| Type = decltype(nullptr)
# 1007| Value = 0
# 1007| ValueCategory = prvalue
# 1008| 1: ExprStmt
# 1008| 0: delete
# 1008| Type = void
# 1008| ValueCategory = prvalue
# 1008| 1: call to ~String
# 1008| Type = void
# 1008| ValueCategory = prvalue
# 1008| -1: static_cast<String *>...
# 1008| Conversion = pointer conversion
# 1008| Type = String *
# 1008| Value = 0
# 1008| ValueCategory = prvalue
# 1008| expr: 0
# 1008| Type = decltype(nullptr)
# 1008| Value = 0
# 1008| ValueCategory = prvalue
# 1009| 2: ExprStmt
# 1009| 0: delete
# 1009| Type = void
# 1009| ValueCategory = prvalue
# 1009| 0: call to operator delete
# 1009| Type = void
# 1009| ValueCategory = prvalue
# 1009| 3: static_cast<SizedDealloc *>...
# 1009| Conversion = pointer conversion
# 1009| Type = SizedDealloc *
# 1009| Value = 0
# 1009| ValueCategory = prvalue
# 1009| expr: 0
# 1009| Type = decltype(nullptr)
# 1009| Value = 0
# 1009| ValueCategory = prvalue
# 1010| 3: ExprStmt
# 1010| 0: delete
# 1010| Type = void
# 1010| ValueCategory = prvalue
# 1010| 3: static_cast<Overaligned *>...
# 1010| Conversion = pointer conversion
# 1010| Type = Overaligned *
# 1010| Value = 0
# 1010| ValueCategory = prvalue
# 1010| expr: 0
# 1010| Type = decltype(nullptr)
# 1010| Value = 0
# 1010| ValueCategory = prvalue
# 1011| 4: ExprStmt
# 1011| 0: delete
# 1011| Type = void
# 1011| ValueCategory = prvalue
# 1011| 1: call to ~PolymorphicBase
# 1011| Type = void
# 1011| ValueCategory = prvalue
# 1011| -1: static_cast<PolymorphicBase *>...
# 1011| Conversion = pointer conversion
# 1011| Type = PolymorphicBase *
# 1011| Value = 0
# 1011| ValueCategory = prvalue
# 1011| expr: 0
# 1011| Type = decltype(nullptr)
# 1011| Value = 0
# 1011| ValueCategory = prvalue
# 1012| 5: return ...
# 1015| void OperatorDeleteArray()
# 1015| params:
# 1015| body: { ... }
# 1016| 0: ExprStmt
# 1016| 0: delete[]
# 1016| Type = void
# 1016| ValueCategory = prvalue
# 1016| 3: static_cast<int *>...
# 1016| Conversion = pointer conversion
# 1016| Type = int *
# 1016| Value = 0
# 1016| ValueCategory = prvalue
# 1016| expr: 0
# 1016| Type = decltype(nullptr)
# 1016| Value = 0
# 1016| ValueCategory = prvalue
# 1017| 1: ExprStmt
# 1017| 0: delete[]
# 1017| Type = void
# 1017| ValueCategory = prvalue
# 1017| 1: call to ~String
# 1017| Type = void
# 1017| ValueCategory = prvalue
# 1017| -1: static_cast<String *>...
# 1017| Conversion = pointer conversion
# 1017| Type = String *
# 1017| Value = 0
# 1017| ValueCategory = prvalue
# 1017| expr: 0
# 1017| Type = decltype(nullptr)
# 1017| Value = 0
# 1017| ValueCategory = prvalue
# 1018| 2: ExprStmt
# 1018| 0: delete[]
# 1018| Type = void
# 1018| ValueCategory = prvalue
# 1018| 0: call to operator delete[]
# 1018| Type = void
# 1018| ValueCategory = prvalue
# 1018| 3: static_cast<SizedDealloc *>...
# 1018| Conversion = pointer conversion
# 1018| Type = SizedDealloc *
# 1018| Value = 0
# 1018| ValueCategory = prvalue
# 1018| expr: 0
# 1018| Type = decltype(nullptr)
# 1018| Value = 0
# 1018| ValueCategory = prvalue
# 1019| 3: ExprStmt
# 1019| 0: delete[]
# 1019| Type = void
# 1019| ValueCategory = prvalue
# 1019| 3: static_cast<Overaligned *>...
# 1019| Conversion = pointer conversion
# 1019| Type = Overaligned *
# 1019| Value = 0
# 1019| ValueCategory = prvalue
# 1019| expr: 0
# 1019| Type = decltype(nullptr)
# 1019| Value = 0
# 1019| ValueCategory = prvalue
# 1020| 4: ExprStmt
# 1020| 0: delete[]
# 1020| Type = void
# 1020| ValueCategory = prvalue
# 1020| 1: call to ~PolymorphicBase
# 1020| Type = void
# 1020| ValueCategory = prvalue
# 1020| -1: static_cast<PolymorphicBase *>...
# 1020| Conversion = pointer conversion
# 1020| Type = PolymorphicBase *
# 1020| Value = 0
# 1020| ValueCategory = prvalue
# 1020| expr: 0
# 1020| Type = decltype(nullptr)
# 1020| Value = 0
# 1020| ValueCategory = prvalue
# 1021| 5: return ...
# 1023| EmptyStruct& EmptyStruct::operator=(EmptyStruct const&)
# 1023| params:
#-----| 0: p#0

View File

@@ -1002,7 +1002,7 @@ int ExprStmt(int b, int y, int z) {
return ({x;});
}
#if 0
// TODO: `delete` gets translated to NoOp
void OperatorDelete() {
delete static_cast<int*>(nullptr); // No destructor
delete static_cast<String*>(nullptr); // Non-virtual destructor, with size.
@@ -1011,6 +1011,7 @@ void OperatorDelete() {
delete static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
}
// TODO: `delete[]` gets translated to NoOp
void OperatorDeleteArray() {
delete[] static_cast<int*>(nullptr); // No destructor
delete[] static_cast<String*>(nullptr); // Non-virtual destructor, with size.
@@ -1018,7 +1019,6 @@ void OperatorDeleteArray() {
delete[] static_cast<Overaligned*>(nullptr); // No destructor, with size and alignment.
delete[] static_cast<PolymorphicBase*>(nullptr); // Virtual destructor
}
#endif
struct EmptyStruct {};

View File

@@ -4418,6 +4418,46 @@ ir.cpp:
# 991| v3_11(void) = UnmodeledUse : mu*
# 991| v3_12(void) = ExitFunction :
# 1006| void OperatorDelete()
# 1006| Block 0
# 1006| v0_0(void) = EnterFunction :
# 1006| mu0_1(unknown) = AliasedDefinition :
# 1006| mu0_2(unknown) = UnmodeledDefinition :
# 1007| r0_3(int *) = Constant[0] :
# 1007| v0_4(void) = NoOp :
# 1008| r0_5(String *) = Constant[0] :
# 1008| v0_6(void) = NoOp :
# 1009| r0_7(SizedDealloc *) = Constant[0] :
# 1009| v0_8(void) = NoOp :
# 1010| r0_9(Overaligned *) = Constant[0] :
# 1010| v0_10(void) = NoOp :
# 1011| r0_11(PolymorphicBase *) = Constant[0] :
# 1011| v0_12(void) = NoOp :
# 1012| v0_13(void) = NoOp :
# 1006| v0_14(void) = ReturnVoid :
# 1006| v0_15(void) = UnmodeledUse : mu*
# 1006| v0_16(void) = ExitFunction :
# 1015| void OperatorDeleteArray()
# 1015| Block 0
# 1015| v0_0(void) = EnterFunction :
# 1015| mu0_1(unknown) = AliasedDefinition :
# 1015| mu0_2(unknown) = UnmodeledDefinition :
# 1016| r0_3(int *) = Constant[0] :
# 1016| v0_4(void) = NoOp :
# 1017| r0_5(String *) = Constant[0] :
# 1017| v0_6(void) = NoOp :
# 1018| r0_7(SizedDealloc *) = Constant[0] :
# 1018| v0_8(void) = NoOp :
# 1019| r0_9(Overaligned *) = Constant[0] :
# 1019| v0_10(void) = NoOp :
# 1020| r0_11(PolymorphicBase *) = Constant[0] :
# 1020| v0_12(void) = NoOp :
# 1021| v0_13(void) = NoOp :
# 1015| v0_14(void) = ReturnVoid :
# 1015| v0_15(void) = UnmodeledUse : mu*
# 1015| v0_16(void) = ExitFunction :
# 1025| void EmptyStructInit()
# 1025| Block 0
# 1025| v0_0(void) = EnterFunction :