summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Analysis/CFG.cpp47
-rw-r--r--clang/lib/Analysis/ConstructionContext.cpp9
2 files changed, 48 insertions, 8 deletions
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 0e529bb0c52..9e4fbd68899 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -569,6 +569,7 @@ private:
CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
CFGBlock *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S);
CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
+ CFGBlock *VisitObjCMessageExpr(ObjCMessageExpr *E, AddStmtChoice asc);
CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E);
CFGBlock *VisitReturnStmt(ReturnStmt *R);
CFGBlock *VisitSEHExceptStmt(SEHExceptStmt *S);
@@ -683,6 +684,27 @@ private:
void findConstructionContexts(const ConstructionContextLayer *Layer,
Stmt *Child);
+ // Scan all arguments of a call expression for a construction context.
+ // These sorts of call expressions don't have a common superclass,
+ // hence strict duck-typing.
+ template <typename CallLikeExpr,
+ typename = typename std::enable_if<
+ std::is_same<CallLikeExpr, CallExpr>::value ||
+ std::is_same<CallLikeExpr, CXXConstructExpr>::value ||
+ std::is_same<CallLikeExpr, ObjCMessageExpr>::value>>
+ void findConstructionContextsForArguments(CallLikeExpr *E) {
+ // A stub for the code that'll eventually be used for finding construction
+ // contexts for constructors of C++ object-type arguments passed into
+ // call-like expression E.
+ // FIXME: Once actually implemented, this construction context layer should
+ // include the index of the argument as well.
+ for (auto Arg : E->arguments())
+ if (Arg->getType()->getAsCXXRecordDecl() && !Arg->isGLValue())
+ findConstructionContexts(
+ ConstructionContextLayer::create(cfg->getBumpVectorContext(), E),
+ Arg);
+ }
+
// Unset the construction context after consuming it. This is done immediately
// after adding the CFGConstructor or CFGCXXRecordTypedCall element, so
// there's no need to do this manually in every Visit... function.
@@ -2101,6 +2123,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::ObjCForCollectionStmtClass:
return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S));
+ case Stmt::ObjCMessageExprClass:
+ return VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), asc);
+
case Stmt::OpaqueValueExprClass:
return Block;
@@ -2383,12 +2408,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
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);
- }
+ findConstructionContextsForArguments(C);
// If this is a call to a no-return function, this stops the block here.
bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn();
@@ -3580,6 +3600,16 @@ CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
return VisitStmt(S, AddStmtChoice::AlwaysAdd);
}
+CFGBlock *CFGBuilder::VisitObjCMessageExpr(ObjCMessageExpr *ME,
+ AddStmtChoice asc) {
+ findConstructionContextsForArguments(ME);
+
+ autoCreateBlock();
+ appendStmt(Block, ME);
+
+ return VisitChildren(ME);
+}
+
CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) {
// If we were in the middle of a block we stop processing that block.
if (badCFG)
@@ -4244,6 +4274,11 @@ CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E,
CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C,
AddStmtChoice asc) {
+ // If the constructor takes objects as arguments by value, we need to properly
+ // construct these objects. Construction contexts we find here aren't for the
+ // constructor C, they're for its arguments only.
+ findConstructionContextsForArguments(C);
+
autoCreateBlock();
appendConstructor(Block, C);
diff --git a/clang/lib/Analysis/ConstructionContext.cpp b/clang/lib/Analysis/ConstructionContext.cpp
index ed1e6324321..3ffb0a6b35c 100644
--- a/clang/lib/Analysis/ConstructionContext.cpp
+++ b/clang/lib/Analysis/ConstructionContext.cpp
@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/ConstructionContext.h"
+#include "clang/AST/ExprObjC.h"
using namespace clang;
@@ -111,7 +112,9 @@ const ConstructionContext *ConstructionContext::createFromLayers(
assert(ParentLayer->isLast());
// This is a constructor into a function argument. Not implemented yet.
- if (isa<CallExpr>(ParentLayer->getTriggerStmt()))
+ if (isa<CallExpr>(ParentLayer->getTriggerStmt()) ||
+ isa<CXXConstructExpr>(ParentLayer->getTriggerStmt()) ||
+ isa<ObjCMessageExpr>(ParentLayer->getTriggerStmt()))
return nullptr;
// This is C++17 copy-elided construction into return statement.
if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) {
@@ -173,7 +176,9 @@ const ConstructionContext *ConstructionContext::createFromLayers(
return create<SimpleReturnedValueConstructionContext>(C, RS);
}
// This is a constructor into a function argument. Not implemented yet.
- if (isa<CallExpr>(TopLayer->getTriggerStmt()))
+ if (isa<CallExpr>(TopLayer->getTriggerStmt()) ||
+ isa<CXXConstructExpr>(TopLayer->getTriggerStmt()) ||
+ isa<ObjCMessageExpr>(TopLayer->getTriggerStmt()))
return nullptr;
llvm_unreachable("Unexpected construction context with statement!");
} else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {
OpenPOWER on IntegriCloud