diff --git a/clang/lib/AST/Interp/Boolean.h b/clang/lib/AST/Interp/Boolean.h index cc3d4686f8f75..e739ce28e92c5 100644 --- a/clang/lib/AST/Interp/Boolean.h +++ b/clang/lib/AST/Interp/Boolean.h @@ -50,6 +50,7 @@ class Boolean { explicit operator int64_t() const { return V; } explicit operator uint64_t() const { return V; } explicit operator int() const { return V; } + explicit operator bool() const { return V; } APSInt toAPSInt() const { return APSInt(APInt(1, static_cast(V), false), true); @@ -85,9 +86,10 @@ class Boolean { static Boolean min(unsigned NumBits) { return Boolean(false); } static Boolean max(unsigned NumBits) { return Boolean(true); } - template - static std::enable_if_t::value, Boolean> from(T Value) { - return Boolean(Value != 0); + template static Boolean from(T Value) { + if constexpr (std::is_integral::value) + return Boolean(Value != 0); + return Boolean(static_cast(Value) != 0); } template diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 18f3341439eea..d2efad4e082c0 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -117,6 +117,7 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { case CK_NullToPointer: return this->Visit(SubExpr); + case CK_IntegralToBoolean: case CK_IntegralCast: { Optional FromT = classify(SubExpr->getType()); Optional ToT = classify(CE->getType()); @@ -132,19 +133,6 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { case CK_ToVoid: return discard(SubExpr); - 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"); } diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index 8bc072c53d6b5..dcb995266c2c3 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -425,12 +425,16 @@ def Neg: Opcode { //===----------------------------------------------------------------------===// // TODO: Expand this to handle casts between more types. -def Sint32TypeClass : TypeClass { - let Types = [Sint32]; +def FromCastTypeClass : TypeClass { + let Types = [Uint32, Sint32, Bool]; +} + +def ToCastTypeClass : TypeClass { + let Types = [Uint32, Sint32, Bool]; } def Cast: Opcode { - let Types = [BoolTypeClass, Sint32TypeClass]; + let Types = [FromCastTypeClass, ToCastTypeClass]; let HasGroup = 1; } diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 6831091d596be..5c1df00a25e77 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -14,6 +14,37 @@ static_assert(number != 10, ""); // expected-error{{failed}} \ // expected-note{{evaluates to}} \ // ref-note{{evaluates to}} +constexpr bool b = number; +static_assert(b, ""); +constexpr int one = true; +static_assert(one == 1, ""); + +namespace IntegralCasts { + constexpr int i = 12; + constexpr unsigned int ui = i; + static_assert(ui == 12, ""); + constexpr unsigned int ub = !false; + static_assert(ub == 1, ""); + + constexpr int si = ui; + static_assert(si == 12, ""); + constexpr int sb = true; + static_assert(sb == 1, ""); + + constexpr int zero = 0; + constexpr unsigned int uzero = 0; + constexpr bool bs = i; + static_assert(bs, ""); + constexpr bool bu = ui; + static_assert(bu, ""); + constexpr bool ns = zero; + static_assert(!ns, ""); + constexpr bool nu = uzero; + static_assert(!nu, ""); +}; + + + constexpr bool getTrue() { return true; } constexpr bool getFalse() { return false; } constexpr void* getNull() { return nullptr; }