[llvm-branch-commits] [lldb] [lldb] Add operator `sizeof` to DIL (PR #211772)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Jul 24 04:59:16 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Ilia Kuklin (kuilpd)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/211772.diff
9 Files Affected:
- (modified) lldb/docs/dil-expr-lang.ebnf (+3-1)
- (modified) lldb/include/lldb/ValueObject/DILAST.h (+26)
- (modified) lldb/include/lldb/ValueObject/DILEval.h (+1)
- (modified) lldb/source/ValueObject/DILAST.cpp (+4)
- (modified) lldb/source/ValueObject/DILEval.cpp (+35)
- (modified) lldb/source/ValueObject/DILParser.cpp (+17-1)
- (added) lldb/test/API/commands/frame/var-dil/expr/SizeOf/Makefile (+3)
- (added) lldb/test/API/commands/frame/var-dil/expr/SizeOf/TestFrameVarDILExprSizeOf.py (+72)
- (added) lldb/test/API/commands/frame/var-dil/expr/SizeOf/main.cpp (+33)
``````````diff
diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index f3c465711e956..a82ae3fae93d7 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -39,7 +39,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 93310a91a15bb..a343704b0d9ac 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,
};
@@ -320,6 +321,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
@@ -346,6 +371,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 35784ea9987f9..6389408dbb970 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 40bf07bdd5aab..bcaeac57b173f 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -87,4 +87,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 4c5ac96dccf74..d9b0cd16d5fc9 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -1578,4 +1578,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 b55b12a2bc42a..4d91cb139ddf1 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -397,8 +397,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;
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/211772
More information about the llvm-branch-commits
mailing list