This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

exception specifications


Hi,
I'm trying to get egcs g++ to check exception specifications as per the
standard. Some of you might recall a test case of mine that's been added to the
test suite about this (g++.old-deja/g++.eh/spec6.C). In trying to get g++ to do
the right thing, I've got to determine what the right thing is and the language
of the standard seems to be open to some interpretation (yes I'm using the
standard now having shelled out all of $18 to ANSI -- I wish it was
hypertextified though)

15.4/2 says [all decls of a function] "shall have an exception-specifier with
the same set of type-ids." This implies that exception specifiers are sets.
However, 15.4/6 says "an exception specification can include the same type more
than once, and can include classes that are related by inheritance, even though
doing so is redundant." So exceptions specification are not sets in the
mathematical sense, but some kind of fuzzy set with semantics we must infer
from the standard. Unfortunately, I can infer several different semantics!

I should accept `throw(T, U)' and `throw(U, T)' where U and T are unrelated as
the same, but after that it gets a little more complicated.

Here are some cases I'd like confirmation about. I really don't know whether
the answers for (1,2,3 & 4) are yes or no. (5 & 6) are about what I see as
inconsistencies in the language of the standard, it appears to contradict
itself, and I'm unsure of how to resolve that.

1) Are `throw(T)' and `throw(T, T)' the same? Consider templatized exception
specifiers, ie `template<class T> void fn()throw(int, T);' The specialization
`template<> void fn<int>()throw(int)' would be acceptable, which looks
inconsistent.

2) Are `throw(T)' and `throw(T, U)' the same, if U is singly derived from T? U
is clearly redundant in the latter specification, but does that cause it to
match the former?

3) Ditto for T *, U * and for T &, U &.

4) (2) and (3) are really asking if 15.4/6 actually means `according to the
matching semantics of catch clauses'. Then `T cv* cv' and `U cv *cv' all come
into the picture.

5) If you believe we're doing catch clause-like matching, then presumably we
should be ignoring the toplevel cv qualifiers of type-ids in the exception
specifier. Both `throw(int)' and `throw(const int)' can throw the same set of
types. But a cv qualified T is distinct to a non-cv qualified T (3.9.3/1
"cv-qualified or cv-unqualified versions of a type are distinct types"). So
doing that would contradict 15.4/2. Continuing the template function from (1)
would the specialization `template<> void fn<const int>() throw(int)', be
valid, or would `throw(int, const int)' be required?

6) If throw(int) and throw(const int) are different throw specifiers, then
15.4/3 becomes strange. That says a virtual function overrider "shall only
allow exceptions that are allowed by the exception specification of the base
class virtual function". This is looser than (2). I.e, an overriding function
`void U::fn() throw(int)' allows the same exceptions as a base function `void
T::fn() throw(const int)', even though U::fn's exception specifier is not a
subset of T::fn's.

Expert comments will be appreciated.

nathan

-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
      You can up the bandwidth, but you can't up the speed of light      
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]