Author: Michael Buch Date: 2026-02-05T07:46:20Z New Revision: 584156d15d24c9b9f67aa7850e86ee2474a250c0
URL: https://github.com/llvm/llvm-project/commit/584156d15d24c9b9f67aa7850e86ee2474a250c0 DIFF: https://github.com/llvm/llvm-project/commit/584156d15d24c9b9f67aa7850e86ee2474a250c0.diff LOG: [lldb][Expression] Add --c++-ignore-context-qualifiers expression evaluation option (#177926) Depends on: * https://github.com/llvm/llvm-project/pull/177920 * https://github.com/llvm/llvm-project/pull/177922 * https://github.com/llvm/llvm-project/pull/179208 (only commit d8676d0ed9286777e1a1e9f625389540cc42c231 and later are relevant for this review) In https://github.com/llvm/llvm-project/pull/177922 we make expressions run in C++ member functions honor the function qualifiers of the current stop context. E.g., this means we can no longer run non-const member functions when stopped in a const-member function. To ensure users can still do this if they really need/want to, we provide an option to not honor the qualifiers at all, leaving the `__lldb_expr` minimally qualified, allowing it to call any function/mutate any members. Added: Modified: lldb/include/lldb/Target/Target.h lldb/source/Commands/CommandObjectExpression.cpp lldb/source/Commands/CommandObjectExpression.h lldb/source/Commands/Options.td lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp lldb/source/Target/Target.cpp lldb/test/API/lang/cpp/expression-context-qualifiers/const_method/TestExprInConstMethod.py lldb/test/API/lang/cpp/expression-context-qualifiers/const_volatile_method/TestExprInConstVolatileMethod.py lldb/test/API/lang/cpp/expression-context-qualifiers/non_const_method/TestExprInNonConstMethod.py lldb/test/API/lang/cpp/expression-context-qualifiers/template_const_method/TestExprInTemplateConstMethod.py lldb/test/API/lang/cpp/expression-context-qualifiers/template_non_const_method/TestExprInTemplateNonConstMethod.py lldb/test/API/lang/cpp/this/TestCPPThis.py lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp Removed: ################################################################################ diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index a79d0f1b6113e..f781c4dabdd9f 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -308,8 +308,7 @@ class TargetProperties : public Properties { class EvaluateExpressionOptions { public: - EvaluateExpressionOptions() - : m_language_options_sp(std::make_shared<StructuredData::Dictionary>()) {} + EvaluateExpressionOptions(); // MSVC has a bug here that reports C4268: 'const' static/global data // initialized with compiler generated default constructor fills the object @@ -494,6 +493,10 @@ class EvaluateExpressionOptions { llvm::Expected<bool> GetBooleanLanguageOption(llvm::StringRef option_name) const; + void SetCppIgnoreContextQualifiers(bool value); + + bool GetCppIgnoreContextQualifiers() const; + private: const StructuredData::Dictionary &GetLanguageOptions() const; diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 4919bd3639d3e..efc0df6cd738e 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -44,6 +44,9 @@ Status CommandObjectExpression::CommandOptions::SetOptionValue( const int short_option = GetDefinitions()[option_idx].short_option; switch (short_option) { + case 'Q': + cpp_ignore_context_qualifiers = true; + break; case 'l': language = Language::GetLanguageTypeFromString(option_arg); if (language == eLanguageTypeUnknown) { @@ -191,6 +194,7 @@ void CommandObjectExpression::CommandOptions::OptionParsingStarting( top_level = false; allow_jit = true; suppress_persistent_result = eLazyBoolCalculate; + cpp_ignore_context_qualifiers = false; } llvm::ArrayRef<OptionDefinition> @@ -213,6 +217,7 @@ CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions( options.SetExecutionPolicy( allow_jit ? EvaluateExpressionOptions::default_execution_policy : lldb_private::eExecutionPolicyNever); + options.SetCppIgnoreContextQualifiers(cpp_ignore_context_qualifiers); bool auto_apply_fixits; if (this->auto_apply_fixits == eLazyBoolCalculate) diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h index 6fccf10e5dbc1..0439ddffce925 100644 --- a/lldb/source/Commands/CommandObjectExpression.h +++ b/lldb/source/Commands/CommandObjectExpression.h @@ -57,6 +57,7 @@ class CommandObjectExpression : public CommandObjectRaw, LanguageRuntimeDescriptionDisplayVerbosity m_verbosity; LazyBool auto_apply_fixits; LazyBool suppress_persistent_result; + bool cpp_ignore_context_qualifiers; }; CommandObjectExpression(CommandInterpreter &interpreter); diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index d96354a39b8b8..8e1b921f47c3d 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -778,6 +778,13 @@ let Command = "expression" in { Desc<"Persist expression result in a variable for subsequent use. " "Expression results will be labeled with $-prefixed variables, " "e.g. $0, $1, etc.">; + def ignore_context_qualifiers + : Option<"c++-ignore-context-qualifiers", "Q">, + Groups<[1, 2]>, + Desc<"When specified, evaluates the expression without taking into " + "account the type ${Q}ualifiers of the scope. In C++, this would " + "permit calling a non-const method when stopped in a const-method " + "(which would be disallowed by language rules).">; } let Command = "frame diag" in { diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index b1f246f6690e7..9f4ccc60c0b34 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -88,10 +88,12 @@ ClangExpressionDeclMap::ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, const lldb::TargetSP &target, - const std::shared_ptr<ClangASTImporter> &importer, ValueObject *ctx_obj) + const std::shared_ptr<ClangASTImporter> &importer, ValueObject *ctx_obj, + bool ignore_context_qualifiers) : ClangASTSource(target, importer), m_found_entities(), m_struct_members(), m_keep_result_in_memory(keep_result_in_memory), - m_result_delegate(result_delegate), m_ctx_obj(ctx_obj), m_parser_vars(), + m_result_delegate(result_delegate), m_ctx_obj(ctx_obj), + m_ignore_context_qualifiers(ignore_context_qualifiers), m_parser_vars(), m_struct_vars() { EnableStructVars(); } @@ -1997,7 +1999,8 @@ 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, ut.GetTypeQualifiers()); + void_clang_type, args, false, + m_ignore_context_qualifiers ? 0 : ut.GetTypeQualifiers()); const bool is_virtual = false; const bool is_static = false; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index df74ebc37a5de..d44c95068f45d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -78,11 +78,18 @@ class ClangExpressionDeclMap : public ClangASTSource { /// \param[in] ctx_obj /// If not empty, then expression is evaluated in context of this object. /// See the comment to `UserExpression::Evaluate` for details. + /// + /// \param[in] ignore_context_qualifiers + /// If \c true, evaluates the expression without taking into account the + /// CV-qualifiers of the scope. E.g., this would permit calling a + /// non-const C++ method when stopped in a const-method (which would be + /// disallowed by C++ language rules). ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, const lldb::TargetSP &target, - const std::shared_ptr<ClangASTImporter> &importer, ValueObject *ctx_obj); + const std::shared_ptr<ClangASTImporter> &importer, ValueObject *ctx_obj, + bool ignore_context_qualifiers); /// Destructor ~ClangExpressionDeclMap() override; @@ -306,6 +313,12 @@ class ClangExpressionDeclMap : public ClangASTSource { ///For details see the comment to ///`UserExpression::Evaluate`. + /// If \c true, evaluates the expression without taking into account the + /// CV-qualifiers of the scope. E.g., this would permit calling a + /// non-const C++ method when stopped in a const-method (which would be + /// disallowed by C++ language rules). + bool m_ignore_context_qualifiers = false; + /// The following values should not live beyond parsing class ParserVars { public: diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index ca4199faa3841..c711367cb6177 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -363,9 +363,12 @@ void ClangExpressionSourceCode::AddLocalVariableDecls(StreamString &stream, } } -bool ClangExpressionSourceCode::GetText( - std::string &text, ExecutionContext &exe_ctx, bool add_locals, - bool force_add_all_locals, llvm::ArrayRef<std::string> modules) const { +bool ClangExpressionSourceCode::GetText(std::string &text, + ExecutionContext &exe_ctx, + bool add_locals, + bool force_add_all_locals, + llvm::ArrayRef<std::string> modules, + bool ignore_context_qualifiers) const { const char *target_specific_defines = "typedef signed char BOOL;\n"; std::string module_macros; llvm::raw_string_ostream module_macros_stream(module_macros); @@ -486,17 +489,20 @@ 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) %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()); + 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(), + ignore_context_qualifiers + ? "" + : 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/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h index f721bb2f319e1..914d405139193 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h @@ -63,8 +63,8 @@ class ClangExpressionSourceCode : public ExpressionSourceCode { /// /// \return true iff the source code was successfully generated. bool GetText(std::string &text, ExecutionContext &exe_ctx, bool add_locals, - bool force_add_all_locals, - llvm::ArrayRef<std::string> modules) const; + bool force_add_all_locals, llvm::ArrayRef<std::string> modules, + bool ignore_context_qualifiers) const; // Given a string returned by GetText, find the beginning and end of the body // passed to CreateWrapped. Return true if the bounds could be found. This diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index 2cbbae11bd18a..634cdec918057 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -416,7 +416,8 @@ void ClangUserExpression::CreateSourceCode( m_filename, prefix, m_expr_text, GetWrapKind())); if (!m_source_code->GetText(m_transformed_text, exe_ctx, !m_ctx_obj, - for_completion, modules_to_import)) { + for_completion, modules_to_import, + m_options.GetCppIgnoreContextQualifiers())) { diagnostic_manager.PutString(lldb::eSeverityError, "couldn't construct expression body"); return; @@ -950,8 +951,8 @@ char ClangUserExpression::ClangUserExpressionHelper::ID; void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap( ExecutionContext &exe_ctx, Materializer::PersistentVariableDelegate &delegate, - bool keep_result_in_memory, - ValueObject *ctx_obj) { + bool keep_result_in_memory, ValueObject *ctx_obj, + bool ignore_context_qualifiers) { std::shared_ptr<ClangASTImporter> ast_importer; auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage( lldb::eLanguageTypeC); @@ -961,7 +962,7 @@ void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap( } m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>( keep_result_in_memory, &delegate, exe_ctx.GetTargetSP(), ast_importer, - ctx_obj); + ctx_obj, ignore_context_qualifiers); } clang::ASTConsumer * diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index 7c0c6a0147e2a..7f1c1ddcad942 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -71,8 +71,8 @@ class ClangUserExpression : public LLVMUserExpression { void ResetDeclMap(ExecutionContext &exe_ctx, Materializer::PersistentVariableDelegate &result_delegate, - bool keep_result_in_memory, - ValueObject *ctx_obj); + bool keep_result_in_memory, ValueObject *ctx_obj, + bool ignore_context_qualifiers); /// Return the object that the parser should allow to access ASTs. May be /// NULL if the ASTs do not need to be transformed. @@ -166,9 +166,9 @@ class ClangUserExpression : public LLVMUserExpression { void ResetDeclMap(ExecutionContext &exe_ctx, Materializer::PersistentVariableDelegate &result_delegate, bool keep_result_in_memory) { - m_type_system_helper.ResetDeclMap(exe_ctx, result_delegate, - keep_result_in_memory, - m_ctx_obj); + m_type_system_helper.ResetDeclMap( + exe_ctx, result_delegate, keep_result_in_memory, m_ctx_obj, + m_options.GetCppIgnoreContextQualifiers()); } lldb::ExpressionVariableSP diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index e6983066a12fa..112ce9be7bd1a 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -187,5 +187,5 @@ void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap( } m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>( keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), ast_importer, - nullptr); + nullptr, /*ignore_context_qualifiers=*/false); } diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 301dbdc6da9be..d9e72cd5453e4 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -5409,3 +5409,23 @@ StructuredData::Dictionary &EvaluateExpressionOptions::GetLanguageOptions() { return *m_language_options_sp; } + +// FIXME: this option is C++ plugin specific and should be registered by it, +// instead of hard-coding it here. +constexpr llvm::StringLiteral s_cpp_ignore_context_qualifiers_option = + "c++-ignore-context-qualifiers"; + +EvaluateExpressionOptions::EvaluateExpressionOptions() + : m_language_options_sp(std::make_shared<StructuredData::Dictionary>()) { + SetCppIgnoreContextQualifiers(false); +} + +void EvaluateExpressionOptions::SetCppIgnoreContextQualifiers(bool value) { + llvm::cantFail( + SetBooleanLanguageOption(s_cpp_ignore_context_qualifiers_option, value)); +} + +bool EvaluateExpressionOptions::GetCppIgnoreContextQualifiers() const { + return llvm::cantFail( + GetBooleanLanguageOption(s_cpp_ignore_context_qualifiers_option)); +} 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 index 0d8f477dce1fd..25c76b69aa3ab 100644 --- 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 @@ -27,6 +27,26 @@ def test(self): "cannot assign to non-static data member within const member function" ], ) + self.expect_expr("m_mem", result_value="-2") + + # Test short and long --c++-ignore-context-qualifiers option. + self.expect( + "expression --c++-ignore-context-qualifiers -- m_mem = 3.0", + error=False, + ) + self.expect_expr("m_mem", result_value="3") + + self.expect( + "expression -Q -- m_mem = 4.0", + error=False, + ) + self.expect_expr("m_mem", result_value="4") + + # Test --c++-ignore-context-qualifiers via SBExpressionOptions. + options = lldb.SBExpressionOptions() + options.SetBooleanLanguageOption("c++-ignore-context-qualifiers", True) + self.expect_expr("m_mem = -2.0; m_mem", options=options, result_value="-2") + self.expect_expr("((Foo*)this)->bar()", result_type="double", result_value="5") lldbutil.continue_to_source_breakpoint( @@ -43,6 +63,9 @@ def test(self): "cannot assign to non-static data member within const member function" ], ) + self.expect_expr("x", result_value="2") + + self.expect_expr("x = -5; x", options=options, result_value="-5") lldbutil.continue_to_source_breakpoint( self, @@ -76,6 +99,9 @@ def test(self): ], ) self.expect_expr("m_mem", result_value="-2") + + self.expect_expr("m_mem = -1; m_mem", options=options, result_value="-1") + self.expect_expr("((Foo*)this)->bar()", result_type="double", result_value="5") lldbutil.continue_to_source_breakpoint( @@ -102,4 +128,6 @@ def test(self): "cannot assign to non-static data member within const member function" ], ) - self.expect_expr("m_mem", result_value="-2") + self.expect_expr("m_mem", result_value="-1") + + self.expect_expr("m_mem = -2; m_mem", options=options, result_value="-2") 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 index f20b9d8164841..f1bcfb3c0827d 100644 --- 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 @@ -20,6 +20,16 @@ def test(self): substrs=["has type 'const Foo'", "but function is not marked const"], ) + options = lldb.SBExpressionOptions() + options.SetBooleanLanguageOption("c++-ignore-context-qualifiers", True) + options.SetIgnoreBreakpoints(True) + self.expect_expr("volatile_method()", options=options) + self.expect( + "expression --c++-ignore-context-qualifiers -- bar()", + error=True, + substrs=["call to member function 'bar' is ambiguous"], + ) + lldbutil.continue_to_source_breakpoint( self, process, "Break here: volatile", lldb.SBFileSpec("main.cpp") ) @@ -35,6 +45,13 @@ def test(self): ) self.expect_expr("volatile_method()") + self.expect_expr("const_method()", options=options) + self.expect( + "expression --c++-ignore-context-qualifiers -- bar()", + error=True, + substrs=["call to member function 'bar' is ambiguous"], + ) + lldbutil.continue_to_source_breakpoint( self, process, "Break here: const volatile", lldb.SBFileSpec("main.cpp") ) @@ -58,3 +75,11 @@ def test(self): "but function is not marked const or volatile", ], ) + + self.expect_expr("const_method()", options=options) + self.expect_expr("volatile_method()", options=options) + self.expect( + "expression --c++-ignore-context-qualifiers -- bar()", + error=True, + substrs=["call to member function 'bar' is ambiguous"], + ) 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 index 835487f3bb7e0..f6358d2037095 100644 --- 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 @@ -36,6 +36,10 @@ def test(self): ], ) + options = lldb.SBExpressionOptions() + options.SetBooleanLanguageOption("c++-ignore-context-qualifiers", True) + self.expect_expr("x = 6.0; x", options=options, result_value="6") + lldbutil.continue_to_source_breakpoint( self, process, 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 index 0d8f477dce1fd..cdaa06b8808b5 100644 --- 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 @@ -29,6 +29,10 @@ def test(self): ) self.expect_expr("((Foo*)this)->bar()", result_type="double", result_value="5") + options = lldb.SBExpressionOptions() + options.SetBooleanLanguageOption("c++-ignore-context-qualifiers", True) + self.expect_expr("m_mem = -2.0; m_mem", options=options, result_value="-2") + lldbutil.continue_to_source_breakpoint( self, process, @@ -43,6 +47,7 @@ def test(self): "cannot assign to non-static data member within const member function" ], ) + self.expect_expr("x = -7.0; x", options=options, result_value="-7") lldbutil.continue_to_source_breakpoint( self, @@ -77,6 +82,7 @@ def test(self): ) self.expect_expr("m_mem", result_value="-2") self.expect_expr("((Foo*)this)->bar()", result_type="double", result_value="5") + self.expect_expr("m_mem = -8.0; m_mem", options=options, result_value="-8") lldbutil.continue_to_source_breakpoint( self, @@ -102,4 +108,4 @@ def test(self): "cannot assign to non-static data member within const member function" ], ) - self.expect_expr("m_mem", result_value="-2") + self.expect_expr("m_mem = -11.0; m_mem", options=options, result_value="-11") 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 index 835487f3bb7e0..f6358d2037095 100644 --- 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 @@ -36,6 +36,10 @@ def test(self): ], ) + options = lldb.SBExpressionOptions() + options.SetBooleanLanguageOption("c++-ignore-context-qualifiers", True) + self.expect_expr("x = 6.0; x", options=options, result_value="6") + lldbutil.continue_to_source_breakpoint( self, process, diff --git a/lldb/test/API/lang/cpp/this/TestCPPThis.py b/lldb/test/API/lang/cpp/this/TestCPPThis.py index f127f80663578..4c4db30589fbf 100644 --- a/lldb/test/API/lang/cpp/this/TestCPPThis.py +++ b/lldb/test/API/lang/cpp/this/TestCPPThis.py @@ -47,14 +47,18 @@ def test_with_run_command(self): ) self.expect("expression -- (int)getpid(); m_a", startstr="(const int) $1 = 3") + self.expect( + "expression --c++-ignore-context-qualifiers -- m_a = 2", + startstr="(int) $2 = 2", + ) self.runCmd("process continue") - self.expect("expression -- s_a", startstr="(int) $2 = 5") + self.expect("expression -- s_a", startstr="(int) $3 = 5") self.runCmd("process continue") - self.expect("expression -- m_a", startstr="(int) $3 = 3") + self.expect("expression -- m_a", startstr="(int) $4 = 2") def set_breakpoint(self, line): lldbutil.run_break_set_by_file_and_line( diff --git a/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp b/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp index 1c07119d4497f..61905ee8df862 100644 --- a/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp +++ b/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp @@ -23,7 +23,7 @@ namespace { struct FakeClangExpressionDeclMap : public ClangExpressionDeclMap { FakeClangExpressionDeclMap(const std::shared_ptr<ClangASTImporter> &importer) : ClangExpressionDeclMap(false, nullptr, lldb::TargetSP(), importer, - nullptr) { + nullptr, /*ignore_context_qualifiers=*/false) { m_holder = std::make_unique<clang_utils::TypeSystemClangHolder>("ast"); m_scratch_context = m_holder->GetAST(); } _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
