NoQ created this revision.
NoQ added reviewers: rsmith, dcoughlin, xazax.hun, a.sidorin, george.karpenkov, 
szepet.
Herald added subscribers: cfe-commits, rnkovacs.

As an improvement over https://reviews.llvm.org/D42699 and 
https://reviews.llvm.org/D42700, this unwraps `ExprWithCleanups` surrounding 
immediate constructors of variables which take temporaries as constructor 
arguments (such as `iterator i = begin()` - a copy constructor accepts a 
temporary here).

With this change, we're fully ready to make use of construction contexts in the 
analyzer (in the next patch). Once we do, the plan is to be adding more and 
more construction contexts for the new cases that were not previously supported 
by the analyzer.

Minor refactoring involved.


Repository:
  rC Clang

https://reviews.llvm.org/D42719

Files:
  include/clang/Analysis/CFG.h
  lib/Analysis/CFG.cpp
  test/Analysis/temp-obj-dtors-cfg-output.cpp

Index: test/Analysis/temp-obj-dtors-cfg-output.cpp
===================================================================
--- test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -492,7 +492,7 @@
 // CHECK:     1: [B10.5] ? [B8.6] : [B9.15]
 // CHECK:     2: [B7.1] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     3: [B7.2]
-// CHECK:     4: [B7.3] (CXXConstructExpr, class A)
+// CHECK:     4: [B7.3] (CXXConstructExpr, [B7.5], class A)
 // CHECK:     5: A a = B() ? A() : A(B());
 // CHECK:     T: (Temp Dtor) [B9.2]
 // CHECK:     Preds (2): B8 B9
@@ -625,7 +625,7 @@
 // CHECK:     2: [B4.1] (BindTemporary)
 // CHECK:     3: [B4.2] (ImplicitCastExpr, NoOp, const struct C)
 // CHECK:     4: [B4.3]
-// CHECK:     5: [B4.4] (CXXConstructExpr, struct C)
+// CHECK:     5: [B4.4] (CXXConstructExpr, [B4.6], struct C)
 // CHECK:     6: C c = C();
 // CHECK:     7: ~C() (Temporary object destructor)
 // CHECK:     8: c
@@ -675,15 +675,15 @@
 // CHECK:     1: D() (CXXConstructExpr, struct D)
 // CXX98:     2: [B3.1] (ImplicitCastExpr, NoOp, const struct D)
 // CXX98:     3: [B3.2]
-// CXX98:     4: [B3.3] (CXXConstructExpr, struct D)
+// CXX98:     4: [B3.3] (CXXConstructExpr, [B3.5], struct D)
 // CXX98:     5: D d = D();
 // CXX98:     6: d
 // CXX98:     7: [B3.6].operator bool
 // CXX98:     8: [B3.6]
 // CXX98:     9: [B3.8] (ImplicitCastExpr, UserDefinedConversion, _Bool)
 // CXX98:     T: if [B3.9]
 // CXX11:     2: [B3.1]
-// CXX11:     3: [B3.2] (CXXConstructExpr, struct D)
+// CXX11:     3: [B3.2] (CXXConstructExpr, [B3.4], struct D)
 // CXX11:     4: D d = D();
 // CXX11:     5: d
 // CXX11:     6: [B3.5].operator bool
@@ -838,7 +838,7 @@
 // CXX11:     1: [B7.3] ?: [B6.6]
 // CHECK:     2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     3: [B4.2]
-// CHECK:     4: [B4.3] (CXXConstructExpr, class A)
+// CHECK:     4: [B4.3] (CXXConstructExpr, [B4.5], class A)
 // CHECK:     5: A a = A() ?: A();
 // CHECK:     T: (Temp Dtor) [B6.2]
 // CHECK:     Preds (2): B5 B6
@@ -993,7 +993,7 @@
 // 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)
+// CHECK:     5: [B1.4] (CXXConstructExpr, [B1.6], class A)
 // CHECK:     6: A a = A();
 // CHECK:     7: ~A() (Temporary object destructor)
 // CHECK:     8: int b;
@@ -1033,7 +1033,7 @@
 // CHECK:     4: [B1.3] (BindTemporary)
 // CHECK:     5: [B1.4] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     6: [B1.5]
-// CHECK:     7: [B1.6] (CXXConstructExpr, class A)
+// CHECK:     7: [B1.6] (CXXConstructExpr, [B1.8], class A)
 // CHECK:     8: A a = A::make();
 // CHECK:     9: ~A() (Temporary object destructor)
 // CHECK:    10: int b;
Index: lib/Analysis/CFG.cpp
===================================================================
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -645,6 +645,11 @@
     return Block;
   }
 
+  // Scan the child statement to find various constructors that might have been
+  // triggered by the given trigger.
+  void VisitForConstructionContext(ConstructionContext::TriggerTy Trigger,
+                                   Stmt *Child);
+
   void autoCreateBlock() { if (!Block) Block = createBlock(); }
   CFGBlock *createBlock(bool add_successor = true);
   CFGBlock *createNoReturnBlock();
@@ -1129,6 +1134,16 @@
   return nullptr;
 }
 
+void CFGBuilder::VisitForConstructionContext(
+    ConstructionContext::TriggerTy Trigger, Stmt *Child) {
+  if (!Child)
+    return;
+  if (auto *Constructor = dyn_cast<CXXConstructExpr>(Child))
+    CurrentConstructionContext = ConstructionContext(Constructor, Trigger);
+  if (auto *Cleanups = dyn_cast<ExprWithCleanups>(Child))
+    VisitForConstructionContext(Trigger, Cleanups->getSubExpr());
+}
+
 /// BuildCFG - Constructs a CFG from an AST (a Stmt*).  The AST can represent an
 ///  arbitrary statement.  Examples include a single expression or a function
 ///  body (compound statement).  The ownership of the returned CFG is
@@ -1256,8 +1271,7 @@
   appendInitializer(Block, I);
 
   if (Init) {
-    if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init))
-      CurrentConstructionContext = {/*Constructor=*/CE, /*Trigger=*/I};
+    VisitForConstructionContext(I, Init);
 
     if (HasTemporaries) {
       // For expression with temporaries go directly to subexpression to omit
@@ -2343,8 +2357,7 @@
   autoCreateBlock();
   appendStmt(Block, DS);
 
-  if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(Init))
-    CurrentConstructionContext = {/*Constructor=*/CE, /*Trigger=*/DS};
+  VisitForConstructionContext(DS, Init);
 
   // Keep track of the last non-null block, as 'Block' can be nulled out
   // if the initializer expression is something like a 'while' in a
@@ -3901,8 +3914,7 @@
   autoCreateBlock();
   appendStmt(Block, NE);
 
-  if (auto *CE = const_cast<CXXConstructExpr *>(NE->getConstructExpr()))
-    CurrentConstructionContext = {/*Constructor=*/CE, /*Trigger=*/NE};
+  VisitForConstructionContext(NE, NE->getInitializer());
 
   if (NE->getInitializer())
     Block = Visit(NE->getInitializer());
Index: include/clang/Analysis/CFG.h
===================================================================
--- include/clang/Analysis/CFG.h
+++ include/clang/Analysis/CFG.h
@@ -139,16 +139,10 @@
 // necessary to express what memory is being initialized by
 // the construction.
 class ConstructionContext {
-  CXXConstructExpr *Constructor;
-  llvm::PointerUnion<Stmt *, CXXCtorInitializer *> Trigger;
-
 public:
-  ConstructionContext(CXXConstructExpr *Constructor,
-                      Stmt *Trigger)
-      : Constructor(Constructor), Trigger(Trigger) {}
+  typedef llvm::PointerUnion<Stmt *, CXXCtorInitializer *> TriggerTy;
 
-  ConstructionContext(CXXConstructExpr *Constructor,
-                      CXXCtorInitializer *Trigger)
+  ConstructionContext(CXXConstructExpr *Constructor, TriggerTy Trigger)
       : Constructor(Constructor), Trigger(Trigger) {}
 
   const ConstructionContext *getPersistentCopy(BumpVectorContext &C) const {
@@ -166,6 +160,10 @@
   const CXXCtorInitializer *getTriggerInit() const {
     return Trigger.dyn_cast<CXXCtorInitializer *>();
   }
+
+private:
+  CXXConstructExpr *Constructor;
+  TriggerTy Trigger;
 };
 
 /// CFGConstructor - Represents C++ constructor call. Maintains information
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to