Targeting a specific scope with defer

Is there a way to specify which scope a deferred block should run at the end of, rather than just the current scope?

e.g. I might want to write:

var data: UnsafeMutablePointer<UInt8>

if someCondition {
    data = someNonOwnedResult
} else {
    data = someOwnedResult
    defer { data.deallocate() } // 🚨 Runs too early.

    try … // More work here contingent on !someCondition.
}

try doSomething(with: data)

// *Now* I want to deallocate `data` (if necessary).

I want that defer to run at the end of the outer scope (typically the function's full scope, but not always), but as far as I can tell there's no elegant way to do that today?

Typically I end up with something like:

var data: UnsafeMutablePointer<UInt8>
var deallocateData = false

let condition = someCondition

if condition {
    data = someNonOwnedResult
} else {
    data = someOwnedResult
    deallocateData = true
}

defer {
    if deallocateData {
        data.deallocate()
    }
}

if !condition {
    try … // Finish doing all the other !someCondition stuff.
}

try doSomething(with: data)

Even in this contrivedly-trivial case that's pretty unappealing, let-alone in real-world code with multiple levels of indentation (when data is populated and its deallocation requirement determined) and with much more stuff in-between the key points.

I feel like it'd be quite helpful if defers could be targeted to labels, including an implicit label for the enclosing function, e.g.:

var data: UnsafeMutablePointer<UInt8>

if someCondition {
    data = someNonOwnedResult
} else {
    data = someOwnedResult
    defer to function exit { data.deallocate() }

    try … // More work here contingent on !someCondition.
}

try doSomething(with: data)

I know there's other workarounds like making a wrapper type for the object & the flag of whether it should be deleted, and handling that in object deinit, but that's conceptually heavy-weight for such a simple task. (made better, semantically, with non-copyable types so that it can be a struct, but even so)

I guess just use a function:

if someCondition {
    try doSomething(with: data)
} else {
    defer { someOwnedResult.deallocate() }
    try doSomething(with: someOwnedResult)
}

A bit clumsy, but more explicit and likely easier to read (to me, at least).

Whenever I find myself wishing for a break n / continue n statement, I tend to refactor it into a function with early returns. Both situations are more or less gotos and, as you mention...

... are quite difficult to follow

Alternatively, you could save one level of indentation with:

guard !someCondition else { return try doSomething(with: data) }

defer { deallocate() }
try … // More work here contingent on !someCondition.
try doSomething(with: data)