enum CallEventKind {
CE_Function,
CE_CXXMember,
+ CE_CXXMemberOperator,
CE_Block,
CE_BEG_SIMPLE_CALLS = CE_Function,
CE_END_SIMPLE_CALLS = CE_Block,
}
};
+/// \brief Represents a C++ overloaded operator call where the operator is
+/// implemented as a non-static member function.
+///
+/// Example: <tt>iter + 1</tt>
+class CXXMemberOperatorCall : public SimpleCall {
+protected:
+ void addExtraInvalidatedRegions(RegionList &Regions) const;
+
+public:
+ CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : SimpleCall(CE, St, LCtx, CE_CXXMemberOperator) {}
+
+ const CXXOperatorCallExpr *getOriginExpr() const {
+ return cast<CXXOperatorCallExpr>(SimpleCall::getOriginExpr());
+ }
+
+ unsigned getNumArgs() const { return getOriginExpr()->getNumArgs() - 1; }
+ const Expr *getArgExpr(unsigned Index) const {
+ return getOriginExpr()->getArg(Index + 1);
+ }
+
+ static bool classof(const CallEvent *CA) {
+ return CA->getKind() == CE_CXXMemberOperator;
+ }
+};
+
/// \brief Represents a call to a block.
///
-/// Example: \c ^{ /* ... */ }()
+/// Example: <tt>^{ /* ... */ }()</tt>
class BlockCall : public SimpleCall {
protected:
void addExtraInvalidatedRegions(RegionList &Regions) const;
using namespace clang;
using namespace ento;
+static CallEventKind classifyCallExpr(const CallExpr *CE) {
+ if (isa<CXXMemberCallExpr>(CE))
+ return CE_CXXMember;
+
+ const CXXOperatorCallExpr *OpCE = dyn_cast<CXXOperatorCallExpr>(CE);
+ if (OpCE) {
+ const FunctionDecl *DirectCallee = CE->getDirectCallee();
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DirectCallee))
+ if (MD->isInstance())
+ return CE_CXXMemberOperator;
+ } else if (CE->getCallee()->getType()->isBlockPointerType()) {
+ return CE_Block;
+ }
+
+ return CE_Function;
+}
+
void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
// Get the entry block in the CFG of the callee.
const StackFrameContext *calleeCtx = CE.getCalleeContext();
case CE_CXXMember:
// These are always at least possible to inline.
break;
+ case CE_CXXMemberOperator:
+ // FIXME: This should be possible to inline, but
+ // RegionStore::enterStackFrame isn't smart enough to handle the first
+ // argument being 'this'. The correct solution is to use CallEvent in
+ // enterStackFrame as well.
+ return false;
case CE_CXXConstructor:
// Do not inline constructors until we can model destructors.
// This is unfortunate, but basically necessary for smart pointers and such.
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this);
// Get the callee kind.
- const CXXMemberCallExpr *MemberCE = dyn_cast<CXXMemberCallExpr>(CE);
- bool IsBlock = (MemberCE ? false
- : CE->getCallee()->getType()->isBlockPointerType());
+ CallEventKind K = classifyCallExpr(CE);
// Evaluate the function call. We try each of the checkers
// to see if the can evaluate the function call.
const LocationContext *LCtx = (*I)->getLocationContext();
// Evaluate the call.
- if (MemberCE)
- evalCall(dstCallEvaluated, *I, CXXMemberCall(MemberCE, State, LCtx));
- else if (IsBlock)
- evalCall(dstCallEvaluated, *I, BlockCall(CE, State, LCtx));
- else
+ switch (K) {
+ case CE_Function:
evalCall(dstCallEvaluated, *I, FunctionCall(CE, State, LCtx));
+ break;
+ case CE_CXXMember:
+ evalCall(dstCallEvaluated, *I, CXXMemberCall(cast<CXXMemberCallExpr>(CE),
+ State, LCtx));
+ break;
+ case CE_CXXMemberOperator:
+ evalCall(dstCallEvaluated, *I,
+ CXXMemberOperatorCall(cast<CXXOperatorCallExpr>(CE),
+ State, LCtx));
+ break;
+ case CE_Block:
+ evalCall(dstCallEvaluated, *I, BlockCall(CE, State, LCtx));
+ break;
+ default:
+ llvm_unreachable("Non-CallExpr CallEventKind");
+ }
}
// Finally, perform the post-condition check of the CallExpr and store
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -verify %s
+void clang_analyzer_eval(bool);
+
struct X0 { };
bool operator==(const X0&, const X0&);
bool PR7287(X0 a, X0 b) {
return operator==(a, b);
}
+
+
+// Inlining non-static member operators mistakenly treated 'this' as the first
+// argument for a while.
+
+struct IntComparable {
+ bool operator==(int x) const {
+ return x == 0;
+ }
+};
+
+void testMemberOperator(IntComparable B) {
+ // FIXME: Change this to TRUE when we re-enable inlining.
+ clang_analyzer_eval(B == 0); // expected-warning{{UNKNOWN}}
+}