[llvm-branch-commits] [lldb] [lldb] Add operator `sizeof` to DIL (PR #211772)
Ilia Kuklin via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Aug 7 05:49:42 PDT 2026
https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/211772
>From 8e29c7bef305697e928f2135844650ec18eb1ccd Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Mon, 20 Jul 2026 23:07:50 +0500
Subject: [PATCH 1/2] [lldb] Add sizeof operator to DIL
---
lldb/docs/dil-expr-lang.ebnf | 4 +-
lldb/include/lldb/ValueObject/DILAST.h | 26 +++++++
lldb/include/lldb/ValueObject/DILEval.h | 1 +
lldb/source/ValueObject/DILAST.cpp | 4 ++
lldb/source/ValueObject/DILEval.cpp | 35 +++++++++
lldb/source/ValueObject/DILParser.cpp | 18 ++++-
.../frame/var-dil/expr/SizeOf/Makefile | 3 +
.../expr/SizeOf/TestFrameVarDILExprSizeOf.py | 72 +++++++++++++++++++
.../frame/var-dil/expr/SizeOf/main.cpp | 33 +++++++++
9 files changed, 194 insertions(+), 2 deletions(-)
create mode 100644 lldb/test/API/commands/frame/var-dil/expr/SizeOf/Makefile
create mode 100644 lldb/test/API/commands/frame/var-dil/expr/SizeOf/TestFrameVarDILExprSizeOf.py
create mode 100644 lldb/test/API/commands/frame/var-dil/expr/SizeOf/main.cpp
diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 0dbfea6eeb637..9c610107da98a 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -45,7 +45,9 @@ postfix_expression = primary_expression
primary_expression = numeric_literal
| boolean_literal
| id_expression
- | "(" expression ")" ;
+ | "(" expression ")"
+ | "sizeof" "(" expression ")"
+ | "sizeof" "(" type_id ")" ;
id_expression = unqualified_id
| qualified_id
diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h
index a2b02bb4a9da8..99abac9001341 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -29,6 +29,7 @@ enum class NodeKind {
eIdentifierNode,
eIntegerLiteralNode,
eMemberOfNode,
+ eSizeOfNode,
eUnaryOpNode,
};
@@ -324,6 +325,30 @@ class CastNode : public ASTNode {
CastKind m_cast_kind;
};
+class SizeOfNode : public ASTNode {
+public:
+ SizeOfNode(uint32_t location, ASTNodeUP node)
+ : ASTNode(location, NodeKind::eSizeOfNode), m_node_arg(std::move(node)) {}
+
+ SizeOfNode(uint32_t location, CompilerType type)
+ : ASTNode(location, NodeKind::eSizeOfNode), m_type_arg(type) {}
+
+ llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
+
+ const std::string &GetFunctionName() const { return m_name; }
+ ASTNode &GetNodeArg() const { return *m_node_arg; }
+ CompilerType GetTypeArg() const { return m_type_arg; }
+
+ static bool classof(const ASTNode &node) {
+ return node.GetKind() == NodeKind::eSizeOfNode;
+ }
+
+private:
+ std::string m_name;
+ ASTNodeUP m_node_arg;
+ CompilerType m_type_arg;
+};
+
/// 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
@@ -350,6 +375,7 @@ class Visitor {
virtual llvm::Expected<lldb::ValueObjectSP>
Visit(const BooleanLiteralNode &node) = 0;
virtual llvm::Expected<lldb::ValueObjectSP> Visit(const CastNode &node) = 0;
+ virtual llvm::Expected<lldb::ValueObjectSP> Visit(const SizeOfNode &node) = 0;
};
} // namespace lldb_private::dil
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index 59fe465b2dd88..489dc801b20db 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -73,6 +73,7 @@ class Interpreter : Visitor {
llvm::Expected<lldb::ValueObjectSP>
Visit(const BooleanLiteralNode &node) override;
llvm::Expected<lldb::ValueObjectSP> Visit(const CastNode &node) override;
+ llvm::Expected<lldb::ValueObjectSP> Visit(const SizeOfNode &node) override;
/// Perform usual unary conversions on a value. At the moment this
/// includes array-to-pointer and integral promotion for eligible types.
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
index bb018712a1ba4..275564916a840 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -93,4 +93,8 @@ llvm::Expected<lldb::ValueObjectSP> CastNode::Accept(Visitor *v) const {
return v->Visit(*this);
}
+llvm::Expected<lldb::ValueObjectSP> SizeOfNode::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 867d6a74f87de..76ecc85c01814 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -1682,4 +1682,39 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const CastNode &node) {
node.GetLocation());
}
+llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const SizeOfNode &node) {
+ CompilerType typearg = node.GetTypeArg();
+ Scalar size;
+ if (typearg.IsValid()) {
+ if (typearg.IsReferenceType())
+ typearg = typearg.GetNonReferenceType();
+ llvm::Expected<uint64_t> byte_size = typearg.GetByteSize(m_target.get());
+ if (!byte_size)
+ return byte_size.takeError();
+ size = *byte_size;
+ } else {
+ auto arg_or_err = EvaluateAndDereference(node.GetNodeArg());
+ if (!arg_or_err)
+ return arg_or_err;
+ lldb::ValueObjectSP arg = *arg_or_err;
+
+ llvm::Expected<uint64_t> byte_size = arg->GetByteSize();
+ if (!byte_size)
+ return byte_size.takeError();
+ size = *byte_size;
+ }
+
+ llvm::Expected<lldb::TypeSystemSP> type_system =
+ GetTypeSystemFromCU(m_stack_frame);
+ if (!type_system)
+ return type_system.takeError();
+ CompilerType size_type = type_system.get()->GetSizeType();
+ if (!size_type)
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, "unable to determine size type", node.GetLocation());
+
+ return ValueObject::CreateValueObjectFromScalar(m_stack_frame, size,
+ size_type, "result");
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index 3af14d31c2e8b..389ce870539e4 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -472,8 +472,24 @@ ASTNodeUP DILParser::ParsePrimaryExpression() {
uint32_t loc = CurToken().GetLocation();
std::string identifier = ParseIdExpression();
- if (!identifier.empty())
+ if (!identifier.empty()) {
+ if (identifier == "sizeof" && CurToken().Is(Token::l_paren)) {
+ m_dil_lexer.Advance();
+ uint32_t save_token_idx = m_dil_lexer.GetCurrentTokenIdx();
+ auto type_id = ParseTypeId();
+ if (type_id) {
+ Expect(Token::r_paren);
+ m_dil_lexer.Advance();
+ return std::make_unique<SizeOfNode>(loc, *type_id);
+ }
+ TentativeParsingRollback(save_token_idx);
+ ASTNodeUP expr = ParseExpression();
+ Expect(Token::r_paren);
+ m_dil_lexer.Advance();
+ return std::make_unique<SizeOfNode>(loc, std::move(expr));
+ }
return std::make_unique<IdentifierNode>(loc, identifier);
+ }
}
if (CurToken().Is(Token::l_paren)) {
diff --git a/lldb/test/API/commands/frame/var-dil/expr/SizeOf/Makefile b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/commands/frame/var-dil/expr/SizeOf/TestFrameVarDILExprSizeOf.py b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/TestFrameVarDILExprSizeOf.py
new file mode 100644
index 0000000000000..05b491aec1286
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/TestFrameVarDILExprSizeOf.py
@@ -0,0 +1,72 @@
+"""
+Test DIL operator sizeof().
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+
+class TestFrameVarDILExprSizeOf(TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def test_sizeof(self):
+ self.build()
+ (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+ self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+ )
+
+ self.runCmd("settings set target.experimental.use-DIL true")
+
+ frame = thread.GetFrameAtIndex(0)
+ int_size = frame.GetValueForVariablePath("int_size").GetValue()
+ short_size = frame.GetValueForVariablePath("short_size").GetValue()
+ double_size = frame.GetValueForVariablePath("double_size").GetValue()
+ ptr_size = frame.GetValueForVariablePath("ptr_size").GetValue()
+ intref_size = frame.GetValueForVariablePath("intref_size").GetValue()
+ arr_size = frame.GetValueForVariablePath("arr_size").GetValue()
+ foo_size = frame.GetValueForVariablePath("foo_size").GetValue()
+ enum_size = frame.GetValueForVariablePath("enum_size").GetValue()
+
+ # Check variables
+ self.expect_var_path("sizeof(i)", value=int_size, type="__size_t")
+ self.expect_var_path("sizeof(sh)", value=short_size)
+ self.expect_var_path("sizeof(d)", value=double_size)
+ self.expect_var_path("sizeof(ptr)", value=ptr_size)
+ self.expect_var_path("sizeof(iref)", value=intref_size)
+ self.expect_var_path("sizeof(arr)", value=arr_size)
+ self.expect_var_path("sizeof(arr + 1)", value=ptr_size)
+
+ # Check types
+ self.expect_var_path("sizeof(int)", value=int_size)
+ self.expect_var_path("sizeof(int*)", value=ptr_size)
+ self.expect_var_path("sizeof(int***)", value=ptr_size)
+ self.expect_var_path("sizeof(short)", value=short_size)
+ self.expect_var_path("sizeof(double)", value=double_size)
+ self.expect_var_path("sizeof(int&)", value=intref_size)
+ self.expect_var_path("sizeof(short&)", value=short_size)
+ self.expect_var_path("sizeof(char&)", value="1")
+ self.expect_var_path("sizeof(short*&)", value=ptr_size)
+
+ # Check struct
+ self.expect_var_path("sizeof(foo)", value=foo_size)
+ self.expect_var_path("sizeof(&foo)", value=ptr_size)
+ self.expect_var_path("sizeof(*foo_ptr)", value=foo_size)
+ self.expect_var_path("sizeof(SizeOfFoo)", value=foo_size)
+ self.expect_var_path("sizeof(SizeOfFoo&)", value=foo_size)
+ self.expect_var_path("sizeof(SizeOfFoo*)", value=ptr_size)
+
+ # Check enum
+ self.expect_var_path("sizeof(enum_one)", value=enum_size)
+ self.expect_var_path("sizeof(&enum_one)", value=ptr_size)
+ self.expect_var_path("sizeof(UnscopedEnum16::kOne16)", value=enum_size)
+ self.expect_var_path("sizeof(UnscopedEnum16)", value=enum_size)
+ self.expect_var_path("sizeof(UnscopedEnum16&)", value=enum_size)
+ self.expect_var_path("sizeof(UnscopedEnum16*)", value=ptr_size)
+
+ self.expect(
+ "frame var -- 'sizeof(bar)'",
+ error=True,
+ substrs=["use of undeclared identifier 'bar'"],
+ )
diff --git a/lldb/test/API/commands/frame/var-dil/expr/SizeOf/main.cpp b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/main.cpp
new file mode 100644
index 0000000000000..61210642f58a7
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/main.cpp
@@ -0,0 +1,33 @@
+#include <cstdint>
+
+void stop() {}
+
+int main(int argc, char **argv) {
+ int i = 1;
+ short sh = 1;
+ double d = 1.0;
+ int *ptr = &i;
+ int &iref = i;
+ int arr[] = {1, 2, 3};
+
+ struct SizeOfFoo {
+ int x, y;
+ double d;
+ } foo;
+ SizeOfFoo *foo_ptr = &foo;
+
+ enum UnscopedEnum16 : int16_t { kZero16, kOne16 };
+ UnscopedEnum16 enum_one = kOne16;
+
+ auto int_size = sizeof(int);
+ auto short_size = sizeof(short);
+ auto double_size = sizeof(double);
+ auto ptr_size = sizeof(int *);
+ auto intref_size = sizeof(int &);
+ auto arr_size = sizeof(arr);
+ auto foo_size = sizeof(SizeOfFoo);
+ auto enum_size = sizeof(UnscopedEnum16);
+
+ stop(); // Set a breakpoint here
+ return 0;
+}
>From d2d69b06409095a067a54a03255d86f32a91a809 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Fri, 24 Jul 2026 22:40:26 +0500
Subject: [PATCH 2/2] Remove unused method
---
lldb/include/lldb/ValueObject/DILAST.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h
index 99abac9001341..b48fa33e5529c 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -335,7 +335,6 @@ class SizeOfNode : public ASTNode {
llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
- const std::string &GetFunctionName() const { return m_name; }
ASTNode &GetNodeArg() const { return *m_node_arg; }
CompilerType GetTypeArg() const { return m_type_arg; }
More information about the llvm-branch-commits
mailing list