/// Represents a member of a struct/union/class.
class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
- unsigned BitField : 1;
- unsigned Mutable : 1;
- mutable unsigned CachedFieldIndex : 30;
-
- /// The kinds of value we can store in InitializerOrBitWidth.
+ /// The kinds of value we can store in StorageKind.
///
/// Note that this is compatible with InClassInitStyle except for
/// ISK_CapturedVLAType.
ISK_CapturedVLAType,
};
+ unsigned BitField : 1;
+ unsigned Mutable : 1;
+ unsigned StorageKind : 2;
+ mutable unsigned CachedFieldIndex : 28;
+
/// If this is a bitfield with a default member initializer, this
/// structure is used to represent the two expressions.
- struct InitAndBitWidth {
- Expr *Init;
+ struct InitAndBitWidthStorage {
+ LazyDeclStmtPtr Init;
Expr *BitWidth;
};
/// and attached.
// FIXME: Tail-allocate this to reduce the size of FieldDecl in the
// overwhelmingly common case that we have none of these things.
- llvm::PointerIntPair<void *, 2, InitStorageKind> InitStorage;
+ union {
+ // Active member if ISK is not ISK_CapturedVLAType and BitField is false.
+ LazyDeclStmtPtr Init;
+ // Active member if ISK is ISK_NoInit and BitField is true.
+ Expr *BitWidth;
+ // Active member if ISK is ISK_InClass*Init and BitField is true.
+ InitAndBitWidthStorage *InitAndBitWidth;
+ // Active member if ISK is ISK_CapturedVLAType.
+ const VariableArrayType *CapturedVLAType;
+ };
protected:
FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
+ SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
InClassInitStyle InitStyle)
- : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
- BitField(false), Mutable(Mutable), CachedFieldIndex(0),
- InitStorage(nullptr, (InitStorageKind) InitStyle) {
+ : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), BitField(false),
+ Mutable(Mutable), StorageKind((InitStorageKind)InitStyle),
+ CachedFieldIndex(0), Init() {
if (BW)
setBitWidth(BW);
}
Expr *getBitWidth() const {
if (!BitField)
return nullptr;
- void *Ptr = InitStorage.getPointer();
- if (getInClassInitStyle())
- return static_cast<InitAndBitWidth*>(Ptr)->BitWidth;
- return static_cast<Expr*>(Ptr);
+ return hasInClassInitializer() ? InitAndBitWidth->BitWidth : BitWidth;
}
unsigned getBitWidthValue(const ASTContext &Ctx) const;
assert(!hasCapturedVLAType() && !BitField &&
"bit width or captured type already set");
assert(Width && "no bit width specified");
- InitStorage.setPointer(
- InitStorage.getInt()
- ? new (getASTContext())
- InitAndBitWidth{getInClassInitializer(), Width}
- : static_cast<void*>(Width));
+ if (hasInClassInitializer())
+ InitAndBitWidth =
+ new (getASTContext()) InitAndBitWidthStorage{Init, Width};
+ else
+ BitWidth = Width;
BitField = true;
}
// Note: used by some clients (i.e., do not remove it).
void removeBitWidth() {
assert(isBitField() && "no bitfield width to remove");
- InitStorage.setPointer(getInClassInitializer());
+ if (hasInClassInitializer()) {
+ // Read the old initializer before we change the active union member.
+ auto ExistingInit = InitAndBitWidth->Init;
+ Init = ExistingInit;
+ }
BitField = false;
}
/// Get the kind of (C++11) default member initializer that this field has.
InClassInitStyle getInClassInitStyle() const {
- InitStorageKind storageKind = InitStorage.getInt();
- return (storageKind == ISK_CapturedVLAType
- ? ICIS_NoInit : (InClassInitStyle) storageKind);
+ return (StorageKind == ISK_CapturedVLAType ? ICIS_NoInit
+ : (InClassInitStyle)StorageKind);
}
/// Determine whether this member has a C++11 default member initializer.
return getInClassInitStyle() != ICIS_NoInit;
}
+ /// Determine whether getInClassInitializer() would return a non-null pointer
+ /// without deserializing the initializer.
+ bool hasNonNullInClassInitializer() const {
+ return hasInClassInitializer() && (BitField ? InitAndBitWidth->Init : Init);
+ }
+
/// Get the C++11 default member initializer for this member, or null if one
/// has not been set. If a valid declaration has a default member initializer,
/// but this returns null, then we have not parsed and attached it yet.
- Expr *getInClassInitializer() const {
- if (!hasInClassInitializer())
- return nullptr;
- void *Ptr = InitStorage.getPointer();
- if (BitField)
- return static_cast<InitAndBitWidth*>(Ptr)->Init;
- return static_cast<Expr*>(Ptr);
- }
+ Expr *getInClassInitializer() const;
/// Set the C++11 in-class initializer for this member.
- void setInClassInitializer(Expr *Init) {
- assert(hasInClassInitializer() && !getInClassInitializer());
- if (BitField)
- static_cast<InitAndBitWidth*>(InitStorage.getPointer())->Init = Init;
- else
- InitStorage.setPointer(Init);
- }
+ void setInClassInitializer(Expr *NewInit);
+
+private:
+ void setLazyInClassInitializer(LazyDeclStmtPtr NewInit);
+public:
/// Remove the C++11 in-class initializer from this member.
void removeInClassInitializer() {
assert(hasInClassInitializer() && "no initializer to remove");
- InitStorage.setPointerAndInt(getBitWidth(), ISK_NoInit);
+ StorageKind = ISK_NoInit;
+ if (BitField) {
+ // Read the bit width before we change the active union member.
+ Expr *ExistingBitWidth = InitAndBitWidth->BitWidth;
+ BitWidth = ExistingBitWidth;
+ }
}
/// Determine whether this member captures the variable length array
/// type.
bool hasCapturedVLAType() const {
- return InitStorage.getInt() == ISK_CapturedVLAType;
+ return StorageKind == ISK_CapturedVLAType;
}
/// Get the captured variable length array type.
const VariableArrayType *getCapturedVLAType() const {
- return hasCapturedVLAType() ? static_cast<const VariableArrayType *>(
- InitStorage.getPointer())
- : nullptr;
+ return hasCapturedVLAType() ? CapturedVLAType : nullptr;
}
/// Set the captured variable length array type for this field.
return false;
}
+Expr *FieldDecl::getInClassInitializer() const {
+ if (!hasInClassInitializer())
+ return nullptr;
+
+ LazyDeclStmtPtr InitPtr = BitField ? InitAndBitWidth->Init : Init;
+ return cast_or_null<Expr>(
+ InitPtr.isOffset() ? InitPtr.get(getASTContext().getExternalSource())
+ : InitPtr.get(nullptr));
+}
+
+void FieldDecl::setInClassInitializer(Expr *NewInit) {
+ setLazyInClassInitializer(LazyDeclStmtPtr(NewInit));
+}
+
+void FieldDecl::setLazyInClassInitializer(LazyDeclStmtPtr NewInit) {
+ assert(hasInClassInitializer() && !getInClassInitializer());
+ if (BitField)
+ InitAndBitWidth->Init = NewInit;
+ else
+ Init = NewInit;
+}
+
unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const {
assert(isBitField() && "not a bitfield");
return getBitWidth()->EvaluateKnownConstInt(Ctx).getZExtValue();
for (auto *Field : RD->fields()) {
Field->getCanonicalDecl()->CachedFieldIndex = Index + 1;
+ assert(Field->getCanonicalDecl()->CachedFieldIndex == Index + 1 &&
+ "overflow in field numbering");
++Index;
}
void FieldDecl::setCapturedVLAType(const VariableArrayType *VLAType) {
assert((getParent()->isLambda() || getParent()->isCapturedRecord()) &&
"capturing type in non-lambda or captured record.");
- assert(InitStorage.getInt() == ISK_NoInit &&
- InitStorage.getPointer() == nullptr &&
- "bit width, initializer or captured type already set");
- InitStorage.setPointerAndInt(const_cast<VariableArrayType *>(VLAType),
- ISK_CapturedVLAType);
+ assert(StorageKind == ISK_NoInit && !BitField &&
+ "bit-field or field with default member initializer cannot capture "
+ "VLA type");
+ StorageKind = ISK_CapturedVLAType;
+ CapturedVLAType = VLAType;
}
//===----------------------------------------------------------------------===//
ID->TypeForDecl = Reader.GetType(DeferredTypeID).getTypePtrOrNull();
} else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
// FunctionDecl's body was written last after all other Stmts/Exprs.
- // We only read it if FD doesn't already have a body (e.g., from another
- // module).
- // FIXME: Can we diagnose ODR violations somehow?
if (Record.readInt())
ReadFunctionDefinition(FD);
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
ReadVarDeclInit(VD);
+ } else if (auto *FD = dyn_cast<FieldDecl>(D)) {
+ if (FD->hasInClassInitializer() && Record.readInt()) {
+ FD->setLazyInClassInitializer(LazyDeclStmtPtr(GetCurrentCursorOffset()));
+ }
}
}
VisitDeclaratorDecl(FD);
FD->Mutable = Record.readInt();
- if (auto ISK = static_cast<FieldDecl::InitStorageKind>(Record.readInt())) {
- FD->InitStorage.setInt(ISK);
- FD->InitStorage.setPointer(ISK == FieldDecl::ISK_CapturedVLAType
- ? Record.readType().getAsOpaquePtr()
- : Record.readExpr());
- }
-
- if (auto *BW = Record.readExpr())
- FD->setBitWidth(BW);
+ unsigned Bits = Record.readInt();
+ FD->StorageKind = Bits >> 1;
+ if (FD->StorageKind == FieldDecl::ISK_CapturedVLAType)
+ FD->CapturedVLAType =
+ cast<VariableArrayType>(Record.readType().getTypePtr());
+ else if (Bits & 1)
+ FD->setBitWidth(Record.readExpr());
if (!FD->getDeclName()) {
if (auto *Tmpl = readDeclAs<FieldDecl>())
// Only apply the update if the field still has an uninstantiated
// default member initializer.
- if (FD->hasInClassInitializer() && !FD->getInClassInitializer()) {
+ if (FD->hasInClassInitializer() && !FD->hasNonNullInClassInitializer()) {
if (DefaultInit)
FD->setInClassInitializer(DefaultInit);
else
Record.AddVarDeclInit(VD);
}
+ // And similarly for FieldDecls. We already serialized whether there is a
+ // default member initializer.
+ if (auto *FD = dyn_cast<FieldDecl>(D)) {
+ if (FD->hasInClassInitializer()) {
+ if (Expr *Init = FD->getInClassInitializer()) {
+ Record.push_back(1);
+ Record.AddStmt(Init);
+ } else {
+ Record.push_back(0);
+ // Initializer has not been instantiated yet.
+ }
+ }
+ }
+
// If this declaration is also a DeclContext, write blocks for the
// declarations that lexically stored inside its context and those
// declarations that are visible from its context.
VisitDeclaratorDecl(D);
Record.push_back(D->isMutable());
- FieldDecl::InitStorageKind ISK = D->InitStorage.getInt();
- Record.push_back(ISK);
- if (ISK == FieldDecl::ISK_CapturedVLAType)
+ Record.push_back((D->StorageKind << 1) | D->BitField);
+ if (D->StorageKind == FieldDecl::ISK_CapturedVLAType)
Record.AddTypeRef(QualType(D->getCapturedVLAType(), 0));
- else if (ISK)
- Record.AddStmt(D->getInClassInitializer());
-
- Record.AddStmt(D->getBitWidth());
+ else if (D->BitField)
+ Record.AddStmt(D->getBitWidth());
if (!D->getDeclName())
Record.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType
// FieldDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
- Abv->Add(BitCodeAbbrevOp(0)); // InitStyle
+ Abv->Add(BitCodeAbbrevOp(0)); // StorageKind
// Type Source Info
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc