[RFC][libcxx] Fix and maintain the no-exceptions build of libcxx

Hi All,

libcxx is fairly well designed to work in a no-exceptions environment, with

most of the sources diligently using the _LIBCPP_NO_EXCEPTIONS macro. However,

it seems to have bit-rotted a bit and could use some TLC right now. A

no-exceptions variety of libcxx would be quite useful when you want to use all

of libcxx goodness without the overhead of exceptions (especially in embedded

environments). I’m willing to do the necessary source / test updates and

following is my plan/proposal:

[Phase-1: Fix the build, setup build-only build bots]

Currently I cannot build libcxx with -DLIBCXX_ENABLE_EXCEPTIONS=0 due to a small

omission in one of the sources. The following patch fixes this:

http://reviews.llvm.org/D14172

Once we get the reviewed+committed, the next step would be to have some build-

bots setup so that we don’t regress the build. I’ve already spoken to Renato

(copied) and he has kindly agreed to setup an ARM build-bot for this.

@Eric, Dimitri: Would it be possible for you to extend your x86 libcxx

build-bots to include a no-exception build as well?

Initially, these bots will be build-only. Once I get the tests updated (below),

we can enable the test runs too.

[Phase-2: Fix the tests, update build-bots to run them]

Currently quite a few tests fail on the no-exceptions libcxx variant build as

above. It appears that most of the tests assume that libcxx is built with

exceptions enabled. We’ll have to update the tests so that they are aware of

the no-exceptions build as well. I have a work-in-progress patch for this, I

will put it up for review separately once I’m done with it.

Note that it’s not just the tests that need to be updated. For example, take

unordered_map::at(key) definition:

template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>

_Tp& unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::at(const key_type& __k)

{

iterator __i = find(__k);

#ifndef _LIBCPP_NO_EXCEPTIONS

if (__i == end())

throw out_of_range(“unordered_map::at: key not found”);

#endif

return __i->second;

}

Here the behavior is not correct w.r.t no-exceptions use case, __i == end()

should instead call abort(). My local patch includes updates to tests as well

as fixes for omissions like this one.

Once this (quite large) patch gets reviewed+committed, we can enable the testing

stages of the bots, so that we don’t regress the no-exceptions behavior.

[Phase-3: Add more tests]

There are quite a few other places in the source which follow the pattern:

#ifndef _LIBCPP_NO_EXCEPTIONS

if (check_some_bad_stat())

throw some_exception()

#endif

// continues like nothing happened

I don’t think all of those cases are exposed in the current tests, we need to

weed-out these cases and add more tests.

Does that sound like an OK plan? What do others think about supporting the

no-exceptions libcxx variety long-term? Please let me know.

Many thanks.

  • Asiri

This looks great from my side - I'm always encouraging users to
disable EH. It's quite annoying in how much it can impact
optimizations.

Absolutely. Feel free to point new jobs at my builders.

Dmitri

Hi Dmitri,

Thanks for this!

Feel free to point new jobs at my builders.

Did you mean here for me to send you the corresponding build-bot configuration? I'm happy to do that, I'll get familiar with [1] and send you the configuration files (never done that sort of a thing before, might take some time).

Best,

- Asiri

[1] Buildbot 3.5.0 documentation

Yes, please also CC Galina Kistanova.

The buildbot configuration is stored in a repository:
https://llvm.org/svn/llvm-project/zorg/trunk/

Dmitri

[snip]

Note that it's not just the tests that need to be updated. For example,
take

unordered_map::at(key) definition:

template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>

_Tp& unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::at(const key_type&
__k)

{

    iterator __i = find(__k);

#ifndef _LIBCPP_NO_EXCEPTIONS

    if (__i == end())

        throw out_of_range("unordered_map::at: key not found");

#endif

    return __i->second;

}

Here the behavior is not correct w.r.t no-exceptions use case, __i == end()

should instead call abort(). My local patch includes updates to tests as
well

as fixes for omissions like this one.

I find it amusing that you think that there's a "correct behavior" when the
standard specifies that an operation should throw an exception and you have
disabled exceptions.

-- Marshall

I find it amusing that you think that there's a "correct behavior" when the standard specifies
that an operation should throw an exception and you have disabled exceptions.

You got me there!

I think it's OK to be consistent across all the places and call abort(), this is what I've been doing
in my current patch. I will double check this behavior with other compilers that provide similar
functionality.

Thanks.

- Asiri

I also want to point out that if you really want no exceptions, you're
going to have to produce (and link to) a custom dylib; since the stuff in
the dylib *will* throw.

-- Marshall

I also want to point out that if you really want no exceptions, you're
going to have to produce (and link to) a custom dylib; since the stuff in
the dylib *will* throw.

IIUC, what you mean here is that it's not just the libcxx headers that I
need to modify, but also the library code (stuff inside libcxx/src). This
is exactly what I'm currently working on.

I have a patch in review at http://reviews.llvm.org/D14292 which makes it
possible to get this library (.so) to build.

In my follow-up patch (which fixes some test failures on this new libcxx
library build), there are changes to both the headers as well as the core
library sources.

Thanks.

- Asiri

This is possibly something that the standards committee should address. There are lots of situations where you don’t want to enable exceptions, and it would be nice to have an official, standard version of C++ that would work in this situation. Embedded C++ tried, but threw away too much to be useful in practice. Is there a subcommittee looking at this kind of use?

David

The WG21 ISO C++ committee did compile a Technical Report on the needs of embedded systems, with particular attention to the impact on libraries of Exception Handling and Locales. This TR was not "Embedded C++" which was essentially C++ with all of its teeth removed; and instead tried to advise how implementers could construct compliant C++ compilers and libraries that better suited the Embedded Systems environment; sub-setting was considered undesirable as it implied 2 Standards for C++, but a more modular use of and implementation the languages features was considered achievable.

This Technical Report was written over a period of 5 years and we even prototyped libraries based on its findings. It would need to be updated to track developments in the language since, in particular threads and synchronisation abstractions, but most of it is still as valid today as it was 9 years ago.

The document (if you can get access to it) is:

  ISO/IEC TR 18015:2006(E)
  Technical Report on C++ Performance

However, once we completed that TR I have never heard anything about it since. Also, when I went to the NCITS web-site, it was selling for a huge price (~$500) which puts it well out of the reach of normal people.

  Martin O'Riordan - Movidius Ltd.

SG14 are probably interested in this, but I don't think they've produced much in the way of documentation or recommendations yet.

Ben

I believe most of SG14's time (at CppCon and Kona) has been spent
discussing this issue.

- Michael Spencer