Author: Ilia Kuklin
Date: 2026-08-11T19:16:25+05:00
New Revision: eb7545872d4a480fdd6b0ce2144941e9dbbde8ce

URL: 
https://github.com/llvm/llvm-project/commit/eb7545872d4a480fdd6b0ce2144941e9dbbde8ce
DIFF: 
https://github.com/llvm/llvm-project/commit/eb7545872d4a480fdd6b0ce2144941e9dbbde8ce.diff

LOG: [lldb] Add operator `sizeof` to DIL (#211772)

Added: 
    lldb/test/API/commands/frame/var-dil/expr/SizeOf/Makefile
    
lldb/test/API/commands/frame/var-dil/expr/SizeOf/TestFrameVarDILExprSizeOf.py
    lldb/test/API/commands/frame/var-dil/expr/SizeOf/main.cpp

Modified: 
    lldb/docs/dil-expr-lang.ebnf
    lldb/include/lldb/ValueObject/DILAST.h
    lldb/include/lldb/ValueObject/DILEval.h
    lldb/source/ValueObject/DILAST.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 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..b48fa33e5529c 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,29 @@ 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;
+
+  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 +374,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..0ef4e244410a4 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -1682,4 +1682,44 @@ 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;
+
+    if (arg->IsBitfield())
+      return llvm::make_error<DILDiagnosticError>(
+          m_expr, "invalid application of 'sizeof' to bit-field",
+          node.GetLocation());
+
+    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..bf578e1c44887
--- /dev/null
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/TestFrameVarDILExprSizeOf.py
@@ -0,0 +1,86 @@
+"""
+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()
+        bitfield_size = 
frame.GetValueForVariablePath("bitfield_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)
+        self.expect_var_path("sizeof(arr[0])", value=int_size)
+        self.expect_var_path("sizeof(arr2d[1])", value=arr_size)
+        self.expect_var_path("sizeof(i + sh + d)", value=double_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)
+        self.expect_var_path("sizeof(foo.d)", value=double_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)
+
+        # Check bitfield
+        self.expect_var_path("sizeof(bitfield)", value=bitfield_size)
+        self.expect_var_path("sizeof(BitFieldStruct)", value=bitfield_size)
+        self.expect(
+            "frame var -- 'sizeof(bitfield.a)'",
+            error=True,
+            substrs=["invalid application of 'sizeof' to bit-field"],
+        )
+
+        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..948e5e9271458
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/SizeOf/main.cpp
@@ -0,0 +1,46 @@
+#include <cstdint>
+
+void stop() {}
+
+struct SizeOfFoo {
+  int x, y;
+  double d;
+  static int z;
+  virtual void foo() {}
+} foo;
+
+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};
+  int arr2d[2][3] = {{1, 2}, {3, 4, 5}};
+
+  SizeOfFoo *foo_ptr = &foo;
+
+  enum UnscopedEnum16 : int16_t { kZero16, kOne16 };
+  UnscopedEnum16 enum_one = kOne16;
+
+  struct BitFieldStruct {
+    int8_t a : 4;
+    int32_t b : 20;
+    uint32_t c : 24;
+    uint64_t d : 48;
+  };
+  BitFieldStruct bitfield = {1, 2, 3, 4};
+
+  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);
+  auto bitfield_size = sizeof(BitFieldStruct);
+
+  stop(); // Set a breakpoint here
+  return 0;
+}


        
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to