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