Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1352,24 +1352,44 @@ const Expr *SubExpr = E->getSubExpr(); Optional T = classify(SubExpr->getType()); - // TODO: Support pointers for inc/dec operators. switch (E->getOpcode()) { case UO_PostInc: { // x++ if (!this->visit(SubExpr)) return false; + if (T == PT_Ptr) { + if (!this->emitIncPtr(E)) + return false; + + return DiscardResult ? this->emitPopPtr(E) : true; + } + return DiscardResult ? this->emitIncPop(*T, E) : this->emitInc(*T, E); } case UO_PostDec: { // x-- if (!this->visit(SubExpr)) return false; + if (T == PT_Ptr) { + if (!this->emitDecPtr(E)) + return false; + + return DiscardResult ? this->emitPopPtr(E) : true; + } + return DiscardResult ? this->emitDecPop(*T, E) : this->emitDec(*T, E); } case UO_PreInc: { // ++x if (!this->visit(SubExpr)) return false; + if (T == PT_Ptr) { + this->emitLoadPtr(E); + this->emitConstUint8(1, E); + this->emitAddOffsetUint8(E); + return DiscardResult ? this->emitStorePopPtr(E) : this->emitStorePtr(E); + } + // Post-inc and pre-inc are the same if the value is to be discarded. if (DiscardResult) return this->emitIncPop(*T, E); @@ -1383,6 +1403,13 @@ if (!this->visit(SubExpr)) return false; + if (T == PT_Ptr) { + this->emitLoadPtr(E); + this->emitConstUint8(1, E); + this->emitSubOffsetUint8(E); + return DiscardResult ? this->emitStorePopPtr(E) : this->emitStorePtr(E); + } + // Post-dec and pre-dec are the same if the value is to be discarded. if (DiscardResult) return this->emitDecPop(*T, E); Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -105,6 +105,8 @@ /// Interpreter entry point. bool Interpret(InterpState &S, APValue &Result); +enum class ArithOp { Add, Sub }; + //===----------------------------------------------------------------------===// // Add, Sub, Mul //===----------------------------------------------------------------------===// @@ -1084,6 +1086,34 @@ return OffsetHelper(S, OpPC); } +template +static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC) { + using OneT = Integral<8, false>; + const Pointer &Ptr = S.Stk.pop(); + + // Get the current value on the stack. + S.Stk.push(Ptr.deref()); + + // Now the current Ptr again and a constant 1. + // FIXME: We shouldn't have to push these two on the stack. + S.Stk.push(Ptr.deref()); + S.Stk.push(OneT::from(1)); + if (!OffsetHelper(S, OpPC)) + return false; + + // Store the new value. + Ptr.deref() = S.Stk.pop(); + return true; +} + +static inline bool IncPtr(InterpState &S, CodePtr OpPC) { + return IncDecPtrHelper(S, OpPC); +} + +static inline bool DecPtr(InterpState &S, CodePtr OpPC) { + return IncDecPtrHelper(S, OpPC); +} + /// 1) Pops a Pointer from the stack. /// 2) Pops another Pointer from the stack. /// 3) Pushes the different of the indices of the two pointers on the stack. Index: clang/lib/AST/Interp/Opcodes.td =================================================================== --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -395,12 +395,21 @@ // [Pointer, Integral] -> [Pointer] def SubOffset : AluOpcode; -// Pointer, Pointer] - [Integral] +// [Pointer, Pointer] -> [Integral] def SubPtr : Opcode { let Types = [IntegerTypeClass]; let HasGroup = 1; } +// [Pointer] -> [Pointer] +def IncPtr : Opcode { + let HasGroup = 0; +} +// [Pointer] -> [Pointer] +def DecPtr : Opcode { + let HasGroup = 0; +} + //===----------------------------------------------------------------------===// // Binary operators. //===----------------------------------------------------------------------===// Index: clang/test/AST/Interp/arrays.cpp =================================================================== --- clang/test/AST/Interp/arrays.cpp +++ clang/test/AST/Interp/arrays.cpp @@ -215,9 +215,6 @@ static_assert(b.a[1].a == 12, ""); namespace IncDec { - // FIXME: Pointer arithmethic needs to be supported in inc/dec - // unary operators -#if 0 constexpr int getNextElem(const int *A, int I) { const int *B = (A + I); ++B; @@ -225,6 +222,59 @@ } constexpr int E[] = {1,2,3,4}; - static_assert(getNextElem(E, 1) == 3); -#endif + static_assert(getNextElem(E, 1) == 3, ""); + + constexpr int getFirst() { + const int *e = E; + return *(e++); + } + static_assert(getFirst() == 1, ""); + + constexpr int getFirst2() { + const int *e = E; + e++; + return *e; + } + static_assert(getFirst2() == 2, ""); + + constexpr int getSecond() { + const int *e = E; + return *(++e); + } + static_assert(getSecond() == 2, ""); + + constexpr int getSecond2() { + const int *e = E; + ++e; + return *e; + } + static_assert(getSecond2() == 2, ""); + + constexpr int getLast() { + const int *e = E + 3; + return *(e--); + } + static_assert(getLast() == 4, ""); + + constexpr int getLast2() { + const int *e = E + 3; + e--; + return *e; + } + static_assert(getLast2() == 3, ""); + + constexpr int getSecondToLast() { + const int *e = E + 3; + return *(--e); + } + static_assert(getSecondToLast() == 3, ""); + + constexpr int getSecondToLast2() { + const int *e = E + 3; + --e; + return *e; + } + static_assert(getSecondToLast2() == 3, ""); + + };