diff --git a/clang/lib/AST/Interp/Boolean.h b/clang/lib/AST/Interp/Boolean.h --- a/clang/lib/AST/Interp/Boolean.h +++ b/clang/lib/AST/Interp/Boolean.h @@ -49,6 +49,7 @@ explicit operator unsigned() const { return V; } explicit operator int64_t() const { return V; } explicit operator uint64_t() const { return V; } + explicit operator int() const { return V; } APSInt toAPSInt() const { return APSInt(APInt(1, static_cast(V), false), true); @@ -134,6 +135,16 @@ *R = Boolean(A.V && B.V); return false; } + + static bool inv(Boolean A, Boolean *R) { + *R = Boolean(!A.V); + return false; + } + + static bool neg(Boolean A, Boolean *R) { + *R = Boolean(A.V); + return false; + } }; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Boolean &B) { diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -71,6 +71,7 @@ bool VisitBinaryOperator(const BinaryOperator *E); bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E); bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E); + bool VisitUnaryOperator(const UnaryOperator *E); protected: bool visitExpr(const Expr *E) override; diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -116,13 +116,36 @@ case CK_NullToPointer: return this->Visit(SubExpr); + case CK_IntegralCast: { + Optional FromT = classify(SubExpr->getType()); + Optional ToT = classify(CE->getType()); + if (!FromT || !ToT) + return false; + + if (!this->Visit(SubExpr)) + return false; + + return this->emitCast(*FromT, *ToT, CE); + } + case CK_ToVoid: return discard(SubExpr); - default: { - // TODO: implement other casts. - return this->bail(CE); - } + case CK_IntegralToBoolean: + // Compare integral from Subexpr with 0 + if (Optional T = classify(SubExpr->getType())) { + if (!this->Visit(SubExpr)) + return false; + + if (!this->emitConst(SubExpr, 0)) + return false; + + return this->emitNE(*T, SubExpr); + } + return false; + + default: + assert(false && "Cast not implemented"); } } @@ -583,6 +606,40 @@ return this->emitNullPtr(E); } +template +bool ByteCodeExprGen::VisitUnaryOperator(const UnaryOperator *E) { + if (!this->Visit(E->getSubExpr())) + return false; + + switch (E->getOpcode()) { + case UO_PostInc: // x++ + case UO_PostDec: // x-- + case UO_PreInc: // --x + case UO_PreDec: // ++x + return false; + + case UO_LNot: // !x + return this->emitInvBool(E); + case UO_Minus: // -x + if (Optional T = classify(E->getType())) + return this->emitNeg(*T, E); + return false; + case UO_Plus: // +x + return true; // noop + + case UO_AddrOf: // &x + case UO_Deref: // *x + case UO_Not: // ~x + case UO_Real: // __real x + case UO_Imag: // __imag x + case UO_Extension: + case UO_Coawait: + assert(false && "Unhandled opcode"); + } + + return false; +} + template void ByteCodeExprGen::emitCleanup() { for (VariableScope *C = VarScope; C; C = C->getParent()) diff --git a/clang/lib/AST/Interp/Integral.h b/clang/lib/AST/Interp/Integral.h --- a/clang/lib/AST/Interp/Integral.h +++ b/clang/lib/AST/Interp/Integral.h @@ -155,9 +155,11 @@ return Integral(Max); } - template - static std::enable_if_t::value, Integral> from(T Value) { - return Integral(Value); + template static Integral from(ValT Value) { + if constexpr (std::is_integral::value) + return Integral(Value); + else + return Integral::from(static_cast(Value)); } template @@ -203,6 +205,11 @@ return CheckMulUB(A.V, B.V, R->V); } + static bool neg(Integral A, Integral *R) { + *R = -A; + return false; + } + private: template static std::enable_if_t::value, bool> CheckAddUB(T A, T B, diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -154,6 +154,36 @@ return AddSubMulHelper(S, OpPC, Bits, LHS, RHS); } +//===----------------------------------------------------------------------===// +// Inv +//===----------------------------------------------------------------------===// + +template ::T> +bool Inv(InterpState &S, CodePtr OpPC) { + using BoolT = PrimConv::T; + const T &Val = S.Stk.pop(); + const unsigned Bits = Val.bitWidth(); + Boolean R; + Boolean::inv(BoolT::from(Val, Bits), &R); + + S.Stk.push(R); + return true; +} + +//===----------------------------------------------------------------------===// +// Neg +//===----------------------------------------------------------------------===// + +template ::T> +bool Neg(InterpState &S, CodePtr OpPC) { + const T &Val = S.Stk.pop(); + T Result; + T::neg(Val, &Result); + + S.Stk.push(Result); + return true; +} + //===----------------------------------------------------------------------===// // EQ, NE, GT, GE, LT, LE //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -73,6 +73,10 @@ let Types = [Ptr]; } +def BoolTypeClass : TypeClass { + let Types = [Bool]; +} + def AllTypeClass : TypeClass { let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types); } @@ -383,6 +387,37 @@ def Add : AluOpcode; def Mul : AluOpcode; + +//===----------------------------------------------------------------------===// +// Unary operators. +//===----------------------------------------------------------------------===// + +// [Real] -> [Real] +def Inv: Opcode { + let Types = [BoolTypeClass]; + let HasGroup = 1; +} + +// [Real] -> [Real] +def Neg: Opcode { + let Types = [AluTypeClass]; + let HasGroup = 1; +} + +//===----------------------------------------------------------------------===// +// Cast. +//===----------------------------------------------------------------------===// +// TODO: Expand this to handle casts between more types. + +def Sint32TypeClass : TypeClass { + let Types = [Sint32]; +} + +def Cast: Opcode { + let Types = [BoolTypeClass, Sint32TypeClass]; + let HasGroup = 1; +} + //===----------------------------------------------------------------------===// // Comparison opcodes. //===----------------------------------------------------------------------===// diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -1,15 +1,33 @@ // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++11 -verify %s +// RUN: %clang_cc1 -std=c++11 -verify=ref %s static_assert(true, ""); -static_assert(false, ""); // expected-error{{failed}} +static_assert(false, ""); // expected-error{{failed}} ref-error{{failed}} static_assert(nullptr == nullptr, ""); static_assert(1 == 1, ""); -static_assert(1 == 3, ""); // expected-error{{failed}} +static_assert(1 == 3, ""); // expected-error{{failed}} ref-error{{failed}} constexpr int number = 10; static_assert(number == 10, ""); -static_assert(number != 10, ""); // expected-error{{failed}} +static_assert(number != 10, ""); // expected-error{{failed}} \ + // ref-error{{failed}} \ + // ref-note{{evaluates to}} constexpr bool getTrue() { return true; } constexpr bool getFalse() { return false; } constexpr void* getNull() { return nullptr; } + +constexpr int neg(int m) { return -m; } +constexpr bool inv(bool b) { return !b; } + +static_assert(12, ""); +static_assert(12 == -(-(12)), ""); +static_assert(!false, ""); +static_assert(!!true, ""); +static_assert(!!true == !false, ""); +static_assert(true == 1, ""); +static_assert(false == 0, ""); +static_assert(!5 == false, ""); +static_assert(!0, ""); +static_assert(-true, ""); +static_assert(-false, ""); //expected-error{{failed}} ref-error{{failed}}