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