https://github.com/cmtice created 
https://github.com/llvm/llvm-project/pull/159500

This adds basic c-style type casting to DIL. It handles basic built-in types: 
bool, char, short, int, long, double, float, and void. It also handles 
user-defined types (e.g. class names, typedefs, etc.). It does NOT handle C++ 
templates at the moment. Not sure if this is something we would want to add to 
DIL later or not. DIL will not be supporting C++-specific-style casts 
(static_cast<>, reinterpret_cast<>, or dynamic_cast<>).

This PR adds quite a bit of type-parsing, which must happen in the parser, to 
resolve ambiguity ("is this thing I'm looking at a type cast or just an 
expression in parentheses?").

I'd be happy to break this up into smaller PRs if someone could suggest a 
reasonable way to break it up.

>From bbacb825638d18f052dfeec253c765001a872229 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmt...@google.com>
Date: Wed, 17 Sep 2025 20:21:52 -0700
Subject: [PATCH] [LLDB] Add type casting to DIL.

This adds basic c-style type casting to DIL. It handles basic
built-in types: bool, char, short, int, long, double, float, and void.
It also handles user-defined types (e.g. class names, typedefs, etc.).
It does NOT handle C++ templates at the moment. Not sure if this is
something we would want to add to DIL later or not. DIL will not
be supporting C++-specific-style casts (static_cast<>, reinterpret_cast<>,
or dynamic_cast<>).

This PR adds quite a bit of type-parsing, which must happen in the
parser, to resolve ambiguity ("is this thing I'm looking at a type cast
or just an expression in parentheses?").

I'd be happy to break this up into smaller PRs if someone could suggest
a reasonable way to break it up.
---
 lldb/docs/dil-expr-lang.ebnf                  |  32 +-
 lldb/include/lldb/ValueObject/DILAST.h        |  41 ++
 lldb/include/lldb/ValueObject/DILEval.h       |   7 +
 lldb/include/lldb/ValueObject/DILParser.h     | 133 ++++
 lldb/source/ValueObject/DILAST.cpp            |   4 +
 lldb/source/ValueObject/DILEval.cpp           | 285 +++++++-
 lldb/source/ValueObject/DILParser.cpp         | 634 +++++++++++++++++-
 .../LocalVars/TestFrameVarDILLocalVars.py     |   1 +
 .../frame/var-dil/expr/CStyleCast/Makefile    |   6 +
 .../CStyleCast/TestFrameVarDILCStyleCast.py   | 233 +++++++
 .../frame/var-dil/expr/CStyleCast/main.cpp    |  81 +++
 11 files changed, 1439 insertions(+), 18 deletions(-)
 create mode 100644 
lldb/test/API/commands/frame/var-dil/expr/CStyleCast/Makefile
 create mode 100644 
lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
 create mode 100644 
lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp

diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 67328939ba420..4a66734e75fec 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -3,10 +3,13 @@
 (* This is currently a subset of the final DIL Language, matching the current
    DIL implementation. *)
 
-expression = unary_expression ;
+expression = cast_expression;
+
+cast_expression = unary_expression
+                | "(" type_id ")" cast_expression;
 
 unary_expression = postfix_expression
-                 | unary_operator expression ;
+                 | unary_operator cast_expression ;
 
 unary_operator = "*" | "&" ;
 
@@ -41,6 +44,31 @@ nested_name_specifier = type_name "::"
                       | namespace_name '::'
                       | nested_name_specifier identifier "::" ;
 
+type_id = type_specifier_seq [abstract_declarator] ;
+
+type_specifier_seq = type_specifier [type_specifier];
+
+type_specifier = ["::"] [nested_name_specifier] type_name;
+               | "char"
+               | "bool"
+               | "short"
+               | "int"
+               | "long"
+               | "signed"
+               | "unsigned"
+               | "float"
+               | "double"
+               | "void" ;
+
+nested_name_specifier = type_name "::"
+                      | namespace_name "::"
+                      | nested_name_specifier identifier "::" ;
+
+abstract_declarator = ptr_operator [abstract_declarator] ;
+
+ptr_operator = "*"
+             | "&";
+
 type_name = class_name
           | enum_name
           | typedef_name;
diff --git a/lldb/include/lldb/ValueObject/DILAST.h 
b/lldb/include/lldb/ValueObject/DILAST.h
index 1d10755c46e39..bbaad28d55735 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -20,6 +20,7 @@ namespace lldb_private::dil {
 enum class NodeKind {
   eArraySubscriptNode,
   eBitExtractionNode,
+  eCStyleCastNode,
   eErrorNode,
   eFloatLiteralNode,
   eIdentifierNode,
@@ -28,6 +29,21 @@ enum class NodeKind {
   eUnaryOpNode,
 };
 
+/// The C-Style casts allowed by DIL.
+enum class CStyleCastKind {
+  eEnumeration,
+  eNullptr,
+  eReference,
+  eNone,
+};
+
+/// Promotions for C-Style casts in DIL.
+enum class CastPromoKind {
+  eArithmetic,
+  ePointer,
+  eNone,
+};
+
 /// The Unary operators recognized by DIL.
 enum class UnaryOpKind {
   AddrOf, // "&"
@@ -226,6 +242,29 @@ class FloatLiteralNode : public ASTNode {
   llvm::APFloat m_value;
 };
 
+class CStyleCastNode : public ASTNode {
+public:
+  CStyleCastNode(uint32_t location, CompilerType type, ASTNodeUP operand,
+                 CStyleCastKind kind)
+      : ASTNode(location, NodeKind::eCStyleCastNode), m_type(type),
+        m_operand(std::move(operand)), m_cast_kind(kind) {}
+
+  llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
+
+  CompilerType GetType() const { return m_type; }
+  ASTNode *GetOperand() const { return m_operand.get(); }
+  CStyleCastKind GetCastKind() const { return m_cast_kind; }
+
+  static bool classof(const ASTNode *node) {
+    return node->GetKind() == NodeKind::eCStyleCastNode;
+  }
+
+private:
+  CompilerType m_type;
+  ASTNodeUP m_operand;
+  CStyleCastKind m_cast_kind;
+};
+
 /// This class contains one Visit method for each specialized type of
 /// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
 /// the correct function in the DIL expression evaluator for evaluating that
@@ -247,6 +286,8 @@ class Visitor {
   Visit(const IntegerLiteralNode *node) = 0;
   virtual llvm::Expected<lldb::ValueObjectSP>
   Visit(const FloatLiteralNode *node) = 0;
+  virtual llvm::Expected<lldb::ValueObjectSP>
+  Visit(const CStyleCastNode *node) = 0;
 };
 
 } // namespace lldb_private::dil
diff --git a/lldb/include/lldb/ValueObject/DILEval.h 
b/lldb/include/lldb/ValueObject/DILEval.h
index 5a48c2c989f4d..3d4ef021cbc6f 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -58,12 +58,19 @@ class Interpreter : Visitor {
   Visit(const IntegerLiteralNode *node) override;
   llvm::Expected<lldb::ValueObjectSP>
   Visit(const FloatLiteralNode *node) override;
+  llvm::Expected<lldb::ValueObjectSP>
+  Visit(const CStyleCastNode *node) override;
 
   llvm::Expected<CompilerType>
   PickIntegerType(lldb::TypeSystemSP type_system,
                   std::shared_ptr<ExecutionContextScope> ctx,
                   const IntegerLiteralNode *literal);
 
+  llvm::Expected<CompilerType>
+  VerifyCStyleCastType(lldb::ValueObjectSP &operand, CompilerType &op_type,
+                       CompilerType target_type, CastPromoKind &promo_kind,
+                       CStyleCastKind &cast_kind, int location);
+
   // Used by the interpreter to create objects, perform casts, etc.
   lldb::TargetSP m_target;
   llvm::StringRef m_expr;
diff --git a/lldb/include/lldb/ValueObject/DILParser.h 
b/lldb/include/lldb/ValueObject/DILParser.h
index 90df109337dcf..081711d26439d 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -10,6 +10,7 @@
 #define LLDB_VALUEOBJECT_DILPARSER_H
 
 #include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/StackFrame.h"
 #include "lldb/Utility/DiagnosticsRendering.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/ValueObject/DILAST.h"
@@ -31,6 +32,9 @@ enum class ErrorCode : unsigned char {
   kUnknown,
 };
 
+llvm::Expected<lldb::TypeSystemSP>
+DILGetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx);
+
 // The following is modeled on class OptionParseError.
 class DILDiagnosticError
     : public llvm::ErrorInfo<DILDiagnosticError, DiagnosticError> {
@@ -55,6 +59,61 @@ class DILDiagnosticError
 
   std::string message() const override { return m_detail.rendered; }
 };
+/// TypeDeclaration builds information about the literal type definition as
+/// type is being parsed. It doesn't perform semantic analysis for non-basic
+/// types -- e.g. "char&&&" is a valid type declaration.
+/// NOTE: CV qualifiers are ignored.
+class TypeDeclaration {
+public:
+  enum class TypeSpecifier {
+    kBool,
+    kChar,
+    kDouble,
+    kFloat,
+    kInt,
+    kLong,
+    kLongDouble,
+    kLongLong,
+    kShort,
+    kUnknown,
+    kVoid,
+  };
+
+  enum class SignSpecifier {
+    kUnknown,
+    kSigned,
+    kUnsigned,
+  };
+
+  bool IsEmpty() const { return !m_is_builtin && !m_is_user_type; }
+
+  lldb::BasicType GetBasicType() const;
+
+public:
+  // Indicates user-defined typename (e.g. "MyClass", "MyTmpl<int>").
+  std::string m_user_typename;
+
+  // Basic type specifier ("void", "char", "intr", "float", "long long", etc.).
+  TypeSpecifier m_type_specifier = TypeSpecifier::kUnknown;
+
+  // Signedness specifier ("signed", "unsigned").
+  SignSpecifier m_sign_specifier = SignSpecifier::kUnknown;
+
+  // Does the type declaration includes "int" specifier?
+  // This is different than `type_specifier_` and is used to detect "int"
+  // duplication for types that can be combined with "int" specifier (e.g.
+  // "short int", "long int").
+  bool m_has_int_specifier = false;
+
+  // Indicates whether there was an error during parsing.
+  bool m_has_error = false;
+
+  // Indicates whether this declaration describes a builtin type.
+  bool m_is_builtin = false;
+
+  // Indicates whether this declaration describes a user type.
+  bool m_is_user_type = false;
+}; // class TypeDeclaration
 
 /// Pure recursive descent parser for C++ like expressions.
 /// EBNF grammar for the parser is described in lldb/docs/dil-expr-lang.ebnf
@@ -100,10 +159,22 @@ class DILParser {
   ASTNodeUP ParseIntegerLiteral();
   ASTNodeUP ParseFloatingPointLiteral();
 
+  ASTNodeUP ParseCastExpression();
+  std::optional<CompilerType> ParseTypeId(bool must_be_type_id = false);
+  void ParseTypeSpecifierSeq(TypeDeclaration *type_decl);
+  bool ParseTypeSpecifier(TypeDeclaration *type_decl);
+  std::string ParseTypeName();
+  CompilerType ResolveTypeDeclarators(CompilerType type,
+                                      const std::vector<Token> &ptr_operators);
+  bool IsSimpleTypeSpecifierKeyword(Token token) const;
+  bool HandleSimpleTypeSpecifier(TypeDeclaration *type_decl);
+
   void BailOut(const std::string &error, uint32_t loc, uint16_t err_len);
 
   void Expect(Token::Kind kind);
 
+  void ExpectOneOf(std::vector<Token::Kind> kinds_vec);
+
   void TentativeParsingRollback(uint32_t saved_idx) {
     if (m_error)
       llvm::consumeError(std::move(m_error));
@@ -132,4 +203,66 @@ class DILParser {
 
 } // namespace lldb_private::dil
 
+namespace llvm {
+template <>
+struct format_provider<lldb_private::dil::TypeDeclaration::TypeSpecifier> {
+  static void format(const lldb_private::dil::TypeDeclaration::TypeSpecifier 
&t,
+                     raw_ostream &OS, llvm::StringRef Options) {
+    switch (t) {
+    case lldb_private::dil::TypeDeclaration::TypeSpecifier::kVoid:
+      OS << "void";
+      break;
+    case lldb_private::dil::TypeDeclaration::TypeSpecifier::kBool:
+      OS << "bool";
+      break;
+    case lldb_private::dil::TypeDeclaration::TypeSpecifier::kChar:
+      OS << "char";
+      break;
+    case lldb_private::dil::TypeDeclaration::TypeSpecifier::kInt:
+      OS << "int";
+      break;
+    case lldb_private::dil::TypeDeclaration::TypeSpecifier::kFloat:
+      OS << "float";
+      break;
+    case lldb_private::dil::TypeDeclaration::TypeSpecifier::kShort:
+      OS << "short";
+      break;
+    case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLong:
+      OS << "long";
+      break;
+    case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLongLong:
+      OS << "long long";
+      break;
+    case lldb_private::dil::TypeDeclaration::TypeSpecifier::kDouble:
+      OS << "double";
+      break;
+    case lldb_private::dil::TypeDeclaration::TypeSpecifier::kLongDouble:
+      OS << "long double";
+      break;
+    default:
+      OS << "invalid type specifier";
+      break;
+    }
+  }
+};
+
+template <>
+struct format_provider<lldb_private::dil::TypeDeclaration::SignSpecifier> {
+  static void format(const lldb_private::dil::TypeDeclaration::SignSpecifier 
&t,
+                     raw_ostream &OS, llvm::StringRef Options) {
+    switch (t) {
+    case lldb_private::dil::TypeDeclaration::SignSpecifier::kSigned:
+      OS << "signed";
+      break;
+    case lldb_private::dil::TypeDeclaration::SignSpecifier::kUnsigned:
+      OS << "unsigned";
+      break;
+    default:
+      OS << "invalid sign specifier";
+      break;
+    }
+  }
+};
+} // namespace llvm
+
 #endif // LLDB_VALUEOBJECT_DILPARSER_H
diff --git a/lldb/source/ValueObject/DILAST.cpp 
b/lldb/source/ValueObject/DILAST.cpp
index 70564663a62cd..f8afd9d7bd50a 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -46,4 +46,8 @@ llvm::Expected<lldb::ValueObjectSP> 
FloatLiteralNode::Accept(Visitor *v) const {
   return v->Visit(this);
 }
 
+llvm::Expected<lldb::ValueObjectSP> CStyleCastNode::Accept(Visitor *v) const {
+  return v->Visit(this);
+}
+
 } // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index c6cf41ee9e9ee..05bcc25d2b9f2 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -13,6 +13,7 @@
 #include "lldb/Symbol/VariableList.h"
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/ValueObject/DILAST.h"
+#include "lldb/ValueObject/DILParser.h"
 #include "lldb/ValueObject/ValueObject.h"
 #include "lldb/ValueObject/ValueObjectRegister.h"
 #include "lldb/ValueObject/ValueObjectVariable.h"
@@ -21,6 +22,42 @@
 
 namespace lldb_private::dil {
 
+lldb::ValueObjectSP
+GetDynamicOrSyntheticValue(lldb::ValueObjectSP in_valobj_sp,
+                           lldb::DynamicValueType use_dynamic,
+                           bool use_synthetic) {
+  Status error;
+  if (!in_valobj_sp) {
+    error = Status("invalid value object");
+    return in_valobj_sp;
+  }
+  lldb::ValueObjectSP value_sp = in_valobj_sp;
+  Target *target = value_sp->GetTargetSP().get();
+  // If this ValueObject holds an error, then it is valuable for that.
+  if (value_sp->GetError().Fail())
+    return value_sp;
+
+  if (!target)
+    return lldb::ValueObjectSP();
+
+  if (use_dynamic != lldb::eNoDynamicValues) {
+    lldb::ValueObjectSP dynamic_sp = value_sp->GetDynamicValue(use_dynamic);
+    if (dynamic_sp)
+      value_sp = dynamic_sp;
+  }
+
+  if (use_synthetic) {
+    lldb::ValueObjectSP synthetic_sp = value_sp->GetSyntheticValue();
+    if (synthetic_sp)
+      value_sp = synthetic_sp;
+  }
+
+  if (!value_sp)
+    error = Status("invalid value object");
+
+  return value_sp;
+}
+
 static lldb::VariableSP DILFindVariable(ConstString name,
                                         VariableList &variable_list) {
   lldb::VariableSP exact_match;
@@ -499,16 +536,6 @@ Interpreter::Visit(const BitFieldExtractionNode *node) {
   return child_valobj_sp;
 }
 
-static llvm::Expected<lldb::TypeSystemSP>
-GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) {
-  SymbolContext symbol_context =
-      ctx->GetSymbolContext(lldb::eSymbolContextCompUnit);
-  lldb::LanguageType language = symbol_context.comp_unit->GetLanguage();
-
-  symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule);
-  return symbol_context.module_sp->GetTypeSystemForLanguage(language);
-}
-
 static CompilerType GetBasicType(lldb::TypeSystemSP type_system,
                                  lldb::BasicType basic_type) {
   if (type_system)
@@ -559,7 +586,7 @@ Interpreter::PickIntegerType(lldb::TypeSystemSP type_system,
 llvm::Expected<lldb::ValueObjectSP>
 Interpreter::Visit(const IntegerLiteralNode *node) {
   llvm::Expected<lldb::TypeSystemSP> type_system =
-      GetTypeSystemFromCU(m_exe_ctx_scope);
+      DILGetTypeSystemFromCU(m_exe_ctx_scope);
   if (!type_system)
     return type_system.takeError();
 
@@ -583,7 +610,7 @@ Interpreter::Visit(const IntegerLiteralNode *node) {
 llvm::Expected<lldb::ValueObjectSP>
 Interpreter::Visit(const FloatLiteralNode *node) {
   llvm::Expected<lldb::TypeSystemSP> type_system =
-      GetTypeSystemFromCU(m_exe_ctx_scope);
+      DILGetTypeSystemFromCU(m_exe_ctx_scope);
   if (!type_system)
     return type_system.takeError();
 
@@ -602,4 +629,238 @@ Interpreter::Visit(const FloatLiteralNode *node) {
                                                   "result");
 }
 
+llvm::Expected<CompilerType> Interpreter::VerifyCStyleCastType(
+    lldb::ValueObjectSP &operand, CompilerType &op_type,
+    CompilerType target_type, CastPromoKind &promo_kind,
+    CStyleCastKind &cast_kind, int location) {
+
+  promo_kind = CastPromoKind::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()) {
+      // C-style cast from pointer to float/double is not allowed.
+      if (target_type.IsFloat()) {
+        std::string errMsg = llvm::formatv(
+            "C-style 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.value();
+        type_byte_size = *temp;
+      if (auto temp = op_type.GetByteSize(m_exe_ctx_scope.get()))
+        // rhs_type_byte_size = temp.value();
+        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 = CastPromoKind::eArithmetic;
+  } else if (target_type.IsEnumerationType()) {
+    // Cast to enum type.
+    if (!op_type.IsScalarType() && !op_type.IsEnumerationType()) {
+      std::string errMsg = llvm::formatv(
+          "C-style 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 = CStyleCastKind::eEnumeration;
+
+  } else 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 = CastPromoKind::ePointer;
+
+  } else 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(
+          "C-style 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 = CStyleCastKind::eNullptr;
+
+  } else if (target_type.IsReferenceType()) {
+    // Cast to a reference type.
+    cast_kind = CStyleCastKind::eReference;
+  } else {
+    // 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());
+  }
+
+  return target_type;
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const CStyleCastNode *node) {
+  auto operand_or_err = Evaluate(node->GetOperand());
+  if (!operand_or_err)
+    return operand_or_err;
+
+  lldb::ValueObjectSP operand = *operand_or_err;
+  CompilerType op_type = operand->GetCompilerType();
+  CStyleCastKind cast_kind = CStyleCastKind::eNone;
+  CastPromoKind promo_kind = CastPromoKind::eNone;
+
+  auto type_or_err =
+      VerifyCStyleCastType(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 CStyleCastKind::eEnumeration: {
+    if (!target_type.IsEnumerationType()) {
+      std::string errMsg = "invalid ast: target type should be an 
enumeration.";
+      return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+                                                  node->GetLocation());
+    }
+    if (op_type.IsFloat())
+      return operand->CastToEnumType(target_type);
+
+    if (op_type.IsInteger() || op_type.IsEnumerationType())
+      return operand->CastToEnumType(target_type);
+
+    std::string errMsg =
+        "invalid ast: operand is not convertible to enumeration type";
+    return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+                                                node->GetLocation());
+    // return error.ToError();
+  }
+  case CStyleCastKind::eNullptr: {
+    if (target_type.GetCanonicalType().GetBasicTypeEnumeration() !=
+        lldb::eBasicTypeNullPtr) {
+      std::string errMsg = "invalid ast: target type should be a nullptr_t.";
+      return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+                                                  node->GetLocation());
+    }
+    return ValueObject::CreateValueObjectFromNullptr(m_target, target_type,
+                                                     "result");
+  }
+  case CStyleCastKind::eReference: {
+    lldb::ValueObjectSP operand_sp(
+        GetDynamicOrSyntheticValue(operand, m_use_dynamic, m_use_synthetic));
+    return lldb::ValueObjectSP(
+        operand_sp->Cast(target_type.GetNonReferenceType()));
+  }
+  case CStyleCastKind::eNone: {
+    switch (promo_kind) {
+    case CastPromoKind::eArithmetic: {
+      if (target_type.GetCanonicalType().GetBasicTypeEnumeration() ==
+          lldb::eBasicTypeInvalid) {
+        std::string errMsg = "invalid ast: target type should be a basic 
type.";
+        return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+                                                    node->GetLocation());
+      }
+      // Pick an appropriate cast.
+      if (op_type.IsPointerType() || op_type.IsNullPtrType()) {
+        return operand->CastToBasicType(target_type);
+      }
+      if (op_type.IsScalarType()) {
+        return operand->CastToBasicType(target_type);
+      }
+      if (op_type.IsEnumerationType()) {
+        return operand->CastToBasicType(target_type);
+      }
+      std::string errMsg =
+          "invalid ast: operand is not convertible to arithmetic type";
+      return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+                                                  node->GetLocation());
+    }
+    case CastPromoKind::ePointer: {
+      if (!target_type.IsPointerType()) {
+        std::string errMsg = "invalid ast: target type should be a pointer";
+        return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+                                                    node->GetLocation());
+      }
+      uint64_t addr =
+          op_type.IsArrayType()
+              ? operand->GetLoadAddress()
+              : (op_type.IsSigned() ? operand->GetValueAsSigned(0)
+                                    : operand->GetValueAsUnsigned(0));
+      llvm::StringRef name = "result";
+      ExecutionContext exe_ctx(m_target.get(), false);
+      return ValueObject::CreateValueObjectFromAddress(name, addr, exe_ctx,
+                                                       target_type,
+                                                       /* do_deref */ false);
+    }
+    case CastPromoKind::eNone: {
+      return lldb::ValueObjectSP();
+    }
+    } // switch promo_kind
+  } // case CStyleCastKind::eNone
+  } // switch cast_kind
+  std::string errMsg = "invalid ast: unexpected c-style cast kind";
+  return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+                                              node->GetLocation());
+}
+
 } // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index 8c4f7fdb25bea..578ee99053201 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -12,7 +12,9 @@
 
//===----------------------------------------------------------------------===//
 
 #include "lldb/ValueObject/DILParser.h"
+#include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/LanguageRuntime.h"
 #include "lldb/Utility/DiagnosticsRendering.h"
 #include "lldb/ValueObject/DILAST.h"
 #include "lldb/ValueObject/DILEval.h"
@@ -42,6 +44,83 @@ DILDiagnosticError::DILDiagnosticError(llvm::StringRef expr,
   m_detail.rendered = std::move(rendered_msg);
 }
 
+llvm::Expected<lldb::TypeSystemSP>
+DILGetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) {
+  SymbolContext symbol_context =
+      ctx->GetSymbolContext(lldb::eSymbolContextCompUnit);
+  lldb::LanguageType language = symbol_context.comp_unit->GetLanguage();
+
+  symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule);
+  return symbol_context.module_sp->GetTypeSystemForLanguage(language);
+}
+
+CompilerType
+ResolveTypeByName(const std::string &name,
+                  std::shared_ptr<ExecutionContextScope> ctx_scope) {
+  // Internally types don't have global scope qualifier in their names and
+  // LLDB doesn't support queries with it too.
+  llvm::StringRef name_ref(name);
+
+  if (name_ref.starts_with("::"))
+    name_ref = name_ref.drop_front(2);
+
+  std::vector<CompilerType> result_type_list;
+  lldb::TargetSP target_sp = ctx_scope->CalculateTarget();
+  const char *type_name = name_ref.data();
+  if (type_name && type_name[0] && target_sp) {
+    ModuleList &images = target_sp->GetImages();
+    ConstString const_type_name(type_name);
+    TypeQuery query(type_name);
+    TypeResults results;
+    images.FindTypes(nullptr, query, results);
+    for (const lldb::TypeSP &type_sp : results.GetTypeMap().Types())
+      if (type_sp)
+        result_type_list.push_back(type_sp->GetFullCompilerType());
+
+    if (auto process_sp = target_sp->GetProcessSP()) {
+      for (auto *runtime : process_sp->GetLanguageRuntimes()) {
+        if (auto *vendor = runtime->GetDeclVendor()) {
+          auto types = vendor->FindTypes(const_type_name, UINT32_MAX);
+          for (auto type : types)
+            result_type_list.push_back(type);
+        }
+      }
+    }
+
+    if (result_type_list.empty()) {
+      for (auto type_system_sp : target_sp->GetScratchTypeSystems())
+        if (auto compiler_type =
+                type_system_sp->GetBuiltinTypeByName(const_type_name))
+          result_type_list.push_back(compiler_type);
+    }
+  }
+
+  // We've found multiple types, try finding the "correct" one.
+  CompilerType full_match;
+  std::vector<CompilerType> partial_matches;
+
+  for (uint32_t i = 0; i < result_type_list.size(); ++i) {
+    CompilerType type = result_type_list[i];
+    llvm::StringRef type_name_ref = type.GetTypeName().GetStringRef();
+    ;
+
+    if (type_name_ref == name_ref)
+      full_match = type;
+    else if (type_name_ref.ends_with(name_ref))
+      partial_matches.push_back(type);
+  }
+
+  // Full match is always correct.
+  if (full_match.IsValid())
+    return full_match;
+
+  // If we have partial matches, pick a "random" one.
+  if (partial_matches.size() > 0)
+    return partial_matches.back();
+
+  return {};
+}
+
 llvm::Expected<ASTNodeUP>
 DILParser::Parse(llvm::StringRef dil_input_expr, DILLexer lexer,
                  std::shared_ptr<StackFrame> frame_sp,
@@ -80,15 +159,64 @@ ASTNodeUP DILParser::Run() {
 // Parse an expression.
 //
 //  expression:
-//    unary_expression
+//    cast_expression
+//
+ASTNodeUP DILParser::ParseExpression() { return ParseCastExpression(); }
+
+// Parse a cast_expression.
 //
-ASTNodeUP DILParser::ParseExpression() { return ParseUnaryExpression(); }
+// cast_expression:
+//   unary_expression
+//   "(" type_id ")" cast_expression
+
+ASTNodeUP DILParser::ParseCastExpression() {
+  // This can be a C-style cast, try parsing the contents as a type 
declaration.
+  if (CurToken().Is(Token::l_paren)) {
+    Token token = CurToken();
+    uint32_t loc = token.GetLocation();
+
+    // Enable lexer backtracking, so that we can rollback in case it's not
+    // actually a type declaration.
+
+    // Start tentative parsing (save token location/idx, for possible 
rollback).
+    uint32_t save_token_idx = m_dil_lexer.GetCurrentTokenIdx();
+
+    // Consume the token only after enabling the backtracking.
+    m_dil_lexer.Advance();
+
+    // Try parsing the type declaration. If the returned value is not valid,
+    // then we should rollback and try parsing the expression.
+    auto type_id = ParseTypeId();
+    if (type_id) {
+      // Successfully parsed the type declaration. Commit the backtracked
+      // tokens and parse the cast_expression.
+
+      if (!type_id.value().IsValid())
+        return std::make_unique<ErrorNode>();
+
+      Expect(Token::r_paren);
+      m_dil_lexer.Advance();
+      auto rhs = ParseCastExpression();
+
+      // return BuildCStyleCast(type_id.value(), std::move(rhs),
+      //                        token.GetLocation());
+      return std::make_unique<CStyleCastNode>(
+          loc, type_id.value(), std::move(rhs), CStyleCastKind::eNone);
+    }
+
+    // Failed to parse the contents of the parentheses as a type declaration.
+    // Rollback the lexer and try parsing it as unary_expression.
+    TentativeParsingRollback(save_token_idx);
+  }
+
+  return ParseUnaryExpression();
+}
 
 // Parse an unary_expression.
 //
 //  unary_expression:
 //    postfix_expression
-//    unary_operator expression
+//    unary_operator cast_expression
 //
 //  unary_operator:
 //    "&"
@@ -99,7 +227,7 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
     Token token = CurToken();
     uint32_t loc = token.GetLocation();
     m_dil_lexer.Advance();
-    auto rhs = ParseExpression();
+    auto rhs = ParseCastExpression();
     switch (token.GetKind()) {
     case Token::star:
       return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Deref,
@@ -271,6 +399,236 @@ std::string DILParser::ParseNestedNameSpecifier() {
   }
 }
 
+// Parse a type_id.
+//
+//  type_id:
+//    type_specifier_seq [abstract_declarator]
+std::optional<CompilerType> DILParser::ParseTypeId(bool must_be_type_id) {
+  uint32_t type_loc = CurToken().GetLocation();
+  TypeDeclaration type_decl;
+
+  // type_specifier_seq is required here, start with trying to parse it.
+  ParseTypeSpecifierSeq(&type_decl);
+
+  if (type_decl.IsEmpty()) {
+    // TODO: Should we bail out if `must_be_type_id` is set?
+    return {};
+  }
+
+  if (type_decl.m_has_error) {
+    if (type_decl.m_is_builtin) {
+      return {};
+    }
+
+    assert(type_decl.m_is_user_type && "type_decl must be a user type");
+    // Found something looking like a user type, but failed to parse it.
+    // Return invalid type if we expect to have a type here, otherwise nullopt.
+    if (must_be_type_id) {
+      return {};
+    }
+    return {};
+  }
+
+  // Try to resolve the base type.
+  CompilerType type;
+  if (type_decl.m_is_builtin) {
+    llvm::Expected<lldb::TypeSystemSP> type_system =
+        DILGetTypeSystemFromCU(m_ctx_scope);
+    if (!type_system)
+      return {};
+    // type = GetBasicType(m_ctx_scope, type_decl.GetBasicType());
+    // type = DILGetBasicType(*type_system, type_decl.GetBasicType());
+    type = (*type_system).get()->GetBasicTypeFromAST(type_decl.GetBasicType());
+    assert(type.IsValid() && "cannot resolve basic type");
+
+  } else {
+    assert(type_decl.m_is_user_type && "type_decl must be a user type");
+    type = ResolveTypeByName(type_decl.m_user_typename, m_ctx_scope);
+    if (!type.IsValid()) {
+      if (must_be_type_id) {
+        BailOut(
+            llvm::formatv("unknown type name '{0}'", 
type_decl.m_user_typename),
+            type_loc, CurToken().GetSpelling().length());
+        return {};
+      }
+      return {};
+    }
+
+    if (LookupIdentifier(type_decl.m_user_typename, m_ctx_scope,
+                         m_use_dynamic)) {
+      // Same-name identifiers should be preferred over typenames.
+      // TODO: Make type accessible with 'class', 'struct' and 'union' 
keywords.
+      if (must_be_type_id) {
+        BailOut(llvm::formatv(
+                    "must use '{0}' tag to refer to type '{1}' in this scope",
+                    type.GetTypeTag(), type_decl.m_user_typename),
+                type_loc, CurToken().GetSpelling().length());
+        return {};
+      }
+      return {};
+    }
+
+    if (LookupGlobalIdentifier(type_decl.m_user_typename, m_ctx_scope,
+                               m_ctx_scope->CalculateTarget(), m_use_dynamic)) 
{
+      // Same-name identifiers should be preferred over typenames.
+      // TODO: Make type accessible with 'class', 'struct' and 'union' 
keywords.
+      if (must_be_type_id) {
+        BailOut(llvm::formatv(
+                    "must use '{0}' tag to refer to type '{1}' in this scope",
+                    type.GetTypeTag(), type_decl.m_user_typename),
+                type_loc, CurToken().GetSpelling().length());
+        return {};
+      }
+      return {};
+    }
+  }
+
+  //
+  //  abstract_declarator:
+  //    ptr_operator [abstract_declarator]
+  //
+  std::vector<Token> ptr_operators;
+  while (CurToken().IsOneOf({Token::star, Token::amp})) {
+    Token tok = CurToken();
+    ptr_operators.push_back(std::move(tok));
+    m_dil_lexer.Advance();
+  }
+  type = ResolveTypeDeclarators(type, ptr_operators);
+
+  return type;
+}
+
+// Parse a type_specifier_seq.
+//
+//  type_specifier_seq:
+//    type_specifier [type_specifier_seq]
+//
+void DILParser::ParseTypeSpecifierSeq(TypeDeclaration *type_decl) {
+  while (true) {
+    bool type_specifier = ParseTypeSpecifier(type_decl);
+    if (!type_specifier) {
+      break;
+    }
+  }
+}
+
+// Parse a type_specifier.
+//
+//  type_specifier:
+//    simple_type_specifier
+//    cv_qualifier
+//
+//  simple_type_specifier:
+//    ["::"] [nested_name_specifier] type_name
+//    "char"
+//    "bool"
+//    "integer"
+//    "float"
+//    "void"
+//
+// Returns TRUE if a type_specifier was successfully parsed at this location.
+//
+bool DILParser::ParseTypeSpecifier(TypeDeclaration *type_decl) {
+  if (IsSimpleTypeSpecifierKeyword(CurToken())) {
+    // User-defined typenames can't be combined with builtin keywords.
+    if (type_decl->m_is_user_type) {
+      BailOut("cannot combine with previous declaration specifier",
+              CurToken().GetLocation(), CurToken().GetSpelling().length());
+      type_decl->m_has_error = true;
+      return false;
+    }
+
+    // From now on this type declaration must describe a builtin type.
+    // TODO: Should this be allowed -- `unsigned myint`?
+    type_decl->m_is_builtin = true;
+
+    if (!HandleSimpleTypeSpecifier(type_decl)) {
+      type_decl->m_has_error = true;
+      return false;
+    }
+    m_dil_lexer.Advance();
+    return true;
+  }
+
+  // The type_specifier must be a user-defined type. Try parsing a
+  // simple_type_specifier.
+  {
+    // Try parsing optional global scope operator.
+    bool global_scope = false;
+    if (CurToken().Is(Token::coloncolon)) {
+      global_scope = true;
+      m_dil_lexer.Advance();
+    }
+
+    uint32_t loc = CurToken().GetLocation();
+
+    // Try parsing optional nested_name_specifier.
+    auto nested_name_specifier = ParseNestedNameSpecifier();
+
+    // Try parsing required type_name.
+    auto type_name = ParseTypeName();
+
+    // If there is a type_name, then this is indeed a simple_type_specifier.
+    // Global and qualified (namespace/class) scopes can be empty, since 
they're
+    // optional. In this case type_name is type we're looking for.
+    if (!type_name.empty()) {
+      // User-defined typenames can't be combined with builtin keywords.
+      if (type_decl->m_is_builtin) {
+        BailOut("cannot combine with previous declaration specifier", loc,
+                CurToken().GetSpelling().length());
+        type_decl->m_has_error = true;
+        return false;
+      }
+      // There should be only one user-defined typename.
+      if (type_decl->m_is_user_type) {
+        BailOut("two or more data types in declaration of 'type name'", loc,
+                CurToken().GetSpelling().length());
+        type_decl->m_has_error = true;
+        return false;
+      }
+
+      // Construct the fully qualified typename.
+      type_decl->m_is_user_type = true;
+      type_decl->m_user_typename =
+          llvm::formatv("{0}{1}{2}", global_scope ? "::" : "",
+                        nested_name_specifier, type_name);
+      return true;
+    }
+  }
+
+  // No type_specifier was found here.
+  return false;
+}
+
+// Parse a type_name.
+//
+//  type_name:
+//    class_name
+//    enum_name
+//    typedef_name
+//
+//  class_name
+//    identifier
+//
+//  enum_name
+//    identifier
+//
+//  typedef_name
+//    identifier
+//
+std::string DILParser::ParseTypeName() {
+  // Typename always starts with an identifier.
+  if (CurToken().IsNot(Token::identifier)) {
+    return "";
+  }
+
+  // Otherwise look for a class_name, enum_name or a typedef_name.
+  std::string identifier = CurToken().GetSpelling();
+  m_dil_lexer.Advance();
+
+  return identifier;
+}
+
 // Parse an id_expression.
 //
 //  id_expression:
@@ -336,6 +694,204 @@ std::string DILParser::ParseUnqualifiedId() {
   return identifier;
 }
 
+CompilerType
+DILParser::ResolveTypeDeclarators(CompilerType type,
+                                  const std::vector<Token> &ptr_operators) {
+  CompilerType bad_type;
+  // Resolve pointers/references.
+  for (Token tk : ptr_operators) {
+    uint32_t loc = tk.GetLocation();
+    if (tk.GetKind() == Token::star) {
+      // Pointers to reference types are forbidden.
+      if (type.IsReferenceType()) {
+        BailOut(llvm::formatv("'type name' declared as a pointer to a "
+                              "reference of type {0}",
+                              type.TypeDescription()),
+                loc, CurToken().GetSpelling().length());
+        return bad_type;
+      }
+      // Get pointer type for the base type: e.g. int* -> int**.
+      type = type.GetPointerType();
+
+    } else if (tk.GetKind() == Token::amp) {
+      // References to references are forbidden.
+      if (type.IsReferenceType()) {
+        BailOut("type name declared as a reference to a reference", loc,
+                CurToken().GetSpelling().length());
+        return bad_type;
+      }
+      // Get reference type for the base type: e.g. int -> int&.
+      type = type.GetLValueReferenceType();
+    }
+  }
+
+  return type;
+}
+
+bool DILParser::IsSimpleTypeSpecifierKeyword(Token token) const {
+  if (token.GetKind() != Token::identifier)
+    return false;
+  if (token.GetSpelling() == "bool" || token.GetSpelling() == "char" ||
+      token.GetSpelling() == "int" || token.GetSpelling() == "float" ||
+      token.GetSpelling() == "void" || token.GetSpelling() == "short" ||
+      token.GetSpelling() == "long" || token.GetSpelling() == "signed" ||
+      token.GetSpelling() == "unsigned" || token.GetSpelling() == "double")
+    return true;
+  return false;
+}
+
+bool DILParser::HandleSimpleTypeSpecifier(TypeDeclaration *type_decl) {
+  using TypeSpecifier = TypeDeclaration::TypeSpecifier;
+  using SignSpecifier = TypeDeclaration::SignSpecifier;
+
+  TypeSpecifier type_spec = type_decl->m_type_specifier;
+  uint32_t loc = CurToken().GetLocation();
+  std::string kind = CurToken().GetSpelling();
+
+  // switch (kind) {
+  if (kind == "int") {
+    // case Token::kw_int: {
+    //  "int" can have signedness and be combined with "short", "long" and
+    //  "long long" (but not with another "int").
+    if (type_decl->m_has_int_specifier) {
+      BailOut("cannot combine with previous 'int' declaration specifier", loc,
+              CurToken().GetSpelling().length());
+      return false;
+    }
+    if (type_spec == TypeSpecifier::kShort ||
+        type_spec == TypeSpecifier::kLong ||
+        type_spec == TypeSpecifier::kLongLong) {
+      type_decl->m_has_int_specifier = true;
+      return true;
+    } else if (type_spec == TypeSpecifier::kUnknown) {
+      type_decl->m_type_specifier = TypeSpecifier::kInt;
+      type_decl->m_has_int_specifier = true;
+      return true;
+    }
+    BailOut(llvm::formatv(
+                "cannot combine with previous '{0}' declaration specifier",
+                type_spec),
+            loc, CurToken().GetSpelling().length());
+    return false;
+  }
+
+  if (kind == "long") {
+    // "long" can have signedness and be combined with "int" or "long" to
+    // form "long long".
+    if (type_spec == TypeSpecifier::kUnknown ||
+        type_spec == TypeSpecifier::kInt) {
+      type_decl->m_type_specifier = TypeSpecifier::kLong;
+      return true;
+    } else if (type_spec == TypeSpecifier::kLong) {
+      type_decl->m_type_specifier = TypeSpecifier::kLongLong;
+      return true;
+    } else if (type_spec == TypeSpecifier::kDouble) {
+      type_decl->m_type_specifier = TypeSpecifier::kLongDouble;
+      return true;
+    }
+    BailOut(llvm::formatv(
+                "cannot combine with previous '{0}' declaration specifier",
+                type_spec),
+            loc, CurToken().GetSpelling().length());
+    return false;
+  }
+
+  if (kind == "short") {
+    // "short" can have signedness and be combined with "int".
+    if (type_spec == TypeSpecifier::kUnknown ||
+        type_spec == TypeSpecifier::kInt) {
+      type_decl->m_type_specifier = TypeSpecifier::kShort;
+      return true;
+    }
+    BailOut(llvm::formatv(
+                "cannot combine with previous '{0}' declaration specifier",
+                type_spec),
+            loc, CurToken().GetSpelling().length());
+    return false;
+  }
+
+  if (kind == "char") {
+    // "char" can have signedness, but it cannot be combined with any other
+    // type specifier.
+    if (type_spec == TypeSpecifier::kUnknown) {
+      type_decl->m_type_specifier = TypeSpecifier::kChar;
+      return true;
+    }
+    BailOut(llvm::formatv(
+                "cannot combine with previous '{0}' declaration specifier",
+                type_spec),
+            loc, CurToken().GetSpelling().length());
+    return false;
+  }
+
+  if (kind == "double") {
+    // "double" can be combined with "long" to form "long double", but it
+    // cannot be combined with signedness specifier.
+    if (type_decl->m_sign_specifier != SignSpecifier::kUnknown) {
+      BailOut("'double' cannot be signed or unsigned", loc,
+              CurToken().GetSpelling().length());
+      return false;
+    }
+    if (type_spec == TypeSpecifier::kUnknown) {
+      type_decl->m_type_specifier = TypeSpecifier::kDouble;
+      return true;
+    } else if (type_spec == TypeSpecifier::kLong) {
+      type_decl->m_type_specifier = TypeSpecifier::kLongDouble;
+      return true;
+    }
+    BailOut(llvm::formatv(
+                "cannot combine with previous '{0}' declaration specifier",
+                type_spec),
+            loc, CurToken().GetSpelling().length());
+    return false;
+  }
+
+  if (kind == "bool" || kind == "void" || kind == "float") {
+    // These types cannot have signedness or be combined with any other type
+    // specifiers.
+    if (type_decl->m_sign_specifier != SignSpecifier::kUnknown) {
+      BailOut(llvm::formatv("'{0}' cannot be signed or unsigned", kind), loc,
+              CurToken().GetSpelling().length());
+      return false;
+    }
+    if (type_spec != TypeSpecifier::kUnknown) {
+      BailOut(llvm::formatv(
+                  "cannot combine with previous '{0}' declaration specifier",
+                  type_spec),
+              loc, CurToken().GetSpelling().length());
+    }
+    if (kind == "bool")
+      type_decl->m_type_specifier = TypeSpecifier::kBool;
+    else if (kind == "void")
+      type_decl->m_type_specifier = TypeSpecifier::kVoid;
+    else if (kind == "float")
+      type_decl->m_type_specifier = TypeSpecifier::kFloat;
+    return true;
+  }
+
+  if (kind == "signed" || kind == "unsigned") {
+    // "signed" and "unsigned" cannot be combined with another signedness
+    // specifier.
+    if (type_spec == TypeSpecifier::kVoid ||
+        type_spec == TypeSpecifier::kBool ||
+        type_spec == TypeSpecifier::kFloat ||
+        type_spec == TypeSpecifier::kDouble ||
+        type_spec == TypeSpecifier::kLongDouble) {
+      BailOut(llvm::formatv("'{0}' cannot be signed or unsigned", type_spec),
+              loc, CurToken().GetSpelling().length());
+      return false;
+    }
+
+    type_decl->m_sign_specifier =
+        (kind == "signed") ? SignSpecifier::kSigned : SignSpecifier::kUnsigned;
+    return true;
+  }
+
+  BailOut(llvm::formatv("invalid simple type specifier kind"), loc,
+          CurToken().GetSpelling().length());
+  return false;
+}
+
 void DILParser::BailOut(const std::string &error, uint32_t loc,
                         uint16_t err_len) {
   if (m_error)
@@ -444,4 +1000,74 @@ void DILParser::Expect(Token::Kind kind) {
   }
 }
 
+void DILParser::ExpectOneOf(std::vector<Token::Kind> kinds_vec) {
+  if (!CurToken().IsOneOf(kinds_vec)) {
+    BailOut(llvm::formatv("expected any of ({0}), got: {1}",
+                          llvm::iterator_range(kinds_vec), CurToken()),
+            CurToken().GetLocation(), CurToken().GetSpelling().length());
+  }
+}
+
+lldb::BasicType TypeDeclaration::GetBasicType() const {
+  if (!m_is_builtin)
+    return lldb::eBasicTypeInvalid;
+
+  if (m_sign_specifier == SignSpecifier::kSigned &&
+      m_type_specifier == TypeSpecifier::kChar) {
+    // "signed char" isn't the same as "char".
+    return lldb::eBasicTypeSignedChar;
+  }
+
+  if (m_sign_specifier == SignSpecifier::kUnsigned) {
+    switch (m_type_specifier) {
+    // "unsigned" is "unsigned int"
+    case TypeSpecifier::kUnknown:
+      return lldb::eBasicTypeUnsignedInt;
+    case TypeSpecifier::kChar:
+      return lldb::eBasicTypeUnsignedChar;
+    case TypeSpecifier::kShort:
+      return lldb::eBasicTypeUnsignedShort;
+    case TypeSpecifier::kInt:
+      return lldb::eBasicTypeUnsignedInt;
+    case TypeSpecifier::kLong:
+      return lldb::eBasicTypeUnsignedLong;
+    case TypeSpecifier::kLongLong:
+      return lldb::eBasicTypeUnsignedLongLong;
+    default:
+      // assert(false && "unknown unsigned basic type");
+      return lldb::eBasicTypeInvalid;
+    }
+  }
+
+  switch (m_type_specifier) {
+  case TypeSpecifier::kUnknown:
+    // "signed" is "signed int"
+    if (m_sign_specifier != SignSpecifier::kSigned)
+      return lldb::eBasicTypeInvalid;
+    return lldb::eBasicTypeInt;
+  case TypeSpecifier::kVoid:
+    return lldb::eBasicTypeVoid;
+  case TypeSpecifier::kBool:
+    return lldb::eBasicTypeBool;
+  case TypeSpecifier::kChar:
+    return lldb::eBasicTypeChar;
+  case TypeSpecifier::kShort:
+    return lldb::eBasicTypeShort;
+  case TypeSpecifier::kInt:
+    return lldb::eBasicTypeInt;
+  case TypeSpecifier::kLong:
+    return lldb::eBasicTypeLong;
+  case TypeSpecifier::kLongLong:
+    return lldb::eBasicTypeLongLong;
+  case TypeSpecifier::kFloat:
+    return lldb::eBasicTypeFloat;
+  case TypeSpecifier::kDouble:
+    return lldb::eBasicTypeDouble;
+  case TypeSpecifier::kLongDouble:
+    return lldb::eBasicTypeLongDouble;
+  }
+
+  return lldb::eBasicTypeInvalid;
+}
+
 } // namespace lldb_private::dil
diff --git 
a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
 
b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
index 0f6618fe47984..85899caaa7433 100644
--- 
a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
+++ 
b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py
@@ -28,4 +28,5 @@ def test_frame_var(self):
         self.expect_var_path("a", value="1")
         self.expect_var_path("b", value="2")
         self.expect_var_path("c", value="'\\xfd'")
+        self.expect_var_path("(int)c", value="-3")
         self.expect_var_path("s", value="4")
diff --git a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/Makefile 
b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/Makefile
new file mode 100644
index 0000000000000..0165eb73f3073
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/Makefile
@@ -0,0 +1,6 @@
+CXX_SOURCES := main.cpp
+#CXXFLAGS_EXTRAS := -std=c++14
+
+USE_LIBSTDCPP := 1
+
+include Makefile.rules
diff --git 
a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
 
b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
new file mode 100644
index 0000000000000..001e39d8a9137
--- /dev/null
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/TestFrameVarDILCStyleCast.py
@@ -0,0 +1,233 @@
+"""
+Make sure 'frame var' using DIL parser/evaultor works for C-Style casts.
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+import os
+import shutil
+import time
+
+class TestFrameVarDILCStyleCast(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def expect_var_path(self, expr, compare_to_framevar=False, value=None, 
type=None):
+        value_dil = super().expect_var_path(expr, value=value, type=type)
+        if compare_to_framevar:
+            self.runCmd("settings set target.experimental.use-DIL false")
+            value_frv = super().expect_var_path(expr, value=value, type=type)
+            self.runCmd("settings set target.experimental.use-DIL true")
+            self.assertEqual(value_dil.GetValue(), value_frv.GetValue())
+
+    def test_type_cast(self):
+        self.build()
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.runCmd("settings set target.experimental.use-DIL true")
+
+        # TestCStyleCastBUiltins
+
+        self.expect_var_path("(int)1", value="1", type="int")
+        self.expect_var_path("(long long)1", value="1", type="long long")
+        self.expect_var_path("(unsigned long)1", value="1", type="unsigned 
long")
+        self.expect_var_path("(char*)1", value="0x0000000000000001", 
type="char *")
+        self.expect_var_path("(long long**)1", value="0x0000000000000001", 
type="long long **")
+
+        self.expect("frame variable '(long&*)1'", error=True,
+                    substrs=["'type name' declared as a pointer to a reference"
+                             " of type 'long &'"])
+
+        self.expect("frame variable '(long& &)1'", error=True,
+                    substrs=["type name declared as a reference to a 
reference"])
+
+        self.expect("frame variable '(long 1)1'", error=True,
+                    substrs=["expected 'r_paren', got: <'1' "
+                             "(integer_constant)>"])
+
+        # TestCStyleCastBasicType
+
+        # Test with integer literals.
+        self.expect_var_path("(char)1", type="char", value="'\\x01'")
+        self.expect_var_path("(long long)1", type="long long", value="1")
+        self.expect_var_path("(short)65534", type="short", value="-2")
+        self.expect_var_path("(unsigned short)100000",
+                    type="unsigned short", value="34464")
+        self.expect_var_path("(float)1", type="float", value="1")
+        self.expect_var_path("(float)1.1", type="float", value="1.10000002")
+        self.expect_var_path("(float)1.1f", type="float", value="1.10000002")
+        self.expect_var_path("(double)1", type="double", value="1")
+        self.expect_var_path("(double)1.1",
+                    type="double", value="1.1000000000000001")
+        self.expect_var_path("(double)1.1f",
+                    type="double", value="1.1000000238418579")
+        self.expect_var_path("(int)1.1", type="int", value="1")
+        self.expect_var_path("(int)1.1f", type="int", value="1")
+        self.expect_var_path("(long)1.1", type="long", value="1")
+        self.expect_var_path("(bool)0", type="bool", value="false")
+        self.expect_var_path("(bool)0.0", type="bool", value="false")
+        self.expect_var_path("(bool)0.0f", type="bool", value="false")
+        self.expect_var_path("(bool)3", type="bool", value="true")
+
+        self.expect("frame variable '&(int)1'", error=True,
+                    substrs=["'result' doesn't have a valid address"])
+
+        # Test with variables.
+        self.expect_var_path("(char)a", type="char", value="'\\x01'")
+        self.expect_var_path("(unsigned char)na", type="unsigned char", 
value="'\\xff'")
+        self.expect_var_path("(short)na", type="short", value="-1")
+        self.expect_var_path("(long long)a", type="long long", value="1")
+        self.expect_var_path("(float)a", type="float", value="1")
+        self.expect_var_path("(float)f", type="float", value="1.10000002")
+        self.expect_var_path("(double)f",
+                    type="double", value="1.1000000238418579")
+        self.expect_var_path("(int)f", type="int", value="1")
+        self.expect_var_path("(long)f", type="long", value="1")
+        self.expect_var_path("(bool)finf", type="bool", value="true")
+        self.expect_var_path("(bool)fnan", type="bool", value="true")
+        self.expect_var_path("(bool)fsnan", type="bool", value="true")
+        self.expect_var_path("(bool)fmax", type="bool", value="true")
+        self.expect_var_path("(bool)fdenorm", type="bool", value="true")
+        self.expect("frame variable '(int)ns_foo_'", error=True,
+                    substrs=["cannot convert 'ns::Foo' to 'int' without a "
+                             "conversion operator"])
+
+        # Test with typedefs and namespaces.
+        self.expect_var_path("(myint)1", type="myint", value="1")
+        self.expect_var_path("(myint)1LL", type="myint", value="1")
+        self.expect_var_path("(ns::myint)1", type="ns::myint", value="1")
+        self.expect_var_path("(::ns::myint)1", type="ns::myint", value="1")
+        self.expect_var_path("(::ns::myint)myint_", type="ns::myint", 
value="1")
+
+        self.expect_var_path("(int)myint_", type="int", value="1")
+        self.expect_var_path("(int)ns_myint_", type="int", value="2")
+        self.expect_var_path("(long long)myint_", type="long long", value="1")
+        self.expect_var_path("(long long)ns_myint_", type="long long", 
value="2")
+        self.expect_var_path("(::ns::myint)myint_", type="ns::myint", 
value="1")
+
+        self.expect_var_path("(ns::inner::mydouble)1", 
type="ns::inner::mydouble", value="1")
+        self.expect_var_path("(::ns::inner::mydouble)1.2",
+                    type="ns::inner::mydouble", value="1.2")
+        self.expect_var_path("(ns::inner::mydouble)myint_",
+                    type="ns::inner::mydouble", value="1")
+        self.expect_var_path("(::ns::inner::mydouble)ns_inner_mydouble_",
+                    type="ns::inner::mydouble", value="1.2")
+        self.expect_var_path("(myint)ns_inner_mydouble_",
+                    type="myint", value="1")
+
+        # Test with pointers and arrays.
+        self.expect_var_path("(long long)ap", type="long long")
+        self.expect_var_path("(unsigned long long)vp", type="unsigned long 
long")
+        self.expect_var_path("(long long)arr", type="long long")
+        self.expect_var_path("(bool)ap", type="bool", value="true")
+        self.expect_var_path("(bool)(int*)0x00000000",
+                    type="bool", value="false")
+        self.expect_var_path("(bool)arr", type="bool", value="true")
+        self.expect("frame variable '(char)ap'", error=True,
+                    substrs=["cast from pointer to smaller type 'char' loses "
+                             "information"])
+        Is32Bit = False
+        if self.target().GetAddressByteSize() == 4:
+          Is32Bit = True;
+
+        if Is32Bit:
+          self.expect("frame variable '(int)arr'", error=True,
+                      substrs=["cast from pointer to smaller type 'int' loses"
+                               " information"])
+        else:
+          self.expect("frame variable '(int)arr'", error=True,
+                      substrs=["cast from pointer to smaller type 'int' loses"
+                               " information"])
+
+        self.expect("frame variable '(float)ap'", error=True,
+                    substrs=["C-style cast from 'int *' to 'float' is not "
+                             "allowed"])
+        self.expect("frame variable '(float)arr'", error=True,
+                    substrs=["C-style cast from 'int *' to 'float' is not "
+                             "allowed"])
+
+        # TestCStyleCastPointer
+        self.expect_var_path("(void*)&a", type="void *")
+        self.expect_var_path("(void*)ap", type="void *")
+        self.expect_var_path("(long long*)vp", type="long long *")
+        self.expect_var_path("(short int*)vp", type="short *")
+        self.expect_var_path("(unsigned long long*)vp", type="unsigned long 
long *")
+        self.expect_var_path("(unsigned short int*)vp", type="unsigned short 
*")
+
+
+        if Is32Bit:
+          self.expect_var_path("(void*)0",
+                      type="void *", value="0x00000000")
+          self.expect_var_path("(void*)1",
+                      type="void *", value="0x00000001")
+          self.expect_var_path("(void*)a",
+                      type="void *", value="0x00000001")
+          self.expect_var_path("(void*)na",
+                      type="void *", value="0xffffffff")
+        else:
+          self.expect_var_path("(void*)0",
+                      type="void *", value="0x0000000000000000")
+          self.expect_var_path("(void*)1",
+                      type="void *", value="0x0000000000000001")
+          self.expect_var_path("(void*)a",
+                      type="void *", value="0x0000000000000001")
+          self.expect_var_path("(void*)na",
+                      type="void *", value="0xffffffffffffffff")
+
+        self.expect_var_path("(int*&)ap", type="int *")
+
+        self.expect("frame variable '(char*) 1.0'", error=True,
+                    substrs=["cannot cast from type 'double' to pointer type"
+                             " 'char *'"])
+
+        self.expect_var_path("*(int*)(void*)ap", type="int", value="1")
+
+        self.expect_var_path("(ns::Foo*)ns_inner_foo_ptr_", type="ns::Foo *")
+        self.expect_var_path("(ns::inner::Foo*)ns_foo_ptr_", 
type="ns::inner::Foo *")
+
+        self.expect("frame variable '(int& &)ap'", error=True,
+                    substrs=["type name declared as a reference to a "
+                             "reference"])
+        self.expect("frame variable '(int&*)ap'", error=True,
+                    substrs=["'type name' declared as a pointer "
+                             "to a reference of type 'int &'"])
+
+        if Is32Bit:
+          self.expect_var_path("(void *)0", type="void *", value="0x00000000")
+        else:
+          self.expect_var_path("(void *)0", type="void *", 
value="0x0000000000000000")
+
+
+        # TestCStyleCastArray
+
+        threads = lldbutil.continue_to_source_breakpoint(
+            self, process,"Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+        )
+        self.assertEqual(
+            len(threads), 1, "There should be a thread stopped at our 
breakpoint"
+        )
+
+        self.expect_var_path("(int*)arr_1d", type="int *")
+        self.expect_var_path("(char*)arr_1d", type="char *")
+        self.expect_var_path("((char*)arr_1d)[0]", type="char", 
value="'\\x01'")
+        self.expect_var_path("((char*)arr_1d)[1]", type="char", value="'\\0'")
+
+        # 2D arrays.
+        self.expect_var_path("(int*)arr_2d", type="int *")
+        self.expect_var_path("((int*)arr_2d)[1]", type="int", value="2")
+        self.expect_var_path("((int*)arr_2d)[2]", type="int", value="3")
+        self.expect_var_path("((int*)arr_2d[1])[1]", type="int", value="5")
+
+        # TestCStyleCastReference
+
+        self.expect_var_path("((InnerFoo&)arr_1d[1]).a", type="int", value="2")
+        self.expect_var_path("((InnerFoo&)arr_1d[1]).b", type="int", value="3")
+
+        self.expect_var_path("(int&)arr_1d[0]", type="int", value="1")
+        self.expect_var_path("(int&)arr_1d[1]", type="int", value="2")
+
+        self.expect_var_path("&(int&)arr_1d", type="int *")
diff --git a/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp 
b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp
new file mode 100644
index 0000000000000..0fd841d95cdf6
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/CStyleCast/main.cpp
@@ -0,0 +1,81 @@
+// CStyleCast, main.cpp
+
+#include <cstdarg>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <limits>
+#include <memory>
+#include <string>
+
+namespace ns {
+
+typedef int myint;
+
+class Foo {};
+
+namespace inner {
+
+using mydouble = double;
+
+class Foo {};
+
+} // namespace inner
+
+} // namespace ns
+
+int main(int argc, char **argv) {
+  int a = 1;
+  int *ap = &a;
+  void *vp = &a;
+  int arr[2] = {1, 2};
+
+  int na = -1;
+  float f = 1.1;
+
+  typedef int myint;
+  std::nullptr_t std_nullptr_t = nullptr;
+  bool found_it = false;
+  if (std_nullptr_t) {
+    found_it = true;
+  } else {
+    found_it = (bool)0;
+  }
+
+  myint myint_ = 1;
+  ns::myint ns_myint_ = 2;
+  ns::Foo ns_foo_;
+  ns::Foo *ns_foo_ptr_ = &ns_foo_;
+
+  ns::inner::mydouble ns_inner_mydouble_ = 1.2;
+  ns::inner::Foo ns_inner_foo_;
+  ns::inner::Foo *ns_inner_foo_ptr_ = &ns_inner_foo_;
+
+  float finf = std::numeric_limits<float>::infinity();
+  float fnan = std::numeric_limits<float>::quiet_NaN();
+  float fsnan = std::numeric_limits<float>::signaling_NaN();
+  float fmax = std::numeric_limits<float>::max();
+  float fdenorm = std::numeric_limits<float>::denorm_min();
+
+  // TestCStyleCastBuiltins
+  // TestCStyleCastBasicType
+  // TestCStyleCastPointer
+  // TestCStyleCastNullptrType
+  if (false) { // Set a breakpoint here
+  }
+
+  struct InnerFoo {
+    int a;
+    int b;
+  };
+
+  InnerFoo ifoo;
+  (void)ifoo;
+
+  int arr_1d[] = {1, 2, 3, 4};
+  int arr_2d[2][3] = {{1, 2, 3}, {4, 5, 6}};
+
+  // TestCStyleCastArray
+  // TestCStyleCastReference
+  return 0; // Set a breakpoint here
+}

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to