Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -226,61 +226,79 @@ // Typecheck the args. Optional LT = classify(LHS->getType()); Optional RT = classify(RHS->getType()); - if (!LT || !RT) { + Optional T = classify(BO->getType()); + if (!LT || !RT || !T) { return this->bail(BO); } - if (Optional T = classify(BO->getType())) { - if (!visit(LHS)) + auto Discard = [this, T, BO](bool Result) { + if (!Result) return false; - if (!visit(RHS)) - return false; - - auto Discard = [this, T, BO](bool Result) { - if (!Result) + return DiscardResult ? this->emitPop(*T, BO) : true; + }; + + // Pointer arithmethic special case. This is supported for one of + // LHS and RHS being a pointer type and the other being an integer type. + if (BO->getType()->isPointerType()) { + PrimType OffsetType; + if (LHS->getType()->isIntegerType() && RHS->getType()->isPointerType()) { + if (!visit(RHS) || !visit(LHS)) return false; - return DiscardResult ? this->emitPop(*T, BO) : true; - }; - - switch (BO->getOpcode()) { - case BO_EQ: - return Discard(this->emitEQ(*LT, BO)); - case BO_NE: - return Discard(this->emitNE(*LT, BO)); - case BO_LT: - return Discard(this->emitLT(*LT, BO)); - case BO_LE: - return Discard(this->emitLE(*LT, BO)); - case BO_GT: - return Discard(this->emitGT(*LT, BO)); - case BO_GE: - return Discard(this->emitGE(*LT, BO)); - case BO_Sub: - return Discard(this->emitSub(*T, BO)); - case BO_Add: - return Discard(this->emitAdd(*T, BO)); - case BO_Mul: - return Discard(this->emitMul(*T, BO)); - case BO_Rem: - return Discard(this->emitRem(*T, BO)); - case BO_Div: - return Discard(this->emitDiv(*T, BO)); - case BO_Assign: - if (!this->emitStore(*T, BO)) + OffsetType = *LT; + } else { + if (!visit(LHS) || !visit(RHS)) return false; - return DiscardResult ? this->emitPopPtr(BO) : true; - case BO_And: - return Discard(this->emitBitAnd(*T, BO)); - case BO_Or: - return Discard(this->emitBitOr(*T, BO)); - case BO_LAnd: - case BO_LOr: - default: - return this->bail(BO); + OffsetType = *RT; } + + if (BO->getOpcode() == BO_Add) + return Discard(this->emitAddOffset(OffsetType, BO)); + else if (BO->getOpcode() == BO_Sub) + return Discard(this->emitSubOffset(OffsetType, BO)); + return this->bail(BO); + } + + if (!visit(LHS) || !visit(RHS)) + return false; + + switch (BO->getOpcode()) { + case BO_EQ: + return Discard(this->emitEQ(*LT, BO)); + case BO_NE: + return Discard(this->emitNE(*LT, BO)); + case BO_LT: + return Discard(this->emitLT(*LT, BO)); + case BO_LE: + return Discard(this->emitLE(*LT, BO)); + case BO_GT: + return Discard(this->emitGT(*LT, BO)); + case BO_GE: + return Discard(this->emitGE(*LT, BO)); + case BO_Sub: + return Discard(this->emitSub(*T, BO)); + case BO_Add: + return Discard(this->emitAdd(*T, BO)); + case BO_Mul: + return Discard(this->emitMul(*T, BO)); + case BO_Rem: + return Discard(this->emitRem(*T, BO)); + case BO_Div: + return Discard(this->emitDiv(*T, BO)); + case BO_Assign: + if (!this->emitStore(*T, BO)) + return false; + return DiscardResult ? this->emitPopPtr(BO) : true; + case BO_And: + return Discard(this->emitBitAnd(*T, BO)); + case BO_Or: + return Discard(this->emitBitOr(*T, BO)); + case BO_LAnd: + case BO_LOr: + default: + return this->bail(BO); } - return this->bail(BO); + llvm_unreachable("Unhandled binary op"); } template Index: clang/test/AST/Interp/arrays.cpp =================================================================== --- clang/test/AST/Interp/arrays.cpp +++ clang/test/AST/Interp/arrays.cpp @@ -37,6 +37,20 @@ static_assert(getElement(1) == 4, ""); static_assert(getElement(5) == 36, ""); +constexpr int data[] = {5, 4, 3, 2, 1}; +constexpr int getElement(const int *Arr, int index) { + return *(Arr + index); +} + +static_assert(getElement(data, 1) == 4, ""); +static_assert(getElement(data, 4) == 1, ""); + +constexpr int getElementFromEnd(const int *Arr, int size, int index) { + return *(Arr + size - index - 1); +} +static_assert(getElementFromEnd(data, 5, 0) == 1, ""); +static_assert(getElementFromEnd(data, 5, 4) == 5, ""); + template constexpr T getElementOf(T* array, int i) { @@ -52,7 +66,6 @@ static_assert(getElementOfArray(foo[2], 3) == &m, ""); -constexpr int data[] = {5, 4, 3, 2, 1}; static_assert(data[0] == 4, ""); // expected-error{{failed}} \ // expected-note{{5 == 4}} \ // ref-error{{failed}} \