Author: Ilia Kuklin
Date: 2026-09-04T17:35:12+05:00
New Revision: 598d9d1369d385582d2a90d71335073d1b2e0950

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

LOG: [lldb] Add composite assignments to existing operators in DIL (#208853)

Add operators `*=`, `/=`, `%=`, `<<=`, `>>=`, `&=`, `^=`, `|=` to DIL.

Added: 
    

Modified: 
    lldb/docs/dil-expr-lang.ebnf
    lldb/include/lldb/ValueObject/DILAST.h
    lldb/include/lldb/ValueObject/DILLexer.h
    lldb/source/ValueObject/DILAST.cpp
    lldb/source/ValueObject/DILEval.cpp
    lldb/source/ValueObject/DILLexer.cpp
    lldb/source/ValueObject/DILParser.cpp
    
lldb/test/API/commands/frame/var-dil/expr/Assignment/TestFrameVarDILCompositeAssign.py
    lldb/test/API/commands/frame/var-dil/expr/Assignment/main.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 3dddcbd1ef609..60bc05bd830eb 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -10,7 +10,12 @@ assignment_expression = conditional_expression
 
 assignment_operator = "="
                     | "+="
-                    | "-=" ;
+                    | "-="
+                    | "*="
+                    | "/="
+                    | "%="
+                    | "<<="
+                    | ">>=" ;
 
 pure_expression = conditional_expression ;
 

diff  --git a/lldb/include/lldb/ValueObject/DILAST.h 
b/lldb/include/lldb/ValueObject/DILAST.h
index 00a50c97324a1..f8b89ab136f15 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -59,6 +59,14 @@ enum class BinaryOpKind {
   Shr,       ///< ">>"
   AddAssign, ///< "+="
   SubAssign, ///< "-="
+  MulAssign, ///< "*="
+  DivAssign, ///< "/="
+  RemAssign, ///< "%="
+  AndAssign, ///< "&="
+  XorAssign, ///< "^="
+  OrAssign,  ///< "|="
+  ShlAssign, ///< "<<="
+  ShrAssign, ///< ">>="
   LAnd,      ///< "&&"
   LOr,       ///< "||"
   LT,        ///< "<"

diff  --git a/lldb/include/lldb/ValueObject/DILLexer.h 
b/lldb/include/lldb/ValueObject/DILLexer.h
index 446891d5ca000..22cd96876f7e7 100644
--- a/lldb/include/lldb/ValueObject/DILLexer.h
+++ b/lldb/include/lldb/ValueObject/DILLexer.h
@@ -27,8 +27,10 @@ class Token {
   enum Kind {
     amp,
     ampamp,
+    ampequal,
     arrow,
     caret,
+    caretequal,
     colon,
     coloncolon,
     eof,
@@ -40,6 +42,7 @@ class Token {
     greater,
     greaterequal,
     greatergreater,
+    greatergreaterequal,
     identifier,
     integer_constant,
     kw_false,
@@ -49,12 +52,15 @@ class Token {
     less,
     lessequal,
     lessless,
+    lesslessequal,
     minus,
     minusequal,
     minusminus,
     percent,
+    percentequal,
     period,
     pipe,
+    pipeequal,
     pipepipe,
     plus,
     plusequal,
@@ -63,7 +69,9 @@ class Token {
     r_paren,
     r_square,
     slash,
+    slashequal,
     star,
+    starequal,
     tilde,
   };
 

diff  --git a/lldb/source/ValueObject/DILAST.cpp 
b/lldb/source/ValueObject/DILAST.cpp
index 7128233d227a9..d9ba85b0a7042 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -17,12 +17,8 @@ BinaryOpKind GetBinaryOpKindFromToken(Token::Kind 
token_kind) {
     return BinaryOpKind::Assign;
   case Token::minus:
     return BinaryOpKind::Sub;
-  case Token::minusequal:
-    return BinaryOpKind::SubAssign;
   case Token::plus:
     return BinaryOpKind::Add;
-  case Token::plusequal:
-    return BinaryOpKind::AddAssign;
   case Token::star:
     return BinaryOpKind::Mul;
   case Token::slash:
@@ -39,6 +35,26 @@ BinaryOpKind GetBinaryOpKindFromToken(Token::Kind 
token_kind) {
     return BinaryOpKind::Shl;
   case Token::greatergreater:
     return BinaryOpKind::Shr;
+  case Token::minusequal:
+    return BinaryOpKind::SubAssign;
+  case Token::plusequal:
+    return BinaryOpKind::AddAssign;
+  case Token::starequal:
+    return BinaryOpKind::MulAssign;
+  case Token::slashequal:
+    return BinaryOpKind::DivAssign;
+  case Token::percentequal:
+    return BinaryOpKind::RemAssign;
+  case Token::ampequal:
+    return BinaryOpKind::AndAssign;
+  case Token::caretequal:
+    return BinaryOpKind::XorAssign;
+  case Token::pipeequal:
+    return BinaryOpKind::OrAssign;
+  case Token::lesslessequal:
+    return BinaryOpKind::ShlAssign;
+  case Token::greatergreaterequal:
+    return BinaryOpKind::ShrAssign;
   case Token::ampamp:
     return BinaryOpKind::LAnd;
   case Token::pipepipe:

diff  --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index f60ce03f2c962..627d30cae9bec 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -1357,24 +1357,12 @@ Interpreter::Visit(const BinaryOpNode &node) {
   }
 
   switch (node.GetKind()) {
-  case BinaryOpKind::Add:
-    return EvaluateBinaryAddition(lhs, rhs, node.GetLocation());
-  case BinaryOpKind::AddAssign: {
-    auto ret_or_err = EvaluateBinaryAddition(lhs, rhs, node.GetLocation());
-    if (!ret_or_err)
-      return ret_or_err;
-    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
-  }
   case BinaryOpKind::Assign:
     return EvaluateAssignment(lhs, rhs, node.GetLocation());
+  case BinaryOpKind::Add:
+    return EvaluateBinaryAddition(lhs, rhs, node.GetLocation());
   case BinaryOpKind::Sub:
     return EvaluateBinarySubtraction(lhs, rhs, node.GetLocation());
-  case BinaryOpKind::SubAssign: {
-    auto ret_or_err = EvaluateBinarySubtraction(lhs, rhs, node.GetLocation());
-    if (!ret_or_err)
-      return ret_or_err;
-    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
-  }
   case BinaryOpKind::Mul:
     return EvaluateBinaryMultiplication(lhs, rhs, node.GetLocation());
   case BinaryOpKind::Div:
@@ -1388,6 +1376,72 @@ Interpreter::Visit(const BinaryOpNode &node) {
   case BinaryOpKind::Shl:
   case BinaryOpKind::Shr:
     return EvaluateBinaryShift(node.GetKind(), lhs, rhs, node.GetLocation());
+  case BinaryOpKind::AddAssign: {
+    auto ret_or_err = EvaluateBinaryAddition(lhs, rhs, node.GetLocation());
+    if (!ret_or_err)
+      return ret_or_err;
+    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+  }
+  case BinaryOpKind::SubAssign: {
+    auto ret_or_err = EvaluateBinarySubtraction(lhs, rhs, node.GetLocation());
+    if (!ret_or_err)
+      return ret_or_err;
+    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+  }
+  case BinaryOpKind::MulAssign: {
+    auto ret_or_err =
+        EvaluateBinaryMultiplication(lhs, rhs, node.GetLocation());
+    if (!ret_or_err)
+      return ret_or_err;
+    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+  }
+  case BinaryOpKind::DivAssign: {
+    auto ret_or_err = EvaluateBinaryDivision(lhs, rhs, node.GetLocation());
+    if (!ret_or_err)
+      return ret_or_err;
+    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+  }
+  case BinaryOpKind::RemAssign: {
+    auto ret_or_err = EvaluateBinaryRemainder(lhs, rhs, node.GetLocation());
+    if (!ret_or_err)
+      return ret_or_err;
+    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+  }
+  case BinaryOpKind::AndAssign: {
+    auto ret_or_err =
+        EvaluateBinaryBitwise(BinaryOpKind::And, lhs, rhs, node.GetLocation());
+    if (!ret_or_err)
+      return ret_or_err;
+    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+  }
+  case BinaryOpKind::XorAssign: {
+    auto ret_or_err =
+        EvaluateBinaryBitwise(BinaryOpKind::Xor, lhs, rhs, node.GetLocation());
+    if (!ret_or_err)
+      return ret_or_err;
+    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+  }
+  case BinaryOpKind::OrAssign: {
+    auto ret_or_err =
+        EvaluateBinaryBitwise(BinaryOpKind::Or, lhs, rhs, node.GetLocation());
+    if (!ret_or_err)
+      return ret_or_err;
+    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+  }
+  case BinaryOpKind::ShlAssign: {
+    auto ret_or_err =
+        EvaluateBinaryShift(BinaryOpKind::Shl, lhs, rhs, node.GetLocation());
+    if (!ret_or_err)
+      return ret_or_err;
+    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+  }
+  case BinaryOpKind::ShrAssign: {
+    auto ret_or_err =
+        EvaluateBinaryShift(BinaryOpKind::Shr, lhs, rhs, node.GetLocation());
+    if (!ret_or_err)
+      return ret_or_err;
+    return EvaluateAssignment(lhs, *ret_or_err, node.GetLocation());
+  }
   case BinaryOpKind::EQ:
   case BinaryOpKind::NE:
   case BinaryOpKind::LT:

diff  --git a/lldb/source/ValueObject/DILLexer.cpp 
b/lldb/source/ValueObject/DILLexer.cpp
index abc54f1fd2f46..2cb7e3042c6f3 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -24,10 +24,14 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
     return "amp";
   case Kind::ampamp:
     return "ampamp";
+  case Kind::ampequal:
+    return "ampequal";
   case Kind::arrow:
     return "arrow";
   case Kind::caret:
     return "caret";
+  case Kind::caretequal:
+    return "caretequal";
   case Kind::colon:
     return "colon";
   case Kind::coloncolon:
@@ -50,6 +54,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
     return "greaterequal";
   case Kind::greatergreater:
     return "greatergreater";
+  case Kind::greatergreaterequal:
+    return "greatergreaterequal";
   case Kind::identifier:
     return "identifier";
   case Kind::integer_constant:
@@ -68,6 +74,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
     return "lessequal";
   case Kind::lessless:
     return "lessless";
+  case Kind::lesslessequal:
+    return "lesslessequal";
   case Kind::minus:
     return "minus";
   case Kind::minusequal:
@@ -76,10 +84,14 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
     return "minusminus";
   case Token::percent:
     return "percent";
+  case Token::percentequal:
+    return "percentequal";
   case Kind::period:
     return "period";
   case Kind::pipe:
     return "pipe";
+  case Kind::pipeequal:
+    return "pipeequal";
   case Kind::pipepipe:
     return "pipepipe";
   case Kind::plus:
@@ -96,8 +108,12 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
     return "r_square";
   case Token::slash:
     return "slash";
+  case Token::slashequal:
+    return "slashequal";
   case Token::star:
     return "star";
+  case Token::starequal:
+    return "starequal";
   case Token::tilde:
     return "tilde";
   }
@@ -228,8 +244,12 @@ 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::greatergreaterequal, ">>="},
+      {Token::lesslessequal, "<<="},
       {Token::ampamp, "&&"},
+      {Token::ampequal, "&="},
       {Token::arrow, "->"},
+      {Token::caretequal, "^="},
       {Token::coloncolon, "::"},
       {Token::equalequal, "=="},
       {Token::exclaimequal, "!="},
@@ -239,9 +259,13 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
       {Token::lessless, "<<"},
       {Token::minusequal, "-="},
       {Token::minusminus, "--"},
+      {Token::percentequal, "%="},
+      {Token::pipeequal, "|="},
       {Token::pipepipe, "||"},
       {Token::plusequal, "+="},
       {Token::plusplus, "++"},
+      {Token::slashequal, "/="},
+      {Token::starequal, "*="},
       {Token::amp, "&"},
       {Token::caret, "^"},
       {Token::colon, ":"},

diff  --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index cc69fa175e303..6a8af6127fe75 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -141,13 +141,22 @@ ASTNodeUP DILParser::ParseExpression() { return 
ParseAssignmentExpression(); }
 //    "="
 //    "+="
 //    "-="
+//    "*="
+//    "/="
+//    "%="
+//    "<<="
+//    ">>="
 //
 ASTNodeUP DILParser::ParseAssignmentExpression() {
   auto lhs = ParseLogicalOrExpression();
   assert(lhs && "ASTNodeUP must not contain a nullptr");
 
   // Check if it's an assignment expression.
-  if (CurToken().IsOneOf({Token::equal, Token::plusequal, Token::minusequal})) 
{
+  if (CurToken().IsOneOf({Token::equal, Token::plusequal, Token::minusequal,
+                          Token::starequal, Token::slashequal,
+                          Token::percentequal, Token::ampequal,
+                          Token::caretequal, Token::pipeequal,
+                          Token::lesslessequal, Token::greatergreaterequal})) {
     // That's an assignment!
     Token token = CurToken();
     m_dil_lexer.Advance();

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 dd5cd68796e70..bfd6f68a3e793 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
@@ -82,6 +82,88 @@ def test_assignment(self):
             )
             self.expect("frame variable 'p -= 2'", substrs=["p = 
0x0000000000000002"])
 
+        self.expect("frame variable 'i = 2'", substrs=["2"])
+        self.expect("frame variable 'i *= 2'", substrs=["4"])
+        self.expect("frame variable 'iref *= 2'", substrs=["8"])
+        self.expect("frame variable 'd = 2.25'", substrs=["2.25"])
+        self.expect("frame variable 'd *= 2.0'", substrs=["4.5"])
+        self.expect("frame variable 'd *= 2'", substrs=["9"])
+        self.expect(
+            "frame variable 'i *= 2.0'",
+            error=True,
+            substrs=[
+                "Incompatible types for assignment: Cannot assign 'double' to 
'int'"
+            ],
+        )
+
+        self.expect("frame variable 'i = 7'", substrs=["7"])
+        self.expect("frame variable 'i /= 3'", substrs=["2"])
+        self.expect("frame variable 'iref /= 2'", substrs=["1"])
+        self.expect("frame variable 'f = 4.5f'", substrs=["4.5"])
+        self.expect("frame variable 'f /= 2.0f", substrs=["2.25"])
+        self.expect("frame variable 'f /= 2", substrs=["1.125"])
+        self.expect(
+            "frame variable 'i /= 1.0f'",
+            error=True,
+            substrs=[
+                "Incompatible types for assignment: Cannot assign 'float' to 
'int'"
+            ],
+        )
+
+        self.expect("frame variable 'i = 7'", substrs=["7"])
+        self.expect("frame variable 'i %= 4'", substrs=["3"])
+        self.expect("frame variable 'iref %= 3'", substrs=["0"])
+        self.expect(
+            "frame variable 'i %= 1.0'",
+            error=True,
+            substrs=["invalid operands to binary expression ('int' and 
'double')"],
+        )
+
+        self.expect("frame variable 'i = 0xF'", substrs=["15"])
+        self.expect("frame variable 'i &= 0b101'", substrs=["5"])
+        self.expect("frame variable 'iref &= 0b100'", substrs=["4"])
+        self.expect(
+            "frame variable 'i &= 1.0'",
+            error=True,
+            substrs=["invalid operands to binary expression ('int' and 
'double')"],
+        )
+
+        self.expect("frame variable 'i = 0xF'", substrs=["15"])
+        self.expect("frame variable 'i ^= 0b1000'", substrs=["7"])
+        self.expect("frame variable 'iref ^= 0b11'", substrs=["4"])
+        self.expect(
+            "frame variable 'i ^= 1.0'",
+            error=True,
+            substrs=["invalid operands to binary expression ('int' and 
'double')"],
+        )
+
+        self.expect("frame variable 'i = 1'", substrs=["1"])
+        self.expect("frame variable 'i |= 0b110'", substrs=["7"])
+        self.expect("frame variable 'iref |= 0b1001'", substrs=["15"])
+        self.expect(
+            "frame variable 'i |= 1.0'",
+            error=True,
+            substrs=["invalid operands to binary expression ('int' and 
'double')"],
+        )
+
+        self.expect("frame variable 'i = 0xF'", substrs=["15"])
+        self.expect("frame variable 'i >>= 1'", substrs=["7"])
+        self.expect("frame variable 'iref >>= 2'", substrs=["1"])
+        self.expect(
+            "frame variable 'i >>= 1.0'",
+            error=True,
+            substrs=["invalid operands to binary expression ('int' and 
'double')"],
+        )
+
+        self.expect("frame variable 'i = 1'", substrs=["1"])
+        self.expect("frame variable 'i <<= 1'", substrs=["2"])
+        self.expect("frame variable 'iref <<= 2'", substrs=["8"])
+        self.expect(
+            "frame variable 'i <<= 1.0'",
+            error=True,
+            substrs=["invalid operands to binary expression ('int' and 
'double')"],
+        )
+
         # Check that there can be only one assignment and only at top level
         self.expect(
             "frame variable 'i = i += 1'",

diff  --git a/lldb/test/API/commands/frame/var-dil/expr/Assignment/main.cpp 
b/lldb/test/API/commands/frame/var-dil/expr/Assignment/main.cpp
index 6438ce08bfb48..f7e90c45d49f7 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/Assignment/main.cpp
+++ b/lldb/test/API/commands/frame/var-dil/expr/Assignment/main.cpp
@@ -12,6 +12,8 @@ int main(int argc, char **argv) {
   float farr[2] = {1.0f, 2.0f};
   int arr[2] = {1, 2};
 
+  int &iref = i;
+
   enum Enum { ONE, TWO };
   Enum eOne = ONE;
   Enum eTwo = TWO;


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

Reply via email to