[Lldb-commits] [lldb] d5927a6 - [LLDB] Add unary plus and minus to DIL (#155617)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Nov 24 06:08:58 PST 2025
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;
+}
More information about the lldb-commits
mailing list