1111#include " Plugins/TypeSystem/Clang/TypeSystemClang.h"
1212#include " lldb/Symbol/Function.h"
1313#include " lldb/Symbol/VariableList.h"
14- #include " lldb/Utility/LLDBLog.h"
15- #include " lldb/Utility/Log.h"
1614
1715using namespace lldb ;
1816using namespace lldb_private ;
@@ -61,19 +59,23 @@ static Function *ExtractDestroyFunction(lldb::TargetSP target_sp,
6159 return destroy_func_address.CalculateSymbolContextFunction ();
6260}
6361
64- static CompilerType InferPromiseType (Function &destroy_func) {
65- Block &block = destroy_func.GetBlock (true );
62+ // clang generates aritifical `__promise` and `__coro_frame` variables inside
63+ // the destroy function. Look for those variables and extract their type.
64+ static CompilerType InferArtificialCoroType (Function *destroy_func,
65+ ConstString var_name) {
66+ if (!destroy_func)
67+ return {};
68+
69+ Block &block = destroy_func->GetBlock (true );
6670 auto variable_list = block.GetBlockVariableList (true );
6771
68- // clang generates an artificial `__promise` variable inside the
69- // `destroy` function. Look for it.
70- auto promise_var = variable_list->FindVariable (ConstString (" __promise" ));
71- if (!promise_var)
72+ auto var = variable_list->FindVariable (var_name);
73+ if (!var)
7274 return {};
73- if (!promise_var ->IsArtificial ())
75+ if (!var ->IsArtificial ())
7476 return {};
7577
76- Type *promise_type = promise_var ->GetType ();
78+ Type *promise_type = var ->GetType ();
7779 if (!promise_type)
7880 return {};
7981 return promise_type->GetForwardCompilerType ();
@@ -107,30 +109,17 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
107109
108110llvm::Expected<uint32_t > lldb_private::formatters::
109111 StdlibCoroutineHandleSyntheticFrontEnd::CalculateNumChildren () {
110- if (!m_resume_ptr_sp || !m_destroy_ptr_sp)
111- return 0 ;
112-
113- return m_promise_ptr_sp ? 3 : 2 ;
112+ return m_children.size ();
114113}
115114
116115lldb::ValueObjectSP lldb_private::formatters::
117116 StdlibCoroutineHandleSyntheticFrontEnd::GetChildAtIndex (uint32_t idx) {
118- switch (idx) {
119- case 0 :
120- return m_resume_ptr_sp;
121- case 1 :
122- return m_destroy_ptr_sp;
123- case 2 :
124- return m_promise_ptr_sp;
125- }
126- return lldb::ValueObjectSP ();
117+ return idx < m_children.size () ? m_children[idx] : lldb::ValueObjectSP ();
127118}
128119
129120lldb::ChildCacheState
130121lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update () {
131- m_resume_ptr_sp.reset ();
132- m_destroy_ptr_sp.reset ();
133- m_promise_ptr_sp.reset ();
122+ m_children.clear ();
134123
135124 ValueObjectSP valobj_sp = m_backend.GetNonSyntheticValue ();
136125 if (!valobj_sp)
@@ -140,77 +129,78 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update() {
140129 if (frame_ptr_addr == 0 || frame_ptr_addr == LLDB_INVALID_ADDRESS)
141130 return lldb::ChildCacheState::eRefetch;
142131
143- auto ast_ctx = valobj_sp->GetCompilerType ().GetTypeSystem <TypeSystemClang>();
144- if (!ast_ctx)
145- return lldb::ChildCacheState::eRefetch;
146-
147- // Create the `resume` and `destroy` children.
148132 lldb::TargetSP target_sp = m_backend.GetTargetSP ();
149133 auto &exe_ctx = m_backend.GetExecutionContextRef ();
150134 lldb::ProcessSP process_sp = target_sp->GetProcessSP ();
151135 auto ptr_size = process_sp->GetAddressByteSize ();
152- CompilerType void_type = ast_ctx->GetBasicType (lldb::eBasicTypeVoid);
153- std::array<CompilerType, 1 > args{void_type};
154- CompilerType coro_func_type = ast_ctx->CreateFunctionType (
155- /* result_type=*/ void_type, args,
156- /* is_variadic=*/ false , /* qualifiers=*/ 0 );
157- CompilerType coro_func_ptr_type = coro_func_type.GetPointerType ();
158- m_resume_ptr_sp = CreateValueObjectFromAddress (
159- " resume" , frame_ptr_addr + 0 * ptr_size, exe_ctx, coro_func_ptr_type);
160- lldbassert (m_resume_ptr_sp);
161- m_destroy_ptr_sp = CreateValueObjectFromAddress (
162- " destroy" , frame_ptr_addr + 1 * ptr_size, exe_ctx, coro_func_ptr_type);
163- lldbassert (m_destroy_ptr_sp);
164-
165- // Get the `promise_type` from the template argument
166- CompilerType promise_type (
167- valobj_sp->GetCompilerType ().GetTypeTemplateArgument (0 ));
168- if (!promise_type)
136+ auto ast_ctx = valobj_sp->GetCompilerType ().GetTypeSystem <TypeSystemClang>();
137+ if (!ast_ctx)
169138 return lldb::ChildCacheState::eRefetch;
170139
171- // Try to infer the promise_type if it was type-erased
140+ // Determine the coroutine frame type and the promise type. Fall back
141+ // to `void`, since even the pointer itself might be useful, even if the
142+ // type inference failed.
143+ Function *destroy_func = ExtractDestroyFunction (target_sp, frame_ptr_addr);
144+ CompilerType void_type = ast_ctx->GetBasicType (lldb::eBasicTypeVoid);
145+ CompilerType promise_type;
146+ if (CompilerType template_argt =
147+ valobj_sp->GetCompilerType ().GetTypeTemplateArgument (0 ))
148+ promise_type = std::move (template_argt);
172149 if (promise_type.IsVoidType ()) {
173- if (Function *destroy_func =
174- ExtractDestroyFunction (target_sp, frame_ptr_addr)) {
175- if (CompilerType inferred_type = InferPromiseType (*destroy_func)) {
150+ // Try to infer the promise_type if it was type-erased
151+ if (destroy_func) {
152+ if (CompilerType inferred_type = InferArtificialCoroType (
153+ destroy_func, ConstString (" __promise" ))) {
176154 promise_type = inferred_type;
177155 }
178156 }
179157 }
158+ CompilerType coro_frame_type =
159+ InferArtificialCoroType (destroy_func, ConstString (" __coro_frame" ));
160+ if (!coro_frame_type)
161+ coro_frame_type = void_type;
180162
181- // If we don't know the promise type, we don't display the `promise` member.
182- // `CreateValueObjectFromAddress` below would fail for `void` types.
183- if (promise_type.IsVoidType ()) {
184- return lldb::ChildCacheState::eRefetch;
185- }
186-
187- // Add the `promise` member. We intentionally add `promise` as a pointer type
188- // instead of a value type, and don't automatically dereference this pointer.
189- // We do so to avoid potential very deep recursion in case there is a cycle
190- // formed between `std::coroutine_handle`s and their promises.
191- lldb::ValueObjectSP promise = CreateValueObjectFromAddress (
192- " promise" , frame_ptr_addr + 2 * ptr_size, exe_ctx, promise_type);
193- Status error;
194- lldb::ValueObjectSP promisePtr = promise->AddressOf (error);
195- if (error.Success ())
196- m_promise_ptr_sp = promisePtr->Clone (ConstString (" promise" ));
163+ // Create the `resume` and `destroy` children.
164+ std::array<CompilerType, 1 > args{coro_frame_type};
165+ CompilerType coro_func_type = ast_ctx->CreateFunctionType (
166+ /* result_type=*/ void_type, args,
167+ /* is_variadic=*/ false , /* qualifiers=*/ 0 );
168+ CompilerType coro_func_ptr_type = coro_func_type.GetPointerType ();
169+ ValueObjectSP resume_ptr_sp = CreateValueObjectFromAddress (
170+ " resume" , frame_ptr_addr + 0 * ptr_size, exe_ctx, coro_func_ptr_type);
171+ lldbassert (resume_ptr_sp);
172+ m_children.push_back (std::move (resume_ptr_sp));
173+ ValueObjectSP destroy_ptr_sp = CreateValueObjectFromAddress (
174+ " destroy" , frame_ptr_addr + 1 * ptr_size, exe_ctx, coro_func_ptr_type);
175+ lldbassert (destroy_ptr_sp);
176+ m_children.push_back (std::move (destroy_ptr_sp));
177+
178+ // Add promise and coro_frame
179+ // Add the `promise` and `coro_frame` member. We intentionally add them as
180+ // pointer types instead of a value type, and don't automatically dereference
181+ // those pointers. We do so to avoid potential very deep recursion in case
182+ // there is a cycle formed between `std::coroutine_handle`s and their
183+ // promises.
184+ ValueObjectSP promise_ptr_sp = CreateValueObjectFromAddress (
185+ " promise" , frame_ptr_addr + 2 * ptr_size, exe_ctx,
186+ promise_type.GetPointerType (), /* do_deref=*/ false );
187+ m_children.push_back (std::move (promise_ptr_sp));
188+ ValueObjectSP coroframe_ptr_sp = CreateValueObjectFromAddress (
189+ " coro_frame" , frame_ptr_addr, exe_ctx, coro_frame_type.GetPointerType (),
190+ /* do_deref=*/ false );
191+ m_children.push_back (std::move (coroframe_ptr_sp));
197192
198193 return lldb::ChildCacheState::eRefetch;
199194}
200195
201196llvm::Expected<size_t >
202197StdlibCoroutineHandleSyntheticFrontEnd::GetIndexOfChildWithName (
203198 ConstString name) {
204- if (!m_resume_ptr_sp || !m_destroy_ptr_sp)
205- return llvm::createStringError (" Type has no child named '%s'" ,
206- name.AsCString ());
207-
208- if (name == ConstString (" resume" ))
209- return 0 ;
210- if (name == ConstString (" destroy" ))
211- return 1 ;
212- if (name == ConstString (" promise_ptr" ) && m_promise_ptr_sp)
213- return 2 ;
199+ for (size_t i = 0 , limit = m_children.size (); i < limit; ++i) {
200+ if (m_children[i]->GetName () == name) {
201+ return i;
202+ }
203+ }
214204
215205 return llvm::createStringError (" Type has no child named '%s'" ,
216206 name.AsCString ());
0 commit comments