Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions lldb/include/lldb/Target/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Commands/CommandObjectExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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>
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Commands/CommandObjectExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions lldb/source/Commands/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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 *
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
20 changes: 20 additions & 0 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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,
Expand Down Expand Up @@ -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(
Expand All @@ -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")
Original file line number Diff line number Diff line change
Expand Up @@ -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")
)
Expand All @@ -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")
)
Expand All @@ -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"],
)
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading
Loading