[Lldb-commits] [lldb] [LLDB] Add type casting to DIL, part 2 or 3 (PR #170332)

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Tue Dec 9 03:27:00 PST 2025


================
@@ -740,16 +771,242 @@ Interpreter::Visit(const BooleanLiteralNode *node) {
   return ValueObject::CreateValueObjectFromBool(m_target, value, "result");
 }
 
+llvm::Expected<CompilerType>
+Interpreter::VerifyCastType(lldb::ValueObjectSP &operand, CompilerType &op_type,
+                            CompilerType target_type,
+                            CastPromotionKind &promo_kind, CastKind &cast_kind,
+                            int location) {
+
+  promo_kind = CastPromotionKind::eNone;
+  if (op_type.IsReferenceType())
+    op_type = op_type.GetNonReferenceType();
+  if (target_type.IsScalarType()) {
+    if (op_type.IsArrayType()) {
+      // Do array-to-pointer conversion.
+      CompilerType deref_type =
+          op_type.IsReferenceType() ? op_type.GetNonReferenceType() : op_type;
+      CompilerType result_type =
+          deref_type.GetArrayElementType(nullptr).GetPointerType();
+      uint64_t addr = operand->GetLoadAddress();
+      llvm::StringRef name = operand->GetName().GetStringRef();
+      operand = ValueObject::CreateValueObjectFromAddress(
+          name, addr, m_exe_ctx_scope, result_type, /*do_deref=*/false);
+      op_type = result_type;
+    }
+
+    if (op_type.IsPointerType() || op_type.IsNullPtrType()) {
+      // Cast from pointer to float/double is not allowed.
+      if (target_type.IsFloat()) {
+        std::string errMsg = llvm::formatv(
+            "Cast from {0} to {1} is not allowed", op_type.TypeDescription(),
+            target_type.TypeDescription());
+        return llvm::make_error<DILDiagnosticError>(
+            m_expr, std::move(errMsg), location,
+            op_type.TypeDescription().length());
+      }
+      // Casting pointer to bool is valid. Otherwise check if the result type
+      // is at least as big as the pointer size.
+      uint64_t type_byte_size = 0;
+      uint64_t rhs_type_byte_size = 0;
+      if (auto temp = target_type.GetByteSize(m_exe_ctx_scope.get()))
+        type_byte_size = *temp;
+      if (auto temp = op_type.GetByteSize(m_exe_ctx_scope.get()))
+        rhs_type_byte_size = *temp;
+      if (!target_type.IsBoolean() && type_byte_size < rhs_type_byte_size) {
+        std::string errMsg = llvm::formatv(
+            "cast from pointer to smaller type {0} loses information",
+            target_type.TypeDescription());
+        return llvm::make_error<DILDiagnosticError>(
+            m_expr, std::move(errMsg), location,
+            op_type.TypeDescription().length());
+      }
+    } else if (!op_type.IsScalarType() && !op_type.IsEnumerationType()) {
+      // Otherwise accept only arithmetic types and enums.
+      std::string errMsg = llvm::formatv(
+          "cannot convert {0} to {1} without a conversion operator",
+          op_type.TypeDescription(), target_type.TypeDescription());
+
+      return llvm::make_error<DILDiagnosticError>(
+          m_expr, std::move(errMsg), location,
+          op_type.TypeDescription().length());
+    }
+    promo_kind = CastPromotionKind::eArithmetic;
+    return target_type;
+  }
+
+  if (target_type.IsEnumerationType()) {
+    // Cast to enum type.
+    if (!op_type.IsScalarType() && !op_type.IsEnumerationType()) {
+      std::string errMsg = llvm::formatv("Cast from {0} to {1} is not allowed",
+                                         op_type.TypeDescription(),
+                                         target_type.TypeDescription());
+
+      return llvm::make_error<DILDiagnosticError>(
+          m_expr, std::move(errMsg), location,
+          op_type.TypeDescription().length());
+    }
+    cast_kind = CastKind::eEnumeration;
+    return target_type;
+  }
+
+  if (target_type.IsPointerType()) {
+    if (!op_type.IsInteger() && !op_type.IsEnumerationType() &&
+        !op_type.IsArrayType() && !op_type.IsPointerType() &&
+        !op_type.IsNullPtrType()) {
+      std::string errMsg = llvm::formatv(
+          "cannot cast from type {0} to pointer type {1}",
+          op_type.TypeDescription(), target_type.TypeDescription());
+
+      return llvm::make_error<DILDiagnosticError>(
+          m_expr, std::move(errMsg), location,
+          op_type.TypeDescription().length());
+    }
+    promo_kind = CastPromotionKind::ePointer;
+    return target_type;
+  }
+
+  if (target_type.IsNullPtrType()) {
+    // Cast to nullptr type.
+    bool is_signed;
+    if (!target_type.IsNullPtrType() &&
+        (!operand->IsIntegerType(is_signed) ||
+         (is_signed && operand->GetValueAsSigned(0) != 0) ||
+         (!is_signed && operand->GetValueAsUnsigned(0) != 0))) {
+      std::string errMsg = llvm::formatv("Cast from {0} to {1} is not allowed",
+                                         op_type.TypeDescription(),
+                                         target_type.TypeDescription());
+
+      return llvm::make_error<DILDiagnosticError>(
+          m_expr, std::move(errMsg), location,
+          op_type.TypeDescription().length());
+    }
+    cast_kind = CastKind::eNullptr;
+    return target_type;
+  }
+
+  if (target_type.IsReferenceType()) {
+    // Cast to a reference type.
+    cast_kind = CastKind::eReference;
+    return target_type;
+  }
+
+  // Unsupported cast.
+  std::string errMsg =
+      llvm::formatv("casting of {0} to {1} is not implemented yet",
+                    op_type.TypeDescription(), target_type.TypeDescription());
+  return llvm::make_error<DILDiagnosticError>(
+      m_expr, std::move(errMsg), location, op_type.TypeDescription().length());
+}
+
 llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const CastNode *node) {
   auto operand_or_err = Evaluate(node->GetOperand());
   if (!operand_or_err)
     return operand_or_err;
 
   lldb::ValueObjectSP operand = *operand_or_err;
-  // Don't actually do the cast for now -- that code will be added later.
-  // For now just return an error message.
-  return llvm::make_error<DILDiagnosticError>(
-      m_expr, "Type casting is not supported here.", node->GetLocation());
+  CompilerType op_type = operand->GetCompilerType();
+  CastKind cast_kind = CastKind::eNone;
+  CastPromotionKind promo_kind = CastPromotionKind::eNone;
+
+  auto type_or_err = VerifyCastType(operand, op_type, node->GetType(),
+                                    promo_kind, cast_kind, node->GetLocation());
+  if (!type_or_err)
+    return type_or_err.takeError();
+
+  CompilerType target_type = *type_or_err;
+  if (op_type.IsReferenceType()) {
+    Status error;
+    operand = operand->Dereference(error);
+    if (error.Fail())
+      return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(),
+                                                  node->GetLocation());
+  }
+
+  switch (cast_kind) {
+  case CastKind::eEnumeration: {
+    if (!target_type.IsEnumerationType()) {
----------------
Michael137 wrote:

Shouldn't all of these kinds assertions happen in `VerifyCastType`? It is the function that sets the `target_type` and the `cast_kind`. So it should also be responsible for ensuring that those two match

https://github.com/llvm/llvm-project/pull/170332


More information about the lldb-commits mailing list