[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