hamzasood created this revision.
This patch implements P0683R1 <http://wg21.link/p0683r1>.
Member initialisers are allowed pre-C++11 as an extension. So I've also allowed
bitfield member initialisers pre-C++2a as an extension (with appropriate
warnings) for consistency.
https://reviews.llvm.org/D36611
Files:
include/clang/AST/Decl.h
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticParseKinds.td
lib/AST/Decl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/Parser/cxx2a-bitfield-member-init.cpp
test/SemaCXX/member-init.cpp
www/cxx_status.html
Index: www/cxx_status.html
===================================================================
--- www/cxx_status.html
+++ www/cxx_status.html
@@ -777,13 +777,12 @@
<h2 id="cxx20">C++2a implementation status</h2>
-<p>Clang does not yet support any of the proposed features of
-<!--<p>Clang has <b>experimental</b> support for some proposed features of-->
+<p>Clang has <b>experimental</b> 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.
-<!--<p>You can use Clang in C++2a mode with the <code>-std=c++2a</code> option.</p>-->
+<p>You can use Clang in C++2a mode with the <code>-std=c++2a</code> option.</p>
<details open>
<summary>List of features and minimum Clang version with support</summary>
@@ -798,7 +797,7 @@
<tr>
<td>Default member initializers for bit-fields</td>
<td><a href="http://wg21.link/p0683r1">P0683R1</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td><tt>const&</tt>-qualified pointers to members</td>
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: 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: 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: 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<FieldDecl::InitStorageKind>(BitWidthOrInitializer - 1));
+ static_cast<FieldDecl::InitStorageKind>(Initializer - 1));
if (FD->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) {
// Read captured variable length array.
FD->InitStorage.setPointer(Record.readType().getAsOpaquePtr());
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/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<Expr *>(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<const Expr *>(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<VariableArrayType *>(VLAType),
ISK_CapturedVLAType);
}
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<CXX98Compat>, 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<CXXPre2aCompat>, DefaultIgnore;
+def ext_bitfield_member_init_cxx2a : ExtWarn<
+ "in-class initialization of bit-field members is a C++2a extension">,
+ InGroup<CXX2a>;
+
// C++11 alias-declaration
def ext_alias_declaration : ExtWarn<
"alias declarations are a C++11 extension">, InGroup<CXX11>;
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/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<Expr *>(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,15 +2494,15 @@
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);
}
/// removeInClassInitializer - Remove the C++11 in-class initializer from this
/// 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
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits