Topic: Exception specification and reference types


Author: Greg Herlihy <greghe@mac.com>
Date: Mon, 19 Nov 2007 17:54:17 CST
Raw View
On Nov 16, 9:14 am, andreytarasev...@hotmail.com (Andrey Tarasevich)
wrote:

>    struct A {
>      struct AA {};
>      virtual void foo() throw(AA&);
>    };
>
>    struct B : A {
>      struct BB : AA {};
>      virtual void foo() throw(AA&, BB&);
>    };
>
> According to my understanding, using reference types in the exception
> specification should be basically equivalent to using corresponding
> non-reference types. Also, when it comes to determining whether the
> specification of a virtual function is extended in the derived class, reference
> types could be thought of as corresponding pointer types.

But a reference type is not a pointer type - so the rules that apply
to pointer types do not automatically extend to reference types.

> However, Comeau online refuses to compile the second example, complaining that
> 'B::foo's exception specification is more loose than that of 'A::foo'.

There are basically three types of exception specifications (involving
base and derived classes) to consider. And the question in each case
is whether a base claas exception specification "matches" a thrown
exception of a derived type. (if it does, then adding the derived type
to the exception specification would be legal - since the derived
type  was already a match).

So, the three questions are:

   1. Does an AA exception specification match a BB type exception?
   2. Does "  AA*   "            "         "   " BB* "       "    ?
   3. Does "  AA&   "            "         "   " BB& "       "    ?

The answers are:

   #1. Yes - by the second bullet point in    15.3/3 : AA is an
unambiguous base class of BB.
   #2  Yes - by the third bullet point: BB* converts to AA* implicitly
   #3. No. The first two bullets do not applyy because AA& is neither
the same type as - nor a base class of - BB& (just as AA* is not a
base class of BB*). And since neither type is a pointer type, the
third bullet point does not apply either - and there are no other
bullet points left by which an AA& exception specification would match
a BB& exception object.

Note that this conclusion does not mean that an AA& exception
specification prohibits BB& exceptions from being thrown. Because an
instance of a derived class is also an instance of its base class, a
BB& object may be thrown from a function with an AA& exception
specification - even if the AA& exception specification does not
"match" a BB& exception object.

Greg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Andrey Tarasevich <andreytarasevich@hotmail.com>
Date: Tue, 20 Nov 2007 15:56:05 CST
Raw View
Greg Herlihy wrote:
> ...
>>    struct A {
>>      struct AA {};
>>      virtual void foo() throw(AA&);
>>    };
>>
>>    struct B : A {
>>      struct BB : AA {};
>>      virtual void foo() throw(AA&, BB&);
>>    };
>>
>> According to my understanding, using reference types in the exception
>> specification should be basically equivalent to using corresponding
>> non-reference types. Also, when it comes to determining whether the
>> specification of a virtual function is extended in the derived class, reference
>> types could be thought of as corresponding pointer types.
>
> But a reference type is not a pointer type - so the rules that apply
> to pointer types do not automatically extend to reference types.

I'm not saying that reference type is a pointer type. I'm just saying
that the TC1 rules for type matching in exception specifications seem to
"synchronize" the rules for pointers and references well enough to make
them behave in similar fashion.

>> However, Comeau online refuses to compile the second example, complaining that
>> 'B::foo's exception specification is more loose than that of 'A::foo'.
>
> There are basically three types of exception specifications (involving
> base and derived classes) to consider. And the question in each case
> is whether a base claas exception specification "matches" a thrown
> exception of a derived type. (if it does, then adding the derived type
> to the exception specification would be legal - since the derived
> type  was already a match).

Yes, that's what I'm talking about.

> So, the three questions are:
>
>    1. Does an AA exception specification match a BB type exception?
>    2. Does "  AA*   "            "         "   " BB* "       "    ?
>    3. Does "  AA&   "            "         "   " BB& "       "    ?
>
> The answers are:
>
>    #1. Yes - by the second bullet point in    15.3/3 : AA is an
> unambiguous base class of BB.

Exactly.

>    #2  Yes - by the third bullet point: BB* converts to AA* implicitly

Agreed.

>    #3. No. The first two bullets do not applyy because AA& is neither
> the same type as - nor a base class of - BB& (just as AA* is not a
> base class of BB*).

Err... I disagree. The second bullet works perfectly fine here. The type
of the throw expression is the type of the temporary object initialized
by the throw expression. When 15.3/3 says "... with an object of type E
." it actually refers to that temporary object (it can't be reference
type, of course, since references are not objects). There are no throw
expressions that throw reference types. A "syntactic" attempt to throw
'T&' actually throws 'T'. And it 'T', not 'T&', that will be used by
15.3/3 in order to decide which handler will catch the exception and, in
post-TC1 C++, whether it matches the exception specification. Using type
'BB&' as the above type 'E' in 15.3/3 makes absolutely no sense. For
this reason, 'throw(AA&, BB&)' specification doesn't allow any extra
exception types to be thrown in addition to the ones allowed
'throw(AA&)' and, therefore, should satisfy the requirements of 15.4/3.

As an extra experiment, on can try the following version

   struct A {
     struct AA {};
     virtual void foo() throw(AA&);
   };

   struct B : A {
     struct BB : AA {};
     virtual void foo() throw(AA&, BB);
   };

Obviously, no new exception types are allowed by the 'B::foo' exception
specification, but Comeau still complains. Even though the second bullet
from 15.3/3 clearly applies here.

> Note that this conclusion does not mean that an AA& exception
> specification prohibits BB& exceptions from being thrown. Because an
> instance of a derived class is also an instance of its base class, a
> BB& object may be thrown from a function with an AA& exception
> specification - even if the AA& exception specification does not
> "match" a BB& exception object.

You seem to be contradicting yourself here. The central issue here is
whether the 'B::foo's exception specification is wider (looser) than
'A::foo's exception specification. This is how the requirement for
virtual functions is formulated in 15.4/3. Note, it is not formulated in
therms of literal types enumerated in 'throw(...)', but rather uses a
notably higher-level approach: it is stated it terms of the _allowed_
exception types. Unless you can demonstrate that there's an exception
type that can "fly through" 'throw(AA&, BB&)' and still be "blocked" by
'throw(AA&)', the requirement of 15.4/3 is met here and the code should
compile.

Franlkly, I come to the conclusion that the current implementation of
Comeau compiler (I'm talking about the online version) simply ignores
the updated version of 15.4/7 and continues to stick to the pre-TC1
specification in this regard. This would explain its behavior, since
under the old 15.4/7 the above would indeed be ill-formed.

--
Best regards,
Andrey Tarasevich

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: andreytarasevich@hotmail.com (Andrey Tarasevich)
Date: Fri, 16 Nov 2007 17:14:33 GMT
Raw View
Hello

Consider the following code fragment

   struct A {
     struct AA {};
     virtual void foo() throw(AA);
   };

   struct B : A {
     struct BB : AA {};
     virtual void foo() throw(AA, BB);
   };

In this case the declaration of 'B::foo' is well-formed (satisfies 15.4/3)
because the extra entry in its exception specification doesn't really extend the
extension specification of 'A::foo' (noting that 'B::BB' is derived from
'A::AA'). But what about the following [similar] code fragment

   struct A {
     struct AA {};
     virtual void foo() throw(AA&);
   };

   struct B : A {
     struct BB : AA {};
     virtual void foo() throw(AA&, BB&);
   };

?

(Note: IIRC, reference types in exception specifications couldn't be
meaningfully used in pre-TC1 C++ under strict formal interpretation of 15.4/7.
The changes introduced for DR#126 gave them some meaning).

According to my understanding, using reference types in the exception
specification should be basically equivalent to using corresponding
non-reference types. Also, when it comes to determining whether the
specification of a virtual function is extended in the derived class, reference
types could be thought of as corresponding pointer types.

However, Comeau online refuses to compile the second example, complaining that
'B::foo's exception specification is more loose than that of 'A::foo'.
Meanwhile, as one would expect, the third version of the fragment, with pointers
in place of references

   struct A {
     struct AA {};
     virtual void foo() throw(AA*);
   };

   struct B : A {
     struct BB : AA {};
     virtual void foo() throw(AA*, BB*);
   };

compiles fine.

Is there something I'm missing about using pointer types in exception
specifications that justifies the Comeau's behavior on the second version of the
code?

--
Best regards,
Andrey Tarasevich

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]