Repository: dotnet/runtime
File: src/coreclr/jit/lower.cpp (C++)

Code before:
        InsertPInvokeMethodEpilog(m_compiler->compCurBB DEBUGARG(node));
    }

    BasicBlock* block = m_compiler->compCurBB;
    if (!block->KindIs(BBJ_RETURN))
    {
        bool profileInconsistent = false;
        for (BasicBlock* const succBlock : block->Succs())
        {
            FlowEdge* const succEdge = m_compiler->fgRemoveAllRefPreds(succBlock, block);

            if (block->hasProfileWeight() && succBlock->hasProfileWeight())
            {
                succBlock->decreaseBBProfileWeight(succEdge->getLikelyWeight());
                profileInconsistent |= (succBlock->NumSucc() > 0);
            }
        }

        if (profileInconsistent)
        {
            JITDUMP("Flow removal of " FMT_BB " needs to be propagated. Data %s inconsistent.\n", block->bbNum,
                    m_compiler->fgPgoConsistent ? "is now" : "was already");
            m_compiler->fgPgoConsistent = false;
        }

        block->SetKind(BBJ_RETURN);

        m_compiler->fgInvalidateDfsTree();
    }
}

//----------------------------------------------------------------------------------------------
// LowerCallStruct: Lowers a call node that returns a struct.
//
// Arguments:
//     call - The call node to lower.
//
// Notes:
//    - this handles only single-register returns;
//    - it transforms the call's user for `GT_STOREIND`.
//
void Lowering::LowerCallStruct(GenTreeCall* call)
{
    assert(varTypeIsStruct(call));
    if (call->HasMultiRegRetVal())
    {
        return;
    }

    if (GlobalJitOptions::compFeatureHfa)
    {

Review comment (suggestion):
When converting the current block to `BBJ_RETURN`, prefer `SetKindAndTargetEdge(BBJ_RETURN)` instead of `SetKind(BBJ_RETURN)`. This clears `bbTargetEdge`/`bbTrueEdge` so the block no longer retains dangling successor edge pointers after you remove it from successor pred lists, matching the pattern used elsewhere when folding blocks into returns.
```suggestion
        block->SetKindAndTargetEdge(BBJ_RETURN);
```

Code after:
    {
        bool profileInconsistent = false;
        for (BasicBlock* const succBlock : block->Succs())
        {
            FlowEdge* const succEdge = m_compiler->fgRemoveAllRefPreds(succBlock, block);

            if (block->hasProfileWeight() && succBlock->hasProfileWeight())
            {
                succBlock->decreaseBBProfileWeight(succEdge->getLikelyWeight());
                profileInconsistent |= (succBlock->NumSucc() > 0);
            }
        }

        if (profileInconsistent)
        {
            JITDUMP("Flow removal of " FMT_BB " needs to be propagated. Data %s inconsistent.\n", block->bbNum,
                    m_compiler->fgPgoConsistent ? "is now" : "was already");
            m_compiler->fgPgoConsistent = false;
        }

        block->SetKindAndTargetEdge(BBJ_RETURN);

        m_compiler->fgInvalidateDfsTree();
    }

    if (m_compiler->compMethodRequiresPInvokeFrame())
    {
        InsertPInvokeMethodEpilog(m_compiler->compCurBB DEBUGARG(node));
    }
}

//----------------------------------------------------------------------------------------------
// LowerCallStruct: Lowers a call node that returns a struct.
//
// Arguments:
//     call - The call node to lower.
//
// Notes:
//    - this handles only single-register returns;
//    - it transforms the call's user for `GT_STOREIND`.
//
void Lowering::LowerCallStruct(GenTreeCall* call)
{
    assert(varTypeIsStruct(call));
    if (call->HasMultiRegRetVal())
    {
        return;
    }

    if (GlobalJitOptions::compFeatureHfa)
    {