aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ExpressionParser/Clang
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-24 15:03:44 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-07-24 15:03:44 +0000
commit4b4fe385e49bd883fd183b5f21c1ea486c722e61 (patch)
treec3d8fdb355c9c73e57723718c22103aaf7d15aa6 /lldb/source/Plugins/ExpressionParser/Clang
parent1f917f69ff07f09b6dbb670971f57f8efe718b84 (diff)
downloadsrc-4b4fe385e49bd883fd183b5f21c1ea486c722e61.tar.gz
src-4b4fe385e49bd883fd183b5f21c1ea486c722e61.zip
Vendor import of llvm-project main llvmorg-15-init-17485-ga3e38b4a206b.vendor/llvm-project/llvmorg-15-init-17485-ga3e38b4a206b
Diffstat (limited to 'lldb/source/Plugins/ExpressionParser/Clang')
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp27
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp7
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp173
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h31
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp54
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h16
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp27
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.h30
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h8
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp38
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h4
11 files changed, 375 insertions, 40 deletions
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
index 7a1ac7870547..799ae29e2841 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
@@ -197,6 +197,27 @@ bool ASTResultSynthesizer::SynthesizeObjCMethodResult(
return ret;
}
+/// Returns true if LLDB can take the address of the given lvalue for the sake
+/// of capturing the expression result. Returns false if LLDB should instead
+/// store the expression result in a result variable.
+static bool CanTakeAddressOfLValue(const Expr *lvalue_expr) {
+ assert(lvalue_expr->getValueKind() == VK_LValue &&
+ "lvalue_expr not a lvalue");
+
+ QualType qt = lvalue_expr->getType();
+ // If the lvalue has const-qualified non-volatile integral or enum type, then
+ // the underlying value might come from a const static data member as
+ // described in C++11 [class.static.data]p3. If that's the case, then the
+ // value might not have an address if the user didn't also define the member
+ // in a namespace scope. Taking the address would cause that LLDB later fails
+ // to link the expression, so those lvalues should be stored in a result
+ // variable.
+ if (qt->isIntegralOrEnumerationType() && qt.isConstQualified() &&
+ !qt.isVolatileQualified())
+ return false;
+ return true;
+}
+
bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
DeclContext *DC) {
Log *log = GetLog(LLDBLog::Expressions);
@@ -265,6 +286,10 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
// - During dematerialization, $0 is marked up as a load address with value
// equal to the contents of the structure entry.
//
+ // - Note: if we cannot take an address of the resulting Lvalue (e.g. it's
+ // a static const member without an out-of-class definition), then we
+ // follow the Rvalue route.
+ //
// For Rvalues
//
// - In AST result synthesis the expression E is transformed into an
@@ -304,7 +329,7 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
clang::VarDecl *result_decl = nullptr;
- if (is_lvalue) {
+ if (is_lvalue && CanTakeAddressOfLValue(last_expr)) {
IdentifierInfo *result_ptr_id;
if (expr_type->isFunctionType())
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 1bf29efb0bee..f8443d608ac3 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -1430,10 +1430,9 @@ static bool ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map,
std::vector<PairType> sorted_items;
sorted_items.reserve(source_map.size());
sorted_items.assign(source_map.begin(), source_map.end());
- llvm::sort(sorted_items.begin(), sorted_items.end(),
- [](const PairType &lhs, const PairType &rhs) {
- return lhs.second < rhs.second;
- });
+ llvm::sort(sorted_items, [](const PairType &lhs, const PairType &rhs) {
+ return lhs.second < rhs.second;
+ });
for (const auto &item : sorted_items) {
DeclFromUser<D> user_decl(const_cast<D *>(item.first));
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 4305a9982343..6ba03dad98d1 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -9,10 +9,13 @@
#include "ClangExpressionDeclMap.h"
#include "ClangASTSource.h"
+#include "ClangExpressionUtil.h"
+#include "ClangExpressionVariable.h"
#include "ClangModulesDeclVendor.h"
#include "ClangPersistentVariables.h"
#include "ClangUtil.h"
+#include "NameSearchContext.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Module.h"
@@ -44,6 +47,7 @@
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Status.h"
+#include "lldb/lldb-private-types.h"
#include "lldb/lldb-private.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -62,6 +66,24 @@ using namespace clang;
static const char *g_lldb_local_vars_namespace_cstr = "$__lldb_local_vars";
+namespace {
+/// A lambda is represented by Clang as an artifical class whose
+/// members are the lambda captures. If we capture a 'this' pointer,
+/// the artifical class will contain a member variable named 'this'.
+/// The function returns a ValueObject for the captured 'this' if such
+/// member exists. If no 'this' was captured, return a nullptr.
+lldb::ValueObjectSP GetCapturedThisValueObject(StackFrame *frame) {
+ assert(frame);
+
+ if (auto thisValSP = frame->FindVariable(ConstString("this")))
+ if (auto thisThisValSP =
+ thisValSP->GetChildMemberWithName(ConstString("this"), true))
+ return thisThisValSP;
+
+ return nullptr;
+}
+} // namespace
+
ClangExpressionDeclMap::ClangExpressionDeclMap(
bool keep_result_in_memory,
Materializer::PersistentVariableDelegate *result_delegate,
@@ -394,6 +416,10 @@ bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl,
else if (parser_vars->m_lldb_var)
offset = m_parser_vars->m_materializer->AddVariable(
parser_vars->m_lldb_var, err);
+ else if (parser_vars->m_lldb_valobj_provider) {
+ offset = m_parser_vars->m_materializer->AddValueObject(
+ name, parser_vars->m_lldb_valobj_provider, err);
+ }
}
if (!err.Success())
@@ -795,6 +821,28 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) {
TypeSystemClang::DeclContextGetAsCXXMethodDecl(function_decl_ctx);
if (method_decl) {
+ if (auto capturedThis = GetCapturedThisValueObject(frame)) {
+ // We're inside a lambda and we captured a 'this'.
+ // Import the outer class's AST instead of the
+ // (unnamed) lambda structure AST so unqualified
+ // member lookups are understood by the Clang parser.
+ //
+ // If we're in a lambda which didn't capture 'this',
+ // $__lldb_class will correspond to the lambda closure
+ // AST and references to captures will resolve like
+ // regular member varaiable accesses do.
+ TypeFromUser pointee_type =
+ capturedThis->GetCompilerType().GetPointeeType();
+
+ LLDB_LOG(log,
+ " CEDM::FEVD Adding captured type ({0} for"
+ " $__lldb_class: {1}",
+ capturedThis->GetTypeName(), capturedThis->GetName());
+
+ AddContextClassType(context, pointee_type);
+ return;
+ }
+
clang::CXXRecordDecl *class_decl = method_decl->getParent();
QualType class_qual_type(class_decl->getTypeForDecl(), 0);
@@ -1053,6 +1101,30 @@ bool ClangExpressionDeclMap::LookupLocalVariable(
context.m_found_variable = true;
}
}
+
+ // We're in a local_var_lookup but haven't found any local variables
+ // so far. When performing a variable lookup from within the context of
+ // a lambda, we count the lambda captures as local variables. Thus,
+ // see if we captured any variables with the requested 'name'.
+ if (!variable_found) {
+ auto find_capture = [](ConstString varname,
+ StackFrame *frame) -> ValueObjectSP {
+ if (auto lambda = ClangExpressionUtil::GetLambdaValueObject(frame)) {
+ if (auto capture = lambda->GetChildMemberWithName(varname, true)) {
+ return capture;
+ }
+ }
+
+ return nullptr;
+ };
+
+ if (auto capture = find_capture(name, frame)) {
+ variable_found = true;
+ context.m_found_variable = true;
+ AddOneVariable(context, std::move(capture), std::move(find_capture));
+ }
+ }
+
return variable_found;
}
@@ -1493,25 +1565,15 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var,
return true;
}
-void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
- VariableSP var,
- ValueObjectSP valobj) {
- assert(m_parser_vars.get());
-
- Log *log = GetLog(LLDBLog::Expressions);
-
- TypeFromUser ut;
- TypeFromParser pt;
- Value var_location;
-
- if (!GetVariableValue(var, var_location, &ut, &pt))
- return;
-
+ClangExpressionVariable::ParserVars *
+ClangExpressionDeclMap::AddExpressionVariable(NameSearchContext &context,
+ TypeFromParser const &pt,
+ ValueObjectSP valobj) {
clang::QualType parser_opaque_type =
QualType::getFromOpaquePtr(pt.GetOpaqueQualType());
if (parser_opaque_type.isNull())
- return;
+ return nullptr;
if (const clang::Type *parser_type = parser_opaque_type.getTypePtr()) {
if (const TagType *tag_type = dyn_cast<TagType>(parser_type))
@@ -1538,16 +1600,89 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
entity->EnableParserVars(GetParserID());
ClangExpressionVariable::ParserVars *parser_vars =
entity->GetParserVars(GetParserID());
+
parser_vars->m_named_decl = var_decl;
- parser_vars->m_llvm_value = nullptr;
- parser_vars->m_lldb_value = var_location;
- parser_vars->m_lldb_var = var;
if (is_reference)
entity->m_flags |= ClangExpressionVariable::EVTypeIsReference;
+ return parser_vars;
+}
+
+void ClangExpressionDeclMap::AddOneVariable(
+ NameSearchContext &context, ValueObjectSP valobj,
+ ValueObjectProviderTy valobj_provider) {
+ assert(m_parser_vars.get());
+ assert(valobj);
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ Value var_location = valobj->GetValue();
+
+ TypeFromUser user_type = valobj->GetCompilerType();
+
+ TypeSystemClang *clang_ast =
+ llvm::dyn_cast_or_null<TypeSystemClang>(user_type.GetTypeSystem());
+
+ if (!clang_ast) {
+ LLDB_LOG(log, "Skipped a definition because it has no Clang AST");
+ return;
+ }
+
+ TypeFromParser parser_type = GuardedCopyType(user_type);
+
+ if (!parser_type) {
+ LLDB_LOG(log,
+ "Couldn't copy a variable's type into the parser's AST context");
+
+ return;
+ }
+
+ if (var_location.GetContextType() == Value::ContextType::Invalid)
+ var_location.SetCompilerType(parser_type);
+
+ ClangExpressionVariable::ParserVars *parser_vars =
+ AddExpressionVariable(context, parser_type, valobj);
+
+ if (!parser_vars)
+ return;
+
LLDB_LOG(log, " CEDM::FEVD Found variable {0}, returned\n{1} (original {2})",
- decl_name, ClangUtil::DumpDecl(var_decl), ClangUtil::ToString(ut));
+ context.m_decl_name, ClangUtil::DumpDecl(parser_vars->m_named_decl),
+ ClangUtil::ToString(user_type));
+
+ parser_vars->m_llvm_value = nullptr;
+ parser_vars->m_lldb_value = std::move(var_location);
+ parser_vars->m_lldb_valobj_provider = std::move(valobj_provider);
+}
+
+void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
+ VariableSP var,
+ ValueObjectSP valobj) {
+ assert(m_parser_vars.get());
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ TypeFromUser ut;
+ TypeFromParser pt;
+ Value var_location;
+
+ if (!GetVariableValue(var, var_location, &ut, &pt))
+ return;
+
+ ClangExpressionVariable::ParserVars *parser_vars =
+ AddExpressionVariable(context, pt, std::move(valobj));
+
+ if (!parser_vars)
+ return;
+
+ LLDB_LOG(log, " CEDM::FEVD Found variable {0}, returned\n{1} (original {2})",
+ context.m_decl_name, ClangUtil::DumpDecl(parser_vars->m_named_decl),
+ ClangUtil::ToString(ut));
+
+ parser_vars->m_llvm_value = nullptr;
+ parser_vars->m_lldb_value = var_location;
+ parser_vars->m_lldb_var = var;
}
void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
index f968f859cc72..bf7646ccaedf 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -531,6 +531,23 @@ private:
TypeFromParser *parser_type = nullptr);
/// Use the NameSearchContext to generate a Decl for the given LLDB
+ /// ValueObject, and put it in the list of found entities.
+ ///
+ /// Helper function used by the other AddOneVariable APIs.
+ ///
+ /// \param[in,out] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// \param[in] pt
+ /// The CompilerType of the variable we're adding a Decl for.
+ ///
+ /// \param[in] var
+ /// The LLDB ValueObject that needs a Decl.
+ ClangExpressionVariable::ParserVars *
+ AddExpressionVariable(NameSearchContext &context, TypeFromParser const &pt,
+ lldb::ValueObjectSP valobj);
+
+ /// Use the NameSearchContext to generate a Decl for the given LLDB
/// Variable, and put it in the Tuple list.
///
/// \param[in] context
@@ -544,6 +561,20 @@ private:
void AddOneVariable(NameSearchContext &context, lldb::VariableSP var,
lldb::ValueObjectSP valobj);
+ /// Use the NameSearchContext to generate a Decl for the given ValueObject
+ /// and put it in the list of found entities.
+ ///
+ /// \param[in,out] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// \param[in] valobj
+ /// The ValueObject that needs a Decl.
+ ///
+ /// \param[in] valobj_provider Callback that fetches a ValueObjectSP
+ /// from the specified frame
+ void AddOneVariable(NameSearchContext &context, lldb::ValueObjectSP valobj,
+ ValueObjectProviderTy valobj_provider);
+
/// Use the NameSearchContext to generate a Decl for the given persistent
/// variable, and put it in the list of found entities.
///
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
index 5168f637c443..56c00b35ba11 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -8,6 +8,8 @@
#include "ClangExpressionSourceCode.h"
+#include "ClangExpressionUtil.h"
+
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
@@ -27,6 +29,7 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-forward.h"
using namespace lldb_private;
@@ -200,6 +203,34 @@ public:
return m_tokens.find(token) != m_tokens.end();
}
};
+
+// If we're evaluating from inside a lambda that captures a 'this' pointer,
+// add a "using" declaration to 'stream' for each capture used in the
+// expression (tokenized by 'verifier').
+//
+// If no 'this' capture exists, generate no using declarations. Instead
+// capture lookups will get resolved by the same mechanism as class member
+// variable lookup. That's because Clang generates an unnamed structure
+// representing the lambda closure whose members are the captured variables.
+void AddLambdaCaptureDecls(StreamString &stream, StackFrame *frame,
+ TokenVerifier const &verifier) {
+ assert(frame);
+
+ if (auto thisValSP = ClangExpressionUtil::GetLambdaValueObject(frame)) {
+ uint32_t numChildren = thisValSP->GetNumChildren();
+ for (uint32_t i = 0; i < numChildren; ++i) {
+ auto childVal = thisValSP->GetChildAtIndex(i, true);
+ ConstString childName(childVal ? childVal->GetName() : ConstString(""));
+
+ if (!childName.IsEmpty() && verifier.hasToken(childName.GetStringRef()) &&
+ childName != "this") {
+ stream.Printf("using $__lldb_local_vars::%s;\n",
+ childName.GetCString());
+ }
+ }
+ }
+}
+
} // namespace
TokenVerifier::TokenVerifier(std::string body) {
@@ -264,16 +295,24 @@ TokenVerifier::TokenVerifier(std::string body) {
}
}
-void ClangExpressionSourceCode::AddLocalVariableDecls(
- const lldb::VariableListSP &var_list_sp, StreamString &stream,
- const std::string &expr) const {
+void ClangExpressionSourceCode::AddLocalVariableDecls(StreamString &stream,
+ const std::string &expr,
+ StackFrame *frame) const {
+ assert(frame);
TokenVerifier tokens(expr);
+ lldb::VariableListSP var_list_sp = frame->GetInScopeVariableList(false, true);
+
for (size_t i = 0; i < var_list_sp->GetSize(); i++) {
lldb::VariableSP var_sp = var_list_sp->GetVariableAtIndex(i);
ConstString var_name = var_sp->GetName();
+ if (var_name == "this" && m_wrap_kind == WrapKind::CppMemberFunction) {
+ AddLambdaCaptureDecls(stream, frame, tokens);
+
+ continue;
+ }
// We can check for .block_descriptor w/o checking for langauge since this
// is not a valid identifier in either C or C++.
@@ -288,9 +327,6 @@ void ClangExpressionSourceCode::AddLocalVariableDecls(
if ((var_name == "self" || var_name == "_cmd") && is_objc)
continue;
- if (var_name == "this" && m_wrap_kind == WrapKind::CppMemberFunction)
- continue;
-
stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString());
}
}
@@ -376,10 +412,8 @@ bool ClangExpressionSourceCode::GetText(
if (add_locals)
if (target->GetInjectLocalVariables(&exe_ctx)) {
- lldb::VariableListSP var_list_sp =
- frame->GetInScopeVariableList(false, true);
- AddLocalVariableDecls(var_list_sp, lldb_local_var_decls,
- force_add_all_locals ? "" : m_body);
+ AddLocalVariableDecls(lldb_local_var_decls,
+ force_add_all_locals ? "" : m_body, frame);
}
}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
index 54ae837fb30f..f721bb2f319e 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
@@ -78,9 +78,19 @@ protected:
Wrapping wrap, WrapKind wrap_kind);
private:
- void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp,
- StreamString &stream,
- const std::string &expr) const;
+ /// Writes "using" declarations for local variables into the specified stream.
+ ///
+ /// Behaviour is undefined if 'frame == nullptr'.
+ ///
+ /// \param[out] stream Stream that this function generates "using"
+ /// declarations into.
+ ///
+ /// \param[in] expr Expression source that we're evaluating.
+ ///
+ /// \param[in] frame StackFrame which carries information about the local
+ /// variables that we're generating "using" declarations for.
+ void AddLocalVariableDecls(StreamString &stream, const std::string &expr,
+ StackFrame *frame) const;
/// String marking the start of the user expression.
std::string m_start_marker;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp
new file mode 100644
index 000000000000..9b490e1c036e
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp
@@ -0,0 +1,27 @@
+//===-- ClangExpressionUtil.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangExpressionUtil.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Utility/ConstString.h"
+
+namespace lldb_private {
+namespace ClangExpressionUtil {
+lldb::ValueObjectSP GetLambdaValueObject(StackFrame *frame) {
+ assert(frame);
+
+ if (auto this_val_sp = frame->FindVariable(ConstString("this")))
+ if (this_val_sp->GetChildMemberWithName(ConstString("this"), true))
+ return this_val_sp;
+
+ return nullptr;
+}
+} // namespace ClangExpressionUtil
+} // namespace lldb_private
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.h
new file mode 100644
index 000000000000..fb8b857256c0
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.h
@@ -0,0 +1,30 @@
+//===-- ClangExpressionUtil.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONUTIL_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONUTIL_H
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+namespace ClangExpressionUtil {
+/// Returns a ValueObject for the lambda class in the current frame
+///
+/// To represent a lambda, Clang generates an artificial class
+/// whose members are the captures and whose operator() is the
+/// lambda implementation. If we capture a 'this' pointer,
+/// the artifical class will contain a member variable named 'this'.
+///
+/// This method returns the 'this' pointer to the artificial lambda
+/// class if a real 'this' was captured. Otherwise, returns nullptr.
+lldb::ValueObjectSP GetLambdaValueObject(StackFrame *frame);
+
+} // namespace ClangExpressionUtil
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
index 7bb68e78373f..c7d9e05269fa 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
@@ -116,7 +116,7 @@ public:
/// The following values should not live beyond parsing
class ParserVars {
public:
- ParserVars() : m_lldb_value(), m_lldb_var() {}
+ ParserVars() = default;
const clang::NamedDecl *m_named_decl =
nullptr; ///< The Decl corresponding to this variable
@@ -129,6 +129,12 @@ public:
const lldb_private::Symbol *m_lldb_sym =
nullptr; ///< The original symbol for this
/// variable, if it was a symbol
+
+ /// Callback that provides a ValueObject for the
+ /// specified frame. Used by the materializer for
+ /// re-fetching ValueObjects when materializing
+ /// ivars.
+ ValueObjectProviderTy m_lldb_valobj_provider;
};
private:
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index 78b8bf11220a..7145e7804e68 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -872,6 +872,34 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx,
return true;
}
+lldb::addr_t ClangUserExpression::GetCppObjectPointer(
+ lldb::StackFrameSP frame_sp, ConstString &object_name, Status &err) {
+ auto valobj_sp =
+ GetObjectPointerValueObject(std::move(frame_sp), object_name, err);
+
+ // We're inside a C++ class method. This could potentially be an unnamed
+ // lambda structure. If the lambda captured a "this", that should be
+ // the object pointer.
+ if (auto thisChildSP =
+ valobj_sp->GetChildMemberWithName(ConstString("this"), true)) {
+ valobj_sp = thisChildSP;
+ }
+
+ if (!err.Success() || !valobj_sp.get())
+ return LLDB_INVALID_ADDRESS;
+
+ lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+
+ if (ret == LLDB_INVALID_ADDRESS) {
+ err.SetErrorStringWithFormat(
+ "Couldn't load '%s' because its value couldn't be evaluated",
+ object_name.AsCString());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ return ret;
+}
+
bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx,
std::vector<lldb::addr_t> &args,
lldb::addr_t struct_address,
@@ -906,8 +934,14 @@ bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx,
address_type != eAddressTypeLoad)
object_ptr_error.SetErrorString("Can't get context object's "
"debuggee address");
- } else
- object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);
+ } else {
+ if (m_in_cplusplus_method) {
+ object_ptr =
+ GetCppObjectPointer(frame_sp, object_name, object_ptr_error);
+ } else {
+ object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);
+ }
+ }
if (!object_ptr_error.Success()) {
exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Printf(
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
index 30cdd2f3e990..4d5458f1807d 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -198,6 +198,10 @@ private:
ExecutionContext &exe_ctx,
std::vector<std::string> modules_to_import,
bool for_completion);
+
+ lldb::addr_t GetCppObjectPointer(lldb::StackFrameSP frame,
+ ConstString &object_name, Status &err);
+
/// Defines how the current expression should be wrapped.
ClangExpressionSourceCode::WrapKind GetWrapKind() const;
bool SetupPersistentState(DiagnosticManager &diagnostic_manager,