Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -87,6 +87,7 @@ bool VisitCharacterLiteral(const CharacterLiteral *E); bool VisitCompoundAssignOperator(const CompoundAssignOperator *E); bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E); + bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E); bool VisitExprWithCleanups(const ExprWithCleanups *E); bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -699,6 +699,41 @@ return this->emitStore(*LT, E); } +template +bool ByteCodeExprGen::VisitPointerCompoundAssignOperator( + const CompoundAssignOperator *E) { + BinaryOperatorKind Op = E->getOpcode(); + const Expr *LHS = E->getLHS(); + const Expr *RHS = E->getRHS(); + std::optional LT = classify(LHS->getType()); + std::optional RT = classify(RHS->getType()); + + if (Op != BO_AddAssign && Op != BO_SubAssign) + return false; + + if (!LT || !RT) + return false; + assert(*LT == PT_Ptr); + + if (!visit(LHS)) + return false; + + if (!this->emitLoadPtr(LHS)) + return false; + + if (!visit(RHS)) + return false; + + if (Op == BO_AddAssign) + this->emitAddOffset(*RT, E); + else + this->emitSubOffset(*RT, E); + + if (DiscardResult) + return this->emitStorePopPtr(E); + return this->emitStorePtr(E); +} + template bool ByteCodeExprGen::VisitCompoundAssignOperator( const CompoundAssignOperator *E) { @@ -708,6 +743,9 @@ if (E->getType()->isFloatingType()) return VisitFloatCompoundAssignOperator(E); + if (E->getType()->isPointerType()) + return VisitPointerCompoundAssignOperator(E); + const Expr *LHS = E->getLHS(); const Expr *RHS = E->getRHS(); std::optional LT = classify(E->getLHS()->getType()); @@ -716,9 +754,7 @@ if (!LT || !RT) return false; - assert(!E->getType()->isPointerType() && - "Support pointer arithmethic in compound assignment operators"); - + assert(!E->getType()->isPointerType() && "Handled above"); assert(!E->getType()->isFloatingType() && "Handled above"); // Get LHS pointer, load its value and get RHS value. Index: clang/test/AST/Interp/literals.cpp =================================================================== --- clang/test/AST/Interp/literals.cpp +++ clang/test/AST/Interp/literals.cpp @@ -514,6 +514,199 @@ return (a -= a); } static_assert(subAll(213) == 0, ""); + + constexpr bool BoolOr(bool b1, bool b2) { + bool a; + a = b1; + a |= b2; + return a; + } + static_assert(BoolOr(true, true), ""); + static_assert(BoolOr(true, false), ""); + static_assert(BoolOr(false, true), ""); + static_assert(!BoolOr(false, false), ""); + + constexpr int IntOr(unsigned a, unsigned b) { + unsigned r; + r = a; + r |= b; + return r; + } + static_assert(IntOr(10, 1) == 11, ""); + static_assert(IntOr(1337, -1) == -1, ""); + static_assert(IntOr(0, 12) == 12, ""); + + constexpr bool BoolAnd(bool b1, bool b2) { + bool a; + a = b1; + a &= b2; + return a; + } + static_assert(BoolAnd(true, true), ""); + static_assert(!BoolAnd(true, false), ""); + static_assert(!BoolAnd(false, true), ""); + static_assert(!BoolAnd(false, false), ""); + + constexpr int IntAnd(unsigned a, unsigned b) { + unsigned r; + r = a; + r &= b; + return r; + } + static_assert(IntAnd(10, 1) == 0, ""); + static_assert(IntAnd(1337, -1) == 1337, ""); + static_assert(IntAnd(0, 12) == 0, ""); + + constexpr bool BoolXor(bool b1, bool b2) { + bool a; + a = b1; + a ^= b2; + return a; + } + static_assert(!BoolXor(true, true), ""); + static_assert(BoolXor(true, false), ""); + static_assert(BoolXor(false, true), ""); + static_assert(!BoolXor(false, false), ""); + + constexpr int IntXor(unsigned a, unsigned b) { + unsigned r; + r = a; + r ^= b; + return r; + } + static_assert(IntXor(10, 1) == 11, ""); + static_assert(IntXor(10, 10) == 0, ""); + static_assert(IntXor(12, true) == 13, ""); + + constexpr bool BoolRem(bool b1, bool b2) { + bool a; + a = b1; + a %= b2; + return a; + } + static_assert(!BoolRem(true, true), ""); + static_assert(!BoolRem(false, true), ""); + + constexpr int IntRem(int a, int b) { + int r; + r = a; + r %= b; // expected-note {{division by zero}} \ + // ref-note {{division by zero}} \ + // expected-note {{outside the range of representable values}} \ + // ref-note {{outside the range of representable values}} + return r; + } + static_assert(IntRem(2, 2) == 0, ""); + static_assert(IntRem(2, 1) == 0, ""); + static_assert(IntRem(9, 7) == 2, ""); + static_assert(IntRem(5, 0) == 0, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to 'IntRem(5, 0)'}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to 'IntRem(5, 0)'}} + + static_assert(IntRem(INT_MIN, -1) == 0, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to 'IntRem}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to 'IntRem}} + + + + constexpr bool BoolDiv(bool b1, bool b2) { + bool a; + a = b1; + a /= b2; + return a; + } + static_assert(BoolDiv(true, true), ""); + static_assert(!BoolDiv(false, true), ""); + + constexpr int IntDiv(int a, int b) { + int r; + r = a; + r /= b; // expected-note {{division by zero}} \ + // ref-note {{division by zero}} \ + // expected-note {{outside the range of representable values}} \ + // ref-note {{outside the range of representable values}} + return r; + } + static_assert(IntDiv(2, 2) == 1, ""); + static_assert(IntDiv(12, 20) == 0, ""); + static_assert(IntDiv(2, 1) == 2, ""); + static_assert(IntDiv(9, 7) == 1, ""); + static_assert(IntDiv(5, 0) == 0, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to 'IntDiv(5, 0)'}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to 'IntDiv(5, 0)'}} + + static_assert(IntDiv(INT_MIN, -1) == 0, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to 'IntDiv}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to 'IntDiv}} + + constexpr bool BoolMul(bool b1, bool b2) { + bool a; + a = b1; + a *= b2; + return a; + } + static_assert(BoolMul(true, true), ""); + static_assert(!BoolMul(true, false), ""); + static_assert(!BoolMul(false, true), ""); + static_assert(!BoolMul(false, false), ""); + + constexpr int IntMul(int a, int b) { + int r; + r = a; + r *= b; // expected-note {{is outside the range of representable values of type 'int'}} \ + // ref-note {{is outside the range of representable values of type 'int'}} + return r; + } + static_assert(IntMul(2, 2) == 4, ""); + static_assert(IntMul(12, 20) == 240, ""); + static_assert(IntMul(2, 1) == 2, ""); + static_assert(IntMul(9, 7) == 63, ""); + static_assert(IntMul(INT_MAX, 2) == 0, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to 'IntMul}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to 'IntMul}} + + constexpr int arr[] = {1,2,3}; + constexpr int ptrInc1() { + const int *p = arr; + p += 2; + return *p; + } + static_assert(ptrInc1() == 3, ""); + + constexpr int ptrInc2() { + const int *p = arr; + return *(p += 1); + } + static_assert(ptrInc2() == 2, ""); + + constexpr int ptrInc3() { // expected-error {{never produces a constant expression}} \ + // ref-error {{never produces a constant expression}} + const int *p = arr; + p += 12; // expected-note {{cannot refer to element 12 of array of 3 elements}} \ + // ref-note {{cannot refer to element 12 of array of 3 elements}} + return *p; + } + + constexpr int ptrIncDec1() { + const int *p = arr; + p += 2; + p -= 1; + return *p; + } + static_assert(ptrIncDec1() == 2, ""); + + constexpr int ptrDec1() { // expected-error {{never produces a constant expression}} \ + // ref-error {{never produces a constant expression}} + const int *p = arr; + p -= 1; // expected-note {{cannot refer to element -1 of array of 3 elements}} \ + // ref-note {{cannot refer to element -1 of array of 3 elements}} + return *p; + } }; #endif