I perceived that many people think that the throw qualifiers, as described by the standard, are not useful, as an example, I quote the Boost Exception-specification rationale:
Although initially appealing, an exception-specification tends to have consequences that require very careful thought to understand. The biggest problem with exception-specifications is that programmers use them as though they have the effect the programmer would like, instead of the effect they actually have. (thanks to Scott McMurray for this quote) Then, what is the best way to have a reliable description of the exceptions a method can throw? (Reliable in the sense that this description can be checked by the compiler). Static checks for the existing qualifier are not practical, since legacy code not using the qualifier in the new way will not compile. That is what I meant when I said:
> theInlineMethod (void) throw () { throw theException(); }; > this will not even compile...
Jason Merrill wrote:
I doubt that anything like this appears in the standard headers.
(Of course, the method I have write is a toy example). Note that, in this case, the legacy code needs to be _modified_, and cannot be wrapped. Since it is quite impractical, I think that it is necessary to distinguish the qualifier meaning "Not other exceptions than a, b and c can be catched" (i.e., the qualifier as described by the standard) from the qualifier meaning "This method throws no other exceptions than a, b, c". In order to distinguish both qualifiers, a new qualifier can be added. Another option to allow such a distinction is to use the word "static" before the throw qualifier. Of course, the new qualifier (or the word static) will not be used in legacy code. For programs using legacy code, the methods belonging to the legacy code must be wrapped into try/catch blocks (we cannot ensure what the exceptions thrown by such methods are, since the throw qualifier is used in the way described by the standard).
Furthermore, gcc internals currently don't support much in the way of inter-procedural analysis, and none between routines in separate modules.
It is not inter-procedural analysis: you only need the prototypes... If you have a prototype void method() _throw foo; and after that prototype you have a method void wrongMethod() _throw () { instance.method(); }; This method can be signaled as incorrect, since method() may throw a foo exception. However, void rightMethod() _throw () { try {instance.method();} catch(foo) { return; } }; can be signaled as correct, since it is known that the only exception that can be thrown by method() is foo. During the compilation of method(), it is checked that every throw instruction throws only foo exceptions (and that every method invoked --as described by the prototypes-- throws only foo exceptions), or that the other exceptions are enclosed into corresponding try/catch blocks. Hence, note that the analysis can be performed using the code of the method and the previous prototypes.
I'm strongly opposed to adding a new qualifier with slightly different semantics from one already in the language.
I agree that this may cause some confusion. What about the "static throw" qualifier? In addition, in order to ensure that the code with the extension will compile in other compilers, a macro STATIC_THROW can be defined, which expands either to "static throw", if the extension is supported, or to "throw" if it is not. With respect to this,
> In addition, the semantic meaning is not the same: a > throw (a,b,c) qualifier indicates that you are able only to catch the > exceptions a, b and c, and that every other exception will be seen as > std::unexpected. Nevertheless, a > _throw(a,b,c) qualifier should indicate that the only exceptions that > can arise are a, b and c. But in both cases, the only exceptions that can leave the function are a, b and c. I don't see what your extension would add that wouldn't also be provided by -Wexception-specs.
Yes, the only exceptions that can leave the function are a, b and c, but, in addition to the exceptions, you may get a nasty call to unexpected()... The idea is that if you can write int main() _throw () { yourCode(); } and your code compile, you will not have unexpected exceptions thrown during the execution of your program. Moreover, you have better control of the exceptions that can be thrown in every point of the execution... All the best, Sergio