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
