[lldb] Add arithmetic binary subtraction to DIL (#184017)

This commit is contained in:
Ilia Kuklin 2026-03-04 15:12:48 +05:00 committed by GitHub
parent b6761b287f
commit 14af5be5da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 65 additions and 7 deletions

View File

@ -5,7 +5,8 @@
expression = additive_expression ;
additive_expression = cast_expression {"+" cast_expression} ;
additive_expression = cast_expression {"+" cast_expression}
cast_expression {"-" cast_expression} ;
cast_expression = unary_expression
| "(" type_id ")" cast_expression;

View File

@ -43,6 +43,7 @@ enum class UnaryOpKind {
/// The binary operators recognized by DIL.
enum class BinaryOpKind {
Add, // "+"
Sub, // "-"
};
/// Translates DIL tokens to BinaryOpKind.

View File

@ -97,6 +97,9 @@ private:
llvm::Expected<lldb::ValueObjectSP>
EvaluateBinaryAddition(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
uint32_t location);
llvm::Expected<lldb::ValueObjectSP>
EvaluateBinarySubtraction(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
uint32_t location);
llvm::Expected<CompilerType>
PickIntegerType(lldb::TypeSystemSP type_system,
std::shared_ptr<ExecutionContextScope> ctx,

View File

@ -15,6 +15,8 @@ BinaryOpKind GetBinaryOpKindFromToken(Token::Kind token_kind) {
switch (token_kind) {
case Token::plus:
return BinaryOpKind::Add;
case Token::minus:
return BinaryOpKind::Sub;
default:
break;
}

View File

@ -558,6 +558,8 @@ Interpreter::EvaluateScalarOp(BinaryOpKind kind, lldb::ValueObjectSP lhs,
switch (kind) {
case BinaryOpKind::Add:
return value_object(l + r);
case BinaryOpKind::Sub:
return value_object(l - r);
}
return llvm::make_error<DILDiagnosticError>(
m_expr, "invalid arithmetic operation", location);
@ -585,6 +587,28 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinaryAddition(
location);
}
llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinarySubtraction(
lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs, uint32_t location) {
// Operation '-' works for:
// {scalar,unscoped_enum} <-> {scalar,unscoped_enum}
// TODO: Pointer arithmetics
auto orig_lhs_type = lhs->GetCompilerType();
auto orig_rhs_type = rhs->GetCompilerType();
auto type_or_err = ArithmeticConversion(lhs, rhs, location);
if (!type_or_err)
return type_or_err.takeError();
CompilerType result_type = *type_or_err;
if (result_type.IsScalarType())
return EvaluateScalarOp(BinaryOpKind::Sub, lhs, rhs, result_type, location);
std::string errMsg =
llvm::formatv("invalid operands to binary expression ('{0}' and '{1}')",
orig_lhs_type.GetTypeName(), orig_rhs_type.GetTypeName());
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
location);
}
llvm::Expected<lldb::ValueObjectSP>
Interpreter::Visit(const BinaryOpNode &node) {
auto lhs_or_err = EvaluateAndDereference(node.GetLHS());
@ -609,6 +633,8 @@ Interpreter::Visit(const BinaryOpNode &node) {
switch (node.GetKind()) {
case BinaryOpKind::Add:
return EvaluateBinaryAddition(lhs, rhs, node.GetLocation());
case BinaryOpKind::Sub:
return EvaluateBinarySubtraction(lhs, rhs, node.GetLocation());
}
return llvm::make_error<DILDiagnosticError>(

View File

@ -138,7 +138,7 @@ ASTNodeUP DILParser::ParseAdditiveExpression() {
auto lhs = ParseCastExpression();
assert(lhs && "ASTNodeUP must not contain a nullptr");
while (CurToken().Is(Token::plus)) {
while (CurToken().IsOneOf({Token::plus, Token::minus})) {
Token token = CurToken();
m_dil_lexer.Advance();
auto rhs = ParseCastExpression();

View File

@ -35,6 +35,9 @@ class TestFrameVarDILBitFieldExtraction(TestBase):
self.expect_var_path("value[0:enum_one]", value="3", type="int:2")
self.expect_var_path("value[enum_one:0]", value="3", type="int:2")
# Test that old range syntax is now a binary subtraction
self.expect_var_path("value[6-1]", value="1", type="int:1")
# Test array and pointer
self.expect(
"frame var 'int_arr[0:2]'",
@ -63,8 +66,3 @@ class TestFrameVarDILBitFieldExtraction(TestBase):
error=True,
substrs=["bit index is not an integer"],
)
self.expect(
"frame var 'value[0-2]'",
error=True,
substrs=["use of '-' for bitfield range is deprecated; use ':' instead"],
)

View File

@ -63,15 +63,25 @@ class TestFrameVarDILArithmetic(TestBase):
self.expect_var_path("1 + s + (x + l)", value="18", type="long")
self.expect_var_path("+2 + (-1)", value="1", type="int")
self.expect_var_path("-2 + (+1)", value="-1", type="int")
self.expect_var_path("1 + (2 - 3)", value="0")
self.expect_var_path("s - x - 1", value="7")
# Check limits and overflows
frame = thread.GetFrameAtIndex(0)
int_min = frame.GetValueForVariablePath("int_min").GetValue()
int_max = frame.GetValueForVariablePath("int_max").GetValue()
uint_max = frame.GetValueForVariablePath("uint_max").GetValue()
ll_min = frame.GetValueForVariablePath("ll_min").GetValue()
ll_max = frame.GetValueForVariablePath("ll_max").GetValue()
ull_max = frame.GetValueForVariablePath("ull_max").GetValue()
self.expect_var_path("int_max + 1", value=int_min)
self.expect_var_path("int_min - 1", value=int_max)
self.expect_var_path("uint_max + 1", value="0")
self.expect_var_path("uint_zero - 1", value=uint_max)
self.expect_var_path("ll_max + 1", value=ll_min)
self.expect_var_path("ll_min - 1", value=ll_max)
self.expect_var_path("ull_max + 1", value="0")
self.expect_var_path("ull_zero - 1", value=ull_max)
# Check signed integer promotion when different types have the same size
uint = frame.GetValueForVariablePath("ui")
@ -87,5 +97,20 @@ class TestFrameVarDILArithmetic(TestBase):
# Check references and typedefs
self.expect_var_path("ref + 1", value="3")
self.expect_var_path("ref - 1l", value="1")
self.expect_var_path("my_ref + 1", value="3")
self.expect_var_path("my_ref - 1", value="1")
self.expect_var_path("ref + my_ref", value="4")
self.expect_var_path("ref - my_ref", value="0")
# TODO: Pointer arithmetics
self.expect(
"frame var -- 'p + 1'",
error=True,
substrs=["invalid operands to binary expression ('int *' and 'int')"],
)
self.expect(
"frame var -- 'p - 1'",
error=True,
substrs=["invalid operands to binary expression ('int *' and 'int')"],
)

View File

@ -33,9 +33,11 @@ int main(int argc, char **argv) {
int int_max = std::numeric_limits<int>::max();
int int_min = std::numeric_limits<int>::min();
unsigned int uint_max = std::numeric_limits<unsigned int>::max();
unsigned int uint_zero = 0;
long long ll_max = std::numeric_limits<long long>::max();
long long ll_min = std::numeric_limits<long long>::min();
unsigned long long ull_max = std::numeric_limits<unsigned long long>::max();
unsigned long long ull_zero = 0;
return 0; // Set a breakpoint here
}