[Lldb-commits] [lldb] Draft: [LLDB] Add scalar literal node (PR #147064)
Ilia Kuklin via lldb-commits
lldb-commits at lists.llvm.org
Wed Jul 16 13:20:31 PDT 2025
https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/147064
>From cf1f908360399ac51770d9fb7e1dac03eceab0e9 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Thu, 3 Jul 2025 19:34:17 +0500
Subject: [PATCH 1/2] [LLDB] *WIP* Add scalar literal node and binary addition
---
lldb/include/lldb/ValueObject/DILAST.h | 58 ++++
lldb/include/lldb/ValueObject/DILEval.h | 15 +
lldb/include/lldb/ValueObject/DILLexer.h | 1 +
lldb/include/lldb/ValueObject/DILParser.h | 3 +
lldb/source/ValueObject/DILAST.cpp | 21 ++
lldb/source/ValueObject/DILEval.cpp | 405 ++++++++++++++++++++++
lldb/source/ValueObject/DILLexer.cpp | 10 +-
lldb/source/ValueObject/DILParser.cpp | 74 +++-
8 files changed, 581 insertions(+), 6 deletions(-)
diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h
index 709f0639135f1..a9d244031d55f 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -9,6 +9,7 @@
#ifndef LLDB_VALUEOBJECT_DILAST_H
#define LLDB_VALUEOBJECT_DILAST_H
+#include "lldb/ValueObject/DILLexer.h"
#include "lldb/ValueObject/ValueObject.h"
#include "llvm/Support/Error.h"
#include <cstdint>
@@ -19,10 +20,12 @@ namespace lldb_private::dil {
/// The various types DIL AST nodes (used by the DIL parser).
enum class NodeKind {
eArraySubscriptNode,
+ eBinaryOpNode,
eBitExtractionNode,
eErrorNode,
eIdentifierNode,
eMemberOfNode,
+ eScalarLiteralNode,
eUnaryOpNode,
};
@@ -32,6 +35,14 @@ enum class UnaryOpKind {
Deref, // "*"
};
+enum class BinaryOpKind {
+ Add, // "+"
+ Sub, // "-"
+};
+
+/// Translates DIL tokens to BinaryOpKind.
+BinaryOpKind GetBinaryOpKindFromToken(Token::Kind token_kind);
+
/// Forward declaration, for use in DIL AST nodes. Definition is at the very
/// end of this file.
class Visitor;
@@ -178,6 +189,49 @@ class BitFieldExtractionNode : public ASTNode {
int64_t m_last_index;
};
+class ScalarLiteralNode : public ASTNode {
+public:
+ ScalarLiteralNode(uint32_t location, lldb::BasicType type, Scalar value)
+ : ASTNode(location, NodeKind::eScalarLiteralNode), m_type(type),
+ m_value(value) {}
+
+ llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
+
+ lldb::BasicType GetType() const { return m_type; }
+ Scalar GetValue() const & { return m_value; }
+
+ static bool classof(const ASTNode *node) {
+ return node->GetKind() == NodeKind::eScalarLiteralNode;
+ }
+
+private:
+ lldb::BasicType m_type;
+ Scalar m_value;
+};
+
+class BinaryOpNode : public ASTNode {
+public:
+ BinaryOpNode(uint32_t location, BinaryOpKind kind, ASTNodeUP lhs,
+ ASTNodeUP rhs)
+ : ASTNode(location, NodeKind::eBinaryOpNode), m_kind(kind),
+ m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {}
+
+ llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
+
+ BinaryOpKind GetKind() const { return m_kind; }
+ ASTNode *GetLHS() const { return m_lhs.get(); }
+ ASTNode *GetRHS() const { return m_rhs.get(); }
+
+ static bool classof(const ASTNode *node) {
+ return node->GetKind() == NodeKind::eBinaryOpNode;
+ }
+
+private:
+ BinaryOpKind m_kind;
+ ASTNodeUP m_lhs;
+ ASTNodeUP m_rhs;
+};
+
/// 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
@@ -195,6 +249,10 @@ class Visitor {
Visit(const ArraySubscriptNode *node) = 0;
virtual llvm::Expected<lldb::ValueObjectSP>
Visit(const BitFieldExtractionNode *node) = 0;
+ virtual llvm::Expected<lldb::ValueObjectSP>
+ Visit(const ScalarLiteralNode *node) = 0;
+ virtual llvm::Expected<lldb::ValueObjectSP>
+ Visit(const BinaryOpNode *node) = 0;
};
} // namespace lldb_private::dil
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index 45e29b3ddcd7b..9e9028f6122fd 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -54,6 +54,21 @@ class Interpreter : Visitor {
Visit(const ArraySubscriptNode *node) override;
llvm::Expected<lldb::ValueObjectSP>
Visit(const BitFieldExtractionNode *node) override;
+ llvm::Expected<lldb::ValueObjectSP>
+ Visit(const ScalarLiteralNode *node) override;
+ llvm::Expected<lldb::ValueObjectSP> Visit(const BinaryOpNode *node) override;
+
+ lldb::ValueObjectSP
+ ConvertValueObjectToTypeSystem(lldb::ValueObjectSP valobj,
+ lldb::TypeSystemSP type_system);
+
+ llvm::Error PrepareBinaryAddition(lldb::ValueObjectSP &lhs,
+ lldb::ValueObjectSP &rhs,
+ uint32_t location);
+
+ llvm::Expected<lldb::ValueObjectSP>
+ EvaluateBinaryAddition(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
+ uint32_t location);
// Used by the interpreter to create objects, perform casts, etc.
lldb::TargetSP m_target;
diff --git a/lldb/include/lldb/ValueObject/DILLexer.h b/lldb/include/lldb/ValueObject/DILLexer.h
index 9c1ba97680253..58059657bf3a5 100644
--- a/lldb/include/lldb/ValueObject/DILLexer.h
+++ b/lldb/include/lldb/ValueObject/DILLexer.h
@@ -34,6 +34,7 @@ class Token {
minus,
numeric_constant,
period,
+ plus,
r_paren,
r_square,
star,
diff --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h
index 9eda7bac4a364..c57ef0cf28022 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -87,6 +87,7 @@ class DILParser {
ASTNodeUP Run();
ASTNodeUP ParseExpression();
+ ASTNodeUP ParseAdditiveExpression();
ASTNodeUP ParseUnaryExpression();
ASTNodeUP ParsePostfixExpression();
ASTNodeUP ParsePrimaryExpression();
@@ -96,6 +97,8 @@ class DILParser {
std::string ParseIdExpression();
std::string ParseUnqualifiedId();
std::optional<int64_t> ParseIntegerConstant();
+ ASTNodeUP ParseNumericLiteral();
+ ASTNodeUP ParseNumericConstant();
void BailOut(const std::string &error, uint32_t loc, uint16_t err_len);
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
index b1cd824c2299e..7aee692f2b28a 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -11,6 +11,18 @@
namespace lldb_private::dil {
+BinaryOpKind GetBinaryOpKindFromToken(Token::Kind token_kind) {
+ switch (token_kind) {
+ case Token::minus:
+ return BinaryOpKind::Sub;
+ case Token::plus:
+ return BinaryOpKind::Add;
+ default:
+ break;
+ }
+ llvm_unreachable("Unknown binary operator kind.");
+}
+
llvm::Expected<lldb::ValueObjectSP> ErrorNode::Accept(Visitor *v) const {
llvm_unreachable("Attempting to Visit a DIL ErrorNode.");
}
@@ -37,4 +49,13 @@ BitFieldExtractionNode::Accept(Visitor *v) const {
return v->Visit(this);
}
+llvm::Expected<lldb::ValueObjectSP>
+ScalarLiteralNode::Accept(Visitor *v) const {
+ return v->Visit(this);
+}
+
+llvm::Expected<lldb::ValueObjectSP> BinaryOpNode::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 8ca9b4215985d..2e42b57e93042 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -7,7 +7,9 @@
//===----------------------------------------------------------------------===//
#include "lldb/ValueObject/DILEval.h"
+#include "lldb/Core/Module.h"
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/ValueObject/DILAST.h"
@@ -401,4 +403,407 @@ Interpreter::Visit(const BitFieldExtractionNode *node) {
return child_valobj_sp;
}
+static CompilerType GetBasicTypeFromCU(std::shared_ptr<StackFrame> ctx,
+ lldb::BasicType basic_type) {
+ SymbolContext symbol_context =
+ ctx->GetSymbolContext(lldb::eSymbolContextCompUnit);
+ auto language = symbol_context.comp_unit->GetLanguage();
+
+ symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule);
+ auto type_system =
+ symbol_context.module_sp->GetTypeSystemForLanguage(language);
+
+ if (type_system)
+ if (auto compiler_type = type_system.get()->GetBasicTypeFromAST(basic_type))
+ return compiler_type;
+
+ CompilerType empty_type;
+ return empty_type;
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const ScalarLiteralNode *node) {
+ CompilerType result_type =
+ GetBasicTypeFromCU(m_exe_ctx_scope, node->GetType());
+ Scalar value = node->GetValue();
+
+ // Scalar later could be float or bool
+ if (result_type.IsInteger() || result_type.IsNullPtrType() ||
+ result_type.IsPointerType()) {
+ llvm::APInt val = value.GetAPSInt();
+ return ValueObject::CreateValueObjectFromAPInt(m_target, val, result_type,
+ "result");
+ }
+
+ return lldb::ValueObjectSP();
+}
+
+static CompilerType GetBasicType(lldb::TypeSystemSP type_system,
+ lldb::BasicType basic_type) {
+ if (type_system)
+ if (auto compiler_type = type_system.get()->GetBasicTypeFromAST(basic_type))
+ return compiler_type;
+
+ CompilerType empty_type;
+ return empty_type;
+}
+
+static CompilerType DoIntegralPromotion(CompilerType from,
+ std::shared_ptr<StackFrame> ctx) {
+ if (!from.IsInteger() && !from.IsUnscopedEnumerationType())
+ return from;
+
+ if (!from.IsPromotableIntegerType())
+ return from;
+
+ if (from.IsUnscopedEnumerationType())
+ return DoIntegralPromotion(from.GetEnumerationIntegerType(), ctx);
+ lldb::BasicType builtin_type =
+ from.GetCanonicalType().GetBasicTypeEnumeration();
+ lldb::TypeSystemSP type_system = from.GetTypeSystem().GetSharedPointer();
+
+ 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();
+ if (auto temp = from.GetByteSize(ctx.get()))
+ from_size = *temp;
+
+ CompilerType promote_types[] = {
+ GetBasicType(type_system, lldb::eBasicTypeInt),
+ GetBasicType(type_system, lldb::eBasicTypeUnsignedInt),
+ GetBasicType(type_system, lldb::eBasicTypeLong),
+ GetBasicType(type_system, lldb::eBasicTypeUnsignedLong),
+ GetBasicType(type_system, lldb::eBasicTypeLongLong),
+ GetBasicType(type_system, lldb::eBasicTypeUnsignedLongLong),
+ };
+ for (auto &type : promote_types) {
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(ctx.get()))
+ byte_size = *temp;
+ if (from_size < byte_size ||
+ (from_size == byte_size &&
+ is_signed == (bool)(type.GetTypeInfo() & lldb::eTypeIsSigned))) {
+ return type;
+ }
+ }
+
+ llvm_unreachable("char type should fit into long long");
+ }
+
+ // Here we can promote only to "int" or "unsigned int".
+ CompilerType int_type = GetBasicType(type_system, lldb::eBasicTypeInt);
+ uint64_t int_byte_size = 0;
+ if (auto temp = int_type.GetByteSize(ctx.get()))
+ int_byte_size = *temp;
+
+ // 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)
+ ? GetBasicType(type_system, lldb::eBasicTypeUnsignedInt)
+ : int_type;
+}
+
+static lldb::ValueObjectSP UnaryConversion(lldb::ValueObjectSP valobj,
+ std::shared_ptr<StackFrame> ctx) {
+ // Perform usual conversions for unary operators.
+ CompilerType in_type = valobj->GetCompilerType();
+ CompilerType result_type;
+
+ if (valobj->GetCompilerType().IsInteger() ||
+ valobj->GetCompilerType().IsUnscopedEnumerationType()) {
+ CompilerType promoted_type =
+ DoIntegralPromotion(valobj->GetCompilerType(), ctx);
+ if (!promoted_type.CompareTypes(valobj->GetCompilerType()))
+ return valobj->CastToBasicType(promoted_type);
+ }
+
+ return valobj;
+}
+
+static size_t ConversionRank(CompilerType type) {
+ // Get integer conversion rank
+ // https://eel.is/c++draft/conv.rank
+ switch (type.GetCanonicalType().GetBasicTypeEnumeration()) {
+ case lldb::eBasicTypeBool:
+ return 1;
+ case lldb::eBasicTypeChar:
+ case lldb::eBasicTypeSignedChar:
+ case lldb::eBasicTypeUnsignedChar:
+ return 2;
+ case lldb::eBasicTypeShort:
+ case lldb::eBasicTypeUnsignedShort:
+ return 3;
+ case lldb::eBasicTypeInt:
+ case lldb::eBasicTypeUnsignedInt:
+ return 4;
+ case lldb::eBasicTypeLong:
+ case lldb::eBasicTypeUnsignedLong:
+ return 5;
+ case lldb::eBasicTypeLongLong:
+ case lldb::eBasicTypeUnsignedLongLong:
+ return 6;
+
+ // The ranks of char16_t, char32_t, and wchar_t are equal to the
+ // ranks of their underlying types.
+ case lldb::eBasicTypeWChar:
+ case lldb::eBasicTypeSignedWChar:
+ case lldb::eBasicTypeUnsignedWChar:
+ return 3;
+ case lldb::eBasicTypeChar16:
+ return 3;
+ case lldb::eBasicTypeChar32:
+ return 4;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static lldb::BasicType BasicTypeToUnsigned(lldb::BasicType basic_type) {
+ switch (basic_type) {
+ case lldb::eBasicTypeInt:
+ return lldb::eBasicTypeUnsignedInt;
+ case lldb::eBasicTypeLong:
+ return lldb::eBasicTypeUnsignedLong;
+ case lldb::eBasicTypeLongLong:
+ return lldb::eBasicTypeUnsignedLongLong;
+ default:
+ return basic_type;
+ }
+}
+
+static void PerformIntegerConversions(std::shared_ptr<StackFrame> ctx,
+ lldb::ValueObjectSP &lhs,
+ lldb::ValueObjectSP &rhs,
+ bool convert_lhs, bool convert_rhs) {
+ CompilerType l_type = lhs->GetCompilerType();
+ CompilerType r_type = rhs->GetCompilerType();
+ if (r_type.IsSigned() && !l_type.IsSigned()) {
+ uint64_t l_size = 0;
+ uint64_t r_size = 0;
+ if (auto temp = l_type.GetByteSize(ctx.get()))
+ l_size = *temp;
+ ;
+ if (auto temp = r_type.GetByteSize(ctx.get()))
+ r_size = *temp;
+ if (l_size <= r_size) {
+ if (r_size == l_size) {
+ lldb::TypeSystemSP type_system =
+ l_type.GetTypeSystem().GetSharedPointer();
+ auto r_type_unsigned = GetBasicType(
+ type_system,
+ BasicTypeToUnsigned(
+ r_type.GetCanonicalType().GetBasicTypeEnumeration()));
+ if (convert_rhs)
+ rhs = rhs->CastToBasicType(r_type_unsigned);
+ }
+ }
+ }
+ if (convert_lhs)
+ lhs = lhs->CastToBasicType(rhs->GetCompilerType());
+}
+
+static CompilerType ArithmeticConversions(lldb::ValueObjectSP &lhs,
+ lldb::ValueObjectSP &rhs,
+ std::shared_ptr<StackFrame> ctx) {
+ // Apply unary conversion (e.g. intergal promotion) for both operands.
+ lhs = UnaryConversion(lhs, ctx);
+ rhs = UnaryConversion(rhs, ctx);
+
+ CompilerType lhs_type = lhs->GetCompilerType();
+ CompilerType rhs_type = rhs->GetCompilerType();
+
+ if (lhs_type.CompareTypes(rhs_type))
+ return lhs_type;
+
+ // If either of the operands is not arithmetic (e.g. pointer), we're done.
+ if (!lhs_type.IsScalarType() || !rhs_type.IsScalarType()) {
+ CompilerType bad_type;
+ return bad_type;
+ }
+
+ // Removed floating point conversions
+ if (lhs_type.IsFloat() || rhs_type.IsFloat()) {
+ CompilerType bad_type;
+ return bad_type;
+ }
+
+ if (lhs_type.IsInteger() && rhs_type.IsInteger()) {
+ using Rank = std::tuple<size_t, bool>;
+ Rank l_rank = {ConversionRank(lhs_type), !lhs_type.IsSigned()};
+ Rank r_rank = {ConversionRank(rhs_type), !rhs_type.IsSigned()};
+
+ if (l_rank < r_rank) {
+ PerformIntegerConversions(ctx, lhs, rhs, true, true);
+ } else if (l_rank > r_rank) {
+ PerformIntegerConversions(ctx, rhs, lhs, true, true);
+ }
+ }
+
+ return rhs_type;
+}
+
+llvm::Error Interpreter::PrepareBinaryAddition(lldb::ValueObjectSP &lhs,
+ lldb::ValueObjectSP &rhs,
+ uint32_t location) {
+ // Operation '+' works for:
+ //
+ // {scalar,unscoped_enum} <-> {scalar,unscoped_enum}
+ // {integer,unscoped_enum} <-> pointer
+ // pointer <-> {integer,unscoped_enum}
+ auto orig_lhs_type = lhs->GetCompilerType();
+ auto orig_rhs_type = rhs->GetCompilerType();
+ auto result_type = ArithmeticConversions(lhs, rhs, m_exe_ctx_scope);
+
+ if (result_type.IsScalarType())
+ return llvm::Error::success();
+
+ // Removed pointer arithmetics
+ return llvm::make_error<DILDiagnosticError>(m_expr, "unimplemented",
+ location);
+}
+
+static lldb::ValueObjectSP EvaluateArithmeticOpInteger(lldb::TargetSP target,
+ BinaryOpKind kind,
+ lldb::ValueObjectSP lhs,
+ lldb::ValueObjectSP rhs,
+ CompilerType rtype) {
+ assert(lhs->GetCompilerType().IsInteger() &&
+ rhs->GetCompilerType().IsInteger() &&
+ "invalid ast: both operands must be integers");
+
+ auto wrap = [target, rtype](auto value) {
+ return ValueObject::CreateValueObjectFromAPInt(target, value, rtype,
+ "result");
+ };
+
+ llvm::Expected<llvm::APSInt> l_value = lhs->GetValueAsAPSInt();
+ llvm::Expected<llvm::APSInt> r_value = rhs->GetValueAsAPSInt();
+
+ if (l_value && r_value) {
+ llvm::APSInt l = *l_value;
+ llvm::APSInt r = *r_value;
+
+ switch (kind) {
+ case BinaryOpKind::Add:
+ return wrap(l + r);
+
+ default:
+ assert(false && "invalid ast: invalid arithmetic operation");
+ return lldb::ValueObjectSP();
+ }
+ } else {
+ return lldb::ValueObjectSP();
+ }
+}
+
+static lldb::ValueObjectSP EvaluateArithmeticOp(lldb::TargetSP target,
+ BinaryOpKind kind,
+ lldb::ValueObjectSP lhs,
+ lldb::ValueObjectSP rhs,
+ CompilerType rtype) {
+ assert((rtype.IsInteger() || rtype.IsFloat()) &&
+ "invalid ast: result type must either integer or floating point");
+
+ // Evaluate arithmetic operation for two integral values.
+ if (rtype.IsInteger()) {
+ return EvaluateArithmeticOpInteger(target, kind, lhs, rhs, rtype);
+ }
+
+ // Removed floating point arithmetics
+
+ return lldb::ValueObjectSP();
+}
+
+llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinaryAddition(
+ lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs, uint32_t location) {
+ // Addition of two arithmetic types.
+ if (lhs->GetCompilerType().IsScalarType() &&
+ rhs->GetCompilerType().IsScalarType()) {
+ return EvaluateArithmeticOp(m_target, BinaryOpKind::Add, lhs, rhs,
+ lhs->GetCompilerType().GetCanonicalType());
+ }
+
+ // Removed pointer arithmetics
+ return llvm::make_error<DILDiagnosticError>(m_expr, "unimplemented",
+ location);
+}
+
+lldb::ValueObjectSP
+Interpreter::ConvertValueObjectToTypeSystem(lldb::ValueObjectSP valobj,
+ lldb::TypeSystemSP type_system) {
+ auto apsint = valobj->GetValueAsAPSInt();
+ if (apsint) {
+ llvm::APInt value = *apsint;
+ if (type_system) {
+ lldb::BasicType basic_type = valobj->GetCompilerType()
+ .GetCanonicalType()
+ .GetBasicTypeEnumeration();
+ if (auto compiler_type =
+ type_system.get()->GetBasicTypeFromAST(basic_type)) {
+ valobj->GetValue().SetCompilerType(compiler_type);
+ return ValueObject::CreateValueObjectFromAPInt(m_target, value,
+ compiler_type, "result");
+ }
+ }
+ }
+
+ return lldb::ValueObjectSP();
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const BinaryOpNode *node) {
+ auto lhs_or_err = Evaluate(node->GetLHS());
+ if (!lhs_or_err)
+ return lhs_or_err;
+ lldb::ValueObjectSP lhs = *lhs_or_err;
+ auto rhs_or_err = Evaluate(node->GetRHS());
+ if (!rhs_or_err)
+ return rhs_or_err;
+ lldb::ValueObjectSP rhs = *rhs_or_err;
+
+ lldb::TypeSystemSP lhs_system =
+ lhs->GetCompilerType().GetTypeSystem().GetSharedPointer();
+ lldb::TypeSystemSP rhs_system =
+ rhs->GetCompilerType().GetTypeSystem().GetSharedPointer();
+
+ // Is this a correct way to check if type systems are the same?
+ if (lhs_system != rhs_system) {
+ // If one of the nodes is a scalar const, convert it to the
+ // type system of another one
+ if (node->GetLHS()->GetKind() == NodeKind::eScalarLiteralNode)
+ lhs = ConvertValueObjectToTypeSystem(lhs, rhs_system);
+ else if (node->GetRHS()->GetKind() == NodeKind::eScalarLiteralNode)
+ rhs = ConvertValueObjectToTypeSystem(rhs, lhs_system);
+ else
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, "incompatible type systems", node->GetLocation());
+ }
+
+ switch (node->GetKind()) {
+ case BinaryOpKind::Add:
+ if (auto err = PrepareBinaryAddition(lhs, rhs, node->GetLocation()))
+ return err;
+ return EvaluateBinaryAddition(lhs, rhs, node->GetLocation());
+
+ // Other ops
+
+ default:
+ break;
+ }
+
+ return llvm::make_error<DILDiagnosticError>(m_expr, "unimplemented",
+ node->GetLocation());
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp
index eaefaf484bc18..2031bf677d6d7 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -40,6 +40,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "numeric_constant";
case Kind::period:
return "period";
+ case Kind::plus:
+ return "plus";
case Kind::r_paren:
return "r_paren";
case Kind::r_square:
@@ -114,10 +116,10 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
return Token(Token::identifier, maybe_word->str(), position);
constexpr std::pair<Token::Kind, const char *> operators[] = {
- {Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
- {Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
- {Token::period, "."}, {Token::r_paren, ")"}, {Token::r_square, "]"},
- {Token::star, "*"},
+ {Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
+ {Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
+ {Token::period, "."}, {Token::plus, "+"}, {Token::r_paren, ")"},
+ {Token::r_square, "]"}, {Token::star, "*"},
};
for (auto [kind, str] : operators) {
if (remainder.consume_front(str))
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index eac41fab90763..6de54eabc8ca1 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -80,9 +80,30 @@ ASTNodeUP DILParser::Run() {
// Parse an expression.
//
// expression:
-// unary_expression
+// additive_expression
//
-ASTNodeUP DILParser::ParseExpression() { return ParseUnaryExpression(); }
+ASTNodeUP DILParser::ParseExpression() { return ParseAdditiveExpression(); }
+
+// Parse an additive_expression.
+//
+// additive_expression:
+// unary_expression {"+" unary_expression}
+// unary_expression {"-" unary_expression}
+//
+ASTNodeUP DILParser::ParseAdditiveExpression() {
+ auto lhs = ParseUnaryExpression();
+
+ while (CurToken().IsOneOf({Token::plus, Token::minus})) {
+ Token token = CurToken();
+ m_dil_lexer.Advance();
+ auto rhs = ParseUnaryExpression();
+ lhs = std::make_unique<BinaryOpNode>(
+ token.GetLocation(), GetBinaryOpKindFromToken(token.GetKind()),
+ std::move(lhs), std::move(rhs));
+ }
+
+ return lhs;
+}
// Parse an unary_expression.
//
@@ -183,6 +204,8 @@ ASTNodeUP DILParser::ParsePostfixExpression() {
// "(" expression ")"
//
ASTNodeUP DILParser::ParsePrimaryExpression() {
+ if (CurToken().Is(Token::numeric_constant))
+ return ParseNumericLiteral();
if (CurToken().IsOneOf(
{Token::coloncolon, Token::identifier, Token::l_paren})) {
// Save the source location for the diagnostics message.
@@ -351,6 +374,7 @@ void DILParser::BailOut(const std::string &error, uint32_t loc,
// integer_literal:
// ? Integer constant ?
//
+// Haven't removed this yet in order to not rewrite the array subscription
std::optional<int64_t> DILParser::ParseIntegerConstant() {
std::string number_spelling;
if (CurToken().GetKind() == Token::minus) {
@@ -370,6 +394,52 @@ std::optional<int64_t> DILParser::ParseIntegerConstant() {
return std::nullopt;
}
+// Parse a numeric_literal.
+//
+// numeric_literal:
+// ? Token::numeric_constant ?
+//
+ASTNodeUP DILParser::ParseNumericLiteral() {
+ Expect(Token::numeric_constant);
+ ASTNodeUP numeric_constant = ParseNumericConstant();
+ if (numeric_constant->GetKind() == NodeKind::eErrorNode) {
+ BailOut(llvm::formatv("Failed to parse token as numeric-constant: {0}",
+ CurToken()),
+ CurToken().GetLocation(), CurToken().GetSpelling().length());
+ return std::make_unique<ErrorNode>();
+ }
+ m_dil_lexer.Advance();
+ return numeric_constant;
+}
+
+static constexpr std::pair<const char *, lldb::BasicType> type_suffixes[] = {
+ {"ull", lldb::eBasicTypeUnsignedLongLong},
+ {"ul", lldb::eBasicTypeUnsignedLong},
+ {"u", lldb::eBasicTypeUnsignedInt},
+ {"ll", lldb::eBasicTypeLongLong},
+ {"l", lldb::eBasicTypeLong},
+};
+
+ASTNodeUP DILParser::ParseNumericConstant() {
+ Token token = CurToken();
+ auto spelling = token.GetSpelling();
+ llvm::StringRef spelling_ref = spelling;
+ lldb::BasicType type = lldb::eBasicTypeInt;
+ for (auto [suffix, t] : type_suffixes) {
+ if (spelling_ref.consume_back_insensitive(suffix)) {
+ type = t;
+ break;
+ }
+ }
+ llvm::APInt raw_value;
+ if (!spelling_ref.getAsInteger(0, raw_value)) {
+ Scalar scalar_value(raw_value);
+ return std::make_unique<ScalarLiteralNode>(token.GetLocation(), type,
+ scalar_value);
+ }
+ return std::make_unique<ErrorNode>();
+}
+
void DILParser::Expect(Token::Kind kind) {
if (CurToken().IsNot(kind)) {
BailOut(llvm::formatv("expected {0}, got: {1}", kind, CurToken()),
>From 81404fb9fd2eeab5f3d11a00f1ab3074262eccdc Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Thu, 17 Jul 2025 00:28:10 +0500
Subject: [PATCH 2/2] Use Scalar for arithmetic operations
---
lldb/include/lldb/ValueObject/DILEval.h | 6 +-
lldb/source/ValueObject/DILEval.cpp | 338 ++++++------------------
2 files changed, 78 insertions(+), 266 deletions(-)
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index 9e9028f6122fd..d9ac16cd41d16 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -62,13 +62,9 @@ class Interpreter : Visitor {
ConvertValueObjectToTypeSystem(lldb::ValueObjectSP valobj,
lldb::TypeSystemSP type_system);
- llvm::Error PrepareBinaryAddition(lldb::ValueObjectSP &lhs,
- lldb::ValueObjectSP &rhs,
- uint32_t location);
-
llvm::Expected<lldb::ValueObjectSP>
EvaluateBinaryAddition(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
- uint32_t location);
+ uint32_t location, std::shared_ptr<StackFrame> ctx);
// Used by the interpreter to create objects, perform casts, etc.
lldb::TargetSP m_target;
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 2e42b57e93042..42d09686d729b 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -448,290 +448,107 @@ static CompilerType GetBasicType(lldb::TypeSystemSP type_system,
return empty_type;
}
-static CompilerType DoIntegralPromotion(CompilerType from,
- std::shared_ptr<StackFrame> ctx) {
- if (!from.IsInteger() && !from.IsUnscopedEnumerationType())
- return from;
-
- if (!from.IsPromotableIntegerType())
- return from;
-
- if (from.IsUnscopedEnumerationType())
- return DoIntegralPromotion(from.GetEnumerationIntegerType(), ctx);
- lldb::BasicType builtin_type =
- from.GetCanonicalType().GetBasicTypeEnumeration();
- lldb::TypeSystemSP type_system = from.GetTypeSystem().GetSharedPointer();
-
- 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();
- if (auto temp = from.GetByteSize(ctx.get()))
- from_size = *temp;
-
- CompilerType promote_types[] = {
- GetBasicType(type_system, lldb::eBasicTypeInt),
- GetBasicType(type_system, lldb::eBasicTypeUnsignedInt),
- GetBasicType(type_system, lldb::eBasicTypeLong),
- GetBasicType(type_system, lldb::eBasicTypeUnsignedLong),
- GetBasicType(type_system, lldb::eBasicTypeLongLong),
- GetBasicType(type_system, lldb::eBasicTypeUnsignedLongLong),
- };
- for (auto &type : promote_types) {
- uint64_t byte_size = 0;
- if (auto temp = type.GetByteSize(ctx.get()))
- byte_size = *temp;
- if (from_size < byte_size ||
- (from_size == byte_size &&
- is_signed == (bool)(type.GetTypeInfo() & lldb::eTypeIsSigned))) {
- return type;
- }
+static CompilerType GetIntCompilerTypeForSize(uint32_t size, bool is_signed,
+ lldb::TypeSystemSP type_system,
+ std::shared_ptr<StackFrame> ctx) {
+ lldb::BasicType promote_types[] = {
+ lldb::eBasicTypeChar, lldb::eBasicTypeUnsignedChar,
+ lldb::eBasicTypeShort, lldb::eBasicTypeUnsignedShort,
+ lldb::eBasicTypeInt, lldb::eBasicTypeUnsignedInt,
+ lldb::eBasicTypeLong, lldb::eBasicTypeUnsignedLong,
+ lldb::eBasicTypeLongLong, lldb::eBasicTypeUnsignedLongLong,
+ };
+ for (auto &basic_type : promote_types) {
+ uint64_t byte_size = 0;
+ CompilerType type = GetBasicType(type_system, basic_type);
+ if (auto temp = type.GetByteSize(ctx.get()))
+ byte_size = *temp;
+ if (size < byte_size ||
+ (size == byte_size &&
+ is_signed == (bool)(type.GetTypeInfo() & lldb::eTypeIsSigned))) {
+ return type;
}
-
- llvm_unreachable("char type should fit into long long");
}
- // Here we can promote only to "int" or "unsigned int".
- CompilerType int_type = GetBasicType(type_system, lldb::eBasicTypeInt);
- uint64_t int_byte_size = 0;
- if (auto temp = int_type.GetByteSize(ctx.get()))
- int_byte_size = *temp;
-
- // 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)
- ? GetBasicType(type_system, lldb::eBasicTypeUnsignedInt)
- : int_type;
+ llvm_unreachable("size could not fit into long long");
+ return CompilerType();
}
-static lldb::ValueObjectSP UnaryConversion(lldb::ValueObjectSP valobj,
- std::shared_ptr<StackFrame> ctx) {
- // Perform usual conversions for unary operators.
- CompilerType in_type = valobj->GetCompilerType();
- CompilerType result_type;
-
- if (valobj->GetCompilerType().IsInteger() ||
- valobj->GetCompilerType().IsUnscopedEnumerationType()) {
- CompilerType promoted_type =
- DoIntegralPromotion(valobj->GetCompilerType(), ctx);
- if (!promoted_type.CompareTypes(valobj->GetCompilerType()))
- return valobj->CastToBasicType(promoted_type);
+static lldb::ValueObjectSP
+CreateValueObjectFromScalar(Scalar scalar, lldb::TargetSP target,
+ lldb::TypeSystemSP type_system,
+ std::shared_ptr<StackFrame> ctx) {
+ switch (scalar.GetType()) {
+ case Scalar::e_int: {
+ llvm::APSInt apsint = scalar.GetAPSInt();
+ auto ret_type = GetIntCompilerTypeForSize(
+ scalar.GetByteSize(), scalar.IsSigned(), type_system, ctx);
+ return ValueObject::CreateValueObjectFromAPInt(target, apsint, ret_type,
+ "result");
}
-
- return valobj;
-}
-
-static size_t ConversionRank(CompilerType type) {
- // Get integer conversion rank
- // https://eel.is/c++draft/conv.rank
- switch (type.GetCanonicalType().GetBasicTypeEnumeration()) {
- case lldb::eBasicTypeBool:
- return 1;
- case lldb::eBasicTypeChar:
- case lldb::eBasicTypeSignedChar:
- case lldb::eBasicTypeUnsignedChar:
- return 2;
- case lldb::eBasicTypeShort:
- case lldb::eBasicTypeUnsignedShort:
- return 3;
- case lldb::eBasicTypeInt:
- case lldb::eBasicTypeUnsignedInt:
- return 4;
- case lldb::eBasicTypeLong:
- case lldb::eBasicTypeUnsignedLong:
- return 5;
- case lldb::eBasicTypeLongLong:
- case lldb::eBasicTypeUnsignedLongLong:
- return 6;
-
- // The ranks of char16_t, char32_t, and wchar_t are equal to the
- // ranks of their underlying types.
- case lldb::eBasicTypeWChar:
- case lldb::eBasicTypeSignedWChar:
- case lldb::eBasicTypeUnsignedWChar:
- return 3;
- case lldb::eBasicTypeChar16:
- return 3;
- case lldb::eBasicTypeChar32:
- return 4;
-
- default:
- break;
+ case Scalar::e_float: {
+ llvm::APFloat apfloat = scalar.GetAPFloat();
+ auto ret_type =
+ scalar.GetByteSize() <= 4
+ ? type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat)
+ : type_system->GetBasicTypeFromAST(lldb::eBasicTypeDouble);
+ return ValueObject::CreateValueObjectFromAPFloat(target, apfloat, ret_type,
+ "result");
}
- return 0;
-}
-
-static lldb::BasicType BasicTypeToUnsigned(lldb::BasicType basic_type) {
- switch (basic_type) {
- case lldb::eBasicTypeInt:
- return lldb::eBasicTypeUnsignedInt;
- case lldb::eBasicTypeLong:
- return lldb::eBasicTypeUnsignedLong;
- case lldb::eBasicTypeLongLong:
- return lldb::eBasicTypeUnsignedLongLong;
default:
- return basic_type;
+ return lldb::ValueObjectSP();
}
}
-static void PerformIntegerConversions(std::shared_ptr<StackFrame> ctx,
- lldb::ValueObjectSP &lhs,
- lldb::ValueObjectSP &rhs,
- bool convert_lhs, bool convert_rhs) {
- CompilerType l_type = lhs->GetCompilerType();
- CompilerType r_type = rhs->GetCompilerType();
- if (r_type.IsSigned() && !l_type.IsSigned()) {
- uint64_t l_size = 0;
- uint64_t r_size = 0;
- if (auto temp = l_type.GetByteSize(ctx.get()))
- l_size = *temp;
- ;
- if (auto temp = r_type.GetByteSize(ctx.get()))
- r_size = *temp;
- if (l_size <= r_size) {
- if (r_size == l_size) {
- lldb::TypeSystemSP type_system =
- l_type.GetTypeSystem().GetSharedPointer();
- auto r_type_unsigned = GetBasicType(
- type_system,
- BasicTypeToUnsigned(
- r_type.GetCanonicalType().GetBasicTypeEnumeration()));
- if (convert_rhs)
- rhs = rhs->CastToBasicType(r_type_unsigned);
+static Scalar GetScalarFromValueObject(lldb::ValueObjectSP valobj,
+ std::shared_ptr<StackFrame> ctx) {
+ if (valobj->GetCompilerType().IsInteger()) {
+ llvm::Expected<llvm::APSInt> value = valobj->GetValueAsAPSInt();
+ if (value) {
+ auto type_size = valobj->GetCompilerType().GetBitSize(ctx.get());
+ if (type_size) {
+ llvm::APInt adjusted(*type_size, value->getExtValue(),
+ value->isSigned());
+ return Scalar(adjusted);
}
}
+ } else {
+ llvm::Expected<llvm::APFloat> l_value = valobj->GetValueAsAPFloat();
+ if (l_value)
+ return Scalar(*l_value);
}
- if (convert_lhs)
- lhs = lhs->CastToBasicType(rhs->GetCompilerType());
-}
-
-static CompilerType ArithmeticConversions(lldb::ValueObjectSP &lhs,
- lldb::ValueObjectSP &rhs,
- std::shared_ptr<StackFrame> ctx) {
- // Apply unary conversion (e.g. intergal promotion) for both operands.
- lhs = UnaryConversion(lhs, ctx);
- rhs = UnaryConversion(rhs, ctx);
-
- CompilerType lhs_type = lhs->GetCompilerType();
- CompilerType rhs_type = rhs->GetCompilerType();
-
- if (lhs_type.CompareTypes(rhs_type))
- return lhs_type;
-
- // If either of the operands is not arithmetic (e.g. pointer), we're done.
- if (!lhs_type.IsScalarType() || !rhs_type.IsScalarType()) {
- CompilerType bad_type;
- return bad_type;
- }
-
- // Removed floating point conversions
- if (lhs_type.IsFloat() || rhs_type.IsFloat()) {
- CompilerType bad_type;
- return bad_type;
- }
-
- if (lhs_type.IsInteger() && rhs_type.IsInteger()) {
- using Rank = std::tuple<size_t, bool>;
- Rank l_rank = {ConversionRank(lhs_type), !lhs_type.IsSigned()};
- Rank r_rank = {ConversionRank(rhs_type), !rhs_type.IsSigned()};
-
- if (l_rank < r_rank) {
- PerformIntegerConversions(ctx, lhs, rhs, true, true);
- } else if (l_rank > r_rank) {
- PerformIntegerConversions(ctx, rhs, lhs, true, true);
- }
- }
-
- return rhs_type;
+ return Scalar();
}
-llvm::Error Interpreter::PrepareBinaryAddition(lldb::ValueObjectSP &lhs,
- lldb::ValueObjectSP &rhs,
- uint32_t location) {
- // Operation '+' works for:
- //
- // {scalar,unscoped_enum} <-> {scalar,unscoped_enum}
- // {integer,unscoped_enum} <-> pointer
- // pointer <-> {integer,unscoped_enum}
- auto orig_lhs_type = lhs->GetCompilerType();
- auto orig_rhs_type = rhs->GetCompilerType();
- auto result_type = ArithmeticConversions(lhs, rhs, m_exe_ctx_scope);
-
- if (result_type.IsScalarType())
- return llvm::Error::success();
-
- // Removed pointer arithmetics
- return llvm::make_error<DILDiagnosticError>(m_expr, "unimplemented",
- location);
-}
-
-static lldb::ValueObjectSP EvaluateArithmeticOpInteger(lldb::TargetSP target,
- BinaryOpKind kind,
- lldb::ValueObjectSP lhs,
- lldb::ValueObjectSP rhs,
- CompilerType rtype) {
- assert(lhs->GetCompilerType().IsInteger() &&
- rhs->GetCompilerType().IsInteger() &&
- "invalid ast: both operands must be integers");
-
- auto wrap = [target, rtype](auto value) {
- return ValueObject::CreateValueObjectFromAPInt(target, value, rtype,
- "result");
- };
-
- llvm::Expected<llvm::APSInt> l_value = lhs->GetValueAsAPSInt();
- llvm::Expected<llvm::APSInt> r_value = rhs->GetValueAsAPSInt();
+static lldb::ValueObjectSP
+EvaluateArithmeticOp(lldb::TargetSP target, BinaryOpKind kind,
+ lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
+ std::shared_ptr<StackFrame> ctx) {
+ auto type_system = lhs->GetCompilerType().GetTypeSystem().GetSharedPointer();
+ Scalar l = GetScalarFromValueObject(lhs, ctx);
+ Scalar r = GetScalarFromValueObject(rhs, ctx);
- if (l_value && r_value) {
- llvm::APSInt l = *l_value;
- llvm::APSInt r = *r_value;
+ if (!l.IsValid() || !r.IsValid())
+ return lldb::ValueObjectSP();
- switch (kind) {
- case BinaryOpKind::Add:
- return wrap(l + r);
+ switch (kind) {
+ case BinaryOpKind::Add:
+ return CreateValueObjectFromScalar(l + r, target, type_system, ctx);
- default:
- assert(false && "invalid ast: invalid arithmetic operation");
- return lldb::ValueObjectSP();
- }
- } else {
+ default:
+ assert(false && "invalid ast: invalid arithmetic operation");
return lldb::ValueObjectSP();
}
}
-static lldb::ValueObjectSP EvaluateArithmeticOp(lldb::TargetSP target,
- BinaryOpKind kind,
- lldb::ValueObjectSP lhs,
- lldb::ValueObjectSP rhs,
- CompilerType rtype) {
- assert((rtype.IsInteger() || rtype.IsFloat()) &&
- "invalid ast: result type must either integer or floating point");
-
- // Evaluate arithmetic operation for two integral values.
- if (rtype.IsInteger()) {
- return EvaluateArithmeticOpInteger(target, kind, lhs, rhs, rtype);
- }
-
- // Removed floating point arithmetics
-
- return lldb::ValueObjectSP();
-}
-
-llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinaryAddition(
- lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs, uint32_t location) {
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::EvaluateBinaryAddition(lldb::ValueObjectSP lhs,
+ lldb::ValueObjectSP rhs, uint32_t location,
+ std::shared_ptr<StackFrame> ctx) {
// Addition of two arithmetic types.
if (lhs->GetCompilerType().IsScalarType() &&
rhs->GetCompilerType().IsScalarType()) {
- return EvaluateArithmeticOp(m_target, BinaryOpKind::Add, lhs, rhs,
- lhs->GetCompilerType().GetCanonicalType());
+ return EvaluateArithmeticOp(m_target, BinaryOpKind::Add, lhs, rhs, ctx);
}
// Removed pointer arithmetics
@@ -792,9 +609,8 @@ Interpreter::Visit(const BinaryOpNode *node) {
switch (node->GetKind()) {
case BinaryOpKind::Add:
- if (auto err = PrepareBinaryAddition(lhs, rhs, node->GetLocation()))
- return err;
- return EvaluateBinaryAddition(lhs, rhs, node->GetLocation());
+ return EvaluateBinaryAddition(lhs, rhs, node->GetLocation(),
+ m_exe_ctx_scope);
// Other ops
More information about the lldb-commits
mailing list