Author: Ilia Kuklin
Date: 2025-11-24T19:08:53+05:00
New Revision: d5927a6172ab9b95f7f533bfdff865c1ce2aad5b

URL: 
https://github.com/llvm/llvm-project/commit/d5927a6172ab9b95f7f533bfdff865c1ce2aad5b
DIFF: 
https://github.com/llvm/llvm-project/commit/d5927a6172ab9b95f7f533bfdff865c1ce2aad5b.diff

LOG: [LLDB] Add unary plus and minus to DIL (#155617)

This patch adds unary nodes plus and minus, introduces unary type
conversions, and adds integral promotion to the type system.

Added: 
    lldb/test/API/commands/frame/var-dil/expr/Arithmetic/Makefile
    
lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
    lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
    lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/Makefile
    
lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILPointerArithmetic.py
    lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp

Modified: 
    lldb/docs/dil-expr-lang.ebnf
    lldb/include/lldb/Symbol/TypeSystem.h
    lldb/include/lldb/ValueObject/DILAST.h
    lldb/include/lldb/ValueObject/DILEval.h
    lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
    lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
    lldb/source/Symbol/CompilerType.cpp
    lldb/source/Symbol/TypeSystem.cpp
    lldb/source/ValueObject/DILEval.cpp
    lldb/source/ValueObject/DILParser.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 70eda3bf40650..ccd2b00223910 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -8,7 +8,7 @@ expression = unary_expression ;
 unary_expression = postfix_expression
                  | unary_operator expression ;
 
-unary_operator = "*" | "&" ;
+unary_operator = "*" | "&" | "+" | "-";
 
 postfix_expression = primary_expression
                    | postfix_expression "[" integer_literal "]"

diff  --git a/lldb/include/lldb/Symbol/TypeSystem.h 
b/lldb/include/lldb/Symbol/TypeSystem.h
index 25b208a65349b..99ea0585e5370 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -411,6 +411,18 @@ class TypeSystem : public PluginInterface,
   GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, size_t idx,
                               bool expand_pack);
 
+  // DIL
+
+  /// Checks if the type is eligible for integral promotion.
+  virtual bool IsPromotableIntegerType(lldb::opaque_compiler_type_t type);
+
+  /// Perform integral promotion on a given type.
+  /// This promotes eligible types (boolean, integers, unscoped enumerations)
+  /// to a larger integer type according to type system rules.
+  /// \returns Promoted type.
+  virtual llvm::Expected<CompilerType>
+  DoIntegralPromotion(CompilerType from, ExecutionContextScope *exe_scope);
+
   // Dumping types
 
 #ifndef NDEBUG

diff  --git a/lldb/include/lldb/ValueObject/DILAST.h 
b/lldb/include/lldb/ValueObject/DILAST.h
index 0f05d753f1b56..91f8d93c09622 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -33,6 +33,8 @@ enum class NodeKind {
 enum class UnaryOpKind {
   AddrOf, // "&"
   Deref,  // "*"
+  Minus,  // "-"
+  Plus,   // "+"
 };
 
 /// Forward declaration, for use in DIL AST nodes. Definition is at the very

diff  --git a/lldb/include/lldb/ValueObject/DILEval.h 
b/lldb/include/lldb/ValueObject/DILEval.h
index eab3218ff828f..a65edc58cc4e7 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -61,6 +61,10 @@ class Interpreter : Visitor {
   llvm::Expected<lldb::ValueObjectSP>
   Visit(const BooleanLiteralNode *node) override;
 
+  /// Perform usual unary conversions on a value. At the moment this
+  /// includes array-to-pointer and integral promotion for eligible types.
+  llvm::Expected<lldb::ValueObjectSP>
+  UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location);
   llvm::Expected<CompilerType>
   PickIntegerType(lldb::TypeSystemSP type_system,
                   std::shared_ptr<ExecutionContextScope> ctx,

diff  --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 51cb883748514..aa8d309fbc730 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -7346,6 +7346,102 @@ CompilerType TypeSystemClang::GetTypeForFormatters(void 
*type) {
   return CompilerType();
 }
 
+bool TypeSystemClang::IsPromotableIntegerType(
+    lldb::opaque_compiler_type_t type) {
+  // Unscoped enums are always considered as promotable, even if their
+  // underlying type does not need to be promoted (e.g. "int").
+  bool is_signed = false;
+  bool isUnscopedEnumerationType =
+      IsEnumerationType(type, is_signed) && !IsScopedEnumerationType(type);
+  if (isUnscopedEnumerationType)
+    return true;
+
+  switch (GetBasicTypeEnumeration(type)) {
+  case lldb::eBasicTypeBool:
+  case lldb::eBasicTypeChar:
+  case lldb::eBasicTypeSignedChar:
+  case lldb::eBasicTypeUnsignedChar:
+  case lldb::eBasicTypeShort:
+  case lldb::eBasicTypeUnsignedShort:
+  case lldb::eBasicTypeWChar:
+  case lldb::eBasicTypeSignedWChar:
+  case lldb::eBasicTypeUnsignedWChar:
+  case lldb::eBasicTypeChar16:
+  case lldb::eBasicTypeChar32:
+    return true;
+
+  default:
+    return false;
+  }
+
+  llvm_unreachable("All cases handled above.");
+}
+
+llvm::Expected<CompilerType>
+TypeSystemClang::DoIntegralPromotion(CompilerType from,
+                                     ExecutionContextScope *exe_scope) {
+  if (!from.IsInteger() && !from.IsUnscopedEnumerationType())
+    return from;
+
+  if (!from.IsPromotableIntegerType())
+    return from;
+
+  if (from.IsUnscopedEnumerationType()) {
+    EnumDecl *enum_decl = GetAsEnumDecl(from);
+    CompilerType promotion_type = GetType(enum_decl->getPromotionType());
+    return DoIntegralPromotion(promotion_type, exe_scope);
+  }
+
+  lldb::BasicType builtin_type =
+      from.GetCanonicalType().GetBasicTypeEnumeration();
+  uint64_t from_size = 0;
+  if (builtin_type == lldb::eBasicTypeWChar ||
+      builtin_type == lldb::eBasicTypeSignedWChar ||
+      builtin_type == lldb::eBasicTypeUnsignedWChar ||
+      builtin_type == lldb::eBasicTypeChar16 ||
+      builtin_type == lldb::eBasicTypeChar32) {
+    // Find the type that can hold the entire range of values for our type.
+    bool is_signed = from.IsSigned();
+    llvm::Expected<uint64_t> from_size = from.GetByteSize(exe_scope);
+    if (!from_size)
+      return from_size.takeError();
+    CompilerType promote_types[] = {
+        GetBasicTypeFromAST(lldb::eBasicTypeInt),
+        GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt),
+        GetBasicTypeFromAST(lldb::eBasicTypeLong),
+        GetBasicTypeFromAST(lldb::eBasicTypeUnsignedLong),
+        GetBasicTypeFromAST(lldb::eBasicTypeLongLong),
+        GetBasicTypeFromAST(lldb::eBasicTypeUnsignedLongLong),
+    };
+    for (CompilerType &type : promote_types) {
+      llvm::Expected<uint64_t> byte_size = type.GetByteSize(exe_scope);
+      if (!byte_size)
+        return byte_size.takeError();
+      if (*from_size < *byte_size ||
+          (*from_size == *byte_size && is_signed == type.IsSigned())) {
+        return type;
+      }
+    }
+    llvm_unreachable("char type should fit into long long");
+  }
+
+  // Here we can promote only to "int" or "unsigned int".
+  CompilerType int_type = GetBasicTypeFromAST(lldb::eBasicTypeInt);
+  llvm::Expected<uint64_t> int_byte_size = int_type.GetByteSize(exe_scope);
+  if (!int_byte_size)
+    return int_byte_size.takeError();
+
+  // Signed integer types can be safely promoted to "int".
+  if (from.IsSigned()) {
+    return int_type;
+  }
+  // Unsigned integer types are promoted to "unsigned int" if "int" cannot hold
+  // their entire value range.
+  return (from_size == *int_byte_size)
+             ? GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt)
+             : int_type;
+}
+
 clang::EnumDecl *TypeSystemClang::GetAsEnumDecl(const CompilerType &type) {
   const clang::EnumType *enutype =
       llvm::dyn_cast<clang::EnumType>(ClangUtil::GetCanonicalQualType(type));

diff  --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h 
b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 375891b3cfd2f..67d206e4d2df2 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -938,6 +938,14 @@ class TypeSystemClang : public TypeSystem {
 
   CompilerType GetTypeForFormatters(void *type) override;
 
+  // DIL
+
+  bool IsPromotableIntegerType(lldb::opaque_compiler_type_t type) override;
+
+  llvm::Expected<CompilerType>
+  DoIntegralPromotion(CompilerType from,
+                      ExecutionContextScope *exe_scope) override;
+
 #define LLDB_INVALID_DECL_LEVEL UINT32_MAX
   // LLDB_INVALID_DECL_LEVEL is returned by CountDeclLevels if child_decl_ctx
   // could not be found in decl_ctx.

diff  --git a/lldb/source/Symbol/CompilerType.cpp 
b/lldb/source/Symbol/CompilerType.cpp
index c999ab256fc98..1a39ea9476390 100644
--- a/lldb/source/Symbol/CompilerType.cpp
+++ b/lldb/source/Symbol/CompilerType.cpp
@@ -370,30 +370,10 @@ bool CompilerType::IsScalarOrUnscopedEnumerationType() 
const {
 }
 
 bool CompilerType::IsPromotableIntegerType() const {
-  // Unscoped enums are always considered as promotable, even if their
-  // underlying type does not need to be promoted (e.g. "int").
-  if (IsUnscopedEnumerationType())
-    return true;
-
-  switch (GetBasicTypeEnumeration()) {
-  case lldb::eBasicTypeBool:
-  case lldb::eBasicTypeChar:
-  case lldb::eBasicTypeSignedChar:
-  case lldb::eBasicTypeUnsignedChar:
-  case lldb::eBasicTypeShort:
-  case lldb::eBasicTypeUnsignedShort:
-  case lldb::eBasicTypeWChar:
-  case lldb::eBasicTypeSignedWChar:
-  case lldb::eBasicTypeUnsignedWChar:
-  case lldb::eBasicTypeChar16:
-  case lldb::eBasicTypeChar32:
-    return true;
-
-  default:
-    return false;
-  }
-
-  llvm_unreachable("All cases handled above.");
+  if (IsValid())
+    if (auto type_system_sp = GetTypeSystem())
+      return type_system_sp->IsPromotableIntegerType(m_type);
+  return false;
 }
 
 bool CompilerType::IsPointerToVoid() const {

diff  --git a/lldb/source/Symbol/TypeSystem.cpp 
b/lldb/source/Symbol/TypeSystem.cpp
index f7d634ffa2dec..8712142893835 100644
--- a/lldb/source/Symbol/TypeSystem.cpp
+++ b/lldb/source/Symbol/TypeSystem.cpp
@@ -123,6 +123,17 @@ CompilerType TypeSystem::GetTypeForFormatters(void *type) {
   return CompilerType(weak_from_this(), type);
 }
 
+bool TypeSystem::IsPromotableIntegerType(lldb::opaque_compiler_type_t type) {
+  return false;
+}
+
+llvm::Expected<CompilerType>
+TypeSystem::DoIntegralPromotion(CompilerType from,
+                                ExecutionContextScope *exe_scope) {
+  return llvm::createStringError(
+      "Integral promotion is not implemented for this TypeSystem");
+}
+
 bool TypeSystem::IsTemplateType(lldb::opaque_compiler_type_t type) {
   return false;
 }

diff  --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index a9dbfad298d05..40a05a467f883 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -21,6 +21,101 @@
 
 namespace lldb_private::dil {
 
+static llvm::Expected<lldb::TypeSystemSP>
+GetTypeSystemFromCU(std::shared_ptr<ExecutionContextScope> ctx) {
+  auto stack_frame = ctx->CalculateStackFrame();
+  if (!stack_frame)
+    return llvm::createStringError("no stack frame in this context");
+  SymbolContext symbol_context =
+      stack_frame->GetSymbolContext(lldb::eSymbolContextCompUnit);
+  lldb::LanguageType language = symbol_context.comp_unit->GetLanguage();
+
+  symbol_context = stack_frame->GetSymbolContext(lldb::eSymbolContextModule);
+  return symbol_context.module_sp->GetTypeSystemForLanguage(language);
+}
+
+static CompilerType GetBasicType(lldb::TypeSystemSP type_system,
+                                 lldb::BasicType basic_type) {
+  if (type_system)
+    return type_system.get()->GetBasicTypeFromAST(basic_type);
+
+  return CompilerType();
+}
+
+static lldb::ValueObjectSP
+ArrayToPointerConversion(ValueObject &valobj, ExecutionContextScope &ctx) {
+  uint64_t addr = valobj.GetLoadAddress();
+  ExecutionContext exe_ctx;
+  ctx.CalculateExecutionContext(exe_ctx);
+  return ValueObject::CreateValueObjectFromAddress(
+      "result", addr, exe_ctx,
+      valobj.GetCompilerType().GetArrayElementType(&ctx).GetPointerType(),
+      /* do_deref */ false);
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location) {
+  if (!valobj)
+    return llvm::make_error<DILDiagnosticError>(m_expr, "invalid value object",
+                                                location);
+  llvm::Expected<lldb::TypeSystemSP> type_system =
+      GetTypeSystemFromCU(m_exe_ctx_scope);
+  if (!type_system)
+    return type_system.takeError();
+
+  CompilerType in_type = valobj->GetCompilerType();
+  if (valobj->IsBitfield()) {
+    // Promote bitfields. If `int` can represent the bitfield value, it is
+    // converted to `int`. Otherwise, if `unsigned int` can represent it, it
+    // is converted to `unsigned int`. Otherwise, it is treated as its
+    // underlying type.
+    uint32_t bitfield_size = valobj->GetBitfieldBitSize();
+    // Some bitfields have undefined size (e.g. result of ternary operation).
+    // The AST's `bitfield_size` of those is 0, and no promotion takes place.
+    if (bitfield_size > 0 && in_type.IsInteger()) {
+      CompilerType int_type = GetBasicType(*type_system, lldb::eBasicTypeInt);
+      CompilerType uint_type =
+          GetBasicType(*type_system, lldb::eBasicTypeUnsignedInt);
+      llvm::Expected<uint64_t> int_bit_size =
+          int_type.GetBitSize(m_exe_ctx_scope.get());
+      if (!int_bit_size)
+        return int_bit_size.takeError();
+      llvm::Expected<uint64_t> uint_bit_size =
+          uint_type.GetBitSize(m_exe_ctx_scope.get());
+      if (!uint_bit_size)
+        return int_bit_size.takeError();
+      if (bitfield_size < *int_bit_size ||
+          (in_type.IsSigned() && bitfield_size == *int_bit_size))
+        return valobj->CastToBasicType(int_type);
+      if (bitfield_size <= *uint_bit_size)
+        return valobj->CastToBasicType(uint_type);
+      // Re-create as a const value with the same underlying type
+      Scalar scalar;
+      bool resolved = valobj->ResolveValue(scalar);
+      if (!resolved)
+        return llvm::createStringError("invalid scalar value");
+      return ValueObject::CreateValueObjectFromScalar(m_target, scalar, 
in_type,
+                                                      "result");
+    }
+  }
+
+  if (in_type.IsArrayType())
+    valobj = ArrayToPointerConversion(*valobj, *m_exe_ctx_scope);
+
+  if (valobj->GetCompilerType().IsInteger() ||
+      valobj->GetCompilerType().IsUnscopedEnumerationType()) {
+    llvm::Expected<CompilerType> promoted_type =
+        type_system.get()->DoIntegralPromotion(valobj->GetCompilerType(),
+                                               m_exe_ctx_scope.get());
+    if (!promoted_type)
+      return promoted_type.takeError();
+    if (!promoted_type->CompareTypes(valobj->GetCompilerType()))
+      return valobj->CastToBasicType(*promoted_type);
+  }
+
+  return valobj;
+}
+
 static lldb::VariableSP DILFindVariable(ConstString name,
                                         VariableList &variable_list) {
   lldb::VariableSP exact_match;
@@ -147,6 +242,10 @@ Interpreter::Interpreter(lldb::TargetSP target, 
llvm::StringRef expr,
 llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *node) 
{
   // Evaluate an AST.
   auto value_or_error = node->Accept(this);
+  // Convert SP with a nullptr to an error.
+  if (value_or_error && !*value_or_error)
+    return llvm::make_error<DILDiagnosticError>(m_expr, "invalid value object",
+                                                node->GetLocation());
   // Return the computed value-or-error. The caller is responsible for
   // checking if an error occured during the evaluation.
   return value_or_error;
@@ -175,21 +274,21 @@ Interpreter::Visit(const IdentifierNode *node) {
 llvm::Expected<lldb::ValueObjectSP>
 Interpreter::Visit(const UnaryOpNode *node) {
   Status error;
-  auto rhs_or_err = Evaluate(node->GetOperand());
-  if (!rhs_or_err)
-    return rhs_or_err;
+  auto op_or_err = Evaluate(node->GetOperand());
+  if (!op_or_err)
+    return op_or_err;
 
-  lldb::ValueObjectSP rhs = *rhs_or_err;
+  lldb::ValueObjectSP operand = *op_or_err;
 
   switch (node->GetKind()) {
   case UnaryOpKind::Deref: {
-    lldb::ValueObjectSP dynamic_rhs = rhs->GetDynamicValue(m_use_dynamic);
-    if (dynamic_rhs)
-      rhs = dynamic_rhs;
+    lldb::ValueObjectSP dynamic_op = operand->GetDynamicValue(m_use_dynamic);
+    if (dynamic_op)
+      operand = dynamic_op;
 
-    lldb::ValueObjectSP child_sp = rhs->Dereference(error);
+    lldb::ValueObjectSP child_sp = operand->Dereference(error);
     if (!child_sp && m_use_synthetic) {
-      if (lldb::ValueObjectSP synth_obj_sp = rhs->GetSyntheticValue()) {
+      if (lldb::ValueObjectSP synth_obj_sp = operand->GetSyntheticValue()) {
         error.Clear();
         child_sp = synth_obj_sp->Dereference(error);
       }
@@ -202,18 +301,69 @@ Interpreter::Visit(const UnaryOpNode *node) {
   }
   case UnaryOpKind::AddrOf: {
     Status error;
-    lldb::ValueObjectSP value = rhs->AddressOf(error);
+    lldb::ValueObjectSP value = operand->AddressOf(error);
     if (error.Fail())
       return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(),
                                                   node->GetLocation());
 
     return value;
   }
+  case UnaryOpKind::Minus: {
+    if (operand->GetCompilerType().IsReferenceType()) {
+      operand = operand->Dereference(error);
+      if (error.Fail())
+        return error.ToError();
+    }
+    llvm::Expected<lldb::ValueObjectSP> conv_op =
+        UnaryConversion(operand, node->GetOperand()->GetLocation());
+    if (!conv_op)
+      return conv_op;
+    operand = *conv_op;
+    CompilerType operand_type = operand->GetCompilerType();
+    if (!operand_type.IsScalarType()) {
+      std::string errMsg =
+          llvm::formatv("invalid argument type '{0}' to unary expression",
+                        operand_type.GetTypeName());
+      return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
+                                                  node->GetLocation());
+    }
+    Scalar scalar;
+    bool resolved = operand->ResolveValue(scalar);
+    if (!resolved)
+      break;
+
+    bool negated = scalar.UnaryNegate();
+    if (negated)
+      return ValueObject::CreateValueObjectFromScalar(
+          m_target, scalar, operand->GetCompilerType(), "result");
+    break;
   }
-
-  // Unsupported/invalid operation.
-  return llvm::make_error<DILDiagnosticError>(
-      m_expr, "invalid ast: unexpected binary operator", node->GetLocation());
+  case UnaryOpKind::Plus: {
+    if (operand->GetCompilerType().IsReferenceType()) {
+      operand = operand->Dereference(error);
+      if (error.Fail())
+        return error.ToError();
+    }
+    llvm::Expected<lldb::ValueObjectSP> conv_op =
+        UnaryConversion(operand, node->GetOperand()->GetLocation());
+    if (!conv_op)
+      return conv_op;
+    operand = *conv_op;
+    CompilerType operand_type = operand->GetCompilerType();
+    if (!operand_type.IsScalarType() &&
+        // Unary plus is allowed for pointers.
+        !operand_type.IsPointerType()) {
+      std::string errMsg =
+          llvm::formatv("invalid argument type '{0}' to unary expression",
+                        operand_type.GetTypeName());
+      return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
+                                                  node->GetLocation());
+    }
+    return operand;
+  }
+  }
+  return llvm::make_error<DILDiagnosticError>(m_expr, "invalid unary 
operation",
+                                              node->GetLocation());
 }
 
 llvm::Expected<lldb::ValueObjectSP>
@@ -499,24 +649,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)
-    return type_system.get()->GetBasicTypeFromAST(basic_type);
-
-  return CompilerType();
-}
-
 llvm::Expected<CompilerType>
 Interpreter::PickIntegerType(lldb::TypeSystemSP type_system,
                              std::shared_ptr<ExecutionContextScope> ctx,

diff  --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index 82b97aafe2261..072ddff1e28d2 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -93,9 +93,12 @@ ASTNodeUP DILParser::ParseExpression() { return 
ParseUnaryExpression(); }
 //  unary_operator:
 //    "&"
 //    "*"
+//    "+"
+//    "-"
 //
 ASTNodeUP DILParser::ParseUnaryExpression() {
-  if (CurToken().IsOneOf({Token::amp, Token::star})) {
+  if (CurToken().IsOneOf(
+          {Token::amp, Token::star, Token::minus, Token::plus})) {
     Token token = CurToken();
     uint32_t loc = token.GetLocation();
     m_dil_lexer.Advance();
@@ -107,7 +110,12 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
     case Token::amp:
       return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::AddrOf,
                                            std::move(rhs));
-
+    case Token::minus:
+      return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Minus,
+                                           std::move(rhs));
+    case Token::plus:
+      return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Plus,
+                                           std::move(rhs));
     default:
       llvm_unreachable("invalid token kind");
     }

diff  --git a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/Makefile 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules

diff  --git 
a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
new file mode 100644
index 0000000000000..53a85fed303f4
--- /dev/null
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
@@ -0,0 +1,46 @@
+"""
+Test DIL arithmetic.
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+
+class TestFrameVarDILArithmetic(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_arithmetic(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.runCmd("settings set target.experimental.use-DIL true")
+
+        # Check unary results and integral promotion
+        self.expect_var_path("+0", value="0")
+        self.expect_var_path("-0", value="0")
+        self.expect_var_path("+1", value="1")
+        self.expect_var_path("-1", value="-1")
+        self.expect_var_path("-9223372036854775808", 
value="9223372036854775808")
+        self.expect_var_path("s", value="10", type="short")
+        self.expect_var_path("+s", value="10", type="int")
+        self.expect_var_path("-s", value="-10", type="int")
+        self.expect_var_path("+us", value="1", type="int")
+        self.expect_var_path("-us", value="-1", type="int")
+        self.expect_var_path("+ref", value="2", type="int")
+        self.expect_var_path("-ref", value="-2", type="int")
+        self.expect_var_path("+0.0", value="0")
+        self.expect_var_path("-0.0", value="-0")
+        self.expect_var_path("+enum_one", value="1")
+        self.expect_var_path("-enum_one", value="-1")
+        self.expect_var_path("+wchar", value="1")
+        self.expect_var_path("+char16", value="2")
+        self.expect_var_path("+char32", value="3")
+        self.expect_var_path("-bitfield.a", value="-1", type="int")
+        self.expect_var_path("+bitfield.a", value="1", type="int")
+        self.expect_var_path("+bitfield.b", value="2", type="int")
+        self.expect_var_path("+bitfield.c", value="3", type="unsigned int")
+        self.expect_var_path("+bitfield.d", value="4", type="uint64_t")

diff  --git a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
new file mode 100644
index 0000000000000..2c70e93433f5f
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
@@ -0,0 +1,23 @@
+#include <cstdint>
+
+int main(int argc, char **argv) {
+  short s = 10;
+  unsigned short us = 1;
+
+  int x = 2;
+  int &ref = x;
+  enum Enum { kZero, kOne } enum_one = kOne;
+  wchar_t wchar = 1;
+  char16_t char16 = 2;
+  char32_t char32 = 3;
+
+  struct BitFieldStruct {
+    char a : 4;
+    int b : 32;
+    unsigned int c : 32;
+    uint64_t d : 48;
+  };
+  BitFieldStruct bitfield = {1, 2, 3, 4};
+
+  return 0; // Set a breakpoint here
+}

diff  --git 
a/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/Makefile 
b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules

diff  --git 
a/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILPointerArithmetic.py
 
b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILPointerArithmetic.py
new file mode 100644
index 0000000000000..88429b370710e
--- /dev/null
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/TestFrameVarDILPointerArithmetic.py
@@ -0,0 +1,29 @@
+"""
+Test DIL pointer arithmetic.
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+
+class TestFrameVarDILPointerArithmetic(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_pointer_arithmetic(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.runCmd("settings set target.experimental.use-DIL true")
+
+        self.expect_var_path("+array", type="int *")
+        self.expect_var_path("+array_ref", type="int *")
+        self.expect_var_path("+p_int0", type="int *")
+        self.expect(
+            "frame var -- '-p_int0'",
+            error=True,
+            substrs=["invalid argument type 'int *' to unary expression"],
+        )

diff  --git 
a/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp 
b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp
new file mode 100644
index 0000000000000..b4e0e88b1ffc9
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/PointerArithmetic/main.cpp
@@ -0,0 +1,11 @@
+void stop() {}
+
+int main(int argc, char **argv) {
+  int array[10];
+  array[0] = 0;
+  int (&array_ref)[10] = array;
+  int *p_int0 = &array[0];
+
+  stop(); // Set a breakpoint here
+  return 0;
+}


        
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to