[Lldb-commits] [lldb] [lldb] Add logical operators to DIL (PR #209742)
Ilia Kuklin via lldb-commits
lldb-commits at lists.llvm.org
Mon Jul 20 06:18:01 PDT 2026
https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/209742
>From fffdae3a777949d78609ea02b4f8851f9be31169 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Tue, 14 Jul 2026 22:38:56 +0500
Subject: [PATCH 1/3] [lldb] Add logical operators to DIL
---
lldb/docs/dil-expr-lang.ebnf | 10 ++-
lldb/include/lldb/ValueObject/DILAST.h | 3 +
lldb/include/lldb/ValueObject/DILEval.h | 2 +
lldb/include/lldb/ValueObject/DILLexer.h | 3 +
lldb/include/lldb/ValueObject/DILParser.h | 2 +
lldb/source/ValueObject/DILAST.cpp | 4 +
lldb/source/ValueObject/DILEval.cpp | 81 +++++++++++++++++++
lldb/source/ValueObject/DILLexer.cpp | 36 ++++-----
lldb/source/ValueObject/DILParser.cpp | 58 +++++++++++--
.../frame/var-dil/expr/Logical/Makefile | 3 +
.../expr/Logical/TestFrameVarDILLogical.py | 78 ++++++++++++++++++
.../frame/var-dil/expr/Logical/main.cpp | 20 +++++
12 files changed, 273 insertions(+), 27 deletions(-)
create mode 100644 lldb/test/API/commands/frame/var-dil/expr/Logical/Makefile
create mode 100644 lldb/test/API/commands/frame/var-dil/expr/Logical/TestFrameVarDILLogical.py
create mode 100644 lldb/test/API/commands/frame/var-dil/expr/Logical/main.cpp
diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index fce8f4461b46f..998b9b1acadd7 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -5,13 +5,17 @@
expression = assignment_expression ;
-assignment_expression = shift_expression
- | shift_expression assignment_operator assignment_expression ;
+assignment_expression = logical_or_expression
+ | logical_or_expression assignment_operator assignment_expression ;
assignment_operator = "="
| "+="
| "-=" ;
+logical_or_expression = logical_and_expression {"||" logical_and_expression} ;
+
+logical_and_expression = shift_expression {"&&" shift_expression} ;
+
shift_expression = additive_expression {"<<" additive_expression}
| additive_expression {">>" additive_expression} ;
@@ -28,7 +32,7 @@ cast_expression = unary_expression
unary_expression = postfix_expression
| unary_operator cast_expression ;
-unary_operator = "*" | "&" | "+" | "-";
+unary_operator = "*" | "&" | "+" | "-" | "!" ;
postfix_expression = primary_expression
| postfix_expression "[" expression "]"
diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h
index 93310a91a15bb..ba2da78cd826d 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -38,6 +38,7 @@ enum class UnaryOpKind {
Deref, ///< "*"
Minus, ///< "-"
Plus, ///< "+"
+ LNot, ///< "!"
};
/// The binary operators recognized by DIL.
@@ -52,6 +53,8 @@ enum class BinaryOpKind {
Shr, ///< ">>"
Sub, ///< "-"
SubAssign, ///< "-="
+ LAnd, ///< "&&"
+ LOr, ///< "||"
};
/// Translates DIL tokens to BinaryOpKind.
diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index 35784ea9987f9..7335702f83510 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -126,6 +126,8 @@ class Interpreter : Visitor {
llvm::Expected<lldb::ValueObjectSP>
EvaluateBinaryRemainder(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
uint32_t location);
+ llvm::Expected<lldb::ValueObjectSP> EvaluateLogical(const BinaryOpNode &node);
+
llvm::Expected<CompilerType>
PickIntegerType(lldb::TypeSystemSP type_system, ExecutionContextScope &ctx,
const IntegerLiteralNode &literal);
diff --git a/lldb/include/lldb/ValueObject/DILLexer.h b/lldb/include/lldb/ValueObject/DILLexer.h
index f9f42dc59b311..400494d1c0c6d 100644
--- a/lldb/include/lldb/ValueObject/DILLexer.h
+++ b/lldb/include/lldb/ValueObject/DILLexer.h
@@ -26,11 +26,13 @@ class Token {
public:
enum Kind {
amp,
+ ampamp,
arrow,
colon,
coloncolon,
eof,
equal,
+ exclaim,
float_constant,
greatergreater,
identifier,
@@ -44,6 +46,7 @@ class Token {
minusequal,
percent,
period,
+ pipepipe,
plus,
plusequal,
r_paren,
diff --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h
index 9e2bbff4b6614..246deb49f26c0 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -84,6 +84,8 @@ class DILParser {
ASTNodeUP ParseExpression();
ASTNodeUP ParseAssignmentExpression();
+ ASTNodeUP ParseLogicalOrExpression();
+ ASTNodeUP ParseLogicalAndExpression();
ASTNodeUP ParseShiftExpression();
ASTNodeUP ParseAdditiveExpression();
ASTNodeUP ParseMultiplicativeExpression();
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
index 40bf07bdd5aab..4cea4d044e11c 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -33,6 +33,10 @@ BinaryOpKind GetBinaryOpKindFromToken(Token::Kind token_kind) {
return BinaryOpKind::Shl;
case Token::greatergreater:
return BinaryOpKind::Shr;
+ case Token::ampamp:
+ return BinaryOpKind::LAnd;
+ case Token::pipepipe:
+ return BinaryOpKind::LOr;
default:
break;
}
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 5fc2376be0e75..1ed3fa39bc605 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -559,6 +559,25 @@ Interpreter::Visit(const UnaryOpNode &node) {
}
return operand;
}
+ case UnaryOpKind::LNot: {
+ CompilerType operand_type = operand->GetCompilerType();
+ if (!operand_type.IsContextuallyConvertibleToBool()) {
+ std::string errMsg =
+ llvm::formatv("invalid argument type '{0}' to unary expression",
+ operand_type.GetTypeName());
+ return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
+ node.GetLocation());
+ }
+ llvm::Expected<lldb::TypeSystemSP> type_system =
+ GetTypeSystemFromCU(m_stack_frame);
+ if (!type_system)
+ return type_system.takeError();
+ auto value_or_err = operand->GetValueAsBool();
+ if (value_or_err)
+ return ValueObject::CreateValueObjectFromBool(m_stack_frame, *type_system,
+ !(*value_or_err), "result");
+ break;
+ }
}
return llvm::make_error<DILDiagnosticError>(m_expr, "invalid unary operation",
node.GetLocation());
@@ -931,8 +950,68 @@ Interpreter::EvaluateBinaryShift(BinaryOpKind kind, lldb::ValueObjectSP lhs,
return EvaluateScalarOp(kind, lhs, rhs, lhs_type, location);
}
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::EvaluateLogical(const BinaryOpNode &node) {
+ // Operations {'&&', '||'} work for:
+ // {IsContextuallyConvertibleToBool} <-> {IsContextuallyConvertibleToBool}
+ // Note: Unlike C++, these operators will not evaluate or check the type
+ // of RHS if the result is determined after evaluating LHS.
+ auto lhs_or_err = EvaluateAndDereference(node.GetLHS());
+ if (!lhs_or_err)
+ return lhs_or_err;
+ lldb::ValueObjectSP lhs = *lhs_or_err;
+ auto lhs_type = lhs->GetCompilerType();
+ if (!lhs_type.IsContextuallyConvertibleToBool()) {
+ std::string errMsg = llvm::formatv(
+ "value of type {0} is not contextually convertible to 'bool'",
+ lhs_type.TypeDescription());
+ return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
+ node.GetLocation());
+ }
+ llvm::Expected<lldb::TypeSystemSP> type_system =
+ GetTypeSystemFromCU(m_stack_frame);
+ if (!type_system)
+ return type_system.takeError();
+
+ // For "&&", exit early if LHS is "false"
+ // For "||", exit early if LHS is "true".
+ auto lvalue_or_err = lhs->GetValueAsBool();
+ if (!lvalue_or_err)
+ return lvalue_or_err.takeError();
+ bool lhs_val = *lvalue_or_err;
+ bool exit_early = node.GetKind() == BinaryOpKind::LAnd ? !lhs_val : lhs_val;
+ if (exit_early)
+ return ValueObject::CreateValueObjectFromBool(m_stack_frame, *type_system,
+ lhs_val, "result");
+
+ // If the result is to be determined, evaluate the RHS.
+ auto rhs_or_err = EvaluateAndDereference(node.GetRHS());
+ if (!rhs_or_err)
+ return rhs_or_err;
+ lldb::ValueObjectSP rhs = *rhs_or_err;
+ auto rhs_type = rhs->GetCompilerType();
+ if (!rhs_type.IsContextuallyConvertibleToBool()) {
+ std::string errMsg = llvm::formatv(
+ "value of type {0} is not contextually convertible to 'bool'",
+ rhs_type.TypeDescription());
+ return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
+ node.GetLocation());
+ }
+
+ auto rvalue_or_err = rhs->GetValueAsBool();
+ if (!rvalue_or_err)
+ return rvalue_or_err.takeError();
+ return ValueObject::CreateValueObjectFromBool(m_stack_frame, *type_system,
+ *rvalue_or_err, "result");
+}
+
llvm::Expected<lldb::ValueObjectSP>
Interpreter::Visit(const BinaryOpNode &node) {
+ // Handle logical operators separately. They may or may not evaluate RHS.
+ if (node.GetKind() == BinaryOpKind::LAnd ||
+ node.GetKind() == BinaryOpKind::LOr)
+ return EvaluateLogical(node);
+
auto lhs_or_err = EvaluateAndDereference(node.GetLHS());
if (!lhs_or_err)
return lhs_or_err;
@@ -980,6 +1059,8 @@ Interpreter::Visit(const BinaryOpNode &node) {
case BinaryOpKind::Shl:
case BinaryOpKind::Shr:
return EvaluateBinaryShift(node.GetKind(), lhs, rhs, node.GetLocation());
+ default:
+ break;
}
return llvm::make_error<DILDiagnosticError>(
diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp
index 997ba6b09f872..eb5da7be06b14 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -22,6 +22,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
switch (kind) {
case Kind::amp:
return "amp";
+ case Kind::ampamp:
+ return "ampamp";
case Kind::arrow:
return "arrow";
case Kind::colon:
@@ -30,6 +32,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "coloncolon";
case Kind::equal:
return "equal";
+ case Kind::exclaim:
+ return "exclaim";
case Kind::eof:
return "eof";
case Kind::float_constant:
@@ -58,6 +62,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "percent";
case Kind::period:
return "period";
+ case Kind::pipepipe:
+ return "pipepipe";
case Kind::plus:
return "plus";
case Kind::plusequal:
@@ -198,25 +204,17 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
// be ordered longest-to-shortest in the list below. E.g. '::' must come
// before ':', and '+=' must come before '+'.
constexpr std::pair<Token::Kind, const char *> operators[] = {
- {Token::arrow, "->"},
- {Token::coloncolon, "::"},
- {Token::greatergreater, ">>"},
- {Token::lessless, "<<"},
- {Token::minusequal, "-="},
- {Token::plusequal, "+="},
- {Token::amp, "&"},
- {Token::colon, ":"},
- {Token::equal, "="},
- {Token::l_paren, "("},
- {Token::l_square, "["},
- {Token::minus, "-"},
- {Token::percent, "%"},
- {Token::period, "."},
- {Token::plus, "+"},
- {Token::r_paren, ")"},
- {Token::r_square, "]"},
- {Token::slash, "/"},
- {Token::star, "*"},
+ {Token::arrow, "->"}, {Token::ampamp, "&&"},
+ {Token::coloncolon, "::"}, {Token::greatergreater, ">>"},
+ {Token::lessless, "<<"}, {Token::minusequal, "-="},
+ {Token::pipepipe, "||"}, {Token::plusequal, "+="},
+ {Token::amp, "&"}, {Token::colon, ":"},
+ {Token::equal, "="}, {Token::exclaim, "!"},
+ {Token::l_paren, "("}, {Token::l_square, "["},
+ {Token::minus, "-"}, {Token::percent, "%"},
+ {Token::period, "."}, {Token::plus, "+"},
+ {Token::r_paren, ")"}, {Token::r_square, "]"},
+ {Token::slash, "/"}, {Token::star, "*"},
};
for (auto [kind, str] : operators) {
if (remainder.consume_front(str))
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index b55b12a2bc42a..1b8852523dad0 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -134,8 +134,8 @@ ASTNodeUP DILParser::ParseExpression() { return ParseAssignmentExpression(); }
// Parse an assignment_expression
//
// assignment_expression
-// shift_expression
-// shift_expression assignment_operator assignment_expression
+// logical_or_expression
+// logical_or_expression assignment_operator assignment_expression
//
// assignment_operator:
// "="
@@ -143,7 +143,7 @@ ASTNodeUP DILParser::ParseExpression() { return ParseAssignmentExpression(); }
// "-="
//
ASTNodeUP DILParser::ParseAssignmentExpression() {
- auto lhs = ParseShiftExpression();
+ auto lhs = ParseLogicalOrExpression();
assert(lhs && "ASTNodeUP must not contain a nullptr");
// Check if it's an assignment expression.
@@ -160,6 +160,50 @@ ASTNodeUP DILParser::ParseAssignmentExpression() {
return lhs;
}
+// Parse a logical_or_expression.
+//
+// logical_or_expression:
+// logical_and_expression {"||" logical_and_expression}
+//
+ASTNodeUP DILParser::ParseLogicalOrExpression() {
+ auto lhs = ParseLogicalAndExpression();
+ assert(lhs && "ASTNodeUP must not contain a nullptr");
+
+ while (CurToken().Is(Token::pipepipe)) {
+ Token token = CurToken();
+ m_dil_lexer.Advance();
+ auto rhs = ParseLogicalAndExpression();
+ assert(lhs && "ASTNodeUP must not contain a nullptr");
+ lhs = std::make_unique<BinaryOpNode>(
+ token.GetLocation(), GetBinaryOpKindFromToken(token.GetKind()),
+ std::move(lhs), std::move(rhs));
+ }
+
+ return lhs;
+}
+
+// Parse a logical_and_expression.
+//
+// logical_and_expression:
+// shift_expression {"&&" shift_expression}
+//
+ASTNodeUP DILParser::ParseLogicalAndExpression() {
+ auto lhs = ParseShiftExpression();
+ assert(lhs && "ASTNodeUP must not contain a nullptr");
+
+ while (CurToken().Is(Token::ampamp)) {
+ Token token = CurToken();
+ m_dil_lexer.Advance();
+ auto rhs = ParseShiftExpression();
+ assert(lhs && "ASTNodeUP must not contain a nullptr");
+ lhs = std::make_unique<BinaryOpNode>(
+ token.GetLocation(), GetBinaryOpKindFromToken(token.GetKind()),
+ std::move(lhs), std::move(rhs));
+ }
+
+ return lhs;
+}
+
// Parse a shift_expression.
//
// shift_expression:
@@ -293,10 +337,11 @@ ASTNodeUP DILParser::ParseCastExpression() {
// "*"
// "+"
// "-"
+// "!"
//
ASTNodeUP DILParser::ParseUnaryExpression() {
- if (CurToken().IsOneOf(
- {Token::amp, Token::star, Token::minus, Token::plus})) {
+ if (CurToken().IsOneOf({Token::amp, Token::star, Token::minus, Token::plus,
+ Token::exclaim})) {
Token token = CurToken();
uint32_t loc = token.GetLocation();
m_dil_lexer.Advance();
@@ -315,6 +360,9 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
case Token::plus:
return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Plus,
std::move(rhs));
+ case Token::exclaim:
+ return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::LNot,
+ std::move(rhs));
default:
llvm_unreachable("invalid token kind");
}
diff --git a/lldb/test/API/commands/frame/var-dil/expr/Logical/Makefile b/lldb/test/API/commands/frame/var-dil/expr/Logical/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/Logical/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/commands/frame/var-dil/expr/Logical/TestFrameVarDILLogical.py b/lldb/test/API/commands/frame/var-dil/expr/Logical/TestFrameVarDILLogical.py
new file mode 100644
index 0000000000000..452973092ffff
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/Logical/TestFrameVarDILLogical.py
@@ -0,0 +1,78 @@
+"""
+Test DIL logical operators.
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+
+class TestFrameVarLogical(TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def test_logical(self):
+ self.build()
+ lldbutil.run_to_source_breakpoint(
+ self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+ )
+
+ self.runCmd("settings set target.experimental.use-DIL true")
+
+ self.expect_var_path("1 && 2", value="true")
+ self.expect_var_path("0 && 1", value="false")
+ self.expect_var_path("0 || 1", value="true")
+ self.expect_var_path("0 || 0", value="false")
+
+ self.expect_var_path("!1", value="false")
+ self.expect_var_path("!!1", value="true")
+
+ self.expect_var_path("!trueVar", value="false")
+ self.expect_var_path("!!trueVar", value="true")
+ self.expect_var_path("!falseVar", value="true")
+ self.expect_var_path("!!falseVar", value="false")
+
+ self.expect_var_path("trueVar || true", value="true")
+ self.expect_var_path("trueVar && false", value="false")
+ self.expect_var_path("falseVar || true", value="true")
+ self.expect_var_path("falseVar && true", value="false")
+ self.expect_var_path("true || false && false", value="true")
+ self.expect_var_path("(true || false) && false", value="false")
+
+ self.expect_var_path("!p_ptr", value="false")
+ self.expect_var_path("!!p_ptr", value="true")
+ self.expect_var_path("p_ptr && true", value="true")
+ self.expect_var_path("p_ptr && false", value="false")
+ self.expect_var_path("!p_nullptr", value="true")
+ self.expect_var_path("!!p_nullptr", value="false")
+ self.expect_var_path("p_nullptr || true", value="true")
+ self.expect_var_path("p_nullptr || false", value="false")
+
+ self.expect_var_path("!array", value="false")
+ self.expect_var_path("!!array", value="true")
+ self.expect_var_path("array || true", value="true")
+ self.expect_var_path("false || array", value="true")
+ self.expect_var_path("array && true", value="true")
+ self.expect_var_path("array && false", value="false")
+
+ # DIL doesn't evaluate the right operand if the left one
+ # determines the result
+ self.expect_var_path("true || __doesnt_exist", value="true")
+ self.expect_var_path("false && __doesnt_exist", value="false")
+
+ # Check errors
+ self.expect(
+ "frame var -- 'false || !s'",
+ error=True,
+ substrs=["invalid argument type 'S' to unary expression"],
+ )
+ self.expect(
+ "frame var -- 's || false'",
+ error=True,
+ substrs=["value of type 'S' is not contextually convertible to 'bool'"],
+ )
+ self.expect(
+ "frame var -- 'true && s'",
+ error=True,
+ substrs=["value of type 'S' is not contextually convertible to 'bool'"],
+ )
diff --git a/lldb/test/API/commands/frame/var-dil/expr/Logical/main.cpp b/lldb/test/API/commands/frame/var-dil/expr/Logical/main.cpp
new file mode 100644
index 0000000000000..3258016157cac
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/Logical/main.cpp
@@ -0,0 +1,20 @@
+#include <cstdint>
+#include <limits>
+
+void stop() {}
+
+int main(int argc, char **argv) {
+ bool trueVar = true;
+ bool falseVar = false;
+
+ const char *p_ptr = "str";
+ const char *p_nullptr = nullptr;
+
+ int array[2] = {1, 2};
+
+ struct S {
+ } s;
+
+ stop(); // Set a breakpoint here
+ return 0;
+}
>From 057b001a1410ecba2ae13d2fed0e4c6ed4ac5cde Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Wed, 15 Jul 2026 19:23:30 +0500
Subject: [PATCH 2/3] Fix asserts
---
lldb/source/ValueObject/DILParser.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index 1b8852523dad0..54da38d8bcd8a 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -173,7 +173,7 @@ ASTNodeUP DILParser::ParseLogicalOrExpression() {
Token token = CurToken();
m_dil_lexer.Advance();
auto rhs = ParseLogicalAndExpression();
- assert(lhs && "ASTNodeUP must not contain a nullptr");
+ assert(rhs && "ASTNodeUP must not contain a nullptr");
lhs = std::make_unique<BinaryOpNode>(
token.GetLocation(), GetBinaryOpKindFromToken(token.GetKind()),
std::move(lhs), std::move(rhs));
@@ -195,7 +195,7 @@ ASTNodeUP DILParser::ParseLogicalAndExpression() {
Token token = CurToken();
m_dil_lexer.Advance();
auto rhs = ParseShiftExpression();
- assert(lhs && "ASTNodeUP must not contain a nullptr");
+ assert(rhs && "ASTNodeUP must not contain a nullptr");
lhs = std::make_unique<BinaryOpNode>(
token.GetLocation(), GetBinaryOpKindFromToken(token.GetKind()),
std::move(lhs), std::move(rhs));
>From 27c212a77cff39187698a0fab082ac358afa42cf Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Mon, 20 Jul 2026 18:17:41 +0500
Subject: [PATCH 3/3] Deferefence the reference type value
---
lldb/source/ValueObject/DILEval.cpp | 5 +++++
.../frame/var-dil/expr/Logical/TestFrameVarDILLogical.py | 2 ++
lldb/test/API/commands/frame/var-dil/expr/Logical/main.cpp | 1 +
3 files changed, 8 insertions(+)
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 1ed3fa39bc605..7ac733ddfc4de 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -560,6 +560,11 @@ Interpreter::Visit(const UnaryOpNode &node) {
return operand;
}
case UnaryOpKind::LNot: {
+ if (operand->GetCompilerType().IsReferenceType()) {
+ operand = operand->Dereference(error);
+ if (error.Fail())
+ return error.ToError();
+ }
CompilerType operand_type = operand->GetCompilerType();
if (!operand_type.IsContextuallyConvertibleToBool()) {
std::string errMsg =
diff --git a/lldb/test/API/commands/frame/var-dil/expr/Logical/TestFrameVarDILLogical.py b/lldb/test/API/commands/frame/var-dil/expr/Logical/TestFrameVarDILLogical.py
index 452973092ffff..1071ef55b01ee 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/Logical/TestFrameVarDILLogical.py
+++ b/lldb/test/API/commands/frame/var-dil/expr/Logical/TestFrameVarDILLogical.py
@@ -31,6 +31,8 @@ def test_logical(self):
self.expect_var_path("!!trueVar", value="true")
self.expect_var_path("!falseVar", value="true")
self.expect_var_path("!!falseVar", value="false")
+ self.expect_var_path("!trueRef", value="false")
+ self.expect_var_path("!!trueRef", value="true")
self.expect_var_path("trueVar || true", value="true")
self.expect_var_path("trueVar && false", value="false")
diff --git a/lldb/test/API/commands/frame/var-dil/expr/Logical/main.cpp b/lldb/test/API/commands/frame/var-dil/expr/Logical/main.cpp
index 3258016157cac..851c7538a2acf 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/Logical/main.cpp
+++ b/lldb/test/API/commands/frame/var-dil/expr/Logical/main.cpp
@@ -6,6 +6,7 @@ void stop() {}
int main(int argc, char **argv) {
bool trueVar = true;
bool falseVar = false;
+ bool &trueRef = trueVar;
const char *p_ptr = "str";
const char *p_nullptr = nullptr;
More information about the lldb-commits
mailing list