NoQ created this revision. NoQ added reviewers: dcoughlin, xazax.hun, a.sidorin, george.karpenkov, szepet. Herald added subscribers: cfe-commits, rnkovacs.
Function argument constructors (that are used for passing objects into functions by value) are completely unlike temporary object constructors, but we were treating them as such because they are also wrapped into a `CXXBindTemporaryExpr`. This patch adds a partial construction context layer for call argument values, but doesn't proceed to transform it into an actual construction context yet. This is tells the clients that we aren't supporting these constructors yet. A lesson to learn here is that construction contexts aren't as safe as i originally expected - even though they work by pattern-matching small specific AST patterns. Repository: rC Clang https://reviews.llvm.org/D45650 Files: lib/Analysis/CFG.cpp lib/Analysis/ConstructionContext.cpp test/Analysis/cfg-rich-constructors.cpp
Index: test/Analysis/cfg-rich-constructors.cpp =================================================================== --- test/Analysis/cfg-rich-constructors.cpp +++ test/Analysis/cfg-rich-constructors.cpp @@ -693,3 +693,49 @@ } } // end namespace implicit_constructor_conversion + +namespace argument_constructors { +class D { +public: + D(); + ~D(); +}; + +void useC(C c); +void useD(D d); + +// FIXME: Find construction context for the argument. +// CHECK: void passArgument() +// CHECK: 1: useC +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(class C)) +// CXX11-NEXT: 3: C() (CXXConstructExpr, [B1.4], class C) +// CXX11-NEXT: 4: [B1.3] +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, class C) +// CXX11-NEXT: 6: [B1.2]([B1.5]) +// CXX17-NEXT: 3: C() (CXXConstructExpr, class C) +// CXX17-NEXT: 4: [B1.2]([B1.3]) +void passArgument() { + useC(C()); +} + +// FIXME: Find construction context for the argument. +// CHECK: void passArgumentWithDestructor() +// CHECK: 1: useD +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(class argument_constructors::D)) +// CXX11-NEXT: 3: argument_constructors::D() (CXXConstructExpr, [B1.4], [B1.6], class argument_constructors::D) +// CXX11-NEXT: 4: [B1.3] (BindTemporary) +// CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class argument_constructors::D) +// CXX11-NEXT: 6: [B1.5] +// CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, class argument_constructors::D) +// CXX11-NEXT: 8: [B1.7] (BindTemporary) +// CXX11-NEXT: 9: [B1.2]([B1.8]) +// CXX11-NEXT: 10: ~argument_constructors::D() (Temporary object destructor) +// CXX11-NEXT: 11: ~argument_constructors::D() (Temporary object destructor) +// CXX17-NEXT: 3: argument_constructors::D() (CXXConstructExpr, class argument_constructors::D) +// CXX17-NEXT: 4: [B1.3] (BindTemporary) +// CXX17-NEXT: 5: [B1.2]([B1.4]) +// CXX17-NEXT: 6: ~argument_constructors::D() (Temporary object destructor) +void passArgumentWithDestructor() { + useD(D()); +} +} // end namespace argument_constructors Index: lib/Analysis/ConstructionContext.cpp =================================================================== --- lib/Analysis/ConstructionContext.cpp +++ lib/Analysis/ConstructionContext.cpp @@ -79,6 +79,9 @@ ParentLayer->getTriggerStmt()))) { return create<TemporaryObjectConstructionContext>(C, BTE, MTE); } + // This is a constructor into a function argument. Not implemented yet. + if (auto *CE = dyn_cast<CallExpr>(ParentLayer->getTriggerStmt())) + return nullptr; // This is C++17 copy-elided construction into return statement. if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) { assert(!RS->getRetValue()->getType().getCanonicalType() @@ -107,13 +110,20 @@ MTE->getStorageDuration() != SD_FullExpression)) return nullptr; + // This is a constructor into a function argument. Not implemented yet. + if (const ConstructionContextLayer *ParentLayer = TopLayer->getParent()) + if (auto *CE = dyn_cast<CallExpr>(ParentLayer->getTriggerStmt())) + return nullptr; assert(TopLayer->isLast()); return create<TemporaryObjectConstructionContext>(C, nullptr, MTE); } if (const auto *RS = dyn_cast<ReturnStmt>(S)) { assert(TopLayer->isLast()); return create<SimpleReturnedValueConstructionContext>(C, RS); } + // This is a constructor into a function argument. Not implemented yet. + if (auto *CE = dyn_cast<CallExpr>(TopLayer->getTriggerStmt())) + return nullptr; llvm_unreachable("Unexpected construction context with statement!"); } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) { assert(TopLayer->isLast()); Index: lib/Analysis/CFG.cpp =================================================================== --- lib/Analysis/CFG.cpp +++ lib/Analysis/CFG.cpp @@ -2367,6 +2367,13 @@ if (!boundType.isNull()) calleeType = boundType; } + // FIXME: Once actually implemented, this construction context layer should + // include the number of the argument as well. + for (auto Arg: C->arguments()) { + findConstructionContexts( + ConstructionContextLayer::create(cfg->getBumpVectorContext(), C), Arg); + } + // If this is a call to a no-return function, this stops the block here. bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn();
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits