From: John McCall Date: Fri, 10 Oct 2014 18:44:34 +0000 (+0000) Subject: Change how we distinguish bitfield widths, in-class X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=41b720df1646af74f68f4a18a93be8ead96234a9;p=clang Change how we distinguish bitfield widths, in-class initializers, and captured VLA types so that we can answer questions like "is this a bit-field" without looking at the enclosing DeclContext. NFC. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219522 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 8846d0ca8f..48e9ed2ccc 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2168,18 +2168,41 @@ class FieldDecl : public DeclaratorDecl, public Mergeable { bool Mutable : 1; mutable unsigned CachedFieldIndex : 31; - /// \brief An InClassInitStyle value, and either a bit width expression (if - /// the InClassInitStyle value is ICIS_NoInit) in struct/class, or a captured - /// variable length array bound in a lambda expression, or a pointer to the - /// in-class initializer for this field (otherwise). + /// The kinds of value we can store in InitializerOrBitWidth. /// - /// We can safely combine these two because in-class initializers are not - /// permitted for bit-fields. + /// 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, + + /// The pointer is an (optional due to delayed parsing) Expr* + /// holding the copy-initializer. + ISK_InClassCopyInit = (unsigned) ICIS_CopyInit, + + /// The pointer is an (optional due to delayed parsing) Expr* + /// holding the list-initializer. + ISK_InClassListInit = (unsigned) ICIS_ListInit, + + /// The pointer is a VariableArrayType* that's been captured; + /// the enclosing context is a lambda or captured statement. + ISK_CapturedVLAType, + }; + + /// \brief Storage for either the bit-width, 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. /// - /// If the InClassInitStyle is not ICIS_NoInit and the initializer is null, - /// then this field has an in-class initializer which has not yet been parsed + /// If the storage kind is ISK_InClassCopyInit or + /// ISK_InClassListInit, but the initializer is null, then this + /// field has an in-class initializer which has not yet been parsed /// and attached. - llvm::PointerIntPair InitializerOrBitWidth; + llvm::PointerIntPair InitStorage; protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, @@ -2187,7 +2210,7 @@ protected: InClassInitStyle InitStyle) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Mutable(Mutable), CachedFieldIndex(0), - InitializerOrBitWidth(BW, InitStyle) { + InitStorage(BW, (InitStorageKind) InitStyle) { assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield"); } @@ -2208,7 +2231,10 @@ public: bool isMutable() const { return Mutable; } /// \brief Determines whether this field is a bitfield. - bool isBitField() const; + bool isBitField() const { + return InitStorage.getInt() == ISK_BitWidthOrNothing && + InitStorage.getPointer() != nullptr; + } /// @brief Determines whether this is an unnamed bitfield. bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); } @@ -2221,25 +2247,33 @@ public: Expr *getBitWidth() const { return isBitField() - ? static_cast(InitializerOrBitWidth.getPointer()) + ? static_cast(InitStorage.getPointer()) : nullptr; } 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); + 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); + } + /// 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"); - InitializerOrBitWidth.setPointer(nullptr); + InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); } /// getInClassInitStyle - Get the kind of (C++11) in-class initializer which /// this field has. InClassInitStyle getInClassInitStyle() const { - return static_cast(InitializerOrBitWidth.getInt()); + InitStorageKind storageKind = InitStorage.getInt(); + return (storageKind == ISK_CapturedVLAType + ? ICIS_NoInit : (InClassInitStyle) storageKind); } /// hasInClassInitializer - Determine whether this member has a C++11 in-class @@ -2247,33 +2281,43 @@ public: bool hasInClassInitializer() const { return getInClassInitStyle() != ICIS_NoInit; } + /// getInClassInitializer - Get the C++11 in-class initializer for this /// member, or null if one has not been set. If a valid declaration has an /// in-class initializer, but this returns null, then we have not parsed and /// attached it yet. Expr *getInClassInitializer() const { return hasInClassInitializer() - ? static_cast(InitializerOrBitWidth.getPointer()) + ? static_cast(InitStorage.getPointer()) : nullptr; } + /// setInClassInitializer - Set the C++11 in-class initializer for this /// member. - void setInClassInitializer(Expr *Init); + void setInClassInitializer(Expr *Init) { + assert(hasInClassInitializer() && + InitStorage.getPointer() == nullptr && + "bit width, 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"); - InitializerOrBitWidth.setPointer(nullptr); - InitializerOrBitWidth.setInt(ICIS_NoInit); + InitStorage.setPointerAndInt(nullptr, ISK_BitWidthOrNothing); } /// \brief Determine whether this member captures the variable length array /// type. - bool hasCapturedVLAType() const; + bool hasCapturedVLAType() const { + return InitStorage.getInt() == ISK_CapturedVLAType; + } + /// \brief Get the captured variable length array type. const VariableArrayType *getCapturedVLAType() const { return hasCapturedVLAType() ? static_cast( - InitializerOrBitWidth.getPointer()) + InitStorage.getPointer()) : nullptr; } /// \brief Set the captured variable length array type for this field. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index aec7059490..e3e365ff0f 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3282,18 +3282,9 @@ bool FieldDecl::isAnonymousStructOrUnion() const { return false; } -bool FieldDecl::isBitField() const { - if (getInClassInitStyle() == ICIS_NoInit && - InitializerOrBitWidth.getPointer()) { - assert(getDeclContext() && "No parent context for FieldDecl"); - return !getDeclContext()->isRecord() || !getParent()->isLambda(); - } - return false; -} - unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const { assert(isBitField() && "not a bitfield"); - Expr *BitWidth = static_cast(InitializerOrBitWidth.getPointer()); + Expr *BitWidth = static_cast(InitStorage.getPointer()); return BitWidth->EvaluateKnownConstInt(Ctx).getZExtValue(); } @@ -3317,34 +3308,28 @@ unsigned FieldDecl::getFieldIndex() const { } SourceRange FieldDecl::getSourceRange() const { - if (const Expr *E = - static_cast(InitializerOrBitWidth.getPointer())) - return SourceRange(getInnerLocStart(), E->getLocEnd()); - return DeclaratorDecl::getSourceRange(); -} + switch (InitStorage.getInt()) { + // All three of these cases store an optional Expr*. + case ISK_BitWidthOrNothing: + case ISK_InClassCopyInit: + case ISK_InClassListInit: + if (const Expr *E = static_cast(InitStorage.getPointer())) + return SourceRange(getInnerLocStart(), E->getLocEnd()); + // FALLTHROUGH -void FieldDecl::setBitWidth(Expr *Width) { - assert(!InitializerOrBitWidth.getPointer() && !hasInClassInitializer() && - "bit width, initializer or captured type already set"); - InitializerOrBitWidth.setPointer(Width); -} - -void FieldDecl::setInClassInitializer(Expr *Init) { - assert(!InitializerOrBitWidth.getPointer() && hasInClassInitializer() && - "bit width, initializer or captured expr already set"); - InitializerOrBitWidth.setPointer(Init); -} - -bool FieldDecl::hasCapturedVLAType() const { - return getDeclContext()->isRecord() && getParent()->isLambda() && - InitializerOrBitWidth.getPointer(); + case ISK_CapturedVLAType: + return DeclaratorDecl::getSourceRange(); + } + llvm_unreachable("bad init storage kind"); } void FieldDecl::setCapturedVLAType(const VariableArrayType *VLAType) { assert(getParent()->isLambda() && "capturing type in non-lambda."); - assert(!InitializerOrBitWidth.getPointer() && !hasInClassInitializer() && + assert(InitStorage.getInt() == ISK_BitWidthOrNothing && + InitStorage.getPointer() == nullptr && "bit width, initializer or captured type already set"); - InitializerOrBitWidth.setPointer(const_cast(VLAType)); + InitStorage.setPointerAndInt(const_cast(VLAType), + ISK_CapturedVLAType); } //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 1c52b20096..93cd932a61 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1000,13 +1000,14 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { VisitDeclaratorDecl(FD); FD->Mutable = Record[Idx++]; if (int BitWidthOrInitializer = Record[Idx++]) { - FD->InitializerOrBitWidth.setInt(BitWidthOrInitializer - 1); - if (FD->getDeclContext()->isRecord() && FD->getParent()->isLambda()) { + FD->InitStorage.setInt( + static_cast(BitWidthOrInitializer - 1)); + if (FD->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) { // Read captured variable length array. - FD->InitializerOrBitWidth.setPointer( + FD->InitStorage.setPointer( Reader.readType(F, Record, Idx).getAsOpaquePtr()); } else { - FD->InitializerOrBitWidth.setPointer(Reader.ReadExpr(F)); + FD->InitStorage.setPointer(Reader.ReadExpr(F)); } } if (!FD->getDeclName()) { diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 0549851cbf..489996825b 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -677,18 +677,17 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { VisitDeclaratorDecl(D); Record.push_back(D->isMutable()); - if ((D->InitializerOrBitWidth.getInt() != ICIS_NoInit || - D->InitializerOrBitWidth.getPointer()) && - !D->hasCapturedVLAType()) { - Record.push_back(D->InitializerOrBitWidth.getInt() + 1); - Writer.AddStmt(static_cast(D->InitializerOrBitWidth.getPointer())); - } else if (D->hasCapturedVLAType()) { - Record.push_back(D->InitializerOrBitWidth.getInt() + 1); + if (D->InitStorage.getInt() == FieldDecl::ISK_BitWidthOrNothing && + D->InitStorage.getPointer() == nullptr) { + Record.push_back(0); + } else if (D->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) { + Record.push_back(D->InitStorage.getInt() + 1); Writer.AddTypeRef( - QualType(static_cast(D->InitializerOrBitWidth.getPointer()), 0), + QualType(static_cast(D->InitStorage.getPointer()), 0), Record); } else { - Record.push_back(0); + Record.push_back(D->InitStorage.getInt() + 1); + Writer.AddStmt(static_cast(D->InitStorage.getPointer())); } if (!D->getDeclName()) Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record);