https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/177922
>From d6d51a930e9ee916ee938d54f439683d26c475dd 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 | 8 +- .../Clang/ClangExpressionSourceCode.cpp | 43 +++++-- .../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, 870 insertions(+), 21 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..41d2d2cb23146 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -844,6 +844,12 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) { QualType class_qual_type = m_ast_context->getCanonicalTagType(class_decl); + // The synthesized __lldb_expr will adopt the qualifiers from this class + // type. Make sure we use the qualifiers of the method that we're currently + // stopped in. + class_qual_type.addFastQualifiers( + method_decl->getMethodQualifiers().getFastQualifiers()); + TypeFromUser class_user_type( class_qual_type.getAsOpaquePtr(), function_decl_ctx.GetTypeSystem()->weak_from_this()); @@ -1991,7 +1997,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..ca4199faa3841 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" @@ -189,6 +190,28 @@ static void AddMacros(const DebugMacros *dm, CompileUnit *comp_unit, } } +/// Return qualifers of the current C++ method. +static clang::Qualifiers GetFrameCVQualifiers(StackFrame *frame) { + if (!frame) + return {}; + + auto this_sp = frame->FindVariable(ConstString("this")); + if (!this_sp) + return {}; + + // Lambdas that capture 'this' have a member variable called 'this'. The class + // context of __lldb_expr for a lambda is the class type of the 'this' capture + // (not the anonymous lambda structure). So use the qualifiers of the captured + // 'this'. + if (auto this_this_sp = this_sp->GetChildMemberWithName("this")) + return clang::Qualifiers::fromCVRMask( + this_this_sp->GetCompilerType().GetPointeeType().GetTypeQualifiers()); + + // Not in a lambda. Return 'this' qualifiers. + return clang::Qualifiers::fromCVRMask( + this_sp->GetCompilerType().GetPointeeType().GetTypeQualifiers()); +} + lldb_private::ClangExpressionSourceCode::ClangExpressionSourceCode( llvm::StringRef filename, llvm::StringRef name, llvm::StringRef prefix, llvm::StringRef body, Wrapping wrap, WrapKind wrap_kind) @@ -463,15 +486,17 @@ bool ClangExpressionSourceCode::GetText( lldb_local_var_decls.GetData(), tagged_body.c_str()); break; case WrapKind::CppMemberFunction: - wrap_stream.Printf("%s" - "void \n" - "$__lldb_class::%s(void *$__lldb_arg) \n" - "{ \n" - " %s; \n" - "%s" - "} \n", - module_imports.c_str(), m_name.c_str(), - lldb_local_var_decls.GetData(), tagged_body.c_str()); + wrap_stream.Printf( + "%s" + "void \n" + "$__lldb_class::%s(void *$__lldb_arg) %s \n" + "{ \n" + " %s; \n" + "%s" + "} \n", + module_imports.c_str(), m_name.c_str(), + GetFrameCVQualifiers(exe_ctx.GetFramePtr()).getAsString().c_str(), + lldb_local_var_decls.GetData(), tagged_body.c_str()); break; case WrapKind::ObjCInstanceMethod: wrap_stream.Printf( 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..2fbbd16204609 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) $1 = 2") self.runCmd("process continue") _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
