[Clang] Add flags and lang option for C++2d (#203992)

This adds diagnostic groups, command-line options, a language option,
and various other things required to support `-std=c++2d`. I haven’t
touched e.g. clang-tidy or clang-format, as I’m not really familiar w/
either. This is only meant to add the most necessary parts to support
C++29 mode.

I grepped for `CPlusPlus26`/`C++26`/`C++2c` and updated all places I
could find where we need to handle every language mode in some way or
another.

This patch is roughly based on b763d6a4ed.
This commit is contained in:
Sirraide 2026-07-03 23:37:02 +02:00 committed by GitHub
parent 5de2fb5112
commit 1381ef49fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 97 additions and 18 deletions

View file

@ -226,6 +226,14 @@ Language Selection and Mode Options
Working draft for C++2c with GNU extensions
| ``c++2d``
Working draft for C++2d
| ``gnu++2d``
Working draft for C++2d with GNU extensions
The default C++ language standard is ``gnu++17``.
Supported values for the OpenCL language are:

View file

@ -231,6 +231,8 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
#### C++2d Feature Support
- Added compiler flags `-std=c++2d` and `-std=gnu++2d` for experimental C++2d implementation work.
- Clang now supports [P3733R1](https://wg21.link/p3733r1>) More named universal character escapes.
The change is applied as a DR to all C++ language modes. (#GH203944)

View file

@ -62,6 +62,8 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
### C++ Language Changes
#### C++2d Feature Support
#### C++2c Feature Support
#### C++23 Feature Support

View file

@ -40,7 +40,7 @@ specific section:
- :ref:`Objective-C Language <objc>`: ObjC 1, ObjC 2, ObjC 2.1, plus
variants depending on base language.
- :ref:`C++ Language <cxx>`: C++98, C++03, C++11, C++14, C++17, C++20, C++23,
and C++26.
C++26, and C++29.
- :ref:`Objective C++ Language <objcxx>`
- :ref:`OpenCL Kernel Language <opencl>`: OpenCL C 1.0, 1.1, 1.2, 2.0, 3.0,
and C++ for OpenCL 1.0 and 2021.

View file

@ -244,6 +244,7 @@ multiclass CXX17Compat<string message, bit ext_warn = true> : CXXCompat<message,
multiclass CXX20Compat<string message, bit ext_warn = true> : CXXCompat<message, 20, ext_warn>;
multiclass CXX23Compat<string message, bit ext_warn = true> : CXXCompat<message, 23, ext_warn>;
multiclass CXX26Compat<string message, bit ext_warn = true> : CXXCompat<message, 26, ext_warn, "2c">;
multiclass CXX29Compat<string message, bit ext_warn = true> : CXXCompat<message, 29, ext_warn, "2d">;
// Definitions for Diagnostics.
include "DiagnosticASTKinds.td"

View file

@ -412,6 +412,9 @@ def CXXPre26CompatPedantic :
DiagGroup<"pre-c++26-compat-pedantic", [CXXPre26Compat]>;
def : DiagGroup<"pre-c++2c-compat", [CXXPre26Compat]>;
def : DiagGroup<"pre-c++2c-compat-pedantic", [CXXPre26CompatPedantic]>;
def CXXPre29Compat : DiagGroup<"pre-c++2d-compat">;
def CXXPre29CompatPedantic :
DiagGroup<"pre-c++2d-compat-pedantic", [CXXPre29Compat]>;
def CXX98CompatBindToTemporaryCopy :
DiagGroup<"c++98-compat-bind-to-temporary-copy">;
@ -1580,6 +1583,10 @@ def CXX23 : DiagGroup<"c++23-extensions", [CXX23AttrsOnLambda]>;
// earlier C++ versions.
def CXX26 : DiagGroup<"c++26-extensions">;
// A warning group for warnings about using C++29 features as extensions in
// earlier C++ versions.
def CXX29 : DiagGroup<"c++2d-extensions">;
def : DiagGroup<"c++0x-extensions", [CXX11]>;
def : DiagGroup<"c++1y-extensions", [CXX14]>;
def : DiagGroup<"c++1z-extensions", [CXX17]>;

View file

@ -57,6 +57,7 @@ LANGOPT(CPlusPlus17 , 1, 0, NotCompatible, "C++17")
LANGOPT(CPlusPlus20 , 1, 0, NotCompatible, "C++20")
LANGOPT(CPlusPlus23 , 1, 0, NotCompatible, "C++23")
LANGOPT(CPlusPlus26 , 1, 0, NotCompatible, "C++26")
LANGOPT(CPlusPlus29 , 1, 0, NotCompatible, "C++29")
LANGOPT(ObjC , 1, 0, NotCompatible, "Objective-C")
LANGOPT(ObjCDefaultSynthProperties , 1, 0, Benign,
"Objective-C auto-synthesized properties")

View file

@ -59,11 +59,12 @@ enum LangFeatures {
CPlusPlus20 = (1 << 10),
CPlusPlus23 = (1 << 11),
CPlusPlus26 = (1 << 12),
Digraphs = (1 << 13),
GNUMode = (1 << 14),
HexFloat = (1 << 15),
OpenCL = (1 << 16),
HLSL = (1 << 17)
CPlusPlus29 = (1 << 13),
Digraphs = (1 << 14),
GNUMode = (1 << 15),
HexFloat = (1 << 16),
OpenCL = (1 << 17),
HLSL = (1 << 18)
};
/// LangStandard - Information about the properties of a particular language
@ -133,6 +134,9 @@ public:
/// isCPlusPlus26 - Language is a post-C++26 variant (or later).
bool isCPlusPlus26() const { return Flags & CPlusPlus26; }
/// isCPlusPlus29 - Language is a post-C++29 variant (or later).
bool isCPlusPlus29() const { return Flags & CPlusPlus29; }
/// hasDigraphs - Language supports digraphs.
bool hasDigraphs() const { return Flags & Digraphs; }

View file

@ -107,7 +107,8 @@ LANGSTANDARD(c2y, "c2y",
LineComment | C99 | C11 | C17 | C23 | C2y | Digraphs | HexFloat, 202400)
LANGSTANDARD(gnu2y, "gnu2y",
C, "Working Draft for ISO C2y with GNU extensions",
LineComment | C99 | C11 | C17 | C23 | C2y | Digraphs | GNUMode | HexFloat, 202400)
LineComment | C99 | C11 | C17 | C23 | C2y | Digraphs | GNUMode
| HexFloat, 202400)
// TODO: Add the iso9899:202y alias once ISO publishes the standard.
// C++ modes
@ -191,6 +192,19 @@ LANGSTANDARD(gnucxx26, "gnu++2c",
CPlusPlus20 | CPlusPlus23 | CPlusPlus26 | Digraphs | HexFloat | GNUMode, 202400)
LANGSTANDARD_ALIAS(gnucxx26, "gnu++26")
// FIXME: Use correct version code for C++29 once published.
// TODO: Add LANGSTANDARD_ALIAS() for "c++29" once C++29 is ratified.
LANGSTANDARD(cxx29, "c++2d",
CXX, "Working draft for C++2d",
LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 |
CPlusPlus20 | CPlusPlus23 | CPlusPlus26 | CPlusPlus29 | Digraphs | HexFloat, 202700)
// TODO: Add LANGSTANDARD_ALIAS() for "gnu++29" once C++29 is ratified.
LANGSTANDARD(gnucxx29, "gnu++2d",
CXX, "Working draft for C++2d with GNU extensions",
LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 |
CPlusPlus20 | CPlusPlus23 | CPlusPlus26 | CPlusPlus29 | Digraphs | HexFloat | GNUMode, 202700)
// OpenCL
LANGSTANDARD(opencl10, "cl1.0",
OpenCL, "OpenCL 1.0",

View file

@ -634,6 +634,7 @@ defvar cpp17 = LangOpts<"CPlusPlus17">;
defvar cpp20 = LangOpts<"CPlusPlus20">;
defvar cpp23 = LangOpts<"CPlusPlus23">;
defvar cpp26 = LangOpts<"CPlusPlus26">;
defvar cpp29 = LangOpts<"CPlusPlus29">;
defvar c99 = LangOpts<"C99">;
defvar c23 = LangOpts<"C23">;
defvar lang_std = LangOpts<"LangStd">;

View file

@ -41,6 +41,7 @@ TESTLANGUAGE_CXX(CXX, 17, c++17, 4)
TESTLANGUAGE_CXX(CXX, 20, c++20, 5)
TESTLANGUAGE_CXX(CXX, 23, c++23, 6)
TESTLANGUAGE_CXX(CXX, 26, c++26, 7)
TESTLANGUAGE_CXX(CXX, 29, c++2d, 8)
#undef TESTLANGUAGE_CXX
#undef TESTLANGUAGE_C

View file

@ -902,6 +902,8 @@ unsigned DiagnosticIDs::getCXXCompatDiagId(const LangOptions &LangOpts,
assert(CompatDiagId < std::size(Diags) && "Invalid compat diag id");
unsigned StdVer = [&] {
if (LangOpts.CPlusPlus29)
return 2029;
if (LangOpts.CPlusPlus26)
return 2026;
if (LangOpts.CPlusPlus23)

View file

@ -124,6 +124,7 @@ void LangOptions::setLangDefaults(LangOptions &Opts, Language Lang,
Opts.CPlusPlus20 = Std.isCPlusPlus20();
Opts.CPlusPlus23 = Std.isCPlusPlus23();
Opts.CPlusPlus26 = Std.isCPlusPlus26();
Opts.CPlusPlus29 = Std.isCPlusPlus29();
Opts.GNUMode = Std.isGNUMode();
Opts.GNUCVersion = 0;
Opts.HexFloats = Std.hasHexFloats();
@ -277,7 +278,9 @@ std::optional<uint32_t> LangOptions::getCPlusPlusLangStd() const {
return std::nullopt;
LangStandard::Kind Std;
if (CPlusPlus26)
if (CPlusPlus29)
Std = LangStandard::lang_cxx29;
else if (CPlusPlus26)
Std = LangStandard::lang_cxx26;
else if (CPlusPlus23)
Std = LangStandard::lang_cxx23;

View file

@ -105,6 +105,7 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
.Case("cplusplus20", LangOpts.CPlusPlus20)
.Case("cplusplus23", LangOpts.CPlusPlus23)
.Case("cplusplus26", LangOpts.CPlusPlus26)
.Case("cplusplus29", LangOpts.CPlusPlus29)
.Case("c99", LangOpts.C99)
.Case("c11", LangOpts.C11)
.Case("c17", LangOpts.C17)

View file

@ -228,7 +228,10 @@ static void addVisualCDefines(const LangOptions &Opts, MacroBuilder &Builder) {
Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1));
if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) {
if (Opts.CPlusPlus26)
if (Opts.CPlusPlus29)
// TODO update to the proper value.
Builder.defineMacro("_MSVC_LANG", "202700L");
else if (Opts.CPlusPlus26)
// TODO update to the proper value.
Builder.defineMacro("_MSVC_LANG", "202400L");
else if (Opts.CPlusPlus23)

View file

@ -150,6 +150,8 @@ static llvm::ManagedStatic<IndexErrorCategory> Category;
static std::string getLangDescription(const LangOptions &LO) {
if (!LO.CPlusPlus)
return "non-C++";
if (LO.CPlusPlus29)
return "C++29";
if (LO.CPlusPlus26)
return "C++26";
if (LO.CPlusPlus23)

View file

@ -1671,7 +1671,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
(Std->containsValue("c++20") || Std->containsValue("c++2a") ||
Std->containsValue("c++23") || Std->containsValue("c++2b") ||
Std->containsValue("c++26") || Std->containsValue("c++2c") ||
Std->containsValue("c++latest"));
Std->containsValue("c++2d") || Std->containsValue("c++latest"));
// Process -fmodule-header{=} flags.
if (Arg *A = Args.getLastArg(options::OPT_fmodule_header_EQ,

View file

@ -7690,9 +7690,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// TransferableCommand::tryParseStdArg() in
// lib/Tooling/InterpolatingCompilationDatabase.cpp
// to match.
// TODO add c++23 and c++26 when MSVC supports it.
// TODO add c++23, c++26, c++29 when MSVC supports
// it.
.Case("c++23preview", "-std=c++23")
.Case("c++latest", "-std=c++26")
.Case("c++latest", "-std=c++2d")
.Default("");
if (IsSYCL) {
const LangStandard *LangStd =
@ -7782,7 +7783,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Std->containsValue("c++23") || Std->containsValue("gnu++23") ||
Std->containsValue("c++23preview") || Std->containsValue("c++2c") ||
Std->containsValue("gnu++2c") || Std->containsValue("c++26") ||
Std->containsValue("gnu++26") || Std->containsValue("c++latest") ||
Std->containsValue("gnu++26") || Std->containsValue("c++2d") ||
Std->containsValue("gnu++2d") || Std->containsValue("c++latest") ||
Std->containsValue("gnu++latest"));
bool HaveModules =
RenderModulesOptions(C, D, Args, Input, Output, HaveCxx20, CmdArgs);

View file

@ -148,9 +148,9 @@ static LangStandard::Kind latestLangStandardC() {
// flag in clang-CL mode.
static LangStandard::Kind latestLangStandardCXX() {
// FIXME: Have a single source of truth for the mapping from
// c++latest --> c++26 that's shared by the driver code
// c++latest --> c++29 that's shared by the driver code
// (clang/lib/Driver/ToolChains/Clang.cpp) and this file.
return LangStandard::lang_cxx26;
return LangStandard::lang_cxx29;
}
// A CompileCommand that can be applied to another file.

View file

@ -625,7 +625,7 @@
// STDCXX23PREVIEW: -std=c++23
// RUN: %clang_cl -fmsc-version=1900 -TP -std:c++latest -### -- %s 2>&1 | FileCheck -check-prefix=STDCXXLATEST %s
// STDCXXLATEST: -std=c++26
// STDCXXLATEST: -std=c++2d
// RUN: env CL="/Gy" %clang_cl -### -- %s 2>&1 | FileCheck -check-prefix=ENV-CL %s
// ENV-CL: "-ffunction-sections"

View file

@ -24,6 +24,8 @@
// CHECK-NEXT: note: use 'gnu++23' for 'ISO C++ 2023 DIS with GNU extensions' standard
// CHECK-NEXT: note: use 'c++2c' or 'c++26' for 'Working draft for C++2c' standard
// CHECK-NEXT: note: use 'gnu++2c' or 'gnu++26' for 'Working draft for C++2c with GNU extensions' standard
// CHECK-NEXT: note: use 'c++2d' for 'Working draft for C++2d' standard
// CHECK-NEXT: note: use 'gnu++2d' for 'Working draft for C++2d with GNU extensions' standard
// Make sure that no other output is present.
// CHECK-NOT: {{^.+$}}

View file

@ -15,6 +15,15 @@
// BLOCKS:#define __BLOCKS__ 1
// BLOCKS:#define __block __attribute__((__blocks__(byref)))
//
// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=c++2d -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix CXX29 %s
//
// CXX29:#define __GNUG__ 4
// CXX29:#define __GXX_EXPERIMENTAL_CXX0X__ 1
// CXX29:#define __GXX_RTTI 1
// CXX29:#define __GXX_WEAK__ 1
// CXX29:#define __cplusplus 202700L
// CXX29:#define __private_extern__ extern
//
// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=c++26 -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix CXX26 %s
// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=c++2c -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix CXX26 %s
//
@ -214,6 +223,13 @@
// RUN: %clang_cc1 -ffreestanding -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix FREESTANDING %s
// FREESTANDING:#define __STDC_HOSTED__ 0
//
// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=gnu++2d -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GXX29 %s
//
// GXX29:#define __GNUG__ 4
// GXX29:#define __GXX_WEAK__ 1
// GXX29:#define __cplusplus 202700L
// GXX29:#define __private_extern__ extern
//
// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=gnu++26 -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GXX26 %s
// RUN: %clang_cc1 -x c++ -fgnuc-version=4.2.1 -std=gnu++2c -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GXX26 %s
//

View file

@ -50,6 +50,8 @@ TEST(LangOptsTest, CppStdLang) {
EXPECT_EQ(opts.getCPlusPlusLangStd(), 202302);
opts.CPlusPlus26 = 1;
EXPECT_EQ(opts.getCPlusPlusLangStd(), 202400);
opts.CPlusPlus29 = 1;
EXPECT_EQ(opts.getCPlusPlusLangStd(), 202700);
EXPECT_FALSE(opts.getCLangStd());
}

View file

@ -112,7 +112,7 @@ improve the quality of clang by self-testing. Some examples:
</ul>
</li>
<li><b>Continue work on C++20, C++23, C++2c, and C23 support</b>:
<li><b>Continue work on C++20, C++23, C++2c, C++2d, and C23 support</b>:
There are still several C++20 features to complete, and work has begun on
supporting the latest language standards. Please see the
<a href="cxx_status.html">C++ status report page</a> to find out what is

View file

@ -37,7 +37,7 @@
</tr>
<tr>
<td><a href="#cxx29">C++2d</a></td>
<td></td>
<td><tt>-std=c++2d</tt></td>
<td class="partial" align="center">Partial</td>
</tr>
<tr>
@ -98,6 +98,8 @@ and so on, to track known bugs with Clang's language conformance.</p>
<p>Clang has support for some of the features of the C++ standard following
C++2c, informally referred to as C++2d.</p>
<p>You can use Clang in C++2d mode with the <code>-std=c++2d</code> option.</p>
<details open>
<summary>List of features and minimum Clang version with support</summary>
<table width="689" border="1" cellspacing="0">

View file

@ -186,6 +186,9 @@ def availability(issue):
elif status.endswith(' c++26'):
status = status[:-6]
avail_suffix = ' (C++26 onwards)'
elif status.endswith(' c++29'):
status = status[:-6]
avail_suffix = ' (C++29 onwards)'
if status == 'unknown':
avail = 'Unknown'
avail_style = 'unknown'