mirror of https://github.com/microsoft/clang.git
[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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@324796 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
20012b6592
commit
a5f94fbb04
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(const Type *t) {
|
|||
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(CXXCtorInitializer *I) {
|
|||
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, StmtPrinterHelper &Helper,
|
|||
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, StmtPrinterHelper &Helper,
|
|||
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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue