[CFG] Provide construction contexts for return value constructors.

When the current function returns a C++ object by value, CFG elements for
constructors that construct the return values can now be queried to discover
that they're indeed participating in construction of the respective return value
at the respective return statement.

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

llvm-svn: 324952
This commit is contained in:
Artem Dergachev 2018-02-12 22:36:36 +00:00
parent 005e7c3d75
commit 9ac2e11385
3 changed files with 98 additions and 2 deletions

View File

@ -2575,6 +2575,8 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) {
addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), R);
EnterConstructionContextIfNecessary(R, R->getRetValue());
// If the one of the destructors does not return, we already have the Exit
// block as a successor.
if (!Block->hasNoReturnElement())

View File

@ -5,6 +5,7 @@ class C {
public:
C();
C(C *);
C(int, int);
static C get();
};
@ -224,3 +225,94 @@ public:
};
} // end namespace ctor_initializers
namespace return_stmt {
// CHECK: C returnVariable()
// CHECK: 1: (CXXConstructExpr, [B1.2], class C)
// CHECK-NEXT: 2: C c;
// CHECK-NEXT: 3: c
// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, class C)
// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C)
// CHECK-NEXT: 6: return [B1.5];
C returnVariable() {
C c;
return c;
}
// CHECK: C returnEmptyBraces()
// CHECK: 1: {} (CXXConstructExpr, [B1.2], class C)
// CHECK-NEXT: 2: return [B1.1];
C returnEmptyBraces() {
return {};
}
// CHECK: C returnBracesWithOperatorNew()
// CHECK: 1: CFGNewAllocator(C *)
// CHECK-NEXT: 2: (CXXConstructExpr, [B1.3], class C)
// CHECK-NEXT: 3: new C([B1.2])
// CHECK-NEXT: 4: {[B1.3]} (CXXConstructExpr, [B1.5], class C)
// CHECK-NEXT: 5: return [B1.4];
C returnBracesWithOperatorNew() {
return {new C()};
}
// CHECK: C returnBracesWithMultipleItems()
// CHECK: 1: 123
// CHECK-NEXT: 2: 456
// CHECK-NEXT: 3: {[B1.1], [B1.2]} (CXXConstructExpr, [B1.4], class C)
// CHECK-NEXT: 4: return [B1.3];
C returnBracesWithMultipleItems() {
return {123, 456};
}
// TODO: Should find construction targets for the first constructor as well.
// CHECK: C returnTemporary()
// CHECK: 1: C() (CXXConstructExpr, class C)
// CHECK-NEXT: 2: [B1.1]
// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C)
// CHECK-NEXT: 4: return [B1.3];
C returnTemporary() {
return C();
}
// TODO: Should find construction targets for the first constructor as well.
// CHECK: C returnTemporaryWithArgument()
// CHECK: 1: nullptr
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *)
// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, class C)
// CHECK-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
// CHECK-NEXT: 5: [B1.4]
// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], class C)
// CHECK-NEXT: 7: return [B1.6];
C returnTemporaryWithArgument() {
return C(nullptr);
}
// CHECK: C returnTemporaryConstructedByFunction()
// CHECK: 1: C::get
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
// CHECK-NEXT: 3: [B1.2]()
// CHECK-NEXT: 4: [B1.3]
// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C)
// CHECK-NEXT: 6: return [B1.5];
C returnTemporaryConstructedByFunction() {
return C::get();
}
// TODO: Should find construction targets for the first constructor as well.
// CHECK: C returnChainOfCopies()
// CHECK: 1: C::get
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
// CHECK-NEXT: 3: [B1.2]()
// CHECK-NEXT: 4: [B1.3]
// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, class C)
// CHECK-NEXT: 6: C([B1.5]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
// CHECK-NEXT: 7: [B1.6]
// CHECK-NEXT: 8: [B1.7] (CXXConstructExpr, [B1.9], class C)
// CHECK-NEXT: 9: return [B1.8];
C returnChainOfCopies() {
return C(C::get());
}
} // end namespace return_stmt

View File

@ -220,7 +220,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: 2: [B1.1] (BindTemporary)
// CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 4: [B1.3]
// CHECK: 5: [B1.4] (CXXConstructExpr, class A)
// WARNINGS: 5: [B1.4] (CXXConstructExpr, class A)
// ANALYZER: 5: [B1.4] (CXXConstructExpr, [B1.7], class A)
// CHECK: 6: ~A() (Temporary object destructor)
// CHECK: 7: return [B1.5];
// CHECK: Preds (1): B2
@ -278,7 +279,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: 2: [B1.1] (BindTemporary)
// CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 4: [B1.3]
// CHECK: 5: [B1.4] (CXXConstructExpr, class A)
// WARNINGS: 5: [B1.4] (CXXConstructExpr, class A)
// ANALYZER: 5: [B1.4] (CXXConstructExpr, [B1.7], class A)
// CHECK: 6: ~A() (Temporary object destructor)
// CHECK: 7: return [B1.5];
// CHECK: Preds (1): B2