While this works:
try
foo();
catch {
fwritefln(stderr, "Can't do that");
}
This doesn't:
try
foo();
catch
fwritefln(stderr, "Can't do that");
Giving the errors:
found 'fwritefln' when expecting '('
basic type expected, not (
And so on.
IMHO, the compiler should parse the second piece of code in the same manner as
the first piece, since there are (as in the first example) no brackets after
the catch keyword defining an object to catch. Right?
I'm using GDC 0.24 on Linux, and i don't know if this is also happening in DMD.

IMHO, the compiler should parse the second piece of code in the same
manner as the first piece, since there are (as in the first example) no
brackets after the catch keyword defining an object to catch. Right?

I've thought about this as well, and I think it's because allowing a
statement without braces there would introduce an ambiguity:
try
foo();
catch
(bar).baz();
Parenthesized expressions are allowed to come at the beginning of
expressions, and therefore at the beginning of statements. So the compiler
would parse the catch block in this case as "catch(bar", thinking that "bar"
is the type of a catch specialization, and then expect an identifier after
"bar".
Thankfully there's no ambiguity when you _do_ specify an exception
specialization:
try
foo();
catch(Object ex)
fwritefln(stderr, "An error happened. %s", ex.toString());

IMHO, the compiler should parse the second piece of code in the same
manner as the first piece, since there are (as in the first example) no
brackets after the catch keyword defining an object to catch. Right?

I've thought about this as well, and I think it's because allowing a
statement without braces there would introduce an ambiguity:
try
foo();
catch
(bar).baz();
Parenthesized expressions are allowed to come at the beginning of
expressions, and therefore at the beginning of statements. So the compiler
would parse the catch block in this case as "catch(bar", thinking that "bar"
is the type of a catch specialization, and then expect an identifier after
"bar".

Well, that makes sense.
But i also tried
catch()
foo();
and it errored, even though this wouldn't be ambigous

I don't think this is an ambiguity. After all, catch(bar) is not a valid
catch statement anyway, since the type is woefully missing.

I'm not saying catch(bar) _is_ valid, I'm saying that the compiler goes "oo,
catch! then lparen! there must be a type and then an identifier next."
Then it tries to parse a type and an identifier, but that fails.
I suppose it's not an ambiguity in the simple sense (two possible valid
parse trees), but more like.. given the sequence of tokens, there's no way
for the compiler to know what's next. It's ambiguous, but one parse tree is
valid and the other is not. Having the compiler explicitly deal with these
kinds of nasty issues ends up with a far more complex (and slower) compiler
than simply having the grammar disallow them in the first place, like what's
been done here.