https://github.com/Michael137 created 
https://github.com/llvm/llvm-project/pull/177922

This was originally removed in `8bdcd522510f923185cdfaec66c4a78d0a0d38c0` under 
the assumption this wasn't required (i.e., LLDB should just always pretend it's 
in a mutable context). But since function qualifiers affect overloading in C++, 
this assumption can lead to unexpected expression evaluator behaviour. Instead, 
in this patch we try to add function qualifiers to 
`$__lldb_class::$__lldb_expr` that resemble the qualifiers in the method that 
we're stopped in.

>From 2122824920d76303183c6185e2710946a6054a20 Mon Sep 17 00:00:00 2001
From: Michael Buch <[email protected]>
Date: Wed, 21 Jan 2026 16:12:03 +0000
Subject: [PATCH] [lldb][Expression] Make __lldb_expr function qualifiers match
 source context

This was originally removed in `8bdcd522510f923185cdfaec66c4a78d0a0d38c0` under 
the assumption this wasn't required (i.e., LLDB should just always pretend it's 
in a mutable context). But since function qualifiers affect overloading in C++, 
this assumption can lead to unexpected expression evaluator behaviour. Instead, 
in this patch we try to add function qualifiers to 
`$__lldb_class::$__lldb_expr` that resemble the qualifiers in the method that 
we're stopped in.
---
 .../Clang/ClangExpressionDeclMap.cpp          |   5 +-
 .../Clang/ClangExpressionSourceCode.cpp       |  16 ++-
 .../TestExprInsideLambdas.py                  |   4 +-
 .../API/lang/cpp/const_this/TestConstThis.py  |  10 +-
 .../const_method/Makefile                     |   3 +
 .../const_method/TestExprInConstMethod.py     | 106 ++++++++++++++++++
 .../const_method/main.cpp                     |  49 ++++++++
 .../const_volatile_method/Makefile            |   3 +
 .../TestExprInConstVolatileMethod.py          |  60 ++++++++++
 .../const_volatile_method/main.cpp            |  43 +++++++
 .../cv_qualified_objects/Makefile             |   3 +
 .../TestExprOnCVQualifiedObjects.py           |  21 ++++
 .../cv_qualified_objects/main.cpp             |  25 +++++
 .../fixit/Makefile                            |   3 +
 .../fixit/TestExprInConstMethodWithFixit.py   |  42 +++++++
 .../fixit/main.cpp                            |  22 ++++
 .../non_const_method/Makefile                 |   3 +
 .../TestExprInNonConstMethod.py               |  85 ++++++++++++++
 .../non_const_method/main.cpp                 |  49 ++++++++
 .../template_const_method/Makefile            |   3 +
 .../TestExprInTemplateConstMethod.py          | 106 ++++++++++++++++++
 .../template_const_method/main.cpp            |  51 +++++++++
 .../template_non_const_method/Makefile        |   3 +
 .../TestExprInTemplateNonConstMethod.py       |  85 ++++++++++++++
 .../template_non_const_method/main.cpp        |  49 ++++++++
 lldb/test/API/lang/cpp/this/TestCPPThis.py    |  12 +-
 26 files changed, 848 insertions(+), 13 deletions(-)
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/Makefile
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/TestExprInConstMethod.py
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/main.cpp
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/Makefile
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/TestExprInConstVolatileMethod.py
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/main.cpp
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/Makefile
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/TestExprOnCVQualifiedObjects.py
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/main.cpp
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/Makefile
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/TestExprInConstMethodWithFixit.py
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/main.cpp
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/Makefile
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/TestExprInNonConstMethod.py
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/main.cpp
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/Makefile
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/TestExprInTemplateConstMethod.py
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/main.cpp
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/Makefile
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/TestExprInTemplateNonConstMethod.py
 create mode 100644 
lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/main.cpp

diff --git 
a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp 
b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 24a5dc5362964..c59ffb797da02 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -57,6 +57,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/TypeBase.h"
 
 #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
@@ -843,6 +844,8 @@ void 
ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) {
     clang::CXXRecordDecl *class_decl = method_decl->getParent();
 
     QualType class_qual_type = m_ast_context->getCanonicalTagType(class_decl);
+    class_qual_type.addFastQualifiers(
+        method_decl->getMethodQualifiers().getFastQualifiers());
 
     TypeFromUser class_user_type(
         class_qual_type.getAsOpaquePtr(),
@@ -1991,7 +1994,7 @@ void 
ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context,
     std::array<CompilerType, 1> args{void_clang_type.GetPointerType()};
 
     CompilerType method_type = m_clang_ast_context->CreateFunctionType(
-        void_clang_type, args, false, 0);
+        void_clang_type, args, false, ut.GetTypeQualifiers());
 
     const bool is_virtual = false;
     const bool is_static = false;
diff --git 
a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp 
b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
index cfe187ffc4114..3a06861dbda9b 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -10,6 +10,7 @@
 
 #include "ClangExpressionUtil.h"
 
+#include "clang/AST/TypeBase.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/SourceManager.h"
@@ -19,6 +20,7 @@
 
 #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
 #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
+#include "Plugins/TypeSystem/Clang//TypeSystemClang.h"
 #include "lldb/Symbol/Block.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/DebugMacros.h"
@@ -406,6 +408,7 @@ bool ClangExpressionSourceCode::GetText(
     }
   }
 
+  clang::Qualifiers cv_quals;
   StreamString debug_macros_stream;
   StreamString lldb_local_var_decls;
   if (StackFrame *frame = exe_ctx.GetFramePtr()) {
@@ -425,6 +428,16 @@ bool ClangExpressionSourceCode::GetText(
         AddLocalVariableDecls(lldb_local_var_decls,
                               force_add_all_locals ? "" : m_body, frame);
       }
+
+    if (auto this_sp = frame->FindVariable(ConstString("this"))) {
+      cv_quals = clang::Qualifiers::fromCVRMask(
+          this_sp->GetCompilerType().GetPointeeType().GetTypeQualifiers());
+      if (auto this_this_sp = this_sp->GetChildMemberWithName("this"))
+        cv_quals =
+            clang::Qualifiers::fromCVRMask(this_this_sp->GetCompilerType()
+                                               .GetPointeeType()
+                                               .GetTypeQualifiers());
+    }
   }
 
   if (m_wrap) {
@@ -465,12 +478,13 @@ bool ClangExpressionSourceCode::GetText(
     case WrapKind::CppMemberFunction:
       wrap_stream.Printf("%s"
                          "void                                   \n"
-                         "$__lldb_class::%s(void *$__lldb_arg)   \n"
+                         "$__lldb_class::%s(void *$__lldb_arg) %s \n"
                          "{                                      \n"
                          "    %s;                                \n"
                          "%s"
                          "}                                      \n",
                          module_imports.c_str(), m_name.c_str(),
+                         cv_quals.getAsString().c_str(),
                          lldb_local_var_decls.GetData(), tagged_body.c_str());
       break;
     case WrapKind::ObjCInstanceMethod:
diff --git 
a/lldb/test/API/commands/expression/expr_inside_lambda/TestExprInsideLambdas.py 
b/lldb/test/API/commands/expression/expr_inside_lambda/TestExprInsideLambdas.py
index e35cfa6a289a7..0a7683b310f43 100644
--- 
a/lldb/test/API/commands/expression/expr_inside_lambda/TestExprInsideLambdas.py
+++ 
b/lldb/test/API/commands/expression/expr_inside_lambda/TestExprInsideLambdas.py
@@ -127,8 +127,8 @@ def test_expr_inside_lambda(self):
 
         # Inside non_capturing_method
         lldbutil.continue_to_breakpoint(process, bkpt)
-        self.expect_expr("local", result_type="int", result_value="5")
-        self.expect_expr("local2", result_type="int", result_value="10")
+        self.expect_expr("local", result_type="const int", result_value="5")
+        self.expect_expr("local2", result_type="const int", result_value="10")
         self.expect_expr("local2 * local", result_type="int", 
result_value="50")
 
         self.expectExprError(
diff --git a/lldb/test/API/lang/cpp/const_this/TestConstThis.py 
b/lldb/test/API/lang/cpp/const_this/TestConstThis.py
index 4b7d3aadb62ab..c2df61fde2b58 100644
--- a/lldb/test/API/lang/cpp/const_this/TestConstThis.py
+++ b/lldb/test/API/lang/cpp/const_this/TestConstThis.py
@@ -11,10 +11,9 @@ def run_class_tests(self):
         # Expression not referencing context class.
         self.expect_expr("1 + 1", result_type="int", result_value="2")
         # Referencing context class.
-        # FIXME: This and the expression below should return const types.
-        self.expect_expr("member", result_type="int", result_value="3")
+        self.expect_expr("member", result_type="const int", result_value="3")
         # Check the type of context class.
-        self.expect_expr("this", result_type="ContextClass *")
+        self.expect_expr("this", result_type="const ContextClass *")
 
     def test_member_func(self):
         self.build()
@@ -36,10 +35,9 @@ def run_template_class_tests(self):
         # Expression not referencing context class.
         self.expect_expr("1 + 1", result_type="int", result_value="2")
         # Referencing context class.
-        # FIXME: This and the expression below should return const types.
-        self.expect_expr("member", result_type="int", result_value="4")
+        self.expect_expr("member", result_type="const int", result_value="4")
         # Check the type of context class.
-        self.expect_expr("this", result_type="TemplatedContextClass<int> *")
+        self.expect_expr("this", result_type="const TemplatedContextClass<int> 
*")
 
     def test_template_member_func(self):
         self.build()
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/Makefile 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/TestExprInConstMethod.py
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/TestExprInConstMethod.py
new file mode 100644
index 0000000000000..0ba6c8a837db4
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/TestExprInConstMethod.py
@@ -0,0 +1,106 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test(self):
+        self.build()
+        (_, process, _, _) = lldbutil.run_to_source_breakpoint(
+            self, "Break: const_method begin", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect_expr("bar()", result_value="2", result_type="int")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+        self.expect(
+            "expression m_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member within const member 
function"
+            ],
+        )
+        self.expect_expr("((Foo*)this)->bar()", result_type="double", 
result_value="5")
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: const_method no-this lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect(
+            "expression x = 7.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member within const member 
function"
+            ],
+        )
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: const_method mutable no-this lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect_expr("x = 7.0")
+        self.expect_expr("x", result_value="7")
+
+        lldbutil.continue_to_source_breakpoint(
+            self, process, "Break: const_method lambda", 
lldb.SBFileSpec("main.cpp")
+        )
+
+        # FIXME: mutating this capture should be disallowed in a non-mutable 
lambda.
+        self.expect_expr("y = 8.0")
+        self.expect_expr("bar()", result_value="2", result_type="int")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+        self.expect(
+            "expression m_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member within const member 
function"
+            ],
+        )
+        self.expect_expr("m_mem", result_value="-2")
+        self.expect_expr("((Foo*)this)->bar()", result_type="double", 
result_value="5")
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: const_method mutable lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect_expr("y = 9.0")
+        self.expect_expr("bar()", result_value="2", result_type="int")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+        self.expect(
+            "expression m_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member within const member 
function"
+            ],
+        )
+        self.expect_expr("m_mem", result_value="-2")
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/main.cpp 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/main.cpp
new file mode 100644
index 0000000000000..7cb74767b458a
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/main.cpp
@@ -0,0 +1,49 @@
+#include <cassert>
+#include <cstdio>
+
+struct Foo {
+  double bar() { return 5.0; }
+
+  int bar() const { return 2; }
+
+  int const_method() const {
+    auto x = bar();
+    assert(x == 2);
+    std::puts("Break: const_method begin");
+
+    [x] {
+      std::puts("Keep on multiple lines...");
+      std::puts("Break: const_method no-this lambda");
+    }();
+
+    [x]() mutable {
+      std::puts("Keep on multiple lines...");
+      std::puts("Break: const_method mutable no-this lambda");
+    }();
+
+    [this, y = x] {
+      auto x = bar() + y;
+      std::puts("Break: const_method lambda");
+    }();
+
+    [this, y = x]() mutable {
+      auto x = bar() + y;
+      std::puts("Break: const_method mutable lambda");
+    }();
+
+    return 120;
+  }
+
+  float m_mem = -2.0;
+  const float m_const_mem = -3.0;
+};
+
+int main() {
+  const Foo f;
+  f.bar();
+
+  Foo f2;
+  f2.bar();
+
+  return Foo{}.const_method();
+}
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/Makefile
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/TestExprInConstVolatileMethod.py
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/TestExprInConstVolatileMethod.py
new file mode 100644
index 0000000000000..f20b9d8164841
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/TestExprInConstVolatileMethod.py
@@ -0,0 +1,60 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test(self):
+        self.build()
+        (_, process, _, _) = lldbutil.run_to_source_breakpoint(
+            self, "Break here: const", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect_expr("bar()", result_type="double", result_value="5")
+        self.expect_expr("const_volatile_method()")
+        self.expect_expr("const_method()")
+        self.expect(
+            "expression volatile_method()",
+            error=True,
+            substrs=["has type 'const Foo'", "but function is not marked 
const"],
+        )
+
+        lldbutil.continue_to_source_breakpoint(
+            self, process, "Break here: volatile", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect_expr(
+            "bar()", result_type="const char *", 
result_summary='"volatile_bar"'
+        )
+        self.expect_expr("const_volatile_method()")
+        self.expect(
+            "expression const_method()",
+            error=True,
+            substrs=["has type 'volatile Foo'", "but function is not marked 
volatile"],
+        )
+        self.expect_expr("volatile_method()")
+
+        lldbutil.continue_to_source_breakpoint(
+            self, process, "Break here: const volatile", 
lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect_expr("bar()", result_type="int", result_value="2")
+        self.expect_expr("other_cv_method()")
+
+        self.expect(
+            "expression const_method()",
+            error=True,
+            substrs=[
+                "has type 'const volatile Foo'",
+                "but function is not marked const or volatile",
+            ],
+        )
+        self.expect(
+            "expression volatile_method()",
+            error=True,
+            substrs=[
+                "has type 'const volatile Foo'",
+                "but function is not marked const or volatile",
+            ],
+        )
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/main.cpp
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/main.cpp
new file mode 100644
index 0000000000000..da0f7e7d1be95
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/main.cpp
@@ -0,0 +1,43 @@
+#include <cassert>
+#include <cstdio>
+
+struct Foo {
+  double bar() const { return 5.0; }
+  const char *bar() volatile { return "volatile_bar"; }
+  int bar() volatile const { return 2; }
+
+  int volatile_method() volatile {
+    std::puts("Break here: volatile");
+    return 0;
+  }
+  int const_method() const {
+    std::puts("Break here: const");
+    return 0;
+  }
+  int other_cv_method() const volatile { return 20; }
+
+  int const_volatile_method() const volatile {
+    auto x = bar();
+    assert(x == 2);
+    other_cv_method();
+
+    std::puts("Break here: const volatile");
+
+    return 120;
+  }
+};
+
+int main() {
+  const Foo f;
+  f.bar();
+  f.const_method();
+
+  volatile Foo f2;
+  f2.bar();
+  f2.volatile_method();
+
+  const volatile Foo f3;
+  f3.bar();
+
+  return Foo{}.const_volatile_method();
+}
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/Makefile
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/TestExprOnCVQualifiedObjects.py
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/TestExprOnCVQualifiedObjects.py
new file mode 100644
index 0000000000000..0f661471df749
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/TestExprOnCVQualifiedObjects.py
@@ -0,0 +1,21 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self,
+            "Break here",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect_expr("f.bar()", result_type="double", result_value="5")
+        self.expect_expr("cf.bar()", result_type="int", result_value="2")
+        self.expect_expr("vf.bar()", result_type="short", result_value="8")
+        self.expect_expr(
+            "cvf.bar()", result_type="const char *", 
result_summary='"volatile"'
+        )
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/main.cpp
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/main.cpp
new file mode 100644
index 0000000000000..eb7f8b82f2695
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/cv_qualified_objects/main.cpp
@@ -0,0 +1,25 @@
+#include <cstdio>
+
+struct Foo {
+  double bar() { return 5.0; }
+  int bar() const { return 2; }
+  short bar() volatile { return 8; }
+  char const *bar() const volatile { return "volatile"; }
+
+  float m_mem = -2.0;
+  const float m_const_mem = -3.0;
+};
+
+int main() {
+  Foo f;
+  const Foo cf;
+  volatile Foo vf;
+  const volatile Foo cvf;
+
+  f.bar();
+  cf.bar();
+  vf.bar();
+  cvf.bar();
+
+  std::puts("Break here");
+}
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/Makefile 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/TestExprInConstMethodWithFixit.py
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/TestExprInConstMethodWithFixit.py
new file mode 100644
index 0000000000000..3c239c89d0ca7
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/TestExprInConstMethodWithFixit.py
@@ -0,0 +1,42 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test(self):
+        self.build()
+        (_, process, _, _) = lldbutil.run_to_source_breakpoint(
+            self, "Break here", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect(
+            "expression m_bar->method()",
+            error=True,
+            substrs=[
+                "member reference type 'const Bar' is not a pointer",
+                "but function is not marked const",
+            ],
+        )
+
+        # Two fix-its
+        self.expect(
+            "expression -- m_bar->method() + m_bar->method()",
+            error=True,
+            substrs=[
+                "member reference type 'const Bar' is not a pointer",
+                "but function is not marked const",
+                "member reference type 'const Bar' is not a pointer",
+                "but function is not marked const",
+            ],
+        )
+
+        self.expect(
+            "expression m_bar->method() + blah",
+            error=True,
+            substrs=[
+                "member reference type 'const Bar' is not a pointer",
+                "but function is not marked const",
+            ],
+        )
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/main.cpp 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/main.cpp
new file mode 100644
index 0000000000000..1dab96e2986da
--- /dev/null
+++ b/lldb/test/API/lang/cpp/expression-context-qualifiers/fixit/main.cpp
@@ -0,0 +1,22 @@
+#include <cassert>
+#include <cstdio>
+
+struct Bar {
+  void method() {}
+};
+
+struct Foo {
+  int const_method() const {
+    std::puts("Break here");
+
+    return 120;
+  }
+
+  Bar m_bar;
+};
+
+int main() {
+  Foo{}.m_bar.method();
+
+  return Foo{}.const_method();
+}
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/Makefile
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/TestExprInNonConstMethod.py
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/TestExprInNonConstMethod.py
new file mode 100644
index 0000000000000..8ff88e8014b4c
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/TestExprInNonConstMethod.py
@@ -0,0 +1,85 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test(self):
+        self.build()
+        (_, process, _, _) = lldbutil.run_to_source_breakpoint(
+            self, "Break: non_const_method begin", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect_expr("bar()", result_value="5", result_type="double")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: non_const_method no-this lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect(
+            "expression x = 7.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member within const member 
function"
+            ],
+        )
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: non_const_method mutable no-this lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect_expr("x = 7.0")
+        self.expect_expr("x", result_value="7")
+
+        lldbutil.continue_to_source_breakpoint(
+            self, process, "Break: non_const_method lambda", 
lldb.SBFileSpec("main.cpp")
+        )
+
+        # FIXME: mutating this capture should be disallowed in a non-mutable 
lambda.
+        self.expect_expr("y = 8.0")
+        self.expect_expr("bar()", result_value="5", result_type="double")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+        self.expect_expr("m_mem = 2.0")
+        self.expect_expr("m_mem", result_value="2")
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: non_const_method mutable lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect_expr("y = 9.0")
+        self.expect_expr("bar()", result_value="5", result_type="double")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+        self.expect_expr("m_mem = 4.0")
+        self.expect_expr("m_mem", result_value="4")
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/main.cpp
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/main.cpp
new file mode 100644
index 0000000000000..141f63b6f2f24
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/main.cpp
@@ -0,0 +1,49 @@
+#include <cassert>
+#include <cstdio>
+
+struct Foo {
+  double bar() { return 5.0; }
+
+  int bar() const { return 2; }
+
+  int non_const_method() {
+    auto x = bar();
+    assert(x == 5.0);
+    std::puts("Break: non_const_method begin");
+
+    [x] {
+      std::puts("Keep on multiple lines...");
+      std::puts("Break: non_const_method no-this lambda");
+    }();
+
+    [x]() mutable {
+      std::puts("Keep on multiple lines...");
+      std::puts("Break: non_const_method mutable no-this lambda");
+    }();
+
+    [this, y = x] {
+      auto x = bar() + y;
+      std::puts("Break: non_const_method lambda");
+    }();
+
+    [this, y = x]() mutable {
+      auto x = bar() + y;
+      std::puts("Break: non_const_method mutable lambda");
+    }();
+
+    return 120;
+  }
+
+  float m_mem = -2.0;
+  const float m_const_mem = -3.0;
+};
+
+int main() {
+  const Foo f;
+  f.bar();
+
+  Foo f2;
+  f2.bar();
+
+  return Foo{}.non_const_method();
+}
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/Makefile
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/TestExprInTemplateConstMethod.py
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/TestExprInTemplateConstMethod.py
new file mode 100644
index 0000000000000..0ba6c8a837db4
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/TestExprInTemplateConstMethod.py
@@ -0,0 +1,106 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test(self):
+        self.build()
+        (_, process, _, _) = lldbutil.run_to_source_breakpoint(
+            self, "Break: const_method begin", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect_expr("bar()", result_value="2", result_type="int")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+        self.expect(
+            "expression m_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member within const member 
function"
+            ],
+        )
+        self.expect_expr("((Foo*)this)->bar()", result_type="double", 
result_value="5")
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: const_method no-this lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect(
+            "expression x = 7.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member within const member 
function"
+            ],
+        )
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: const_method mutable no-this lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect_expr("x = 7.0")
+        self.expect_expr("x", result_value="7")
+
+        lldbutil.continue_to_source_breakpoint(
+            self, process, "Break: const_method lambda", 
lldb.SBFileSpec("main.cpp")
+        )
+
+        # FIXME: mutating this capture should be disallowed in a non-mutable 
lambda.
+        self.expect_expr("y = 8.0")
+        self.expect_expr("bar()", result_value="2", result_type="int")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+        self.expect(
+            "expression m_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member within const member 
function"
+            ],
+        )
+        self.expect_expr("m_mem", result_value="-2")
+        self.expect_expr("((Foo*)this)->bar()", result_type="double", 
result_value="5")
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: const_method mutable lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect_expr("y = 9.0")
+        self.expect_expr("bar()", result_value="2", result_type="int")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+        self.expect(
+            "expression m_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member within const member 
function"
+            ],
+        )
+        self.expect_expr("m_mem", result_value="-2")
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/main.cpp
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/main.cpp
new file mode 100644
index 0000000000000..8238f2a52f5aa
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/main.cpp
@@ -0,0 +1,51 @@
+#include <cassert>
+#include <cstdio>
+
+struct Foo {
+  double bar() { return 5.0; }
+
+  int bar() const { return 2; }
+
+  void non_const_method() {}
+
+  int template_const_method() const {
+    auto x = bar();
+    assert(x == 2);
+    std::puts("Break: const_method begin");
+
+    [x] {
+      std::puts("Keep on multiple lines...");
+      std::puts("Break: const_method no-this lambda");
+    }();
+
+    [x]() mutable {
+      std::puts("Keep on multiple lines...");
+      std::puts("Break: const_method mutable no-this lambda");
+    }();
+
+    [this, y = x] {
+      auto x = bar() + y;
+      std::puts("Break: const_method lambda");
+    }();
+
+    [this, y = x]() mutable {
+      auto x = bar() + y;
+      std::puts("Break: const_method mutable lambda");
+    }();
+
+    return 120;
+  }
+
+  float m_mem = -2.0;
+  const float m_const_mem = -3.0;
+};
+
+int main() {
+  const Foo f;
+  f.bar();
+
+  Foo f2;
+  f2.bar();
+
+  return Foo{}.template_const_method();
+}
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/Makefile
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/TestExprInTemplateNonConstMethod.py
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/TestExprInTemplateNonConstMethod.py
new file mode 100644
index 0000000000000..8ff88e8014b4c
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/TestExprInTemplateNonConstMethod.py
@@ -0,0 +1,85 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test(self):
+        self.build()
+        (_, process, _, _) = lldbutil.run_to_source_breakpoint(
+            self, "Break: non_const_method begin", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect_expr("bar()", result_value="5", result_type="double")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: non_const_method no-this lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect(
+            "expression x = 7.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member within const member 
function"
+            ],
+        )
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: non_const_method mutable no-this lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect_expr("x = 7.0")
+        self.expect_expr("x", result_value="7")
+
+        lldbutil.continue_to_source_breakpoint(
+            self, process, "Break: non_const_method lambda", 
lldb.SBFileSpec("main.cpp")
+        )
+
+        # FIXME: mutating this capture should be disallowed in a non-mutable 
lambda.
+        self.expect_expr("y = 8.0")
+        self.expect_expr("bar()", result_value="5", result_type="double")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+        self.expect_expr("m_mem = 2.0")
+        self.expect_expr("m_mem", result_value="2")
+
+        lldbutil.continue_to_source_breakpoint(
+            self,
+            process,
+            "Break: non_const_method mutable lambda",
+            lldb.SBFileSpec("main.cpp"),
+        )
+
+        self.expect_expr("y = 9.0")
+        self.expect_expr("bar()", result_value="5", result_type="double")
+        self.expect(
+            "expression m_const_mem = 2.0",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member",
+                "with const-qualified type",
+            ],
+        )
+        self.expect_expr("m_mem = 4.0")
+        self.expect_expr("m_mem", result_value="4")
diff --git 
a/lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/main.cpp
 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/main.cpp
new file mode 100644
index 0000000000000..1632555c69d01
--- /dev/null
+++ 
b/lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/main.cpp
@@ -0,0 +1,49 @@
+#include <cassert>
+#include <cstdio>
+
+struct Foo {
+  double bar() { return 5.0; }
+
+  int bar() const { return 2; }
+
+  int template_non_const_method() {
+    auto x = bar();
+    assert(x == 5.0);
+    std::puts("Break: non_const_method begin");
+
+    [x] {
+      std::puts("Keep on multiple lines...");
+      std::puts("Break: non_const_method no-this lambda");
+    }();
+
+    [x]() mutable {
+      std::puts("Keep on multiple lines...");
+      std::puts("Break: non_const_method mutable no-this lambda");
+    }();
+
+    [this, y = x] {
+      auto x = bar() + y;
+      std::puts("Break: non_const_method lambda");
+    }();
+
+    [this, y = x]() mutable {
+      auto x = bar() + y;
+      std::puts("Break: non_const_method mutable lambda");
+    }();
+
+    return 120;
+  }
+
+  float m_mem = -2.0;
+  const float m_const_mem = -3.0;
+};
+
+int main() {
+  const Foo f;
+  f.bar();
+
+  Foo f2;
+  f2.bar();
+
+  return Foo{}.template_non_const_method();
+}
diff --git a/lldb/test/API/lang/cpp/this/TestCPPThis.py 
b/lldb/test/API/lang/cpp/this/TestCPPThis.py
index c9dcf30b53443..d83034c658ddb 100644
--- a/lldb/test/API/lang/cpp/this/TestCPPThis.py
+++ b/lldb/test/API/lang/cpp/this/TestCPPThis.py
@@ -1,6 +1,7 @@
 """
 Tests that C++ member and static variables are available where they should be.
 """
+
 import lldb
 from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
@@ -37,10 +38,15 @@ def test_with_run_command(self):
 
         self.runCmd("process continue")
 
-        # This would be disallowed if we enforced const.  But we don't.
-        self.expect("expression -- m_a = 2", startstr="(int) $1 = 2")
+        self.expect(
+            "expression -- m_a = 2",
+            error=True,
+            substrs=[
+                "cannot assign to non-static data member within const member 
function"
+            ],
+        )
 
-        self.expect("expression -- (int)getpid(); m_a", startstr="(int) $2 = 
2")
+        self.expect("expression -- (int)getpid(); m_a", startstr="(const int) 
$2 = 2")
 
         self.runCmd("process continue")
 

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

Reply via email to