Exception Specs & Redeclarations


C++0x says that exception specs on redeclarations no longer have to be equivalent, just compatible. It also has the interesting rule that noexcept(false) is compatible with any non-empty throw() spec. This is a bit problematic for Clang's redeclaration checking. Consider:

void f() throw(A);
void f() noexcept(false); // compatible with first decl
void f() throw(B); // compatible with second decl, incompatible with first

Because we always do redecl checking against the latest decl (and if I'm wrong about that, just flip the first two decls), this problem would not be detected unless I adjust the spec of the second decl to match the first when merging. Now, I can do that (I just have to rebuild the function type from scratch), but there's an interesting problem here for the dependent case:

template <bool Throws>
void g() throw(A);
template <bool Nothrow>
void g() noexcept(Nothrow);

Here I can't remove the noexcept spec, because I still need it to determine that g<true> is actually an invalid instantiation, because the prototypes then conflict.

My opinion is that the standard is broken here. noexcept(false) shouldn't be compatible with throw(X) specifiers. That can only lead to chaos.

But if there are important reasons to keep the standard as it is, what would be the best way to implement this?


After looking through the standard history, I now know the rationale behind this compatibility feature. However, the problem I pointed out remains. I am not sure that the benefit (can update header files to avoid deprecation warnings in client code, without having to update source files) outweighs the cost (really messy redecl merging - and I can't believe Clang is the only compiler to suffer from this).

However, assuming that others do not share my opinion here, I think a narrower wording would be beneficial. In particular:
1) A throw(X) specifier *on a definition only* should be compatible with noexcept(false) on declarations. (I realise that would be tricky to get right in Clang.)
and/or 2) The compatibility rule does not apply to function templates. (Or at least, and that's what I'm actually going to implement for now, dependent noexcept specifiers are incompatible with dynamic specifiers.)


Check out


which strikes the problematic compatibility rule. Let's assume the proposed resolution; IIRC, it's what GCC does.

  - Doug

Happy to oblige.


The resolution doesn't address Alistair's example, though. How do throw and noexcept specifiers get composed for implicitly generated definitions?


I think that if any throw() is present, the implicitly generated definition needs to get the dynamic exception specification throw(), since throw() is, in effect, a slightly looser exception specification than noexcept.

  - Doug