Advancing libc++ Beyond C++03

Hello,

libc++ claims to support GCC with C++03 (“G++03”), and this is a problem for our users.

Our C++03 users are all using Clang. They must be. Less than 9% of the C++03 tests pass with GCC [1][2]. No non-trivial C++ program could work.

Attempting to support G++03 impacts our QoI considerably. Unlike Clang, G++03 offers almost no C++11 extensions. If we could remove all the fallbacks for G++03, it would mean libc++ could::

  • Improve Correctness:

Every #ifdef _LIBCPP_HAS_NO_<C++11-feature> is a bug manifest. It exists to admit for deviant semantics.

  • Achieve ABI stability between C++03 and C++11

Differences between our C++03 and C++Rest branches contain ABI bugs. For example std::nullptr_t and std::function::operator()(...) are currently incompatible between C++11 and C++03, but could be fixed.

  • Decrease Compile Times and Memory Usage:

Writing efficient SFINAE requires C++11. Using alias templates, libc++ could reduce the number of instantiations it produces substantially.

  • Decrease Binary Size

Similar to the last point, G++03 forces metaprogramming techniques that emit more debug information [3] [4]. Compared to libstdc++, debug information size increases of +10% are not uncommon.

I would like the communities blessing to officially unsupport GCC in C++03 in the 9.0 release.

/Eric

[1] https://gist.github.com/EricWF/83b352471c999655859f75f60c9061a8

[2] Clang and GCC are our only “supported” C++03 compilers. MSVC and XLC don’t support C++03, we don’t support ILC.
[3] G++03 disallows default template parameters, so SFINAE must be written as default function parameters. Function parameters create live variables, live variables force debug info emission for their type, which emits debug information for the SFINAE construct.
[4] Unlike C++03 metafunctions written with normal class templates, C++11 alias templates aren’t instantiated at every use.

+1.

-eric

Hello,

libc++ claims to support GCC with C++03 (“G++03”), and this is a problem for our users.

Our C++03 users are all using Clang. They must be. Less than 9% of the C++03 tests pass with GCC [1][2]. No non-trivial C++ program could work.

Attempting to support G++03 impacts our QoI considerably. Unlike Clang, G++03 offers almost no C++11 extensions. If we could remove all the fallbacks for G++03, it would mean libc++ could::

  • Improve Correctness:

Every #ifdef _LIBCPP_HAS_NO_<C++11-feature> is a bug manifest. It exists to admit for deviant semantics.

  • Achieve ABI stability between C++03 and C++11

Differences between our C++03 and C++Rest branches contain ABI bugs. For example std::nullptr_t and std::function::operator()(...) are currently incompatible between C++11 and C++03, but could be fixed.

Would we break ABI of C++03 using clang as a compiler? Would we only do so for STL features which aren’t actually part of C++03 anyways?

Yes, fixing these ABI bugs would require an ABI change. I don’t know of ABI bugs in standard C++03 components,

I’m not sure how many users actually depend on our C++11 extensions in C++03. Or how many of those people mix
different C++ dialects in the same binary.

My sense is that having a different ABI between C++11 and C++03 is worse than breaking ABI compatibility once to fix that.

In the case of std::function::operator()(...), the C++03 implementation passes rvalues across the type-erasure boundary
by value, C++11 passes by rvalue reference. If both versions of the vtable appear in your program than you’ve got problems.

It’s less clear if deleting <__nullptr> emulation is as palatable for all parties. I could imagine a user writing a declaration

that contains std::nullptr_t in the mangling.

/Eric

Yes, fixing these ABI bugs would require an ABI change. I don’t know of ABI bugs in standard C++03 components,

I’m not sure how many users actually depend on our C++11 extensions in C++03. Or how many of those people mix
different C++ dialects in the same binary.

My sense is that having a different ABI between C++11 and C++03 is worse than breaking ABI compatibility once to fix that.

In the case of std::function::operator()(...), the C++03 implementation passes rvalues across the type-erasure boundary
by value, C++11 passes by rvalue reference. If both versions of the vtable appear in your program than you’ve got problems.

It’s less clear if deleting <__nullptr> emulation is as palatable for all parties. I could imagine a user writing a declaration

that contains std::nullptr_t in the mangling.

Ok thanks, that answers one of my questions: the C++03 extensions would break ABI. Would your suggested change affect compliant C++03 ABI?

Breaking extensions seems less bad… but it’s reminiscent of the std::experimental discussion: what expectations have we given developers when using extensions? If we break ABI on just extensions, can we diagnose the breakage? Or just drop the extension (maybe keep it behind a flag, deprecate, etc)?

Sorry for asking so many questions! In general I agree that shedding burden is useful, but I want to understand the caveats (if any). Maybe that can inform future extensions too :slight_smile:

IMO, it is a mistake to be attempting to provide a c++11 standard library without the c++11 language, and we’d be better off removing those types that cannot be implemented in c++03 (and are thus currently implemented incompatibly or incorrectly) from libcxx’s c++03 mode, rather than fixing them.

Yes, fixing these ABI bugs would require an ABI change. I don’t know of ABI bugs in standard C++03 components,

I’m not sure how many users actually depend on our C++11 extensions in C++03. Or how many of those people mix
different C++ dialects in the same binary.

My sense is that having a different ABI between C++11 and C++03 is worse than breaking ABI compatibility once to fix that.

In the case of std::function::operator()(...), the C++03 implementation passes rvalues across the type-erasure boundary
by value, C++11 passes by rvalue reference. If both versions of the vtable appear in your program than you’ve got problems.

It’s less clear if deleting <__nullptr> emulation is as palatable for all parties. I could imagine a user writing a declaration

that contains std::nullptr_t in the mangling.

Ok thanks, that answers one of my questions: the C++03 extensions would break ABI. Would your suggested change affect compliant C++03 ABI?

No, it would have no effect on the "compliant C++03 ABI`.

Breaking extensions seems less bad… but it’s reminiscent of the std::experimental discussion: what expectations have we given developers when using extensions? If we break ABI on just extensions, can we diagnose the breakage? Or just drop the extension (maybe keep it behind a flag, deprecate, etc)?

We’ll also be improving their QoI significantly at the same time. Our non-variadic fallbacks are of poor quality.

I’m unsure what expectations we’ve given developers that user these extensions, I’m actually not aware of any users.

We could diagnose the breakage, Or we could re-create the C++03 ABI in the variadic version of std::function.
Either way, I would get to delete <__functional_base_03> and <__functional_03>.

I think we should have a separate conversation about if we can drop the extensions, and how we would manage that.

IMO, it is a mistake to be attempting to provide a c++11 standard library without the c++11 language, and we’d be better off removing those types that cannot be implemented in c++03 (and are thus currently implemented incompatibly or incorrectly) from libcxx’s c++03 mode, rather than fixing them.

It’s not quite that simple. libc++ was explicitly designed to target C++11 and later. It has no notion of C++03.

Internally the library depends on buckets of C++11 library features to implement C++03 components. <type_traits>, , unique_ptr, the C++11 allocator model, etc…
Trying to separate out C++03 would be impossible, and subdividing the library harmful.

The good news is that removing the C++03 fallbacks is the fix. We’re just going to use the C++11 implementations.

/Eric

PS. The biggest issue I’ve had is separating >>.

Hi. Do I understand correctly that code dependent on libc++, which is compiled
with Clang and "-std=c++03 -pedantic -Werror" will break in many cases?

Hello,

libc++ claims to support GCC with C++03 (“G++03”), and this is a problem for our users.

Our C++03 users are all using Clang. They must be. Less than 9% of the C++03 tests pass with GCC [1][2]. No non-trivial C++ program could work.

Attempting to support G++03 impacts our QoI considerably. Unlike Clang, G++03 offers almost no C++11 extensions. If we could remove all the fallbacks for G++03, it would mean libc++ could::

I like the general idea and I definitely support dropping support for C++03 under GCC, since it is effectively unsupported today anyway.

  • Improve Correctness:

Every #ifdef _LIBCPP_HAS_NO_<C++11-feature> is a bug manifest. It exists to admit for deviant semantics.

  • Achieve ABI stability between C++03 and C++11

Differences between our C++03 and C++Rest branches contain ABI bugs. For example std::nullptr_t and std::function::operator()(...) are currently incompatible between C++11 and C++03, but could be fixed.

I’d like to echo what some people said regarding breaking ABI here. Instead of breaking the ABI for C++11 extensions in C++03, we could also remove them altogether. This would be a larger change that would require a deprecation period for those extensions, but it might be worth it and it would be safer than an ABI break (because source breaks are compile-time). We could:

  1. Introduce a switch that removes C++11 extensions in C++03
  2. Somehow flag the use of these extensions, asking users to move to C++11 or use alternatives
  3. After some time, toggle the switch to ON by default, removing the extensions
  4. After some time, remove the switch altogether
  5. Get rid of the C++11 extensions in C++03, which are now unused

This hinges on the feasibility of users actually moving to C++11 or using alternatives, and most importantly the number of impacted users. If there’s interest, it would be possible to survey large some code bases to get a sense for these numbers and the feasibility of my plan.

Eric, WDYT?

Either way, I would try to dissociate the two projects of dropping support for GCC/C++03 AND taking advantage of the freedom that gives us.

Louis

The good news is that removing the C++03 fallbacks is the fix. We’re just going
to use the C++11 implementations.

Hi. Do I understand correctly that code dependent on libc++, which is compiled
with Clang and “-std=c++03 -pedantic -Werror” will break in many cases?

No, that is not correct.

Because we mark the files as system headers they are unaffected by -pedantic.
And these warnings don’t leak into user code.

For example, if they call a stdlib function that’s implemented as a variadic template, that will not
cause a diagnostic at the callsite.

/Eric

Thanks for the explanation.

Hello,

libc++ claims to support GCC with C++03 (“G++03”), and this is a problem for our users.

Our C++03 users are all using Clang. They must be. Less than 9% of the C++03 tests pass with GCC [1][2]. No non-trivial C++ program could work.

Attempting to support G++03 impacts our QoI considerably. Unlike Clang, G++03 offers almost no C++11 extensions. If we could remove all the fallbacks for G++03, it would mean libc++ could::

I like the general idea and I definitely support dropping support for C++03 under GCC, since it is effectively unsupported today anyway.

  • Improve Correctness:

Every #ifdef _LIBCPP_HAS_NO_<C++11-feature> is a bug manifest. It exists to admit for deviant semantics.

  • Achieve ABI stability between C++03 and C++11

Differences between our C++03 and C++Rest branches contain ABI bugs. For example std::nullptr_t and std::function::operator()(...) are currently incompatible between C++11 and C++03, but could be fixed.

I’d like to echo what some people said regarding breaking ABI here. Instead of breaking the ABI for C++11 extensions in C++03, we could also remove them altogether. This would be a larger change that would require a deprecation period for those extensions, but it might be worth it and it would be safer than an ABI break (because source breaks are compile-time). We could:

  1. Introduce a switch that removes C++11 extensions in C++03
  2. Somehow flag the use of these extensions, asking users to move to C++11 or use alternatives
  3. After some time, toggle the switch to ON by default, removing the extensions
  4. After some time, remove the switch altogether
  5. Get rid of the C++11 extensions in C++03, which are now unused

This wasn’t clear in my original message, however I would target only those C++03 extensions whose removal provides a benefit. So if a C++11 feature is implemented in C++03 as an extension but it’s trivial to provide, I wouldn’t necessarily try removing it per the process described above, simply because the benefit is small and we risk breaking users. I wouldn’t object to the removal of such trivial extensions either, though (I like being strict about conformance).

Louis

Hello,

libc++ claims to support GCC with C++03 (“G++03”), and this is a problem for our users.

Our C++03 users are all using Clang. They must be. Less than 9% of the C++03 tests pass with GCC [1][2]. No non-trivial C++ program could work.

Attempting to support G++03 impacts our QoI considerably. Unlike Clang, G++03 offers almost no C++11 extensions. If we could remove all the fallbacks for G++03, it would mean libc++ could::

I like the general idea and I definitely support dropping support for C++03 under GCC, since it is effectively unsupported today anyway.

  • Improve Correctness:

Every #ifdef _LIBCPP_HAS_NO_<C++11-feature> is a bug manifest. It exists to admit for deviant semantics.

  • Achieve ABI stability between C++03 and C++11

Differences between our C++03 and C++Rest branches contain ABI bugs. For example std::nullptr_t and std::function::operator()(...) are currently incompatible between C++11 and C++03, but could be fixed.

I’d like to echo what some people said regarding breaking ABI here. Instead of breaking the ABI for C++11 extensions in C++03, we could also remove them altogether. This would be a larger change that would require a deprecation period for those extensions, but it might be worth it and it would be safer than an ABI break (because source breaks are compile-time). We could:

The ABI break is optional. But this option is only available to us after we drop G++03.
We can choose to fix these ABI bugs, or we can choose to keep the ABI stable.

Let’s couch the discussion of how to fix these bugs for now.

  1. Introduce a switch that removes C++11 extensions in C++03
  2. Somehow flag the use of these extensions, asking users to move to C++11 or use alternatives
  3. After some time, toggle the switch to ON by default, removing the extensions
  4. After some time, remove the switch altogether
  5. Get rid of the C++11 extensions in C++03, which are now unused

This hinges on the feasibility of users actually moving to C++11 or using alternatives, and most importantly the number of impacted users. If there’s interest, it would be possible to survey large some code bases to get a sense for these numbers and the feasibility of my plan.

Eric, WDYT?

libc++ is a C++11 implementation of the standard library. We should be envisioning a future without C++03 support.

If a C++11 extension has cost to implement, decreases QoI, doesn’t have existing users, or does not provide real benefit,
then we should consider dropping it. Some extensions I think we should remove (on a reasonable timeline):

  • std::function: I doubt it has many C++03 users, and we don’t really need it internally.

  • <future>: It’s a shell of the actual thing in C++03. I doubt there are users.

We can have a lot of really nice things for libc++ once we take the initial step of dropping G++03.

/Eric

I’ve sent a patch that explicitly disables G++03.

https://reviews.llvm.org/D63154

Lets try to get it landed.

/Eric

I know I am a bit late to this discussion, but for what it is worth I completely agree with what Eric has said here.

A few things to add:

  1. Removing support for G++03 will allow us to get rid of a lot of code. For example, we have 5 overloads for each shared_ptr creation function where one is all that is needed.
  2. Each patch will be much easier and faster to write. When we do not need to take into account supporting many C++03 features, we will be able to write smaller patches that are less complex. Additionally, fewer patches will need to be re-written.
  3. As Eric pointed out in his original message, a lot of libc++ does not work with G++03. No matter what, I don’t think it is a good idea to half-support something. It looks bad for libc++ to say it supports G++03 and in reality only support it sometimes.
  4. For those who still need to use G++03, they can get the old libc++ code that is still compatible. There is no reason someone cannot head over to the llvm download page and download libc++ 8.0. If they are still using G++03, they are probably OK without the latest and greatest.

I plan to disable GCC with C++03 later today if there are no objections.

(See https://reviews.llvm.org/D63154)

Afterwards, I’ll start another thread about the direction we want to set
with Clang, our C++03 extensions in general, and the future for C++03.

/Eric