aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-07-31 20:45:53 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-07-31 20:45:53 +0000
commit4b1d99562879a0e3ff14137592345925f32a8482 (patch)
tree6b35e7ed18b5f9a7e00ce21c5e0accc41e69071d /include
parent90f288ce4978a49280fceff4cd7cc7a0f549ccca (diff)
downloadclang-4b1d99562879a0e3ff14137592345925f32a8482.tar.gz
[CFG] [analyzer] Implement function argument construction contexts.
In r330377 and r338425 we have already identified what constitutes function argument constructors and added stubs in order to prevent confusing them with other temporary object constructors. Now we implement a ConstructionContext sub-class to carry all the necessary information about the construction site, namely call expression and argument index. On the analyzer side, the patch interacts with the recently implemented pre-C++17 copy elision support in an interesting manner. If on the CFG side we didn't find a construction context for the elidable constructor, we build the CFG as if the elidable constructor is not elided, and the non-elided constructor within it is a simple temporary. But the same problem may occur in the analyzer: if the elidable constructor has a construction context but the analyzer doesn't implement such context yet, the analyzer should also try to skip copy elision and still inline the non-elided temporary constructor. This was implemented by adding a "roll back" mechanism: when elision fails, roll back the changes and proceed as if it's a simple temporary. The approach is wonky, but i'm fine with that as long as it's merely a defensive mechanism that should eventually go away once all construction contexts become supported. Differential Revision: https://reviews.llvm.org/D48681. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@338436 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include')
-rw-r--r--include/clang/Analysis/CFG.h3
-rw-r--r--include/clang/Analysis/ConstructionContext.h47
2 files changed, 43 insertions, 7 deletions
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index 1655325db7..bf81d8358a 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -196,7 +196,8 @@ public:
// These are possible in C++17 due to mandatory copy elision.
isa<ReturnedValueConstructionContext>(C) ||
isa<VariableConstructionContext>(C) ||
- isa<ConstructorInitializerConstructionContext>(C)));
+ isa<ConstructorInitializerConstructionContext>(C) ||
+ isa<ArgumentConstructionContext>(C)));
Data2.setPointer(const_cast<ConstructionContext *>(C));
}
diff --git a/include/clang/Analysis/ConstructionContext.h b/include/clang/Analysis/ConstructionContext.h
index 40cb0e7e5d..c4a8a77d88 100644
--- a/include/clang/Analysis/ConstructionContext.h
+++ b/include/clang/Analysis/ConstructionContext.h
@@ -41,6 +41,12 @@ private:
/// new-expression triggers construction of the newly allocated object(s).
TriggerTy Trigger;
+ /// If a single trigger statement triggers multiple constructors, they are
+ /// usually being enumerated. This covers function argument constructors
+ /// triggered by a call-expression and items in an initializer list triggered
+ /// by an init-list-expression.
+ unsigned Index;
+
/// Sometimes a single trigger is not enough to describe the construction
/// site. In this case we'd have a chain of "partial" construction context
/// layers.
@@ -55,13 +61,13 @@ private:
/// Not all of these are currently supported.
const ConstructionContextLayer *Parent = nullptr;
- ConstructionContextLayer(TriggerTy Trigger,
- const ConstructionContextLayer *Parent)
- : Trigger(Trigger), Parent(Parent) {}
+ ConstructionContextLayer(TriggerTy Trigger, unsigned Index,
+ const ConstructionContextLayer *Parent)
+ : Trigger(Trigger), Index(Index), Parent(Parent) {}
public:
static const ConstructionContextLayer *
- create(BumpVectorContext &C, TriggerTy Trigger,
+ create(BumpVectorContext &C, TriggerTy Trigger, unsigned Index = 0,
const ConstructionContextLayer *Parent = nullptr);
const ConstructionContextLayer *getParent() const { return Parent; }
@@ -75,11 +81,13 @@ public:
return Trigger.dyn_cast<CXXCtorInitializer *>();
}
+ unsigned getIndex() const { return Index; }
+
/// Returns true if these layers are equal as individual layers, even if
/// their parents are different.
bool isSameLayer(const ConstructionContextLayer *Other) const {
assert(Other);
- return (Trigger == Other->Trigger);
+ return (Trigger == Other->Trigger && Index == Other->Index);
}
/// See if Other is a proper initial segment of this construction context
@@ -114,7 +122,8 @@ public:
SimpleReturnedValueKind,
CXX17ElidedCopyReturnedValueKind,
RETURNED_VALUE_BEGIN = SimpleReturnedValueKind,
- RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind
+ RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind,
+ ArgumentKind
};
protected:
@@ -469,6 +478,32 @@ public:
}
};
+class ArgumentConstructionContext : public ConstructionContext {
+ const Expr *CE; // The call of which the context is an argument.
+ unsigned Index; // Which argument we're constructing.
+ const CXXBindTemporaryExpr *BTE; // Whether the object needs to be destroyed.
+
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit ArgumentConstructionContext(const Expr *CE, unsigned Index,
+ const CXXBindTemporaryExpr *BTE)
+ : ConstructionContext(ArgumentKind), CE(CE),
+ Index(Index), BTE(BTE) {
+ assert(isa<CallExpr>(CE) || isa<CXXConstructExpr>(CE) ||
+ isa<ObjCMessageExpr>(CE));
+ // BTE is optional.
+ }
+
+public:
+ const Expr *getCallLikeExpr() const { return CE; }
+ unsigned getIndex() const { return Index; }
+ const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == ArgumentKind;
+ }
+};
+
} // end namespace clang
#endif // LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H