]> granicus.if.org Git - clang/commitdiff
[CFG] Provide construction contexts for return value constructors.
authorArtem Dergachev <artem.dergachev@gmail.com>
Mon, 12 Feb 2018 22:36:36 +0000 (22:36 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Mon, 12 Feb 2018 22:36:36 +0000 (22:36 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@324952 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/CFG.cpp
test/Analysis/cfg-rich-constructors.cpp
test/Analysis/temp-obj-dtors-cfg-output.cpp

index 934abb063e899d8a7dc06b54efc701642c5b5192..cec5a652b94aeb3f885529bad98376b23104c863 100644 (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())
index 012d382a75a3bda498fe22ced60a43ed5b283ec0..46125f729f9805608e37b3a462789ca1c4c7e4be 100644 (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
index f6c84f505d98f4072259bb10d1513b002e7ed362..1ddf877861a3d2cb493b1c0155765a2730b2a155 100644 (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