]> granicus.if.org Git - clang/commitdiff
[CFG] [analyzer] Don't treat argument constructors as temporary constructors.
authorArtem Dergachev <artem.dergachev@gmail.com>
Thu, 19 Apr 2018 23:09:22 +0000 (23:09 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Thu, 19 Apr 2018 23:09:22 +0000 (23:09 +0000)
Function argument constructors (that are used for passing objects into functions
by value) are completely unlike temporary object constructors, but we were
treating them as such because they are also wrapped into a CXXBindTemporaryExpr.

This patch adds a partial construction context layer for call argument values,
but doesn't proceed to transform it into an actual construction context yet.
This is tells the clients that we aren't supporting these constructors yet.

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

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

lib/Analysis/CFG.cpp
lib/Analysis/ConstructionContext.cpp
test/Analysis/cfg-rich-constructors.cpp

index 34d40162275711ba19507dbacfab14517b0b2ae4..66019329a3b21b7bf4d851601122180d3e6a9fb6 100644 (file)
@@ -2367,6 +2367,13 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
     if (!boundType.isNull()) calleeType = boundType;
   }
 
+  // FIXME: Once actually implemented, this construction context layer should
+  // include the number of the argument as well.
+  for (auto Arg: C->arguments()) {
+    findConstructionContexts(
+        ConstructionContextLayer::create(cfg->getBumpVectorContext(), C), Arg);
+  }
+
   // If this is a call to a no-return function, this stops the block here.
   bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn();
 
index 9f3c00b2bc992739cdf35577df85338cca15f840..8656a1bbe0911fc3d9c1ee05c4f6aa3e93c2ce2a 100644 (file)
@@ -79,6 +79,9 @@ const ConstructionContext *ConstructionContext::createFromLayers(
                  ParentLayer->getTriggerStmt()))) {
           return create<TemporaryObjectConstructionContext>(C, BTE, MTE);
         }
+        // This is a constructor into a function argument. Not implemented yet.
+        if (auto *CE = dyn_cast<CallExpr>(ParentLayer->getTriggerStmt()))
+          return nullptr;
         // This is C++17 copy-elided construction into return statement.
         if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) {
           assert(!RS->getRetValue()->getType().getCanonicalType()
@@ -114,6 +117,9 @@ const ConstructionContext *ConstructionContext::createFromLayers(
       assert(TopLayer->isLast());
       return create<SimpleReturnedValueConstructionContext>(C, RS);
     }
+    // This is a constructor into a function argument. Not implemented yet.
+    if (auto *CE = dyn_cast<CallExpr>(TopLayer->getTriggerStmt()))
+      return nullptr;
     llvm_unreachable("Unexpected construction context with statement!");
   } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {
     assert(TopLayer->isLast());
index 51eca122292aa810c1d1ea2f3f16b7672f1ee98a..eaaa5786f8315ee45d73191a6e7a3d72bfc11de9 100644 (file)
@@ -693,3 +693,75 @@ void implicitConstructionConversionFromFunctionValueWithLifetimeExtension() {
 }
 
 } // end namespace implicit_constructor_conversion
+
+namespace argument_constructors {
+class D {
+public:
+  D();
+  ~D();
+};
+
+void useC(C c);
+void useCByReference(const C &c);
+void useD(D d);
+void useDByReference(const D &d);
+
+// FIXME: Find construction context for the argument.
+// CHECK: void passArgument()
+// CHECK:          1: useC
+// CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(class C))
+// CXX11-NEXT:     3: C() (CXXConstructExpr, [B1.4], class C)
+// CXX11-NEXT:     4: [B1.3]
+// CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, class C)
+// CXX11-NEXT:     6: [B1.2]([B1.5])
+// CXX17-NEXT:     3: C() (CXXConstructExpr, class C)
+// CXX17-NEXT:     4: [B1.2]([B1.3])
+void passArgument() {
+  useC(C());
+}
+
+// CHECK: void passArgumentByReference()
+// CHECK:          1: useCByReference
+// CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class C &))
+// CHECK-NEXT:     3: C() (CXXConstructExpr, [B1.5], class C)
+// CHECK-NEXT:     4: [B1.3] (ImplicitCastExpr, NoOp, const class C)
+// CHECK-NEXT:     5: [B1.4]
+// CHECK-NEXT:     6: [B1.2]([B1.5])
+void passArgumentByReference() {
+  useCByReference(C());
+}
+
+// FIXME: Find construction context for the argument.
+// CHECK: void passArgumentWithDestructor()
+// CHECK:          1: useD
+// CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(class argument_constructors::D))
+// CXX11-NEXT:     3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.6], class argument_constructors::D)
+// CXX11-NEXT:     4: [B1.3] (BindTemporary)
+// CXX11-NEXT:     5: [B1.4] (ImplicitCastExpr, NoOp, const class argument_constructors::D)
+// CXX11-NEXT:     6: [B1.5]
+// CXX11-NEXT:     7: [B1.6] (CXXConstructExpr, class argument_constructors::D)
+// CXX11-NEXT:     8: [B1.7] (BindTemporary)
+// CXX11-NEXT:     9: [B1.2]([B1.8])
+// CXX11-NEXT:    10: ~argument_constructors::D() (Temporary object destructor)
+// CXX11-NEXT:    11: ~argument_constructors::D() (Temporary object destructor)
+// CXX17-NEXT:     3: argument_constructors::D() (CXXConstructExpr, class argument_constructors::D)
+// CXX17-NEXT:     4: [B1.3] (BindTemporary)
+// CXX17-NEXT:     5: [B1.2]([B1.4])
+// CXX17-NEXT:     6: ~argument_constructors::D() (Temporary object destructor)
+void passArgumentWithDestructor() {
+  useD(D());
+}
+
+// CHECK: void passArgumentWithDestructorByReference()
+// CHECK:          1: useDByReference
+// CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class argumen
+// CHECK-NEXT:     3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.6], class argument_c
+// CHECK-NEXT:     4: [B1.3] (BindTemporary)
+// CHECK-NEXT:     5: [B1.4] (ImplicitCastExpr, NoOp, const class argument_constructors::D)
+// CHECK-NEXT:     6: [B1.5]
+// CHECK-NEXT:     7: [B1.2]([B1.6])
+// CHECK-NEXT:     8: ~argument_constructors::D() (Temporary object destructor)
+void passArgumentWithDestructorByReference() {
+  useDByReference(D());
+}
+} // end namespace argument_constructors