diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafetyOps.def b/clang/include/clang/Analysis/Analyses/ThreadSafetyOps.def index b33e2e8bf6cc..42184d824609 100644 --- a/clang/include/clang/Analysis/Analyses/ThreadSafetyOps.def +++ b/clang/include/clang/Analysis/Analyses/ThreadSafetyOps.def @@ -33,6 +33,8 @@ TIL_OPCODE_DEF(Call) TIL_OPCODE_DEF(Alloc) TIL_OPCODE_DEF(Load) TIL_OPCODE_DEF(Store) +TIL_OPCODE_DEF(ArrayFirst) +TIL_OPCODE_DEF(ArrayAdd) TIL_OPCODE_DEF(UnaryOp) TIL_OPCODE_DEF(BinaryOp) diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h index d9fdd3a8ad9a..477ae48ab6e6 100644 --- a/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h +++ b/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h @@ -798,6 +798,7 @@ private: // Store a value to memory. +// Source is a pointer, destination is the value to store. class Store : public SExpr { public: static bool classof(const SExpr *E) { return E->opcode() == COP_Store; } @@ -830,6 +831,68 @@ private: }; +// If p is a reference to an array, then first(p) is a reference to the first +// element. The usual array notation p[i] becomes first(p + i). +class ArrayFirst : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayFirst; } + + ArrayFirst(SExpr *A) : SExpr(COP_ArrayFirst), Array(A) {} + ArrayFirst(const ArrayFirst &E, SExpr *A) : SExpr(E), Array(A) {} + + SExpr *array() { return Array.get(); } + const SExpr *array() const { return Array.get(); } + + template typename V::R_SExpr traverse(V &Visitor) { + typename V::R_SExpr Na = Visitor.traverse(Array); + return Visitor.reduceArrayFirst(*this, Na); + } + + template typename C::CType compare(ArrayFirst* E, C& Cmp) { + return Cmp.compare(array(), E->array()); + } + +private: + SExprRef Array; +}; + + +// Pointer arithmetic, restricted to arrays only. +// If p is a reference to an array, then p + n, where n is an integer, is +// a reference to a subarray. +class ArrayAdd : public SExpr { +public: + static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayAdd; } + + ArrayAdd(SExpr *A, SExpr *N) : SExpr(COP_ArrayAdd), Array(A), Index(N) {} + ArrayAdd(const ArrayAdd &E, SExpr *A, SExpr *N) + : SExpr(E), Array(A), Index(N) {} + + SExpr *array() { return Array.get(); } + const SExpr *array() const { return Array.get(); } + + SExpr *index() { return Index.get(); } + const SExpr *index() const { return Index.get(); } + + template typename V::R_SExpr traverse(V &Visitor) { + typename V::R_SExpr Na = Visitor.traverse(Array); + typename V::R_SExpr Ni = Visitor.traverse(Index); + return Visitor.reduceArrayAdd(*this, Na, Ni); + } + + template typename C::CType compare(ArrayAdd* E, C& Cmp) { + typename C::CType Ct = Cmp.compare(array(), E->array()); + if (Cmp.notTrue(Ct)) + return Ct; + return Cmp.compare(index(), E->index()); + } + +private: + SExprRef Array; + SExprRef Index; +}; + + // Simple unary operation -- e.g. !, ~, etc. class UnaryOp : public SExpr { public: diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h b/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h index 8649018e1794..81ac93ac8260 100644 --- a/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h +++ b/clang/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h @@ -169,6 +169,12 @@ public: R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { return new (Arena) Store(Orig, E0, E1); } + R_SExpr reduceArrayFirst(ArrayFirst &Orig, R_SExpr E0) { + return new (Arena) ArrayFirst(Orig, E0); + } + R_SExpr reduceArrayAdd(ArrayAdd &Orig, R_SExpr E0, R_SExpr E1) { + return new (Arena) ArrayAdd(Orig, E0, E1); + } R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { return new (Arena) UnaryOp(Orig, E0); } @@ -279,6 +285,10 @@ public: R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { return E0; } R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { return E0; } R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { return E0 && E1; } + R_SExpr reduceArrayFirst(Store &Orig, R_SExpr E0) { return E0; } + R_SExpr reduceArrayAdd(Store &Orig, R_SExpr E0, R_SExpr E1) { + return E0 && E1; + } R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { return E0; } R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) { return E0 && E1; @@ -454,6 +464,8 @@ protected: case COP_Alloc: return Prec_Other; case COP_Load: return Prec_Postfix; case COP_Store: return Prec_Other; + case COP_ArrayFirst: return Prec_Postfix; + case COP_ArrayAdd: return Prec_Postfix; case COP_UnaryOp: return Prec_Unary; case COP_BinaryOp: return Prec_Binary; @@ -645,6 +657,23 @@ protected: self()->printSExpr(E->source(), SS, Prec_Other-1); } + void printArrayFirst(ArrayFirst *E, StreamType &SS) { + self()->printSExpr(E->array(), SS, Prec_Postfix); + if (ArrayAdd *A = dyn_cast_or_null(E)) { + SS << "["; + printSExpr(A->index(), SS, Prec_MAX); + SS << "]"; + return; + } + SS << "[0]"; + } + + void printArrayAdd(ArrayAdd *E, StreamType &SS) { + self()->printSExpr(E->array(), SS, Prec_Postfix); + SS << " + "; + self()->printSExpr(E->index(), SS, Prec_Atom); + } + void printUnaryOp(UnaryOp *E, StreamType &SS) { self()->printSExpr(E->expr(), SS, Prec_Unary); } diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp index b22d64219106..391680918e3e 100644 --- a/clang/lib/Analysis/ThreadSafetyCommon.cpp +++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp @@ -399,7 +399,10 @@ til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE, til::SExpr * SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E, CallingContext *Ctx) { - return new (Arena) til::Undefined(E); + til::SExpr *E0 = translate(E->getBase(), Ctx); + til::SExpr *E1 = translate(E->getIdx(), Ctx); + auto *AA = new (Arena) til::ArrayAdd(E0, E1); + return new (Arena) til::ArrayFirst(AA); }