mirror of
https://github.com/github/codeql.git
synced 2026-04-24 16:25:15 +02:00
Merge pull request #16125 from MathiasVP/destructors-for-unconditional-unnamed
C++: Generate IR for destruction of unconditionally constructed temporaries
This commit is contained in:
@@ -364,6 +364,8 @@ class ConversionNode extends ExprNode {
|
||||
childIndex = 0 and
|
||||
result.getAst() = conv.getExpr() and
|
||||
conv.getExpr() instanceof Conversion
|
||||
or
|
||||
result.getAst() = expr.getImplicitDestructorCall(childIndex - 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,12 @@ class Expr extends StmtParent, @expr {
|
||||
* order of destruction.
|
||||
*/
|
||||
DestructorCall getImplicitDestructorCall(int n) {
|
||||
exists(Expr e |
|
||||
e = this.(TemporaryObjectExpr).getExpr() and
|
||||
synthetic_destructor_call(e, max(int i | synthetic_destructor_call(e, i, _)) - n, result)
|
||||
)
|
||||
or
|
||||
not this = any(TemporaryObjectExpr temp).getExpr() and
|
||||
synthetic_destructor_call(this, max(int i | synthetic_destructor_call(this, i, _)) - n, result)
|
||||
}
|
||||
|
||||
|
||||
@@ -128,8 +128,10 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
vaStartExpr.getLastNamedParameter().getFullyConverted() = expr
|
||||
)
|
||||
or
|
||||
// suppress destructors of temporary variables until proper support is added for them.
|
||||
exists(Expr parent | parent.getAnImplicitDestructorCall() = expr)
|
||||
// Do not translate implicit destructor calls for unnamed temporary variables that are
|
||||
// conditionally constructed (until we have a mechanism for calling these only when the
|
||||
// temporary's constructor was run)
|
||||
isConditionalTemporaryDestructorCall(expr)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,6 +257,42 @@ private predicate usedAsCondition(Expr expr) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasThrowingChild(Expr e) {
|
||||
e = any(ThrowExpr throw).getFullyConverted()
|
||||
or
|
||||
exists(Expr child |
|
||||
e = getRealParent(child) and
|
||||
hasThrowingChild(child)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isInConditionalEvaluation(Expr e) {
|
||||
exists(ConditionalExpr cond |
|
||||
e = cond.getThen().getFullyConverted() and not cond.isTwoOperand()
|
||||
or
|
||||
e = cond.getElse().getFullyConverted()
|
||||
or
|
||||
// If one of the operands throws then the temporaries constructed in either
|
||||
// branch will also be attached to the ternary expression. We suppress
|
||||
// those destructor calls as well.
|
||||
hasThrowingChild([cond.getThen(), cond.getElse()]) and
|
||||
e = cond.getFullyConverted()
|
||||
)
|
||||
or
|
||||
e = any(LogicalAndExpr lae).getRightOperand().getFullyConverted()
|
||||
or
|
||||
e = any(LogicalOrExpr loe).getRightOperand().getFullyConverted()
|
||||
or
|
||||
isInConditionalEvaluation(getRealParent(e))
|
||||
}
|
||||
|
||||
private predicate isConditionalTemporaryDestructorCall(DestructorCall dc) {
|
||||
exists(TemporaryObjectExpr temp |
|
||||
temp = dc.getQualifier().(ReuseExpr).getReusedExpr() and
|
||||
isInConditionalEvaluation(temp)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `conv` is an `InheritanceConversion` that requires a `TranslatedLoad`, despite not being
|
||||
* marked as having an lvalue-to-rvalue conversion.
|
||||
@@ -782,6 +820,16 @@ newtype TTranslatedElement =
|
||||
not ignoreSideEffects(expr) and
|
||||
opcode = getCallSideEffectOpcode(expr)
|
||||
} or
|
||||
// The set of destructors to invoke after a `throw`. These need to be special
|
||||
// cased because the edge kind following a throw is an `ExceptionEdge`, and
|
||||
// we need to make sure that the edge kind is still an `ExceptionEdge` after
|
||||
// all the destructors have run.
|
||||
TTranslatedDestructorsAfterThrow(ThrowExpr throw) {
|
||||
exists(DestructorCall dc |
|
||||
dc = throw.getAnImplicitDestructorCall() and
|
||||
not ignoreExpr(dc)
|
||||
)
|
||||
} or
|
||||
// A precise side effect of an argument to a `Call`
|
||||
TTranslatedArgumentExprSideEffect(Call call, Expr expr, int n, SideEffectOpcode opcode) {
|
||||
not ignoreExpr(expr) and
|
||||
|
||||
@@ -90,10 +90,26 @@ abstract class TranslatedExpr extends TranslatedElement {
|
||||
final override TranslatedElement getChild(int id) {
|
||||
result = this.getChildInternal(id)
|
||||
or
|
||||
exists(int maxChildId, int destructorIndex |
|
||||
maxChildId = max(int childId | exists(this.getChildInternal(childId))) and
|
||||
result.(TranslatedExpr).getExpr() = expr.getImplicitDestructorCall(destructorIndex) and
|
||||
id = maxChildId + 1 + destructorIndex
|
||||
exists(int destructorIndex |
|
||||
result = this.getImplicitDestructorCall(destructorIndex) and
|
||||
id = this.getFirstDestructorCallIndex() + destructorIndex
|
||||
)
|
||||
}
|
||||
|
||||
final private TranslatedExpr getImplicitDestructorCall(int index) {
|
||||
result.getExpr() = expr.getImplicitDestructorCall(index)
|
||||
}
|
||||
|
||||
final override predicate hasAnImplicitDestructorCall() {
|
||||
exists(this.getImplicitDestructorCall(_))
|
||||
}
|
||||
|
||||
final override int getFirstDestructorCallIndex() {
|
||||
not this.handlesDestructorsExplicitly() and
|
||||
(
|
||||
result = max(int childId | exists(this.getChildInternal(childId))) + 1
|
||||
or
|
||||
not exists(this.getChildInternal(_)) and result = 0
|
||||
)
|
||||
}
|
||||
|
||||
@@ -395,6 +411,14 @@ class TranslatedLoad extends TranslatedValueCategoryAdjustment, TTranslatedLoad
|
||||
result = this.getOperand().getResult()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate handlesDestructorsExplicitly() {
|
||||
// The class that generates IR for `e` will (implicitly or explicitly)
|
||||
// handle the generation of destructor calls for `e`. Without disabling
|
||||
// destructor call generation here the destructor will get multiple
|
||||
// parents.
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1999,6 +2023,13 @@ abstract class TranslatedAllocationSize extends TranslatedExpr, TTranslatedAlloc
|
||||
final override predicate producesExprResult() { none() }
|
||||
|
||||
final override Instruction getResult() { result = this.getInstruction(AllocationSizeTag()) }
|
||||
|
||||
final override predicate handlesDestructorsExplicitly() {
|
||||
// Since the enclosing `TranslatedNewOrNewArrayExpr` (implicitly) handles the destructors
|
||||
// we need to disable the implicit handling here as otherwise the destructors will have
|
||||
// multiple parents
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
TranslatedAllocationSize getTranslatedAllocationSize(NewOrNewArrayExpr newExpr) {
|
||||
@@ -2156,6 +2187,13 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
|
||||
|
||||
final override predicate producesExprResult() { none() }
|
||||
|
||||
final override predicate handlesDestructorsExplicitly() {
|
||||
// Since the enclosing `TranslatedNewOrNewArrayExpr` (implicitly) handles the destructors
|
||||
// we need to disable the implicit handling here as otherwise the destructors will have
|
||||
// multiple parents
|
||||
any()
|
||||
}
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
tag = CallTargetTag() and result = expr.getAllocator()
|
||||
}
|
||||
@@ -2817,6 +2855,68 @@ class TranslatedReuseExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of the destructor calls of the parent `TranslatedThrow`.
|
||||
*
|
||||
* This object does not itself generate the destructor calls. Instead, its
|
||||
* children provide the actual calls, and this object ensures that we correctly
|
||||
* exit with an `ExceptionEdge` after executing all the destructor calls.
|
||||
*/
|
||||
class TranslatedDestructorsAfterThrow extends TranslatedElement, TTranslatedDestructorsAfterThrow {
|
||||
ThrowExpr throw;
|
||||
|
||||
TranslatedDestructorsAfterThrow() { this = TTranslatedDestructorsAfterThrow(throw) }
|
||||
|
||||
override string toString() { result = "Destructor calls after throw: " + throw }
|
||||
|
||||
private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
|
||||
result.getExpr() = throw.getImplicitDestructorCall(id)
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getChild(0).getFirstInstruction(kind)
|
||||
}
|
||||
|
||||
override ThrowExpr getAst() { result = throw }
|
||||
|
||||
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 = throw.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, exit this element with an exceptional edge
|
||||
not exists(this.getChild(id + 1)) and
|
||||
kind instanceof ExceptionEdge and
|
||||
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
|
||||
)
|
||||
}
|
||||
|
||||
override TranslatedElement getLastChild() {
|
||||
result =
|
||||
this.getTranslatedImplicitDestructorCall(max(int id |
|
||||
exists(throw.getImplicitDestructorCall(id))
|
||||
))
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getLastChild().getALastInstruction()
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IR translation of a `throw` expression.
|
||||
*/
|
||||
@@ -2831,13 +2931,22 @@ abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
|
||||
|
||||
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
|
||||
tag = ThrowTag() and
|
||||
kind instanceof ExceptionEdge and
|
||||
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
|
||||
(
|
||||
result = this.getDestructors().getFirstInstruction(kind)
|
||||
or
|
||||
not exists(this.getDestructors()) and
|
||||
kind instanceof ExceptionEdge and
|
||||
result = this.getParent().getExceptionSuccessorInstruction(any(GotoEdge edge))
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getResult() { none() }
|
||||
|
||||
abstract Opcode getThrowOpcode();
|
||||
|
||||
override predicate handlesDestructorsExplicitly() { any() }
|
||||
|
||||
TranslatedDestructorsAfterThrow getDestructors() { result.getAst() = expr }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2849,6 +2958,9 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn
|
||||
|
||||
final override TranslatedElement getChildInternal(int id) {
|
||||
result = TranslatedVariableInitialization.super.getChildInternal(id)
|
||||
or
|
||||
id = max(int i | exists(TranslatedVariableInitialization.super.getChildInternal(i))) + 1 and
|
||||
result = this.getDestructors()
|
||||
}
|
||||
|
||||
final override Instruction getChildSuccessorInternal(TranslatedElement elem, EdgeKind kind) {
|
||||
@@ -2914,14 +3026,22 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableIn
|
||||
class TranslatedReThrowExpr extends TranslatedThrowExpr {
|
||||
override ReThrowExpr expr;
|
||||
|
||||
override TranslatedElement getChildInternal(int id) { none() }
|
||||
override TranslatedElement getChildInternal(int id) {
|
||||
id = 0 and
|
||||
result = this.getDestructors()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getInstruction(ThrowTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() { result = this.getInstruction(ThrowTag()) }
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getDestructors().getALastInstruction()
|
||||
or
|
||||
not this.hasAnImplicitDestructorCall() and
|
||||
result = this.getInstruction(ThrowTag())
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { none() }
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to begin | call to begin |
|
||||
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to end | call to end |
|
||||
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to begin | call to begin |
|
||||
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to end | call to end |
|
||||
| test.cpp:689:17:689:29 | temporary object | This object is destroyed before $@ is called. | test.cpp:689:31:689:35 | call to begin | call to begin |
|
||||
| test.cpp:689:46:689:58 | temporary object | This object is destroyed before $@ is called. | test.cpp:689:60:689:62 | call to end | call to end |
|
||||
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:19:703:23 | call to begin | call to begin |
|
||||
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:36:703:38 | call to end | call to end |
|
||||
| test.cpp:716:36:716:48 | temporary object | This object is destroyed before $@ is called. | test.cpp:716:17:716:17 | call to begin | call to begin |
|
||||
| test.cpp:716:36:716:48 | temporary object | This object is destroyed before $@ is called. | test.cpp:716:17:716:17 | call to end | call to end |
|
||||
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to begin | call to begin |
|
||||
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to end | call to end |
|
||||
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to begin | call to begin |
|
||||
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to end | call to end |
|
||||
|
||||
@@ -677,10 +677,10 @@ std::vector<std::vector<int>> return_self_by_value(const std::vector<std::vector
|
||||
|
||||
void test() {
|
||||
for (auto x : returnValue()) {} // GOOD
|
||||
for (auto x : returnValue()[0]) {} // BAD [NOT DETECTED] (see *)
|
||||
for (auto x : returnValue()[0]) {} // BAD
|
||||
for (auto x : external_by_value(returnValue())) {} // GOOD
|
||||
for (auto x : external_by_const_ref(returnValue())) {} // GOOD
|
||||
for (auto x : returnValue().at(0)) {} // BAD [NOT DETECTED] (see *)
|
||||
for (auto x : returnValue().at(0)) {} // BAD
|
||||
|
||||
for (auto x : returnRef()) {} // GOOD
|
||||
for (auto x : returnRef()[0]) {} // GOOD
|
||||
@@ -700,7 +700,7 @@ void test() {
|
||||
|
||||
{
|
||||
auto&& v = returnValue()[0];
|
||||
for(auto it = v.begin(); it != v.end(); ++it) {} // BAD [NOT DETECTED] (see *)
|
||||
for(auto it = v.begin(); it != v.end(); ++it) {} // BAD
|
||||
}
|
||||
|
||||
{
|
||||
@@ -713,7 +713,7 @@ void test() {
|
||||
for(auto it = v.begin(); it != v.end(); ++it) {} // GOOD
|
||||
}
|
||||
|
||||
for (auto x : return_self_by_ref(returnValue())) {} // BAD [NOT DETECTED] (see *)
|
||||
for (auto x : return_self_by_ref(returnValue())) {} // BAD
|
||||
|
||||
for (auto x : return_self_by_value(returnValue())) {} // GOOD
|
||||
}
|
||||
@@ -724,7 +724,7 @@ void iterate(const std::vector<T>& v) {
|
||||
}
|
||||
|
||||
std::vector<int>& ref_to_first_in_returnValue_1() {
|
||||
return returnValue()[0]; // BAD [NOT DETECTED] (see *)
|
||||
return returnValue()[0]; // BAD
|
||||
}
|
||||
|
||||
std::vector<int>& ref_to_first_in_returnValue_2() {
|
||||
@@ -732,7 +732,7 @@ std::vector<int>& ref_to_first_in_returnValue_2() {
|
||||
}
|
||||
|
||||
std::vector<int>& ref_to_first_in_returnValue_3() {
|
||||
return returnValue()[0]; // BAD [NOT DETECTED] (see *)
|
||||
return returnValue()[0]; // BAD
|
||||
}
|
||||
|
||||
std::vector<int> first_in_returnValue_1() {
|
||||
|
||||
@@ -3681,12 +3681,6 @@ destructors_for_temps.cpp:
|
||||
# 39| getElse(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 39| Type = [VoidType] void
|
||||
# 39| ValueCategory = prvalue
|
||||
# 39| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 39| Type = [VoidType] void
|
||||
# 39| ValueCategory = prvalue
|
||||
# 39| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 39| Type = [Class] ClassWithDestructor2
|
||||
# 39| ValueCategory = xvalue
|
||||
# 39| getThen().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 39| Type = [Class] ClassWithDestructor2
|
||||
# 39| ValueCategory = prvalue(load)
|
||||
@@ -3696,6 +3690,12 @@ destructors_for_temps.cpp:
|
||||
# 39| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 39| Type = [Class] ClassWithDestructor2
|
||||
# 39| ValueCategory = prvalue
|
||||
# 39| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 39| Type = [VoidType] void
|
||||
# 39| ValueCategory = prvalue
|
||||
# 39| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 39| Type = [Class] ClassWithDestructor2
|
||||
# 39| ValueCategory = xvalue
|
||||
# 40| getStmt(1): [ReturnStmt] return ...
|
||||
# 42| [TopLevelFunction] void temp_test6(bool)
|
||||
# 42| <params>:
|
||||
@@ -3800,6 +3800,12 @@ destructors_for_temps.cpp:
|
||||
# 51| getElse(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 51| Type = [VoidType] void
|
||||
# 51| ValueCategory = prvalue
|
||||
# 51| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 51| Type = [Class] ClassWithDestructor2
|
||||
# 51| ValueCategory = prvalue(load)
|
||||
# 51| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 51| Type = [Class] ClassWithDestructor2
|
||||
# 51| ValueCategory = prvalue
|
||||
# 51| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 51| Type = [VoidType] void
|
||||
# 51| ValueCategory = prvalue
|
||||
@@ -3818,12 +3824,6 @@ destructors_for_temps.cpp:
|
||||
# 51| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 51| Type = [Class] ClassWithDestructor2
|
||||
# 51| ValueCategory = xvalue
|
||||
# 51| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 51| Type = [Class] ClassWithDestructor2
|
||||
# 51| ValueCategory = prvalue(load)
|
||||
# 51| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 51| Type = [Class] ClassWithDestructor2
|
||||
# 51| ValueCategory = prvalue
|
||||
# 52| getStmt(2): [ReturnStmt] return ...
|
||||
# 52| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 52| Type = [VoidType] void
|
||||
@@ -3865,6 +3865,12 @@ destructors_for_temps.cpp:
|
||||
# 55| getElse(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 55| Type = [VoidType] void
|
||||
# 55| ValueCategory = prvalue
|
||||
# 55| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 55| Type = [Class] ClassWithDestructor2
|
||||
# 55| ValueCategory = prvalue(load)
|
||||
# 55| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 55| Type = [Class] ClassWithDestructor2
|
||||
# 55| ValueCategory = prvalue
|
||||
# 55| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 55| Type = [VoidType] void
|
||||
# 55| ValueCategory = prvalue
|
||||
@@ -3883,13 +3889,224 @@ destructors_for_temps.cpp:
|
||||
# 55| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 55| Type = [Class] ClassWithDestructor2
|
||||
# 55| ValueCategory = xvalue
|
||||
# 55| getElse().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 55| Type = [Class] ClassWithDestructor2
|
||||
# 55| ValueCategory = prvalue(load)
|
||||
# 55| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 55| Type = [Class] ClassWithDestructor2
|
||||
# 55| ValueCategory = prvalue
|
||||
# 56| getStmt(1): [ReturnStmt] return ...
|
||||
# 58| [TopLevelFunction] void temp_test8_simple(bool)
|
||||
# 58| <params>:
|
||||
# 58| getParameter(0): [Parameter] b
|
||||
# 58| Type = [BoolType] bool
|
||||
# 58| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 59| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 59| getExpr(): [ConditionalExpr] ... ? ... : ...
|
||||
# 59| Type = [PlainCharType] char
|
||||
# 59| ValueCategory = prvalue
|
||||
# 59| getCondition(): [VariableAccess] b
|
||||
# 59| Type = [BoolType] bool
|
||||
# 59| ValueCategory = prvalue(load)
|
||||
# 59| getThen(): [ThrowExpr] throw ...
|
||||
# 59| Type = [PlainCharType] char
|
||||
# 59| ValueCategory = prvalue
|
||||
# 59| getExpr(): [FunctionCall] call to get_x
|
||||
# 59| Type = [PlainCharType] char
|
||||
# 59| ValueCategory = prvalue
|
||||
# 59| getQualifier(): [ConstructorCall] call to ClassWithDestructor2
|
||||
# 59| Type = [VoidType] void
|
||||
# 59| ValueCategory = prvalue
|
||||
# 59| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 59| Type = [Class] ClassWithDestructor2
|
||||
# 59| ValueCategory = prvalue(load)
|
||||
# 59| getElse(): [CharLiteral] 97
|
||||
# 59| Type = [PlainCharType] char
|
||||
# 59| Value = [CharLiteral] 97
|
||||
# 59| ValueCategory = prvalue
|
||||
# 59| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 59| Type = [VoidType] void
|
||||
# 59| ValueCategory = prvalue
|
||||
# 59| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 59| Type = [Class] ClassWithDestructor2
|
||||
# 59| ValueCategory = xvalue
|
||||
# 60| getStmt(1): [ReturnStmt] return ...
|
||||
# 62| [CopyAssignmentOperator] string& string::operator=(string const&)
|
||||
# 62| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const string &
|
||||
# 62| [CopyConstructor] void string::string(string const&)
|
||||
# 62| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const string &
|
||||
# 64| [Constructor] void string::string(char const*)
|
||||
# 64| <params>:
|
||||
# 64| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
# 64| Type = [PointerType] const char *
|
||||
# 65| [Destructor] void string::~string()
|
||||
# 65| <params>:
|
||||
# 68| [TopLevelFunction] bool const_ref_string(string const&)
|
||||
# 68| <params>:
|
||||
# 68| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
# 68| Type = [LValueReferenceType] const string &
|
||||
# 70| [TopLevelFunction] bool conditional_temp_via_conjunction(bool)
|
||||
# 70| <params>:
|
||||
# 70| getParameter(0): [Parameter] b
|
||||
# 70| Type = [BoolType] bool
|
||||
# 71| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 72| getStmt(0): [ReturnStmt] return ...
|
||||
# 72| getExpr(): [LogicalAndExpr] ... && ...
|
||||
# 72| Type = [BoolType] bool
|
||||
# 72| ValueCategory = prvalue
|
||||
# 72| getLeftOperand(): [VariableAccess] b
|
||||
# 72| Type = [BoolType] bool
|
||||
# 72| ValueCategory = prvalue(load)
|
||||
# 72| getRightOperand(): [FunctionCall] call to const_ref_string
|
||||
# 72| Type = [BoolType] bool
|
||||
# 72| ValueCategory = prvalue
|
||||
# 72| getArgument(0): [ConstructorCall] call to string
|
||||
# 72| Type = [VoidType] void
|
||||
# 72| ValueCategory = prvalue
|
||||
# 72| getArgument(0):
|
||||
# 72| Type = [ArrayType] const char[1]
|
||||
# 72| Value = [StringLiteral] ""
|
||||
# 72| ValueCategory = lvalue
|
||||
# 72| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 72| Type = [PointerType] const char *
|
||||
# 72| ValueCategory = prvalue
|
||||
# 72| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 72| Type = [LValueReferenceType] const string &
|
||||
# 72| ValueCategory = prvalue
|
||||
# 72| getExpr(): [TemporaryObjectExpr] temporary object
|
||||
# 72| Type = [SpecifiedType] const string
|
||||
# 72| ValueCategory = lvalue
|
||||
# 72| getImplicitDestructorCall(0): [DestructorCall] call to ~string
|
||||
# 72| Type = [VoidType] void
|
||||
# 72| ValueCategory = prvalue
|
||||
# 72| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 72| Type = [SpecifiedType] const string
|
||||
# 72| ValueCategory = xvalue
|
||||
# 75| [TopLevelFunction] ClassWithDestructor2 make()
|
||||
# 75| <params>:
|
||||
# 77| [TopLevelFunction] void temp_test9()
|
||||
# 77| <params>:
|
||||
# 77| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 78| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 78| getExpr(): [FunctionCall] call to make
|
||||
# 78| Type = [Class] ClassWithDestructor2
|
||||
# 78| ValueCategory = prvalue
|
||||
# 78| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 78| Type = [Class] ClassWithDestructor2
|
||||
# 78| ValueCategory = prvalue
|
||||
# 78| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 78| Type = [VoidType] void
|
||||
# 78| ValueCategory = prvalue
|
||||
# 78| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 78| Type = [Class] ClassWithDestructor2
|
||||
# 78| ValueCategory = xvalue
|
||||
# 79| getStmt(1): [ReturnStmt] return ...
|
||||
# 81| [TopLevelFunction] void temp_test10(int)
|
||||
# 81| <params>:
|
||||
# 81| getParameter(0): [Parameter] i
|
||||
# 81| Type = [IntType] int
|
||||
# 81| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 82| getStmt(0): [WhileStmt] while (...) ...
|
||||
# 82| getCondition(): [LTExpr] ... < ...
|
||||
# 82| Type = [BoolType] bool
|
||||
# 82| ValueCategory = prvalue
|
||||
# 82| getLesserOperand(): [VariableAccess] i
|
||||
# 82| Type = [IntType] int
|
||||
# 82| ValueCategory = prvalue(load)
|
||||
# 82| getGreaterOperand(): [Literal] 10
|
||||
# 82| Type = [IntType] int
|
||||
# 82| Value = [Literal] 10
|
||||
# 82| ValueCategory = prvalue
|
||||
# 82| getStmt(): [BlockStmt] { ... }
|
||||
# 83| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 83| getExpr(): [FunctionCall] call to make
|
||||
# 83| Type = [Class] ClassWithDestructor2
|
||||
# 83| ValueCategory = prvalue
|
||||
# 83| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 83| Type = [Class] ClassWithDestructor2
|
||||
# 83| ValueCategory = prvalue
|
||||
# 83| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 83| Type = [VoidType] void
|
||||
# 83| ValueCategory = prvalue
|
||||
# 83| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 83| Type = [Class] ClassWithDestructor2
|
||||
# 83| ValueCategory = xvalue
|
||||
# 85| getStmt(1): [ReturnStmt] return ...
|
||||
# 87| [CopyAssignmentOperator] ClassWithDestructor3& ClassWithDestructor3::operator=(ClassWithDestructor3 const&)
|
||||
# 87| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const ClassWithDestructor3 &
|
||||
# 87| [Constructor] void ClassWithDestructor3::ClassWithDestructor3()
|
||||
# 87| <params>:
|
||||
# 88| [Destructor] void ClassWithDestructor3::~ClassWithDestructor3()
|
||||
# 88| <params>:
|
||||
# 89| [MemberFunction] ClassWithDestructor2 ClassWithDestructor3::getClassWithDestructor2()
|
||||
# 89| <params>:
|
||||
# 92| [TopLevelFunction] ClassWithDestructor3 makeClassWithDestructor3()
|
||||
# 92| <params>:
|
||||
# 94| [TopLevelFunction] void temp_test11()
|
||||
# 94| <params>:
|
||||
# 94| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 99| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 99| getExpr(): [FunctionCall] call to getClassWithDestructor2
|
||||
# 99| Type = [Class] ClassWithDestructor2
|
||||
# 99| ValueCategory = prvalue
|
||||
# 99| getQualifier(): [FunctionCall] call to makeClassWithDestructor3
|
||||
# 99| Type = [Struct] ClassWithDestructor3
|
||||
# 99| ValueCategory = prvalue
|
||||
# 99| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 99| Type = [Struct] ClassWithDestructor3
|
||||
# 99| ValueCategory = prvalue(load)
|
||||
# 99| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 99| Type = [Class] ClassWithDestructor2
|
||||
# 99| ValueCategory = prvalue
|
||||
# 99| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 99| Type = [VoidType] void
|
||||
# 99| ValueCategory = prvalue
|
||||
# 99| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 99| Type = [Class] ClassWithDestructor2
|
||||
# 99| ValueCategory = xvalue
|
||||
# 99| getImplicitDestructorCall(1): [DestructorCall] call to ~ClassWithDestructor3
|
||||
# 99| Type = [VoidType] void
|
||||
# 99| ValueCategory = prvalue
|
||||
# 99| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 99| Type = [Struct] ClassWithDestructor3
|
||||
# 99| ValueCategory = xvalue
|
||||
# 100| getStmt(1): [ReturnStmt] return ...
|
||||
# 102| [TopLevelFunction] void temp_test12(ClassWithDestructor3)
|
||||
# 102| <params>:
|
||||
# 102| getParameter(0): [Parameter] x
|
||||
# 102| Type = [Struct] ClassWithDestructor3
|
||||
# 102| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 103| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 103| getExpr(): [AddExpr] ... + ...
|
||||
# 103| Type = [IntType] int
|
||||
# 103| ValueCategory = prvalue
|
||||
# 103| getLeftOperand(): [FunctionCall] call to get_x
|
||||
# 103| Type = [PlainCharType] char
|
||||
# 103| ValueCategory = prvalue
|
||||
# 103| getQualifier(): [FunctionCall] call to getClassWithDestructor2
|
||||
# 103| Type = [Class] ClassWithDestructor2
|
||||
# 103| ValueCategory = prvalue
|
||||
# 103| getQualifier(): [VariableAccess] x
|
||||
# 103| Type = [Struct] ClassWithDestructor3
|
||||
# 103| ValueCategory = lvalue
|
||||
# 103| getQualifier().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 103| Type = [Class] ClassWithDestructor2
|
||||
# 103| ValueCategory = prvalue(load)
|
||||
# 103| getRightOperand(): [Literal] 5
|
||||
# 103| Type = [IntType] int
|
||||
# 103| Value = [Literal] 5
|
||||
# 103| ValueCategory = prvalue
|
||||
# 103| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor2
|
||||
# 103| Type = [VoidType] void
|
||||
# 103| ValueCategory = prvalue
|
||||
# 103| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 103| Type = [Class] ClassWithDestructor2
|
||||
# 103| ValueCategory = xvalue
|
||||
# 103| getLeftOperand().getFullyConverted(): [CStyleCast] (int)...
|
||||
# 103| Conversion = [IntegralConversion] integral conversion
|
||||
# 103| Type = [IntType] int
|
||||
# 103| ValueCategory = prvalue
|
||||
# 104| getStmt(1): [ReturnStmt] return ...
|
||||
ir.c:
|
||||
# 5| [TopLevelFunction] int getX(MyCoords*)
|
||||
# 5| <params>:
|
||||
@@ -13676,15 +13893,15 @@ ir.cpp:
|
||||
# 1425| getExpr(): [FunctionCall] call to defaultConstruct
|
||||
# 1425| Type = [Struct] String
|
||||
# 1425| ValueCategory = prvalue
|
||||
# 1425| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 1425| Type = [Struct] String
|
||||
# 1425| ValueCategory = prvalue
|
||||
# 1425| getImplicitDestructorCall(0): [DestructorCall] call to ~String
|
||||
# 1425| Type = [VoidType] void
|
||||
# 1425| ValueCategory = prvalue
|
||||
# 1425| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 1425| Type = [Struct] String
|
||||
# 1425| ValueCategory = xvalue
|
||||
# 1425| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 1425| Type = [Struct] String
|
||||
# 1425| ValueCategory = prvalue
|
||||
# 1426| getStmt(9): [ReturnStmt] return ...
|
||||
# 1426| getImplicitDestructorCall(0): [DestructorCall] call to ~String
|
||||
# 1426| Type = [VoidType] void
|
||||
@@ -13795,15 +14012,15 @@ ir.cpp:
|
||||
# 1437| getExpr(): [FunctionCall] call to defaultConstruct
|
||||
# 1437| Type = [Class] destructor_only
|
||||
# 1437| ValueCategory = prvalue
|
||||
# 1437| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 1437| Type = [Class] destructor_only
|
||||
# 1437| ValueCategory = prvalue
|
||||
# 1437| getImplicitDestructorCall(0): [DestructorCall] call to ~destructor_only
|
||||
# 1437| Type = [VoidType] void
|
||||
# 1437| ValueCategory = prvalue
|
||||
# 1437| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 1437| Type = [Class] destructor_only
|
||||
# 1437| ValueCategory = xvalue
|
||||
# 1437| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 1437| Type = [Class] destructor_only
|
||||
# 1437| ValueCategory = prvalue
|
||||
# 1438| getStmt(8): [ReturnStmt] return ...
|
||||
# 1438| getImplicitDestructorCall(0): [DestructorCall] call to ~destructor_only
|
||||
# 1438| Type = [VoidType] void
|
||||
@@ -20228,12 +20445,6 @@ ir.cpp:
|
||||
# 2307| getArgument(0).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 2307| Type = [PointerType] const char *
|
||||
# 2307| ValueCategory = prvalue
|
||||
# 2307| getImplicitDestructorCall(0): [DestructorCall] call to ~String
|
||||
# 2307| Type = [VoidType] void
|
||||
# 2307| ValueCategory = prvalue
|
||||
# 2307| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 2307| Type = [Struct] String
|
||||
# 2307| ValueCategory = xvalue
|
||||
# 2307| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2307| Type = [Struct] String
|
||||
# 2307| ValueCategory = lvalue
|
||||
@@ -20243,6 +20454,12 @@ ir.cpp:
|
||||
# 2307| getExpr(): [TemporaryObjectExpr] temporary object
|
||||
# 2307| Type = [ClassTemplateInstantiation,Struct] vector<String>
|
||||
# 2307| ValueCategory = xvalue
|
||||
# 2307| getImplicitDestructorCall(0): [DestructorCall] call to ~String
|
||||
# 2307| Type = [VoidType] void
|
||||
# 2307| ValueCategory = prvalue
|
||||
# 2307| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 2307| Type = [Struct] String
|
||||
# 2307| ValueCategory = xvalue
|
||||
# 2307| getBeginEndDeclaration(): [DeclStmt] declaration
|
||||
# 2307| getDeclarationEntry(0): [VariableDeclarationEntry] declaration of (__begin)
|
||||
# 2307| Type = [NestedTypedefType,UsingAliasTypedefType] iterator
|
||||
@@ -21901,6 +22118,126 @@ ir.cpp:
|
||||
# 2446| Type = [RValueReferenceType] ClassWithDestructor &&
|
||||
# 2446| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2448| getStmt(0): [ReturnStmt] return ...
|
||||
# 2450| [TopLevelFunction] void rethrow_with_destruction(int)
|
||||
# 2450| <params>:
|
||||
# 2450| getParameter(0): [Parameter] x
|
||||
# 2450| Type = [IntType] int
|
||||
# 2450| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2451| getStmt(0): [DeclStmt] declaration
|
||||
# 2451| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
|
||||
# 2451| Type = [Class] ClassWithDestructor
|
||||
# 2451| getVariable().getInitializer(): [Initializer] initializer for c
|
||||
# 2451| getExpr(): [ConstructorCall] call to ClassWithDestructor
|
||||
# 2451| Type = [VoidType] void
|
||||
# 2451| ValueCategory = prvalue
|
||||
# 2452| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 2452| getExpr(): [ReThrowExpr] re-throw exception
|
||||
# 2452| Type = [VoidType] void
|
||||
# 2452| ValueCategory = prvalue
|
||||
# 2453| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2453| Type = [VoidType] void
|
||||
# 2453| ValueCategory = prvalue
|
||||
# 2453| getQualifier(): [VariableAccess] c
|
||||
# 2453| Type = [Class] ClassWithDestructor
|
||||
# 2453| ValueCategory = lvalue
|
||||
# 2455| [CopyAssignmentOperator] ByValueConstructor& ByValueConstructor::operator=(ByValueConstructor const&)
|
||||
# 2455| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const ByValueConstructor &
|
||||
# 2455| [MoveAssignmentOperator] ByValueConstructor& ByValueConstructor::operator=(ByValueConstructor&&)
|
||||
# 2455| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] ByValueConstructor &&
|
||||
# 2455| [CopyConstructor] void ByValueConstructor::ByValueConstructor(ByValueConstructor const&)
|
||||
# 2455| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const ByValueConstructor &
|
||||
# 2455| [MoveConstructor] void ByValueConstructor::ByValueConstructor(ByValueConstructor&&)
|
||||
# 2455| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] ByValueConstructor &&
|
||||
# 2456| [Constructor] void ByValueConstructor::ByValueConstructor(ClassWithDestructor)
|
||||
# 2456| <params>:
|
||||
# 2456| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
# 2456| Type = [Class] ClassWithDestructor
|
||||
# 2459| [TopLevelFunction] void new_with_destructor(ClassWithDestructor)
|
||||
# 2459| <params>:
|
||||
# 2459| getParameter(0): [Parameter] a
|
||||
# 2459| Type = [Class] ClassWithDestructor
|
||||
# 2460| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2461| getStmt(0): [DeclStmt] declaration
|
||||
# 2461| getDeclarationEntry(0): [VariableDeclarationEntry] definition of b
|
||||
# 2461| Type = [PointerType] ByValueConstructor *
|
||||
# 2461| getVariable().getInitializer(): [Initializer] initializer for b
|
||||
# 2461| getExpr(): [NewExpr] new
|
||||
# 2461| Type = [PointerType] ByValueConstructor *
|
||||
# 2461| ValueCategory = prvalue
|
||||
# 2461| getInitializer(): [ConstructorCall] call to ByValueConstructor
|
||||
# 2461| Type = [VoidType] void
|
||||
# 2461| ValueCategory = prvalue
|
||||
# 2461| getArgument(0): [VariableAccess] a
|
||||
# 2461| Type = [Class] ClassWithDestructor
|
||||
# 2461| ValueCategory = prvalue(load)
|
||||
# 2461| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 2461| Type = [Class] ClassWithDestructor
|
||||
# 2461| ValueCategory = lvalue
|
||||
# 2461| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2461| Type = [VoidType] void
|
||||
# 2461| ValueCategory = prvalue
|
||||
# 2461| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 2461| Type = [Class] ClassWithDestructor
|
||||
# 2461| ValueCategory = xvalue
|
||||
# 2462| getStmt(1): [ReturnStmt] return ...
|
||||
# 2465| [CopyAssignmentOperator] rvalue_conversion_with_destructor::A& rvalue_conversion_with_destructor::A::operator=(rvalue_conversion_with_destructor::A const&)
|
||||
# 2465| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const A &
|
||||
# 2465| [MoveAssignmentOperator] rvalue_conversion_with_destructor::A& rvalue_conversion_with_destructor::A::operator=(rvalue_conversion_with_destructor::A&&)
|
||||
# 2465| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] A &&
|
||||
# 2469| [CopyAssignmentOperator] rvalue_conversion_with_destructor::B& rvalue_conversion_with_destructor::B::operator=(rvalue_conversion_with_destructor::B const&)
|
||||
# 2469| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const B &
|
||||
# 2469| [Constructor] void rvalue_conversion_with_destructor::B::B()
|
||||
# 2469| <params>:
|
||||
# 2471| [Destructor] void rvalue_conversion_with_destructor::B::~B()
|
||||
# 2471| <params>:
|
||||
# 2473| [ConstMemberFunction] rvalue_conversion_with_destructor::A* rvalue_conversion_with_destructor::B::operator->() const
|
||||
# 2473| <params>:
|
||||
# 2476| [TopLevelFunction] rvalue_conversion_with_destructor::B rvalue_conversion_with_destructor::get()
|
||||
# 2476| <params>:
|
||||
# 2478| [TopLevelFunction] void rvalue_conversion_with_destructor::test()
|
||||
# 2478| <params>:
|
||||
# 2479| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2480| getStmt(0): [DeclStmt] declaration
|
||||
# 2480| getDeclarationEntry(0): [VariableDeclarationEntry] definition of a
|
||||
# 2480| Type = [IntType] unsigned int
|
||||
# 2480| getVariable().getInitializer(): [Initializer] initializer for a
|
||||
# 2480| getExpr(): [PointerFieldAccess] a
|
||||
# 2480| Type = [IntType] unsigned int
|
||||
# 2480| ValueCategory = prvalue(load)
|
||||
# 2480| getQualifier(): [FunctionCall] call to operator->
|
||||
# 2480| Type = [PointerType] A *
|
||||
# 2480| ValueCategory = prvalue
|
||||
# 2480| getQualifier(): [FunctionCall] call to get
|
||||
# 2480| Type = [Struct] B
|
||||
# 2480| ValueCategory = prvalue
|
||||
# 2480| getQualifier().getFullyConverted(): [CStyleCast] (const B)...
|
||||
# 2480| Conversion = [PrvalueAdjustmentConversion] prvalue adjustment conversion
|
||||
# 2480| Type = [SpecifiedType] const B
|
||||
# 2480| ValueCategory = prvalue
|
||||
# 2480| getExpr(): [TemporaryObjectExpr] temporary object
|
||||
# 2480| Type = [Struct] B
|
||||
# 2480| ValueCategory = prvalue(load)
|
||||
# 2480| getImplicitDestructorCall(0): [DestructorCall] call to ~B
|
||||
# 2480| Type = [VoidType] void
|
||||
# 2480| ValueCategory = prvalue
|
||||
# 2480| getQualifier(): [ReuseExpr] reuse of temporary object
|
||||
# 2480| Type = [Struct] B
|
||||
# 2480| ValueCategory = xvalue
|
||||
# 2481| getStmt(1): [ReturnStmt] return ...
|
||||
perf-regression.cpp:
|
||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||
# 4| <params>:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -54,3 +54,51 @@ void temp_test7(bool b) {
|
||||
void temp_test8(bool b) {
|
||||
b ? throw ClassWithConstructor('x', ClassWithDestructor2().get_x()) : ClassWithDestructor2();
|
||||
}
|
||||
|
||||
void temp_test8_simple(bool b) {
|
||||
b ? throw ClassWithDestructor2().get_x() : 'a';
|
||||
}
|
||||
|
||||
struct string
|
||||
{
|
||||
string(const char *);
|
||||
~string();
|
||||
};
|
||||
|
||||
bool const_ref_string(const string &);
|
||||
|
||||
bool conditional_temp_via_conjunction(bool b)
|
||||
{
|
||||
return b && const_ref_string("");
|
||||
}
|
||||
|
||||
ClassWithDestructor2 make();
|
||||
|
||||
void temp_test9() {
|
||||
make();
|
||||
}
|
||||
|
||||
void temp_test10(int i) {
|
||||
while(i < 10) {
|
||||
make();
|
||||
}
|
||||
}
|
||||
|
||||
struct ClassWithDestructor3 {
|
||||
~ClassWithDestructor3();
|
||||
ClassWithDestructor2 getClassWithDestructor2();
|
||||
};
|
||||
|
||||
ClassWithDestructor3 makeClassWithDestructor3();
|
||||
|
||||
void temp_test11() {
|
||||
// Two destructors are called at the semicolon (i.e., they're both attached
|
||||
// to the call to `getClassWithDestructor2()`):
|
||||
// First, ~ClassWithDestructor2::ClassWithDestructor2(), and then the call
|
||||
// to `~ClassWithDestructor3::ClassWithDestructor3()`.
|
||||
makeClassWithDestructor3().getClassWithDestructor2();
|
||||
}
|
||||
|
||||
void temp_test12(ClassWithDestructor3 x) {
|
||||
x.getClassWithDestructor2().get_x() + 5;
|
||||
}
|
||||
@@ -2447,4 +2447,38 @@ void param_with_destructor_by_rref(ClassWithDestructor&& c) {
|
||||
// No destructor call should be here
|
||||
}
|
||||
|
||||
void rethrow_with_destruction(int x) {
|
||||
ClassWithDestructor c;
|
||||
throw;
|
||||
}
|
||||
|
||||
struct ByValueConstructor {
|
||||
ByValueConstructor(ClassWithDestructor);
|
||||
};
|
||||
|
||||
void new_with_destructor(ClassWithDestructor a)
|
||||
{
|
||||
ByValueConstructor* b = new ByValueConstructor(a);
|
||||
}
|
||||
|
||||
namespace rvalue_conversion_with_destructor {
|
||||
struct A {
|
||||
unsigned a;
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
~B();
|
||||
|
||||
inline A *operator->() const;
|
||||
};
|
||||
|
||||
B get();
|
||||
|
||||
void test()
|
||||
{
|
||||
auto a = get()->a;
|
||||
}
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++20 --clang
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -12,7 +12,11 @@ unnecessaryPhiInstruction
|
||||
memoryOperandDefinitionIsUnmodeled
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
containsLoopOfForwardEdges
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
@@ -24,8 +28,4 @@ nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
nonUniqueIRVariable
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -12,7 +12,11 @@ unnecessaryPhiInstruction
|
||||
memoryOperandDefinitionIsUnmodeled
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
containsLoopOfForwardEdges
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
@@ -24,8 +28,4 @@ nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
nonUniqueIRVariable
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -12,7 +12,11 @@ unnecessaryPhiInstruction
|
||||
memoryOperandDefinitionIsUnmodeled
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
containsLoopOfForwardEdges
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
@@ -24,8 +28,4 @@ nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
nonUniqueIRVariable
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -12,7 +12,11 @@ unnecessaryPhiInstruction
|
||||
memoryOperandDefinitionIsUnmodeled
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
containsLoopOfForwardEdges
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
@@ -24,8 +28,4 @@ nonUniqueEnclosingIRFunction
|
||||
fieldAddressOnNonPointer
|
||||
thisArgumentIsNonPointer
|
||||
nonUniqueIRVariable
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
multipleIRTypes
|
||||
missingCppType
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -7,7 +7,7 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ms_try_mix.cpp:35:13:35:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:38:5:38:5 | Chi: c106 | Instruction 'Chi: c106' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:53:5:53:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:49:6:49:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() |
|
||||
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
ambiguousSuccessors
|
||||
|
||||
@@ -8,7 +8,7 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ms_try_mix.cpp:35:13:35:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:38:5:38:5 | IndirectMayWriteSideEffect: c106 | Instruction 'IndirectMayWriteSideEffect: c106' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:53:5:53:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:49:6:49:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() |
|
||||
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
| stmt_expr.cpp:29:11:32:11 | CopyValue: (statement expression) | Instruction 'CopyValue: (statement expression)' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
|
||||
@@ -7,7 +7,7 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ms_try_mix.cpp:35:13:35:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:38:5:38:5 | IndirectMayWriteSideEffect: c106 | Instruction 'IndirectMayWriteSideEffect: c106' has no successors in function '$@'. | ms_try_mix.cpp:29:6:29:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
|
||||
| ms_try_mix.cpp:53:5:53:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:49:6:49:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() |
|
||||
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:13:21:13 | void stmtexpr::g(int) | void stmtexpr::g(int) |
|
||||
ambiguousSuccessors
|
||||
|
||||
Reference in New Issue
Block a user