[CFG] Provide construction contexts for lifetime-extended temporaries.

When constructing a temporary that is going to be lifetime-extended through a
MaterializeTemporaryExpr later, CFG elements for the respective constructor
can now be queried to obtain the reference to that MaterializeTemporaryExpr
and therefore gain information about lifetime extension.

This may produce multi-layered construction contexts when information about
both temporary destruction and lifetime extension is available.

Differential Revision: https://reviews.llvm.org/D43477

llvm-svn: 326014
This commit is contained in:
Artem Dergachev 2018-02-24 02:00:30 +00:00
parent c9f0b65f54
commit f43ac4c9ac
4 changed files with 53 additions and 11 deletions

View File

@ -193,6 +193,17 @@ public:
return Trigger.dyn_cast<CXXCtorInitializer *>(); return Trigger.dyn_cast<CXXCtorInitializer *>();
} }
const MaterializeTemporaryExpr *getMaterializedTemporary() const {
// TODO: Be more careful to ensure that there's only one MTE around.
for (const ConstructionContext *CC = this; CC; CC = CC->getParent()) {
if (const auto *MTE = dyn_cast_or_null<MaterializeTemporaryExpr>(
CC->getTriggerStmt())) {
return MTE;
}
}
return nullptr;
}
bool isSameAsPartialContext(const ConstructionContext *Other) const { bool isSameAsPartialContext(const ConstructionContext *Other) const {
assert(Other); assert(Other);
return (Trigger == Other->Trigger); return (Trigger == Other->Trigger);
@ -248,6 +259,10 @@ public:
return getConstructionContext()->getTriggerInit(); return getConstructionContext()->getTriggerInit();
} }
const MaterializeTemporaryExpr *getMaterializedTemporary() const {
return getConstructionContext()->getMaterializedTemporary();
}
private: private:
friend class CFGElement; friend class CFGElement;

View File

@ -548,6 +548,8 @@ private:
Stmt *Term, Stmt *Term,
CFGBlock *TrueBlock, CFGBlock *TrueBlock,
CFGBlock *FalseBlock); CFGBlock *FalseBlock);
CFGBlock *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
AddStmtChoice asc);
CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc); CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc);
CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S);
CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S);
@ -1840,6 +1842,10 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::LambdaExprClass: case Stmt::LambdaExprClass:
return VisitLambdaExpr(cast<LambdaExpr>(S), asc); return VisitLambdaExpr(cast<LambdaExpr>(S), asc);
case Stmt::MaterializeTemporaryExprClass:
return VisitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(S),
asc);
case Stmt::MemberExprClass: case Stmt::MemberExprClass:
return VisitMemberExpr(cast<MemberExpr>(S), asc); return VisitMemberExpr(cast<MemberExpr>(S), asc);
@ -2975,6 +2981,16 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
return EntryConditionBlock; return EntryConditionBlock;
} }
CFGBlock *
CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE,
AddStmtChoice asc) {
findConstructionContexts(
ConstructionContext::create(cfg->getBumpVectorContext(), MTE),
MTE->getTemporary());
return VisitStmt(MTE, asc);
}
CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) { CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) {
if (asc.alwaysAdd(*this, M)) { if (asc.alwaysAdd(*this, M)) {
autoCreateBlock(); autoCreateBlock();
@ -4706,13 +4722,20 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
} else if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(S)) { } else if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(S)) {
OS << " (CXXConstructExpr, "; OS << " (CXXConstructExpr, ";
if (Optional<CFGConstructor> CE = E.getAs<CFGConstructor>()) { if (Optional<CFGConstructor> CE = E.getAs<CFGConstructor>()) {
// TODO: Refactor into ConstructionContext::print().
if (const Stmt *S = CE->getTriggerStmt()) if (const Stmt *S = CE->getTriggerStmt())
Helper.handledStmt((const_cast<Stmt *>(S)), OS); Helper.handledStmt(const_cast<Stmt *>(S), OS);
else if (const CXXCtorInitializer *I = CE->getTriggerInit()) else if (const CXXCtorInitializer *I = CE->getTriggerInit())
print_initializer(OS, Helper, I); print_initializer(OS, Helper, I);
else else
llvm_unreachable("Unexpected trigger kind!"); llvm_unreachable("Unexpected trigger kind!");
OS << ", "; OS << ", ";
if (const Stmt *S = CE->getMaterializedTemporary()) {
if (S != CE->getTriggerStmt()) {
Helper.handledStmt(const_cast<Stmt *>(S), OS);
OS << ", ";
}
}
} }
OS << CCE->getType().getAsString() << ")"; OS << CCE->getType().getAsString() << ")";
} else if (const CastExpr *CE = dyn_cast<CastExpr>(S)) { } else if (const CastExpr *CE = dyn_cast<CastExpr>(S)) {

View File

@ -133,11 +133,10 @@ void simpleVariableWithTernaryOperator(bool coin) {
C c = coin ? C::get() : C(0); C c = coin ? C::get() : C(0);
} }
// TODO: Should find construction target here.
// CHECK: void referenceVariableWithConstructor() // CHECK: void referenceVariableWithConstructor()
// CHECK: 1: 0 // CHECK: 1: 0
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *) // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *)
// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, const class C) // CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], const class C)
// CHECK-NEXT: 4: [B1.3] // CHECK-NEXT: 4: [B1.3]
// CHECK-NEXT: 5: const C &c(0); // CHECK-NEXT: 5: const C &c(0);
void referenceVariableWithConstructor() { void referenceVariableWithConstructor() {
@ -267,9 +266,8 @@ C returnBracesWithMultipleItems() {
return {123, 456}; return {123, 456};
} }
// TODO: Should find construction targets for the first constructor as well.
// CHECK: C returnTemporary() // CHECK: C returnTemporary()
// CHECK: 1: C() (CXXConstructExpr, class C) // CHECK: 1: C() (CXXConstructExpr, [B1.2], class C)
// CHECK-NEXT: 2: [B1.1] // CHECK-NEXT: 2: [B1.1]
// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C) // CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C)
// CHECK-NEXT: 4: return [B1.3]; // CHECK-NEXT: 4: return [B1.3];
@ -400,7 +398,7 @@ void temporaryInCondition() {
// CHECK: void referenceVariableWithConstructor() // CHECK: void referenceVariableWithConstructor()
// CHECK: 1: 0 // CHECK: 1: 0
// CHECK-NEXT: 2: [B1.1] (CXXConstructExpr, [B1.3], const class temporary_object_expr_with_dtors::D) // CHECK-NEXT: 2: [B1.1] (CXXConstructExpr, [B1.3], [B1.4], const class temporary_object_expr_with_dtors::D)
// CHECK-NEXT: 3: [B1.2] (BindTemporary) // CHECK-NEXT: 3: [B1.2] (BindTemporary)
// CHECK-NEXT: 4: [B1.3] // CHECK-NEXT: 4: [B1.3]
// CHECK-NEXT: 5: const temporary_object_expr_with_dtors::D &d(0); // CHECK-NEXT: 5: const temporary_object_expr_with_dtors::D &d(0);

View File

@ -714,7 +714,9 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (1): B3 // CHECK: Preds (1): B3
// CHECK: Succs (1): B0 // CHECK: Succs (1): B0
// CHECK: [B3] // CHECK: [B3]
// CHECK: 1: D() (CXXConstructExpr, struct D) // WARNINGS: 1: D() (CXXConstructExpr, struct D)
// CXX98-ANALYZER: 1: D() (CXXConstructExpr, struct D)
// CXX11-ANALYZER: 1: D() (CXXConstructExpr, [B3.2], struct D)
// CXX98: 2: [B3.1] (ImplicitCastExpr, NoOp, const struct D) // CXX98: 2: [B3.1] (ImplicitCastExpr, NoOp, const struct D)
// CXX98: 3: [B3.2] // CXX98: 3: [B3.2]
// CXX98-WARNINGS: 4: [B3.3] (CXXConstructExpr, struct D) // CXX98-WARNINGS: 4: [B3.3] (CXXConstructExpr, struct D)
@ -925,7 +927,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B4 // CHECK: Succs (1): B4
// CHECK: [B7] // CHECK: [B7]
// WARNINGS: 1: A() (CXXConstructExpr, class A) // WARNINGS: 1: A() (CXXConstructExpr, class A)
// ANALYZER: 1: A() (CXXConstructExpr, [B7.2], class A) // ANALYZER-CXX98: 1: A() (CXXConstructExpr, [B7.2], [B7.3], class A)
// ANALYZER-CXX11: 1: A() (CXXConstructExpr, [B7.2], class A)
// CHECK: 2: [B7.1] (BindTemporary) // CHECK: 2: [B7.1] (BindTemporary)
// CXX98: 3: [B7.2].operator bool // CXX98: 3: [B7.2].operator bool
// CXX98: 4: [B7.2] // CXX98: 4: [B7.2]
@ -992,7 +995,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: 1: foo // CHECK: 1: foo
// CHECK: 2: [B7.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &)) // CHECK: 2: [B7.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
// WARNINGS: 3: A() (CXXConstructExpr, class A) // WARNINGS: 3: A() (CXXConstructExpr, class A)
// ANALYZER: 3: A() (CXXConstructExpr, [B7.4], class A) // ANALYZER-CXX98: 3: A() (CXXConstructExpr, [B7.4], class A)
// ANALYZER-CXX11: 3: A() (CXXConstructExpr, class A)
// CHECK: 4: [B7.3] (BindTemporary) // CHECK: 4: [B7.3] (BindTemporary)
// CXX98: 5: [B7.4].operator bool // CXX98: 5: [B7.4].operator bool
// CXX98: 6: [B7.4] // CXX98: 6: [B7.4]
@ -1043,7 +1047,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Succs (1): B9 // CHECK: Succs (1): B9
// CHECK: [B12] // CHECK: [B12]
// WARNINGS: 1: A() (CXXConstructExpr, class A) // WARNINGS: 1: A() (CXXConstructExpr, class A)
// ANALYZER: 1: A() (CXXConstructExpr, [B12.2], class A) // ANALYZER-CXX98: 1: A() (CXXConstructExpr, [B12.2], [B12.3], class A)
// ANALYZER-CXX11: 1: A() (CXXConstructExpr, [B12.2], class A)
// CHECK: 2: [B12.1] (BindTemporary) // CHECK: 2: [B12.1] (BindTemporary)
// CXX98: 3: [B12.2].operator bool // CXX98: 3: [B12.2].operator bool
// CXX98: 4: [B12.2] // CXX98: 4: [B12.2]
@ -1199,7 +1204,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: [B2 (NORETURN)] // CHECK: [B2 (NORETURN)]
// CHECK: 1: int a; // CHECK: 1: int a;
// WARNINGS: 2: NoReturn() (CXXConstructExpr, class NoReturn) // WARNINGS: 2: NoReturn() (CXXConstructExpr, class NoReturn)
// ANALYZER: 2: NoReturn() (CXXConstructExpr, [B2.3], class NoReturn) // ANALYZER-CXX98: 2: NoReturn() (CXXConstructExpr, [B2.3], [B2.4], class NoReturn)
// ANALYZER-CXX11: 2: NoReturn() (CXXConstructExpr, [B2.3], class NoReturn)
// CHECK: 3: [B2.2] (BindTemporary) // CHECK: 3: [B2.2] (BindTemporary)
// CHECK: [[MEMBER:[45]]]: [B2.{{[34]}}].f // CHECK: [[MEMBER:[45]]]: [B2.{{[34]}}].f
// CHECK: {{[56]}}: [B2.[[MEMBER]]]() // CHECK: {{[56]}}: [B2.[[MEMBER]]]()