Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -211,6 +211,8 @@ 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_Assign: if (!this->emitStore(*T, BO)) return false; Index: clang/lib/AST/Interp/Integral.h =================================================================== --- clang/lib/AST/Interp/Integral.h +++ clang/lib/AST/Interp/Integral.h @@ -210,6 +210,11 @@ return CheckMulUB(A.V, B.V, R->V); } + static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) { + *R = Integral(A.V % B.V); + return false; + } + static bool neg(Integral A, Integral *R) { *R = -A; return false; Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -153,6 +153,26 @@ return AddSubMulHelper(S, OpPC, Bits, LHS, RHS); } +/// 1) Pops the RHS from the stack. +/// 2) Pops the LHS from the stack. +/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS). +template ::T> +bool Rem(InterpState &S, CodePtr OpPC) { + const T &RHS = S.Stk.pop(); + const T &LHS = S.Stk.pop(); + + if (RHS.isZero()) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_expr_divide_by_zero); + return false; + } + const unsigned Bits = RHS.bitWidth() * 2; + T Result; + T::rem(LHS, RHS, Bits, &Result); + S.Stk.push(Result); + return true; +} + //===----------------------------------------------------------------------===// // Inv //===----------------------------------------------------------------------===// Index: clang/lib/AST/Interp/Opcodes.td =================================================================== --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -54,9 +54,13 @@ list Types; } -def AluTypeClass : TypeClass { +def NumberTypeClass : TypeClass { let Types = [Sint8, Uint8, Sint16, Uint16, Sint32, - Uint32, Sint64, Uint64, Bool]; + Uint32, Sint64, Uint64]; +} + +def AluTypeClass : TypeClass { + let Types = !listconcat(NumberTypeClass.Types, [Bool]); } def PtrTypeClass : TypeClass { @@ -393,6 +397,10 @@ def Sub : AluOpcode; def Add : AluOpcode; def Mul : AluOpcode; +def Rem : Opcode { + let Types = [NumberTypeClass]; + let HasGroup = 1; +} //===----------------------------------------------------------------------===// Index: clang/test/AST/Interp/literals.cpp =================================================================== --- clang/test/AST/Interp/literals.cpp +++ clang/test/AST/Interp/literals.cpp @@ -145,3 +145,25 @@ #endif }; + +namespace rem { + static_assert(2 % 2 == 0, ""); + static_assert(2 % 1 == 0, ""); + static_assert(-3 % 4 == -3, ""); + static_assert(4 % -2 == 0, ""); + static_assert(-3 % -4 == -3, ""); + + constexpr int zero() { return 0; } + static_assert(10 % zero() == 20, ""); // ref-error {{not an integral constant expression}} \ + // ref-note {{division by zero}} \ + // expected-error {{not an integral constant expression}} \ + // expected-note {{division by zero}} + + + static_assert(true % true == 0, ""); + static_assert(false % true == 0, ""); + static_assert(true % false == 10, ""); // ref-error {{not an integral constant expression}} \ + // ref-note {{division by zero}} \ + // expected-error {{not an integral constant expression}} \ + // expected-note {{division by zero}} +};