[Lldb-commits] [lldb] eb75458 - [lldb] Add operator `sizeof` to DIL (#211772)
via lldb-commits
lldb-commits at lists.llvm.org
Tue Aug 11 07:16:36 PDT 2026
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;
+}
More information about the lldb-commits
mailing list