Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -47,6 +47,7 @@ namespace clang { class FileManager; + class AllocationUnit; class AtomicExpr; class ASTRecordLayout; class BlockExpr; @@ -1827,6 +1828,8 @@ /// Get the offset of a FieldDecl or IndirectFieldDecl, in bits. uint64_t getFieldOffset(const ValueDecl *FD) const; + AllocationUnit getBitFieldAllocationUnit(const ValueDecl *FD) const; + bool isNearlyEmpty(const CXXRecordDecl *RD) const; VTableContextBase *getVTableContext(); Index: include/clang/AST/RecordLayout.h =================================================================== --- include/clang/AST/RecordLayout.h +++ include/clang/AST/RecordLayout.h @@ -24,6 +24,24 @@ class RecordDecl; class CXXRecordDecl; +/// AllocationUnit - Contains the offset and size of the allocation +/// unit in which a bitfield is allocated +class AllocationUnit { +public: + AllocationUnit() + { + } + + AllocationUnit(CharUnits Offset, CharUnits Size) : + Offset(Offset), + Size(Size) + { + } + + CharUnits Offset; + CharUnits Size; +}; + /// ASTRecordLayout - /// This class contains layout information for one RecordDecl, /// which is a struct/union/class. The decl represented must be a definition, @@ -76,6 +94,14 @@ // FieldCount - Number of fields. unsigned FieldCount; + /// AllocationUnits - Array of allocation units for bitfields. + /// The elements of the AllocationUnitIndices array index into this. + AllocationUnit *AllocationUnits; + + /// AllocationUnitIndices - Array of allocation unit indices for bitfields, + /// indexed by field index. + unsigned *AllocationUnitIndices; + /// CXXRecordLayoutInfo - Contains C++ specific layout information. struct CXXRecordLayoutInfo { /// NonVirtualSize - The non-virtual size (in chars) of an object, which is @@ -138,7 +164,10 @@ ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, CharUnits requiredAlignment, CharUnits datasize, const uint64_t *fieldoffsets, - unsigned fieldcount); + unsigned fieldcount, + const AllocationUnit *allocationUnits, + unsigned allocationUnitCount, + const int *allocationUnitIndices); // Constructor for C++ records. typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy; @@ -149,6 +178,9 @@ CharUnits vbptroffset, CharUnits datasize, const uint64_t *fieldoffsets, unsigned fieldcount, + const AllocationUnit *allocationUnits, + unsigned allocationUnitCount, + const int *allocationUnitIndices, CharUnits nonvirtualsize, CharUnits nonvirtualalignment, CharUnits SizeOfLargestEmptySubobject, const CXXRecordDecl *PrimaryBase, @@ -183,6 +215,17 @@ return FieldOffsets[FieldNo]; } + /// getBitFieldAllocationUnit - Get the allocation unit in which the given + /// bitfield was allocated. + const AllocationUnit &getBitFieldAllocationUnit(unsigned FieldNo) const { + assert(FieldNo < FieldCount && "Invalid Field No"); + assert(AllocationUnits != nullptr && "Field is not a bitfield"); + int AllocationUnitIndex = AllocationUnitIndices[FieldNo]; + assert(AllocationUnitIndex >= 0 && + "Field is not a bitfield"); + return AllocationUnits[AllocationUnitIndex]; + } + /// getDataSize() - Get the record data size, which is the record size /// without tail padding, in characters. CharUnits getDataSize() const { Index: include/clang/CodeGen/CodeViewTypeTable.h =================================================================== --- /dev/null +++ include/clang/CodeGen/CodeViewTypeTable.h @@ -0,0 +1,328 @@ +#ifndef LLVM_CLANG_CODEGEN_CODEVIEWTYPETABLE_H +#define LLVM_CLANG_CODEGEN_CODEVIEWTYPETABLE_H + +#include "llvm/ADT/iterator.h" +#include "llvm/CodeView/FieldListRecordBuilder.h" +#include "llvm/CodeView/TypeSymbolEmitter.h" +#include "llvm/CodeView/TypeTableBuilder.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/VTableBuilder.h" +#include "clang/Basic/TargetInfo.h" +#include +#include +#include + +namespace clang { +namespace CodeGen { + +class TagTypeIndices +{ +public: + llvm::codeview::TypeIndex DeclarationTI; + llvm::codeview::TypeIndex DefinitionTI; +}; + +class CodeViewTypeTable +{ +private: + typedef std::list DeclList; + + class VirtualMethodInfo + { + public: + VirtualMethodInfo(llvm::codeview::MethodKind Kind, int32_t SlotOffset) : + Kind(Kind), + SlotOffset(SlotOffset) + { + } + + llvm::codeview::MethodKind getKind() const { return Kind; } + int32_t getSlotOffset() const { return SlotOffset; } + + private: + llvm::codeview::MethodKind Kind; + int32_t SlotOffset; + }; + + class FieldList; + class MethodListHelper; + + typedef std::map + DefinitionMapTy; + typedef std::map TagTypeMap; + +public: + typedef DefinitionMapTy::const_iterator iterator; + typedef llvm::iterator_range range; + + class referenced_tag_iterator : public llvm::iterator_adaptor_base< + referenced_tag_iterator, TagTypeMap::const_iterator, + std::bidirectional_iterator_tag, const TagDecl* const> + { + friend class CodeViewTypeTable; + + private: + referenced_tag_iterator(TagTypeMap::const_iterator I) : + iterator_adaptor_base(I) + { + } + + public: + reference operator*() const + { + return I->first; + } + }; + + typedef llvm::iterator_range referenced_tag_range; + +private: + CodeViewTypeTable(const CodeViewTypeTable&) = delete; + void operator=(const CodeViewTypeTable&) = delete; + +public: + CodeViewTypeTable(llvm::codeview::TypeTableBuilder& Builder, + ASTContext& Context, MangleContext& MContext); + +public: + llvm::codeview::TypeIndex getTypeIndex(QualType Type); + llvm::codeview::TypeIndex getTypeIndexForDefinition(QualType Type); + llvm::codeview::TypeIndex getTypeIndexForFunctionType( + const FunctionDecl* Decl, bool Pointer, bool IgnoreConstructorFlags); + llvm::codeview::TypeIndex getTypeIndexForPlainPointerToMemberFunction( + const MemberPointerType* Ty); + llvm::codeview::TypeIndex getTypeIndexForMemberFunctionType( + const CXXRecordDecl* ClassDecl, const FunctionProtoType* FuncType); + + TagTypeIndices getTypeIndexForTypeDescriptor(uint32_t ExtraBytes); + TagTypeIndices getTypeIndexForThrowInfo(); + TagTypeIndices getTypeIndexForCatchableTypeArray(); + TagTypeIndices getTypeIndexForCatchableTypeArray(uint32_t Count); + TagTypeIndices getTypeIndexForCatchableType(); + TagTypeIndices getTypeIndexForTypeDescriptor(); + + llvm::codeview::TypeIndex getPointerToConstType( + llvm::codeview::TypeIndex ReferentType); + + void finishDefinitions(); + + range getDefinitions() const + { + return llvm::make_range(DefinitionMap.begin(), DefinitionMap.end()); + } + + size_t getDefinitionCount() const + { + return DefinitionMap.size(); + } + + referenced_tag_range referenced_tags() const + { + return referenced_tag_range(referenced_tag_iterator(TagTypes.cbegin()), + referenced_tag_iterator(TagTypes.cend())); + } + + void emitTypeSymbolsForTag(const TagDecl* D, + llvm::codeview::TypeSymbolEmitter& Emitter); + +private: + llvm::codeview::TypeIndex getCachedTypeIndex(QualType Type); + void setCachedTypeIndex(QualType Type, llvm::codeview::TypeIndex TypeInd); + + TagTypeIndices getTypeIndexForPMD(); + + uint32_t writeTypeDescriptorFields( + llvm::codeview::FieldListRecordBuilder& Fields, uint32_t ExtraBytes); + uint32_t writeCatchableTypeArrayFields( + llvm::codeview::FieldListRecordBuilder& Fields, uint32_t Count); + + TagTypeIndices computeTypeIndexForBuiltinStruct(llvm::StringRef Name, + llvm::StringRef UniqueName, uint32_t Size, + llvm::codeview::FieldListRecordBuilder& Fields, uint16_t MemberCount); + + llvm::codeview::TypeIndex getTypeIndexForFunctionType( + const FunctionDecl* Decl, bool IgnoreConstructorFlags); + + llvm::codeview::TypeIndex computeTypeIndex(QualType Type); + llvm::codeview::SimpleTypeKind computeSimpleTypeKindForBuiltinType( + const BuiltinType* Type); + llvm::codeview::TypeIndex computeTypeIndexForModifiedType(QualType Type); + llvm::codeview::TypeIndex computeTypeIndexForBuiltinType( + const BuiltinType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForFunctionType( + const FunctionType* Type); + llvm::codeview::TypeIndex computeTypeIndexForPointerOrReferenceType( + QualType Type, llvm::codeview::PointerMode Mode); + llvm::codeview::TypeIndex computeTypeIndexForConstantArrayType( + QualType Type); + llvm::codeview::TypeIndex computeTypeIndexForIncompleteArrayType( + QualType Type); + llvm::codeview::TypeIndex computeTypeIndexForEnumType( + const EnumType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForEnumDeclaration( + const EnumDecl* D); + llvm::codeview::TypeIndex computeTypeIndexForEnumDefinition( + const EnumDecl* D); + llvm::codeview::TypeIndex computeTypeIndexForRecordType( + const RecordType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForRecordDeclaration( + const RecordDecl* D, llvm::codeview::TypeRecordKind Kind); + llvm::codeview::TypeIndex computeTypeIndexForRecordDefinition( + const RecordDecl* D, llvm::codeview::TypeRecordKind Kind); + llvm::codeview::TypeIndex computeTypeIndexForTypedefType( + const TypedefType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForDecayedType( + const DecayedType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForParenType( + const ParenType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForElaboratedType( + const ElaboratedType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForAttributedType( + const AttributedType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForSubstTemplateTypeParm( + const SubstTemplateTypeParmType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForTemplateSpecialization( + const TemplateSpecializationType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForMemberPointer( + const MemberPointerType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForVector( + const VectorType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForAuto( + const AutoType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForDecltype( + const DecltypeType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForAdjusted( + const AdjustedType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForTypeOf( + const TypeOfType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForTypeOfExpr( + const TypeOfExprType* Type, unsigned int CVR); + llvm::codeview::TypeIndex computeTypeIndexForInjectedClassName( + const InjectedClassNameType* Type, unsigned int CVR); + + llvm::codeview::TypeIndex computeTypeIndexForTagDeclaration( + const TagDecl* D); + llvm::codeview::TypeIndex computeTypeIndexForTagDefinition( + const TagDecl* D); + llvm::codeview::TypeIndex computeTypeIndexForMemberFunctionType( + const CXXRecordDecl* ClassDecl, const FunctionProtoType* FuncType, + llvm::codeview::FunctionOptions Options, bool IsStatic); + llvm::codeview::TypeIndex computeTypeIndexForVTableShape( + const CXXRecordDecl* D); + + llvm::codeview::TypeIndex getTypeIndexForTagDeclaration(const TagDecl* D); + llvm::codeview::TypeIndex getTypeIndexForTagDefinition(const TagDecl* D); + + llvm::codeview::TypeIndex computeModifiedTypeIndex( + llvm::codeview::TypeIndex TypeInd, unsigned int CVR); + + void emitRecordForMethodDecls(FieldList& Fields, DeclarationName DN, + const CXXMethodDecl* const* Decls, size_t Count); + void emitRecordForMemberDecl(FieldList& Fields, const Decl* D); + void emitRecordForFieldDecl(FieldList& Fields, const FieldDecl* D); + void emitRecordForFieldDecl(FieldList& Fields, const FieldDecl* D, + const ValueDecl* VD, llvm::codeview::MemberAccess Access); + void emitRecordForIndirectFieldDecl(FieldList& Fields, + const IndirectFieldDecl* D); + void emitRecordForStaticFieldDecl(FieldList& Fields, const VarDecl* D); + void emitRecordForBaseClass(FieldList& Fields, const CXXRecordDecl* D, + const CXXBaseSpecifier& Base, bool isIndirect); + void emitRecordForNestedType(FieldList& Fields, const TypeDecl* D); + void emitRecordForVectorDeletingDestructor(FieldList& Fields, + const CXXDestructorDecl* D); + void emitRecordForLocalVftableConstructorClosure(FieldList& Fields, + const CXXRecordDecl* D); + void emitRecordsForImplicitConstructors(MethodListHelper& Methods, + const CXXRecordDecl* RD, const CXXMethodDecl* const* Decls, size_t Count); + void emitRecordsForImplicitAssignmentOperators(MethodListHelper& Methods, + const CXXRecordDecl* RD, const CXXMethodDecl* const* Decls, size_t Count); + + void emitBaseClasses(FieldList& Fields, const RecordDecl* D); + + std::string computeTagName(const TagDecl* D); + std::string computeTagUniqueName(const TagDecl* D); + std::string computeTypeUniqueName(QualType Ty); + llvm::codeview::ClassOptions computeTagClassOptions(const TagDecl* D); + + llvm::codeview::TypeIndex getVirtualBasePointerTypeIndex(); + + llvm::codeview::WindowsRTClassKind getWindowsRTClassKind(const RecordDecl* D) + { + return llvm::codeview::WindowsRTClassKind::None; + } + + llvm::codeview::TypeIndex computeProcedureType( + llvm::codeview::TypeIndex ReturnType, + llvm::ArrayRef ArgumentTypes); + + llvm::codeview::TypeIndex computeProcedurePointerType( + llvm::codeview::TypeIndex ReturnType, + llvm::ArrayRef ArgumentTypes); + + void setDefinitionForDeclaration( + llvm::codeview::TypeIndex DeclarationTypeInd, + llvm::codeview::TypeIndex DefinitionTypeInd); + + llvm::codeview::HfaKind computeHfaKind(const RecordDecl* D) const; + llvm::codeview::HfaKind computeHfaKind(QualType Ty) const; + + llvm::codeview::MethodInfo computeMethodInfo(const CXXMethodDecl* D); + llvm::codeview::MethodInfo computeImplicitConstructorInfo( + const CXXRecordDecl* RD, llvm::ArrayRef ParamTypes); + llvm::codeview::MethodInfo computeImplicitAssignmentInfo( + const CXXRecordDecl* RD, llvm::ArrayRef ParamTypes); + + int32_t computeVTableSlotOffset(const CXXMethodDecl* D) const; + VirtualMethodInfo computeVirtualMethodInfo(const CXXMethodDecl* D, + bool ForceIntro) const; + + uint32_t getPointerByteSize() const + { + uint32_t BitSize = Context.getTargetInfo().getPointerWidth(0); + return Context.toCharUnitsFromBits(BitSize).getQuantity(); + } + + llvm::codeview::PointerOptions computePointerOptions(unsigned int CVR) const; + + QualType computeThisType(const CXXRecordDecl* D, + const FunctionProtoType* FuncTy) const; + + CallingConv getThisCallCallingConv() const { + if (getPointerByteSize() == 8) { + return CallingConv::CC_C; + } + else { + return CallingConv::CC_X86ThisCall; + } + } + + static void gatherMemberDecls(const RecordDecl* D, DeclList& Members); + +private: + llvm::codeview::TypeTableBuilder& Builder; + ASTContext& Context; + MicrosoftVTableContext& VTableContext; + MangleContext& MContext; + + llvm::codeview::TypeIndex ArrayIndexTI; + llvm::codeview::TypeIndex VoidPointerTI; + llvm::codeview::PointerKind DefaultPointerKind; + + std::map Types; + DefinitionMapTy DefinitionMap; + TagTypeMap TagTypes; + std::vector PendingTags; + llvm::codeview::TypeIndex VirtualBasePointerTI; + std::map TypeDescriptorTypes; + std::map CatchableTypeArrayTypes; + TagTypeIndices PmdTIs; + TagTypeIndices TypeDescriptorTIs; + TagTypeIndices CatchableTypeTIs; + TagTypeIndices CatchableTypeArrayTIs; + TagTypeIndices ThrowInfoTIs; +}; + +} +} + +#endif Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -329,6 +329,8 @@ } } // unnamed namespace +#pragma optimize("", off) +// FIXME: Disable optimizations for this function until devdiv:1210441 is fixed. const RawComment *ASTContext::getRawCommentForAnyRedecl( const Decl *D, const Decl **OriginalDecl) const { @@ -397,6 +399,7 @@ return RC; } +#pragma optimize("", on) static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod, SmallVectorImpl &Redeclared) { @@ -4991,8 +4994,8 @@ bool ASTContext::isMSStaticDataMemberInlineDefinition(const VarDecl *VD) const { return getLangOpts().MSVCCompat && VD->isStaticDataMember() && - VD->getType()->isIntegralOrEnumerationType() && - VD->isFirstDecl() && !VD->isOutOfLine() && VD->hasInit(); + VD->getType()->isIntegralOrEnumerationType() && + VD->isFirstDecl() && !VD->isOutOfLine() && VD->hasInit(); } static inline @@ -6202,7 +6205,7 @@ llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 4); QualType IntArrayType = Context->getConstantArrayType(Context->IntTy, - Size, ArrayType::Normal, 0); + Size, ArrayType::Normal, 0); return Context->buildImplicitTypedef(IntArrayType, "__builtin_va_list"); } @@ -8213,7 +8216,7 @@ return External; if ((!Context.getLangOpts().CPlusPlus && !Context.getLangOpts().MSVCCompat && - !FD->hasAttr()) || + !FD->hasAttr()) || FD->hasAttr()) { // FIXME: This doesn't match gcc's behavior for dllexport inline functions. Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -409,10 +409,6 @@ // first, since it is most likely to be the declaration in a header file. FD = FD->getFirstDecl(); - // We should never ever see a FunctionNoProtoType at this point. - // We don't even know how to mangle their types anyway :). - const FunctionProtoType *FT = FD->getType()->castAs(); - // extern "C" functions can hold entities that must be mangled. // As it stands, these functions still need to get expressed in the full // external name. They have their class and type omitted, replaced with '9'. @@ -426,7 +422,7 @@ mangleFunctionClass(FD); - mangleFunctionType(FT, FD); + mangleFunctionType(FD->getFunctionType(), FD); } else { Out << '9'; } Index: lib/AST/RecordLayout.cpp =================================================================== --- lib/AST/RecordLayout.cpp +++ lib/AST/RecordLayout.cpp @@ -33,14 +33,24 @@ CharUnits requiredAlignment, CharUnits datasize, const uint64_t *fieldoffsets, - unsigned fieldcount) + unsigned fieldcount, + const AllocationUnit *allocationUnits, + unsigned allocationUnitCount, + const int *allocationUnitIndices) : Size(size), DataSize(datasize), Alignment(alignment), RequiredAlignment(requiredAlignment), FieldOffsets(nullptr), - FieldCount(fieldcount), CXXInfo(nullptr) { + FieldCount(fieldcount), AllocationUnits(nullptr), + AllocationUnitIndices(nullptr), CXXInfo(nullptr) { if (FieldCount > 0) { FieldOffsets = new (Ctx) uint64_t[FieldCount]; memcpy(FieldOffsets, fieldoffsets, FieldCount * sizeof(*FieldOffsets)); } + if (allocationUnitCount > 0) { + AllocationUnits = new (Ctx) AllocationUnit[allocationUnitCount]; + std::copy_n(allocationUnits, allocationUnitCount, AllocationUnits); + AllocationUnitIndices = new (Ctx) unsigned[FieldCount]; + std::copy_n(allocationUnitIndices, FieldCount, AllocationUnitIndices); + } } // Constructor for C++ records. @@ -52,6 +62,9 @@ CharUnits datasize, const uint64_t *fieldoffsets, unsigned fieldcount, + const AllocationUnit *allocationUnits, + unsigned allocationUnitCount, + const int*allocationUnitIndices, CharUnits nonvirtualsize, CharUnits nonvirtualalignment, CharUnits SizeOfLargestEmptySubobject, @@ -64,12 +77,19 @@ const VBaseOffsetsMapTy& VBaseOffsets) : Size(size), DataSize(datasize), Alignment(alignment), RequiredAlignment(requiredAlignment), FieldOffsets(nullptr), - FieldCount(fieldcount), CXXInfo(new (Ctx) CXXRecordLayoutInfo) + FieldCount(fieldcount), AllocationUnits(nullptr), + AllocationUnitIndices(nullptr), CXXInfo(new (Ctx) CXXRecordLayoutInfo) { if (FieldCount > 0) { FieldOffsets = new (Ctx) uint64_t[FieldCount]; memcpy(FieldOffsets, fieldoffsets, FieldCount * sizeof(*FieldOffsets)); } + if (allocationUnitCount > 0) { + AllocationUnits = new (Ctx) AllocationUnit[allocationUnitCount]; + std::copy_n(allocationUnits, allocationUnitCount, AllocationUnits); + AllocationUnitIndices = new (Ctx) unsigned[FieldCount]; + std::copy_n(allocationUnitIndices, FieldCount, AllocationUnitIndices); + } CXXInfo->PrimaryBase.setPointer(PrimaryBase); CXXInfo->PrimaryBase.setInt(IsPrimaryBaseVirtual); Index: lib/AST/RecordLayoutBuilder.cpp =================================================================== --- lib/AST/RecordLayoutBuilder.cpp +++ lib/AST/RecordLayoutBuilder.cpp @@ -2194,6 +2194,7 @@ const ASTRecordLayout *&PreviousBaseLayout); void injectVFPtr(const CXXRecordDecl *RD); void injectVBPtr(const CXXRecordDecl *RD); + void relocateFields(CharUnits Offset); /// \brief Lays out the fields of the record. Also rounds size up to /// alignment. void layoutFields(const RecordDecl *RD); @@ -2214,10 +2215,23 @@ /// \brief Places a field at an offset in CharUnits. void placeFieldAtOffset(CharUnits FieldOffset) { FieldOffsets.push_back(Context.toBits(FieldOffset)); + if (!AllocationUnits.empty()) { + AllocationUnitIndices.push_back(-1); + } } /// \brief Places a bitfield at a bit offset. void placeFieldAtBitOffset(uint64_t FieldOffset) { FieldOffsets.push_back(FieldOffset); + assert(!AllocationUnits.empty()); + AllocationUnitIndices.push_back(AllocationUnits.size() - 1); + } + void addAllocationUnit(CharUnits Offset, CharUnits Size) { + if (AllocationUnitIndices.empty() && !FieldOffsets.empty()) { + // If this is the first bitfield we've seen, go back and add allocation + // unit indices for all previous fields. + AllocationUnitIndices.append(FieldOffsets.size(), -1); + } + AllocationUnits.push_back(AllocationUnit(Offset, Size)); } /// \brief Compute the set of virtual bases for which vtordisps are required. void computeVtorDispSet( @@ -2253,6 +2267,10 @@ const CXXRecordDecl *SharedVBPtrBase; /// \brief The collection of field offsets. SmallVector FieldOffsets; + /// \brief The collection of bitfield allocation units. + SmallVector AllocationUnits; + /// \brief The collection of bitfield allocation unit indices for each field. + SmallVector AllocationUnitIndices; /// \brief Base classes and their offsets in the record. BaseOffsetsMapTy Bases; /// \brief virtual base classes and their offsets in the record. @@ -2586,13 +2604,15 @@ LastFieldIsNonZeroWidthBitfield = true; CurrentBitfieldSize = Info.Size; if (IsUnion) { - placeFieldAtOffset(CharUnits::Zero()); + addAllocationUnit(CharUnits::Zero(), CurrentBitfieldSize); + placeFieldAtBitOffset(0); Size = std::max(Size, Info.Size); // TODO: Add a Sema warning that MS ignores bitfield alignment in unions. } else { // Allocate a new block of memory and place the bitfield in it. CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment); - placeFieldAtOffset(FieldOffset); + addAllocationUnit(FieldOffset, CurrentBitfieldSize); + placeFieldAtBitOffset(Context.toBits(FieldOffset)); Size = FieldOffset + Info.Size; Alignment = std::max(Alignment, Info.Alignment); RemainingBitsInField = Context.toBits(Info.Size) - Width; @@ -2604,6 +2624,7 @@ // Zero-width bitfields are ignored unless they follow a non-zero-width // bitfield. if (!LastFieldIsNonZeroWidthBitfield) { + // No need to add an AllocationUnit, since we're not really allocating. placeFieldAtOffset(IsUnion ? CharUnits::Zero() : Size); // TODO: Add a Sema warning that MS ignores alignment for zero // sized bitfields that occur after zero-size bitfields or non-bitfields. @@ -2624,6 +2645,16 @@ } } +void MicrosoftRecordLayoutBuilder::relocateFields(CharUnits Offset) { + for (uint64_t &FieldOffset : FieldOffsets) { + FieldOffset += Context.toBits(Offset); + } + + for (AllocationUnit &AllocUnit : AllocationUnits) { + AllocUnit.Offset += Offset; + } +} + void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) { if (!HasVBPtr || SharedVBPtrBase) return; @@ -2642,8 +2673,7 @@ CharUnits Offset = (FieldStart - InjectionSite).RoundUpToAlignment( std::max(RequiredAlignment, Alignment)); Size += Offset; - for (uint64_t &FieldOffset : FieldOffsets) - FieldOffset += Context.toBits(Offset); + relocateFields(Offset); for (BaseOffsetsMapTy::value_type &Base : Bases) if (Base.second >= InjectionSite) Base.second += Offset; @@ -2659,8 +2689,7 @@ // Increase the size of the object and push back all fields, the vbptr and all // bases by the offset amount. Size += Offset; - for (uint64_t &FieldOffset : FieldOffsets) - FieldOffset += Context.toBits(Offset); + relocateFields(Offset); if (HasVBPtr) VBPtrOffset += Offset; for (BaseOffsetsMapTy::value_type &Base : Bases) @@ -2853,7 +2882,9 @@ Builder.HasOwnVFPtr, Builder.HasOwnVFPtr || Builder.PrimaryBase, Builder.VBPtrOffset, Builder.NonVirtualSize, Builder.FieldOffsets.data(), - Builder.FieldOffsets.size(), Builder.NonVirtualSize, + Builder.FieldOffsets.size(), Builder.AllocationUnits.data(), + Builder.AllocationUnits.size(), Builder.AllocationUnitIndices.data(), + Builder.NonVirtualSize, Builder.Alignment, CharUnits::Zero(), Builder.PrimaryBase, false, Builder.SharedVBPtrBase, Builder.EndsWithZeroSizedObject, Builder.LeadsWithZeroSizedBase, @@ -2862,7 +2893,9 @@ Builder.layout(D); return new (*this) ASTRecordLayout( *this, Builder.Size, Builder.Alignment, Builder.RequiredAlignment, - Builder.Size, Builder.FieldOffsets.data(), Builder.FieldOffsets.size()); + Builder.Size, Builder.FieldOffsets.data(), Builder.FieldOffsets.size(), + Builder.AllocationUnits.data(), Builder.AllocationUnits.size(), + Builder.AllocationUnitIndices.data()); } } @@ -2921,6 +2954,7 @@ DataSize, Builder.FieldOffsets.data(), Builder.FieldOffsets.size(), + nullptr, 0, nullptr, NonVirtualSize, Builder.NonVirtualAlignment, EmptySubobjects.SizeOfLargestEmptySubobject, @@ -2939,7 +2973,8 @@ Builder.Alignment, Builder.getSize(), Builder.FieldOffsets.data(), - Builder.FieldOffsets.size()); + Builder.FieldOffsets.size(), + nullptr, 0, nullptr); } ASTRecordLayouts[D] = NewEntry; @@ -3018,6 +3053,31 @@ return OffsetInBits; } +static AllocationUnit getBitFieldAllocationUnit(const ASTContext &C, const FieldDecl *FD) { + assert(FD->isBitField()); + const ASTRecordLayout &Layout = C.getASTRecordLayout(FD->getParent()); + return Layout.getBitFieldAllocationUnit(FD->getFieldIndex()); +} + +AllocationUnit ASTContext::getBitFieldAllocationUnit(const ValueDecl *VD) const { + AllocationUnit AllocUnit; + if (const FieldDecl *FD = dyn_cast(VD)) { + AllocUnit = ::getBitFieldAllocationUnit(*this, FD); + } else { + const IndirectFieldDecl *IFD = cast(VD); + + uint64_t OffsetInBits = 0; + for (IndirectFieldDecl::chain_iterator ChainIter = IFD->chain_begin(); ChainIter != (IFD->chain_end() - 1); ++ChainIter) { + const FieldDecl *ChainDecl = cast(*ChainIter); + OffsetInBits += ::getFieldOffset(*this, ChainDecl); + } + AllocUnit = ::getBitFieldAllocationUnit(*this, IFD->getAnonField()); + AllocUnit.Offset += toCharUnitsFromBits(OffsetInBits); + } + + return AllocUnit; +} + /// getObjCLayout - Get or compute information about the layout of the /// given interface. /// @@ -3059,7 +3119,8 @@ Builder.Alignment, Builder.getDataSize(), Builder.FieldOffsets.data(), - Builder.FieldOffsets.size()); + Builder.FieldOffsets.size(), + nullptr, 0, nullptr); ObjCLayouts[Key] = NewEntry; Index: lib/CodeGen/CGDebugInfo.h =================================================================== --- lib/CodeGen/CGDebugInfo.h +++ lib/CodeGen/CGDebugInfo.h @@ -18,6 +18,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "clang/Basic/SourceLocation.h" +#include "clang/CodeGen/CodeViewTypeTable.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/DenseMap.h" #include "llvm/IR/DIBuilder.h" @@ -119,6 +120,8 @@ NamespaceAliasCache; llvm::DenseMap StaticDataMemberCache; + std::unique_ptr CodeViewTypes; + /// Helper functions for getOrCreateType. /// @{ /// Currently the checksum of an interface includes the number of @@ -387,6 +390,16 @@ llvm::DIModule * getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod); + /// Get a CodeView type index for a type. + llvm::codeview::TypeIndex getOrCreateTypeIndex(QualType Ty); + + /// Get a CodeView type index for a function's type. + llvm::codeview::TypeIndex getOrCreateTypeIndexForFunction( + const FunctionDecl *D, QualType FuncTy); + + llvm::codeview::TypeIndex getOrCreateTypeIndexForFunction( + const FunctionDecl *D); + /// Get the type from the cache or create a new partial type if /// necessary. llvm::DIType *getOrCreateLimitedType(const RecordType *Ty, llvm::DIFile *F); Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -31,6 +31,7 @@ #include "clang/Lex/PreprocessorOptions.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/CodeView/TypeIndex.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" @@ -42,11 +43,18 @@ #include "llvm/Support/Path.h" using namespace clang; using namespace clang::CodeGen; +using namespace llvm::codeview; CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()), DBuilder(CGM.getModule()) { CreateCompileUnit(); + + if (DebugKind > CodeGenOptions::DebugLineTablesOnly) { + CodeViewTypes.reset( + new CodeViewTypeTable(DBuilder.getCodeViewTypesBuilder(), + CGM.getContext(), CGM.getCXXABI().getMangleContext())); + } } CGDebugInfo::~CGDebugInfo() { @@ -1068,6 +1076,7 @@ StringRef MethodName = getFunctionName(Method); llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit); + llvm::codeview::TypeIndex MethodTI = getOrCreateTypeIndexForFunction(Method); // Since a single ctor/dtor corresponds to multiple functions, it doesn't // make sense to give a single ctor/dtor a linkage name. @@ -1127,7 +1136,7 @@ llvm::DINodeArray TParamsArray = CollectFunctionTemplateParams(Method, Unit); llvm::DISubprogram *SP = DBuilder.createMethod( RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine, - MethodTy, /*isLocalToUnit=*/false, + MethodTy, MethodTI, /*isLocalToUnit=*/false, /* isDefinition=*/false, Virtuality, VIndex, ContainingType, Flags, CGM.getLangOpts().Optimize, nullptr, TParamsArray.get()); @@ -2071,6 +2080,36 @@ return Res; } +llvm::codeview::TypeIndex CGDebugInfo::getOrCreateTypeIndex(QualType Ty) { + if (CodeViewTypes != nullptr) { + return CodeViewTypes->getTypeIndexForDefinition(Ty); + } + else { + return llvm::codeview::TypeIndex(); + } +} + +llvm::codeview::TypeIndex CGDebugInfo::getOrCreateTypeIndexForFunction( + const FunctionDecl *D, QualType FuncTy) { + if (D != nullptr) { + return getOrCreateTypeIndexForFunction(D); + } + else { + return getOrCreateTypeIndex(FuncTy); + } +} + +llvm::codeview::TypeIndex CGDebugInfo::getOrCreateTypeIndexForFunction( + const FunctionDecl *D) { + assert(D != nullptr); + if (CodeViewTypes != nullptr) { + return CodeViewTypes->getTypeIndexForFunctionType(D, false, false); + } + else { + return llvm::codeview::TypeIndex(); + } +} + unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl *ID) { // The assumption is that the number of ivars can only increase // monotonically, so it is safe to just use their current number as @@ -2379,7 +2418,9 @@ FunctionProtoType::ExtProtoInfo()); llvm::DISubprogram *SP = DBuilder.createTempFunctionFwdDecl( DContext, Name, LinkageName, Unit, Line, - getOrCreateFunctionType(FD, FnType, Unit), !FD->isExternallyVisible(), + getOrCreateFunctionType(FD, FnType, Unit), + getOrCreateTypeIndexForFunction(FD), + !FD->isExternallyVisible(), false /*declaration*/, 0, Flags, CGM.getLangOpts().Optimize, nullptr, TParamsArray.get(), getFunctionDeclaration(FD)); const FunctionDecl *CanonDecl = cast(FD->getCanonicalDecl()); @@ -2401,7 +2442,7 @@ collectVarDeclProps(VD, Unit, Line, T, Name, LinkageName, DContext); auto *GV = DBuilder.createTempGlobalVariableFwdDecl( DContext, Name, LinkageName, Unit, Line, getOrCreateType(T, Unit), - !VD->isExternallyVisible(), nullptr, nullptr); + getOrCreateTypeIndex(T), !VD->isExternallyVisible(), nullptr, nullptr); FwdDeclReplaceMap.emplace_back( std::piecewise_construct, std::make_tuple(cast(VD->getCanonicalDecl())), @@ -2587,7 +2628,10 @@ // are emitted as CU level entities by the backend. llvm::DISubprogram *SP = DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, - getOrCreateFunctionType(D, FnType, Unit), Fn->hasInternalLinkage(), + getOrCreateFunctionType(D, FnType, Unit), + getOrCreateTypeIndexForFunction(dyn_cast_or_null(D), + FnType), + Fn->hasInternalLinkage(), true /*definition*/, ScopeLine, Flags, CGM.getLangOpts().Optimize, Fn, TParamsArray.get(), getFunctionDeclaration(D)); // We might get here with a VarDecl in the case we're generating @@ -2753,11 +2797,14 @@ if (!Unwritten) Unit = getOrCreateFile(VD->getLocation()); llvm::DIType *Ty; + llvm::codeview::TypeIndex TI; uint64_t XOffset = 0; if (VD->hasAttr()) Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset); - else + else { Ty = getOrCreateType(VD->getType(), Unit); + TI = getOrCreateTypeIndex(VD->getType()); + } // If there is no debug info for this type then do not emit debug info // for this variable. @@ -2806,7 +2853,8 @@ // Create the descriptor for the variable. auto *D = DBuilder.createLocalVariable(Tag, Scope, VD->getName(), Unit, - Line, Ty, ArgNo); + Line, Ty, TI, + ArgNo); // Insert an llvm.dbg.declare into the current block. DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr), @@ -2829,6 +2877,8 @@ // for artificial variables. for (const auto *Field : RD->fields()) { llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit); + llvm::codeview::TypeIndex FieldTI = getOrCreateTypeIndex(Field->getType()); + StringRef FieldName = Field->getName(); // Ignore unnamed fields. Do not ignore unnamed records. @@ -2837,7 +2887,7 @@ // Use VarDecl's Tag, Scope and Line number. auto *D = DBuilder.createLocalVariable( - Tag, Scope, FieldName, Unit, Line, FieldTy, + Tag, Scope, FieldName, Unit, Line, FieldTy, FieldTI, CGM.getLangOpts().Optimize, Flags | llvm::DINode::FlagArtificial, ArgNo); @@ -2851,7 +2901,7 @@ // Create the descriptor for the variable. auto *D = - DBuilder.createLocalVariable(Tag, Scope, Name, Unit, Line, Ty, + DBuilder.createLocalVariable(Tag, Scope, Name, Unit, Line, Ty, TI, CGM.getLangOpts().Optimize, Flags, ArgNo); // Insert an llvm.dbg.declare into the current block. @@ -2932,7 +2982,7 @@ auto *D = DBuilder.createLocalVariable( llvm::dwarf::DW_TAG_auto_variable, cast(LexicalBlockStack.back()), VD->getName(), Unit, - Line, Ty); + Line, Ty, llvm::codeview::TypeIndex()); // Insert an llvm.dbg.declare into the current block. auto DL = llvm::DebugLoc::get(Line, Column, LexicalBlockStack.back()); @@ -3092,7 +3142,8 @@ // Create the descriptor for the parameter. auto *debugVar = DBuilder.createLocalVariable( llvm::dwarf::DW_TAG_arg_variable, scope, Arg->getName(), tunit, line, - type, CGM.getLangOpts().Optimize, flags, ArgNo); + type, llvm::codeview::TypeIndex(), CGM.getLangOpts().Optimize, flags, + ArgNo); if (LocalAddr) { // Insert an llvm.dbg.value into the current block. @@ -3133,6 +3184,7 @@ for (const auto *Field : RD->fields()) { llvm::DIType *FieldTy = getOrCreateType(Field->getType(), Unit); + llvm::codeview::TypeIndex FieldTI = getOrCreateTypeIndex(Field->getType()); StringRef FieldName = Field->getName(); // Ignore unnamed fields, but recurse into anonymous records. @@ -3145,7 +3197,7 @@ } // Use VarDecl's Tag, Scope and Line number. GV = DBuilder.createGlobalVariable(DContext, FieldName, LinkageName, Unit, - LineNo, FieldTy, + LineNo, FieldTy, FieldTI, Var->hasInternalLinkage(), Var, nullptr); } return GV; @@ -3177,7 +3229,7 @@ } else { GV = DBuilder.createGlobalVariable( DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), - Var->hasInternalLinkage(), Var, + getOrCreateTypeIndex(T), Var->hasInternalLinkage(), Var, getOrCreateStaticDataMemberDeclarationOrNull(D)); } DeclCache[D->getCanonicalDecl()].reset(static_cast(GV)); @@ -3190,10 +3242,13 @@ llvm::DIFile *Unit = getOrCreateFile(VD->getLocation()); StringRef Name = VD->getName(); llvm::DIType *Ty = getOrCreateType(VD->getType(), Unit); + llvm::codeview::TypeIndex TI = getOrCreateTypeIndex(VD->getType()); if (const EnumConstantDecl *ECD = dyn_cast(VD)) { const EnumDecl *ED = cast(ECD->getDeclContext()); assert(isa(ED->getTypeForDecl()) && "Enum without EnumType?"); - Ty = getOrCreateType(QualType(ED->getTypeForDecl(), 0), Unit); + QualType DeclTy(ED->getTypeForDecl(), 0); + Ty = getOrCreateType(DeclTy, Unit); + TI = getOrCreateTypeIndex(DeclTy); } // Do not use global variables for enums. // @@ -3222,7 +3277,7 @@ return; GV.reset(DBuilder.createGlobalVariable( DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty, - true, Init, getOrCreateStaticDataMemberDeclarationOrNull(VarD))); + TI, true, Init, getOrCreateStaticDataMemberDeclarationOrNull(VarD))); } llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) { @@ -3352,6 +3407,20 @@ RE = RetainedTypes.end(); RI != RE; ++RI) DBuilder.retainType(cast(TypeCache[*RI])); + if (CodeViewTypes != nullptr) { + CodeViewTypes->finishDefinitions(); + llvm::codeview::TypeSymbolEmitter &Emitter = + DBuilder.getCodeViewTypeSymbolEmitter(); + + // Emit metadata records for any referenced tags. These records may + // be the only reference to the TI of the tag's definition. + for (const TagDecl *TD : CodeViewTypes->referenced_tags()) { + if (TD->isDefinedOutsideFunctionOrMethod()) { + CodeViewTypes->emitTypeSymbolsForTag(TD, Emitter); + } + } + } + DBuilder.finalize(); } Index: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -2,6 +2,7 @@ Analysis BitReader BitWriter + CodeView Core IPO IRReader @@ -68,7 +69,9 @@ CodeGenPGO.cpp CodeGenTBAA.cpp CodeGenTypes.cpp + CodeViewTypeTable.cpp CoverageMappingGen.cpp + DisplayNameGenerator.cpp ItaniumCXXABI.cpp MicrosoftCXXABI.cpp ModuleBuilder.cpp Index: lib/CodeGen/CodeViewTypeTable.cpp =================================================================== --- /dev/null +++ lib/CodeGen/CodeViewTypeTable.cpp @@ -0,0 +1,2204 @@ +#include "clang/CodeGen/CodeViewTypeTable.h" +#include "DisplayNameGenerator.h" +#include "llvm/CodeView/FieldListRecordBuilder.h" +#include "llvm/CodeView/MethodListRecordBuilder.h" +#include "llvm/CodeView/TypeIndex.h" +#include "llvm/Support/raw_ostream.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Mangle.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Type.h" +#include + +using namespace clang; +using namespace CodeGen; + +using namespace std; +using namespace llvm; +using namespace llvm::codeview; + +namespace { + + bool returnsUdt(const FunctionType* FuncType, bool IsInstance) + { + // TODO: refactor ABI code to share implementation. + if (const CXXRecordDecl* RD = + FuncType->getReturnType()->getAsCXXRecordDecl()) { + if (IsInstance) { + return true; + } + if (!RD->isPOD()) { + return true; + } + } + + return false; + } + + bool returnsUdt(const FunctionDecl* D) + { + bool IsInstance = false; + if (const CXXMethodDecl* MD = dyn_cast(D)) { + if (MD->isInstance()) { + IsInstance = true; + } + } + + return returnsUdt(D->getFunctionType(), IsInstance); + } + + bool isWCharT(const TypedefNameDecl* decl) + { + if (decl->getName() != "wchar_t") { + return false; + } + + //TODO: Make sure it's the right underlying type. + return true; + } + + bool mergeHfaKinds(Optional& Existing, HfaKind New) + { + if (New == HfaKind::None) { + return false; + } + else if (!Existing.hasValue()) { + Existing = New; + return true; + } + else { + return Existing.getValue() == New; + } + } + + MemberAccess translateAccess(AccessSpecifier Access) + { + switch (Access) { + case AccessSpecifier::AS_public: + case AccessSpecifier::AS_none: + // We sometimes see AS_none in C, mostly for anonymous fields. + return MemberAccess::Public; + + case AccessSpecifier::AS_protected: + return MemberAccess::Protected; + + case AccessSpecifier::AS_private: + return MemberAccess::Private; + + default: + assert(false); + return MemberAccess::Public; + } + } + + CallingConvention translateCallingConvention(CallingConv CallConv) + { + switch (CallConv) { + case CallingConv::CC_X86FastCall: + return CallingConvention::NearFast; + + case CallingConv::CC_X86Pascal: + return CallingConvention::NearPascal; + + case CallingConv::CC_X86StdCall: + return CallingConvention::NearStdCall; + + case CallingConv::CC_X86ThisCall: + return CallingConvention::ThisCall; + + case CallingConv::CC_C: + return CallingConvention::NearC; + + case CallingConv::CC_X86VectorCall: + return CallingConvention::NearVector; + + default: + assert(false); + return CallingConvention::NearC; + } + } + + PointerToMemberRepresentation translatePointerToMemberRepresentation( + MSInheritanceAttr::Spelling Inheritance, bool IsMemberFunctionPointer) + { + switch (Inheritance) { + case MSInheritanceAttr::Spelling::Keyword_single_inheritance: + return IsMemberFunctionPointer ? + PointerToMemberRepresentation::SingleInheritanceFunction : + PointerToMemberRepresentation::SingleInheritanceData; + + case MSInheritanceAttr::Spelling::Keyword_multiple_inheritance: + return IsMemberFunctionPointer ? + PointerToMemberRepresentation::MultipleInheritanceFunction : + PointerToMemberRepresentation::MultipleInheritanceData; + + case MSInheritanceAttr::Spelling::Keyword_virtual_inheritance: + return IsMemberFunctionPointer ? + PointerToMemberRepresentation::VirtualInheritanceFunction : + PointerToMemberRepresentation::VirtualInheritanceData; + + case MSInheritanceAttr::Spelling::Keyword_unspecified_inheritance: + return IsMemberFunctionPointer ? + PointerToMemberRepresentation::GeneralFunction : + PointerToMemberRepresentation::GeneralData; + } + + assert(false); + return PointerToMemberRepresentation::Unknown; + } + + struct MemberOrder + { + size_t Index; + size_t FirstOverloadIndex; + }; + + bool operator<(const MemberOrder& Left, const MemberOrder& Right) + { + if (Left.FirstOverloadIndex != Right.FirstOverloadIndex) { + return Left.FirstOverloadIndex < Right.FirstOverloadIndex; + } + else if (Left.Index != Right.Index) { + // Reverse order. + return Left.Index > Right.Index; + } + else { + return false; + } + } + + bool shouldEmitMemberDecl(const Decl* D) + { + if (D->isImplicit()) { + return isa(D); + } + else { + Decl::Kind Kind = D->getKind(); + switch (Kind) { + case Decl::Kind::Var: + case Decl::Kind::Field: + case Decl::Kind::CXXMethod: + case Decl::Kind::CXXConstructor: + case Decl::Kind::CXXConversion: + case Decl::Kind::CXXDestructor: + case Decl::Kind::CXXRecord: + case Decl::Kind::Enum: + return true; + + case Decl::Kind::FunctionTemplate: + case Decl::Kind::ClassTemplate: + return false; + + default: + return false; + } + } + } + + MethodOptions computeMethodOptions(const CXXMethodDecl* D) + { + MethodOptions Options = MethodOptions::None; + if (D->isImplicit()) { + Options = Options | MethodOptions::CompilerGenerated; + } + + return Options; + } + + bool isIntroducingVirtual(const CXXMethodDecl* D) + { + return D->isVirtual() && + (D->begin_overridden_methods() == D->end_overridden_methods()); + } +} + +class CodeViewTypeTable::FieldList +{ +public: + FieldList(const TagDecl* Decl, ClassOptions Options) : + Decl(Decl), + MemberCount(0), + Options(Options) + { + } + +public: + const TagDecl* getTagDecl() const + { + return Decl; + } + + FieldListRecordBuilder& getBuilder() + { + return Builder; + } + + uint32_t getMemberCount() const + { + return MemberCount; + } + + void incrementMemberCount(uint32_t Count = 1) + { + MemberCount += Count; + } + + ClassOptions getOptions() const + { + return Options; + } + + void addOptions(ClassOptions NewOptions) + { + Options = Options | NewOptions; + } + +private: + const TagDecl* const Decl; + FieldListRecordBuilder Builder; + uint32_t MemberCount; + ClassOptions Options; + +private: + FieldList(const FieldList&) = delete; + FieldList& operator=(const FieldList&) = delete; +}; + +class CodeViewTypeTable::MethodListHelper +{ +public: + explicit MethodListHelper(CodeViewTypeTable& Table, FieldList& Fields, + DeclarationName DN) : + Table(Table), + Fields(Fields), + DN(DN), + Count(0) + { + } + + void writeMethod(const MethodInfo& Method) + { + if (Count == 0) { + FirstMethodInfo = Method; + } + else { + if (Count == 1) { + MethodListBuilder.writeMethod(FirstMethodInfo); + } + MethodListBuilder.writeMethod(Method); + } + + ++Count; + Fields.incrementMemberCount(); + } + + void finish() + { + if (Count > 0) { + string Name = DisplayNameGenerator::getMethodName(DN); + if (Count == 1) { + Fields.getBuilder().writeOneMethod(FirstMethodInfo, Name); + + } + else { + TypeIndex Methods = Table.Builder.writeMethodList(MethodListBuilder); + Fields.getBuilder().writeMethod(static_cast(Count), + Methods, Name); + } + + DeclarationName::NameKind NameKind = DN.getNameKind(); + switch (NameKind) { + case DeclarationName::NameKind::CXXConstructorName: + case DeclarationName::NameKind::CXXDestructorName: + Fields.addOptions(ClassOptions::HasConstructorOrDestructor); + break; + + case DeclarationName::NameKind::CXXOperatorName: + Fields.addOptions(ClassOptions::HasOverloadedOperator); + if (DN.getCXXOverloadedOperator() == OverloadedOperatorKind::OO_Equal) { + Fields.addOptions(ClassOptions::HasOverloadedAssignmentOperator); + } + break; + + case DeclarationName::NameKind::CXXConversionFunctionName: + Fields.addOptions(ClassOptions::HasConversionOperator); + break; + + default: + break; + } + } + } + +private: + CodeViewTypeTable& Table; + FieldList& Fields; + DeclarationName DN; + MethodListRecordBuilder MethodListBuilder; + size_t Count; + MethodInfo FirstMethodInfo; +}; + +CodeViewTypeTable::CodeViewTypeTable(TypeTableBuilder& Builder, + ASTContext& Context, MangleContext& MContext) : + Builder(Builder), + Context(Context), + VTableContext(*static_cast( + Context.getVTableContext())), + MContext(MContext), + VirtualBasePointerTI(), + PmdTIs(), + TypeDescriptorTIs(), + CatchableTypeTIs(), + CatchableTypeArrayTIs(), + ThrowInfoTIs() +{ + if (getPointerByteSize() == 8) { + ArrayIndexTI = TypeIndex::UInt64Quad(); + VoidPointerTI = TypeIndex::VoidPointer64(); + DefaultPointerKind = PointerKind::Near64; + } + else { + ArrayIndexTI = TypeIndex::UInt32Long(); + VoidPointerTI = TypeIndex::VoidPointer32(); + DefaultPointerKind = PointerKind::Near32; + } +} + +TypeIndex CodeViewTypeTable::getTypeIndex(QualType Type) +{ + TypeIndex TypeInd = getCachedTypeIndex(Type); + if (TypeInd != TypeIndex()) { + return TypeInd; + } + + TypeInd = computeTypeIndex(Type); + setCachedTypeIndex(Type, TypeInd); + + return TypeInd; +} + +TypeIndex CodeViewTypeTable::getTypeIndexForDefinition(QualType Type) +{ + // First, call getTypeIndex to ensure that we have a type index for the + // declaration. Otherwise, we think this is a definition-only type, and + // never create a declaration. + TypeIndex TypeInd = getTypeIndex(Type); + + if (const TagType* Tag = Type->getAs()) { + const TagDecl* D = Tag->getDecl()->getDefinition(); + if (D != nullptr) { + return getTypeIndexForTagDefinition(D); + } + } + + return TypeInd; +} + +TagTypeIndices CodeViewTypeTable::getTypeIndexForCatchableTypeArray( + uint32_t Count) +{ + uint32_t ExtraBytes = Count * getPointerByteSize(); + auto I = CatchableTypeArrayTypes.find(ExtraBytes); + if (I != CatchableTypeArrayTypes.end()) { + return I->second; + } + + char Name[64]; + sprintf(Name, "$_s__CatchableTypeArray$_extraBytes_%u", ExtraBytes); + + char UniqueName[64]; + sprintf(UniqueName, ".?AU%s@@", Name); + + FieldListRecordBuilder Fields; + uint32_t Offset = writeCatchableTypeArrayFields(Fields, Count); + + TagTypeIndices TIs = computeTypeIndexForBuiltinStruct(Name, UniqueName, + Offset, Fields, 2); + CatchableTypeArrayTypes.insert(make_pair(ExtraBytes, TIs)); + + return TIs; +} + +TagTypeIndices CodeViewTypeTable::getTypeIndexForTypeDescriptor( + uint32_t ExtraBytes) +{ + auto I = TypeDescriptorTypes.find(ExtraBytes); + if (I != TypeDescriptorTypes.end()) { + return I->second; + } + + char Name[64]; + sprintf(Name, "$_TypeDescriptor$_extraBytes_%u", ExtraBytes); + + char UniqueName[64]; + sprintf(UniqueName, ".?AU%s@@", Name); + + FieldListRecordBuilder Fields; + uint32_t Offset = writeTypeDescriptorFields(Fields, ExtraBytes); + + TagTypeIndices TIs = computeTypeIndexForBuiltinStruct(Name, UniqueName, + Offset, Fields, 3); + TypeDescriptorTypes.insert(make_pair(ExtraBytes, TIs)); + + return TIs; +} + +TagTypeIndices CodeViewTypeTable::computeTypeIndexForBuiltinStruct( + StringRef Name, StringRef UniqueName, uint32_t Size, + FieldListRecordBuilder& Fields, uint16_t MemberCount) +{ + TagTypeIndices TIs; + + TIs.DeclarationTI = Builder.writeAggregate(AggregateRecord(TypeRecordKind::Structure, + 0, ClassOptions::HasUniqueName | ClassOptions::ForwardReference, HfaKind::None, + WindowsRTClassKind::None, TypeIndex(), TypeIndex(), TypeIndex(), 0, Name, UniqueName)); + + TypeIndex FieldListTI = Builder.writeFieldList(Fields); + + TIs.DefinitionTI = Builder.writeAggregate(AggregateRecord(TypeRecordKind::Structure, + MemberCount, ClassOptions::HasUniqueName, HfaKind::None, WindowsRTClassKind::None, + FieldListTI, TypeIndex(), TypeIndex(), Size, Name, UniqueName)); + + setDefinitionForDeclaration(TIs.DeclarationTI, TIs.DefinitionTI); + + return TIs; +} + +TagTypeIndices CodeViewTypeTable::getTypeIndexForPMD() +{ + if (PmdTIs.DeclarationTI == TypeIndex()) { + FieldListRecordBuilder Fields; + uint32_t Offset = 0; + Fields.writeMember(MemberAccess::Public, TypeIndex::Int32(), + Offset, "mdisp"); + Offset += 4; + Fields.writeMember(MemberAccess::Public, TypeIndex::Int32(), + Offset, "pdisp"); + Offset += 4; + Fields.writeMember(MemberAccess::Public, TypeIndex::Int32(), + Offset, "vdisp"); + Offset += 4; + + PmdTIs = computeTypeIndexForBuiltinStruct("_PMD", ".?AU_PMD@@", Offset, + Fields, 3); + } + + return PmdTIs; +} + +uint32_t CodeViewTypeTable::writeTypeDescriptorFields( + FieldListRecordBuilder& Fields, uint32_t ExtraBytes) +{ + TypeIndex VTablePointerTI = getPointerToConstType(TypeIndex::Void()); + + uint32_t Offset = 0; + Fields.writeMember(MemberAccess::Public, VTablePointerTI, Offset, + "pVFTable"); + Offset += getPointerByteSize(); + Fields.writeMember(MemberAccess::Public, VoidPointerTI, Offset, + "spare"); + Offset += getPointerByteSize(); + + TypeIndex ArrayTI = Builder.writeArray(ArrayRecord( + TypeIndex::NarrowCharacter(), ArrayIndexTI, ExtraBytes, "")); + Fields.writeMember(MemberAccess::Public, ArrayTI, Offset, "name"); + Offset += ExtraBytes; + + return Offset; +} + +TagTypeIndices CodeViewTypeTable::getTypeIndexForTypeDescriptor() +{ + if (TypeDescriptorTIs.DeclarationTI == TypeIndex()) { + FieldListRecordBuilder Fields; + uint32_t Size = writeTypeDescriptorFields(Fields, 0); + + TypeDescriptorTIs = computeTypeIndexForBuiltinStruct("_TypeDescriptor", + ".?AU_TypeDescriptor@@", Size, Fields, 3); + } + + return TypeDescriptorTIs; +} + +TagTypeIndices CodeViewTypeTable::getTypeIndexForCatchableType() +{ + if (CatchableTypeTIs.DeclarationTI == TypeIndex()) { + FieldListRecordBuilder Fields; + uint32_t Offset = 0; + Fields.writeMember(MemberAccess::Public, TypeIndex::UInt32(), Offset, + "properties"); + Offset += 4; + + TypeIndex TypeDescriptorPointerTI = + Builder.writePointer(PointerRecord(getTypeIndexForTypeDescriptor().DeclarationTI, + DefaultPointerKind, PointerMode::Pointer, PointerOptions::None, + getPointerByteSize())); + + TypeIndex CopyFunctionPointerTI = computeProcedurePointerType( + TypeIndex::Void(), { VoidPointerTI }); + + Fields.writeMember(MemberAccess::Public, TypeDescriptorPointerTI, Offset, + "pType"); + Offset += getPointerByteSize(); + Fields.writeMember(MemberAccess::Public, getTypeIndexForPMD().DeclarationTI, + Offset, "thisDisplacement"); + Offset += 12; + Fields.writeMember(MemberAccess::Public, TypeIndex::Int32(), Offset, + "sizeOrOffset"); + Offset += 4; + Fields.writeMember(MemberAccess::Public, CopyFunctionPointerTI, Offset, + "copyFunction"); + Offset += getPointerByteSize(); + + CatchableTypeTIs = computeTypeIndexForBuiltinStruct("_s__CatchableType", + ".?AU_s__CatchableType@@", Offset, Fields, 5); + } + + return CatchableTypeTIs; +} + +TagTypeIndices CodeViewTypeTable::getTypeIndexForCatchableTypeArray() +{ + if (CatchableTypeArrayTIs.DeclarationTI == TypeIndex()) { + FieldListRecordBuilder Fields; + uint32_t ByteSize = writeCatchableTypeArrayFields(Fields, 0); + + CatchableTypeArrayTIs = computeTypeIndexForBuiltinStruct( + "_s__CatchableTypeArray", ".?AU_s__CatchableTypeArray@@", ByteSize, + Fields, 2); + } + + return CatchableTypeArrayTIs; +} + +uint32_t CodeViewTypeTable::writeCatchableTypeArrayFields( + FieldListRecordBuilder& Fields, uint32_t Count) +{ + uint32_t Offset = 0; + Fields.writeMember(MemberAccess::Public, TypeIndex::Int32(), Offset, + "nCatchableTypes"); + Offset += 4; + + TypeIndex CatchableTypePointerTI = getPointerToConstType( + getTypeIndexForCatchableType().DeclarationTI); + TypeIndex CatchableTypePointerArrayTI = Builder.writeArray( + ArrayRecord(CatchableTypePointerTI, ArrayIndexTI, + Count * getPointerByteSize(), "")); + Fields.writeMember(MemberAccess::Public, CatchableTypePointerArrayTI, + Offset, "arrayOfCatchableTypes"); + Offset += Count * getPointerByteSize(); + + return Offset; +} + +TagTypeIndices CodeViewTypeTable::getTypeIndexForThrowInfo() +{ + if (ThrowInfoTIs.DeclarationTI == TypeIndex()) { + FieldListRecordBuilder Fields; + uint32_t Offset = 0; + Fields.writeMember(MemberAccess::Public, TypeIndex::UInt32(), Offset, + "attributes"); + Offset += 4; + + TypeIndex UnwindTI = computeProcedurePointerType(TypeIndex::Void(), + { VoidPointerTI }); + Fields.writeMember(MemberAccess::Public, UnwindTI, Offset, "pmfnUnwind"); + Offset += getPointerByteSize(); + + TypeIndex ForwardCompatTI = computeProcedurePointerType(TypeIndex::Int32(), + {}); + Fields.writeMember(MemberAccess::Public, ForwardCompatTI, Offset, + "pForwardCompat"); + Offset += getPointerByteSize(); + + TypeIndex CatchableTypeArrayPointerTI = getPointerToConstType( + getTypeIndexForCatchableTypeArray().DeclarationTI); + Fields.writeMember(MemberAccess::Public, CatchableTypeArrayPointerTI, + Offset, "pCatchableTypeArray"); + Offset += getPointerByteSize(); + + ThrowInfoTIs = computeTypeIndexForBuiltinStruct("_s__ThrowInfo", + ".?AU_s__ThrowInfo@@", Offset, Fields, 4); + } + + return ThrowInfoTIs; +} + +TypeIndex CodeViewTypeTable::getTypeIndexForFunctionType( + const FunctionDecl* Decl, bool Pointer, bool IgnoreConstructorFlags) +{ + TypeIndex TI = getTypeIndexForFunctionType(Decl, IgnoreConstructorFlags); + if (Pointer) { + return Builder.writePointer(PointerRecord(TI, DefaultPointerKind, PointerMode::Pointer, + PointerOptions::None, getPointerByteSize())); + } + else { + return TI; + } +} + +TypeIndex CodeViewTypeTable::getTypeIndexForPlainPointerToMemberFunction( + const MemberPointerType* Ty) +{ + assert(Ty->isMemberFunctionPointer()); + + const CXXRecordDecl* RD = Ty->getClass()->getAsCXXRecordDecl(); + + TypeIndex TI = computeTypeIndexForMemberFunctionType(RD, + Ty->getPointeeType()->castAs(), FunctionOptions::None, + false); + + return Builder.writePointer(PointerRecord(TI, DefaultPointerKind, PointerMode::Pointer, + PointerOptions::None, getPointerByteSize())); +} + +TypeIndex CodeViewTypeTable::getTypeIndexForMemberFunctionType( + const CXXRecordDecl* ClassDecl, const FunctionProtoType* FuncType) +{ + return computeTypeIndexForMemberFunctionType(ClassDecl, FuncType, + FunctionOptions::None, false); +} + +TypeIndex CodeViewTypeTable::getTypeIndexForFunctionType( + const FunctionDecl* Decl, bool IgnoreConstructorFlags) +{ + //TODO: Caching? + + if (const CXXMethodDecl* MD = dyn_cast(Decl)) { + const CXXRecordDecl* ClassDecl = MD->getParent(); + const FunctionProtoType* FuncType = + Decl->getType()->castAs(); + FunctionOptions Options = FunctionOptions::None; + if (!IgnoreConstructorFlags && isa(Decl)) { + Options = Options | FunctionOptions::Constructor; + if (ClassDecl->getNumVBases() > 0) { + Options = Options | FunctionOptions::ConstructorWithVirtualBases; + } + } + + return computeTypeIndexForMemberFunctionType(ClassDecl, FuncType, + Options, MD->isStatic()); + } + + QualType FuncType = Decl->getType(); + if (!Decl->hasWrittenPrototype()) { + // Use an unprototyped function type for the function. For K&R style + // definitions, Clang uses a FunctionProtoType, since it does know the + // parameter types, but C1 uses the unprototyped type. + if (const FunctionProtoType* FuncProtoType = + dyn_cast(Decl->getFunctionType())) { + FuncType = Context.getFunctionNoProtoType( + FuncProtoType->getReturnType(), FuncProtoType->getExtInfo()); + } + } + + return getTypeIndex(FuncType); +} + +TypeIndex CodeViewTypeTable::computeTypeIndex(QualType Type) +{ + Type::TypeClass typeClass = Type->getTypeClass(); + switch (typeClass) { + case Type::TypeClass::FunctionNoProto: + case Type::TypeClass::FunctionProto: + // isFunction + return computeTypeIndexForFunctionType( + Type->castAs()); + + case Type::TypeClass::ConstantArray: + //TODO: Other array types? + // isAnyArray + return computeTypeIndexForConstantArrayType(Type); + + case Type::TypeClass::IncompleteArray: + return computeTypeIndexForIncompleteArrayType(Type); + + case Type::TypeClass::Pointer: + return computeTypeIndexForPointerOrReferenceType(Type, + PointerMode::Pointer); + + case Type::TypeClass::LValueReference: + return computeTypeIndexForPointerOrReferenceType(Type, + PointerMode::LValueReference); + + case Type::TypeClass::RValueReference: + return computeTypeIndexForPointerOrReferenceType(Type, + PointerMode::RValueReference); + + case Type::TypeClass::Enum: + return computeTypeIndexForEnumType(cast(Type.getTypePtr()), + Type.getCVRQualifiers()); + + case Type::TypeClass::Record: + return computeTypeIndexForRecordType(cast(Type.getTypePtr()), + Type.getCVRQualifiers()); + + case Type::TypeClass::Builtin: + return computeTypeIndexForBuiltinType(cast(Type.getTypePtr()), + Type.getCVRQualifiers()); + + case Type::TypeClass::Elaborated: + return computeTypeIndexForElaboratedType( + cast(Type.getTypePtr()), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::Typedef: + return computeTypeIndexForTypedefType( + cast(Type.getTypePtr()), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::Decayed: + return computeTypeIndexForDecayedType(cast(Type.getTypePtr()), + Type.getLocalCVRQualifiers()); + + case Type::TypeClass::Paren: + return computeTypeIndexForParenType(cast(Type.getTypePtr()), + Type.getLocalCVRQualifiers()); + + case Type::TypeClass::Attributed: + return computeTypeIndexForAttributedType(cast(Type.getTypePtr()), + Type.getLocalCVRQualifiers()); + + case Type::TypeClass::SubstTemplateTypeParm: + return computeTypeIndexForSubstTemplateTypeParm( + Type->castAs(), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::TemplateSpecialization: + return computeTypeIndexForTemplateSpecialization( + Type->castAs(), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::MemberPointer: + return computeTypeIndexForMemberPointer( + Type->castAs(), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::Vector: + return computeTypeIndexForVector(Type->castAs(), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::Auto: + return computeTypeIndexForAuto(Type->castAs(), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::Decltype: + return computeTypeIndexForDecltype(Type->castAs(), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::Adjusted: + return computeTypeIndexForAdjusted(Type->castAs(), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::TypeOf: + return computeTypeIndexForTypeOf(Type->castAs(), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::TypeOfExpr: + return computeTypeIndexForTypeOfExpr(Type->castAs(), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::InjectedClassName: + return computeTypeIndexForInjectedClassName(Type->castAs(), Type.getLocalCVRQualifiers()); + + case Type::TypeClass::Atomic: + case Type::TypeClass::UnaryTransform: + case Type::TypeClass::VariableArray: + case Type::TypeClass::BlockPointer: + case Type::TypeClass::Complex: + case Type::TypeClass::ObjCInterface: + case Type::TypeClass::ObjCObject: + case Type::TypeClass::ObjCObjectPointer: + case Type::TypeClass::ExtVector: + // Not yet implemented. + assert(false); + return TypeIndex(); + + case Type::TypeClass::SubstTemplateTypeParmPack: + case Type::TypeClass::PackExpansion: + case Type::TypeClass::TemplateTypeParm: + case Type::TypeClass::DependentName: + case Type::TypeClass::DependentSizedArray: + case Type::TypeClass::DependentSizedExtVector: + case Type::TypeClass::DependentTemplateSpecialization: + case Type::TypeClass::UnresolvedUsing: + // Should not appear outside of uninstantiated contexts. + assert(false); + return TypeIndex(); + } + assert(false); + return TypeIndex(); +} + +SimpleTypeKind CodeViewTypeTable::computeSimpleTypeKindForBuiltinType( + const BuiltinType* Type) +{ + //TODO: HRESULT handling + BuiltinType::Kind Kind = Type->getKind(); + switch (Kind) { + case BuiltinType::Kind::Void: + return SimpleTypeKind::Void; + case BuiltinType::Kind::Bool: + return SimpleTypeKind::Boolean8; + case BuiltinType::Kind::Char_S: + case BuiltinType::Kind::Char_U: + return SimpleTypeKind::NarrowCharacter; + case BuiltinType::Kind::SChar: + if (Context.getLangOpts().CPlusPlus) { + return SimpleTypeKind::SignedCharacter; + } + else { + return SimpleTypeKind::NarrowCharacter; + } + break; + case BuiltinType::Kind::UChar: + return SimpleTypeKind::UnsignedCharacter; + case BuiltinType::Kind::WChar_U: + return SimpleTypeKind::WideCharacter; + case BuiltinType::Kind::Short: + return SimpleTypeKind::Int16Short; + case BuiltinType::Kind::UShort: + return SimpleTypeKind::UInt16Short; + case BuiltinType::Kind::Int: + return SimpleTypeKind::Int32; + case BuiltinType::Kind::UInt: + return SimpleTypeKind::UInt32; + case BuiltinType::Kind::Long: + return SimpleTypeKind::Int32Long; + case BuiltinType::Kind::ULong: + return SimpleTypeKind::UInt32Long; + case BuiltinType::Kind::LongLong: + return SimpleTypeKind::Int64Quad; + case BuiltinType::Kind::ULongLong: + return SimpleTypeKind::UInt64Quad; + case BuiltinType::Kind::Float: + return SimpleTypeKind::Float32; + case BuiltinType::Kind::Double: + case BuiltinType::Kind::LongDouble: + return SimpleTypeKind::Float64; + case BuiltinType::Kind::NullPtr: + // TODO + return SimpleTypeKind::None; + + default: + assert(false && "Unimplemented builtin type kind"); + return SimpleTypeKind::None; + } +} + +TypeIndex CodeViewTypeTable::computeModifiedTypeIndex(TypeIndex TypeInd, + unsigned int CVR) +{ + ModifierOptions Mods = ModifierOptions::None; + if (CVR & Qualifiers::Const) { + Mods = Mods | ModifierOptions::Const; + } + if (CVR & Qualifiers::Volatile) { + Mods = Mods | ModifierOptions::Volatile; + } + //TODO: Unaligned + //TODO: Restrict + + if (Mods == ModifierOptions::None) { + return TypeInd; + } + else { + return Builder.writeModifier(ModifierRecord(TypeInd, Mods)); + } +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForModifiedType(QualType Type) +{ + ModifierOptions Mods = ModifierOptions::None; + if (Type.isConstQualified()) { + Mods = Mods | ModifierOptions::Const; + } + if (Type.isVolatileQualified()) { + Mods = Mods | ModifierOptions::Volatile; + } + /* + if (Type.isUnalignedQualified()) { + Mods = Mods | ModifierOptions::Unaligned; + } + */ + + TypeIndex UnmodifiedTypeInd = getTypeIndex(Type.getUnqualifiedType()); + return Builder.writeModifier(ModifierRecord(UnmodifiedTypeInd, Mods)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForBuiltinType( + const BuiltinType* Type, unsigned int CVR) +{ + TypeIndex TypeInd(computeSimpleTypeKindForBuiltinType(Type)); + + return computeModifiedTypeIndex(TypeInd, CVR); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForFunctionType( + const FunctionType* Type) +{ + TypeIndex ReturnTypeInd = getTypeIndex(Type->getReturnType()); + + uint16_t parameterCount; + llvm::SmallVector ArgumentTypes; + if (const FunctionProtoType* ProtoType = dyn_cast(Type)) { + for (QualType ParamType : ProtoType->getParamTypes()) { + ArgumentTypes.push_back(getTypeIndex(ParamType)); + } + if (ProtoType->isVariadic()) { + ArgumentTypes.push_back(TypeIndex()); + } + parameterCount = static_cast(ArgumentTypes.size()); + } + else { + // Unprototyped function types get a single unknown argument, just like + // varargs. Unlike varargs, though, the unknown argument doesn't count as + // part of the parameter count in the procedure record. + ArgumentTypes.push_back(TypeIndex()); + parameterCount = 0; + } + TypeIndex ArgumentListInd = Builder.writeArgumentList(ArgumentListRecord(ArgumentTypes)); + + CallingConvention CallConv = translateCallingConvention(Type->getCallConv()); + FunctionOptions Options = FunctionOptions::None; + if (returnsUdt(Type, false)) { + Options = Options | FunctionOptions::CxxReturnUdt; + } + return Builder.writeProcedure(ProcedureRecord(ReturnTypeInd, CallConv, Options, + parameterCount, ArgumentListInd)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForMemberFunctionType( + const CXXRecordDecl* ClassDecl, const FunctionProtoType* FuncType, + FunctionOptions Options, bool IsStatic) +{ + //TODO: This adjustors? + int32_t ThisPointerAdjustment = 0; + TypeIndex ReturnTypeInd = getTypeIndex(FuncType->getReturnType()); + TypeIndex ClassTypeInd = + getTypeIndexForTagDeclaration(ClassDecl->getCanonicalDecl()); + TypeIndex ThisTypeInd; + if (!IsStatic) { + ThisTypeInd = getTypeIndex(computeThisType(ClassDecl, FuncType)); + } + CallingConvention CallConv = + translateCallingConvention(FuncType->getCallConv()); + + uint16_t parameterCount; + llvm::SmallVector ArgumentTypes; + for (QualType ParamType : FuncType->getParamTypes()) { + ArgumentTypes.push_back(getTypeIndex(ParamType)); + } + if (FuncType->isVariadic()) { + ArgumentTypes.push_back(TypeIndex()); + } + parameterCount = static_cast(ArgumentTypes.size()); + + TypeIndex ArgumentListInd = Builder.writeArgumentList(ArgumentListRecord(ArgumentTypes)); + + if (returnsUdt(FuncType, !IsStatic)) { + Options = Options | FunctionOptions::CxxReturnUdt; + } + + return Builder.writeMemberFunction(MemberFunctionRecord(ReturnTypeInd, + ClassTypeInd, ThisTypeInd, CallConv, Options, parameterCount, ArgumentListInd, + ThisPointerAdjustment)); +} + +PointerOptions CodeViewTypeTable::computePointerOptions(unsigned int CVR) const +{ + PointerOptions Options = PointerOptions::None; + if (CVR & Qualifiers::Const) { + Options = Options | PointerOptions::Const; + } + if (CVR & Qualifiers::Volatile) { + Options = Options | PointerOptions::Volatile; + } + + return Options; +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForPointerOrReferenceType( + QualType Type, PointerMode Mode) +{ + TypeIndex PointeeTypeInd = getTypeIndex(Type->getPointeeType()); + + PointerOptions Options = computePointerOptions(Type.getCVRQualifiers()); + + uint8_t Size = Context.getTypeSizeInChars(Type).getQuantity(); + if ((Mode == PointerMode::Pointer) && PointeeTypeInd.isSimple() && + (PointeeTypeInd.getSimpleMode() == SimpleTypeMode::Direct) && + (Options == PointerOptions::None)) { + SimpleTypeMode SimpleMode = (Size == 8) ? SimpleTypeMode::NearPointer64 : + SimpleTypeMode::NearPointer32; + return TypeIndex(PointeeTypeInd.getSimpleKind(), SimpleMode); + } + else { + PointerKind Kind = (Size == 8) ? PointerKind::Near64 : PointerKind::Near32; + return Builder.writePointer(PointerRecord(PointeeTypeInd, Kind, Mode, Options, Size)); + } +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForConstantArrayType( + QualType Type) +{ + const ConstantArrayType* ArrayType = + cast(Type.getTypePtr()); + QualType ElementType = ArrayType->getElementType(); + ElementType = ElementType.withCVRQualifiers(Type.getCVRQualifiers()); + TypeIndex ElementTypeInd = getTypeIndex(ElementType); + uint64_t Size = Context.getTypeSizeInChars(Type).getQuantity(); + + //TODO: Index type? + return Builder.writeArray(ArrayRecord(ElementTypeInd, ArrayIndexTI, Size, "")); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForIncompleteArrayType( + QualType Type) +{ + const IncompleteArrayType* ArrayType = + cast(Type.getTypePtr()); + QualType ElementType = ArrayType->getElementType(); + ElementType = ElementType.withCVRQualifiers(Type.getCVRQualifiers()); + TypeIndex ElementTypeInd = getTypeIndex(ElementType); + + //TODO: Index type? + return Builder.writeArray(ArrayRecord(ElementTypeInd, ArrayIndexTI, 0, "")); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForVTableShape( + const CXXRecordDecl* D) +{ + assert(D->isPolymorphic()); + + const VTableLayout& VTLayout = + VTableContext.getVFTableLayout(D, Context.toCharUnitsFromBits(0)); + + SmallVector Slots; + for (const VTableComponent& Component : + llvm::make_range(VTLayout.vtable_component_begin(), + VTLayout.vtable_component_end())) { + VTableComponent::Kind Kind = Component.getKind(); + switch (Kind) { + case VTableComponent::Kind::CK_RTTI: + // Doesn't count. + break; + + case VTableComponent::Kind::CK_FunctionPointer: + case VTableComponent::Kind::CK_DeletingDtorPointer: + Slots.push_back(VirtualTableSlotKind::Near); + break; + + case VTableComponent::Kind::CK_CompleteDtorPointer: + case VTableComponent::Kind::CK_OffsetToTop: + case VTableComponent::Kind::CK_UnusedFunctionPointer: + case VTableComponent::Kind::CK_VCallOffset: + case VTableComponent::Kind::CK_VBaseOffset: + assert(false); + break; + } + } + + return Builder.writeVirtualTableShape(VirtualTableShapeRecord(Slots)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForEnumType(const EnumType* Type, + unsigned int CVR) +{ + //TODO: Forward-declared enums + TypeIndex TypeInd = getTypeIndexForTagDefinition(Type->getDecl()->getDefinition()); + + return computeModifiedTypeIndex(TypeInd, CVR); +} + +TypeIndex CodeViewTypeTable::getTypeIndexForTagDeclaration(const TagDecl* D) +{ + const TagDecl* CD = D->getCanonicalDecl(); + auto Existing = TagTypes.find(CD); + if (Existing != TagTypes.end()) { + return Existing->second.DeclarationTI; + } + + TypeIndex TypeInd = computeTypeIndexForTagDeclaration(CD); + TagTypeIndices TagTypeInds = { TypeInd, TypeIndex() }; + TagTypes.insert(make_pair(CD, TagTypeInds)); + + // Add the declaration to the queue of declaration for which we will + // eventually create definitions. + PendingTags.push_back(CD); + + return TypeInd; +} + +TypeIndex CodeViewTypeTable::getTypeIndexForTagDefinition(const TagDecl* D) +{ + assert(D->isThisDeclarationADefinition()); + + bool hadDeclaration; + const TagDecl* CD = D->getCanonicalDecl(); + auto Existing = TagTypes.find(CD); + if (Existing != TagTypes.end()) { + hadDeclaration = true; + if (Existing->second.DefinitionTI != TypeIndex()) { + return Existing->second.DefinitionTI; + } + } + else { + hadDeclaration = false; + TagTypeIndices TagTypeInds = { TypeIndex(), TypeIndex() }; + Existing = TagTypes.insert(make_pair(CD, TagTypeInds)).first; + } + + TypeIndex TypeInd = computeTypeIndexForTagDefinition(D); + Existing->second.DefinitionTI = TypeInd; + if (!hadDeclaration) { + Existing->second.DeclarationTI = TypeInd; + } + setDefinitionForDeclaration(Existing->second.DeclarationTI, + Existing->second.DefinitionTI); + + return TypeInd; +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForTagDeclaration( + const TagDecl* D) +{ + assert(D == D->getCanonicalDecl()); + + TagDecl::TagKind Kind = D->getTagKind(); + switch (Kind) { + case TagDecl::TagKind::TTK_Enum: + return computeTypeIndexForEnumDeclaration(cast(D)); + + case TagDecl::TagKind::TTK_Class: + return computeTypeIndexForRecordDeclaration(cast(D), + TypeRecordKind::Class); + + case TagDecl::TagKind::TTK_Struct: + return computeTypeIndexForRecordDeclaration(cast(D), + TypeRecordKind::Structure); + + case TagDecl::TagKind::TTK_Union: + return computeTypeIndexForRecordDeclaration(cast(D), + TypeRecordKind::Union); + + case TagDecl::TagKind::TTK_Interface: + assert(false); + return TypeIndex(); + + default: + assert(false); + return TypeIndex(); + } +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForTagDefinition(const TagDecl* D) +{ + assert(D->isThisDeclarationADefinition()); + + TagDecl::TagKind Kind = D->getTagKind(); + switch (Kind) { + case TagDecl::TagKind::TTK_Enum: + return computeTypeIndexForEnumDefinition(cast(D)); + + case TagDecl::TagKind::TTK_Class: + return computeTypeIndexForRecordDefinition(cast(D), + TypeRecordKind::Class); + + case TagDecl::TagKind::TTK_Struct: + return computeTypeIndexForRecordDefinition(cast(D), + TypeRecordKind::Structure); + + case TagDecl::TagKind::TTK_Union: + return computeTypeIndexForRecordDefinition(cast(D), + TypeRecordKind::Union); + + case TagDecl::TagKind::TTK_Interface: + assert(false); + return TypeIndex(); + + default: + assert(false); + return TypeIndex(); + } +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForEnumDeclaration( + const EnumDecl* D) +{ + ClassOptions Options = ClassOptions::ForwardReference | + computeTagClassOptions(D); + + return Builder.writeEnum(EnumRecord(0, Options, TypeIndex(), + computeTagName(D), computeTagUniqueName(D), TypeIndex())); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForEnumDefinition( + const EnumDecl* D) +{ + assert(D->isThisDeclarationADefinition()); + +ClassOptions Options = computeTagClassOptions(D); + +TypeIndex UnderlyingType = getTypeIndex(D->getIntegerType()); +if (UnderlyingType == TypeIndex::WideCharacter()) { + // Underlying type treats wchar_t as unsigned short. + UnderlyingType = TypeIndex::UInt16Short(); +} + +FieldList Fields(D, Options); +for (const EnumConstantDecl* ED : D->enumerators()) { + Fields.getBuilder().writeEnumerate(MemberAccess::Public, + ED->getInitVal().getLimitedValue(), ED->getName()); + Fields.incrementMemberCount(); +} +TypeIndex FieldListInd = Builder.writeFieldList(Fields.getBuilder()); + +return Builder.writeEnum(EnumRecord(Fields.getMemberCount(), Fields.getOptions(), + FieldListInd, computeTagName(D), computeTagUniqueName(D), UnderlyingType)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForRecordType( + const RecordType* Type, unsigned int CVR) +{ + TypeIndex TypeInd = getTypeIndexForTagDeclaration( + Type->getDecl()->getCanonicalDecl()); + + return computeModifiedTypeIndex(TypeInd, CVR); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForRecordDefinition( + const RecordDecl* RD, TypeRecordKind Kind) +{ + assert(RD->isThisDeclarationADefinition()); + + //TODO: See TiForTagDecl for additional handling of WinRT, CLR, EnC, worklist, and unnamed tag handling. + + ClassOptions Options = computeTagClassOptions(RD); + if (Kind == TypeRecordKind::Union) { + Options = Options | ClassOptions::Sealed; + } + + /* + if (Type->isIntrinsicTag()) { + Options = Options | ClassOptions::Intrinsic; + } + */ + + WindowsRTClassKind WinRTKind = getWindowsRTClassKind(RD); + uint64_t Size = Context.getTypeSizeInChars( + Context.getTagDeclType(RD)).getQuantity(); + HfaKind Hfa = computeHfaKind(RD); + + FieldList Fields(RD, Options); + + TypeIndex VTableShape; + if (const CXXRecordDecl* CxxD = dyn_cast(RD)) { + const ASTRecordLayout& Layout = Context.getASTRecordLayout(RD); + + if (CxxD->isPolymorphic() && Layout.hasOwnVFPtr()) { + VTableShape = computeTypeIndexForVTableShape(CxxD); + } + + emitBaseClasses(Fields, RD); + + if (Layout.hasOwnVFPtr()) { + TypeIndex VTableShapePointer = Builder.writePointer(PointerRecord( + VTableShape,DefaultPointerKind, PointerMode::Pointer, PointerOptions::None, + getPointerByteSize())); + Fields.getBuilder().writeVirtualFunctionTablePointer(VTableShapePointer); + Fields.incrementMemberCount(); + } + } + + DeclList Members; + gatherMemberDecls(RD, Members); + DeclList::const_iterator I = Members.begin(); + while (I != Members.end()) { + const NamedDecl* D = *I; + ++I; + if (const CXXMethodDecl* MD = dyn_cast(D)) { + DeclList::const_iterator OverloadsEnd = find_if_not(I, Members.cend(), + [&](const NamedDecl* OtherD) { + return OtherD->getDeclName() == D->getDeclName(); + }); + + SmallVector Overloads; + Overloads.push_back(MD); + for (const NamedDecl* Overload : make_range(I, OverloadsEnd)) { + Overloads.push_back(cast(Overload)); + } + I = OverloadsEnd; + + emitRecordForMethodDecls(Fields, D->getDeclName(), Overloads.data(), + Overloads.size()); + } + else { + emitRecordForMemberDecl(Fields, D); + } + } + + if (const CXXRecordDecl* CxxD = dyn_cast(RD)) { + if (!CxxD->hasUserDeclaredConstructor()) { + QualType RecordType = Context.getRecordType(CxxD); + emitRecordForMethodDecls(Fields, + Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(RecordType)), nullptr, 0); + } + + const CXXDestructorDecl* Dtor = CxxD->getDestructor(); + if ((Dtor != nullptr) && Dtor->isImplicit()) { + if (Dtor->isVirtual() || !Dtor->isTrivial()) { + const CXXMethodDecl* DtorMethod = Dtor; + emitRecordForMethodDecls(Fields, Dtor->getDeclName(), &DtorMethod, 1); + } + } + + if ((Fields.getOptions() & + ClassOptions::HasOverloadedAssignmentOperator) == ClassOptions::None) { + emitRecordForMethodDecls(Fields, + Context.DeclarationNames.getCXXOperatorName( + OverloadedOperatorKind::OO_Equal), nullptr, 0); + } + + if (Dtor != nullptr) { + if (Dtor->isVirtual()) { + if (CxxD->hasDefaultConstructor()) { + emitRecordForLocalVftableConstructorClosure(Fields, CxxD); + } + } + if (!Dtor->isTrivial()) { + emitRecordForVectorDeletingDestructor(Fields, Dtor); + } + } + } + + TypeIndex FieldListInd = Builder.writeFieldList(Fields.getBuilder()); + + return Builder.writeAggregate(AggregateRecord(Kind, Fields.getMemberCount(), + Fields.getOptions(), Hfa, WinRTKind, FieldListInd, TypeIndex(), + VTableShape, Size, computeTagName(RD), computeTagUniqueName(RD))); +} + +void CodeViewTypeTable::emitRecordForLocalVftableConstructorClosure( + FieldList& Fields, const CXXRecordDecl* D) +{ + MemberAccess Access = MemberAccess::Public; + + QualType Type = Context.getFunctionType(Context.VoidTy, {}, + FunctionProtoType::ExtProtoInfo(getThisCallCallingConv())); + TypeIndex TI = computeTypeIndexForMemberFunctionType(D, + Type->castAs(), FunctionOptions::None, false); + MethodOptions Options = MethodOptions::CompilerGenerated; + MethodKind Kind = MethodKind::Vanilla; + + Fields.getBuilder().writeOneMethod(Access, Kind, + Options, TI, -1, "__local_vftable_ctor_closure"); + + Fields.incrementMemberCount(); +} + +void CodeViewTypeTable::emitRecordForVectorDeletingDestructor(FieldList& Fields, + const CXXDestructorDecl* D) +{ + MemberAccess Access = translateAccess(D->getAccess()); + QualType Type = Context.getFunctionType(Context.VoidPtrTy, + { Context.UnsignedIntTy }, + FunctionProtoType::ExtProtoInfo(getThisCallCallingConv())); + TypeIndex TI = computeTypeIndexForMemberFunctionType(D->getParent(), + Type->castAs(), FunctionOptions::None, false); + MethodOptions Options = computeMethodOptions(D) | + MethodOptions::CompilerGenerated; + VirtualMethodInfo VInfo = computeVirtualMethodInfo(D, true); + + Fields.getBuilder().writeOneMethod(Access, VInfo.getKind(), + Options, TI, VInfo.getSlotOffset(), "__vecDelDtor"); + + Fields.incrementMemberCount(); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForRecordDeclaration( + const RecordDecl* D, TypeRecordKind Kind) +{ + assert(D == D->getCanonicalDecl()); + + //TODO: See TiForTagDecl for additional handling of WinRT, CLR, EnC, worklist, and unnamed tag handling. + + ClassOptions Options = ClassOptions::ForwardReference | + computeTagClassOptions(D); + /* + if (Type->isIntrinsicTag()) { + Options = Options | ClassOptions::Intrinsic; + } + */ + + WindowsRTClassKind WinRTKind = getWindowsRTClassKind(D); + + return Builder.writeAggregate(AggregateRecord(Kind, 0, Options, HfaKind::None, + WinRTKind, TypeIndex(), TypeIndex(), TypeIndex(), 0, + computeTagName(D), computeTagUniqueName(D))); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForTypedefType( + const TypedefType* Type, unsigned int CVR) +{ + const TypedefNameDecl* decl = Type->getDecl(); + if (isWCharT(decl)) { + return computeModifiedTypeIndex(TypeIndex::WideCharacter(), CVR); + } + else { + return getTypeIndex(Type->getDecl()->getUnderlyingType().withCVRQualifiers(CVR)); + } +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForDecayedType( + const DecayedType* Type, unsigned int CVR) +{ + TypeIndex TypeInd = getTypeIndex(Type->getDecayedType()); + return computeModifiedTypeIndex(TypeInd, CVR); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForParenType( + const ParenType* Type, unsigned int CVR) +{ + return getTypeIndex(Type->getInnerType().withCVRQualifiers(CVR)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForAttributedType( + const AttributedType* Type, unsigned int CVR) +{ + return getTypeIndex(Type->getModifiedType().withCVRQualifiers(CVR)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForSubstTemplateTypeParm( + const SubstTemplateTypeParmType* Type, unsigned int CVR) +{ + return getTypeIndex(Type->getReplacementType().withCVRQualifiers(CVR)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForTemplateSpecialization( + const TemplateSpecializationType* Type, unsigned int CVR) +{ + return getTypeIndex(Type->desugar().withCVRQualifiers(CVR)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForMemberPointer( + const MemberPointerType* Type, unsigned int CVR) +{ + QualType PointeeTy = Type->getPointeeType(); + const CXXRecordDecl* RD = Type->getClass()->getAsCXXRecordDecl(); + + TypeIndex PointeeTypeInd; + PointerMode Mode; + if (Type->isMemberDataPointer()) { + Mode = PointerMode::PointerToDataMember; + PointeeTypeInd = getTypeIndex(PointeeTy); + } + else { + Mode = PointerMode::PointerToMemberFunction; + PointeeTypeInd = computeTypeIndexForMemberFunctionType(RD, + PointeeTy->castAs(), FunctionOptions::None, false); + } + QualType ContainingTy(Type->getClass(), 0); + TypeIndex ContainingTypeInd = getTypeIndex(ContainingTy); + + PointerOptions Options = computePointerOptions(CVR); + + uint8_t Size; + PointerToMemberRepresentation Representation; + if (RD->getAttr() == nullptr) { + //TODO: Fill in the definition later + Size = 0; + Representation = PointerToMemberRepresentation::Unknown; + } + else { + Size = Context.getTypeSizeInChars(Type).getQuantity(); + + MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); + Representation = translatePointerToMemberRepresentation(Inheritance, + Type->isMemberFunctionPointer()); + } + + return Builder.writePointerToMember(PointerToMemberRecord( + PointeeTypeInd, DefaultPointerKind, Mode, Options, Size, ContainingTypeInd, + Representation)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForVector( + const VectorType* Type, unsigned int CVR) +{ + //TODO: Name, HFA + + uint32_t Size = Context.getTypeSizeInChars(Type).getQuantity(); + FieldListRecordBuilder Fields; + TypeIndex ArrayTI = Builder.writeArray(ArrayRecord(getTypeIndex( + Type->getElementType()), ArrayIndexTI, Size, "")); + Fields.writeMember(MemberAccess::Public, ArrayTI, 0, "Elements"); + TypeIndex FieldListTI = Builder.writeFieldList(Fields); + + return Builder.writeAggregate(AggregateRecord(TypeRecordKind::Structure, 1, ClassOptions::HasUniqueName, + HfaKind::None, WindowsRTClassKind::None, FieldListTI, TypeIndex(), TypeIndex(), Size, + "Vector", "Vector")); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForAuto( + const AutoType* Type, unsigned int CVR) +{ + return getTypeIndex(Type->getDeducedType().withCVRQualifiers(CVR)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForDecltype( + const DecltypeType* Type, unsigned int CVR) +{ + return getTypeIndex(Type->getUnderlyingType().withCVRQualifiers(CVR)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForInjectedClassName( + const InjectedClassNameType* Type, unsigned int CVR) +{ + return getTypeIndex(Type->getInjectedSpecializationType().withCVRQualifiers(CVR)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForAdjusted( + const AdjustedType* Type, unsigned int CVR) +{ + return getTypeIndex(Type->getAdjustedType().withCVRQualifiers(CVR)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForTypeOf( + const TypeOfType* Type, unsigned int CVR) +{ + return getTypeIndex(Type->getUnderlyingType().withCVRQualifiers(CVR)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForTypeOfExpr( + const TypeOfExprType* Type, unsigned int CVR) +{ + return getTypeIndex(Type->getUnderlyingExpr()->getType().withCVRQualifiers(CVR)); +} + +TypeIndex CodeViewTypeTable::computeTypeIndexForElaboratedType( + const ElaboratedType* Type, unsigned int CVR) +{ + return getTypeIndex(Type->getNamedType().withCVRQualifiers(CVR)); +} + +ClassOptions CodeViewTypeTable::computeTagClassOptions(const TagDecl* D) +{ + ClassOptions Options = ClassOptions::HasUniqueName; + if (D->getParent()->isRecord()) { + Options = Options | ClassOptions::Nested; + } + if (Context.getLangOpts().CPlusPlus && + (D->getParentFunctionOrMethod() != nullptr)) { + Options = Options | ClassOptions::Scoped; + } + + return Options; +} + +string CodeViewTypeTable::computeTagName(const TagDecl* D) +{ + SmallVector Buffer; + raw_svector_ostream Stream(Buffer); + + DisplayNameGenerator Gen(Context, Stream); + Gen.generateDecl(D); + + Stream.flush(); + + return string(Buffer.data(), Buffer.size()); +} + +string CodeViewTypeTable::computeTagUniqueName(const TagDecl* D) +{ + return computeTypeUniqueName(Context.getTagDeclType(D)); +} + +string CodeViewTypeTable::computeTypeUniqueName(QualType Type) +{ + SmallString<256> Buffer; + llvm::raw_svector_ostream Out(Buffer); + Out.write('.'); + MContext.mangleTypeName(Type, Out); + return Out.str(); +} + +void CodeViewTypeTable::finishDefinitions() +{ + while (!PendingTags.empty()) { + vector PreviousPendingTags; + PendingTags.swap(PreviousPendingTags); + for (const TagDecl* D : PreviousPendingTags) { + const TagDecl* Def = D->getDefinition(); + if (Def != nullptr) { + getTypeIndexForTagDefinition(Def); + } + } + } +} + +TypeIndex CodeViewTypeTable::getCachedTypeIndex(QualType Type) +{ + auto Existing = Types.find(Type.getAsOpaquePtr()); + if (Existing != Types.end()) { + return Existing->second; + } + else { + return TypeIndex(); + } +} + +void CodeViewTypeTable::setCachedTypeIndex(QualType Type, TypeIndex TypeInd) +{ + Types.insert(std::make_pair(Type.getAsOpaquePtr(), TypeInd)); +} + +void CodeViewTypeTable::emitRecordForMemberDecl(FieldList& Fields, + const Decl* D) +{ + Decl::Kind kind = D->getKind(); + switch (kind) { + case Decl::Kind::Field: + emitRecordForFieldDecl(Fields, cast(D)); + break; + + case Decl::Kind::IndirectField: + emitRecordForIndirectFieldDecl(Fields, cast(D)); + break; + + case Decl::Kind::CXXConstructor: + case Decl::Kind::CXXDestructor: + case Decl::Kind::CXXConversion: + case Decl::Kind::CXXMethod: + // These should have been emitted via emitRecordForMethodDecls. + assert(false); + break; + + case Decl::Kind::Var: + emitRecordForStaticFieldDecl(Fields, cast(D)); + break; + + case Decl::Kind::Enum: + case Decl::Kind::CXXRecord: + case Decl::Kind::Record: + case Decl::Kind::Typedef: + emitRecordForNestedType(Fields, cast(D)); + break; + + case Decl::Kind::AccessSpec: + case Decl::Kind::FunctionTemplate: + case Decl::Kind::ClassTemplate: + case Decl::Kind::VarTemplate: + break; + + default: + assert(false); + break; + } +} + +void CodeViewTypeTable::emitRecordForMethodDecls(FieldList& Fields, + DeclarationName DN, const CXXMethodDecl* const* Decls, size_t Count) +{ + MethodListHelper Helper(*this, Fields, DN); + + DeclarationName::NameKind NameKind = DN.getNameKind(); + switch (NameKind) { + case DeclarationName::NameKind::CXXConstructorName: + emitRecordsForImplicitConstructors(Helper, + cast(Fields.getTagDecl()), Decls, Count); + break; + + case DeclarationName::NameKind::CXXOperatorName: + if (DN.getCXXOverloadedOperator() == + OverloadedOperatorKind::OO_Equal) { + emitRecordsForImplicitAssignmentOperators(Helper, + cast(Fields.getTagDecl()), Decls, Count); + } + break; + + default: + break; + } + + for (const CXXMethodDecl* D : make_range(Decls, Decls + Count)) { + MethodInfo Method = computeMethodInfo(D); + Helper.writeMethod(Method); + } + + Helper.finish(); +} + +void CodeViewTypeTable::emitRecordsForImplicitConstructors( + MethodListHelper& Methods, const CXXRecordDecl* RD, + const CXXMethodDecl* const* Decls, size_t Count) +{ + QualType RecordType = Context.getRecordType(RD); + + bool HasImplicitMoveConstructor = RD->needsImplicitMoveConstructor(); + bool HasImplicitCopyConstructor = RD->needsImplicitCopyConstructor(); + bool HasImplicitDefaultConstructor = RD->needsImplicitDefaultConstructor(); + for (const Decl* D : RD->decls()) { + if (D->isImplicit()) { + if (const CXXConstructorDecl* CD = dyn_cast(D)) { + if (CD->isMoveConstructor()) { + HasImplicitMoveConstructor = true; + } + if (CD->isCopyConstructor()) { + HasImplicitCopyConstructor = true; + } + if (CD->isDefaultConstructor()) { + HasImplicitDefaultConstructor = true; + } + } + } + } + + if (HasImplicitMoveConstructor) { + if (RD->isPolymorphic() || (RD->getNumVBases() > 0)) { + MethodInfo Method = computeImplicitConstructorInfo(RD, + { Context.getRValueReferenceType(RecordType) }); + + Methods.writeMethod(Method); + } + } + + if (HasImplicitCopyConstructor) { + if (RD->isPolymorphic() || (RD->getNumVBases() > 0)) { + QualType PointeeType = RecordType; + if (RD->implicitCopyConstructorHasConstParam()) { + PointeeType.addConst(); + } + MethodInfo Method = computeImplicitConstructorInfo(RD, + { Context.getLValueReferenceType(PointeeType) }); + + Methods.writeMethod(Method); + } + } + + if (HasImplicitDefaultConstructor) { + if (RD->isPolymorphic() || (RD->getNumVBases() > 0)) { + MethodInfo Method = computeImplicitConstructorInfo(RD, {}); + + Methods.writeMethod(Method); + } + } +} + +void CodeViewTypeTable::emitRecordsForImplicitAssignmentOperators( + MethodListHelper& Methods, const CXXRecordDecl* RD, + const CXXMethodDecl* const* Decls, size_t Count) +{ + QualType RecordType = Context.getRecordType(RD); + + bool HasImplicitMoveAssignment = RD->needsImplicitMoveAssignment(); + bool HasImplicitCopyAssignment = RD->needsImplicitCopyAssignment(); + for (const Decl* D : RD->decls()) { + if (D->isImplicit()) { + if (const CXXMethodDecl* MD = dyn_cast(D)) { + if (MD->isMoveAssignmentOperator()) { + HasImplicitMoveAssignment = true; + } + if (MD->isCopyAssignmentOperator()) { + HasImplicitCopyAssignment = true; + } + } + } + } + + if (HasImplicitMoveAssignment && (RD->getNumVBases() == 0)) { + if (RD->isPolymorphic()) { + MethodInfo Method = computeImplicitAssignmentInfo(RD, + { Context.getRValueReferenceType(RecordType) }); + + Methods.writeMethod(Method); + } + } + + if (HasImplicitCopyAssignment) { + if (RD->isPolymorphic() || (RD->getNumVBases() > 0)) { + QualType PointeeType = RecordType; + if (RD->implicitCopyAssignmentHasConstParam()) { + PointeeType.addConst(); + } + MethodInfo Method = computeImplicitAssignmentInfo(RD, + { Context.getLValueReferenceType(PointeeType) }); + + Methods.writeMethod(Method); + } + } +} + +void CodeViewTypeTable::emitRecordForFieldDecl(FieldList& Fields, + const FieldDecl* D) +{ + MemberAccess Access = translateAccess(D->getAccess()); + + emitRecordForFieldDecl(Fields, D, D, Access); +} + +void CodeViewTypeTable::emitRecordForFieldDecl(FieldList& Fields, + const FieldDecl* D, const ValueDecl* VD, MemberAccess Access) +{ + TypeIndex TypeInd = getTypeIndex(D->getType()); + + uint64_t BitOffset = Context.getFieldOffset(VD); + if (D->isBitField()) { + if (D->getBitWidthValue(Context) == 0) { + // Don't emit records for zero-size bitfields. + return; + } + AllocationUnit AU = Context.getBitFieldAllocationUnit(VD); + uint64_t AUBitOffset = Context.toBits(AU.Offset); + TypeInd = Builder.writeBitField(BitFieldRecord(TypeInd, D->getBitWidthValue(Context), + BitOffset - AUBitOffset)); + BitOffset = AUBitOffset; + } + uint64_t ByteOffset = Context.toCharUnitsFromBits(BitOffset).getQuantity(); + Fields.getBuilder().writeMember(Access, TypeInd, ByteOffset, D->getName()); + Fields.incrementMemberCount(); +} + +void CodeViewTypeTable::emitRecordForIndirectFieldDecl(FieldList& Fields, + const IndirectFieldDecl* D) +{ + const FieldDecl* FD = D->getAnonField(); + const FieldDecl* OuterFD = cast(*(D->chain_begin())); + MemberAccess Access = translateAccess(OuterFD->getAccess()); + + emitRecordForFieldDecl(Fields, FD, D, Access); +} + +void CodeViewTypeTable::emitRecordForStaticFieldDecl(FieldList& Fields, + const VarDecl* D) +{ + TypeIndex TypeInd = getTypeIndex(D->getType()); + MemberAccess Access = translateAccess(D->getAccess()); + + Fields.getBuilder().writeStaticMember(Access, TypeInd, D->getName()); + Fields.incrementMemberCount(); +} + +void CodeViewTypeTable::emitRecordForNestedType(FieldList& Fields, + const TypeDecl* D) +{ + if (const TagDecl* TD = dyn_cast(D)) { + if (TD->isEmbeddedInDeclarator()) { + return; + } + } + + TypeIndex TypeInd = getTypeIndex(Context.getTypeDeclType(D)); + + Fields.getBuilder().writeNestedType(TypeInd, D->getName()); + Fields.incrementMemberCount(); + Fields.addOptions(ClassOptions::ContainsNestedClass); +} + +void CodeViewTypeTable::emitRecordForBaseClass(FieldList& Fields, + const CXXRecordDecl* D, const CXXBaseSpecifier& Base, bool isIndirect) +{ + TypeIndex TypeInd = getTypeIndex(Base.getType()); + MemberAccess Access = translateAccess(Base.getAccessSpecifier()); + + const RecordType* BaseRecordType = Base.getType()->castAs(); + const CXXRecordDecl* BaseDecl = + cast(BaseRecordType->getDecl()); + + if (Base.isVirtual()) { + const ASTRecordLayout& Layout = Context.getASTRecordLayout(D); + uint32_t VBPtrOffset = Layout.getVBPtrOffset().getQuantity(); + uint32_t VBIndex = VTableContext.getVBTableIndex(D, BaseDecl); + + TypeRecordKind Kind = isIndirect ? + TypeRecordKind::IndirectVirtualBaseClass : + TypeRecordKind::VirtualBaseClass; + Fields.getBuilder().writeVirtualBaseClass(Kind, Access, TypeInd, + getVirtualBasePointerTypeIndex(), VBPtrOffset, VBIndex); + Fields.incrementMemberCount(); + } + else { + assert(!isIndirect); + + const ASTRecordLayout& Layout = Context.getASTRecordLayout(D); + uint64_t Offset = Layout.getBaseClassOffset(BaseDecl).getQuantity(); + Fields.getBuilder().writeBaseClass(Access, TypeInd, Offset); + Fields.incrementMemberCount(); + } +} + +void CodeViewTypeTable::emitBaseClasses(FieldList& Fields, const RecordDecl* D) +{ + const CXXRecordDecl* CxxD = dyn_cast(D); + if (CxxD == nullptr) { + return; + } + + llvm::SmallPtrSet DirectVBaseTypes; + + for (const CXXBaseSpecifier& Base : CxxD->bases()) { + if (!Base.isVirtual()) { + emitRecordForBaseClass(Fields, CxxD, Base, false); + } + } + for (const CXXBaseSpecifier& Base : CxxD->bases()) { + if (Base.isVirtual()) { + emitRecordForBaseClass(Fields, CxxD, Base, false); + DirectVBaseTypes.insert(Context.getCanonicalType(Base.getType())); + } + } + for (const CXXBaseSpecifier& Base : CxxD->vbases()) { + assert(Base.isVirtual()); + if (!DirectVBaseTypes.count(Context.getCanonicalType(Base.getType()))) { + emitRecordForBaseClass(Fields, CxxD, Base, true); + } + } +} + +void CodeViewTypeTable::setDefinitionForDeclaration( + TypeIndex DeclarationTypeInd, TypeIndex DefinitionTypeInd) +{ + assert(DefinitionTypeInd != TypeIndex()); + if (DefinitionTypeInd != DeclarationTypeInd) { + DefinitionMap.insert(make_pair(DeclarationTypeInd, DefinitionTypeInd)); + } +} + +TypeIndex CodeViewTypeTable::getVirtualBasePointerTypeIndex() +{ + if (VirtualBasePointerTI == TypeIndex()) { + QualType Type = Context.getPointerType(Context.IntTy.withConst()); + VirtualBasePointerTI = getTypeIndex(Type); + } + + return VirtualBasePointerTI; +} + +HfaKind CodeViewTypeTable::computeHfaKind(const RecordDecl* D) const +{ + Optional Kind = None; + + // If this is a C++ record, check the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast(D)) { + if (!CXXRD->hasTrivialCopyConstructor() || !CXXRD->hasTrivialDestructor()) { + return HfaKind::None; + } + for (const CXXBaseSpecifier& Base : CXXRD->bases()) { + if (!mergeHfaKinds(Kind, computeHfaKind(Base.getType()))) { + return HfaKind::None; + } + } + } + + for (const FieldDecl* FD : D->fields()) { + if (!mergeHfaKinds(Kind, computeHfaKind(FD->getType()))) { + return HfaKind::None; + } + } + + return Kind.getValueOr(HfaKind::None); +} + +HfaKind CodeViewTypeTable::computeHfaKind(QualType Ty) const +{ + if (const ConstantArrayType* ArrayTy = Context.getAsConstantArrayType(Ty)) { + return computeHfaKind(ArrayTy->getElementType()); + } + else if (const RecordType* RecordTy = Ty->getAs()) { + const RecordDecl* RD = RecordTy->getDecl(); + + return computeHfaKind(RD); + } + else if (const BuiltinType* BuiltinTy = Ty->getAs()) { + switch (BuiltinTy->getKind()) { + case BuiltinType::Kind::Float: + return HfaKind::Float; + case BuiltinType::Kind::Double: + case BuiltinType::Kind::LongDouble: + return HfaKind::Double; + default: + //TODO: Vector types + return HfaKind::None; + } + } + else { + return HfaKind::None; + } +} + +MethodInfo CodeViewTypeTable::computeMethodInfo(const CXXMethodDecl* D) +{ + VirtualMethodInfo VInfo = computeVirtualMethodInfo(D, false); + return MethodInfo(translateAccess(D->getAccess()), + VInfo.getKind(), computeMethodOptions(D), + getTypeIndexForFunctionType(D, false, false), + VInfo.getSlotOffset()); +} + +CodeViewTypeTable::VirtualMethodInfo +CodeViewTypeTable::computeVirtualMethodInfo(const CXXMethodDecl* D, + bool ForceIntro) const +{ + if (D->isVirtual()) { + bool IsIntro = isIntroducingVirtual(D); + if (ForceIntro || IsIntro) { + int32_t SlotOffset; + if (IsIntro) { + SlotOffset = computeVTableSlotOffset(D); + } + else { + assert(D->size_overridden_methods() > 0); + SlotOffset = computeVTableSlotOffset(*D->begin_overridden_methods()); + } + if (D->isPure()) { + return VirtualMethodInfo(MethodKind::PureIntroducingVirtual, + SlotOffset); + } + else { + return VirtualMethodInfo(MethodKind::IntroducingVirtual, SlotOffset); + } + } + else { + if (D->isPure()) { + return VirtualMethodInfo(MethodKind::PureVirtual, -1); + } + else { + return VirtualMethodInfo(MethodKind::Virtual, -1); + } + } + } + else if (D->isStatic()) { + return VirtualMethodInfo(MethodKind::Static, -1); + } + else { + return VirtualMethodInfo(MethodKind::Vanilla, -1); + } +} + +int32_t CodeViewTypeTable::computeVTableSlotOffset(const CXXMethodDecl* D) const +{ + D = D->getCanonicalDecl(); + assert(D->isVirtual()); + + GlobalDecl GD; + if (const CXXDestructorDecl* DD = dyn_cast(D)) { + GD = GlobalDecl(DD, CXXDtorType::Dtor_Deleting); + } + else { + GD = GlobalDecl(D); + } + const MicrosoftVTableContext::MethodVFTableLocation& Loc = + VTableContext.getMethodVFTableLocation(GD); + + return Loc.Index * getPointerByteSize(); +} + +void CodeViewTypeTable::emitTypeSymbolsForTag(const TagDecl* D, + TypeSymbolEmitter& Emitter) +{ + const TagDecl* Def = D->getDefinition(); + if (Def == nullptr) { + return; + } + if (isa(Def)) { + return; + } + + TypeIndex TI = getTypeIndexForTagDefinition(Def); + string Name = computeTagName(Def); + + Emitter.writeUserDefinedType(TI, Name); +} + +QualType CodeViewTypeTable::computeThisType(const CXXRecordDecl* D, + const FunctionProtoType* FuncTy) const +{ + QualType RecordTy = Context.getRecordType(D). + withCVRQualifiers(FuncTy->getTypeQuals()); + return Context.getPointerType(RecordTy).withConst(); +} + +void CodeViewTypeTable::gatherMemberDecls( + const RecordDecl* D, DeclList& Members) +{ + typedef map OverloadMap; + OverloadMap Overloads; + + for (const Decl* MD : D->decls()) { + if (const NamedDecl* ND = dyn_cast(MD)) { + if (shouldEmitMemberDecl(ND)) { + DeclList::iterator I = Members.insert(Members.end(), ND); + if (const CXXMethodDecl* Method = dyn_cast(ND)) { + bool Inserted; + OverloadMap::iterator Overload; + tie(Overload, Inserted) = Overloads.insert( + make_pair(ND->getDeclName(), I)); + if (!Inserted) { + Members.splice(Overload->second, Members, I); + Overload->second = I; + } + } + } + } + } +} + +MethodInfo CodeViewTypeTable::computeImplicitConstructorInfo( + const CXXRecordDecl* RD, ArrayRef ParamTypes) +{ + CallingConv CC = Context.getDefaultCallingConvention(false, true); + + const FunctionProtoType* FuncType = Context.getFunctionType(Context.VoidTy, + ParamTypes, + FunctionProtoType::ExtProtoInfo(CC))->castAs(); + + FunctionOptions Options = FunctionOptions::Constructor; + if (RD->getNumVBases() > 0) { + Options = Options | FunctionOptions::ConstructorWithVirtualBases; + } + + TypeIndex TI = computeTypeIndexForMemberFunctionType(RD, FuncType, + Options, false); + + return MethodInfo(MemberAccess::Public, MethodKind::Vanilla, + MethodOptions::CompilerGenerated, TI, -1); +} + +MethodInfo CodeViewTypeTable::computeImplicitAssignmentInfo( + const CXXRecordDecl* RD, ArrayRef ParamTypes) +{ + CallingConv CC = Context.getDefaultCallingConvention(false, true); + + QualType RecordType = Context.getRecordType(RD); + + const FunctionProtoType* FuncType = Context.getFunctionType( + Context.getLValueReferenceType(RecordType), + ParamTypes, + FunctionProtoType::ExtProtoInfo(CC))->castAs(); + + TypeIndex TI = computeTypeIndexForMemberFunctionType(RD, FuncType, + FunctionOptions::None, false); + + return MethodInfo(MemberAccess::Public, MethodKind::Vanilla, + MethodOptions::CompilerGenerated, TI, -1); +} + +TypeIndex CodeViewTypeTable::computeProcedureType( + TypeIndex ReturnType, + ArrayRef ArgumentTypes) +{ + TypeIndex ArgumentListTI = Builder.writeArgumentList(ArgumentListRecord(ArgumentTypes)); + + return Builder.writeProcedure(ProcedureRecord(ReturnType, + CallingConvention::NearC, FunctionOptions::None, ArgumentTypes.size(), ArgumentListTI)); +} + +TypeIndex CodeViewTypeTable::computeProcedurePointerType( + TypeIndex ReturnType, ArrayRef ArgumentTypes) +{ + return Builder.writePointer(PointerRecord(computeProcedureType(ReturnType, ArgumentTypes), + DefaultPointerKind, PointerMode::Pointer, PointerOptions::None, + getPointerByteSize())); +} + +TypeIndex CodeViewTypeTable::getPointerToConstType(TypeIndex ReferentType) +{ + TypeIndex ConstTI = Builder.writeModifier(ModifierRecord(ReferentType, + ModifierOptions::Const)); + + return Builder.writePointer(PointerRecord(ConstTI, DefaultPointerKind, + PointerMode::Pointer, PointerOptions::None, getPointerByteSize())); +} + Index: lib/CodeGen/DisplayNameGenerator.h =================================================================== --- /dev/null +++ lib/CodeGen/DisplayNameGenerator.h @@ -0,0 +1,159 @@ +#ifndef LLVM_CLANG_LIB_CODEGEN_DISPLAYNAMEGENERATOR_H +#define LLVM_CLANG_LIB_CODEGEN_DISPLAYNAMEGENERATOR_H + +#include "clang/AST/ASTContext.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace CodeGen { + +class DisplayNameGenerator +{ +private: + enum Mode + { + Prefix = 0x01, + Suffix = 0x02, + Both = Prefix | Suffix + }; + +public: + DisplayNameGenerator(ASTContext& Context, llvm::raw_ostream& Out) : + Context(Context), + Out(Out), + AfterSpace(0), + EnsureSpaceBeforeIndirection(false), + EnsureSpaceBeforeSeparator(false), + EnsureSpaceBeforeQualifier(false), + EnsureSpaceBeforeCloseAngle(false) + { + } + + void generateDecl(const TagDecl* D); + + static std::string getMethodName(DeclarationName DN); + +private: + void generate(QualType Ty, Mode M); + void generateFunctionProtoType(const FunctionProtoType* Ty, Mode M); + void generateConstantArrayType(const ConstantArrayType* Ty, Mode M); + void generateIncompleteArrayType(const IncompleteArrayType* Ty, Mode M); + void generatePointerType(const PointerType* Ty, unsigned CVR, Mode M); + void generateLValueReferenceType(const LValueReferenceType* Ty, Mode M); + void generateRValueReferenceType(const RValueReferenceType* Ty, Mode M); + void generateEnumType(const EnumType* Ty, unsigned CVR, Mode M); + void generateRecordType(const RecordType* Ty, unsigned CVR, Mode M); + void generateBuiltinType(const BuiltinType* Ty, unsigned CVR, Mode M); + void generateMemberPointerType(const MemberPointerType* Ty, unsigned CVR, + Mode M); + + void generateQualifiers(unsigned CVR, bool Leaf, bool LeadingSpace); + void generateTagName(const TagDecl* D); + void generateNamespace(const NamespaceDecl* NS); + + void generateTemplateArgument(const TemplateArgument& Arg, bool& First); + void generateDeclForTemplateArgument(const ValueDecl* D, QualType Ty); + void generateFieldDecl(const FieldDecl* D, const MemberPointerType* Ty); + void generateMemberFunctionDecl(const CXXMethodDecl* D, + const MemberPointerType* Ty); + void generateNullTemplateArgument(QualType Ty); + void generateTemplateTemplateArgument(const TemplateName& TName); + void generatePackTemplateArgument(llvm::ArrayRef Args, + bool& First); + void generateExpressionTemplateArgument(const Expr* E); + + void generateFunctionDecl(const FunctionDecl* D); + void generateVarDecl(const VarDecl* D); + void generateScope(const DeclContext* DC, const Decl* D); + void generateTemplateArgumentList(const TemplateArgumentList& Args); + + void write(StringRef S) + { + Out << S; + EnsureSpaceBeforeIndirection = false; + EnsureSpaceBeforeSeparator = false; + EnsureSpaceBeforeQualifier = false; + if (S.size() > 0) { + EnsureSpaceBeforeCloseAngle = S.back() == '>'; + } + } + + void write(int64_t Val) + { + Out << Val; + EnsureSpaceBeforeIndirection = false; + EnsureSpaceBeforeSeparator = false; + EnsureSpaceBeforeQualifier = false; + EnsureSpaceBeforeCloseAngle = false; + } + + void writeCloseAngle() + { + if (EnsureSpaceBeforeCloseAngle || EnsureSpaceBeforeSeparator) { + ensureSpace(); + } + write(">"); + } + + void writeIndirection(const char* S) + { + if (EnsureSpaceBeforeIndirection) { + ensureSpace(); + } + write(S); + } + + void writeSeparator(const char* S, bool& First) + { + if (First) { + First = false; + } + else { + writeSeparator(S); + } + } + + void writeSeparator(const char* S) + { + if (EnsureSpaceBeforeSeparator) { + ensureSpace(); + } + write(S); + } + + void writeQualifier(const char* S) + { + if (EnsureSpaceBeforeQualifier) { + ensureSpace(); + } + write(S); + EnsureSpaceBeforeQualifier = true; + } + + void ensureSpace() + { + if (AfterSpace != Out.tell()) { + assert(AfterSpace < Out.tell()); + write(" "); + AfterSpace = Out.tell(); + } + } + +private: + ASTContext& Context; + raw_ostream& Out; + uint64_t AfterSpace; + bool EnsureSpaceBeforeSeparator; + bool EnsureSpaceBeforeIndirection; + bool EnsureSpaceBeforeQualifier; + bool EnsureSpaceBeforeCloseAngle; + +private: + DisplayNameGenerator(const DisplayNameGenerator&) = delete; + DisplayNameGenerator& operator=(const DisplayNameGenerator&) = delete; +}; + +} +} + +#endif Index: lib/CodeGen/DisplayNameGenerator.cpp =================================================================== --- /dev/null +++ lib/CodeGen/DisplayNameGenerator.cpp @@ -0,0 +1,947 @@ +#include "DisplayNameGenerator.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/VTableBuilder.h" +#include "clang/Basic/TargetInfo.h" + +using namespace clang; +using namespace CodeGen; + +using namespace std; +using namespace llvm; + +namespace { + +class LocalDeclarationFinder : + public ConstStmtVisitor +{ +public: + static unsigned getScopeIndex(const ASTContext& Context, + const Decl* TargetDecl, const FunctionDecl* FD) + { + LocalDeclarationFinder Finder(Context, TargetDecl->getCanonicalDecl()); + + return Finder.Visit(FD->getBody()); + } + + unsigned VisitCompoundStmt(const CompoundStmt* S) + { + beginScope(); + { + for (const Stmt* ChildS : S->body()) { + unsigned FoundScope = Visit(ChildS); + if (FoundScope != 0) { + return FoundScope; + } + } + } + endScope(); + + return 0; + } + + unsigned VisitDeclStmt(const DeclStmt* S) + { + for (const Decl* D : S->decls()) { + if (D->getCanonicalDecl() == TargetDecl) { + return getCurrentScope(); + } + } + + return 0; + } + + unsigned VisitIfStmt(const IfStmt* S) + { + beginCppScope(); // if + { + beginCppScope(); // then + { + unsigned FoundScope = Visit(S->getThen()); + if (FoundScope != 0) { + return FoundScope; + } + } + endCppScope(); + + if (const Stmt* ElseS = S->getElse()) { + beginCppScope(); // else + { + unsigned FoundScope = Visit(ElseS); + if (FoundScope != 0) { + return FoundScope; + } + } + endCppScope(); + } + } + endCppScope(); + + return 0; + } + + unsigned VisitWhileStmt(const WhileStmt* S) + { + beginCppScope(); // body + { + unsigned FoundScope = Visit(S->getBody()); + if (FoundScope != 0) { + return FoundScope; + } + } + endCppScope(); + + return 0; + } + + unsigned VisitDoStmt(const DoStmt* S) + { + beginCppScope(); // body + { + unsigned FoundScope = Visit(S->getBody()); + if (FoundScope != 0) { + return FoundScope; + } + } + endCppScope(); + + return 0; + } + + unsigned VisitForStmt(const ForStmt* S) + { + beginScope(); // body + { + unsigned FoundScope = Visit(S->getBody()); + if (FoundScope != 0) { + return FoundScope; + } + } + endScope(); + + return 0; + } + +private: + explicit LocalDeclarationFinder(const ASTContext& Context, + const Decl* TargetDecl) : + IsCPlusPlus(Context.getLangOpts().CPlusPlus), + TargetDecl(TargetDecl), + ScopeCount(0) + { + } + + void beginScope() + { + ++ScopeCount; + unsigned ScopeIndex = ScopeCount; + + ScopeStack.push_back(ScopeIndex); + } + + void endScope() + { + ScopeStack.pop_back(); + } + + void beginCppScope() + { + if (IsCPlusPlus) { + beginScope(); + } + } + + void endCppScope() + { + if (IsCPlusPlus) { + endScope(); + } + } + + unsigned getCurrentScope() const + { + return ScopeStack.back(); + } + +private: + const bool IsCPlusPlus; + const Decl* const TargetDecl; + unsigned ScopeCount; + SmallVector ScopeStack; +}; + +StringRef getTagName(const TagDecl* D) +{ + if (D->hasNameForLinkage()) { + StringRef Name = D->getName(); + if (Name.empty()) { + return D->getTypedefNameForAnonDecl()->getName(); + } + else { + return Name; + } + } + else { + return ""; + } +} + +const char* getCallingConventionName(CallingConv CC) +{ + switch (CC) { + case CallingConv::CC_C: + return "__cdecl"; + + case CallingConv::CC_X86FastCall: + return "__fastcall"; + + case CallingConv::CC_X86StdCall: + return "__stdcall"; + + case CallingConv::CC_X86ThisCall: + return "__thiscall"; + + case CallingConv::CC_X86VectorCall: + return "__vectorcall"; + + default: + assert(false); + return "??"; + } +} + +const char* getBuiltinTypeName(const BuiltinType* Ty) +{ + BuiltinType::Kind Kind = Ty->getKind(); + switch (Kind) { + case BuiltinType::Kind::Bool: + return "bool"; + + case BuiltinType::Kind::Char16: + return "char16_t"; + + case BuiltinType::Kind::Char32: + return "char32_t"; + + case BuiltinType::Kind::Char_S: + case BuiltinType::Kind::Char_U: + return "char"; + + case BuiltinType::Kind::Double: + return "double"; + + case BuiltinType::Kind::Float: + return "float"; + + case BuiltinType::Kind::Half: + assert(false); + return ""; + + case BuiltinType::Kind::Int: + return "int"; + + case BuiltinType::Kind::Int128: + assert(false); + return ""; + + case BuiltinType::Kind::Long: + return "long"; + + case BuiltinType::Kind::LongDouble: + return "long double"; + + case BuiltinType::Kind::LongLong: + return "__int64"; + + case BuiltinType::Kind::NullPtr: + assert(false); + return ""; + + case BuiltinType::Kind::SChar: + return "signed char"; + + case BuiltinType::Kind::Short: + return "short"; + + case BuiltinType::Kind::UChar: + return "unsigned char"; + + case BuiltinType::Kind::UInt: + return "unsigned int"; + + case BuiltinType::Kind::UInt128: + assert(false); + return ""; + + case BuiltinType::Kind::ULong: + return "unsigned long"; + + case BuiltinType::Kind::ULongLong: + return "unsigned __int64"; + + case BuiltinType::Kind::UShort: + return "unsigned short"; + + case BuiltinType::Kind::Void: + return "void"; + + case BuiltinType::Kind::WChar_S: + case BuiltinType::Kind::WChar_U: + return "wchar_t"; + + case BuiltinType::Kind::ARCUnbridgedCast: + case BuiltinType::Kind::ObjCClass: + case BuiltinType::Kind::ObjCId: + case BuiltinType::Kind::ObjCSel: + // NYI + assert(false); + return ""; + + case BuiltinType::Kind::OCLEvent: + case BuiltinType::Kind::OCLImage1d: + case BuiltinType::Kind::OCLImage1dArray: + case BuiltinType::Kind::OCLImage1dBuffer: + case BuiltinType::Kind::OCLImage2d: + case BuiltinType::Kind::OCLImage2dArray: + case BuiltinType::Kind::OCLImage3d: + case BuiltinType::Kind::OCLSampler: + // NYI + assert(false); + return ""; + + case BuiltinType::Kind::BoundMember: + case BuiltinType::Kind::BuiltinFn: + case BuiltinType::Kind::Dependent: + case BuiltinType::Kind::UnknownAny: + case BuiltinType::Kind::PseudoObject: + case BuiltinType::Kind::Overload: + assert(false); + return ""; + } + assert(false); + return ""; +} + +} + +string DisplayNameGenerator::getMethodName(DeclarationName DN) +{ + switch (DN.getNameKind()) { + case DeclarationName::NameKind::CXXConstructorName: + return DN.getCXXNameType()->getAsCXXRecordDecl()->getName().str(); + + case DeclarationName::NameKind::CXXConversionFunctionName: + return "conversion"; + + case DeclarationName::NameKind::CXXLiteralOperatorName: + return "literal operator"; + + case DeclarationName::NameKind::CXXOperatorName: + return DN.getAsString(); + + case DeclarationName::NameKind::CXXDestructorName: + return "~" + DN.getCXXNameType()->getAsCXXRecordDecl()->getName().str(); + + case DeclarationName::NameKind::Identifier: + return DN.getAsIdentifierInfo()->getName().str(); + + default: + assert(false); + return ""; + } +} + +void DisplayNameGenerator::generate(QualType Ty, Mode M) +{ + QualType CanonicalTy = Ty.getCanonicalType(); + Type::TypeClass TyClass = CanonicalTy->getTypeClass(); + switch (TyClass) { + case Type::TypeClass::FunctionNoProto: + // We shouldn't see these in C++, and we shouldn't be generating + // display names containing types in C. + assert(false); + return; + + case Type::TypeClass::FunctionProto: + return generateFunctionProtoType(CanonicalTy->castAs(), + M); + + case Type::TypeClass::ConstantArray: + return generateConstantArrayType(Context.getAsConstantArrayType( + CanonicalTy), M); + + case Type::TypeClass::IncompleteArray: + return generateIncompleteArrayType(Context.getAsIncompleteArrayType( + CanonicalTy), M); + + case Type::TypeClass::Pointer: + return generatePointerType(CanonicalTy->castAs(), + CanonicalTy.getCVRQualifiers(), M); + + case Type::TypeClass::LValueReference: + return generateLValueReferenceType( + CanonicalTy->castAs(), M); + + case Type::TypeClass::RValueReference: + return generateRValueReferenceType( + CanonicalTy->castAs(), M); + + case Type::TypeClass::Enum: + return generateEnumType(CanonicalTy->castAs(), + CanonicalTy.getCVRQualifiers(), M); + + case Type::TypeClass::Record: + return generateRecordType(CanonicalTy->castAs(), + CanonicalTy.getCVRQualifiers(), M); + + case Type::TypeClass::Builtin: + return generateBuiltinType(CanonicalTy->castAs(), + CanonicalTy.getCVRQualifiers(), M); + + case Type::TypeClass::MemberPointer: + return generateMemberPointerType(CanonicalTy->castAs(), + CanonicalTy.getCVRQualifiers(), M); + + case Type::TypeClass::Attributed: + default: + write("??"); + break; + } +} + +void DisplayNameGenerator::generateFunctionProtoType( + const FunctionProtoType* Ty, Mode M) +{ + if (M & Prefix) { + generate(Ty->getReturnType(), Prefix); + } + if (M == Prefix) { + writeIndirection("("); + } + if (M & Prefix) { + writeIndirection(getCallingConventionName(Ty->getCallConv())); + } + + if (M == Suffix) { + write(")"); + } + + if (M & Suffix) { + write("("); + if ((Ty->getNumParams() > 0) || Ty->isVariadic()) { + bool First = true; + for (QualType ParamTy : Ty->param_types()) { + writeSeparator(",", First); + generate(ParamTy, Both); + } + if (Ty->isVariadic()) { + writeSeparator(",", First); + write("..."); + } + } + else { + write("void"); + } + write(")"); + generateQualifiers(Ty->getTypeQuals(), true, false); + + generate(Ty->getReturnType(), Suffix); + } +} + +void DisplayNameGenerator::generateConstantArrayType( + const ConstantArrayType* Ty, Mode M) +{ + if (M & Prefix) { + generate(Ty->getElementType(), Prefix); + } + if (M & Suffix) { + writeIndirection("["); + write(Ty->getSize().getZExtValue()); + write("]"); + generate(Ty->getElementType(), Suffix); + } +} + +void DisplayNameGenerator::generateIncompleteArrayType( + const IncompleteArrayType* Ty, Mode M) +{ + if (M & Prefix) { + generate(Ty->getElementType(), Prefix); + } + if (M & Suffix) { + writeIndirection("[0]"); + generate(Ty->getElementType(), Suffix); + } +} + +void DisplayNameGenerator::generatePointerType(const PointerType* Ty, + unsigned CVR, Mode M) +{ + if (M & Prefix) { + generate(Ty->getPointeeType(), Prefix); + writeIndirection("*"); + generateQualifiers(CVR, false, true); + if (!Ty->getPointeeType()->isFunctionType()) { + EnsureSpaceBeforeIndirection = true; + } + } + + if (M & Suffix) { + generate(Ty->getPointeeType(), Suffix); + } +} + +void DisplayNameGenerator::generateMemberPointerType( + const MemberPointerType* Ty, unsigned CVR, Mode M) +{ + if (M & Prefix) { + generate(Ty->getPointeeType(), Prefix); + ensureSpace(); + generateDecl(Ty->getClass()->getAsCXXRecordDecl()); + write("::*"); + generateQualifiers(CVR, false, true); + if (!Ty->getPointeeType()->isFunctionType()) { + EnsureSpaceBeforeIndirection = true; + } + } + + if (M & Suffix) { + generate(Ty->getPointeeType(), Suffix); + } +} + +void DisplayNameGenerator::generateLValueReferenceType( + const LValueReferenceType* Ty, Mode M) +{ + if (M & Prefix) { + generate(Ty->getPointeeType(), Prefix); + writeIndirection("&"); + } + if (M & Suffix) { + generate(Ty->getPointeeType(), Suffix); + } +} + +void DisplayNameGenerator::generateRValueReferenceType( + const RValueReferenceType* Ty, Mode M) +{ + if (M & Prefix) { + generate(Ty->getPointeeType(), Prefix); + writeIndirection("&&"); + } + if (M & Suffix) { + generate(Ty->getPointeeType(), Suffix); + } +} + +void DisplayNameGenerator::generateEnumType(const EnumType* Ty, unsigned CVR, + Mode M) +{ + if (M & Prefix) { + write("enum "); + generateDecl(Ty->getDecl()); + generateQualifiers(CVR, true, true); + EnsureSpaceBeforeIndirection = true; + } +} + +void DisplayNameGenerator::generateRecordType(const RecordType* Ty, + unsigned CVR, Mode M) +{ + if (M & Prefix) { + generateDecl(Ty->getDecl()); + generateQualifiers(CVR, true, true); + EnsureSpaceBeforeIndirection = true; + } +} + +void DisplayNameGenerator::generateBuiltinType(const BuiltinType* Ty, + unsigned CVR, Mode M) +{ + if (M & Prefix) { + write(getBuiltinTypeName(Ty)); + generateQualifiers(CVR, true, true); + EnsureSpaceBeforeIndirection = true; + } +} + +void DisplayNameGenerator::generateTemplateArgument(const TemplateArgument& Arg, + bool& First) +{ + TemplateArgument::ArgKind Kind = Arg.getKind(); + if (Kind != TemplateArgument::ArgKind::Pack) { + writeSeparator(",", First); + } + switch (Kind) { + case TemplateArgument::ArgKind::Type: + return generate(Arg.getAsType(), Both); + + case TemplateArgument::ArgKind::Integral: { + int64_t Val; + APSInt SVal = Arg.getAsIntegral(); + if (SVal.isSigned()) { + Val = SVal.getSExtValue(); + } + else { + Val = static_cast(SVal.getZExtValue()); + } + write(Val); + return; + } + + case TemplateArgument::ArgKind::Declaration: + return generateDeclForTemplateArgument(Arg.getAsDecl(), + Arg.getParamTypeForDecl()); + + case TemplateArgument::ArgKind::NullPtr: + return generateNullTemplateArgument(Arg.getNullPtrType()); + + case TemplateArgument::ArgKind::Template: + return generateTemplateTemplateArgument(Arg.getAsTemplate()); + + case TemplateArgument::ArgKind::TemplateExpansion: + //TODO: How do we get here? + assert(false); + break; + + case TemplateArgument::ArgKind::Pack: + return generatePackTemplateArgument(Arg.getPackAsArray(), First); + + case TemplateArgument::ArgKind::Expression: + return generateExpressionTemplateArgument(Arg.getAsExpr()); + + case TemplateArgument::ArgKind::Null: + assert(false); + break; + } + + assert(false); +} + +void DisplayNameGenerator::generateExpressionTemplateArgument(const Expr* E) +{ + const CXXUuidofExpr* UE; + if (const UnaryOperator* UOp = dyn_cast(E)) { + assert(UOp->getOpcode() == UnaryOperator::Opcode::UO_AddrOf); + UE = cast(UOp->getSubExpr()); + } + else { + UE = cast(E); + } + + StringRef Uuid = UE->getUuidAsStringRef(Context); + string Name = "_GUID_" + Uuid.lower(); + std::replace(Name.begin(), Name.end(), '-', '_'); + + write("&"); + write(Name); +} + +void DisplayNameGenerator::generatePackTemplateArgument( + ArrayRef Args, bool& First) +{ + for (const TemplateArgument& Arg : Args) { + generateTemplateArgument(Arg, First); + } +} + +void DisplayNameGenerator::generateDeclForTemplateArgument(const ValueDecl* D, + QualType Ty) +{ + Decl::Kind Kind = D->getKind(); + switch (Kind) { + case Decl::Kind::Function: + write("&"); + generateFunctionDecl(cast(D)); + break; + + case Decl::Kind::CXXMethod: + case Decl::Kind::CXXConversion: + if (const MemberPointerType* MPTy = Ty->getAs()) { + generateMemberFunctionDecl(cast(D), MPTy); + } + else { + write("&"); + generateFunctionDecl(cast(D)); + } + break; + + case Decl::Kind::Field: + generateFieldDecl(cast(D), Ty->castAs()); + break; + + case Decl::Kind::Var: + case Decl::Kind::VarTemplateSpecialization: + write("&"); + generateVarDecl(cast(D)); + break; + + default: + assert(false); + break; + } +} + +void DisplayNameGenerator::generateNullTemplateArgument(QualType Ty) +{ + if (const MemberPointerType* MPTy = Ty->getAs()) { + if (MPTy->isMemberDataPointer()) { + generateFieldDecl(nullptr, MPTy); + } + else { + generateMemberFunctionDecl(nullptr, MPTy); + } + } + else { + // TODO: More kinds + write("0"); + } +} + +void DisplayNameGenerator::generateTemplateTemplateArgument( + const TemplateName& TName) +{ + const ClassTemplateDecl* CTD = + cast(TName.getAsTemplateDecl()); + + generateScope(CTD->getDeclContext(), CTD); + write(CTD->getName()); +} + +void DisplayNameGenerator::generateMemberFunctionDecl(const CXXMethodDecl* D, + const MemberPointerType* Ty) +{ + // TODO: Merge with mangling code. + + const CXXRecordDecl* RD = Ty->getClass()->getAsCXXRecordDecl(); + + MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel(); + + if (!MSInheritanceAttr::hasOnlyOneField(true, IM)) { + write("{"); + } + + // If non-virtual, mangle the name. If virtual, mangle as a virtual memptr + // thunk. + int64_t NVOffset = 0; + int64_t VBTableOffset = 0; + int64_t VBPtrOffset = 0; + if (D) { + assert(!D->isStatic()); + if (MSInheritanceAttr::hasOnlyOneField(true, IM)) { + write("&"); + } + generateDecl(D->getParent()); + write("::"); + + if (D->isVirtual()) { + MicrosoftVTableContext *VTContext = + cast(Context.getVTableContext()); + const MicrosoftVTableContext::MethodVFTableLocation &ML = + VTContext->getMethodVFTableLocation(GlobalDecl(D)); + + write("`vcall'{"); + CharUnits PointerWidth = Context.toCharUnitsFromBits( + Context.getTargetInfo().getPointerWidth(0)); + uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity(); + write(OffsetInVFTable); + write("}'"); + + NVOffset = ML.VFPtrOffset.getQuantity(); + VBTableOffset = ML.VBTableIndex * 4; + if (ML.VBase) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + VBPtrOffset = Layout.getVBPtrOffset().getQuantity(); + } + } + else { + write(getMethodName(D->getDeclName())); + } + } + else { + write("0"); + if (IM == MSInheritanceAttr::Keyword_unspecified_inheritance) { + VBTableOffset = -1; + } + } + + if (MSInheritanceAttr::hasNVOffsetField(/*IsMemberFunction=*/true, IM)) { + write(","); + write(NVOffset); + } + if (MSInheritanceAttr::hasVBPtrOffsetField(IM)) { + write(","); + write(VBPtrOffset); + } + if (MSInheritanceAttr::hasVBTableOffsetField(IM)) { + write(","); + write(VBTableOffset); + } + + if (!MSInheritanceAttr::hasOnlyOneField(true, IM)) { + write("}"); + } +} + +void DisplayNameGenerator::generateFieldDecl(const FieldDecl* D, + const MemberPointerType* Ty) +{ + //TODO: Merge with mangling code. + + const CXXRecordDecl* RD = Ty->getClass()->getAsCXXRecordDecl(); + + int64_t FieldOffset; + int64_t VBTableOffset; + MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel(); + if (D) { + FieldOffset = Context.getFieldOffset(D); + assert(FieldOffset % Context.getCharWidth() == 0 && + "cannot take address of bitfield"); + FieldOffset /= Context.getCharWidth(); + + VBTableOffset = 0; + } + else { + FieldOffset = RD->nullFieldOffsetIsZero() ? 0 : -1; + + VBTableOffset = -1; + } + + if (!MSInheritanceAttr::hasOnlyOneField(Ty->isMemberFunctionPointer(), IM)) { + write("{"); + } + + write(FieldOffset); + + // The C++ standard doesn't allow base-to-derived member pointer conversions + // in template parameter contexts, so the vbptr offset of data member pointers + // is always zero. + if (MSInheritanceAttr::hasVBPtrOffsetField(IM)) { + write(","); + write(0LL); + } + if (MSInheritanceAttr::hasVBTableOffsetField(IM)) { + write(","); + write(VBTableOffset); + } + + if (!MSInheritanceAttr::hasOnlyOneField(Ty->isMemberFunctionPointer(), IM)) { + write("}"); + } +} + +void DisplayNameGenerator::generateDecl(const TagDecl* D) +{ + const DeclContext* Parent = D->getParent(); + generateScope(Parent, D); + + write(getTagName(D)); + + if (const ClassTemplateSpecializationDecl* TD = + dyn_cast(D)) { + generateTemplateArgumentList(TD->getTemplateArgs()); + } +} + +void DisplayNameGenerator::generateFunctionDecl(const FunctionDecl* D) +{ + generateScope(D->getParent(), D); + write(getMethodName(D->getDeclName())); + + if (const TemplateArgumentList* Args = D->getTemplateSpecializationArgs()) { + generateTemplateArgumentList(*Args); + } +} + +void DisplayNameGenerator::generateVarDecl(const VarDecl* D) +{ + generateScope(D->getDeclContext(), D); + write(D->getName()); + + if (const VarTemplateSpecializationDecl* VTSD = + dyn_cast(D)) { + generateTemplateArgumentList(VTSD->getTemplateArgs()); + } +} + +void DisplayNameGenerator::generateTemplateArgumentList( + const TemplateArgumentList& Args) +{ + write("<"); + bool First = true; + for (const TemplateArgument& Arg : Args.asArray()) { + generateTemplateArgument(Arg, First); + } + writeCloseAngle(); +} + +void DisplayNameGenerator::generateScope(const DeclContext* DC, const Decl* D) +{ + if (const TagDecl* TD = dyn_cast(DC)) { + generateDecl(TD); + write("::"); + } + else if (const NamespaceDecl* ND = + dyn_cast(DC)) { + generateNamespace(ND); + write("::"); + } + else if (const TranslationUnitDecl* TUD = + dyn_cast(DC)) { + } + else if (const FunctionDecl* FD = + dyn_cast(DC)) { + assert(FD->doesThisDeclarationHaveABody()); + if (Context.getLangOpts().CPlusPlus) { + generateFunctionDecl(FD); + write("::__l"); + + unsigned ScopeIndex = LocalDeclarationFinder::getScopeIndex(Context, D, + FD); + Out << ScopeIndex + 1U; + write("::"); + } + } + else if (const LinkageSpecDecl* LSD = dyn_cast(DC)) { + generateScope(LSD->getDeclContext(), D); + } + else { + assert(false); + } +} + +void DisplayNameGenerator::generateTagName(const TagDecl* D) +{ + write(getTagName(D)); +} + +void DisplayNameGenerator::generateQualifiers(unsigned CVR, bool Leaf, + bool LeadingSpace) +{ + if (CVR == 0) { + return; + } + + if (LeadingSpace) { + EnsureSpaceBeforeQualifier = true; + } + if (CVR & Qualifiers::Const) { + writeQualifier("const"); + EnsureSpaceBeforeSeparator |= Leaf; + } + if (CVR & Qualifiers::Volatile) { + writeQualifier("volatile"); + EnsureSpaceBeforeSeparator |= Leaf; + } + if (CVR & Qualifiers::Restrict) { + writeQualifier("__restrict"); + EnsureSpaceBeforeSeparator |= Leaf; + } +} + +void DisplayNameGenerator::generateNamespace(const NamespaceDecl* NS) +{ + // TODO: Anonymous namespaces + write(NS->getName()); +} Index: utils/clang.natvis =================================================================== --- utils/clang.natvis +++ utils/clang.natvis @@ -32,6 +32,9 @@ [{(clang::DeclSpec::SCS)StorageClassSpec}], [{(clang::TypeSpecifierType)TypeSpecType}] + + {(clang::Decl::Kind)DeclKind} + {Name,s}