https://github.com/kuilpd updated 
https://github.com/llvm/llvm-project/pull/214348

>From 0fedba653fb77500356ad89222eaf1a754d73756 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <[email protected]>
Date: Mon, 3 Aug 2026 22:53:48 +0500
Subject: [PATCH 1/5] [lldb] Restrict expressions to one assignment in DIL

---
 lldb/docs/dil-expr-lang.ebnf                  | 22 ++---
 lldb/include/lldb/ValueObject/DILParser.h     |  3 +-
 lldb/source/ValueObject/DILParser.cpp         | 89 ++++++++++---------
 .../expr/Assignment/TestFrameVarDILAssign.py  | 23 +++++
 .../TestFrameVarDILCompositeAssign.py         | 17 ++++
 5 files changed, 103 insertions(+), 51 deletions(-)

diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index a0d49204ceb55..9d0c35f8c8c97 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -3,18 +3,20 @@
 (* This is currently a subset of the final DIL Language, matching the current
    DIL implementation. *)
 
-expression = conditional_expression ;
+expression = assignment_expression ;
 
-conditional_expression = assignment_expression
-                       | assignment_expression "?" expression ":" expression ;
-
-assignment_expression = logical_or_expression
-                      | logical_or_expression assignment_operator 
assignment_expression ;
+assignment_expression = pure_expression
+                      | pure_expression assignment_operator pure_expression ;
 
 assignment_operator = "="
                     | "+="
                     | "-=" ;
 
+pure_expression = conditional_expression ;
+
+conditional_expression = logical_or_expression
+                       | logical_or_expression "?" pure_expression ":" 
pure_expression ;
+
 logical_or_expression = logical_and_expression {"||" logical_and_expression} ;
 
 logical_and_expression = inclusive_or_expression {"&&" 
inclusive_or_expression} ;
@@ -52,16 +54,16 @@ unary_expression = postfix_expression
 unary_operator = "*" | "&" | "+" | "-" | "~" | "!" ;
 
 postfix_expression = primary_expression
-                   | postfix_expression "[" expression "]"
-                   | postfix_expression "[" expression ":" expression "]"
+                   | postfix_expression "[" pure_expression "]"
+                   | postfix_expression "[" pure_expression ":" 
pure_expression "]"
                    | postfix_expression "." id_expression
                    | postfix_expression "->" id_expression ;
 
 primary_expression = numeric_literal
                    | boolean_literal
                    | id_expression
-                   | "(" expression ")"
-                   | "sizeof" "(" expression ")"
+                   | "(" pure_expression ")"
+                   | "sizeof" "(" pure_expression ")"
                    | "sizeof" "(" type_id ")" ;
 
 id_expression = unqualified_id
diff --git a/lldb/include/lldb/ValueObject/DILParser.h 
b/lldb/include/lldb/ValueObject/DILParser.h
index cc495d48d93c5..0e0982acd9192 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -82,8 +82,9 @@ class DILParser {
   ASTNodeUP Run();
 
   ASTNodeUP ParseExpression();
-  ASTNodeUP ParseConditionalExpression();
   ASTNodeUP ParseAssignmentExpression();
+  ASTNodeUP ParsePureExpression();
+  ASTNodeUP ParseConditionalExpression();
   ASTNodeUP ParseLogicalOrExpression();
   ASTNodeUP ParseLogicalAndExpression();
   ASTNodeUP ParseInclusiveOrExpression();
diff --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index dd6e6244461a4..8a442a5d418b8 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -129,41 +129,13 @@ ASTNodeUP DILParser::Run() {
 //  expression:
 //    assignment_expression
 //
-ASTNodeUP DILParser::ParseExpression() { return ParseConditionalExpression(); }
-
-// Parse a conditional_expression.
-//
-//  conditional_expression:
-//    assignment_expression
-//    assignment_expression "?" expression ":" expression
-//
-ASTNodeUP DILParser::ParseConditionalExpression() {
-  auto lhs = ParseAssignmentExpression();
-  assert(lhs && "ASTNodeUP must not contain a nullptr");
-
-  // Check if it's a ternary operator.
-  if (CurToken().Is(Token::question)) {
-    Token token = CurToken();
-    m_dil_lexer.Advance();
-    auto true_op = ParseExpression();
-    assert(true_op && "ASTNodeUP must not contain a nullptr");
-    Expect(Token::colon);
-    m_dil_lexer.Advance();
-    auto false_op = ParseExpression();
-    assert(false_op && "ASTNodeUP must not contain a nullptr");
-    lhs = std::make_unique<ConditionalNode>(token.GetLocation(), 
std::move(lhs),
-                                            std::move(true_op),
-                                            std::move(false_op));
-  }
-
-  return lhs;
-}
+ASTNodeUP DILParser::ParseExpression() { return ParseAssignmentExpression(); }
 
 // Parse an assignment_expression
 //
 //  assignment_expression
-//    logical_or_expression
-//    logical_or_expression assignment_operator assignment_expression
+//    pure_expression
+//    pure_expression assignment_operator pure_expression
 //
 //  assignment_operator:
 //    "="
@@ -171,7 +143,7 @@ ASTNodeUP DILParser::ParseConditionalExpression() {
 //    "-="
 //
 ASTNodeUP DILParser::ParseAssignmentExpression() {
-  auto lhs = ParseLogicalOrExpression();
+  auto lhs = ParsePureExpression();
   assert(lhs && "ASTNodeUP must not contain a nullptr");
 
   // Check if it's an assignment expression.
@@ -179,7 +151,7 @@ ASTNodeUP DILParser::ParseAssignmentExpression() {
     // That's an assignment!
     Token token = CurToken();
     m_dil_lexer.Advance();
-    auto rhs = ParseAssignmentExpression();
+    auto rhs = ParsePureExpression();
     assert(rhs && "ASTNodeUP must not contain a nullptr");
     lhs = std::make_unique<BinaryOpNode>(
         token.GetLocation(), GetBinaryOpKindFromToken(token.GetKind()),
@@ -188,6 +160,43 @@ ASTNodeUP DILParser::ParseAssignmentExpression() {
   return lhs;
 }
 
+// Parse a pure expression without side effects.
+//
+//  pure_expression:
+//    conditional_expression
+//
+ASTNodeUP DILParser::ParsePureExpression() {
+  return ParseConditionalExpression();
+}
+
+// Parse a conditional_expression.
+//
+//  conditional_expression:
+//    logical_or_expression
+//    logical_or_expression "?" pure_expression ":" pure_expression
+//
+ASTNodeUP DILParser::ParseConditionalExpression() {
+  auto lhs = ParseLogicalOrExpression();
+  assert(lhs && "ASTNodeUP must not contain a nullptr");
+
+  // Check if it's a ternary operator.
+  if (CurToken().Is(Token::question)) {
+    Token token = CurToken();
+    m_dil_lexer.Advance();
+    auto true_op = ParsePureExpression();
+    assert(true_op && "ASTNodeUP must not contain a nullptr");
+    Expect(Token::colon);
+    m_dil_lexer.Advance();
+    auto false_op = ParsePureExpression();
+    assert(false_op && "ASTNodeUP must not contain a nullptr");
+    lhs = std::make_unique<ConditionalNode>(token.GetLocation(), 
std::move(lhs),
+                                            std::move(true_op),
+                                            std::move(false_op));
+  }
+
+  return lhs;
+}
+
 // Parse a logical_or_expression.
 //
 //  logical_or_expression:
@@ -526,8 +535,8 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
 //
 //  postfix_expression:
 //    primary_expression
-//    postfix_expression "[" expression "]"
-//    postfix_expression "[" expression ":" expression "]"
+//    postfix_expression "[" pure_expression "]"
+//    postfix_expression "[" pure_expression ":" pure_expression "]"
 //    postfix_expression "." id_expression
 //    postfix_expression "->" id_expression
 //
@@ -540,11 +549,11 @@ ASTNodeUP DILParser::ParsePostfixExpression() {
     switch (token.GetKind()) {
     case Token::l_square: {
       m_dil_lexer.Advance();
-      ASTNodeUP index = ParseExpression();
+      ASTNodeUP index = ParsePureExpression();
       assert(index && "ASTNodeUP must not contain a nullptr");
       if (CurToken().GetKind() == Token::colon) {
         m_dil_lexer.Advance();
-        ASTNodeUP last_index = ParseExpression();
+        ASTNodeUP last_index = ParsePureExpression();
         assert(last_index && "ASTNodeUP must not contain a nullptr");
         lhs = std::make_unique<BitFieldExtractionNode>(
             loc, std::move(lhs), std::move(index), std::move(last_index));
@@ -584,7 +593,7 @@ ASTNodeUP DILParser::ParsePostfixExpression() {
 //    numeric_literal
 //    boolean_literal
 //    id_expression
-//    "(" expression ")"
+//    "(" pure_expression ")"
 //
 ASTNodeUP DILParser::ParsePrimaryExpression() {
   if (CurToken().IsOneOf({Token::integer_constant, Token::float_constant}))
@@ -608,7 +617,7 @@ ASTNodeUP DILParser::ParsePrimaryExpression() {
           return std::make_unique<SizeOfNode>(loc, *type_id);
         }
         TentativeParsingRollback(save_token_idx);
-        ASTNodeUP expr = ParseExpression();
+        ASTNodeUP expr = ParsePureExpression();
         Expect(Token::r_paren);
         m_dil_lexer.Advance();
         return std::make_unique<SizeOfNode>(loc, std::move(expr));
@@ -619,7 +628,7 @@ ASTNodeUP DILParser::ParsePrimaryExpression() {
 
   if (CurToken().Is(Token::l_paren)) {
     m_dil_lexer.Advance();
-    auto expr = ParseExpression();
+    auto expr = ParsePureExpression();
     Expect(Token::r_paren);
     m_dil_lexer.Advance();
     return expr;
diff --git 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py
index 5734395cf0ff0..826adc03d0d8d 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py
@@ -206,3 +206,26 @@ def test_assignment(self):
             error=True,
             substrs=["new value is too big"],
         )
+
+        # Check that there can be only one assignment and only at top level
+        self.expect(
+            "frame variable 'i = i = 1'",
+            error=True,
+            substrs=["expected 'eof', got: <'='"],
+        )
+        self.expect(
+            "frame variable 'i = 1 - (i = 1)'",
+            error=True,
+            substrs=["expected 'r_paren', got: <'='"],
+        )
+        self.expect(
+            "frame variable '1 + (i = 1)'",
+            error=True,
+            substrs=["expected 'r_paren', got: <'='"],
+        )
+        self.expect(
+            "frame variable '(i = 1) + 1'",
+            error=True,
+            substrs=["expected 'r_paren', got: <'='"],
+        )
+        self.expect("frame variable '*(arr + 1) = 5'", substrs=["= 5"])
diff --git 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
index 6f87fba87c9a5..9b58a8323ea5e 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
@@ -81,3 +81,20 @@ def test_assignment(self):
                 "frame variable 'p = (int *)10'", substrs=["p = 
0x000000000000000a"]
             )
             self.expect("frame variable 'p -= 2'", substrs=["p = 
0x0000000000000002"])
+
+        # Check that there can be only one assignment and only at top level
+        self.expect(
+            "frame variable 'i = i += 1'",
+            error=True,
+            substrs=["expected 'eof', got: <'+='"],
+        )
+        self.expect(
+            "frame variable 'i += 1 + (i -= 1)'",
+            error=True,
+            substrs=["expected 'r_paren', got: <'-='"],
+        )
+        self.expect(
+            "frame variable '*(arr + 1) = arr[1] += 1'",
+            error=True,
+            substrs=["expected 'eof', got: <'+='"],
+        )

>From 2b3f22ef679ac8f5f2a05f73dfe800fa9405a547 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <[email protected]>
Date: Thu, 6 Aug 2026 01:03:57 +0500
Subject: [PATCH 2/5] Add a verbose error for unexpected assignment

---
 lldb/source/ValueObject/DILParser.cpp                     | 4 ++++
 .../var-dil/expr/Assignment/TestFrameVarDILAssign.py      | 8 ++++----
 .../expr/Assignment/TestFrameVarDILCompositeAssign.py     | 6 +++---
 3 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index 8a442a5d418b8..30cb96dd9b1a7 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -1070,6 +1070,10 @@ ASTNodeUP DILParser::ParseFloatingPointLiteral() {
 }
 
 void DILParser::Expect(Token::Kind kind) {
+  if (CurToken().IsOneOf({Token::equal, Token::plusequal, Token::minusequal})) 
{
+    BailOut("Assignment is allowed only at top level.",
+            CurToken().GetLocation(), CurToken().GetSpelling().length());
+  }
   if (CurToken().IsNot(kind)) {
     BailOut(llvm::formatv("expected {0}, got: {1}", kind, CurToken()),
             CurToken().GetLocation(), CurToken().GetSpelling().length());
diff --git 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py
index 826adc03d0d8d..d954467c2cf97 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py
@@ -211,21 +211,21 @@ def test_assignment(self):
         self.expect(
             "frame variable 'i = i = 1'",
             error=True,
-            substrs=["expected 'eof', got: <'='"],
+            substrs=["Assignment is allowed only at top level"],
         )
         self.expect(
             "frame variable 'i = 1 - (i = 1)'",
             error=True,
-            substrs=["expected 'r_paren', got: <'='"],
+            substrs=["Assignment is allowed only at top level"],
         )
         self.expect(
             "frame variable '1 + (i = 1)'",
             error=True,
-            substrs=["expected 'r_paren', got: <'='"],
+            substrs=["Assignment is allowed only at top level"],
         )
         self.expect(
             "frame variable '(i = 1) + 1'",
             error=True,
-            substrs=["expected 'r_paren', got: <'='"],
+            substrs=["Assignment is allowed only at top level"],
         )
         self.expect("frame variable '*(arr + 1) = 5'", substrs=["= 5"])
diff --git 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
index 9b58a8323ea5e..17e3dce781d96 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
@@ -86,15 +86,15 @@ def test_assignment(self):
         self.expect(
             "frame variable 'i = i += 1'",
             error=True,
-            substrs=["expected 'eof', got: <'+='"],
+            substrs=["Assignment is allowed only at top level"],
         )
         self.expect(
             "frame variable 'i += 1 + (i -= 1)'",
             error=True,
-            substrs=["expected 'r_paren', got: <'-='"],
+            substrs=["Assignment is allowed only at top level"],
         )
         self.expect(
             "frame variable '*(arr + 1) = arr[1] += 1'",
             error=True,
-            substrs=["expected 'eof', got: <'+='"],
+            substrs=["Assignment is allowed only at top level"],
         )

>From e0f12469919611e0e8f50d64e758ceea70f051c7 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <[email protected]>
Date: Thu, 6 Aug 2026 02:51:10 +0500
Subject: [PATCH 3/5] Add errors for -- and ++

---
 lldb/include/lldb/ValueObject/DILLexer.h      |  2 ++
 lldb/source/ValueObject/DILLexer.cpp          |  6 +++++
 lldb/source/ValueObject/DILParser.cpp         | 22 +++++++++++++++++--
 .../TestFrameVarDILCompositeAssign.py         | 22 +++++++++++++++++++
 4 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/lldb/include/lldb/ValueObject/DILLexer.h 
b/lldb/include/lldb/ValueObject/DILLexer.h
index 69d6b49800b29..446891d5ca000 100644
--- a/lldb/include/lldb/ValueObject/DILLexer.h
+++ b/lldb/include/lldb/ValueObject/DILLexer.h
@@ -51,12 +51,14 @@ class Token {
     lessless,
     minus,
     minusequal,
+    minusminus,
     percent,
     period,
     pipe,
     pipepipe,
     plus,
     plusequal,
+    plusplus,
     question,
     r_paren,
     r_square,
diff --git a/lldb/source/ValueObject/DILLexer.cpp 
b/lldb/source/ValueObject/DILLexer.cpp
index 0f1978e28e512..abc54f1fd2f46 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -72,6 +72,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
     return "minus";
   case Kind::minusequal:
     return "minusequal";
+  case Kind::minusminus:
+    return "minusminus";
   case Token::percent:
     return "percent";
   case Kind::period:
@@ -84,6 +86,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
     return "plus";
   case Kind::plusequal:
     return "plusequal";
+  case Kind::plusplus:
+    return "plusplus";
   case Kind::question:
     return "question";
   case Kind::r_paren:
@@ -234,8 +238,10 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
       {Token::lessequal, "<="},
       {Token::lessless, "<<"},
       {Token::minusequal, "-="},
+      {Token::minusminus, "--"},
       {Token::pipepipe, "||"},
       {Token::plusequal, "+="},
+      {Token::plusplus, "++"},
       {Token::amp, "&"},
       {Token::caret, "^"},
       {Token::colon, ":"},
diff --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index 30cb96dd9b1a7..08b618dceb203 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -499,7 +499,8 @@ ASTNodeUP DILParser::ParseCastExpression() {
 //
 ASTNodeUP DILParser::ParseUnaryExpression() {
   if (CurToken().IsOneOf({Token::amp, Token::star, Token::minus, Token::plus,
-                          Token::tilde, Token::exclaim})) {
+                          Token::tilde, Token::exclaim, Token::minusminus,
+                          Token::plusplus})) {
     Token token = CurToken();
     uint32_t loc = token.GetLocation();
     m_dil_lexer.Advance();
@@ -524,6 +525,14 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
     case Token::exclaim:
       return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::LNot,
                                            std::move(rhs));
+    case Token::minusminus:
+      BailOut("Decrement operator is not supported. Use `-=` instead.",
+              CurToken().GetLocation(), CurToken().GetSpelling().length());
+      return std::make_unique<ErrorNode>();
+    case Token::plusplus:
+      BailOut("Increment operator is not supported. Use `+=` instead.",
+              CurToken().GetLocation(), CurToken().GetSpelling().length());
+      return std::make_unique<ErrorNode>();
     default:
       llvm_unreachable("invalid token kind");
     }
@@ -543,7 +552,8 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
 ASTNodeUP DILParser::ParsePostfixExpression() {
   ASTNodeUP lhs = ParsePrimaryExpression();
   assert(lhs && "ASTNodeUP must not contain a nullptr");
-  while (CurToken().IsOneOf({Token::l_square, Token::period, Token::arrow})) {
+  while (CurToken().IsOneOf({Token::l_square, Token::period, Token::arrow,
+                             Token::minusminus, Token::plusplus})) {
     uint32_t loc = CurToken().GetLocation();
     Token token = CurToken();
     switch (token.GetKind()) {
@@ -579,6 +589,14 @@ ASTNodeUP DILParser::ParsePostfixExpression() {
           token.GetKind() == Token::arrow, member_id);
       break;
     }
+    case Token::minusminus:
+      BailOut("Decrement operator is not supported. Use `-=` instead.",
+              CurToken().GetLocation(), CurToken().GetSpelling().length());
+      return std::make_unique<ErrorNode>();
+    case Token::plusplus:
+      BailOut("Increment operator is not supported. Use `+=` instead.",
+              CurToken().GetLocation(), CurToken().GetSpelling().length());
+      return std::make_unique<ErrorNode>();
     default:
       llvm_unreachable("invalid token");
     }
diff --git 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
index 17e3dce781d96..dd5cd68796e70 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
@@ -98,3 +98,25 @@ def test_assignment(self):
             error=True,
             substrs=["Assignment is allowed only at top level"],
         )
+
+        # Check that operators `--` and `++` return an error message.
+        self.expect(
+            "frame variable 'i++'",
+            error=True,
+            substrs=["Increment operator is not supported. Use `+=` instead."],
+        )
+        self.expect(
+            "frame variable '++i'",
+            error=True,
+            substrs=["Increment operator is not supported. Use `+=` instead."],
+        )
+        self.expect(
+            "frame variable 'i--'",
+            error=True,
+            substrs=["Decrement operator is not supported. Use `-=` instead."],
+        )
+        self.expect(
+            "frame variable -- '--i'",
+            error=True,
+            substrs=["Decrement operator is not supported. Use `-=` instead."],
+        )

>From 127d9ad5bce32d9c48af6fbd8830d161e3878892 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <[email protected]>
Date: Thu, 6 Aug 2026 03:54:43 +0500
Subject: [PATCH 4/5] Fix the shell test

---
 lldb/test/Shell/Commands/command-dil-diagnostics.test | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lldb/test/Shell/Commands/command-dil-diagnostics.test 
b/lldb/test/Shell/Commands/command-dil-diagnostics.test
index 5b15cff4e3cd5..b9647bf0a64e3 100644
--- a/lldb/test/Shell/Commands/command-dil-diagnostics.test
+++ b/lldb/test/Shell/Commands/command-dil-diagnostics.test
@@ -13,9 +13,9 @@ frame var a+b
 # CHECK-NEXT: {{^                   (╰─ )?}}error: use of undeclared 
identifier 'b'
 
 ## Check diagnostics when called from API.
-script lldb.frame.GetValueForVariablePath("++foo")
+script lldb.frame.GetValueForVariablePath("1+foo")
 # CHECK: error: <user expression>:1:3: use of undeclared identifier 'foo'
-# CHECK-NEXT: {{^    }}1 | ++foo
+# CHECK-NEXT: {{^    }}1 | 1+foo
 # CHECK-NEXT: {{^    }}  |   ^~~
 
 ## Check that a result that fails to retrieve data is displaying an error.

>From aec018e2cc8b0b589e4a9540583c2e55429fcba5 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <[email protected]>
Date: Thu, 20 Aug 2026 23:56:36 +0500
Subject: [PATCH 5/5] Keep conditional operator precedence over assignment

---
 lldb/docs/dil-expr-lang.ebnf                  |  4 +-
 lldb/include/lldb/ValueObject/DILParser.h     |  1 +
 lldb/source/ValueObject/DILParser.cpp         | 44 ++++++++++++-------
 .../expr/Assignment/TestFrameVarDILAssign.py  | 23 ++++++++++
 4 files changed, 53 insertions(+), 19 deletions(-)

diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 9d0c35f8c8c97..3dddcbd1ef609 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -5,8 +5,8 @@
 
 expression = assignment_expression ;
 
-assignment_expression = pure_expression
-                      | pure_expression assignment_operator pure_expression ;
+assignment_expression = conditional_expression
+                      | logical_or_expression assignment_operator 
pure_expression ;
 
 assignment_operator = "="
                     | "+="
diff --git a/lldb/include/lldb/ValueObject/DILParser.h 
b/lldb/include/lldb/ValueObject/DILParser.h
index 0e0982acd9192..ad7bc8ee73bba 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -85,6 +85,7 @@ class DILParser {
   ASTNodeUP ParseAssignmentExpression();
   ASTNodeUP ParsePureExpression();
   ASTNodeUP ParseConditionalExpression();
+  ASTNodeUP ParseConditionalBranches(ASTNodeUP condition);
   ASTNodeUP ParseLogicalOrExpression();
   ASTNodeUP ParseLogicalAndExpression();
   ASTNodeUP ParseInclusiveOrExpression();
diff --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index 08b618dceb203..97fd768545e61 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
-//    pure_expression
-//    pure_expression assignment_operator pure_expression
+//    conditional_expression
+//    logical_or_expression assignment_operator pure_expression
 //
 //  assignment_operator:
 //    "="
@@ -143,9 +143,15 @@ ASTNodeUP DILParser::ParseExpression() { return 
ParseAssignmentExpression(); }
 //    "-="
 //
 ASTNodeUP DILParser::ParseAssignmentExpression() {
-  auto lhs = ParsePureExpression();
+  auto lhs = ParseLogicalOrExpression();
   assert(lhs && "ASTNodeUP must not contain a nullptr");
 
+  // Check if it's a ternary operator.
+  // This is done to keep conditional_expression's precedence
+  // over assignment_expression.
+  if (CurToken().Is(Token::question))
+    return ParseConditionalBranches(std::move(lhs));
+
   // Check if it's an assignment expression.
   if (CurToken().IsOneOf({Token::equal, Token::plusequal, Token::minusequal})) 
{
     // That's an assignment!
@@ -179,24 +185,28 @@ ASTNodeUP DILParser::ParseConditionalExpression() {
   auto lhs = ParseLogicalOrExpression();
   assert(lhs && "ASTNodeUP must not contain a nullptr");
 
-  // Check if it's a ternary operator.
-  if (CurToken().Is(Token::question)) {
-    Token token = CurToken();
-    m_dil_lexer.Advance();
-    auto true_op = ParsePureExpression();
-    assert(true_op && "ASTNodeUP must not contain a nullptr");
-    Expect(Token::colon);
-    m_dil_lexer.Advance();
-    auto false_op = ParsePureExpression();
-    assert(false_op && "ASTNodeUP must not contain a nullptr");
-    lhs = std::make_unique<ConditionalNode>(token.GetLocation(), 
std::move(lhs),
-                                            std::move(true_op),
-                                            std::move(false_op));
-  }
+  if (CurToken().Is(Token::question))
+    lhs = ParseConditionalBranches(std::move(lhs));
 
   return lhs;
 }
 
+ASTNodeUP DILParser::ParseConditionalBranches(ASTNodeUP condition) {
+  assert(condition && "ASTNodeUP must not contain a nullptr");
+
+  Token token = CurToken();
+  m_dil_lexer.Advance();
+  auto true_op = ParsePureExpression();
+  assert(true_op && "ASTNodeUP must not contain a nullptr");
+  Expect(Token::colon);
+  m_dil_lexer.Advance();
+  auto false_op = ParsePureExpression();
+  assert(false_op && "ASTNodeUP must not contain a nullptr");
+  return std::make_unique<ConditionalNode>(
+      token.GetLocation(), std::move(condition), std::move(true_op),
+      std::move(false_op));
+}
+
 // Parse a logical_or_expression.
 //
 //  logical_or_expression:
diff --git 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py
index d954467c2cf97..9b3ab51422064 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILAssign.py
@@ -229,3 +229,26 @@ def test_assignment(self):
             substrs=["Assignment is allowed only at top level"],
         )
         self.expect("frame variable '*(arr + 1) = 5'", substrs=["= 5"])
+
+        # Check that assignment is parsed correctly when combined
+        # with ternary conditional operator
+        self.expect("frame variable 'i = false ? 1 : 2'", substrs=["i = 2"])
+        self.expect(
+            "frame variable 'false ? i = 1 : i'",
+            error=True,
+            substrs=["Assignment is allowed only at top level"],
+        )
+        self.expect(
+            "frame variable 'false ? i : i = 1'",
+            error=True,
+            substrs=["Assignment is allowed only at top level"],
+        )
+        self.expect("frame variable '(false ? i : j) = 1'", substrs=["j = 1"])
+        self.expect(
+            "frame variable '(true ? arr[0] : arr[1]) = false ? 0 : 5'", 
substrs=["= 5"]
+        )
+        self.expect(
+            "frame variable 'true ? arr[0] : arr[1] = false ? 0 : 5'",
+            error=True,
+            substrs=["Assignment is allowed only at top level"],
+        )

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

Reply via email to