[clang][Interp] Implement IntegralToBoolean casts
authorTimm Bäder <tbaeder@redhat.com>
Fri, 26 Aug 2022 13:39:17 +0000 (15:39 +0200)
committerTimm Bäder <tbaeder@redhat.com>
Thu, 8 Sep 2022 05:31:07 +0000 (07:31 +0200)
Redo how we do IntegralCasts and implement IntegralToBoolean casts using
the already existing cast op.

Differential Revision: https://reviews.llvm.org/D132739

clang/lib/AST/Interp/Boolean.h
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/Opcodes.td
clang/test/AST/Interp/literals.cpp

index cc3d4686f8f75ce0ba1b0a1a6e2ecbbc038be4cb..e739ce28e92c5a0ccd907b69fbc5b1de5dec1e21 100644 (file)
@@ -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<uint64_t>(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 <typename T>
-  static std::enable_if_t<std::is_integral<T>::value, Boolean> from(T Value) {
-    return Boolean(Value != 0);
+  template <typename T> static Boolean from(T Value) {
+    if constexpr (std::is_integral<T>::value)
+      return Boolean(Value != 0);
+    return Boolean(static_cast<decltype(Boolean::V)>(Value) != 0);
   }
 
   template <unsigned SrcBits, bool SrcSign>
index 18f3341439eeab437817eeb88a7b8bee940e0251..d2efad4e082c05af7a2b948d93ed8b871405fe3e 100644 (file)
@@ -117,6 +117,7 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
   case CK_NullToPointer:
     return this->Visit(SubExpr);
 
+  case CK_IntegralToBoolean:
   case CK_IntegralCast: {
     Optional<PrimType> FromT = classify(SubExpr->getType());
     Optional<PrimType> ToT = classify(CE->getType());
@@ -132,19 +133,6 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
   case CK_ToVoid:
     return discard(SubExpr);
 
-  case CK_IntegralToBoolean:
-    // Compare integral from Subexpr with 0
-    if (Optional<PrimType> 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");
   }
index 8bc072c53d6b518a10ae577d7171915e4fed0b41..dcb995266c2c32168d5d36d215f32d36e86d2ae5 100644 (file)
@@ -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;
 }
 
index 6831091d596be44083fad17e83c94249979698e6..5c1df00a25e775410e3b9db419e02cca11edb8c0 100644 (file)
@@ -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; }