const Expr *SubExpr = E->getSubExpr();
std::optional<PrimType> 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);
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);
/// Interpreter entry point.
bool Interpret(InterpState &S, APValue &Result);
+enum class ArithOp { Add, Sub };
+
//===----------------------------------------------------------------------===//
// Add, Sub, Mul
//===----------------------------------------------------------------------===//
return OffsetHelper<T, false>(S, OpPC);
}
+template <ArithOp Op>
+static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC) {
+ using OneT = Integral<8, false>;
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ // Get the current value on the stack.
+ S.Stk.push<Pointer>(Ptr.deref<Pointer>());
+
+ // Now the current Ptr again and a constant 1.
+ // FIXME: We shouldn't have to push these two on the stack.
+ S.Stk.push<Pointer>(Ptr.deref<Pointer>());
+ S.Stk.push<OneT>(OneT::from(1));
+ if (!OffsetHelper<OneT, Op == ArithOp::Add>(S, OpPC))
+ return false;
+
+ // Store the new value.
+ Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
+ return true;
+}
+
+static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
+ return IncDecPtrHelper<ArithOp::Add>(S, OpPC);
+}
+
+static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
+ return IncDecPtrHelper<ArithOp::Sub>(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.
// [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.
//===----------------------------------------------------------------------===//
// ref-note {{in call to 'BU()'}}
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;
}
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, "");
+
+ constexpr int bad1() { // ref-error {{never produces a constant expression}}
+ const int *e = E + 3;
+ e++; // This is fine because it's a one-past-the-end pointer
+ return *e; // expected-note {{read of dereferenced one-past-the-end pointer}} \
+ // ref-note 2{{read of dereferenced one-past-the-end pointer}}
+ }
+ static_assert(bad1() == 0, ""); // expected-error {{not an integral constant expression}} \
+ // expected-note {{in call to}} \
+ // ref-error {{not an integral constant expression}} \
+ // ref-note {{in call to}}
+
+ constexpr int bad2() { // ref-error {{never produces a constant expression}}
+ const int *e = E + 4;
+ e++; // expected-note {{cannot refer to element 5 of array of 4 elements}} \
+ // ref-note 2{{cannot refer to element 5 of array of 4 elements}}
+ return *e; // This is UB as well
+ }
+ static_assert(bad2() == 0, ""); // expected-error {{not an integral constant expression}} \
+ // expected-note {{in call to}} \
+ // ref-error {{not an integral constant expression}} \
+ // ref-note {{in call to}}
+
+
+ constexpr int bad3() { // ref-error {{never produces a constant expression}}
+ const int *e = E;
+ e--; // expected-note {{cannot refer to element -1 of array of 4 elements}} \
+ // ref-note 2{{cannot refer to element -1 of array of 4 elements}}
+ return *e; // This is UB as well
+ }
+ static_assert(bad3() == 0, ""); // expected-error {{not an integral constant expression}} \
+ // expected-note {{in call to}} \
+ // ref-error {{not an integral constant expression}} \
+ // ref-note {{in call to}}
};