C goto vs Zig defer / errdefer / break

ten?!? :slight_smile: you’re kidding…
One label is more than enough:

bool do_smth(... result *r) {

    int fd1 = -1;
    int fd2 = -1;
    void *m1 = NULL;
    void *m2 = NULL;

    fd1 = open(...);
    if (-1 == fd1) {
        ...
        goto __failure;
    }

    fd2 = open(...);
    if (-1 == fd2) {
        ...
        goto __failure;
    }

    m1 = malloc(...);
    if (NULL == m1) {
        ...
        goto __failure;
    }

    m2 = malloc(...);
    if (NULL == m2) {
        ...
        goto __failure;
    }

    r->fd1 = fd1;
    r->fd2 = fd2;
    r->m1 = m1;
    r->m2 = m2;
    return true;

  __failure:
    if (-1 != fd1)
        close(fd1);
    if (-1 != fd2)
        close(fd2);
    if (NULL != m1)
        free(m1);
    if (NULL != m2)
        free(m2);
    return false;
}

I’ve never seen more clear cleanup pattern than this one.