r338436 - [CFG] [analyzer] Implement function argument construction contexts.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 31 13:45:53 PDT 2018


Author: dergachev
Date: Tue Jul 31 13:45:53 2018
New Revision: 338436

URL: http://llvm.org/viewvc/llvm-project?rev=338436&view=rev
Log:
[CFG] [analyzer] Implement function argument construction contexts.

In r330377 and r338425 we have already identified what constitutes function
argument constructors and added stubs in order to prevent confusing them
with other temporary object constructors.

Now we implement a ConstructionContext sub-class to carry all the necessary
information about the construction site, namely call expression and argument
index.

On the analyzer side, the patch interacts with the recently implemented
pre-C++17 copy elision support in an interesting manner. If on the CFG side we
didn't find a construction context for the elidable constructor, we build
the CFG as if the elidable constructor is not elided, and the non-elided
constructor within it is a simple temporary. But the same problem may occur
in the analyzer: if the elidable constructor has a construction context but
the analyzer doesn't implement such context yet, the analyzer should also
try to skip copy elision and still inline the non-elided temporary constructor.
This was implemented by adding a "roll back" mechanism: when elision fails,
roll back the changes and proceed as if it's a simple temporary. The approach
is wonky, but i'm fine with that as long as it's merely a defensive mechanism
that should eventually go away once all construction contexts become supported.

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

Modified:
    cfe/trunk/include/clang/Analysis/CFG.h
    cfe/trunk/include/clang/Analysis/ConstructionContext.h
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/lib/Analysis/ConstructionContext.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
    cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
    cfe/trunk/test/Analysis/cfg-rich-constructors.mm

Modified: cfe/trunk/include/clang/Analysis/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=338436&r1=338435&r2=338436&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/CFG.h (original)
+++ cfe/trunk/include/clang/Analysis/CFG.h Tue Jul 31 13:45:53 2018
@@ -196,7 +196,8 @@ public:
                  // These are possible in C++17 due to mandatory copy elision.
                  isa<ReturnedValueConstructionContext>(C) ||
                  isa<VariableConstructionContext>(C) ||
-                 isa<ConstructorInitializerConstructionContext>(C)));
+                 isa<ConstructorInitializerConstructionContext>(C) ||
+                 isa<ArgumentConstructionContext>(C)));
     Data2.setPointer(const_cast<ConstructionContext *>(C));
   }
 

Modified: cfe/trunk/include/clang/Analysis/ConstructionContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ConstructionContext.h?rev=338436&r1=338435&r2=338436&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/ConstructionContext.h (original)
+++ cfe/trunk/include/clang/Analysis/ConstructionContext.h Tue Jul 31 13:45:53 2018
@@ -41,6 +41,12 @@ private:
   /// new-expression triggers construction of the newly allocated object(s).
   TriggerTy Trigger;
 
+  /// If a single trigger statement triggers multiple constructors, they are
+  /// usually being enumerated. This covers function argument constructors
+  /// triggered by a call-expression and items in an initializer list triggered
+  /// by an init-list-expression.
+  unsigned Index;
+
   /// Sometimes a single trigger is not enough to describe the construction
   /// site. In this case we'd have a chain of "partial" construction context
   /// layers.
@@ -55,13 +61,13 @@ private:
   /// Not all of these are currently supported.
   const ConstructionContextLayer *Parent = nullptr;
 
-  ConstructionContextLayer(TriggerTy Trigger,
-                          const ConstructionContextLayer *Parent)
-      : Trigger(Trigger), Parent(Parent) {}
+  ConstructionContextLayer(TriggerTy Trigger, unsigned Index,
+                           const ConstructionContextLayer *Parent)
+      : Trigger(Trigger), Index(Index), Parent(Parent) {}
 
 public:
   static const ConstructionContextLayer *
-  create(BumpVectorContext &C, TriggerTy Trigger,
+  create(BumpVectorContext &C, TriggerTy Trigger, unsigned Index = 0,
          const ConstructionContextLayer *Parent = nullptr);
 
   const ConstructionContextLayer *getParent() const { return Parent; }
@@ -75,11 +81,13 @@ public:
     return Trigger.dyn_cast<CXXCtorInitializer *>();
   }
 
+  unsigned getIndex() const { return Index; }
+
   /// Returns true if these layers are equal as individual layers, even if
   /// their parents are different.
   bool isSameLayer(const ConstructionContextLayer *Other) const {
     assert(Other);
-    return (Trigger == Other->Trigger);
+    return (Trigger == Other->Trigger && Index == Other->Index);
   }
 
   /// See if Other is a proper initial segment of this construction context
@@ -114,7 +122,8 @@ public:
     SimpleReturnedValueKind,
     CXX17ElidedCopyReturnedValueKind,
     RETURNED_VALUE_BEGIN = SimpleReturnedValueKind,
-    RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind
+    RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind,
+    ArgumentKind
   };
 
 protected:
@@ -469,6 +478,32 @@ public:
   }
 };
 
+class ArgumentConstructionContext : public ConstructionContext {
+  const Expr *CE; // The call of which the context is an argument.
+  unsigned Index; // Which argument we're constructing.
+  const CXXBindTemporaryExpr *BTE; // Whether the object needs to be destroyed.
+
+  friend class ConstructionContext; // Allows to create<>() itself.
+
+  explicit ArgumentConstructionContext(const Expr *CE, unsigned Index,
+                                       const CXXBindTemporaryExpr *BTE)
+      : ConstructionContext(ArgumentKind), CE(CE),
+        Index(Index), BTE(BTE) {
+    assert(isa<CallExpr>(CE) || isa<CXXConstructExpr>(CE) ||
+           isa<ObjCMessageExpr>(CE));
+    // BTE is optional.
+  }
+
+public:
+  const Expr *getCallLikeExpr() const { return CE; }
+  unsigned getIndex() const { return Index; }
+  const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
+
+  static bool classof(const ConstructionContext *CC) {
+    return CC->getKind() == ArgumentKind;
+  }
+};
+
 } // end namespace clang
 
 #endif // LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=338436&r1=338435&r2=338436&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Tue Jul 31 13:45:53 2018
@@ -693,16 +693,13 @@ private:
                 std::is_same<CallLikeExpr, CXXConstructExpr>::value ||
                 std::is_same<CallLikeExpr, ObjCMessageExpr>::value>>
   void findConstructionContextsForArguments(CallLikeExpr *E) {
-    // A stub for the code that'll eventually be used for finding construction
-    // contexts for constructors of C++ object-type arguments passed into
-    // call-like expression E.
-    // FIXME: Once actually implemented, this construction context layer should
-    // include the index of the argument as well.
-    for (auto Arg : E->arguments())
+    for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
+      Expr *Arg = E->getArg(i);
       if (Arg->getType()->getAsCXXRecordDecl() && !Arg->isGLValue())
         findConstructionContexts(
-            ConstructionContextLayer::create(cfg->getBumpVectorContext(), E),
+            ConstructionContextLayer::create(cfg->getBumpVectorContext(), E, i),
             Arg);
+    }
   }
 
   // Unset the construction context after consuming it. This is done immediately
@@ -1289,9 +1286,9 @@ void CFGBuilder::findConstructionContext
   if (!Child)
     return;
 
-  auto withExtraLayer = [this, Layer](Stmt *S) {
+  auto withExtraLayer = [this, Layer](Stmt *S, unsigned Index = 0) {
     return ConstructionContextLayer::create(cfg->getBumpVectorContext(), S,
-                                            Layer);
+                                            Index, Layer);
   };
 
   switch(Child->getStmtClass()) {
@@ -5012,7 +5009,7 @@ static void print_construction_context(r
     OS << ", ";
     const auto *SICC = cast<SimpleConstructorInitializerConstructionContext>(CC);
     print_initializer(OS, Helper, SICC->getCXXCtorInitializer());
-    break;
+    return;
   }
   case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind: {
     OS << ", ";
@@ -5063,6 +5060,17 @@ static void print_construction_context(r
     Stmts.push_back(TOCC->getConstructorAfterElision());
     break;
   }
+  case ConstructionContext::ArgumentKind: {
+    const auto *ACC = cast<ArgumentConstructionContext>(CC);
+    if (const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {
+      OS << ", ";
+      Helper.handledStmt(const_cast<Stmt *>(BTE), OS);
+    }
+    OS << ", ";
+    Helper.handledStmt(const_cast<Expr *>(ACC->getCallLikeExpr()), OS);
+    OS << "+" << ACC->getIndex();
+    return;
+  }
   }
   for (auto I: Stmts)
     if (I) {

Modified: cfe/trunk/lib/Analysis/ConstructionContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ConstructionContext.cpp?rev=338436&r1=338435&r2=338436&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ConstructionContext.cpp (original)
+++ cfe/trunk/lib/Analysis/ConstructionContext.cpp Tue Jul 31 13:45:53 2018
@@ -21,10 +21,11 @@ using namespace clang;
 
 const ConstructionContextLayer *
 ConstructionContextLayer::create(BumpVectorContext &C, TriggerTy Trigger,
+                                 unsigned Index,
                                  const ConstructionContextLayer *Parent) {
   ConstructionContextLayer *CC =
       C.getAllocator().Allocate<ConstructionContextLayer>();
-  return new (CC) ConstructionContextLayer(Trigger, Parent);
+  return new (CC) ConstructionContextLayer(Trigger, Index, Parent);
 }
 
 bool ConstructionContextLayer::isStrictlyMoreSpecificThan(
@@ -111,11 +112,14 @@ const ConstructionContext *ConstructionC
         }
         assert(ParentLayer->isLast());
 
-        // This is a constructor into a function argument. Not implemented yet.
+        // This is a constructor into a function argument.
         if (isa<CallExpr>(ParentLayer->getTriggerStmt()) ||
             isa<CXXConstructExpr>(ParentLayer->getTriggerStmt()) ||
-            isa<ObjCMessageExpr>(ParentLayer->getTriggerStmt()))
-          return nullptr;
+            isa<ObjCMessageExpr>(ParentLayer->getTriggerStmt())) {
+          return create<ArgumentConstructionContext>(
+              C, cast<Expr>(ParentLayer->getTriggerStmt()),
+              ParentLayer->getIndex(), BTE);
+        }
         // This is C++17 copy-elided construction into return statement.
         if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) {
           assert(!RS->getRetValue()->getType().getCanonicalType()
@@ -175,11 +179,15 @@ const ConstructionContext *ConstructionC
       assert(TopLayer->isLast());
       return create<SimpleReturnedValueConstructionContext>(C, RS);
     }
-    // This is a constructor into a function argument. Not implemented yet.
+    // This is a constructor into a function argument.
     if (isa<CallExpr>(TopLayer->getTriggerStmt()) ||
         isa<CXXConstructExpr>(TopLayer->getTriggerStmt()) ||
-        isa<ObjCMessageExpr>(TopLayer->getTriggerStmt()))
-      return nullptr;
+        isa<ObjCMessageExpr>(TopLayer->getTriggerStmt())) {
+      assert(TopLayer->isLast());
+      return create<ArgumentConstructionContext>(
+          C, cast<Expr>(TopLayer->getTriggerStmt()), TopLayer->getIndex(),
+          /*BTE=*/nullptr);
+    }
     llvm_unreachable("Unexpected construction context with statement!");
   } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {
     assert(TopLayer->isLast());

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=338436&r1=338435&r2=338436&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Tue Jul 31 13:45:53 2018
@@ -221,25 +221,42 @@ std::pair<ProgramStateRef, SVal> ExprEng
       // and construct directly into the final object. This call
       // also sets the CallOpts flags for us.
       SVal V;
+      // If the elided copy/move constructor is not supported, there's still
+      // benefit in trying to model the non-elided constructor.
+      // Stash our state before trying to elide, as it'll get overwritten.
+      ProgramStateRef PreElideState = State;
+      EvalCallOptions PreElideCallOpts = CallOpts;
+
       std::tie(State, V) = prepareForObjectConstruction(
           CE, State, LCtx, TCC->getConstructionContextAfterElision(), CallOpts);
 
-      // Remember that we've elided the constructor.
-      State = addObjectUnderConstruction(State, CE, LCtx, V);
-
-      // Remember that we've elided the destructor.
-      if (BTE)
-        State = elideDestructor(State, BTE, LCtx);
-
-      // Instead of materialization, shamelessly return
-      // the final object destination.
-      if (MTE)
-        State = addObjectUnderConstruction(State, MTE, LCtx, V);
-
-      return std::make_pair(State, V);
+      // FIXME: This definition of "copy elision has not failed" is unreliable.
+      // It doesn't indicate that the constructor will actually be inlined
+      // later; it is still up to evalCall() to decide.
+      if (!CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion) {
+        // Remember that we've elided the constructor.
+        State = addObjectUnderConstruction(State, CE, LCtx, V);
+
+        // Remember that we've elided the destructor.
+        if (BTE)
+          State = elideDestructor(State, BTE, LCtx);
+
+        // Instead of materialization, shamelessly return
+        // the final object destination.
+        if (MTE)
+          State = addObjectUnderConstruction(State, MTE, LCtx, V);
+
+        return std::make_pair(State, V);
+      } else {
+        // Copy elision failed. Revert the changes and proceed as if we have
+        // a simple temporary.
+        State = PreElideState;
+        CallOpts = PreElideCallOpts;
+      }
+      // FALL-THROUGH
     }
     case ConstructionContext::SimpleTemporaryObjectKind: {
-      const auto *TCC = cast<SimpleTemporaryObjectConstructionContext>(CC);
+      const auto *TCC = cast<TemporaryObjectConstructionContext>(CC);
       const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr();
       const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr();
       SVal V = UnknownVal();
@@ -274,6 +291,10 @@ std::pair<ProgramStateRef, SVal> ExprEng
       CallOpts.IsTemporaryCtorOrDtor = true;
       return std::make_pair(State, V);
     }
+    case ConstructionContext::ArgumentKind: {
+      // Function argument constructors. Not implemented yet.
+      break;
+    }
     }
   }
   // If we couldn't find an existing region to construct into, assume we're

Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=338436&r1=338435&r2=338436&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original)
+++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Tue Jul 31 13:45:53 2018
@@ -826,21 +826,49 @@ void useC(C c);
 void useCByReference(const C &c);
 void useD(D d);
 void useDByReference(const D &d);
+void useCAndD(C c, 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-ELIDE-NEXT:     3: C() (CXXConstructExpr, [B1.4], [B1.5], class C)
+// CXX11-NOELIDE-NEXT:     3: C() (CXXConstructExpr, [B1.4], class C)
 // CXX11-NEXT:     4: [B1.3]
-// CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, class C)
+// CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.6]+0, class C)
 // CXX11-NEXT:     6: [B1.2]([B1.5])
-// CXX17-NEXT:     3: C() (CXXConstructExpr, class C)
+// CXX17-NEXT:     3: C() (CXXConstructExpr, [B1.4]+0, class C)
 // CXX17-NEXT:     4: [B1.2]([B1.3])
 void passArgument() {
   useC(C());
 }
 
+// CHECK: void passTwoArguments()
+// CHECK:        [B1]
+// CHECK-NEXT:     1: useCAndD
+// CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(class C, class argument_constructors::D))
+// CXX11-ELIDE-NEXT:     3: C() (CXXConstructExpr, [B1.4], [B1.5], class C)
+// CXX11-NOELIDE-NEXT:     3: C() (CXXConstructExpr, [B1.4], class C)
+// CXX11-NEXT:     4: [B1.3]
+// CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.12]+0, class C)
+// CXX11-ELIDE-NEXT:     6: argument_constructors::D() (CXXConstructExpr, [B1.7], [B1.9], [B1.10], class argument_constructors::D)
+// CXX11-NOELIDE-NEXT:     6: argument_constructors::D() (CXXConstructExpr, [B1.7], [B1.9], class argument_constructors::D)
+// CXX11-NEXT:     7: [B1.6] (BindTemporary)
+// CXX11-NEXT:     8: [B1.7] (ImplicitCastExpr, NoOp, const class argument_constructors::D)
+// CXX11-NEXT:     9: [B1.8]
+// CXX11-NEXT:    10: [B1.9] (CXXConstructExpr, [B1.11], [B1.12]+1, class argument_constructors::D)
+// CXX11-NEXT:    11: [B1.10] (BindTemporary)
+// CXX11-NEXT:    12: [B1.2]([B1.5], [B1.11])
+// CXX11-NEXT:    13: ~argument_constructors::D() (Temporary object destructor)
+// CXX11-NEXT:    14: ~argument_constructors::D() (Temporary object destructor)
+// CXX17-NEXT:     3: C() (CXXConstructExpr, [B1.6]+0, class C)
+// CXX17-NEXT:     4: argument_constructors::D() (CXXConstructExpr, [B1.5], [B1.6]+1, class argument_co
+// CXX17-NEXT:     5: [B1.4] (BindTemporary)
+// CXX17-NEXT:     6: [B1.2]([B1.3], [B1.5])
+// CXX17-NEXT:     7: ~argument_constructors::D() (Temporary object destructor)
+void passTwoArguments() {
+  useCAndD(C(), D());
+}
+
 // CHECK: void passArgumentByReference()
 // CHECK:          1: useCByReference
 // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class C &))
@@ -852,20 +880,20 @@ 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-ELIDE-NEXT:     3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.6], [B1.7], class argument_constructors::D)
+// CXX11-NOELIDE-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:     7: [B1.6] (CXXConstructExpr, [B1.8], [B1.9]+0, 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:     3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.5]+0, 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)
@@ -886,13 +914,13 @@ void passArgumentWithDestructorByReferen
   useDByReference(D());
 }
 
-// FIXME: Find construction context for the argument.
 // CHECK: void passArgumentIntoAnotherConstructor()
-// CXX11:          1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], class argument_constructors::D)
+// CXX11-ELIDE:          1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class argument_constructors::D)
+// CXX11-NOELIDE:          1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.4], class argument_constructors::D)
 // CXX11-NEXT:     2: [B1.1] (BindTemporary)
 // CXX11-NEXT:     3: [B1.2] (ImplicitCastExpr, NoOp, const class argument_constructors::D)
 // CXX11-NEXT:     4: [B1.3]
-// CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, class argument_constructors::D)
+// CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.6], [B1.7]+0, class argument_constructors::D)
 // CXX11-NEXT:     6: [B1.5] (BindTemporary)
 // CXX11-ELIDE-NEXT:     7: [B1.6] (CXXConstructExpr, [B1.9], [B1.10], class argument_constructors::E)
 // CXX11-NOELIDE-NEXT:     7: [B1.6] (CXXConstructExpr, [B1.9], class argument_constructors::E)
@@ -902,7 +930,7 @@ void passArgumentWithDestructorByReferen
 // CXX11-NEXT:    11: argument_constructors::E e = argument_constructors::E(argument_constructors::D());
 // CXX11-NEXT:    12: ~argument_constructors::D() (Temporary object destructor)
 // CXX11-NEXT:    13: ~argument_constructors::D() (Temporary object destructor)
-// CXX17:          1: argument_constructors::D() (CXXConstructExpr, class argument_constructors::D)
+// CXX17:          1: argument_constructors::D() (CXXConstructExpr, [B1.2], [B1.3]+0, class argument_constructors::D)
 // CXX17-NEXT:     2: [B1.1] (BindTemporary)
 // CXX17-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.5], class argument_constructors::E)
 // CXX17-NEXT:     4: argument_constructors::E([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class argument_constructors::E)

Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.mm?rev=338436&r1=338435&r2=338436&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cfg-rich-constructors.mm (original)
+++ cfe/trunk/test/Analysis/cfg-rich-constructors.mm Tue Jul 31 13:45:53 2018
@@ -18,21 +18,21 @@ public:
 -(D) bar;
 @end
 
-// FIXME: Find construction context for the argument.
 // CHECK: void passArgumentIntoMessage(E *e)
 // CHECK:          1: e
 // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, LValueToRValue, E *)
-// CXX11-NEXT:     3: D() (CXXConstructExpr, [B1.4], [B1.6], class D)
+// CXX11-ELIDE-NEXT:     3: D() (CXXConstructExpr, [B1.4], [B1.6], [B1.7], class D)
+// CXX11-NOELIDE-NEXT:     3: D() (CXXConstructExpr, [B1.4], [B1.6], class D)
 // CXX11-NEXT:     4: [B1.3] (BindTemporary)
 // CXX11-NEXT:     5: [B1.4] (ImplicitCastExpr, NoOp, const class D)
 // CXX11-NEXT:     6: [B1.5]
-// CXX11-NEXT:     7: [B1.6] (CXXConstructExpr, class D)
+// CXX11-NEXT:     7: [B1.6] (CXXConstructExpr, [B1.8], [B1.9]+0, class D)
 // CXX11-NEXT:     8: [B1.7] (BindTemporary)
 // Double brackets trigger FileCheck variables, escape.
 // CXX11-NEXT:     9: {{\[}}[B1.2] foo:[B1.8]]
 // CXX11-NEXT:    10: ~D() (Temporary object destructor)
 // CXX11-NEXT:    11: ~D() (Temporary object destructor)
-// CXX17-NEXT:     3: D() (CXXConstructExpr, class D)
+// CXX17-NEXT:     3: D() (CXXConstructExpr, [B1.4], [B1.5]+0, class D)
 // CXX17-NEXT:     4: [B1.3] (BindTemporary)
 // Double brackets trigger FileCheck variables, escape.
 // CXX17-NEXT:     5: {{\[}}[B1.2] foo:[B1.4]]




More information about the cfe-commits mailing list