r324796 - [CFG] Add construction context for constructor initializers.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 9 18:18:04 PST 2018


Author: dergachev
Date: Fri Feb  9 18:18:04 2018
New Revision: 324796

URL: http://llvm.org/viewvc/llvm-project?rev=324796&view=rev
Log:
[CFG] Add construction context for constructor initializers.

CFG elements for constructors of fields and base classes that are being
initialized before the body of the whole-class constructor starts can now be
queried to discover that they're indeed participating in initialization of their
respective fields or bases before the whole-class constructor kicks in.

CFG construction contexts are now capable of representing CXXCtorInitializer
triggers, which aren't considered to be statements in the Clang AST.

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

Modified:
    cfe/trunk/include/clang/Analysis/CFG.h
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
    cfe/trunk/test/Analysis/initializers-cfg-output.cpp

Modified: cfe/trunk/include/clang/Analysis/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=324796&r1=324795&r2=324796&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/CFG.h (original)
+++ cfe/trunk/include/clang/Analysis/CFG.h Fri Feb  9 18:18:04 2018
@@ -145,19 +145,30 @@ protected:
 // necessary to express what memory is being initialized by
 // the construction.
 class ConstructionContext {
+public:
+  typedef llvm::PointerUnion<Stmt *, CXXCtorInitializer *> TriggerTy;
+
+private:
   // The construction site - the statement that triggered the construction
   // for one of its parts. For instance, stack variable declaration statement
   // triggers construction of itself or its elements if it's an array,
   // new-expression triggers construction of the newly allocated object(s).
-  Stmt *Trigger = nullptr;
+  TriggerTy Trigger;
 
 public:
   ConstructionContext() = default;
-  ConstructionContext(Stmt *Trigger) : Trigger(Trigger) {}
+  ConstructionContext(TriggerTy Trigger)
+      : Trigger(Trigger) {}
 
-  bool isNull() const { return Trigger == nullptr; }
+  bool isNull() const { return Trigger.isNull(); }
 
-  const Stmt *getTriggerStmt() const { return Trigger; }
+  const Stmt *getTriggerStmt() const {
+    return Trigger.dyn_cast<Stmt *>();
+  }
+
+  const CXXCtorInitializer *getTriggerInit() const {
+    return Trigger.dyn_cast<CXXCtorInitializer *>();
+  }
 
   const ConstructionContext *getPersistentCopy(BumpVectorContext &C) const {
     ConstructionContext *CC = C.getAllocator().Allocate<ConstructionContext>();
@@ -185,6 +196,10 @@ public:
     return getConstructionContext()->getTriggerStmt();
   }
 
+  const CXXCtorInitializer *getTriggerInit() const {
+    return getConstructionContext()->getTriggerInit();
+  }
+
 private:
   friend class CFGElement;
 

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=324796&r1=324795&r2=324796&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Fri Feb  9 18:18:04 2018
@@ -654,7 +654,8 @@ private:
   // to the trigger statement. The construction context will be unset once
   // it is consumed when the CFG building procedure processes the
   // construct-expression and adds the respective CFGConstructor element.
-  void EnterConstructionContextIfNecessary(Stmt *Trigger, Stmt *Child);
+  void EnterConstructionContextIfNecessary(
+      ConstructionContext::TriggerTy Trigger, Stmt *Child);
   // Unset the construction context after consuming it. This is done immediately
   // after adding the CFGConstructor element, so there's no need to
   // do this manually in every Visit... function.
@@ -1147,8 +1148,8 @@ static const VariableArrayType *FindVA(c
   return nullptr;
 }
 
-void CFGBuilder::EnterConstructionContextIfNecessary(Stmt *Trigger,
-                                                     Stmt *Child) {
+void CFGBuilder::EnterConstructionContextIfNecessary(
+    ConstructionContext::TriggerTy Trigger, Stmt *Child) {
   if (!BuildOpts.AddRichCXXConstructors)
     return;
   if (!Child)
@@ -1294,6 +1295,8 @@ CFGBlock *CFGBuilder::addInitializer(CXX
   appendInitializer(Block, I);
 
   if (Init) {
+    EnterConstructionContextIfNecessary(I, Init);
+
     if (HasTemporaries) {
       // For expression with temporaries go directly to subexpression to omit
       // generating destructors for the second time.
@@ -4605,6 +4608,27 @@ public:
 
 } // namespace
 
+static void print_initializer(raw_ostream &OS, StmtPrinterHelper &Helper,
+                              const CXXCtorInitializer *I) {
+  if (I->isBaseInitializer())
+    OS << I->getBaseClass()->getAsCXXRecordDecl()->getName();
+  else if (I->isDelegatingInitializer())
+    OS << I->getTypeSourceInfo()->getType()->getAsCXXRecordDecl()->getName();
+  else
+    OS << I->getAnyMember()->getName();
+  OS << "(";
+  if (Expr *IE = I->getInit())
+    IE->printPretty(OS, &Helper, PrintingPolicy(Helper.getLangOpts()));
+  OS << ")";
+
+  if (I->isBaseInitializer())
+    OS << " (Base initializer)";
+  else if (I->isDelegatingInitializer())
+    OS << " (Delegating initializer)";
+  else
+    OS << " (Member initializer)";
+}
+
 static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
                        const CFGElement &E) {
   if (Optional<CFGStmt> CS = E.getAs<CFGStmt>()) {
@@ -4643,6 +4667,8 @@ static void print_elem(raw_ostream &OS,
       if (Optional<CFGConstructor> CE = E.getAs<CFGConstructor>()) {
         if (const Stmt *S = CE->getTriggerStmt())
           Helper.handledStmt((const_cast<Stmt *>(S)), OS);
+        else if (const CXXCtorInitializer *I = CE->getTriggerInit())
+          print_initializer(OS, Helper, I);
         else
           llvm_unreachable("Unexpected trigger kind!");
         OS << ", ";
@@ -4659,23 +4685,8 @@ static void print_elem(raw_ostream &OS,
     if (isa<Expr>(S))
       OS << '\n';
   } else if (Optional<CFGInitializer> IE = E.getAs<CFGInitializer>()) {
-    const CXXCtorInitializer *I = IE->getInitializer();
-    if (I->isBaseInitializer())
-      OS << I->getBaseClass()->getAsCXXRecordDecl()->getName();
-    else if (I->isDelegatingInitializer())
-      OS << I->getTypeSourceInfo()->getType()->getAsCXXRecordDecl()->getName();
-    else OS << I->getAnyMember()->getName();
-
-    OS << "(";
-    if (Expr *IE = I->getInit())
-      IE->printPretty(OS, &Helper, PrintingPolicy(Helper.getLangOpts()));
-    OS << ")";
-
-    if (I->isBaseInitializer())
-      OS << " (Base initializer)\n";
-    else if (I->isDelegatingInitializer())
-      OS << " (Delegating initializer)\n";
-    else OS << " (Member initializer)\n";
+    print_initializer(OS, Helper, IE->getInitializer());
+    OS << '\n';
   } else if (Optional<CFGAutomaticObjDtor> DE =
                  E.getAs<CFGAutomaticObjDtor>()) {
     const VarDecl *VD = DE->getVarDecl();

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=324796&r1=324795&r2=324796&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original)
+++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Fri Feb  9 18:18:04 2018
@@ -126,3 +126,28 @@ void referenceVariableWithInitializer()
 }
 
 } // end namespace decl_stmt
+
+namespace ctor_initializers {
+
+class D: public C {
+  C c1;
+
+public:
+
+// CHECK: D()
+// CHECK:          1:  (CXXConstructExpr, C() (Base initializer), class C)
+// CHECK-NEXT:     2: C([B1.1]) (Base initializer)
+// CHECK-NEXT:     3: CFGNewAllocator(C *)
+// CHECK-NEXT:     4:  (CXXConstructExpr, [B1.5], class C)
+// CHECK-NEXT:     5: new C([B1.4])
+// CHECK-NEXT:     6: [B1.5] (CXXConstructExpr, c1([B1.5]) (Member initializer), class C)
+// CHECK-NEXT:     7: c1([B1.6]) (Member initializer)
+  D(): C(), c1(new C()) {}
+
+// CHECK: D(int)
+// CHECK:          1:  (CXXConstructExpr, D() (Delegating initializer), class ctor_initializers::D)
+// CHECK-NEXT:     2: D([B1.1]) (Delegating initializer)
+  D(int): D() {}
+};
+
+} // end namespace ctor_initializers

Modified: cfe/trunk/test/Analysis/initializers-cfg-output.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/initializers-cfg-output.cpp?rev=324796&r1=324795&r2=324796&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/initializers-cfg-output.cpp (original)
+++ cfe/trunk/test/Analysis/initializers-cfg-output.cpp Fri Feb  9 18:18:04 2018
@@ -63,13 +63,17 @@ class TestDelegating {
 // CHECK:  [B2 (ENTRY)]
 // CHECK:    Succs (1): B1
 // CHECK:  [B1]
-// CHECK:    1:  (CXXConstructExpr, class A)
+// WARNINGS:    1:  (CXXConstructExpr, class A)
+// ANALYZER:    1:  (CXXConstructExpr, A() (Base initializer), class A)
 // CHECK:    2: A([B1.1]) (Base initializer)
-// CHECK:    3:  (CXXConstructExpr, class C)
+// WARNINGS:    3:  (CXXConstructExpr, class C)
+// ANALYZER:    3:  (CXXConstructExpr, C() (Base initializer), class C)
 // CHECK:    4: C([B1.3]) (Base initializer)
-// CHECK:    5:  (CXXConstructExpr, class B)
+// WARNINGS:    5:  (CXXConstructExpr, class B)
+// ANALYZER:    5:  (CXXConstructExpr, B() (Base initializer), class B)
 // CHECK:    6: B([B1.5]) (Base initializer)
-// CHECK:    7:  (CXXConstructExpr, class A)
+// WARNINGS:    7:  (CXXConstructExpr, class A)
+// ANALYZER:    7:  (CXXConstructExpr, A() (Base initializer), class A)
 // CHECK:    8: A([B1.7]) (Base initializer)
 // CHECK:    9: /*implicit*/(int)0
 // CHECK:   10: i([B1.9]) (Member initializer)
@@ -118,7 +122,8 @@ class TestDelegating {
 // CHECK:  [B1]
 // CHECK:    1: 2
 // CHECK:    2: 3
-// CHECK:    3: [B1.1], [B1.2] (CXXConstructExpr, class TestDelegating)
+// WARNINGS:    3: [B1.1], [B1.2] (CXXConstructExpr, class TestDelegating)
+// ANALYZER:    3: [B1.1], [B1.2] (CXXConstructExpr, TestDelegating([B1.1], [B1.2]) (Delegating initializer), class TestDelegating)
 // CHECK:    4: TestDelegating([B1.3]) (Delegating initializer)
 // CHECK:    Preds (1): B2
 // CHECK:    Succs (1): B0




More information about the cfe-commits mailing list