diff mbox

Add const char* constructors for exception classes in <stdexcept>

Message ID 1387466908.2455.355.camel@yam-132-YW-E178-FTW
State New
Headers show

Commit Message

Oleg Endo Dec. 19, 2013, 3:28 p.m. UTC
On Thu, 2013-12-19 at 01:19 +0000, Jonathan Wakely wrote:
> On 19 December 2013 00:10, Oleg Endo wrote:
> > Hello,
> >
> > When writing code such as
> > ...
> >   throw std::logic_error ("cold coffee");
> > ...
> > currently the construction of std::string happens in the code that
> > throws the exception, which results in code bloat.  Implementing the
> > const char* constructors as defined by C++11 fixes the issue.
> > I'm not sure whether the #if __cplusplus >= 201103L checks are required.
> > C++98 code could also benefit from the overloads.
> 
> I think there was some good reason we haven't added these yet, but I
> can't remember it.
> 
> > Tested with 'make all' and 'make install', writing a hello world and
> > checking the asm output.
> 
> For all patches we need to know that the libstdc++ testsuite passes too.

Right, I should have done that in the first place.  The patch was
broken.  Sorry for the noise.

Files in libstdc++-v3/src/c++98/ seem to be never compiled with C++11.
Thus I can think of two options:
1) Add const char* ctors for C++98 and C++11.
2) Add #ifdef'ed declarations to libstdc++-v3/include/std/stdexcept and
add a new file libstdc++-v3/src/c++11/stdexcept.cc with the
implementations.

The attached patch does 1).

Tested with 'make all' and 'make check-target-libstdc++-v3' on
i686-pc-linux-gnu, configured with:
../gcc-trunk2/configure --prefix=/<...> --enable-languages=c,c++

		=== libstdc++ Summary ===

# of expected passes		5142
# of unexpected failures	2
# of expected failures		34
# of unsupported tests		476

Cheers,
Oleg

libstdc++-v3/ChangeLog:
        * include/std/stdexcept (logic_error, domain_error, 
        invalid_argument, length_error, out_of_range, runtime_error, 
        range_error, overflow_error, underflow_error): Declare const 
        char* constructors.
        * src/c++98/stdexcept.cc (logic_error, domain_error, 
        invalid_argument, length_error, out_of_range, runtime_error, 
        range_error, overflow_error, underflow_error): Implement them.
	* config/abi/pre/gnu.ver ( _ZNSt11logic_errorC[12]EPKc, 
	_ZNSt12domain_errorC[12]EPKc, _ZNSt16invalid_argumentC[12]EPKc, 
	_ZNSt12length_errorC[12]EPKc, _ZNSt12out_of_rangeC[12]EPKc, 
	_ZNSt13runtime_errorC[12]EPKc, _ZNSt11range_errorC[12]EPKc, 
	_ZNSt14overflow_errorC[12]EPKc, _ZNSt15underflow_errorC[12]EPKc):
	Add new exports.
	* doc/xml/manual/status_cxx2011.xml: Update.

Comments

Oleg Endo Jan. 26, 2014, 2:15 p.m. UTC | #1
Ping.
The patch in question is here:
http://gcc.gnu.org/ml/gcc-patches/2013-12/msg01688.html


On Thu, 2013-12-19 at 16:28 +0100, Oleg Endo wrote:
> On Thu, 2013-12-19 at 01:19 +0000, Jonathan Wakely wrote:
> > On 19 December 2013 00:10, Oleg Endo wrote:
> > > Hello,
> > >
> > > When writing code such as
> > > ...
> > >   throw std::logic_error ("cold coffee");
> > > ...
> > > currently the construction of std::string happens in the code that
> > > throws the exception, which results in code bloat.  Implementing the
> > > const char* constructors as defined by C++11 fixes the issue.
> > > I'm not sure whether the #if __cplusplus >= 201103L checks are required.
> > > C++98 code could also benefit from the overloads.
> > 
> > I think there was some good reason we haven't added these yet, but I
> > can't remember it.
> > 
> > > Tested with 'make all' and 'make install', writing a hello world and
> > > checking the asm output.
> > 
> > For all patches we need to know that the libstdc++ testsuite passes too.
> 
> Right, I should have done that in the first place.  The patch was
> broken.  Sorry for the noise.
> 
> Files in libstdc++-v3/src/c++98/ seem to be never compiled with C++11.
> Thus I can think of two options:
> 1) Add const char* ctors for C++98 and C++11.
> 2) Add #ifdef'ed declarations to libstdc++-v3/include/std/stdexcept and
> add a new file libstdc++-v3/src/c++11/stdexcept.cc with the
> implementations.
> 
> The attached patch does 1).
> 
> Tested with 'make all' and 'make check-target-libstdc++-v3' on
> i686-pc-linux-gnu, configured with:
> ../gcc-trunk2/configure --prefix=/<...> --enable-languages=c,c++
> 
> 		=== libstdc++ Summary ===
> 
> # of expected passes		5142
> # of unexpected failures	2
> # of expected failures		34
> # of unsupported tests		476
> 
> Cheers,
> Oleg
> 
> libstdc++-v3/ChangeLog:
>         * include/std/stdexcept (logic_error, domain_error, 
>         invalid_argument, length_error, out_of_range, runtime_error, 
>         range_error, overflow_error, underflow_error): Declare const 
>         char* constructors.
>         * src/c++98/stdexcept.cc (logic_error, domain_error, 
>         invalid_argument, length_error, out_of_range, runtime_error, 
>         range_error, overflow_error, underflow_error): Implement them.
> 	* config/abi/pre/gnu.ver ( _ZNSt11logic_errorC[12]EPKc, 
> 	_ZNSt12domain_errorC[12]EPKc, _ZNSt16invalid_argumentC[12]EPKc, 
> 	_ZNSt12length_errorC[12]EPKc, _ZNSt12out_of_rangeC[12]EPKc, 
> 	_ZNSt13runtime_errorC[12]EPKc, _ZNSt11range_errorC[12]EPKc, 
> 	_ZNSt14overflow_errorC[12]EPKc, _ZNSt15underflow_errorC[12]EPKc):
> 	Add new exports.
> 	* doc/xml/manual/status_cxx2011.xml: Update.
Jonathan Wakely Jan. 29, 2014, 3:21 p.m. UTC | #2
On 26/01/14 15:15 +0100, Oleg Endo wrote:
>> Files in libstdc++-v3/src/c++98/ seem to be never compiled with C++11.
>> Thus I can think of two options:
>> 1) Add const char* ctors for C++98 and C++11.
>> 2) Add #ifdef'ed declarations to libstdc++-v3/include/std/stdexcept and
>> add a new file libstdc++-v3/src/c++11/stdexcept.cc with the
>> implementations.

3) Move stdexcept.cc from src/c++98 to src/c++11
4) Define the functions inline using forwarding constructors, which
    means we don't need new exports.

>> The attached patch does 1).

I don't think we want the constructors in C++03 mode though, it could
break some valid programs e.g. a custom string type with implicit
conversion to const char* and std::string can be passed to an exception
constructor in C++03, but adding the overloads would make it
ambiguous.

I think I prefer option 4, it avoids adding new exports during Stage 3
(although the patch was initially posted during Stage 1, it is now
quite late to add new exports, which is not your fault but still a
concern.)
Oleg Endo Jan. 29, 2014, 9:17 p.m. UTC | #3
On Wed, 2014-01-29 at 15:21 +0000, Jonathan Wakely wrote:
> On 26/01/14 15:15 +0100, Oleg Endo wrote:
> >> Files in libstdc++-v3/src/c++98/ seem to be never compiled with C++11.
> >> Thus I can think of two options:
> >> 1) Add const char* ctors for C++98 and C++11.
> >> 2) Add #ifdef'ed declarations to libstdc++-v3/include/std/stdexcept and
> >> add a new file libstdc++-v3/src/c++11/stdexcept.cc with the
> >> implementations.
> 
> 3) Move stdexcept.cc from src/c++98 to src/c++11
> 4) Define the functions inline using forwarding constructors, which
>     means we don't need new exports.
> 
> >> The attached patch does 1).
> 
> I don't think we want the constructors in C++03 mode though, it could
> break some valid programs e.g. a custom string type with implicit
> conversion to const char* and std::string can be passed to an exception
> constructor in C++03, but adding the overloads would make it
> ambiguous.

Good point.

> 
> I think I prefer option 4, it avoids adding new exports during Stage 3
> (although the patch was initially posted during Stage 1, it is now
> quite late to add new exports, which is not your fault but still a
> concern.)

My original intention was to eliminate code bloat when doing something
like  throw std::logic_error ("cold coffee");
If the const char* overloads are inlined it will emit code to construct
an std::string from const char* in user code where the exception is
being constructed over and over again.  The idea was to move that code
into the std library.
BTW the original patch was posted during Stage 3 (19.12.2013).  I don't
mind waiting until Stage 1 if adding exports now is a problem.

Cheers,
Oleg
Jonathan Wakely Jan. 29, 2014, 9:38 p.m. UTC | #4
On 29 January 2014 21:17, Oleg Endo wrote:
> My original intention was to eliminate code bloat when doing something
> like  throw std::logic_error ("cold coffee");
> If the const char* overloads are inlined it will emit code to construct
> an std::string from const char* in user code where the exception is
> being constructed over and over again.  The idea was to move that code
> into the std library.

That's exactly what happens today with the constructors that only take
a std::string, so it wouldn't be any worse than what we have now,
would it?

> BTW the original patch was posted during Stage 3 (19.12.2013).  I don't
> mind waiting until Stage 1 if adding exports now is a problem.

OK, let's wait and decide how we want to do it properly in stage 1.

(If we're going to make various changes that impact the ABI during the
next stage 1 we might even want to consider changing the
std::exception base class to store something like a
std::shared_ptr<std::string> so that copying an exception object will
never throw an exception, which is something I've been thinking about
recently.)
Oleg Endo Jan. 29, 2014, 10:45 p.m. UTC | #5
On Wed, 2014-01-29 at 21:38 +0000, Jonathan Wakely wrote:
> On 29 January 2014 21:17, Oleg Endo wrote:
> > My original intention was to eliminate code bloat when doing something
> > like  throw std::logic_error ("cold coffee");
> > If the const char* overloads are inlined it will emit code to construct
> > an std::string from const char* in user code where the exception is
> > being constructed over and over again.  The idea was to move that code
> > into the std library.
> 
> That's exactly what happens today with the constructors that only take
> a std::string, so it wouldn't be any worse than what we have now,
> would it?

Sorry, I'm not sure I understand your question.  Maybe you meant "any
better than what we have"?  Anyway, I've attached two outputs that show
what I mean.  The version with the const char* ctor overloads
implemented in the library is significantly shorter in the throwing path
(5x function call vs. 7x function call + other inlined std::string ctor
code).

> 
> > BTW the original patch was posted during Stage 3 (19.12.2013).  I don't
> > mind waiting until Stage 1 if adding exports now is a problem.
> 
> OK, let's wait and decide how we want to do it properly in stage 1.

Sure.  Actually I've missed some of the other exception types in
system_error, which should be added, too.  That would eliminate the
   TODO: Add const char* ctors to all exceptions.

I'd also propose moving the system_error ctor implementations into the
library as well, for the same reasons as above.

> 
> (If we're going to make various changes that impact the ABI during the
> next stage 1 we might even want to consider changing the
> std::exception base class to store something like a
> std::shared_ptr<std::string> so that copying an exception object will
> never throw an exception, which is something I've been thinking about
> recently.)

Wouldn't using std::shared_ptr<std::string> introduce an additional heap
allocation when creating the exception, though?
How about storing the exception message in a plain zero terminated
string instead?  This would require only one heap allocation if the
string data is prefixed with a refcount variable.  Basically,
std::make_shared re-invented because it doesn't work with arrays.
Or maybe implement N3640 + N3641 first (even if for library internal use
only as a start)...

Cheers,
Oleg
Oleg Endo May 1, 2014, 4:18 p.m. UTC | #6
Jonathan,

now that we're in stage 1 again, I'd like to revive the issue below.  Do
you have any particular plans?  How should we proceed?

Cheers,
Oleg

On Wed, 2014-01-29 at 23:45 +0100, Oleg Endo wrote:
> On Wed, 2014-01-29 at 21:38 +0000, Jonathan Wakely wrote:
> > On 29 January 2014 21:17, Oleg Endo wrote:
> > > My original intention was to eliminate code bloat when doing something
> > > like  throw std::logic_error ("cold coffee");
> > > If the const char* overloads are inlined it will emit code to construct
> > > an std::string from const char* in user code where the exception is
> > > being constructed over and over again.  The idea was to move that code
> > > into the std library.
> > 
> > That's exactly what happens today with the constructors that only take
> > a std::string, so it wouldn't be any worse than what we have now,
> > would it?
> 
> Sorry, I'm not sure I understand your question.  Maybe you meant "any
> better than what we have"?  Anyway, I've attached two outputs that show
> what I mean.  The version with the const char* ctor overloads
> implemented in the library is significantly shorter in the throwing path
> (5x function call vs. 7x function call + other inlined std::string ctor
> code).
> 
> > 
> > > BTW the original patch was posted during Stage 3 (19.12.2013).  I don't
> > > mind waiting until Stage 1 if adding exports now is a problem.
> > 
> > OK, let's wait and decide how we want to do it properly in stage 1.
> 
> Sure.  Actually I've missed some of the other exception types in
> system_error, which should be added, too.  That would eliminate the
>    TODO: Add const char* ctors to all exceptions.
> 
> I'd also propose moving the system_error ctor implementations into the
> library as well, for the same reasons as above.
> 
> > 
> > (If we're going to make various changes that impact the ABI during the
> > next stage 1 we might even want to consider changing the
> > std::exception base class to store something like a
> > std::shared_ptr<std::string> so that copying an exception object will
> > never throw an exception, which is something I've been thinking about
> > recently.)
> 
> Wouldn't using std::shared_ptr<std::string> introduce an additional heap
> allocation when creating the exception, though?
> How about storing the exception message in a plain zero terminated
> string instead?  This would require only one heap allocation if the
> string data is prefixed with a refcount variable.  Basically,
> std::make_shared re-invented because it doesn't work with arrays.
> Or maybe implement N3640 + N3641 first (even if for library internal use
> only as a start)...
> 
> Cheers,
> Oleg
Jonathan Wakely May 2, 2014, 3:57 p.m. UTC | #7
On 1 May 2014 17:18, Oleg Endo wrote:
> Jonathan,
>
> now that we're in stage 1 again, I'd like to revive the issue below.  Do
> you have any particular plans?  How should we proceed?

Hi Oleg, sorry for letting the thread die in January.

We will definitely want to deal with the missing constructors in
<stdexcept> during stage 1, but I'm not sure exactly when :-)

I'll come back to this next week - ping me if you don't hear from me again!
Oleg Endo May 11, 2014, 7:01 p.m. UTC | #8
On 02 May 2014, at 17:57, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:

> On 1 May 2014 17:18, Oleg Endo wrote:
>> Jonathan,
>> 
>> now that we're in stage 1 again, I'd like to revive the issue below.  Do
>> you have any particular plans?  How should we proceed?
> 
> Hi Oleg, sorry for letting the thread die in January.
> 
> We will definitely want to deal with the missing constructors in
> <stdexcept> during stage 1, but I'm not sure exactly when :-)
> 
> I'll come back to this next week - ping me if you don't hear from me again!

And here I am, pinging... :)

If it helps, I could brush up the patch that I submitted here:
http://gcc.gnu.org/ml/gcc-patches/2013-12/msg01688.html

The thing you've mentioned regarding exception message string storage in
http://gcc.gnu.org/ml/gcc-patches/2014-01/msg01925.html
is a different issue I think.

Cheers,
Oleg
diff mbox

Patch

Index: libstdc++-v3/config/abi/pre/gnu.ver
===================================================================
--- libstdc++-v3/config/abi/pre/gnu.ver	(revision 206101)
+++ libstdc++-v3/config/abi/pre/gnu.ver	(working copy)
@@ -1371,6 +1371,33 @@ 
     # std::regex_error::regex_error(std::regex_constants::error_type)
     _ZNSt11regex_errorC[01]ENSt15regex_constants10error_typeE;
 
+    # std::logic_error::logic_error(const char*)
+    _ZNSt11logic_errorC[12]EPKc;
+
+    # std::domain_error::domain_error(const char*)
+    _ZNSt12domain_errorC[12]EPKc;
+
+    # std::invalid_argument::invalid_argument(const char*)
+    _ZNSt16invalid_argumentC[12]EPKc;
+
+    # std::length_error::length_error(const char*)
+    _ZNSt12length_errorC[12]EPKc;
+
+    # std::out_of_range::out_of_range(const char*)
+    _ZNSt12out_of_rangeC[12]EPKc;
+
+    # std::runtime_error::runtime_error(const char*)
+    _ZNSt13runtime_errorC[12]EPKc;
+
+    # std::range_error::range_error(const char*)
+    _ZNSt11range_errorC[12]EPKc;
+
+    # std::overflow_error::overflow_error(const char*)
+    _ZNSt14overflow_errorC[12]EPKc;
+
+    # std::underflow_error::underflow_error(const char*)
+    _ZNSt15underflow_errorC[12]EPKc;
+
 } GLIBCXX_3.4.19;
 
 # Symbols in the support library (libsupc++) have their own tag.
Index: libstdc++-v3/src/c++98/stdexcept.cc
===================================================================
--- libstdc++-v3/src/c++98/stdexcept.cc	(revision 206101)
+++ libstdc++-v3/src/c++98/stdexcept.cc	(working copy)
@@ -36,6 +36,9 @@ 
   logic_error::logic_error(const string& __arg)
   : exception(), _M_msg(__arg) { }
 
+  logic_error::logic_error(const char* __arg)
+  : exception(), _M_msg(__arg) { }
+
   logic_error::~logic_error() _GLIBCXX_USE_NOEXCEPT { }
 
   const char*
@@ -45,26 +48,41 @@ 
   domain_error::domain_error(const string& __arg)
   : logic_error(__arg) { }
 
+  domain_error::domain_error(const char* __arg)
+  : logic_error(__arg) { }
+
   domain_error::~domain_error() _GLIBCXX_USE_NOEXCEPT { }
 
   invalid_argument::invalid_argument(const string& __arg)
   : logic_error(__arg) { }
 
+  invalid_argument::invalid_argument(const char* __arg)
+  : logic_error(__arg) { }
+
   invalid_argument::~invalid_argument() _GLIBCXX_USE_NOEXCEPT { }
 
   length_error::length_error(const string& __arg)
   : logic_error(__arg) { }
 
+  length_error::length_error(const char* __arg)
+  : logic_error(__arg) { }
+
   length_error::~length_error() _GLIBCXX_USE_NOEXCEPT { }
 
   out_of_range::out_of_range(const string& __arg)
   : logic_error(__arg) { }
 
+  out_of_range::out_of_range(const char* __arg)
+  : logic_error(__arg) { }
+
   out_of_range::~out_of_range() _GLIBCXX_USE_NOEXCEPT { }
 
   runtime_error::runtime_error(const string& __arg)
   : exception(), _M_msg(__arg) { }
 
+  runtime_error::runtime_error(const char* __arg)
+  : exception(), _M_msg(__arg) { }
+
   runtime_error::~runtime_error() _GLIBCXX_USE_NOEXCEPT { }
 
   const char*
@@ -74,16 +92,25 @@ 
   range_error::range_error(const string& __arg)
   : runtime_error(__arg) { }
 
+  range_error::range_error(const char* __arg)
+  : runtime_error(__arg) { }
+
   range_error::~range_error() _GLIBCXX_USE_NOEXCEPT { }
 
   overflow_error::overflow_error(const string& __arg)
   : runtime_error(__arg) { }
 
+  overflow_error::overflow_error(const char* __arg)
+  : runtime_error(__arg) { }
+
   overflow_error::~overflow_error() _GLIBCXX_USE_NOEXCEPT { }
 
   underflow_error::underflow_error(const string& __arg)
   : runtime_error(__arg) { }
 
+  underflow_error::underflow_error(const char* __arg)
+  : runtime_error(__arg) { }
+
   underflow_error::~underflow_error() _GLIBCXX_USE_NOEXCEPT { }
 
 _GLIBCXX_END_NAMESPACE_VERSION
Index: libstdc++-v3/doc/xml/manual/status_cxx2011.xml
===================================================================
--- libstdc++-v3/doc/xml/manual/status_cxx2011.xml	(revision 206101)
+++ libstdc++-v3/doc/xml/manual/status_cxx2011.xml	(working copy)
@@ -270,11 +270,10 @@ 
       <entry/>
     </row>
     <row>
-      <?dbhtml bgcolor="#B0B0B0" ?>
       <entry>19.2</entry>
       <entry>Exception classes</entry>
-      <entry>Partial</entry>
-      <entry>Missing <code>const char*</code> constructors.</entry>
+      <entry>Y</entry>
+      <entry/>
     </row>
     <row>
       <entry>19.3</entry>
Index: libstdc++-v3/include/std/stdexcept
===================================================================
--- libstdc++-v3/include/std/stdexcept	(revision 206101)
+++ libstdc++-v3/include/std/stdexcept	(working copy)
@@ -58,9 +58,12 @@ 
 
   public:
     /** Takes a character string describing the error.  */
-    explicit 
+    explicit
     logic_error(const string& __arg);
 
+    explicit
+    logic_error(const char* __arg);
+
     virtual ~logic_error() _GLIBCXX_USE_NOEXCEPT;
 
     /** Returns a C-style character string describing the general cause of
@@ -75,6 +78,8 @@ 
   {
   public:
     explicit domain_error(const string& __arg);
+    explicit domain_error(const char* __arg);
+
     virtual ~domain_error() _GLIBCXX_USE_NOEXCEPT;
   };
 
@@ -83,6 +88,8 @@ 
   {
   public:
     explicit invalid_argument(const string& __arg);
+    explicit invalid_argument(const char* __arg);
+
     virtual ~invalid_argument() _GLIBCXX_USE_NOEXCEPT;
   };
 
@@ -92,6 +99,8 @@ 
   {
   public:
     explicit length_error(const string& __arg);
+    explicit length_error(const char* __arg);
+
     virtual ~length_error() _GLIBCXX_USE_NOEXCEPT;
   };
 
@@ -101,6 +110,8 @@ 
   {
   public:
     explicit out_of_range(const string& __arg);
+    explicit out_of_range(const char* __arg);
+
     virtual ~out_of_range() _GLIBCXX_USE_NOEXCEPT;
   };
 
@@ -115,9 +126,12 @@ 
 
   public:
     /** Takes a character string describing the error.  */
-    explicit 
+    explicit
     runtime_error(const string& __arg);
 
+    explicit
+    runtime_error(const char* __arg);
+
     virtual ~runtime_error() _GLIBCXX_USE_NOEXCEPT;
 
     /** Returns a C-style character string describing the general cause of
@@ -131,6 +145,8 @@ 
   {
   public:
     explicit range_error(const string& __arg);
+    explicit range_error(const char* __arg);
+
     virtual ~range_error() _GLIBCXX_USE_NOEXCEPT;
   };
 
@@ -139,6 +155,8 @@ 
   {
   public:
     explicit overflow_error(const string& __arg);
+    explicit overflow_error(const char* __arg);
+
     virtual ~overflow_error() _GLIBCXX_USE_NOEXCEPT;
   };
 
@@ -147,6 +165,8 @@ 
   {
   public:
     explicit underflow_error(const string& __arg);
+    explicit underflow_error(const char* __arg);
+
     virtual ~underflow_error() _GLIBCXX_USE_NOEXCEPT;
   };