Skip to content

Commit

Permalink
[CFG] Provide construction contexts for return value constructors.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
haoNoQ committed Feb 12, 2018
1 parent 005e7c3 commit 9ac2e11
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 2 deletions.
2 changes: 2 additions & 0 deletions clang/lib/Analysis/CFG.cpp
Expand Up @@ -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())
Expand Down
92 changes: 92 additions & 0 deletions clang/test/Analysis/cfg-rich-constructors.cpp
Expand Up @@ -5,6 +5,7 @@ class C {
public:
C();
C(C *);
C(int, int);

static C get();
};
Expand Down Expand Up @@ -224,3 +225,94 @@ class D: public C {
};

} // 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
6 changes: 4 additions & 2 deletions clang/test/Analysis/temp-obj-dtors-cfg-output.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 9ac2e11

Please sign in to comment.