Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -2369,15 +2369,17 @@ unsigned Mutable : 1; mutable unsigned CachedFieldIndex : 31; - /// The kinds of value we can store in InitializerOrBitWidth. + /// \brief Expression representing the bit-width, + /// or nullptr if this field isn't a bitfield. + Expr *BitWidth; + + /// The kinds of value we can store in InitStorage. /// /// Note that this is compatible with InClassInitStyle except for /// ISK_CapturedVLAType. enum InitStorageKind { - /// If the pointer is null, there's nothing special. Otherwise, - /// this is a bitfield and the pointer is the Expr* storing the - /// bit-width. - ISK_BitWidthOrNothing = (unsigned) ICIS_NoInit, + /// Nothing special, the pointer should be null. + ISK_Nothing = (unsigned) ICIS_NoInit, /// The pointer is an (optional due to delayed parsing) Expr* /// holding the copy-initializer. @@ -2392,12 +2394,11 @@ ISK_CapturedVLAType, }; - /// \brief Storage for either the bit-width, the in-class - /// initializer, or the captured variable length array bound. + /// \brief Storage for either the in-class initializer + /// or the captured variable length array bound. /// /// We can safely combine these because in-class initializers are - /// not permitted for bit-fields, and both are exclusive with VLA - /// captures. + /// exclusive with VLA captures. /// /// If the storage kind is ISK_InClassCopyInit or /// ISK_InClassListInit, but the initializer is null, then this @@ -2410,10 +2411,8 @@ QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), - Mutable(Mutable), CachedFieldIndex(0), - InitStorage(BW, (InitStorageKind) InitStyle) { - assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield"); - } + Mutable(Mutable), CachedFieldIndex(0), BitWidth(BW), + InitStorage(nullptr, (InitStorageKind) InitStyle) { } public: static FieldDecl *Create(const ASTContext &C, DeclContext *DC, @@ -2433,8 +2432,7 @@ /// \brief Determines whether this field is a bitfield. bool isBitField() const { - return InitStorage.getInt() == ISK_BitWidthOrNothing && - InitStorage.getPointer() != nullptr; + return BitWidth != nullptr; } /// @brief Determines whether this is an unnamed bitfield. @@ -2447,26 +2445,24 @@ bool isAnonymousStructOrUnion() const; Expr *getBitWidth() const { - return isBitField() - ? static_cast(InitStorage.getPointer()) - : nullptr; + return BitWidth; } unsigned getBitWidthValue(const ASTContext &Ctx) const; /// setBitWidth - Set the bit-field width for this member. // Note: used by some clients (i.e., do not remove it). void setBitWidth(Expr *Width) { - assert(InitStorage.getInt() == ISK_BitWidthOrNothing && - InitStorage.getPointer() == nullptr && - "bit width, initializer or captured type already set"); - InitStorage.setPointerAndInt(Width, ISK_BitWidthOrNothing); + assert(InitStorage.getInt() != ISK_CapturedVLAType && + BitWidth == nullptr && + "bit width or captured type already set"); + BitWidth = Width; } /// removeBitWidth - Remove the bit-field width from this member. // Note: used by some clients (i.e., do not remove it). void removeBitWidth() { assert(isBitField() && "no bitfield width to remove"); - InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); + BitWidth = nullptr; } /// getInClassInitStyle - Get the kind of (C++11) in-class initializer which @@ -2498,7 +2494,7 @@ void setInClassInitializer(Expr *Init) { assert(hasInClassInitializer() && InitStorage.getPointer() == nullptr && - "bit width, initializer or captured type already set"); + "initializer or captured type already set"); InitStorage.setPointer(Init); } @@ -2506,7 +2502,7 @@ /// member. void removeInClassInitializer() { assert(hasInClassInitializer() && "no initializer to remove"); - InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); + InitStorage.setPointerAndInt(nullptr, ISK_Nothing); } /// \brief Determine whether this member captures the variable length array Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -167,6 +167,9 @@ def CXXPre1zCompat : DiagGroup<"c++98-c++11-c++14-compat">; def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic", [CXXPre1zCompat]>; +def CXXPre2aCompat : DiagGroup<"c++98-c++11-c++14-c++1z-compat">; +def CXXPre2aCompatPedantic : DiagGroup<"c++98-c++11-c++14-c++1z-compat-pedantic", + [CXXPre2aCompat]>; def CXX98CompatBindToTemporaryCopy : DiagGroup<"c++98-compat-bind-to-temporary-copy">; @@ -780,6 +783,10 @@ // earlier C++ versions. def CXX1z : DiagGroup<"c++1z-extensions">; +// A warning group for warnings about using C++2a features as extensions in +// earlier C++ versions. +def CXX2a : DiagGroup<"c++2a-extensions">; + def : DiagGroup<"c++0x-extensions", [CXX11]>; def : DiagGroup<"c++1y-extensions", [CXX14]>; Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -730,11 +730,17 @@ def warn_cxx98_compat_nonstatic_member_init : Warning< "in-class initialization of non-static data members is incompatible with C++98">, InGroup, DefaultIgnore; -def err_bitfield_member_init: Error< - "bit-field member cannot have an in-class initializer">; def err_incomplete_array_member_init: Error< "array bound cannot be deduced from an in-class initializer">; +// C++2a in-class bitfield member initialization +def warn_cxx1z_compat_bitfield_member_init : Warning< + "in-class initialization of bit-field members is incompatible with " + "C++ standards before C++2a">, InGroup, DefaultIgnore; +def ext_bitfield_member_init_cxx2a : ExtWarn< + "in-class initialization of bit-field members is a C++2a extension">, + InGroup; + // C++11 alias-declaration def ext_alias_declaration : ExtWarn< "alias declarations are a C++11 extension">, InGroup; Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -3553,7 +3553,6 @@ unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const { assert(isBitField() && "not a bitfield"); - auto *BitWidth = static_cast(InitStorage.getPointer()); return BitWidth->EvaluateKnownConstInt(Ctx).getZExtValue(); } @@ -3578,14 +3577,14 @@ SourceRange FieldDecl::getSourceRange() const { switch (InitStorage.getInt()) { - // All three of these cases store an optional Expr*. - case ISK_BitWidthOrNothing: + // Both of these cases store an optional Expr*. case ISK_InClassCopyInit: case ISK_InClassListInit: if (const auto *E = static_cast(InitStorage.getPointer())) return SourceRange(getInnerLocStart(), E->getLocEnd()); // FALLTHROUGH + case ISK_Nothing: case ISK_CapturedVLAType: return DeclaratorDecl::getSourceRange(); } @@ -3595,9 +3594,9 @@ void FieldDecl::setCapturedVLAType(const VariableArrayType *VLAType) { assert((getParent()->isLambda() || getParent()->isCapturedRecord()) && "capturing type in non-lambda or captured record."); - assert(InitStorage.getInt() == ISK_BitWidthOrNothing && + assert(InitStorage.getInt() == ISK_Nothing && InitStorage.getPointer() == nullptr && - "bit width, initializer or captured type already set"); + "initializer or captured type already set"); InitStorage.setPointerAndInt(const_cast(VLAType), ISK_CapturedVLAType); } Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -2403,6 +2403,7 @@ /// declarator constant-initializer[opt] /// [C++11] declarator brace-or-equal-initializer[opt] /// identifier[opt] ':' constant-expression +/// brace-or-equal-initializer[opt][C++2a] /// /// virt-specifier-seq: /// virt-specifier @@ -2720,10 +2721,12 @@ InClassInitStyle HasInClassInit = ICIS_NoInit; bool HasStaticInitializer = false; if (Tok.isOneOf(tok::equal, tok::l_brace) && PureSpecLoc.isInvalid()) { - if (BitfieldSize.get()) { - Diag(Tok, diag::err_bitfield_member_init); - SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); - } else if (DeclaratorInfo.isDeclarationOfFunction()) { + if (BitfieldSize.get()) + Diag(Tok, !getLangOpts().CPlusPlus2a + ? diag::ext_bitfield_member_init_cxx2a + : diag::warn_cxx1z_compat_bitfield_member_init); + + if (DeclaratorInfo.isDeclarationOfFunction()) { // It's a pure-specifier. if (!TryConsumePureSpecifier(/*AllowFunctionDefinition*/ false)) // Parse it as an expression so that Sema can diagnose it. Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -1219,9 +1219,10 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { VisitDeclaratorDecl(FD); FD->Mutable = Record.readInt(); - if (int BitWidthOrInitializer = Record.readInt()) { + FD->BitWidth = Record.readExpr(); + if (int Initializer = Record.readInt()) { FD->InitStorage.setInt( - static_cast(BitWidthOrInitializer - 1)); + static_cast(Initializer - 1)); if (FD->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) { // Read captured variable length array. FD->InitStorage.setPointer(Record.readType().getAsOpaquePtr()); Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -849,8 +849,8 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { VisitDeclaratorDecl(D); Record.push_back(D->isMutable()); - if (D->InitStorage.getInt() == FieldDecl::ISK_BitWidthOrNothing && - D->InitStorage.getPointer() == nullptr) { + Record.AddStmt(D->getBitWidth()); + if (D->InitStorage.getInt() == FieldDecl::ISK_Nothing) { Record.push_back(0); } else if (D->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) { Record.push_back(D->InitStorage.getInt() + 1); Index: test/Parser/cxx2a-bitfield-member-init.cpp =================================================================== --- test/Parser/cxx2a-bitfield-member-init.cpp +++ test/Parser/cxx2a-bitfield-member-init.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s +// expected-no-diagnostics + +// This is a slightly modified version of the example from C++2a [class.mem]p7. +// It tests the resolution of parsing ambiguities. + +int a; +struct S { + unsigned x1 : 8 = 42; + unsigned x2 : 8 {42}; + + unsigned y1 : true ? 8 : a = 42; + unsigned y2 : (true ? 8 : a) = 42; + + unsigned z1 : 1 || new int { 1 }; + unsigned z2 : (1 || new int) { 1 }; +}; + +constexpr S s{}; +static_assert(s.x1 == 42 && s.x2 == 42); +static_assert(s.y1 == 0 && s.y2 == 42); +static_assert(s.z1 == 0 && s.z2 == 1); Index: test/SemaCXX/member-init.cpp =================================================================== --- test/SemaCXX/member-init.cpp +++ test/SemaCXX/member-init.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 -Wall %s struct Bitfield { - int n : 3 = 7; // expected-error {{bit-field member cannot have an in-class initializer}} + int n : 3 = 2; // expected-warning {{C++2a extension}} }; int a; Index: www/cxx_status.html =================================================================== --- www/cxx_status.html +++ www/cxx_status.html @@ -777,13 +777,12 @@

C++2a implementation status

-

Clang does not yet support any of the proposed features of - +

Clang has experimental support for some proposed features of the C++ standard following C++17, provisionally named C++2a. Note that support for these features may change or be removed without notice, as the draft C++2a standard evolves. - +

You can use Clang in C++2a mode with the -std=c++2a option.

List of features and minimum Clang version with support @@ -798,7 +797,7 @@ Default member initializers for bit-fields P0683R1 - No + SVN const&-qualified pointers to members