================ @@ -140,77 +129,78 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update() { if (frame_ptr_addr == 0 || frame_ptr_addr == LLDB_INVALID_ADDRESS) return lldb::ChildCacheState::eRefetch; - auto ast_ctx = valobj_sp->GetCompilerType().GetTypeSystem<TypeSystemClang>(); - if (!ast_ctx) - return lldb::ChildCacheState::eRefetch; - - // Create the `resume` and `destroy` children. lldb::TargetSP target_sp = m_backend.GetTargetSP(); auto &exe_ctx = m_backend.GetExecutionContextRef(); lldb::ProcessSP process_sp = target_sp->GetProcessSP(); auto ptr_size = process_sp->GetAddressByteSize(); - CompilerType void_type = ast_ctx->GetBasicType(lldb::eBasicTypeVoid); - std::array<CompilerType, 1> args{void_type}; - CompilerType coro_func_type = ast_ctx->CreateFunctionType( - /*result_type=*/void_type, args, - /*is_variadic=*/false, /*qualifiers=*/0); - CompilerType coro_func_ptr_type = coro_func_type.GetPointerType(); - m_resume_ptr_sp = CreateValueObjectFromAddress( - "resume", frame_ptr_addr + 0 * ptr_size, exe_ctx, coro_func_ptr_type); - lldbassert(m_resume_ptr_sp); - m_destroy_ptr_sp = CreateValueObjectFromAddress( - "destroy", frame_ptr_addr + 1 * ptr_size, exe_ctx, coro_func_ptr_type); - lldbassert(m_destroy_ptr_sp); - - // Get the `promise_type` from the template argument - CompilerType promise_type( - valobj_sp->GetCompilerType().GetTypeTemplateArgument(0)); - if (!promise_type) + auto ast_ctx = valobj_sp->GetCompilerType().GetTypeSystem<TypeSystemClang>(); + if (!ast_ctx) return lldb::ChildCacheState::eRefetch; - // Try to infer the promise_type if it was type-erased + // Determine the coroutine frame type and the promise type. Fall back + // to `void`, since even the pointer itself might be useful, even if the + // type inference failed. + Function *destroy_func = ExtractDestroyFunction(target_sp, frame_ptr_addr); + CompilerType void_type = ast_ctx->GetBasicType(lldb::eBasicTypeVoid); + CompilerType promise_type; + if (CompilerType template_argt = + valobj_sp->GetCompilerType().GetTypeTemplateArgument(0)) + promise_type = std::move(template_argt); if (promise_type.IsVoidType()) { - if (Function *destroy_func = - ExtractDestroyFunction(target_sp, frame_ptr_addr)) { - if (CompilerType inferred_type = InferPromiseType(*destroy_func)) { + // Try to infer the promise_type if it was type-erased + if (destroy_func) { + if (CompilerType inferred_type = InferArtificialCoroType( + destroy_func, ConstString("__promise"))) { promise_type = inferred_type; } } } + CompilerType coro_frame_type = + InferArtificialCoroType(destroy_func, ConstString("__coro_frame")); + if (!coro_frame_type) + coro_frame_type = void_type; - // If we don't know the promise type, we don't display the `promise` member. - // `CreateValueObjectFromAddress` below would fail for `void` types. - if (promise_type.IsVoidType()) { - return lldb::ChildCacheState::eRefetch; - } - - // Add the `promise` member. We intentionally add `promise` as a pointer type - // instead of a value type, and don't automatically dereference this pointer. - // We do so to avoid potential very deep recursion in case there is a cycle - // formed between `std::coroutine_handle`s and their promises. - lldb::ValueObjectSP promise = CreateValueObjectFromAddress( - "promise", frame_ptr_addr + 2 * ptr_size, exe_ctx, promise_type); - Status error; - lldb::ValueObjectSP promisePtr = promise->AddressOf(error); - if (error.Success()) - m_promise_ptr_sp = promisePtr->Clone(ConstString("promise")); + // Create the `resume` and `destroy` children. + std::array<CompilerType, 1> args{coro_frame_type}; + CompilerType coro_func_type = ast_ctx->CreateFunctionType( + /*result_type=*/void_type, args, + /*is_variadic=*/false, /*qualifiers=*/0); + CompilerType coro_func_ptr_type = coro_func_type.GetPointerType(); + ValueObjectSP resume_ptr_sp = CreateValueObjectFromAddress( + "resume", frame_ptr_addr + 0 * ptr_size, exe_ctx, coro_func_ptr_type); + lldbassert(resume_ptr_sp); + m_children.push_back(std::move(resume_ptr_sp)); + ValueObjectSP destroy_ptr_sp = CreateValueObjectFromAddress( + "destroy", frame_ptr_addr + 1 * ptr_size, exe_ctx, coro_func_ptr_type); + lldbassert(destroy_ptr_sp); + m_children.push_back(std::move(destroy_ptr_sp)); + + // Add promise and coro_frame + // Add the `promise` and `coro_frame` member. We intentionally add them as + // pointer types instead of a value type, and don't automatically dereference + // those pointers. We do so to avoid potential very deep recursion in case + // there is a cycle formed between `std::coroutine_handle`s and their + // promises. + ValueObjectSP promise_ptr_sp = CreateValueObjectFromAddress( + "promise", frame_ptr_addr + 2 * ptr_size, exe_ctx, + promise_type.GetPointerType(), /*do_deref=*/false); + m_children.push_back(std::move(promise_ptr_sp)); + ValueObjectSP coroframe_ptr_sp = CreateValueObjectFromAddress( + "coro_frame", frame_ptr_addr, exe_ctx, coro_frame_type.GetPointerType(), + /*do_deref=*/false); + m_children.push_back(std::move(coroframe_ptr_sp)); return lldb::ChildCacheState::eRefetch; } llvm::Expected<size_t> StdlibCoroutineHandleSyntheticFrontEnd::GetIndexOfChildWithName( ConstString name) { - if (!m_resume_ptr_sp || !m_destroy_ptr_sp) - return llvm::createStringError("Type has no child named '%s'", - name.AsCString()); - - if (name == ConstString("resume")) - return 0; - if (name == ConstString("destroy")) - return 1; - if (name == ConstString("promise_ptr") && m_promise_ptr_sp) - return 2; + for (size_t i = 0, limit = m_children.size(); i < limit; ++i) { + if (m_children[i]->GetName() == name) { + return i; + } + } ---------------- labath wrote:
```suggestion for (const auto &[idx, child_sp] : llvm::enumerate(m_children)) { if (child_sp->GetName() == name) return idx; } ``` https://github.com/llvm/llvm-project/pull/141516 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits