Home Dashboard Directory Help
Search

incorrect exception-specifier in VC++ header file causes correct user code not to compile by JiveDadson


Status: 

Closed
 as By Design Help for as By Design


3
0
Sign in
to vote
Type: Bug
ID: 766514
Opened: 10/7/2012 2:13:32 PM
Access Restriction: Public
1
Workaround(s)
view
1
User(s) can reproduce this bug

Description

Derive a class from std::basic_streambuf that has a destructor with no exception-specifier. It will not compile when the /Za flag (disable Microsoft extensions) is used. This causes boost::format to fail to compile with /Za. When one gets that compiler error, it is not easy to track down the cause.

Both C++03 and C++11 specify that the virtual destructor for std::basic_streambuf shall have no exception-specifier (C++03, Section 27.5.1 - C++11, Section 27.6.3). Exception-specifiers are deprecated, and should be removed in any case. The standards also require that any override of a virtual function, including virtual destructors, shall not indicate exception-exclusion that is weaker than the exception-specifier on the base class's member function.

"If a virtual function has an exception-specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall only allow exceptions that are allowed by the exception-specification of the base class virtual function." (C++03 §15.4/3)

Conclusions:

1. /Za in this case does not disable an "extension"; It enables one, and a dangerous one at that. The behavior with /Za is the behavior that is mandated by the C++ standards.

2. The spurious "throw()" exception-specifier in the VC++ header file assures that any class that derives from std::basic_streambuf must use a deprecated feature in order to be correct. Even if it does not define an override for the destructor, the compiler must provide one with a "throw()" specifier. (I have not checked to see if VC++ does so.)

Action indicated - (must be done in this order)

1. Remove exception-specifiers from all header files. They are deprecated, and if used incorrectly, as in the case of std::basic_streambuf, cause conforming programs to fail to compile when the /Za flag is present. Do not replace throw() with noexcept in standard interfaces unless the C++ standard says to.

2. Make the compiler conform with C++03 §15.4/3 regardless of the /Za flag. The standard-conforming behavior is not an "extension." It is necessary.



Details
Sign in to post a comment.
Posted by Microsoft on 11/15/2012 at 9:07 PM
Hi,

Thanks for reporting this issue. I've resolved it as By Design because this behavior is permitted by C++11 (and the current Working Paper, N3485).

N3485 17.6.5.12 [res.on.exception.handling]/4: "Destructor operations defined in the C++ standard library shall not throw exceptions. Every destructor in the C++ standard library shall behave as if it had a non-throwing exception specification."

15.4 [except.spec]/12: "An exception-specification is non-throwing if it is of the form throw(), noexcept, or noexcept(constant-expression) where the constant-expression yields true."

Note that while [res.on.exception.handling]/1 says "An implementation may strengthen the exception-specification for a non-virtual function by adding a non-throwing noexcept-specification.", /4 neither talks about implementation strengthening nor distinguishes virtual destructors from non-virtual destructors. /4 simply says that Standard destructors behave "as if" they are marked with "throw ()", "noexcept", or "noexcept(true)". One way to satisfy an "as if" requirement is to actually do it. Additionally, /4's blanket wording means that class definitions in the Standard don't have to mark their destructors as noexcept, because this is already implied by normative wording.

(As an aside, we're using "throw ()" for the non-Standard optimization semantics that VC grants. At an unspecified time in the future when the compiler implements noexcept, we'll start using that instead.)

Note: Connect doesn't notify me about comments. If you have any further questions, please E-mail me.

Stephan T. Lavavej
Senior Developer - Visual C++ Libraries
stl@microsoft.com
Posted by Microsoft on 10/7/2012 at 9:38 PM
Thanks for your feedback.

We are rerouting this issue to the appropriate group within the Visual Studio Product Team for triage and resolution. These specialized experts will follow-up with your issue.

Posted by Microsoft on 10/7/2012 at 2:51 PM
Thank you for your feedback, we are currently reviewing the issue you have submitted. If this issue is urgent, please contact support directly(http://support.microsoft.com)
Sign in to post a workaround.
Posted by JiveDadson on 10/7/2012 at 2:31 PM
1. Add a deprecated exception-specifier throw() to the derived class's member function. In the case of boost::format, the necessary hack is to alt_stream.hpp, line 65.

or,

2. Remove the deprecated exception-specifier from VC++ include files. There is a macro _NOEXCEPT in yvals.h at line 18.