diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/RecordLayoutBuilder.cpp | 232 | 
1 files changed, 225 insertions, 7 deletions
| diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 983a2874a73..0ede4bce20d 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -57,9 +57,23 @@ class EmptySubobjectMap {                              const BaseInfo *Derived);    void ComputeBaseInfo(); +  bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, uint64_t Offset); +  void AddSubobjectAtOffset(const CXXRecordDecl *RD, uint64_t Offset); +      bool CanPlaceBaseSubobjectAtOffset(const BaseInfo *Info, uint64_t Offset);    void UpdateEmptyBaseSubobjects(const BaseInfo *Info, uint64_t Offset); +  bool CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,  +                                      const CXXRecordDecl *Class, +                                      uint64_t Offset); +  bool CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, +                                      uint64_t Offset); +   +  void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,  +                                  const CXXRecordDecl *Class, +                                  uint64_t Offset); +  void UpdateEmptyFieldSubobjects(const FieldDecl *FD, uint64_t Offset); +    public:    /// This holds the size of the largest empty subobject (either a base    /// or a member). Will be zero if the record being built doesn't contain @@ -79,6 +93,10 @@ public:    /// (direct or indirect) of the same type having the same offset.    bool CanPlaceBaseAtOffset(const CXXRecordDecl *RD, bool BaseIsVirtual,                              uint64_t Offset); + +  /// CanPlaceFieldAtOffset - Return whether a field can be placed at the given +  /// offset. +  bool CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset);  };  void EmptySubobjectMap::ComputeEmptySubobjectSizes() { @@ -198,8 +216,43 @@ void EmptySubobjectMap::ComputeBaseInfo() {  }  bool +EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,  +                                             uint64_t Offset) { +  // We only need to check empty bases. +  if (!RD->isEmpty()) +    return true; + +  EmptyClassOffsetsMapTy::const_iterator I = EmptyClassOffsets.find(Offset); +  if (I == EmptyClassOffsets.end()) +    return true; +   +  const ClassVectorTy& Classes = I->second; +  if (std::find(Classes.begin(), Classes.end(), RD) == Classes.end()) +    return true; + +  // There is already an empty class of the same type at this offset. +  return false; +} +   +void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD,  +                                             uint64_t Offset) { +  // We only care about empty bases. +  if (!RD->isEmpty()) +    return; + +  ClassVectorTy& Classes = EmptyClassOffsets[Offset]; +  assert(std::find(Classes.begin(), Classes.end(), RD) == Classes.end() && +         "Duplicate empty class detected!"); +     +  Classes.push_back(RD); +} + +bool  EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseInfo *Info,                                                    uint64_t Offset) { +  if (!CanPlaceSubobjectAtOffset(Info->Class, Offset)) +    return false; +    // Traverse all non-virtual bases.    for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) {      BaseInfo* Base = Info->Bases[I]; @@ -224,15 +277,26 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseInfo *Info,      }    } -  // FIXME: Member variables. +  const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class); + +  // Traverse all member variables. +  unsigned FieldNo = 0; +  for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(),  +       E = Info->Class->field_end(); I != E; ++I, ++FieldNo) { +    const FieldDecl *FD = *I; +     +    uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo); +     +    if (!CanPlaceFieldSubobjectAtOffset(FD, FieldOffset)) +      return false; +  } +      return true;  }  void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseInfo *Info,                                                     uint64_t Offset) { -  if (Info->Class->isEmpty()) { -    // FIXME: Record that there is an empty class at this offset. -  } +  AddSubobjectAtOffset(Info->Class, Offset);    // Traverse all non-virtual bases.    for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) { @@ -254,8 +318,19 @@ void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseInfo *Info,      if (Info == PrimaryVirtualBaseInfo->Derived)        UpdateEmptyBaseSubobjects(PrimaryVirtualBaseInfo, Offset);    } -   -  // FIXME: Member variables. + +  const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class); + +  // Traverse all member variables. +  unsigned FieldNo = 0; +  for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(),  +       E = Info->Class->field_end(); I != E; ++I, ++FieldNo) { +    const FieldDecl *FD = *I; +     +    uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo); +     +    UpdateEmptyFieldSubobjects(FD, FieldOffset); +  }  }  bool EmptySubobjectMap::CanPlaceBaseAtOffset(const CXXRecordDecl *RD, @@ -275,11 +350,154 @@ bool EmptySubobjectMap::CanPlaceBaseAtOffset(const CXXRecordDecl *RD,    if (!CanPlaceBaseSubobjectAtOffset(Info, Offset))      return false; -   + +  // We are able to place the base at this offset. Make sure to update the +  // empty base subobject map.    UpdateEmptyBaseSubobjects(Info, Offset);    return true;  } +bool +EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,  +                                                  const CXXRecordDecl *Class, +                                                  uint64_t Offset) { +  if (!CanPlaceSubobjectAtOffset(RD, Offset)) +    return false; +   +  const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + +  // Traverse all non-virtual bases. +  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), +       E = RD->bases_end(); I != E; ++I) { +    if (I->isVirtual()) +      continue; + +    const CXXRecordDecl *BaseDecl = +      cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + +    uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); +    if (!CanPlaceFieldSubobjectAtOffset(BaseDecl, Class, BaseOffset)) +      return false; +  } + +  // Traverse all member variables. +  unsigned FieldNo = 0; +  for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); +       I != E; ++I, ++FieldNo) { +    const FieldDecl *FD = *I; +     +    uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo); +     +    if (!CanPlaceFieldSubobjectAtOffset(FD, FieldOffset)) +      return false; +  } + +  return true; +} + +bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, +                                                       uint64_t Offset) { +  QualType T = FD->getType(); +  if (const RecordType *RT = T->getAs<RecordType>()) { +    const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); +    return CanPlaceFieldSubobjectAtOffset(RD, RD, Offset); +  } + +  // If we have an array type we need to look at every element. +  if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { +    QualType ElemTy = Context.getBaseElementType(AT); +    const RecordType *RT = ElemTy->getAs<RecordType>(); +    if (!RT) +      return true; +   +    const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); +    const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + +    uint64_t NumElements = Context.getConstantArrayElementCount(AT); +    uint64_t ElementOffset = Offset; +    for (uint64_t I = 0; I != NumElements; ++I) { +      if (!CanPlaceFieldSubobjectAtOffset(RD, RD, ElementOffset)) +        return false; + +      ElementOffset += Layout.getSize(); +    } +  } + +  return true; +} + +bool +EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) { +  if (!CanPlaceFieldSubobjectAtOffset(FD, Offset)) +    return false; +   +  // We are able to place the member variable at this offset. +  // Make sure to update the empty base subobject map. +  UpdateEmptyFieldSubobjects(FD, Offset); +  return true; +} + +void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,  +                                                   const CXXRecordDecl *Class, +                                                   uint64_t Offset) { +  AddSubobjectAtOffset(RD, Offset); + +  const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + +  // Traverse all non-virtual bases. +  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), +       E = RD->bases_end(); I != E; ++I) { +    if (I->isVirtual()) +      continue; + +    const CXXRecordDecl *BaseDecl = +      cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + +    uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); +    UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset); +  } + +  // Traverse all member variables. +  unsigned FieldNo = 0; +  for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); +       I != E; ++I, ++FieldNo) { +    const FieldDecl *FD = *I; +     +    uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo); + +    UpdateEmptyFieldSubobjects(FD, FieldOffset); +  } +} +   +void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD, +                                                   uint64_t Offset) { +  QualType T = FD->getType(); +  if (const RecordType *RT = T->getAs<RecordType>()) { +    const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); +    UpdateEmptyFieldSubobjects(RD, RD, Offset); +    return; +  } + +  // If we have an array type we need to update every element. +  if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { +    QualType ElemTy = Context.getBaseElementType(AT); +    const RecordType *RT = ElemTy->getAs<RecordType>(); +    if (!RT) +      return; +     +    const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); +    const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); +     +    uint64_t NumElements = Context.getConstantArrayElementCount(AT); +    uint64_t ElementOffset = Offset; +     +    for (uint64_t I = 0; I != NumElements; ++I) { +      UpdateEmptyFieldSubobjects(RD, RD, ElementOffset); +      ElementOffset += Layout.getSize(); +    } +  } +} +  class RecordLayoutBuilder {    // FIXME: Remove this and make the appropriate fields public.    friend class clang::ASTContext; | 

