CFG: Destroy temporaries in (a,b) expression in the correct order.

This commit is contained in:
Richard Smith 2020-08-05 14:52:24 -07:00
parent c66169136f
commit 076b120beb
2 changed files with 26 additions and 12 deletions

View File

@ -4773,11 +4773,11 @@ CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E,
CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors( CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
BinaryOperator *E, bool ExternallyDestructed, TempDtorContext &Context) { BinaryOperator *E, bool ExternallyDestructed, TempDtorContext &Context) {
if (E->isCommaOp()) { if (E->isCommaOp()) {
// For comma operator LHS expression is visited // For the comma operator, the LHS expression is evaluated before the RHS
// before RHS expression. For destructors visit them in reverse order. // expression, so prepend temporary destructors for the LHS first.
CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), ExternallyDestructed, Context);
CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context); CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context);
return LHSBlock ? LHSBlock : RHSBlock; CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), ExternallyDestructed, Context);
return RHSBlock ? RHSBlock : LHSBlock;
} }
if (E->isLogicalOp()) { if (E->isLogicalOp()) {
@ -4798,19 +4798,15 @@ CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
} }
if (E->isAssignmentOp()) { if (E->isAssignmentOp()) {
// For assignment operator (=) LHS expression is visited // For assignment operators, the RHS expression is evaluated before the LHS
// before RHS expression. For destructors visit them in reverse order. // expression, so prepend temporary destructors for the RHS first.
CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), false, Context); CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), false, Context);
CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context); CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context);
return LHSBlock ? LHSBlock : RHSBlock; return LHSBlock ? LHSBlock : RHSBlock;
} }
// For any other binary operator RHS expression is visited before // Any other operator is visited normally.
// LHS expression (order of children). For destructors visit them in reverse return VisitChildrenForTemporaryDtors(E, ExternallyDestructed, Context);
// order.
CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context);
CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), false, Context);
return RHSBlock ? RHSBlock : LHSBlock;
} }
CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors( CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(

View File

@ -575,6 +575,24 @@ int vla_evaluate(int x) {
return x; return x;
} }
// CHECK-LABEL: void CommaTemp::f()
// CHECK: [B1]
// CHECK-NEXT: 1: CommaTemp::A() (CXXConstructExpr,
// CHECK-NEXT: 2: [B1.1] (BindTemporary)
// CHECK-NEXT: 3: CommaTemp::B() (CXXConstructExpr,
// CHECK-NEXT: 4: [B1.3] (BindTemporary)
// CHECK-NEXT: 5: ... , [B1.4]
// CHECK-NEXT: 6: ~CommaTemp::B() (Temporary object destructor)
// CHECK-NEXT: 7: ~CommaTemp::A() (Temporary object destructor)
namespace CommaTemp {
struct A { ~A(); };
struct B { ~B(); };
void f();
}
void CommaTemp::f() {
A(), B();
}
// CHECK-LABEL: template<> int *PR18472<int>() // CHECK-LABEL: template<> int *PR18472<int>()
// CHECK: [B2 (ENTRY)] // CHECK: [B2 (ENTRY)]
// CHECK-NEXT: Succs (1): B1 // CHECK-NEXT: Succs (1): B1