On Wednesday, 13 May 2026 at 01:44:22 UTC, Steven Schveighoffer wrote:
I think I can get a small reproducible example that does not need all the extra complication. But need some time to narrow it down.


This is extremely surprising, that this has never been seen before.

I have confirmed that this is a long standing issue, back at least as far as version 2.068 (as far back as run.dlang.io has).

I can confirm this is a problem on all OSes and architectures (the minimal example shows the problem on macos ldc2 as well).

The pattern is that if you recurse on a non-template function, where the recursion throws an exception, and you try to catch that exception in the function, it does not emit the catch clauses unless they are Throwable (and presumably Error).

Reproduction case:

```d
import std.stdio;

void poison() {}

void foo(bool shouldthrow)
{
    if(shouldthrow) {
        throw new Exception("here");
    }
    try {
        // poison();
        foo(true);
    }
    catch(Exception e) {
        writeln("caught exception");
    }
    catch(Throwable t) {
        writeln("caught throwable");
    }
}

void main()
{
    foo(false);
}
```

This prints "caught throwable" in all versions of dmd back to 2.068 (and presumably earlier), and also on ldc. if the call to `poison` is uncommented, then it prints "caught exception". So it's a front-end semantic bug.

My hypothesis is that the compiler has temporarily marked `foo` as `nothrow` before finishing semantic, and therefore when it recurses, it thinks this cannot possibly throw an `Exception`. Therefore, it elides the catch clause for `Exception`.

Thank you for persisting on this, I would not have expected this outcome.

I will file a bug report on it.

-Steve

Reply via email to