RFC: Lets just call it C++26 and forget about the C++2c business (at least, internally)

SO I’ve felt this way for a while, and I think now that we’re hitting our 4th straight on-time C++ release, we can make this decision with little risk.

Background:
Historically, we’ve been calling the C++ releases (and C releases!) based on the language, decade, and a letter. So, C++1x, C++1y, C++1z, C++2a, C++2b, C2x.

Proposal:
I believe that from a user-interface perspective, and from everything visible to users, that this is ‘a good thing’.

HOWEVER, I’ve seen churn/mistakes made (and some latent missed conversions from the time-frame) at each transition from x/y/z/a/b to 1/4/7/0/3, and I don’t think they are worth what I see as little/no gain.

Therefore, I am proposing that ALL INTERNAL names just use C++26. This does NOT include: Times we mention it in a Diagnostic Message, or our command-line flag, or places we mention it in documentation.

However, it DOES include what we care the LangOption flag (LO.CPlusPlus26 instead of LO.CPlusPlus2C). Also, diagnostics that are language version specific (such as err_cxx2b_size_t_suffix!) would have just been err_cxx23_size_t_suffix instead. Our Diagnostic Groups would just be CXXPre26Compat and CXXPre26CompatPedantic from the start. It also includes how we refer to it in comments (C++26 instead of C++2c).

My hope is that it will result in fewer mistakes, and that the C++26 variant of this patch ([clang] Use -std=c++23 instead of -std=c++2b · llvm/llvm-project@ba15d18 · GitHub) will be reduced to adding the language version flag for -std=c++26, our documentation, and updating our diagnostic messages (messages only!).

3 Likes

In libc++ we also changed something very similar recently (in https://reviews.llvm.org/D131498), since we expect C++2c to become C++26, and making things less confusing. Note that even if C++2c wouldn’t become C++26, there would be the same amount of churn as there is now, so I don’t see any downside to this.

3 Likes

In general I agree that using the 26 name seems safe; WG21 has proven they can manage time based releases. Especially the renaming of LO.CPlusPlus2b to LO.CPlusPlus23 can cause issue since it’s part of the interface (see https://reviews.llvm.org/D149554). (I also had a talk about his with @ldionne yesterday, he will post more on that,)

I’ve already created a draft patch (using c++2c everywhere) https://reviews.llvm.org/D149875 .

I’ll keep it in draft until this RFC has concluded.

2 Likes

I was actually discussing something similar with @mordante the other day. I wonder what the purpose of the -std=c++2c flag even is. What do we intend to convey to users with that flag?

  • Is the API for that standard finalized and stable?
  • Is the quality of implementation good?
  • Are we going to make changes like ABI changes?

I think, but I’m not certain, that most people within Clang/libc++ understand that -std=c++2c implies that the API isn’t finalized, and hence we reserve the right to make some changes. In fact, we might be required to make some changes depending on WG21 decisions made during the C++26 release cycle.

However, I am fairly confident that most users just don’t think about this. They probably use -std=c++2c as a way to “get whatever’s ready from C++26”, without deep consideration for stability or quality of implementation. I view this as an issue, because we can essentially end up shipping something unstable to users and they can start relying on it in critical places just because of a messaging problem.

That is why we introduced the -fexperimental-library flag in Clang for use within libc++. We use it to control whether experimental parts of the library are provided or not. In this context, experimental basically means “anything that you shouldn’t use in production just yet”:

  • Things for which WG21 is still changing API
  • Things where WG21 has finalized its design but we are still experimenting with e.g. ABI-affecting tradeoffs within libc++
  • The few std::experimental things we implement
  • Anything for which we don’t feel like the quality is high enough yet to ship to end users

This ensures that we are intentional about what we let users depend on. By default, they can be certain that whatever they get is stable and we’re happy about the quality. If they want to play with unstable stuff, they can use -fexperimental-library and those features will be available, but they shouldn’t ship that in production.

One thing we could do for Clang is have a -std=c++26 flag that says “whatever is ready and stable from C++26”, and also a -std=c++next or -std=c++latest (like MSVC?) that basically says: “give me all the latest stuff, understanding it might not be stable yet”. In that context, -std=c++latest would also enable -fexperimental-library, but -std=c++26 would not. This would achieve the same level of intentionality that we have for libc++ but for the compiler/toolchain as a whole, which I personally believe is a good thing.

Thoughts?

2 Likes

We all know that the next standard will be released in 2026. But I don’t know the feature set. Clang claiming -std=c++26 feels a bit odd. I am in favour of -std=c++next or -std=c++latest. Everybody knows things may change, but I get everything that is there today.

I don’t think there’s a major issue here to be solved – we go through this dance once every 3 or so years, so it’s not a huge burden (and in terms of blame churn, we can always add the revision doing this renaming to the ignored revisions list).

However, I also don’t see a major problem with using the expected release date for C++ for internal identifiers. WG21 has shipped every three years for a while now and the committee has a strong mandate to continuing shipping every three years. So the only real risk is if the committee slips and we have to rename from “26” to “27” – it’s easier to mechanically find all the places where we use 2c than to find places with 26. However, that’s a pretty minor risk IMO.

In terms of user-facing identifiers, we should not go with the presumed release date. There is no C++26 until WG21 and ISO say there is, and we don’t want to give users a mistaken impression as to what is and isn’t a released standards mode. (Also, it’d be a bit weird to say -std=c++26 in 2023 – I know we wish we had time machines, but this was not what we meant!) So this includes things like the standards mode flag, diagnostic text, documentation, etc.

So tl;dr: I’m okay with this change if others like the idea.

That this is an in-progress standards mode that has not been ratified by any standards committee, and all details about those in-progress features is subject to change. It is not a comment on the quality of implementation (we have feature flags for testing support for individual features for signaling when we think a feature is complete).

That’s an interesting idea that’s worth considering, but is a bit orthogonal to what I think Erich is after with this RFC. I’m not opposed to the idea you have, but it’d be nice to hear more feedback from Microsoft on how well /std:c++latest has been received by their users, what problems they’ve seen from it, etc. It’s basically a YOLO mode for the standards version where the user is saying “I don’t care what I get” and we already have that concept when the user does not specify an explicit standards mode. So far, that model has worked well for us because we can bump the default mode when we believe the ecosystem can support that standards mode well. The same is not true for /std:c++latest, but perhaps that’s not an issue? Or perhaps that issue is different on Windows from other platforms? And can we do the same thing with C, or does that present different problems due to the way the C runtime library is distributed? (Basically, I think the bar is higher for deciding on -std=c++latest than for Erich’s RFC because the language mode is user-facing, so I don’t want to mix the two ideas too heavily.)

1 Like

+1

I like the idea of asking the compiler “give me bleeding edge stuff”, regardless of any said WIP C++ standard version. It’s a convenient way to continuously build projects against newer features and picking problems / make source code changes as they show up - instead of relying on someone introducing the next letter, or tracking new flags in upstream for the same purpose. As a side note, IMO next seems better than latest (which could imply some stability).

2 Likes

I’ve seen cases where project maintainers have discovered that feature X is only available with -std:c++latest and just assumed they should therefore use that option for their project. That option name can be misinterpreted as meaning the most recent C++ standard. This is probably not a frequent occurrence, but it might not be a bad idea to issue a diagnostic with use of that option to inform the user that they should not expect stable behavior when using it.

1 Like

I’m fairly neutral on the internal stuffs, I agree with you, we know C++26 will be the next C++.
(I also agree with @AaronBallman than the current mode of operation isn’t too much of a churn either)

For the public facing bits there are benefits to 2c: It’s a good reminder that things are unstable and it’s consistent with GCC. Which is valuable for people using both - it would be a pain for any compiler explorer user if that option diverges.

1 Like

GCC doesn’t support -std=c++2c option yet, but FWIW when -std=c++2b was added, -std=c++23 was added at the same time. There was never a time when GCC supported the -std=c++2b option but didn’t also support -std=c++23.

1 Like

Oh, that’s really good to know Jonathan, thank you for mentioning that! Do you recall what the rationale was for adding the specific date variant at the same time?

See Jason’s review comments:

Hmm, I don’t think it’s that premature; the C++ committee has been very
serious about time-based releases every three years. I think it makes
sense for the advertised flag to be c++2b, but let’s also go ahead and
add the c++23 flags as hidden, and use cxx23 internally.

So this is kinda what Erich is suggesting here, but going a little further. The documented option is -std=c++2b but internally everything just refers to C++23 right away (so no churn to update that later), and additionally just support -std=c++23 from day one, even if it’s not documented. IIRC the rationale was that the distinction between -std=c++23 and -std=c++2b has no clearly defined meaning, and even if we decided on one, most users aren’t going to know or appreciate the distinction.

I think another argument in favour is that it means makefiles using -std=c++23 Just Work. You don’t need to use -std=c++2b for some versions and -std=c++23 for others (because the outcome of that is that everybody just uses -std=c++2b forever, because it’s more portable).

1 Like

Thank you for the explanation, that seems quite reasonable to me for C++ largely because of the aid with build scripts. I would be okay with supporting -std=c++26 up front (and using cxx26 internally) so long as we don’t document the -std=c++26 until the standard is finalized. I agree there’s not a functional distinction between the two spellings (and I don’t think we want to introduce any), but I think we still want to favor -std=c++2c so that users reading our documentation have some idea of what “era” the compiler is from. e.g., if you get clang as the system compiler and are looking through its manpages, it helps to see at a glance “oh, this compiler came at a time when the standard wasn’t yet final”, so it can help with setting user expectations (somewhat).

2 Likes

This seems completely reasonable to me.

Review to add the new flags here: ⚙ D150450 Add C++26 compile flags.

I have no issue with this for C++, but C2X is the first faster release of C, for C2Y/C3A we should still use the cryptic names.